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:
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"),
|
||||
]
|
||||
@@ -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 == "车型图片"
|
||||
@@ -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))
|
||||
Reference in new issue
Block a user