feat(P1): 素材列表支持按类型过滤 - 视频库/配音库分类
Preview Deploy / Deploy Preview Environment (pull_request) Failing after 15s
AI Code Review / AI Code Review (pull_request) Failing after 38s
Auto Approve CI PRs / Auto Approve on CI Green (pull_request) Successful in 2m38s
Auto Merge CI PRs / Auto Merge on CI Green + Approved (pull_request) Successful in 5m14s
Preview Cleanup / Cleanup Preview Environment (pull_request) Successful in 30s
CI/CD Pipeline / Frontend Unit Tests (pull_request) Failing after 1423h53m39s
CI Build & Deploy Pipeline / Production Browser E2E (pull_request) Failing after 1423h54m23s
CI Build & Deploy Pipeline / Staging API Integration Tests (pull_request) Failing after 1423h54m25s
CI Build & Deploy Pipeline / Staging E2E Tests (pull_request) Failing after 1423h54m25s
CI Build & Deploy Pipeline / Build Production Web Image (pull_request) Failing after 1423h54m26s
CI Build & Deploy Pipeline / Build Production API Image (pull_request) Failing after 1423h54m26s
CI Build & Deploy Pipeline / Build Staging Worker Image (pull_request) Failing after 1423h54m28s
CI Build & Deploy Pipeline / Build Staging Web Image (pull_request) Failing after 1423h54m28s
CI Build & Deploy Pipeline / Build Staging API Image (pull_request) Failing after 1423h54m28s
CI/CD Pipeline / Check if frontend-only change (pull_request) Has been skipped
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI Build & Deploy Pipeline / Build Production Worker Image (pull_request) Failing after 1424h26m30s
CI Build & Deploy Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Failing after 1424h26m31s
CI Build & Deploy Pipeline / Deploy Production (pull_request) Failing after 1424h26m29s

新增/修复:
- Asset domain 增加 file_type property(从 mime_type 推导)
- AssetRepository 新增 find_by_project_and_file_type / count_by_project_and_file_type / count_by_library_and_file_type
- 素材列表接口 kind 过滤全路径覆盖(DB层分页更高效):
  - library_id模式:total改用count查询(之前用len(items)不准)
  - project_id模式:改用DB层file_type查询(之前内存过滤性能差)
  - 跨项目模式:新增kind过滤(之前完全没有)
  - 内存过滤路径:project_id和跨项目增加DB层预过滤+改用file_type判断
- 向后兼容:kind参数已存在,只是之前不完整
This commit is contained in:
CI Bot
2026-07-19 07:28:33 +08:00
parent ef8b747c7b
commit 97cf565946
3 changed files with 108 additions and 25 deletions
+59 -25
View File
@@ -201,7 +201,7 @@ def list_assets(
items = asset_repository.find_by_library_and_file_type(
library_id, ft, skip=skip, limit=limit, status=status_list
)
total = len(items)
total = asset_repository.count_by_library_and_file_type(library_id, ft, status=status_list)
else:
items = asset_repository.find_by_library(library_id, skip=skip, limit=limit, status=status_list)
total = asset_repository.count_by_project(library.project_id, status=status_list)
@@ -216,11 +216,11 @@ def list_assets(
if project_id:
check_project_access(project_id, user_id, project_repository)
if ft:
# 无直接方法,加载后按 file_type 过滤(仍比全量加载好)
all_items = asset_repository.find_by_project(project_id, status=status_list)
items = [i for i in all_items if i.mime_type and i.mime_type.startswith(ft)]
total = len(items)
paged = items[skip : skip + limit]
items = asset_repository.find_by_project_and_file_type(
project_id, ft, skip=skip, limit=limit, status=status_list
)
total = asset_repository.count_by_project_and_file_type(project_id, ft, status=status_list)
paged = items
else:
items = asset_repository.find_by_project(project_id, skip=skip, limit=limit, status=status_list)
total = asset_repository.count_by_project(project_id, status=status_list)
@@ -243,22 +243,43 @@ def list_assets(
if not project_ids:
return ListAssetsResponse(items=[], total=0, skip=skip, limit=limit)
total = asset_repository.count_by_project_ids(project_ids, status=status_list)
# 跨项目分页:逐项目累积直到凑够一页
paged_items: list = []
offset = skip
remaining = limit
for pid in project_ids:
proj_total = asset_repository.count_by_project(pid, status=status_list)
if offset >= proj_total:
offset -= proj_total
continue
proj_items = asset_repository.find_by_project(pid, skip=offset, limit=remaining, status=status_list)
paged_items.extend(proj_items)
remaining -= len(proj_items)
offset = 0
if remaining <= 0:
break
if ft:
# 有 kind 过滤:逐项目查 file_type,凑够一页
total = 0
paged_items: list = []
offset = skip
remaining = limit
for pid in project_ids:
proj_total = asset_repository.count_by_project_and_file_type(pid, ft, status=status_list)
total += proj_total
if offset >= proj_total:
offset -= proj_total
continue
proj_items = asset_repository.find_by_project_and_file_type(
pid, ft, skip=offset, limit=remaining, status=status_list
)
paged_items.extend(proj_items)
remaining -= len(proj_items)
offset = 0
if remaining <= 0:
break
else:
total = asset_repository.count_by_project_ids(project_ids, status=status_list)
# 跨项目分页:逐项目累积直到凑够一页
paged_items: list = []
offset = skip
remaining = limit
for pid in project_ids:
proj_total = asset_repository.count_by_project(pid, status=status_list)
if offset >= proj_total:
offset -= proj_total
continue
proj_items = asset_repository.find_by_project(pid, skip=offset, limit=remaining, status=status_list)
paged_items.extend(proj_items)
remaining -= len(proj_items)
offset = 0
if remaining <= 0:
break
return ListAssetsResponse(
items=[_to_asset_response(item) for item in paged_items],
@@ -281,7 +302,14 @@ def list_assets(
all_items = asset_repository.find_by_library(library_id, status=status_list)
elif project_id:
check_project_access(project_id, user_id, project_repository)
all_items = asset_repository.find_by_project(project_id, status=status_list)
if kind:
ft = kind_to_file_type.get(kind)
if ft:
all_items = asset_repository.find_by_project_and_file_type(project_id, ft, status=status_list)
else:
all_items = asset_repository.find_by_project(project_id, status=status_list)
else:
all_items = asset_repository.find_by_project(project_id, status=status_list)
else:
try:
projects = project_repository.find_accessible_projects(user_id)
@@ -290,12 +318,18 @@ def list_assets(
return ListAssetsResponse(items=[], total=0, skip=skip, limit=limit)
all_items = []
for proj in projects:
all_items.extend(asset_repository.find_by_project(proj.id, status=status_list))
if kind and kind_to_file_type.get(kind):
all_items.extend(
asset_repository.find_by_project_and_file_type(proj.id, kind_to_file_type[kind], status=status_list)
)
else:
all_items.extend(asset_repository.find_by_project(proj.id, status=status_list))
# 应用 kind 过滤(如果有)+ keyword/gender/style
if kind:
ft = kind_to_file_type.get(kind)
all_items = [i for i in all_items if i.mime_type and i.mime_type.startswith(ft or "")]
if ft:
all_items = [i for i in all_items if i.file_type == ft]
filtered = _apply_memory_filters(all_items)
total = len(filtered)
paged = filtered[skip : skip + limit]