模特库标签分页与全能创作收口:藏长视频、选择器分页

角色库导入打标签并支持筛选;模特库与全能创作角色/商品选择改为每页 20 条分页。临时限制成片 ≤60 秒,过滤对话里的超长时长选项,并收拢本地全能创作与后台用户相关修复。
This commit is contained in:
Azmat@qq.com
2026-09-21 16:24:37 +08:00
parent 690eb3d843
commit 0bd1db6bf9
48 changed files with 3386 additions and 896 deletions
+27 -22
View File
@@ -37,6 +37,22 @@ class QuickCreateApiTests(TestCase):
self.client = APIClient()
self.client.force_authenticate(self.user)
def _fake_video_model(self, name="doubao-seedance-2-0-fast-260128"):
"""提交时会先按 metadata["pricing"] 预估费用,缺价目一律 400 —— 假模型必须带价。"""
return SimpleNamespace(
id=uuid.uuid4(),
name=name,
display_name="Seedance 2.0 Fast",
metadata={
"capabilities": {
"resolutions": ["480p", "720p"],
"aspect_ratios": ["9:16"],
"durations": [15, 30],
},
"pricing": {"default": {"no_ref_video": 46, "with_ref_video": 28}},
},
)
def _uploaded_asset(self, **kwargs):
upload = kwargs["upload"]
return Asset.objects.create(
@@ -55,16 +71,9 @@ class QuickCreateApiTests(TestCase):
@patch("apps.projects.views._store_uploaded_asset")
def test_submit_creates_product_project_and_persistent_job(self, store_asset, require_worker_task, enqueue, get_model, get_quick_model):
store_asset.side_effect = self._uploaded_asset
video_model_id = uuid.uuid4()
get_model.side_effect = [
object(),
SimpleNamespace(
id=video_model_id,
name="doubao-seedance-2-0-fast-260128",
display_name="Seedance 2.0 Fast",
metadata={"capabilities": {"resolutions": ["480p", "720p"], "aspect_ratios": ["9:16"], "durations": [15]}},
),
]
video_model = self._fake_video_model()
video_model_id = video_model.id
get_model.side_effect = [object(), video_model]
response = self.client.post(
"/api/projects/quick-create/",
{
@@ -120,12 +129,7 @@ class QuickCreateApiTests(TestCase):
"""刷新页面时前端拉状态有空档,用户容易以为「没任务」再提交一次 ——
那会重复建商品、重复扣费。后端必须拦住,并把在跑的那条带回去。"""
store_asset.side_effect = self._uploaded_asset
video_model = SimpleNamespace(
id=uuid.uuid4(),
name="doubao-seedance-2-0-fast-260128",
display_name="Seedance 2.0 Fast",
metadata={"capabilities": {"resolutions": ["480p", "720p"], "aspect_ratios": ["9:16"], "durations": [15]}},
)
video_model = self._fake_video_model()
get_model.side_effect = [object(), video_model, object(), video_model]
def _post():
@@ -167,10 +171,7 @@ class QuickCreateApiTests(TestCase):
@patch("apps.projects.views._store_uploaded_asset")
def test_submit_requires_product_category(self, store_asset, require_worker_task, enqueue, get_model, get_quick_model):
store_asset.side_effect = self._uploaded_asset
get_model.side_effect = [
object(),
SimpleNamespace(id=uuid.uuid4(), name="seedance", display_name="Seedance", metadata={}),
]
get_model.side_effect = [object(), self._fake_video_model("seedance")]
response = self.client.post(
"/api/projects/quick-create/",
{
@@ -200,7 +201,7 @@ class QuickCreateApiTests(TestCase):
)
source = Product.objects.create(team=self.team, created_by=self.user, title="旧商品", cover_asset=source_asset)
ProductImage.objects.create(product=source, asset=source_asset, sort_order=0, is_primary=True)
get_model.side_effect = [object(), SimpleNamespace(id=uuid.uuid4(), name="seedance", display_name="Seedance", metadata={})]
get_model.side_effect = [object(), self._fake_video_model("seedance")]
response = self.client.post(
"/api/projects/quick-create/",
@@ -230,7 +231,7 @@ class QuickCreateApiTests(TestCase):
other = User.objects.create_user(username="quick-image-other", password="pass")
other_team = Team.objects.create(name="Image Other Team", owner=other)
foreign = Product.objects.create(team=other_team, created_by=other, title="别人的图")
get_model.side_effect = [object(), SimpleNamespace(metadata={})]
get_model.side_effect = [object(), self._fake_video_model("seedance")]
response = self.client.post(
"/api/projects/quick-create/",
{
@@ -1375,6 +1376,10 @@ class QuickCreateCoordinatorTests(TestCase):