feat(admin): 新增全套运营管理功能,修复核心路由bug及后端seed问题

修复Vue Admin布局中RouterView未绑定唯一key的问题,解决RBAC系统资源页面切换后内容不刷新的ISSUE-001故障,新增routeViewKey工具函数区分路由实例
完善路由配置,新增admin空路径路由,修复路由命名空路径告警
新增媒体管理、运维发布/重置页面,补全全站路由注册与动态路由过滤逻辑
新增玩法、线索、管家、系统资源管理的全套工具函数、业务组件及单元测试用例
修复后端app/seed.py中媒体资源重复检测未考虑会话内pending资源的bug,新增对应测试验证修复逻辑
修正alembic迁移版本0015的依赖关系,删除废弃的旧迁移文件
优化后端系统接口的字典序列化逻辑,简化重复代码
添加QA验收报告与相关测试截图,完善项目测试覆盖
This commit is contained in:
duanshuwen committed 2026-08-26 18:48:48 +08:00
1 parent fa6fd2a8eb
commit efab6d1398
73 files changed
+3963 -788

No files matched your search

@@ -1,67 +0,0 @@
from importlib.util import module_from_spec, spec_from_file_location
from pathlib import Path
MIGRATION_PATH = Path(__file__).parents[1] / "alembic" / "versions" / "0009_remove_product_domain.py"
SPEC = spec_from_file_location("remove_product_domain_migration", MIGRATION_PATH)
assert SPEC and SPEC.loader
MIGRATION = module_from_spec(SPEC)
SPEC.loader.exec_module(MIGRATION)
class LegacySchemaInspector:
def get_table_names(self) -> list[str]:
return ["Product", "MiniProgramFavorite", "MiniProgramHistory"]
def get_foreign_keys(self, table_name: str) -> list[dict[str, object]]:
foreign_keys = {
"MiniProgramFavorite": [
{
"name": "MiniProgramFavorite_productId_fkey",
"constrained_columns": ["productId"],
"referred_table": "Product",
"referred_columns": ["id"],
}
],
"MiniProgramHistory": [
{
"name": "MiniProgramHistory_productId_fkey",
"constrained_columns": ["productId"],
"referred_table": "Product",
"referred_columns": ["id"],
}
],
}
return foreign_keys.get(table_name, [])
def test_upgrade_drops_legacy_product_foreign_keys_before_product_table(monkeypatch):
events: list[tuple[str, ...]] = []
inspector = LegacySchemaInspector()
monkeypatch.setattr(MIGRATION, "inspect", lambda _bind: inspector)
monkeypatch.setattr(MIGRATION.op, "get_bind", lambda: object())
monkeypatch.setattr(
MIGRATION.op,
"drop_constraint",
lambda name, table_name, type_: events.append(("drop_constraint", name, table_name, type_)),
)
monkeypatch.setattr(MIGRATION.op, "drop_table", lambda table_name: events.append(("drop_table", table_name)))
MIGRATION.upgrade()
assert events == [
(
"drop_constraint",
"MiniProgramFavorite_productId_fkey",
"MiniProgramFavorite",
"foreignkey",
),
(
"drop_constraint",
"MiniProgramHistory_productId_fkey",
"MiniProgramHistory",
"foreignkey",
),
("drop_table", "Product"),
]
+23
View File
@@ -0,0 +1,23 @@
from app.seed import create_media
class PendingMediaSession:
def __init__(self):
self.new = []
def scalar(self, _statement):
return None
def add(self, item):
self.new.append(item)
def test_create_media_reuses_pending_asset_with_same_url():
db = PendingMediaSession()
create_media(db, "/assets/guizhou/shared.jpg", "hero", "首页图片")
create_media(db, "/assets/guizhou/shared.jpg", "vehicle-option", "车型图片")
assert len(db.new) == 1
assert db.new[0].group == "vehicle-option"
assert db.new[0].name == "车型图片"
+44
View File
@@ -0,0 +1,44 @@
import json
from datetime import datetime
from app.models import AdminDepartment, AdminMenu, AdminRole
from app.routers.system import _dept_dict, _menu_dict, _role_dict
def test_role_audit_snapshot_serializes_datetime_fields():
role = AdminRole(
id="role-1",
name="验收角色",
code="acceptance_role",
dataScope="self",
description=None,
isActive=True,
createdAt=datetime(2026, 8, 26, 1, 0),
updatedAt=datetime(2026, 8, 26, 1, 0),
)
json.dumps(_role_dict(role))
def test_menu_and_department_audit_snapshots_serialize_datetime_fields():
menu = AdminMenu(
id="menu-1",
name="验收菜单",
type="page",
sortOrder=1,
isVisible=True,
isActive=True,
createdAt=datetime(2026, 8, 26, 1, 0),
updatedAt=datetime(2026, 8, 26, 1, 0),
)
dept = AdminDepartment(
id="dept-1",
name="验收部门",
sortOrder=1,
isActive=True,
createdAt=datetime(2026, 8, 26, 1, 0),
updatedAt=datetime(2026, 8, 26, 1, 0),
)
json.dumps(_menu_dict(menu))
json.dumps(_dept_dict(dept))