更新方形Logo和头颈部CT默认分类
- 侧边栏 Logo 改为导入根目录 logo_square.png,favicon 也切换为 /logo_square.png,并让前端服务显式提供该根目录图片。 - 头颈部CT分割默认模板分类名改为纯中文,去掉括号英文翻译,颜色和 maskid 保持用户给定顺序。 - 增加旧版头颈部CT英文括号 label 的窄迁移,启动 seed 时自动把旧默认系统模板更新为纯中文默认。 - 更新前端 Logo 测试、后端默认模板和恢复出厂设置测试,覆盖纯中文分类和根目录方形 Logo。 - 更新 AGENTS、README、前端审计、需求冻结和测试计划文档,记录根目录 Logo 和头颈部CT纯中文默认分类。
This commit is contained in:
@@ -86,16 +86,16 @@ def bundled_default_template_definitions() -> list[dict]:
|
||||
"classes": _with_reserved_unclassified_class(_template_classes(
|
||||
"头颈部CT分割",
|
||||
[
|
||||
"肿瘤/结节 (Tumor/Nodule)",
|
||||
"下颌骨 (Mandible)",
|
||||
"甲状腺 (Thyroid)",
|
||||
"气管 (Trachea)",
|
||||
"颈椎 (Cervical Spine)",
|
||||
"颈动脉 (Carotid Artery)",
|
||||
"颈静脉 (Jugular Vein)",
|
||||
"腮腺 (Parotid Gland)",
|
||||
"下颌下腺 (Submandibular Gland)",
|
||||
"舌骨 (Hyoid Bone)",
|
||||
"肿瘤/结节",
|
||||
"下颌骨",
|
||||
"甲状腺",
|
||||
"气管",
|
||||
"颈椎",
|
||||
"颈动脉",
|
||||
"颈静脉",
|
||||
"腮腺",
|
||||
"下颌下腺",
|
||||
"舌骨",
|
||||
],
|
||||
[
|
||||
(255, 0, 0),
|
||||
@@ -115,6 +115,19 @@ def bundled_default_template_definitions() -> list[dict]:
|
||||
]
|
||||
|
||||
|
||||
def _has_legacy_head_neck_english_labels(template: Template) -> bool:
|
||||
if template.name != "头颈部CT分割":
|
||||
return False
|
||||
classes = (template.mapping_rules or {}).get("classes") or []
|
||||
return any(
|
||||
isinstance(item, dict)
|
||||
and isinstance(item.get("name"), str)
|
||||
and "(" in item["name"]
|
||||
and ")" in item["name"]
|
||||
for item in classes
|
||||
)
|
||||
|
||||
|
||||
def ensure_default_templates(db: Session, *, restore_existing: bool = False) -> list[Template]:
|
||||
"""Create bundled system templates, optionally restoring existing ones exactly."""
|
||||
templates: list[Template] = []
|
||||
@@ -126,7 +139,7 @@ def ensure_default_templates(db: Session, *, restore_existing: bool = False) ->
|
||||
if existing is None:
|
||||
existing = Template(owner_user_id=None)
|
||||
db.add(existing)
|
||||
elif not restore_existing:
|
||||
elif not restore_existing and not _has_legacy_head_neck_english_labels(existing):
|
||||
templates.append(existing)
|
||||
continue
|
||||
|
||||
|
||||
@@ -189,16 +189,16 @@ def test_demo_factory_reset_leaves_admin_and_parsed_demo_dicom(client, db_sessio
|
||||
head_neck_classes = templates_by_name["头颈部CT分割"].mapping_rules["classes"]
|
||||
lap_classes = templates_by_name["腹腔镜胆囊切除术"].mapping_rules["classes"]
|
||||
assert [item["name"] for item in head_neck_classes] == [
|
||||
"肿瘤/结节 (Tumor/Nodule)",
|
||||
"下颌骨 (Mandible)",
|
||||
"甲状腺 (Thyroid)",
|
||||
"气管 (Trachea)",
|
||||
"颈椎 (Cervical Spine)",
|
||||
"颈动脉 (Carotid Artery)",
|
||||
"颈静脉 (Jugular Vein)",
|
||||
"腮腺 (Parotid Gland)",
|
||||
"下颌下腺 (Submandibular Gland)",
|
||||
"舌骨 (Hyoid Bone)",
|
||||
"肿瘤/结节",
|
||||
"下颌骨",
|
||||
"甲状腺",
|
||||
"气管",
|
||||
"颈椎",
|
||||
"颈动脉",
|
||||
"颈静脉",
|
||||
"腮腺",
|
||||
"下颌下腺",
|
||||
"舌骨",
|
||||
"待分类",
|
||||
]
|
||||
assert [item["maskId"] for item in head_neck_classes] == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0]
|
||||
|
||||
@@ -55,16 +55,16 @@ def test_default_head_neck_ct_template_is_seeded_and_visible(client, db_session)
|
||||
head_neck = next(template for template in listing.json() if template["name"] == "头颈部CT分割")
|
||||
assert head_neck["description"] == "头颈部CT分割"
|
||||
expected_names = [
|
||||
"肿瘤/结节 (Tumor/Nodule)",
|
||||
"下颌骨 (Mandible)",
|
||||
"甲状腺 (Thyroid)",
|
||||
"气管 (Trachea)",
|
||||
"颈椎 (Cervical Spine)",
|
||||
"颈动脉 (Carotid Artery)",
|
||||
"颈静脉 (Jugular Vein)",
|
||||
"腮腺 (Parotid Gland)",
|
||||
"下颌下腺 (Submandibular Gland)",
|
||||
"舌骨 (Hyoid Bone)",
|
||||
"肿瘤/结节",
|
||||
"下颌骨",
|
||||
"甲状腺",
|
||||
"气管",
|
||||
"颈椎",
|
||||
"颈动脉",
|
||||
"颈静脉",
|
||||
"腮腺",
|
||||
"下颌下腺",
|
||||
"舌骨",
|
||||
"待分类",
|
||||
]
|
||||
expected_colors = [
|
||||
@@ -89,3 +89,32 @@ def test_default_head_neck_ct_template_is_seeded_and_visible(client, db_session)
|
||||
raise AssertionError(f"Unexpected head-neck colors: {actual_colors}")
|
||||
if actual_mask_ids != [*list(range(1, 11)), 0]:
|
||||
raise AssertionError(f"Unexpected head-neck mask IDs: {actual_mask_ids}")
|
||||
|
||||
|
||||
def test_default_head_neck_ct_template_migrates_legacy_english_labels(db_session):
|
||||
from main import ensure_default_templates
|
||||
from models import Template
|
||||
|
||||
db_session.add(Template(
|
||||
name="头颈部CT分割",
|
||||
description="legacy",
|
||||
color="#ef4444",
|
||||
z_index=10,
|
||||
owner_user_id=None,
|
||||
mapping_rules={
|
||||
"classes": [
|
||||
{"id": "old-1", "name": "肿瘤/结节 (Tumor/Nodule)", "color": "#ff0000", "zIndex": 10, "maskId": 1},
|
||||
{"id": "reserved-unclassified", "name": "待分类", "color": "#000000", "zIndex": 0, "maskId": 0},
|
||||
],
|
||||
"rules": [],
|
||||
},
|
||||
))
|
||||
db_session.commit()
|
||||
|
||||
ensure_default_templates(db_session)
|
||||
|
||||
templates = db_session.query(Template).filter(Template.name == "头颈部CT分割").all()
|
||||
assert len(templates) == 1
|
||||
classes = templates[0].mapping_rules["classes"]
|
||||
assert classes[0]["name"] == "肿瘤/结节"
|
||||
assert all("(" not in item["name"] for item in classes)
|
||||
|
||||
Reference in New Issue
Block a user