diff --git a/backend/app/api/v1/module_system/dict/service.py b/backend/app/api/v1/module_system/dict/service.py index ab7977ce..f095d8e5 100644 --- a/backend/app/api/v1/module_system/dict/service.py +++ b/backend/app/api/v1/module_system/dict/service.py @@ -126,6 +126,7 @@ class DictTypeService: await RedisCURD(redis).set( key=redis_key, value="", + expire=None, ) log.info(f"创建字典类型成功: {new_obj_dict}") except Exception as e: @@ -203,6 +204,7 @@ class DictTypeService: await RedisCURD(redis).set( key=redis_key, value=value, + expire=None, ) log.info(f"更新字典类型成功并刷新缓存: {new_obj_dict}") except Exception as e: @@ -408,6 +410,7 @@ class DictDataService: await RedisCURD(redis).set( key=redis_key, value=value, + expire=None, ) except Exception as e: log.error(f"❌ 初始化字典数据失败 [{dict_type}]: {e}") @@ -507,6 +510,7 @@ class DictDataService: await RedisCURD(redis).set( key=redis_key, value=value, + expire=None, ) log.info(f"创建字典数据写入缓存成功: {obj}") except Exception as e: @@ -577,6 +581,7 @@ class DictDataService: await RedisCURD(redis).set( key=redis_key, value=value, + expire=None, ) except Exception as e: log.error(f"更新字典数据类型变更时刷新旧缓存失败: {e}") @@ -596,6 +601,7 @@ class DictDataService: await RedisCURD(redis).set( key=redis_key, value=value, + expire=None, ) log.info(f"更新字典数据写入缓存成功: {obj}") except Exception as e: diff --git a/backend/app/api/v1/module_system/params/service.py b/backend/app/api/v1/module_system/params/service.py index 755f40dd..327f5494 100644 --- a/backend/app/api/v1/module_system/params/service.py +++ b/backend/app/api/v1/module_system/params/service.py @@ -162,6 +162,7 @@ class ParamsService: result = await RedisCURD(redis).set( key=redis_key, value="", + expire=None, ) if not result: log.error(f"同步配置到缓存失败: {new_obj_dict}") @@ -208,6 +209,7 @@ class ParamsService: result = await RedisCURD(redis).set( key=redis_key, value=value, + expire=None, ) if not result: log.error(f"同步配置到缓存失败: {new_obj_dict}") @@ -346,6 +348,7 @@ class ParamsService: result = await RedisCURD(redis).set( key=redis_key, value=value, + expire=None, ) if not result: log.error(f"❌️ 初始化系统配置失败: {config_obj_dict}") diff --git a/backend/app/scripts/data/sys_menu.json b/backend/app/scripts/data/sys_menu.json index 85048bbe..49113c2e 100644 --- a/backend/app/scripts/data/sys_menu.json +++ b/backend/app/scripts/data/sys_menu.json @@ -1,73 +1,31 @@ [ { - "name": "仪表盘", + "name": "平台管理", "type": 1, - "icon": "client", + "icon": "ri:building-4-line", "order": 1, - "permission": "", - "route_name": "Dashboard", - "route_path": "/dashboard", + "permission": null, + "route_name": "Platform", + "route_path": "/platform", "component_path": null, "status": "0", "keep_alive": true, "hidden": false, "always_show": true, - "title": "仪表盘", + "title": "平台管理", "params": null, "affix": false, - "redirect": "/dashboard/workplace", - "description": "初始化数据", - "children": [ - { - "name": "工作台", - "type": 2, - "icon": "el-icon-PieChart", - "order": 1, - "permission": "dashboard:workplace:query", - "route_name": "Workplace", - "route_path": "/dashboard/workplace", - "component_path": "dashboard/workplace", - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "工作台", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - } - ], - "client": "pc" - }, - { - "name": "系统管理", - "type": 1, - "icon": "system", - "order": 2, - "permission": null, - "route_name": "System", - "route_path": "/system", - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "系统管理", - "params": null, - "affix": false, - "redirect": "/system/menu", + "redirect": "/platform/menu", "description": "初始化数据", "children": [ { "name": "菜单管理", "type": 2, - "icon": "menu", + "icon": "ri:menu-line", "order": 1, "permission": "module_system:menu:query", "route_name": "Menu", - "route_path": "/system/menu", + "route_path": "menu", "component_path": "module_system/menu/index", "status": "0", "keep_alive": true, @@ -203,30 +161,30 @@ "client": "pc" }, { - "name": "部门管理", + "name": "租户管理", "type": 2, - "icon": "tree", + "icon": "ri:presentation-line", "order": 2, - "permission": "module_system:dept:query", - "route_name": "Dept", - "route_path": "/system/dept", - "component_path": "module_system/dept/index", + "permission": "module_system:tenant:query", + "route_name": "Tenant", + "route_path": "tenant", + "component_path": "module_system/tenant/index", "status": "0", "keep_alive": true, + "hidden": false, "always_show": false, - "title": "部门管理", + "title": "租户管理", "params": null, "affix": false, - "hidden": false, "redirect": null, "description": "初始化数据", "children": [ { - "name": "创建部门", + "name": "创建租户", "type": 3, "icon": null, "order": 1, - "permission": "module_system:dept:create", + "permission": "module_system:tenant:create", "route_name": null, "route_path": null, "component_path": null, @@ -234,7 +192,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "创建部门", + "title": "创建租户", "params": null, "affix": false, "redirect": null, @@ -242,11 +200,11 @@ "client": "pc" }, { - "name": "修改部门", + "name": "修改租户", "type": 3, "icon": null, "order": 2, - "permission": "module_system:dept:update", + "permission": "module_system:tenant:update", "route_name": null, "route_path": null, "component_path": null, @@ -254,7 +212,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "修改部门", + "title": "修改租户", "params": null, "affix": false, "redirect": null, @@ -262,11 +220,11 @@ "client": "pc" }, { - "name": "删除部门", + "name": "删除租户", "type": 3, "icon": null, "order": 3, - "permission": "module_system:dept:delete", + "permission": "module_system:tenant:delete", "route_name": null, "route_path": null, "component_path": null, @@ -274,7 +232,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "删除部门", + "title": "删除租户", "params": null, "affix": false, "redirect": null, @@ -282,11 +240,11 @@ "client": "pc" }, { - "name": "批量修改部门状态", + "name": "批量修改租户状态", "type": 3, "icon": null, "order": 4, - "permission": "module_system:dept:patch", + "permission": "module_system:tenant:patch", "route_name": null, "route_path": null, "component_path": null, @@ -294,7 +252,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "批量修改部门状态", + "title": "批量修改租户状态", "params": null, "affix": false, "redirect": null, @@ -302,11 +260,11 @@ "client": "pc" }, { - "name": "详情部门", + "name": "租户详情", "type": 3, "icon": null, "order": 5, - "permission": "module_system:dept:detail", + "permission": "module_system:tenant:query", "route_name": null, "route_path": null, "component_path": null, @@ -314,7 +272,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "详情部门", + "title": "租户详情", "params": null, "affix": false, "redirect": null, @@ -322,11 +280,11 @@ "client": "pc" }, { - "name": "查询部门", + "name": "查询租户", "type": 3, "icon": null, "order": 6, - "permission": "module_system:dept:query", + "permission": "module_system:tenant:query", "route_name": null, "route_path": null, "component_path": null, @@ -334,979 +292,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "查询部门", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - } - ], - "client": "pc" - }, - { - "name": "岗位管理", - "type": 2, - "icon": "el-icon-Coordinate", - "order": 3, - "permission": "module_system:position:query", - "route_name": "Position", - "route_path": "/system/position", - "component_path": "module_system/position/index", - "status": "0", - "keep_alive": true, - "always_show": false, - "title": "岗位管理", - "params": null, - "affix": false, - "hidden": false, - "redirect": null, - "description": "初始化数据", - "children": [ - { - "name": "创建岗位", - "type": 3, - "icon": null, - "order": 1, - "permission": "module_system:position:create", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "创建岗位", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "修改岗位", - "type": 3, - "icon": null, - "order": 2, - "permission": "module_system:position:update", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "修改岗位", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "删除岗位", - "type": 3, - "icon": null, - "order": 3, - "permission": "module_system:position:delete", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "修改岗位", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "批量修改岗位状态", - "type": 3, - "icon": null, - "order": 4, - "permission": "module_system:position:patch", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "批量修改岗位状态", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "岗位导出", - "type": 3, - "icon": null, - "order": 5, - "permission": "module_system:position:export", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "岗位导出", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "详情岗位", - "type": 3, - "icon": null, - "order": 6, - "permission": "module_system:position:detail", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "详情岗位", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "查询岗位", - "type": 3, - "icon": null, - "order": 7, - "permission": "module_system:position:query", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "查询岗位", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - } - ], - "client": "pc" - }, - { - "name": "角色管理", - "type": 2, - "icon": "role", - "order": 4, - "permission": "module_system:role:query", - "route_name": "Role", - "route_path": "/system/role", - "component_path": "module_system/role/index", - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "角色管理", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "children": [ - { - "name": "创建角色", - "type": 3, - "icon": null, - "order": 1, - "permission": "module_system:role:create", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "创建角色", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "修改角色", - "type": 3, - "icon": null, - "order": 2, - "permission": "module_system:role:update", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "修改角色", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "删除角色", - "type": 3, - "icon": null, - "order": 3, - "permission": "module_system:role:delete", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "删除角色", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "批量修改角色状态", - "type": 3, - "icon": null, - "order": 4, - "permission": "module_system:role:patch", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "批量修改角色状态", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "角色导出", - "type": 3, - "icon": null, - "order": 5, - "permission": "module_system:role:export", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "角色导出", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "详情角色", - "type": 3, - "icon": null, - "order": 6, - "permission": "module_system:role:detail", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "详情角色", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "查询角色", - "type": 3, - "icon": null, - "order": 7, - "permission": "module_system:role:query", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "查询角色", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "分配权限", - "type": 3, - "icon": null, - "order": 8, - "permission": "module_system:role:permission", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "分配权限", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - } - ], - "client": "pc" - }, - { - "name": "用户管理", - "type": 2, - "icon": "el-icon-User", - "order": 5, - "permission": "module_system:user:query", - "route_name": "User", - "route_path": "/system/user", - "component_path": "module_system/user/index", - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "用户管理", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "children": [ - { - "name": "创建用户", - "type": 3, - "icon": null, - "order": 1, - "permission": "module_system:user:create", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "创建用户", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "修改用户", - "type": 3, - "icon": null, - "order": 2, - "permission": "module_system:user:update", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "修改用户", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "删除用户", - "type": 3, - "icon": null, - "order": 3, - "permission": "module_system:user:delete", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "删除用户", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "批量修改用户状态", - "type": 3, - "icon": null, - "order": 4, - "permission": "module_system:user:patch", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "批量修改用户状态", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "导出用户", - "type": 3, - "icon": null, - "order": 5, - "permission": "module_system:user:export", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "导出用户", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "导入用户", - "type": 3, - "icon": null, - "order": 6, - "permission": "module_system:user:import", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "导入用户", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "下载用户导入模板", - "type": 3, - "icon": null, - "order": 7, - "permission": "module_system:user:download", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "下载用户导入模板", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "详情用户", - "type": 3, - "icon": null, - "order": 8, - "permission": "module_system:user:detail", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "详情用户", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "查询用户", - "type": 3, - "icon": null, - "order": 9, - "permission": "module_system:user:query", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "查询用户", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - } - ], - "client": "pc" - }, - { - "name": "日志管理", - "type": 2, - "icon": "el-icon-Aim", - "order": 6, - "permission": "module_system:log:query", - "route_name": "Log", - "route_path": "/system/log", - "component_path": "module_system/log/index", - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "日志管理", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "children": [ - { - "name": "日志删除", - "type": 3, - "icon": null, - "order": 1, - "permission": "module_system:log:delete", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "日志删除", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "日志导出", - "type": 3, - "icon": null, - "order": 2, - "permission": "module_system:log:export", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "日志导出", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "日志详情", - "type": 3, - "icon": null, - "order": 3, - "permission": "module_system:log:detail", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "日志详情", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "查询日志", - "type": 3, - "icon": null, - "order": 4, - "permission": "module_system:log:query", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "查询日志", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - } - ], - "client": "pc" - }, - { - "name": "公告管理", - "type": 2, - "icon": "bell", - "order": 7, - "permission": "module_system:notice:query", - "route_name": "Notice", - "route_path": "/system/notice", - "component_path": "module_system/notice/index", - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "公告管理", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "children": [ - { - "name": "公告创建", - "type": 3, - "icon": null, - "order": 1, - "permission": "module_system:notice:create", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "公告创建", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "公告修改", - "type": 3, - "icon": null, - "order": 2, - "permission": "module_system:notice:update", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "修改用户", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "公告删除", - "type": 3, - "icon": null, - "order": 3, - "permission": "module_system:notice:delete", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "公告删除", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "公告导出", - "type": 3, - "icon": null, - "order": 4, - "permission": "module_system:notice:export", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "公告导出", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "公告批量修改状态", - "type": 3, - "icon": null, - "order": 5, - "permission": "module_system:notice:patch", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "公告批量修改状态", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "公告详情", - "type": 3, - "icon": null, - "order": 6, - "permission": "module_system:notice:detail", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "公告详情", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "查询公告", - "type": 3, - "icon": null, - "order": 5, - "permission": "module_system:notice:query", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "查询公告", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - } - ], - "client": "pc" - }, - { - "name": "参数管理", - "type": 2, - "icon": "setting", - "order": 8, - "permission": "module_system:param:query", - "route_name": "Params", - "route_path": "/system/param", - "component_path": "module_system/param/index", - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "参数管理", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "children": [ - { - "name": "创建参数", - "type": 3, - "icon": null, - "order": 1, - "permission": "module_system:param:create", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "创建参数", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "修改参数", - "type": 3, - "icon": null, - "order": 2, - "permission": "module_system:param:update", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "修改参数", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "删除参数", - "type": 3, - "icon": null, - "order": 3, - "permission": "module_system:param:delete", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "删除参数", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "导出参数", - "type": 3, - "icon": null, - "order": 4, - "permission": "module_system:param:export", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "导出参数", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "参数上传", - "type": 3, - "icon": null, - "order": 5, - "permission": "module_system:param:upload", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "参数上传", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "参数详情", - "type": 3, - "icon": null, - "order": 6, - "permission": "module_system:param:detail", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "参数详情", - "params": null, - "affix": false, - "redirect": null, - "description": "初始化数据", - "client": "pc" - }, - { - "name": "查询参数", - "type": 3, - "icon": null, - "order": 7, - "permission": "module_system:param:query", - "route_name": null, - "route_path": null, - "component_path": null, - "status": "0", - "keep_alive": true, - "hidden": false, - "always_show": false, - "title": "查询参数", + "title": "查询租户", "params": null, "affix": false, "redirect": null, @@ -1319,11 +305,11 @@ { "name": "字典管理", "type": 2, - "icon": "dict", - "order": 9, + "icon": "ri:book-2-line", + "order": 3, "permission": "module_system:dict_type:query", "route_name": "Dict", - "route_path": "/system/dict", + "route_path": "dict", "component_path": "module_system/dict/index", "status": "0", "keep_alive": true, @@ -1619,30 +605,30 @@ "client": "pc" }, { - "name": "租户管理", + "name": "参数管理", "type": 2, - "icon": "el-icon-DataBoard", - "order": 10, - "permission": "module_system:tenant:query", - "route_name": "Tenant", - "route_path": "/system/tenant", - "component_path": "module_system/tenant/index", + "icon": "ri:settings-3-line", + "order": 4, + "permission": "module_system:param:query", + "route_name": "Params", + "route_path": "param", + "component_path": "module_system/param/index", "status": "0", "keep_alive": true, "hidden": false, "always_show": false, - "title": "租户管理", + "title": "参数管理", "params": null, "affix": false, "redirect": null, "description": "初始化数据", "children": [ { - "name": "创建租户", + "name": "创建参数", "type": 3, "icon": null, "order": 1, - "permission": "module_system:tenant:create", + "permission": "module_system:param:create", "route_name": null, "route_path": null, "component_path": null, @@ -1650,7 +636,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "创建租户", + "title": "创建参数", "params": null, "affix": false, "redirect": null, @@ -1658,11 +644,11 @@ "client": "pc" }, { - "name": "修改租户", + "name": "修改参数", "type": 3, "icon": null, "order": 2, - "permission": "module_system:tenant:update", + "permission": "module_system:param:update", "route_name": null, "route_path": null, "component_path": null, @@ -1670,7 +656,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "修改租户", + "title": "修改参数", "params": null, "affix": false, "redirect": null, @@ -1678,11 +664,11 @@ "client": "pc" }, { - "name": "删除租户", + "name": "删除参数", "type": 3, "icon": null, "order": 3, - "permission": "module_system:tenant:delete", + "permission": "module_system:param:delete", "route_name": null, "route_path": null, "component_path": null, @@ -1690,7 +676,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "删除租户", + "title": "删除参数", "params": null, "affix": false, "redirect": null, @@ -1698,11 +684,11 @@ "client": "pc" }, { - "name": "批量修改租户状态", + "name": "导出参数", "type": 3, "icon": null, "order": 4, - "permission": "module_system:tenant:patch", + "permission": "module_system:param:export", "route_name": null, "route_path": null, "component_path": null, @@ -1710,7 +696,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "批量修改租户状态", + "title": "导出参数", "params": null, "affix": false, "redirect": null, @@ -1718,11 +704,11 @@ "client": "pc" }, { - "name": "租户详情", + "name": "参数上传", "type": 3, "icon": null, "order": 5, - "permission": "module_system:tenant:query", + "permission": "module_system:param:upload", "route_name": null, "route_path": null, "component_path": null, @@ -1730,7 +716,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "租户详情", + "title": "参数上传", "params": null, "affix": false, "redirect": null, @@ -1738,11 +724,11 @@ "client": "pc" }, { - "name": "查询租户", + "name": "参数详情", "type": 3, "icon": null, "order": 6, - "permission": "module_system:tenant:query", + "permission": "module_system:param:detail", "route_name": null, "route_path": null, "component_path": null, @@ -1750,7 +736,1001 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "查询租户", + "title": "参数详情", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "查询参数", + "type": 3, + "icon": null, + "order": 7, + "permission": "module_system:param:query", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "查询参数", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + } + ], + "client": "pc" + } + ], + "client": "pc" + }, + { + "name": "系统管理", + "type": 1, + "icon": "ri:settings-2-line", + "order": 2, + "permission": null, + "route_name": "System", + "route_path": "/system", + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "系统管理", + "params": null, + "affix": false, + "redirect": "/system/dept", + "description": "初始化数据", + "children": [ + { + "name": "部门管理", + "type": 2, + "icon": "ri:node-tree", + "order": 2, + "permission": "module_system:dept:query", + "route_name": "Dept", + "route_path": "/system/dept", + "component_path": "module_system/dept/index", + "status": "0", + "keep_alive": true, + "always_show": false, + "title": "部门管理", + "params": null, + "affix": false, + "hidden": false, + "redirect": null, + "description": "初始化数据", + "children": [ + { + "name": "创建部门", + "type": 3, + "icon": null, + "order": 1, + "permission": "module_system:dept:create", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "创建部门", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "修改部门", + "type": 3, + "icon": null, + "order": 2, + "permission": "module_system:dept:update", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "修改部门", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "删除部门", + "type": 3, + "icon": null, + "order": 3, + "permission": "module_system:dept:delete", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "删除部门", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "批量修改部门状态", + "type": 3, + "icon": null, + "order": 4, + "permission": "module_system:dept:patch", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "批量修改部门状态", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "详情部门", + "type": 3, + "icon": null, + "order": 5, + "permission": "module_system:dept:detail", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "详情部门", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "查询部门", + "type": 3, + "icon": null, + "order": 6, + "permission": "module_system:dept:query", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "查询部门", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + } + ], + "client": "pc" + }, + { + "name": "岗位管理", + "type": 2, + "icon": "ri:map-pin-line", + "order": 3, + "permission": "module_system:position:query", + "route_name": "Position", + "route_path": "/system/position", + "component_path": "module_system/position/index", + "status": "0", + "keep_alive": true, + "always_show": false, + "title": "岗位管理", + "params": null, + "affix": false, + "hidden": false, + "redirect": null, + "description": "初始化数据", + "children": [ + { + "name": "创建岗位", + "type": 3, + "icon": null, + "order": 1, + "permission": "module_system:position:create", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "创建岗位", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "修改岗位", + "type": 3, + "icon": null, + "order": 2, + "permission": "module_system:position:update", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "修改岗位", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "删除岗位", + "type": 3, + "icon": null, + "order": 3, + "permission": "module_system:position:delete", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "修改岗位", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "批量修改岗位状态", + "type": 3, + "icon": null, + "order": 4, + "permission": "module_system:position:patch", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "批量修改岗位状态", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "岗位导出", + "type": 3, + "icon": null, + "order": 5, + "permission": "module_system:position:export", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "岗位导出", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "详情岗位", + "type": 3, + "icon": null, + "order": 6, + "permission": "module_system:position:detail", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "详情岗位", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "查询岗位", + "type": 3, + "icon": null, + "order": 7, + "permission": "module_system:position:query", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "查询岗位", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + } + ], + "client": "pc" + }, + { + "name": "角色管理", + "type": 2, + "icon": "ri:admin-line", + "order": 4, + "permission": "module_system:role:query", + "route_name": "Role", + "route_path": "/system/role", + "component_path": "module_system/role/index", + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "角色管理", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "children": [ + { + "name": "创建角色", + "type": 3, + "icon": null, + "order": 1, + "permission": "module_system:role:create", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "创建角色", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "修改角色", + "type": 3, + "icon": null, + "order": 2, + "permission": "module_system:role:update", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "修改角色", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "删除角色", + "type": 3, + "icon": null, + "order": 3, + "permission": "module_system:role:delete", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "删除角色", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "批量修改角色状态", + "type": 3, + "icon": null, + "order": 4, + "permission": "module_system:role:patch", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "批量修改角色状态", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "角色导出", + "type": 3, + "icon": null, + "order": 5, + "permission": "module_system:role:export", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "角色导出", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "详情角色", + "type": 3, + "icon": null, + "order": 6, + "permission": "module_system:role:detail", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "详情角色", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "查询角色", + "type": 3, + "icon": null, + "order": 7, + "permission": "module_system:role:query", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "查询角色", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "分配权限", + "type": 3, + "icon": null, + "order": 8, + "permission": "module_system:role:permission", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "分配权限", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + } + ], + "client": "pc" + }, + { + "name": "用户管理", + "type": 2, + "icon": "ri:user-line", + "order": 5, + "permission": "module_system:user:query", + "route_name": "User", + "route_path": "/system/user", + "component_path": "module_system/user/index", + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "用户管理", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "children": [ + { + "name": "创建用户", + "type": 3, + "icon": null, + "order": 1, + "permission": "module_system:user:create", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "创建用户", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "修改用户", + "type": 3, + "icon": null, + "order": 2, + "permission": "module_system:user:update", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "修改用户", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "删除用户", + "type": 3, + "icon": null, + "order": 3, + "permission": "module_system:user:delete", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "删除用户", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "批量修改用户状态", + "type": 3, + "icon": null, + "order": 4, + "permission": "module_system:user:patch", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "批量修改用户状态", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "导出用户", + "type": 3, + "icon": null, + "order": 5, + "permission": "module_system:user:export", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "导出用户", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "导入用户", + "type": 3, + "icon": null, + "order": 6, + "permission": "module_system:user:import", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "导入用户", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "下载用户导入模板", + "type": 3, + "icon": null, + "order": 7, + "permission": "module_system:user:download", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "下载用户导入模板", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "详情用户", + "type": 3, + "icon": null, + "order": 8, + "permission": "module_system:user:detail", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "详情用户", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "查询用户", + "type": 3, + "icon": null, + "order": 9, + "permission": "module_system:user:query", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "查询用户", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + } + ], + "client": "pc" + }, + { + "name": "日志管理", + "type": 2, + "icon": "ri:focus-3-line", + "order": 6, + "permission": "module_system:log:query", + "route_name": "Log", + "route_path": "/system/log", + "component_path": "module_system/log/index", + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "日志管理", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "children": [ + { + "name": "日志删除", + "type": 3, + "icon": null, + "order": 1, + "permission": "module_system:log:delete", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "日志删除", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "日志导出", + "type": 3, + "icon": null, + "order": 2, + "permission": "module_system:log:export", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "日志导出", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "日志详情", + "type": 3, + "icon": null, + "order": 3, + "permission": "module_system:log:detail", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "日志详情", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "查询日志", + "type": 3, + "icon": null, + "order": 4, + "permission": "module_system:log:query", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "查询日志", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + } + ], + "client": "pc" + }, + { + "name": "公告管理", + "type": 2, + "icon": "ri:notification-3-line", + "order": 7, + "permission": "module_system:notice:query", + "route_name": "Notice", + "route_path": "/system/notice", + "component_path": "module_system/notice/index", + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "公告管理", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "children": [ + { + "name": "公告创建", + "type": 3, + "icon": null, + "order": 1, + "permission": "module_system:notice:create", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "公告创建", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "公告修改", + "type": 3, + "icon": null, + "order": 2, + "permission": "module_system:notice:update", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "修改用户", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "公告删除", + "type": 3, + "icon": null, + "order": 3, + "permission": "module_system:notice:delete", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "公告删除", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "公告导出", + "type": 3, + "icon": null, + "order": 4, + "permission": "module_system:notice:export", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "公告导出", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "公告批量修改状态", + "type": 3, + "icon": null, + "order": 5, + "permission": "module_system:notice:patch", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "公告批量修改状态", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "公告详情", + "type": 3, + "icon": null, + "order": 6, + "permission": "module_system:notice:detail", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "公告详情", + "params": null, + "affix": false, + "redirect": null, + "description": "初始化数据", + "client": "pc" + }, + { + "name": "查询公告", + "type": 3, + "icon": null, + "order": 5, + "permission": "module_system:notice:query", + "route_name": null, + "route_path": null, + "component_path": null, + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "查询公告", "params": null, "affix": false, "redirect": null, @@ -1766,7 +1746,7 @@ { "name": "监控管理", "type": 1, - "icon": "monitor", + "icon": "ri:computer-line", "order": 3, "permission": null, "route_name": "Monitor", @@ -1785,7 +1765,7 @@ { "name": "在线用户", "type": 2, - "icon": "el-icon-Headset", + "icon": "ri:customer-service-2-line", "order": 1, "permission": "module_monitor:online:query", "route_name": "MonitorOnline", @@ -1827,7 +1807,7 @@ { "name": "服务器监控", "type": 2, - "icon": "el-icon-Odometer", + "icon": "ri:dashboard-3-line", "order": 2, "permission": "module_monitor:server:query", "route_name": "MonitorServer", @@ -1847,7 +1827,7 @@ { "name": "缓存监控", "type": 2, - "icon": "el-icon-Stopwatch", + "icon": "ri:timer-flash-line", "order": 3, "permission": "module_monitor:cache:query", "route_name": "MonitorCache", @@ -1889,7 +1869,7 @@ { "name": "文件管理", "type": 2, - "icon": "el-icon-Files", + "icon": "ri:folder-5-line", "order": 4, "permission": "module_monitor:resource:query", "route_name": "Resource", @@ -2074,11 +2054,11 @@ { "name": "接口管理", "type": 1, - "icon": "document", + "icon": "ri:file-text-line", "order": 4, "permission": null, - "route_name": "Common", - "route_path": "/common", + "route_name": "Swagger", + "route_path": "/swagger", "component_path": null, "status": "0", "keep_alive": true, @@ -2087,18 +2067,18 @@ "title": "接口管理", "params": null, "affix": false, - "redirect": "/common/docs", + "redirect": "/swagger/docs", "description": "初始化数据", "children": [ { "name": "Swagger文档", "type": 4, - "icon": "api", + "icon": "ri:plug-line", "order": 1, - "permission": "module_common:docs:query", + "permission": "module_swagger:docs:query", "route_name": "Docs", - "route_path": "/common/docs", - "component_path": "module_common/docs/index", + "route_path": "/swagger/docs", + "component_path": "module_swagger/docs/index", "status": "0", "keep_alive": true, "hidden": false, @@ -2113,12 +2093,12 @@ { "name": "Redoc文档", "type": 4, - "icon": "el-icon-Document", + "icon": "ri:file-text-line", "order": 2, - "permission": "module_common:redoc:query", + "permission": "module_swagger:redoc:query", "route_name": "Redoc", - "route_path": "/common/redoc", - "component_path": "module_common/redoc/index", + "route_path": "/swagger/redoc", + "component_path": "module_swagger/redoc/index", "status": "0", "keep_alive": true, "hidden": false, @@ -2133,12 +2113,12 @@ { "name": "LangJin文档", "type": 4, - "icon": "el-icon-Document", + "icon": "ri:file-text-line", "order": 3, - "permission": "module_common:ljdoc:query", + "permission": "module_swagger:ljdoc:query", "route_name": "Ljdoc", - "route_path": "/common/ljdoc", - "component_path": "module_common/ljdoc/index", + "route_path": "/swagger/ljdoc", + "component_path": "module_swagger/ljdoc/index", "status": "0", "keep_alive": true, "hidden": false, @@ -2156,7 +2136,7 @@ { "name": "代码管理", "type": 1, - "icon": "code", + "icon": "ri:code-s-slash-line", "order": 5, "permission": null, "route_name": "Generator", @@ -2175,7 +2155,7 @@ { "name": "代码生成", "type": 2, - "icon": "code", + "icon": "ri:code-s-slash-line", "order": 1, "permission": "module_generator:gencode:query", "route_name": "GenCode", @@ -2378,9 +2358,9 @@ "client": "pc" }, { - "name": "应用管理", + "name": "应用门户", "type": 1, - "icon": "el-icon-ShoppingBag", + "icon": "ri:shopping-bag-3-line", "order": 6, "permission": null, "route_name": "Application", @@ -2390,7 +2370,7 @@ "keep_alive": true, "hidden": false, "always_show": false, - "title": "应用管理", + "title": "应用门户", "params": null, "affix": false, "redirect": "/application/portal", @@ -2399,7 +2379,7 @@ { "name": "插件市场", "type": 2, - "icon": "el-icon-ShoppingCartFull", + "icon": "ri:shopping-cart-2-line", "order": 1, "permission": "module_application:portal:query", "route_name": "PortalApp", @@ -2544,7 +2524,7 @@ { "name": "AI管理", "type": 1, - "icon": "el-icon-ChatLineSquare", + "icon": "ri:chat-3-line", "order": 7, "permission": null, "route_name": "AI", @@ -2563,7 +2543,7 @@ { "name": "AI智能助手", "type": 2, - "icon": "el-icon-ChatDotRound", + "icon": "ri:message-2-line", "order": 1, "permission": "module_ai:chat:query", "route_name": "Chat", @@ -2702,11 +2682,32 @@ ], "client": "pc" }, + { + "name": "会话聊天", + "type": 2, + "icon": "ri:message-3-line", + "order": 2, + "permission": "module_ai:chat:query", + "route_name": "FaChat", + "route_path": "/ai/fachat", + "component_path": "module_ai/fachat/index", + "status": "0", + "keep_alive": true, + "hidden": false, + "always_show": false, + "title": "会话聊天", + "params": null, + "affix": false, + "redirect": null, + "description": "会话聊天(FaChat)", + "children": [], + "client": "pc" + }, { "name": "会话记忆", "type": 2, - "icon": "el-icon-ChatLineSquare", - "order": 2, + "icon": "ri:chat-3-line", + "order": 3, "permission": "module_ai:chat:query", "route_name": "Memory", "route_path": "/ai/memory", @@ -2790,7 +2791,7 @@ { "name": "任务管理", "type": 1, - "icon": "el-icon-SetUp", + "icon": "ri:tools-line", "order": 8, "permission": null, "route_name": "Task", @@ -2809,7 +2810,7 @@ { "name": "定时任务", "type": 1, - "icon": "el-icon-Timer", + "icon": "ri:timer-line", "order": 1, "permission": null, "route_name": "Cronjob", @@ -2828,7 +2829,7 @@ { "name": "调度器监控", "type": 2, - "icon": "el-icon-DataLine", + "icon": "ri:line-chart-line", "order": 1, "permission": "module_task:cronjob:job:query", "route_name": "Job", @@ -2950,7 +2951,7 @@ { "name": "节点管理", "type": 2, - "icon": "el-icon-Postcard", + "icon": "ri:mail-send-line", "order": 2, "permission": "module_task:cronjob:node:query", "route_name": "Node", @@ -3095,7 +3096,7 @@ { "name": "工作流", "type": 1, - "icon": "el-icon-SetUp", + "icon": "ri:tools-line", "order": 2, "permission": null, "route_name": "WorkflowMgr", @@ -3114,7 +3115,7 @@ { "name": "流程编排", "type": 2, - "icon": "el-icon-SetUp", + "icon": "ri:tools-line", "order": 1, "permission": "module_task:workflow:definition:query", "route_name": "Workflow", @@ -3256,7 +3257,7 @@ { "name": "编排节点类型", "type": 2, - "icon": "el-icon-Grid", + "icon": "ri:layout-grid-line", "order": 2, "permission": "module_task:workflow:node-type:query", "route_name": "WorkflowNodeType", @@ -3384,7 +3385,7 @@ { "name": "案例管理", "type": 1, - "icon": "menu", + "icon": "ri:menu-line", "order": 9, "permission": null, "route_name": "Example", @@ -3403,7 +3404,7 @@ { "name": "示例管理", "type": 2, - "icon": "menu", + "icon": "ri:menu-line", "order": 1, "permission": "module_example:demo:query", "route_name": "Demo", @@ -3605,7 +3606,7 @@ { "name": "二级目录", "type": 1, - "icon": "menu", + "icon": "ri:menu-line", "order": 2, "permission": null, "route_name": "DemoDir", @@ -3624,7 +3625,7 @@ { "name": "三级菜单", "type": 2, - "icon": "menu", + "icon": "ri:menu-line", "order": 1, "permission": "module_example:demo01:query", "route_name": "Demo01", @@ -3832,7 +3833,7 @@ { "name": "首页", "type": 1, - "icon": "homepage", + "icon": "ri:home-4-line", "order": 90, "permission": "", "route_name": "AppHome", @@ -3853,7 +3854,7 @@ { "name": "同事", "type": 1, - "icon": "visitor", + "icon": "ri:user-heart-line", "order": 91, "permission": "", "route_name": "AppColleague", @@ -3874,7 +3875,7 @@ { "name": "打卡", "type": 1, - "icon": "time", + "icon": "ri:time-line", "order": 92, "permission": "", "route_name": "AppAttendance", @@ -3895,7 +3896,7 @@ { "name": "消息", "type": 1, - "icon": "message", + "icon": "ri:message-3-line", "order": 93, "permission": "", "route_name": "AppMessage", @@ -3916,7 +3917,7 @@ { "name": "我的", "type": 1, - "icon": "user", + "icon": "ri:user-line", "order": 94, "permission": "", "route_name": "AppMine", diff --git a/backend/app/scripts/data/sys_user.json b/backend/app/scripts/data/sys_user.json index 792667a4..d1f6be52 100644 --- a/backend/app/scripts/data/sys_user.json +++ b/backend/app/scripts/data/sys_user.json @@ -1,7 +1,7 @@ [ { "tenant_id": 1, - "username": "admin", + "username": "super", "password": "$2b$12$e2IJgS/cvHgJ0H3G7Xa08OXoXnk6N/NX3IZRtubBDElA0VLZhkNOa", "name": "超级管理员", "mobile": null, @@ -19,5 +19,47 @@ "description": "超级管理员", "created_id": null, "updated_id": null + }, + { + "tenant_id": 1, + "username": "admin", + "password": "$2b$12$e2IJgS/cvHgJ0H3G7Xa08OXoXnk6N/NX3IZRtubBDElA0VLZhkNOa", + "name": "管理员", + "mobile": null, + "email": null, + "gender": "0", + "avatar": "https://service.fastapiadmin.com/api/v1/static/image/avatar.png", + "is_superuser": true, + "last_login": null, + "gitee_login": null, + "github_login": null, + "wx_login": null, + "qq_login": null, + "dept_id": 1, + "status": "0", + "description": "管理员", + "created_id": null, + "updated_id": null + }, + { + "tenant_id": 1, + "username": "user", + "password": "$2b$12$e2IJgS/cvHgJ0H3G7Xa08OXoXnk6N/NX3IZRtubBDElA0VLZhkNOa", + "name": "普通用户", + "mobile": null, + "email": null, + "gender": "0", + "avatar": "https://service.fastapiadmin.com/api/v1/static/image/avatar.png", + "is_superuser": false, + "last_login": null, + "gitee_login": null, + "github_login": null, + "wx_login": null, + "qq_login": null, + "dept_id": 1, + "status": "0", + "description": "普通用户", + "created_id": null, + "updated_id": null } ] \ No newline at end of file diff --git a/backend/fastapi-backend.spec b/backend/fastapi-backend.spec deleted file mode 100644 index 84713936..00000000 --- a/backend/fastapi-backend.spec +++ /dev/null @@ -1,38 +0,0 @@ -# -*- mode: python ; coding: utf-8 -*- - - -a = Analysis( - ['app/main.py'], - pathex=[], - binaries=[], - datas=[], - hiddenimports=[], - hookspath=[], - hooksconfig={}, - runtime_hooks=[], - excludes=[], - noarchive=False, - optimize=0, -) -pyz = PYZ(a.pure) - -exe = EXE( - pyz, - a.scripts, - a.binaries, - a.datas, - [], - name='fastapi-backend', - debug=False, - bootloader_ignore_signals=False, - strip=False, - upx=True, - upx_exclude=[], - runtime_tmpdir=None, - console=True, - disable_windowed_traceback=False, - argv_emulation=False, - target_arch=None, - codesign_identity=None, - entitlements_file=None, -) diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 6d641437..d526c015 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -10,7 +10,7 @@ dependencies = [ "aiosqlite==0.17.0", # sqlite 异步操作数据库 "alembic==1.15.1", # 数据库迁移 "apscheduler==3.11.0", # 定时任务 - "asyncmy==0.2.11", # mysql 异步操作数据库:基于 mysqlclient:asyncmy 是 mysqlclient 的异步版本,mysqlclient 是一个 C 语言编写的 MySQL 客户端,性能较高。性能:asyncmy 通常在性能上优于 aiomysql,特别是在高并发和大数据量的场景下。 + "asyncmy==0.2.11", # mysql 异步操作数据库:基于 mysqlclient:asyncmy 是 mysqlclient 的异步版本,mysqlclient 是一个 C 语言编写的 MySQL 客户端,性能较高。性能:asyncmy 通常在性能上优于 aiomysql,特别是在高并发和大数据量的场景下。 "asyncpg==0.30.0", # postgresql 异步操作数据库基于 psycopg2:asyncpg 是 psycopg2 的异步版本,psycopg2 是一个 pure-Python PostgreSQL 数据库适配器。性能:asyncpg 通常在性能上优于 psycopg2,特别是在高并发和大数据量的场景下。 "bcrypt==4.0.1", # 密码加密解析,切勿升级,如果升级,请同时升级python版本 "bleach==6.3.0", # 过滤 HTML 标签 @@ -25,7 +25,7 @@ dependencies = [ "itsdangerous==2.2.0", # 用于安全处理各种数据,如密码、密钥等 "jinja2==3.1.6", # 模板引擎 "loguru==0.7.3", # 日志 - "openai==2.28.0", + "openai==2.28.0", # OpenAI API 客户端 "openpyxl==3.1.5", # Excel "pandas==2.2.3", # 数据处理 "passlib==1.7.4", # 密码加密 @@ -44,10 +44,11 @@ dependencies = [ "tomli>=2.0.1; python_version < '3.11'", # 解析 plugin.toml(3.11+ 用标准库 tomllib) "sqlalchemy==2.0.45", # 数据库ORM "sqlglot[rs]==27.8.0", # sql 解析 - "typer==0.19.0", # 命令行工具 + "typer==0.19.0", # 命令行工具 "user-agents==2.2.0", # 获取用户UA "uvicorn==0.30.6", # uvicorn web 框架 "websockets>=15.0.1,<16.0", # websocket(prefect>=3.5 需 >=15.0.1;与部署 requirements.txt 一致) + "tomli>=2.0.1 ; python_full_version < '3.15'", ] [dependency-groups] diff --git a/backend/requirements.txt b/backend/requirements.txt index 228e510d..39cebfb8 100755 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -1,15 +1,15 @@ # 与 pyproject.toml [project] dependencies 一致(生产 pip;不含 dev 组:pytest / ruff / fakeredis) -agno==2.5.8 -aiofiles==24.1.0 # 文件操作 +agno==2.5.8 # AI agent框架 +aiofiles==24.1.0 # 文件操作 aiosqlite==0.17.0 # sqlite 异步操作数据库 alembic==1.15.1 # 数据库迁移 -apscheduler==3.11.0 # 定时任务 -asyncmy==0.2.11 -asyncpg==0.30.0 +apscheduler==3.11.0 # 定时任务 +asyncmy==0.2.11 # 异步mysql操作数据库 +asyncpg==0.30.0 # 异步postgresql操作数据库 bcrypt==4.0.1 # 密码加密解析,切勿升级,如果升级,请同时升级python版本 bleach==6.3.0 # 过滤 HTML 标签 click==8.1.7 # 命令行参数解析 -croniter>=1.0.12,<5.0.0 # cron(与 prefect 约束一致;部署 requirements.txt 同源) +croniter>=1.0.12,<5.0.0 # cron(与 prefect 约束一致;部署 requirements.txt 同源) cryptography==45.0.2 # mysql8 密码加密 fastapi==0.115.2 # fastapi 框架 fastapi-limiter==0.1.6 # 接口限流 @@ -19,27 +19,26 @@ httpx==0.27.2 # HTTP 客户端 itsdangerous==2.2.0 # 用于安全处理各种数据,如密码、密钥等 jinja2==3.1.6 # 模板引擎 loguru==0.7.3 # 日志 -openai==2.28.0 +openai==2.28.0 # OpenAI API 客户端 openpyxl==3.1.5 # Excel pandas==2.2.3 # 数据处理 passlib==1.7.4 # 密码加密 -prefect>=3.5.0,<4 # 工作流编排(与 typer>=0.19 兼容;部署与 requirements.txt 一致) +prefect>=3.5.0,<4 # 工作流编排(与 typer>=0.19 兼容;部署与 requirements.txt 一致) pillow==11.0.0 # 图片处理 psutil==6.1.0 # 系统信息 -psycopg==3.3.2 -psycopg-binary==3.3.2 -pydantic-settings==2.5.2 # 配置设置 -pydantic-validation-decorator==0.1.4 # 模型验证 +psycopg==3.3.2 # PostgreSQL 异步操作数据库 +psycopg-binary==3.3.2 # PostgreSQL 异步操作数据库二进制版本 +pydantic-settings==2.5.2 # 配置设置 +pydantic-validation-decorator==0.1.4 # 模型验证 pyjwt==2.9.0 # OAuth2 -pymysql==1.1.2 +pymysql==1.1.2 # MySQL 异步操作数据库 python-multipart==0.0.9 # request.form() 对表单进行「解析」时安装 -redis==7.1.0 +redis==7.1.0 # Redis 异步操作数据库 rich==13.9.4 # 终端打印美化 -tomli>=2.0.1; python_version < "3.11" # 解析 plugin.toml(3.11+ 用标准库 tomllib) +tomli>=2.0.1; python_version < "3.15" # 解析 plugin.toml(3.11+ 用标准库 tomllib) sqlalchemy==2.0.45 # 数据库ORM -sqlglot[rs]==27.8.0 # sql 解析 +sqlglot[rs]==27.8.0 # sql 解析 typer==0.19.0 # 命令行工具 user-agents==2.2.0 # 获取用户UA uvicorn==0.30.6 # uvicorn web 框架 -websockets>=15.0.1,<16.0 # websocket(prefect>=3.5 需 >=15.0.1;与部署 requirements.txt 一致) -pyinstaller>=6.14.2 +websockets>=15.0.1,<16.0 # websocket(prefect>=3.5 需 >=15.0.1;与部署 requirements.txt 一致) diff --git a/backend/static/upload/help.png b/backend/static/upload/help.png new file mode 100644 index 00000000..c2ea0e12 Binary files /dev/null and b/backend/static/upload/help.png differ diff --git a/backend/uv.lock b/backend/uv.lock index 6f63f1a6..3ae366fc 100644 --- a/backend/uv.lock +++ b/backend/uv.lock @@ -285,7 +285,7 @@ dependencies = [ { name = "rich" }, { name = "sqlalchemy" }, { name = "sqlglot", extra = ["rs"] }, - { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "tomli", marker = "python_full_version < '3.15'" }, { name = "typer" }, { name = "user-agents" }, { name = "uvicorn" }, @@ -340,6 +340,7 @@ requires-dist = [ { name = "sqlalchemy", specifier = "==2.0.45" }, { name = "sqlglot", extras = ["rs"], specifier = "==27.8.0" }, { name = "tomli", marker = "python_full_version < '3.11'", specifier = ">=2.0.1" }, + { name = "tomli", marker = "python_full_version < '3.15'", specifier = ">=2.0.1" }, { name = "typer", specifier = "==0.19.0" }, { name = "user-agents", specifier = "==2.2.0" }, { name = "uvicorn", specifier = "==0.30.6" }, diff --git a/frontend/new-web/.env.development b/frontend/new-web/.env.development index 01c63815..0a6dd7d0 100755 --- a/frontend/new-web/.env.development +++ b/frontend/new-web/.env.development @@ -10,12 +10,12 @@ VITE_APP_TITLE = FastAPI Admin VITE_API_URL = / # 代理目标:本机后端(若出现 ENOTFOUND,说明上面域名在当前网络/DNS 下不可解析,改用本地或可用地址) -# VITE_API_BASE_URL = http://127.0.0.1:8000 -VITE_API_BASE_URL = https://service.fastapiadmin.com +VITE_API_BASE_URL = http://127.0.0.1:8001 +# VITE_API_BASE_URL = https://service.fastapiadmin.com # 是否删除控制台输出 VITE_DROP_CONSOLE = false # WebSocket 端点(AI对话功能需要配置) -# VITE_APP_WS_ENDPOINT = ws://localhost:8000 -VITE_APP_WS_ENDPOINT = wss://service.fastapiadmin.com +VITE_APP_WS_ENDPOINT = ws://localhost:8001 +# VITE_APP_WS_ENDPOINT = wss://service.fastapiadmin.com diff --git a/frontend/new-web/scripts/clean-dev.ts b/frontend/new-web/scripts/clean-dev.ts index 68fc02bb..758c11d2 100644 --- a/frontend/new-web/scripts/clean-dev.ts +++ b/frontend/new-web/scripts/clean-dev.ts @@ -155,13 +155,9 @@ const targets = [ "README.zh-CN.md", "CHANGELOG.md", "CHANGELOG.zh-CN.md", - "src/views/change", "src/views/safeguard", - "src/views/article", - "src/views/examples", "src/views/system/nested", "src/views/widgets", - "src/views/template", "src/views/dashboard/analysis", "src/views/dashboard/ecommerce", "src/mock/json", @@ -240,7 +236,7 @@ async function cleanRouteModules() { try { // 删除演示相关的路由模块 - const modulesToRemove = ["template.ts", "widgets.ts", "examples.ts", "article.ts"]; + const modulesToRemove = ["widgets.ts"]; for (const module of modulesToRemove) { const modulePath = path.join(modulesPath, module); @@ -251,40 +247,19 @@ async function cleanRouteModules() { } } - // 重写 dashboard.ts - 只保留 console - const dashboardContent = `import { AppRouteRecord } from '@/types/router' - -export const dashboardRoutes: AppRouteRecord = { - name: 'Dashboard', - path: '/dashboard', - component: '/index/index', - meta: { - title: 'menus.dashboard.title', - icon: 'ri:pie-chart-line', - roles: ['R_SUPER', 'R_ADMIN'] - }, - children: [ - { - path: 'console', - name: 'Console', - component: '/dashboard/console', - meta: { - title: 'menus.dashboard.console', - keepAlive: false, - fixedTab: true - } + // 仪表盘页面在 staticRoutes 根 Layout children 中挂载;删除独立 dashboard 模块文件 + try { + await fs.rm(path.join(modulesPath, "dashboard.ts"), { force: true }); + } catch { + // 忽略 } - ] -} -`; - await fs.writeFile(path.join(modulesPath, "dashboard.ts"), dashboardContent, "utf-8"); // 重写 system.ts - 移除 nested 嵌套菜单 const systemContent = `import { AppRouteRecord } from '@/types/router' export const systemRoutes: AppRouteRecord = { - path: '/system', - name: 'System', + path: '/art-system', + name: 'ArtSystem', component: '/index/index', meta: { title: 'menus.system.title', @@ -294,7 +269,7 @@ export const systemRoutes: AppRouteRecord = { children: [ { path: 'user', - name: 'User', + name: 'ArtTplUser', component: '/system/user', meta: { title: 'menus.system.user', @@ -304,7 +279,7 @@ export const systemRoutes: AppRouteRecord = { }, { path: 'role', - name: 'Role', + name: 'ArtTplRole', component: '/system/role', meta: { title: 'menus.system.role', @@ -312,20 +287,9 @@ export const systemRoutes: AppRouteRecord = { roles: ['R_SUPER'] } }, - { - path: 'user-center', - name: 'UserCenter', - component: '/system/user-center', - meta: { - title: 'menus.system.userCenter', - isHide: true, - keepAlive: true, - isHideTab: true - } - }, { path: 'menu', - name: 'Menus', + name: 'ArtTplMenus', component: '/system/menu', meta: { title: 'menus.system.menu', @@ -345,7 +309,6 @@ export const systemRoutes: AppRouteRecord = { // 重写 index.ts - 只导入保留的模块 const indexContent = `import { AppRouteRecord } from '@/types/router' -import { dashboardRoutes } from './dashboard' import { systemRoutes } from './system' import { resultRoutes } from './result' import { exceptionRoutes } from './exception' @@ -354,7 +317,6 @@ import { exceptionRoutes } from './exception' * 导出所有模块化路由 */ export const routeModules: AppRouteRecord[] = [ - dashboardRoutes, systemRoutes, resultRoutes, exceptionRoutes @@ -564,7 +526,7 @@ const fastEnterConfig: FastEnterConfig = { name: '个人中心', enabled: true, order: 4, - routeName: 'UserCenter' + routeName: 'Profile' } ] } @@ -639,7 +601,7 @@ async function showCleanupWarning() { { icon: icons.file, name: "演示页面", - desc: "widgets、template、article、examples、safeguard等页面", + desc: "widgets、article、examples、safeguard 等页面", color: theme.purple, }, { diff --git a/frontend/new-web/src/App.vue b/frontend/new-web/src/App.vue index a150ee4b..bc0f577b 100755 --- a/frontend/new-web/src/App.vue +++ b/frontend/new-web/src/App.vue @@ -7,7 +7,7 @@ shadow: 'never', }" > - - + diff --git a/frontend/new-web/src/api/auth.ts b/frontend/new-web/src/api/auth.ts deleted file mode 100644 index 355bae90..00000000 --- a/frontend/new-web/src/api/auth.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * 认证相关便捷接口(示例页等使用 `@/api/auth` 路径导入) - * 实现委托至 `@/api/module_system/auth` / `user` - */ -import AuthAPI, { type LoginFormData } from "@/api/module_system/auth"; -import UserAPI, { type UserInfo } from "@/api/module_system/user"; -import { ResultEnum } from "@/enums/api/result.enum"; - -export interface FetchLoginParams { - userName: string; - password: string; -} - -export async function fetchLogin(params: FetchLoginParams): Promise<{ - token: string; - refreshToken: string; -}> { - const captchaRes = await AuthAPI.getCaptcha(); - const captchaInfo = captchaRes.data?.data; - - const loginForm: LoginFormData = { - username: params.userName, - password: params.password, - captcha_key: captchaInfo?.key ?? "", - captcha: "", - remember: false, - login_type: "PC端", - }; - - const response = await AuthAPI.login(loginForm); - if (response.data.code !== ResultEnum.SUCCESS || !response.data.data) { - throw new Error(response.data.msg || "登录失败"); - } - - const data = response.data.data; - return { - token: data.access_token, - refreshToken: data.refresh_token, - }; -} - -/** 使用当前请求上下文中的 token 拉取用户信息(与 store.getUserInfo 数据来源一致) */ -export async function fetchGetUserInfo(): Promise { - const response = await UserAPI.getCurrentUserInfo(); - if (response.data.code !== ResultEnum.SUCCESS || response.data.data == null) { - throw new Error(response.data.msg || "获取用户信息失败"); - } - - const raw = response.data.data; - const next = { ...raw }; - delete next.menus; - return next as UserInfo; -} diff --git a/frontend/new-web/src/api/module_ai/chat.ts b/frontend/new-web/src/api/module_ai/chat.ts index cf4f112f..3d11a3bb 100644 --- a/frontend/new-web/src/api/module_ai/chat.ts +++ b/frontend/new-web/src/api/module_ai/chat.ts @@ -2,15 +2,16 @@ import request from "@/utils/http"; const API_PATH = "/ai/chat"; +/** 会话分页列表查询(列表接口) */ +export interface ChatSessionListQuery extends PageQuery { + title?: string; + created_at?: string[]; + updated_at?: string[]; +} + export const AiChatAPI = { - getSessionList(query: { - page_no: number; - page_size: number; - title?: string; - created_at?: string[]; - updated_at?: string[]; - }) { - return request>>({ + getSessionList(query: ChatSessionListQuery) { + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_application/portal.ts b/frontend/new-web/src/api/module_application/portal.ts index dfb9e1a2..70856982 100644 --- a/frontend/new-web/src/api/module_application/portal.ts +++ b/frontend/new-web/src/api/module_application/portal.ts @@ -19,7 +19,7 @@ export const ApplicationAPI = { * @param query 查询参数 */ listApp(query: ApplicationPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_example/demo.ts b/frontend/new-web/src/api/module_example/demo.ts index 92647c0c..94f456b4 100644 --- a/frontend/new-web/src/api/module_example/demo.ts +++ b/frontend/new-web/src/api/module_example/demo.ts @@ -4,7 +4,7 @@ const API_PATH = "/example/demo"; const DemoAPI = { getDemoList(query: DemoPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_example/demo01.ts b/frontend/new-web/src/api/module_example/demo01.ts index 5262431e..533ee23e 100644 --- a/frontend/new-web/src/api/module_example/demo01.ts +++ b/frontend/new-web/src/api/module_example/demo01.ts @@ -4,7 +4,7 @@ const API_PATH = "/example/demo01"; const Demo01API = { getDemo01List(query: Demo01PageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_generator/gencode.ts b/frontend/new-web/src/api/module_generator/gencode.ts index 747d5728..d8757039 100644 --- a/frontend/new-web/src/api/module_generator/gencode.ts +++ b/frontend/new-web/src/api/module_generator/gencode.ts @@ -5,7 +5,7 @@ const API_PATH = "/generator/gencode"; const GencodeAPI = { // 查询生成表数据 listTable(query: GenTablePageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, @@ -14,7 +14,7 @@ const GencodeAPI = { // 查询db数据库列表 listDbTable(query: DBTablePageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/db/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_monitor/online.ts b/frontend/new-web/src/api/module_monitor/online.ts index 5ce44ae9..db9e182f 100644 --- a/frontend/new-web/src/api/module_monitor/online.ts +++ b/frontend/new-web/src/api/module_monitor/online.ts @@ -5,7 +5,7 @@ const API_PATH = "/monitor/online"; const OnlineAPI = { // 查询在线用户列表 listOnline(query: OnlineUserPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_monitor/resource.ts b/frontend/new-web/src/api/module_monitor/resource.ts index 267e804f..cc54b305 100644 --- a/frontend/new-web/src/api/module_monitor/resource.ts +++ b/frontend/new-web/src/api/module_monitor/resource.ts @@ -8,7 +8,7 @@ export const ResourceAPI = { * @param query 查询参数 */ listResource(query: ResourcePageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_system/auth.ts b/frontend/new-web/src/api/module_system/auth.ts index d6dbc50a..acaad578 100644 --- a/frontend/new-web/src/api/module_system/auth.ts +++ b/frontend/new-web/src/api/module_system/auth.ts @@ -1,5 +1,4 @@ import request from "@/utils/http"; -// import request from '@/utils/http' const API_PATH = "/system/auth"; diff --git a/frontend/new-web/src/api/module_system/dict.ts b/frontend/new-web/src/api/module_system/dict.ts index e78731f0..6d34d3c7 100644 --- a/frontend/new-web/src/api/module_system/dict.ts +++ b/frontend/new-web/src/api/module_system/dict.ts @@ -4,7 +4,7 @@ const API_PATH = "/system/dict"; const DictAPI = { listDictType(query: DictPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/type/list`, method: "get", params: query, @@ -67,7 +67,7 @@ const DictAPI = { }, listDictData(query: DictDataPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/data/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_system/params.ts b/frontend/new-web/src/api/module_system/params.ts index 33db4f1b..236bd074 100644 --- a/frontend/new-web/src/api/module_system/params.ts +++ b/frontend/new-web/src/api/module_system/params.ts @@ -25,7 +25,7 @@ const ParamsAPI = { }, listParams(query: ConfigPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_system/position.ts b/frontend/new-web/src/api/module_system/position.ts index 0c0f11f6..931c3f3d 100644 --- a/frontend/new-web/src/api/module_system/position.ts +++ b/frontend/new-web/src/api/module_system/position.ts @@ -4,7 +4,7 @@ const API_PATH = "/system/position"; const PositionAPI = { listPosition(query?: PositionPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_system/role.ts b/frontend/new-web/src/api/module_system/role.ts index af936fe0..b427a3a5 100644 --- a/frontend/new-web/src/api/module_system/role.ts +++ b/frontend/new-web/src/api/module_system/role.ts @@ -4,7 +4,7 @@ const API_PATH = "/system/role"; const RoleAPI = { listRole(query?: TablePageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_system/tenant.ts b/frontend/new-web/src/api/module_system/tenant.ts index d5d5af93..3f2e0fdd 100644 --- a/frontend/new-web/src/api/module_system/tenant.ts +++ b/frontend/new-web/src/api/module_system/tenant.ts @@ -4,7 +4,7 @@ const API_PATH = "/system/tenant"; const TenantAPI = { listTenant(query?: TenantPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_system/user.ts b/frontend/new-web/src/api/module_system/user.ts index 954cefbb..dea87c69 100644 --- a/frontend/new-web/src/api/module_system/user.ts +++ b/frontend/new-web/src/api/module_system/user.ts @@ -61,7 +61,7 @@ export const UserAPI = { }, listUser(query: UserPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_task/cronjob/job.ts b/frontend/new-web/src/api/module_task/cronjob/job.ts index 5d3d661b..89b7beca 100644 --- a/frontend/new-web/src/api/module_task/cronjob/job.ts +++ b/frontend/new-web/src/api/module_task/cronjob/job.ts @@ -95,7 +95,7 @@ const JobAPI = { }, getJobLogList(query: JobLogPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/log/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_task/cronjob/node.ts b/frontend/new-web/src/api/module_task/cronjob/node.ts index 16213714..e9372f63 100644 --- a/frontend/new-web/src/api/module_task/cronjob/node.ts +++ b/frontend/new-web/src/api/module_task/cronjob/node.ts @@ -11,7 +11,7 @@ const NodeAPI = { }, listNode(query: NodePageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_task/workflow/definition.ts b/frontend/new-web/src/api/module_task/workflow/definition.ts index 5065a8c9..0c635c77 100644 --- a/frontend/new-web/src/api/module_task/workflow/definition.ts +++ b/frontend/new-web/src/api/module_task/workflow/definition.ts @@ -5,7 +5,7 @@ const API_PATH = "/task/workflow/definition"; const WorkflowDefinitionAPI = { getWorkflowList(query: WorkflowPageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/module_task/workflow/node-type.ts b/frontend/new-web/src/api/module_task/workflow/node-type.ts index fbbb9e3a..166f68d8 100644 --- a/frontend/new-web/src/api/module_task/workflow/node-type.ts +++ b/frontend/new-web/src/api/module_task/workflow/node-type.ts @@ -12,7 +12,7 @@ const WorkflowNodeTypeAPI = { }, getWorkflowNodeTypeList(query: WorkflowNodeTypePageQuery) { - return request>>({ + return request>>({ url: `${API_PATH}/list`, method: "get", params: query, diff --git a/frontend/new-web/src/api/system-manage.ts b/frontend/new-web/src/api/system-manage.ts deleted file mode 100644 index 6b974cff..00000000 --- a/frontend/new-web/src/api/system-manage.ts +++ /dev/null @@ -1,115 +0,0 @@ -/** - * 系统管理相关聚合接口(表格示例、views/system/* 等使用的 `@/api/system-manage`) - * 内部委托至 `module_system` 下各 API,并做分页字段与行展示字段映射。 - */ -import MenuAPI, { type MenuTable } from "@/api/module_system/menu"; -import RoleAPI, { type RoleTable, type TablePageQuery } from "@/api/module_system/role"; -import UserAPI, { type UserInfo, type UserPageQuery } from "@/api/module_system/user"; -import type { AppRouteRecord } from "@/types/router"; -import { ResultEnum } from "@/enums/api/result.enum"; - -function assertSuccess(res: { data: ApiResponse }, fallbackMsg: string): T { - if (res.data.code !== ResultEnum.SUCCESS || res.data.data == null) { - throw new Error(res.data.msg || fallbackMsg); - } - return res.data.data; -} - -/** useTable 传入 current / size 及演示页自定义筛选字段 */ -export async function fetchGetUserList(params: Record) { - const q: UserPageQuery = { - page_no: Number(params.current) || 1, - page_size: Number(params.size) || 20, - username: (params.userName ?? params.name) as string | undefined, - name: params.name as string | undefined, - mobile: (params.userPhone ?? params.phone) as string | undefined, - email: (params.userEmail ?? params.email) as string | undefined, - status: params.status as string | undefined, - }; - - const res = await UserAPI.listUser(q); - const page = assertSuccess(res, "获取用户列表失败"); - - const items = (page.items || []).map((u) => mapUserToListRow(u)); - - return { - items, - total: page.total, - page_no: page.page_no, - page_size: page.page_size, - has_next: page.has_next, - }; -} - -function mapUserToListRow(u: UserInfo) { - return { - id: u.id, - nickName: u.name ?? u.username, - userName: u.username, - userGender: u.gender, - userPhone: u.mobile, - userEmail: u.email, - avatar: u.avatar, - status: u.status, - }; -} - -export async function fetchGetRoleList(params: Record) { - const q: TablePageQuery = { - page_no: Number(params.current) || 1, - page_size: Number(params.size) || 20, - name: params.roleName as string | undefined, - status: - params.enabled !== undefined && params.enabled !== null && params.enabled !== "" - ? String(params.enabled) - : undefined, - }; - - const res = await RoleAPI.listRole(q); - const page = assertSuccess(res, "获取角色列表失败"); - - const items = (page.items || []).map((r) => mapRoleToListRow(r)); - - return { - items, - total: page.total, - page_no: page.page_no, - page_size: page.page_size, - has_next: page.has_next, - }; -} - -function mapRoleToListRow(r: RoleTable) { - return { - roleId: r.id, - roleName: r.name, - roleCode: r.code, - description: r.description, - enabled: r.status === "0", - createTime: r.created_time, - }; -} - -function mapMenuTableToRoute(m: MenuTable): AppRouteRecord { - const childrenRaw = m.children?.filter(Boolean) ?? []; - const children = childrenRaw.length ? childrenRaw.map(mapMenuTableToRoute) : undefined; - - return { - path: (m.route_path ?? "").trim(), - name: m.route_name, - meta: { - title: m.title ?? m.name ?? "", - icon: m.icon, - hidden: m.hidden, - keepAlive: m.keep_alive, - }, - children, - }; -} - -/** 菜单管理演示页:树形表格数据 */ -export async function fetchGetMenuList(): Promise { - const res = await MenuAPI.listMenu({}); - const tree = assertSuccess(res, "获取菜单失败"); - return (tree || []).map(mapMenuTableToRoute); -} diff --git a/frontend/new-web/src/components/AiAssistant/index.vue b/frontend/new-web/src/components/AiAssistant/index.vue index 801c0a95..c0c781ad 100644 --- a/frontend/new-web/src/components/AiAssistant/index.vue +++ b/frontend/new-web/src/components/AiAssistant/index.vue @@ -2,7 +2,7 @@
- - +
-
-
💡 试试这些命令:
- {{ example }} - +
- +
🎯 将要执行:
- + 跳转到: {{ response.action.pageName }} 并搜索: - {{ response.action.query }} + {{ response.action.query }}
- + 跳转至: {{ response.action.pageName }} 并搜索: - {{ response.action.query }} + {{ response.action.query }} - - + + 执行: {{ response.action.functionCall.name }}
- + 执行: {{ response.action.functionName }}
@@ -107,14 +107,14 @@ - +
diff --git a/frontend/new-web/src/components/Breadcrumb/index.vue b/frontend/new-web/src/components/Breadcrumb/index.vue index 3137c682..7d62bc1b 100644 --- a/frontend/new-web/src/components/Breadcrumb/index.vue +++ b/frontend/new-web/src/components/Breadcrumb/index.vue @@ -1,6 +1,6 @@ - - diff --git a/frontend/new-web/src/components/Crud/CrudContent.vue b/frontend/new-web/src/components/Crud/CrudContent.vue deleted file mode 100644 index 2c34c546..00000000 --- a/frontend/new-web/src/components/Crud/CrudContent.vue +++ /dev/null @@ -1,1141 +0,0 @@ - - - - - diff --git a/frontend/new-web/src/components/Crud/CrudFormModal.vue b/frontend/new-web/src/components/Crud/CrudFormModal.vue deleted file mode 100644 index 91d03ffb..00000000 --- a/frontend/new-web/src/components/Crud/CrudFormModal.vue +++ /dev/null @@ -1,243 +0,0 @@ - - - - - diff --git a/frontend/new-web/src/components/Crud/CrudLayout.vue b/frontend/new-web/src/components/Crud/CrudLayout.vue deleted file mode 100644 index 06a3bba9..00000000 --- a/frontend/new-web/src/components/Crud/CrudLayout.vue +++ /dev/null @@ -1,33 +0,0 @@ - - - - diff --git a/frontend/new-web/src/components/Crud/CrudSearch.vue b/frontend/new-web/src/components/Crud/CrudSearch.vue deleted file mode 100644 index c3534267..00000000 --- a/frontend/new-web/src/components/Crud/CrudSearch.vue +++ /dev/null @@ -1,428 +0,0 @@ - - - - - diff --git a/frontend/new-web/src/components/Crud/CrudToolbarActions.vue b/frontend/new-web/src/components/Crud/CrudToolbarActions.vue deleted file mode 100644 index f0d403e9..00000000 --- a/frontend/new-web/src/components/Crud/CrudToolbarActions.vue +++ /dev/null @@ -1,127 +0,0 @@ - - - - diff --git a/frontend/new-web/src/components/Crud/CrudToolbarLeft.vue b/frontend/new-web/src/components/Crud/CrudToolbarLeft.vue deleted file mode 100644 index 1783dc2d..00000000 --- a/frontend/new-web/src/components/Crud/CrudToolbarLeft.vue +++ /dev/null @@ -1,91 +0,0 @@ - - - - diff --git a/frontend/new-web/src/components/Crud/crudColsToArtTableColumns.ts b/frontend/new-web/src/components/Crud/crudColsToArtTableColumns.ts deleted file mode 100644 index bb0611f1..00000000 --- a/frontend/new-web/src/components/Crud/crudColsToArtTableColumns.ts +++ /dev/null @@ -1,111 +0,0 @@ -import dayjs from "dayjs"; -import type { ColumnOption } from "@/types/component"; -import type { IContentConfig } from "./types"; - -type CrudCol = IContentConfig["cols"][number]; - -/** 不参与透传给 ElTableColumn 的 Crud 扩展字段 */ -const CRUD_META_KEYS = new Set([ - "templet", - "slotName", - "selectList", - "dateFormat", - "operat", - "imageWidth", - "imageHeight", - "priceFormat", - "activeValue", - "inactiveValue", - "activeText", - "inactiveText", - "inputType", - "initFn", - "disabled", -]); - -function passthroughColumn(col: CrudCol): ColumnOption { - const raw = col as Record; - const out: Record = {}; - for (const key of Object.keys(raw)) { - if (CRUD_META_KEYS.has(key)) continue; - if (key === "show") continue; - out[key] = raw[key]; - } - if (col.show !== undefined) { - out.checked = col.show; - out.visible = col.show; - } - return out as ColumnOption; -} - -/** - * 将 Crud `cols` 转为 ArtTable / ArtTableHeader 使用的 `ColumnOption[]`。 - * - `templet: custom` → `useSlot` - * - `templet: date` → `formatter`(dayjs) - * - `templet: list` → `formatter`(selectList) - * - 其余带 `templet` 且无法在 Art 列模型表达的,仍走 `useSlot`,由页面提供同名插槽 - */ -export function mapCrudColsToArtColumns(items: CrudCol[]): ColumnOption[] { - const out: ColumnOption[] = []; - - for (const col of items) { - if (col.show === false) continue; - - if (col.type === "selection" || col.type === "index") { - out.push(passthroughColumn(col)); - continue; - } - - const base = passthroughColumn(col); - - if (col.templet === "custom" && col.prop) { - out.push({ - ...base, - useSlot: true, - slotName: col.slotName ?? col.prop, - }); - continue; - } - - if (col.templet === "date" && col.prop) { - const fmt = col.dateFormat ?? "YYYY-MM-DD HH:mm:ss"; - const prop = col.prop; - out.push({ - ...base, - formatter: (row: Record) => { - const v = row[prop]; - return v ? dayjs(v as string | number | Date).format(fmt) : ""; - }, - }); - continue; - } - - if (col.templet === "list" && col.prop && col.selectList) { - const prop = col.prop; - const sl = col.selectList as Record; - out.push({ - ...base, - formatter: (row: Record) => - sl[row[prop] as string] != null ? String(sl[row[prop] as string]) : "", - }); - continue; - } - - if (!col.templet) { - out.push(base); - continue; - } - - /* 其余 templet 优先走单元格展示兜底(复杂控件请改用 templet: custom + 插槽,或继续使用 legacy 表格) */ - if (col.prop) { - out.push({ - ...base, - formatter: (row: Record) => row[col.prop!] ?? "", - }); - } else { - out.push(base); - } - } - - return out; -} diff --git a/frontend/new-web/src/components/Crud/crudHelpers.ts b/frontend/new-web/src/components/Crud/crudHelpers.ts deleted file mode 100644 index 8f0cadd3..00000000 --- a/frontend/new-web/src/components/Crud/crudHelpers.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { IObject, IComponentType, ISearchComponent } from "./types"; -import { markRaw } from "vue"; -import { - ElCascader, - ElCheckbox, - ElCheckboxGroup, - ElDatePicker, - ElInput, - ElInputNumber, - ElInputTag, - ElOption, - ElRadio, - ElRadioGroup, - ElSelect, - ElSwitch, - ElText, - ElTimePicker, - ElTimeSelect, - ElTreeSelect, -} from "element-plus"; -import InputTag from "@/components/InputTag/index.vue"; -import IconSelect from "@/components/IconSelect/index.vue"; -import DatePicker from "@/components/DatePicker/index.vue"; - -export const getTooltipProps = (tips: string | IObject) => { - return typeof tips === "string" ? { content: tips } : tips; -}; - -export const modalComponentMap = new Map([ - ["input", markRaw(ElInput)], - ["select", markRaw(ElSelect)], - ["switch", markRaw(ElSwitch)], - ["cascader", markRaw(ElCascader)], - ["input-number", markRaw(ElInputNumber)], - ["input-tag", markRaw(InputTag)], - ["time-picker", markRaw(ElTimePicker)], - ["time-select", markRaw(ElTimeSelect)], - ["date-picker", markRaw(ElDatePicker)], - ["tree-select", markRaw(ElTreeSelect)], - ["custom-tag", markRaw(InputTag)], - ["text", markRaw(ElText)], - ["radio", markRaw(ElRadioGroup)], - ["checkbox", markRaw(ElCheckboxGroup)], - ["icon-select", markRaw(IconSelect)], - ["custom", ""], -]); - -export const searchComponentMap = new Map([ - ["input", markRaw(ElInput)], - ["select", markRaw(ElSelect)], - ["cascader", markRaw(ElCascader)], - ["input-number", markRaw(ElInputNumber)], - ["date-picker", markRaw(DatePicker)], - ["time-picker", markRaw(ElTimePicker)], - ["time-select", markRaw(ElTimeSelect)], - ["tree-select", markRaw(ElTreeSelect)], - ["input-tag", markRaw(ElInputTag)], - ["custom-tag", markRaw(InputTag)], -]); - -export const childrenMap = new Map([ - ["select", markRaw(ElOption)], - ["radio", markRaw(ElRadio)], - ["checkbox", markRaw(ElCheckbox)], -]); diff --git a/frontend/new-web/src/components/Crud/crudSearchFormToArt.ts b/frontend/new-web/src/components/Crud/crudSearchFormToArt.ts deleted file mode 100644 index 7d5f6d73..00000000 --- a/frontend/new-web/src/components/Crud/crudSearchFormToArt.ts +++ /dev/null @@ -1,240 +0,0 @@ -import type { SearchFormItem } from "@/components/Core/forms/art-search-bar/index.vue"; -import type { IFormItems, ISearchComponent } from "./types"; -import { unref } from "vue"; - -/** - * 与 legacy `CrudSearch` onMounted 赋值逻辑一致,需在挂载 ArtSearchBar 之前同步执行, - * 以便 ArtSearchBar 内部 `initialModelValue` 快照正确。 - */ -export function createCrudSearchInitialParams( - items: IFormItems, - getCustomComponent: (componentName: string) => unknown -): Record { - const q: Record = {}; - for (const item of items) { - if (getCustomComponent(item.type ?? "")) { - q[item.prop] = item.initialValue ?? null; - } else if (["input-tag", "custom-tag", "cascader"].includes(item?.type ?? "")) { - q[item.prop] = Array.isArray(item.initialValue) ? item.initialValue : []; - } else if ( - item.type === "date-picker" && - String(item.attrs?.type ?? "") - .toLowerCase() - .includes("range") - ) { - q[item.prop] = item.initialValue ?? []; - } else if (item.type === "select") { - q[item.prop] = item.initialValue !== undefined ? item.initialValue : null; - } else if (item.type === "input-number") { - q[item.prop] = item.initialValue ?? null; - } else { - q[item.prop] = item.initialValue ?? ""; - } - } - return q; -} - -export type MapCrudSearchToArtOptions = { - customComponents?: Record; - /** 筛选控件最大宽度,透传到各 `props.style.maxWidth`(`false` 表示不限制) */ - fieldMaxWidth?: string | false; -}; - -function artSpanFromCol(col: unknown): number | undefined { - if (col && typeof col === "object" && "span" in col) { - const s = (col as { span?: number }).span; - return typeof s === "number" ? s : undefined; - } - return undefined; -} - -function mapDatePickerType(attrs: IFormItems[number]["attrs"]): string { - const t = String(attrs?.type ?? "date").toLowerCase(); - if (t.includes("datetimerange")) return "datetimerange"; - if (t.includes("daterange")) return "daterange"; - if (t.includes("datetime")) return "datetime"; - return "date"; -} - -/** - * 将 Crud `ISearchConfig.formItems` 转为 ArtSearchBar `items`。 - */ -export function mapCrudSearchFormItemsToArt( - formItems: IFormItems, - options?: MapCrudSearchToArtOptions -): SearchFormItem[] { - const { customComponents, fieldMaxWidth } = options ?? {}; - - const maxStyle = - fieldMaxWidth === undefined || fieldMaxWidth === false - ? undefined - : { maxWidth: fieldMaxWidth }; - - return formItems.map((item) => { - const attrs = item.attrs ?? {}; - const prevStyle = attrs.style && typeof attrs.style === "object" ? attrs.style : {}; - const baseProps = { - ...attrs, - ...(maxStyle ? { style: { ...prevStyle, ...maxStyle } } : {}), - }; - - const custom = item.type ? customComponents?.[item.type as string] : undefined; - if (custom) { - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span: artSpanFromCol(item.col), - render: custom, - props: baseProps, - }; - } - - const span = artSpanFromCol(item.col); - const optsRaw = item.options ? unref(item.options) : undefined; - const selectOptions = Array.isArray(optsRaw) - ? optsRaw.map((o) => ({ label: o.label, value: o.value, ...o })) - : undefined; - - switch (item.type) { - case "input": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "input", - props: baseProps, - }; - case "select": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "select", - props: { ...baseProps, ...(selectOptions ? { options: selectOptions } : {}) }, - }; - case "input-number": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "number", - props: baseProps, - }; - case "cascader": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "cascader", - props: baseProps, - }; - case "tree-select": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "treeselect", - props: baseProps, - }; - case "date-picker": { - const artType = mapDatePickerType(item.attrs); - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: artType, - props: baseProps, - }; - } - case "time-picker": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "timepicker", - props: baseProps, - }; - case "time-select": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "timeselect", - props: baseProps, - }; - case "input-tag": - case "custom-tag": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "inputTag", - props: baseProps, - }; - case "radio": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "radiogroup", - props: { ...baseProps, ...(selectOptions ? { options: selectOptions } : {}) }, - }; - case "checkbox": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "checkboxgroup", - props: { ...baseProps, ...(selectOptions ? { options: selectOptions } : {}) }, - }; - case "switch": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "switch", - props: baseProps, - }; - case "rate": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "rate", - props: baseProps, - }; - case "slider": - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "slider", - props: baseProps, - }; - default: - return { - key: item.prop, - label: item.label, - hidden: item.hidden, - span, - type: "input", - props: baseProps, - }; - } - }); -} diff --git a/frontend/new-web/src/components/Crud/index.ts b/frontend/new-web/src/components/Crud/index.ts deleted file mode 100644 index 5dfa8dfd..00000000 --- a/frontend/new-web/src/components/Crud/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * CRUD 列表模块(目录名 `CURD`)。组件与组合式函数统一使用 **Crud** 拼写(勿写 Curd)。 - */ -export { default as CrudLayout } from "./CrudLayout.vue"; -export { default as CrudArtTableDemo } from "./CrudArtTableDemo.vue"; -export { default as CrudSearch } from "./CrudSearch.vue"; -export { default as CrudContent } from "./CrudContent.vue"; -export { default as CrudFormModal } from "./CrudFormModal.vue"; -export { default as CrudExportModal } from "./CrudExportModal.vue"; -export { default as CrudImportModal } from "./CrudImportModal.vue"; -export { default as CrudToolbarLeft } from "./CrudToolbarLeft.vue"; -export { default as CrudToolbarActions } from "./CrudToolbarActions.vue"; - -export { useCrudList } from "./useCrudList"; -export { useCrudArtTableDemo } from "./useCrudArtTableDemo"; -export type { DemoUserRow } from "./useCrudArtTableDemo"; - -export { childrenMap, getTooltipProps, modalComponentMap, searchComponentMap } from "./crudHelpers"; - -export * from "./types"; diff --git a/frontend/new-web/src/components/Crud/useCrudArtTableDemo.ts b/frontend/new-web/src/components/Crud/useCrudArtTableDemo.ts deleted file mode 100644 index 3830c176..00000000 --- a/frontend/new-web/src/components/Crud/useCrudArtTableDemo.ts +++ /dev/null @@ -1,483 +0,0 @@ -/** - * CrudArtTableDemo(Art 栈)演示:ArtSearchBar + ArtTableHeader + ArtTable + useTable。 - */ -import { h, ref, computed } from "vue"; -import type { TableError } from "@/utils/table/tableUtils"; -import { ElMessage, ElMessageBox } from "element-plus"; -import { useTable } from "@/hooks/core/useTable"; -import { fetchGetUserList } from "@/api/system-manage"; -import { ACCOUNT_TABLE_DATA } from "@/mock/temp/formData"; -import { getColumnKey } from "@/hooks/core/useTableColumns"; - -export interface DemoUserRow { - id?: number; - nickName?: string; - userName: string; - userGender?: string; - userPhone?: string; - userEmail?: string; - avatar?: string; - status?: string; - department?: string; - score?: number; -} - -export function useCrudArtTableDemo() { - const selectedRows = ref([]); - const tableRef = ref(); - const searchBarRef = ref(); - const phoneSearch = ref(""); - - const tableConfig = ref({ - height: "100%", - fixedHeight: false, - }); - - const computedTableHeight = computed(() => (tableConfig.value.fixedHeight ? "500px" : "")); - - const searchFormState = ref({ - name: "", - phone: "", - status: "1", - department: "", - daterange: ["2025-01-01", "2025-02-10"] as [string, string], - }); - - const rules = { - name: [{ required: true, message: "请输入用户名", trigger: "blur" }], - phone: [ - { required: true, message: "请输入手机号", trigger: "blur" }, - { pattern: /^1[3456789]\d{9}$/, message: "请输入正确的手机号", trigger: "blur" }, - ], - }; - - const searchItems = computed(() => [ - { - key: "name", - label: "用户名", - type: "input", - props: { placeholder: "请输入用户名" }, - }, - { - key: "phone", - label: "手机号", - type: "input", - props: { placeholder: "请输入手机号", maxlength: "11" }, - }, - { - key: "status", - label: "状态", - type: "select", - options: [ - { label: "全部", value: "" }, - { label: "在线", value: "1" }, - { label: "离线", value: "2" }, - { label: "异常", value: "3" }, - { label: "注销", value: "4" }, - ], - }, - { - key: "department", - label: "部门", - type: "select", - options: [ - { label: "全部", value: "" }, - { label: "技术部", value: "技术部" }, - { label: "产品部", value: "产品部" }, - { label: "运营部", value: "运营部" }, - { label: "市场部", value: "市场部" }, - { label: "设计部", value: "设计部" }, - ], - }, - { - key: "daterange", - label: "日期范围", - type: "daterange", - props: { - type: "daterange", - startPlaceholder: "开始日期", - endPlaceholder: "结束日期", - valueFormat: "YYYY-MM-DD", - }, - }, - ]); - - const USER_STATUS_CONFIG = { - "1": { type: "success" as const, text: "在线" }, - "2": { type: "info" as const, text: "离线" }, - "3": { type: "warning" as const, text: "异常" }, - "4": { type: "danger" as const, text: "注销" }, - } as const; - - const getUserStatusConfig = (status: string) => - USER_STATUS_CONFIG[status as keyof typeof USER_STATUS_CONFIG] ?? { - type: "info" as const, - text: "未知", - }; - - const exportColumns = computed(() => ({ - userName: { title: "用户名", width: 15 }, - userEmail: { title: "邮箱", width: 20 }, - userPhone: { title: "手机号", width: 15 }, - userGender: { title: "性别", width: 10 }, - department: { title: "部门", width: 15 }, - status: { - title: "状态", - width: 10, - formatter: (value: string) => getUserStatusConfig(value).text, - }, - })); - - const buildSearchParams = (params: typeof searchFormState.value) => { - const { daterange, ...filtersParams } = params; - const [startTime, endTime] = Array.isArray(daterange) ? daterange : [null, null]; - return { ...filtersParams, startTime, endTime }; - }; - - const { - data, - loading, - pagination, - handleSizeChange, - handleCurrentChange, - replaceSearchParams, - resetSearchParams, - getData, - getDataDebounced, - clearData, - refreshData, - refreshCreate, - refreshUpdate, - refreshRemove, - columns, - columnChecks, - addColumn, - removeColumn, - updateColumn, - toggleColumn, - resetColumns, - reorderColumns, - getColumnConfig, - getAllColumns, - } = useTable({ - core: { - apiFn: (params) => fetchGetUserList(params), - apiParams: { - current: 1, - size: 20, - ...searchFormState.value, - }, - excludeParams: ["daterange"], - immediate: true, - columnsFactory: () => [ - { type: "selection", width: 50 }, - { type: "globalIndex", width: 60, label: "序号" }, - { - prop: "avatar", - label: "用户信息", - minWidth: 200, - useSlot: true, - useHeaderSlot: true, - sortable: false, - }, - { - prop: "userGender", - label: "性别", - sortable: true, - formatter: (row: unknown) => String((row as DemoUserRow).userGender ?? "未知"), - }, - { - prop: "userPhone", - label: "手机号", - useHeaderSlot: true, - sortable: true, - }, - { prop: "department", label: "部门", sortable: true }, - { prop: "score", label: "评分", useSlot: true, sortable: true }, - { prop: "status", label: "状态", useSlot: true, sortable: true }, - { - prop: "operation", - label: "操作", - width: 190, - useSlot: true, - fixed: "right", - }, - ], - }, - transform: { - dataTransformer: (records) => { - if (!Array.isArray(records)) return []; - return records.map((item: unknown, index: number) => { - const row = item as DemoUserRow; - return { - ...row, - avatar: ACCOUNT_TABLE_DATA[index % ACCOUNT_TABLE_DATA.length].avatar, - department: ["技术部", "产品部", "运营部", "市场部", "设计部"][ - Math.floor(Math.random() * 5) - ], - score: Math.floor(Math.random() * 5) + 1, - status: ["1", "2", "3", "4"][Math.floor(Math.random() * 4)], - }; - }) as typeof records; - }, - }, - performance: { - enableCache: true, - cacheTime: 5 * 60 * 1000, - debounceTime: 300, - maxCacheSize: 100, - }, - hooks: { - onError: (error: TableError) => { - ElMessage.error(error.message); - }, - }, - debug: { - enableLog: false, - logLevel: "info", - }, - }); - - const artPagination = computed(() => { - const p = pagination as unknown as Record; - return { - current: Number(p.current ?? p.page_no ?? 1), - size: Number(p.size ?? p.page_size ?? 10), - total: Number(p.total ?? 0), - }; - }); - - interface SortInfo { - prop: string; - order: "ascending" | "descending" | null; - } - - const handleSelectionChange = (selection: DemoUserRow[]) => { - selectedRows.value = selection; - }; - - const handleRowClick = (row: DemoUserRow) => { - console.log("行点击:", row.userName); - }; - - const handleHeaderClick = (column: { label: string; property: string }) => { - console.log("表头点击:", column.label); - }; - - const handleSortChange = (sortInfo: SortInfo) => { - console.log("排序:", sortInfo.prop, sortInfo.order); - }; - - const handleSearch = async () => { - await searchBarRef.value?.validate?.(); - replaceSearchParams(buildSearchParams(searchFormState.value)); - getData(); - }; - - const handleReset = () => { - resetSearchParams(); - }; - - const handlePhoneSearch = (value: string) => { - searchFormState.value.phone = value; - replaceSearchParams(buildSearchParams(searchFormState.value)); - getDataDebounced(); - }; - - const handleRefresh = () => { - refreshData(); - }; - - const handleAdd = () => { - ElMessage.success("新增用户成功"); - refreshCreate(); - }; - - const handleEdit = (row: DemoUserRow) => { - ElMessage.success(`编辑用户 ${row.userName} 成功`); - setTimeout(() => refreshUpdate(), 1000); - }; - - const handleDelete = async (row: DemoUserRow) => { - try { - await ElMessageBox.confirm(`确定要删除用户 ${row.userName} 吗?`, "警告", { - confirmButtonText: "确定", - cancelButtonText: "取消", - type: "warning", - }); - ElMessage.success("删除成功"); - setTimeout(() => refreshRemove(), 1000); - } catch { - ElMessage.info("已取消删除"); - } - }; - - const handleView = (row: DemoUserRow) => { - ElMessage.info(`查看用户 ${row.userName}`); - }; - - const handleBatchDelete = async () => { - try { - await ElMessageBox.confirm( - `确定要删除选中的 ${selectedRows.value.length} 个用户吗?`, - "警告", - { - confirmButtonText: "确定", - cancelButtonText: "取消", - type: "warning", - } - ); - ElMessage.success(`批量删除 ${selectedRows.value.length} 个用户成功`); - selectedRows.value = []; - setTimeout(() => refreshRemove(), 1000); - } catch { - ElMessage.info("已取消删除"); - } - }; - - const handleExportSuccess = (_filename: string, count: number) => { - ElMessage.success(`导出 ${count} 条数据成功`); - }; - - const handleImportSuccess = (rows: Record[]) => { - ElMessage.success(`导入 ${rows.length} 条数据成功`); - refreshCreate(); - }; - - const handleImportError = (error: Error) => { - ElMessage.error(`导入失败:${error.message}`); - }; - - const handleClearData = () => { - clearData(); - ElMessage.info("数据已清空"); - }; - - const handleColumnCommand = (command: string): void => { - switch (command) { - case "addColumn": { - addColumn?.({ - prop: "remark", - label: "备注", - width: 150, - formatter: () => h("span", { style: "color: #999" }, "暂无备注"), - }); - ElMessage.success('已新增"备注"列'); - break; - } - case "batchAddColumns": { - addColumn?.( - [ - { - prop: "remark", - label: "备注", - width: 150, - formatter: () => h("span", { style: "color: #999" }, "暂无备注"), - }, - { - prop: "tags", - label: "标签", - width: 120, - formatter: () => h("span", { style: "color: #67c23a" }, "新用户"), - }, - ], - 5 - ); - ElMessage.success('已批量新增"备注"和"标签"列'); - break; - } - case "toggleColumn": { - if (getColumnConfig?.("userPhone")) { - toggleColumn?.("userPhone"); - ElMessage.success("已切换手机号列显示状态"); - } - break; - } - case "batchToggleColumns": { - toggleColumn?.(["userGender", "userPhone"]); - ElMessage.success("已批量切换性别和手机号列显示状态"); - break; - } - case "removeColumn": { - removeColumn?.("status"); - ElMessage.success("已删除状态列"); - break; - } - case "batchRemoveColumns": { - removeColumn?.(["status", "score"]); - ElMessage.success("已批量删除状态和评分列"); - break; - } - case "updateColumn": { - updateColumn?.("userPhone", { label: "联系电话", width: 140 }); - ElMessage.success('手机号列已更新为"联系电话"'); - break; - } - case "batchUpdateColumns": { - updateColumn?.([ - { prop: "userGender", updates: { width: 200, label: "性别-已更新", sortable: false } }, - { prop: "userPhone", updates: { width: 200, label: "手机号-已更新", sortable: false } }, - ]); - ElMessage.success("已批量更新性别和手机号列"); - break; - } - case "reorderColumns": { - const allCols = getAllColumns?.(); - if (allCols) { - const genderIndex = allCols.findIndex((col) => getColumnKey(col) === "userGender"); - const phoneIndex = allCols.findIndex((col) => getColumnKey(col) === "userPhone"); - if (genderIndex !== -1 && phoneIndex !== -1) { - reorderColumns?.(genderIndex, phoneIndex); - ElMessage.success("已交换性别和手机号列位置"); - } - } - break; - } - case "resetColumns": { - resetColumns?.(); - ElMessage.success("已重置所有列配置"); - break; - } - default: - console.warn("未知的列配置命令:", command); - } - }; - - return { - searchBarRef, - searchFormState, - searchItems, - rules, - phoneSearch, - selectedRows, - tableRef, - columnChecks, - loading, - data, - artPagination, - columns, - computedTableHeight, - exportColumns, - getUserStatusConfig, - handleSearch, - handleReset, - handlePhoneSearch, - handleRefresh, - handleSelectionChange, - handleRowClick, - handleHeaderClick, - handleSortChange, - handleSizeChange, - handleCurrentChange, - handleAdd, - handleEdit, - handleDelete, - handleView, - handleBatchDelete, - handleExportSuccess, - handleImportSuccess, - handleImportError, - handleClearData, - handleColumnCommand, - }; -} diff --git a/frontend/new-web/src/components/Crud/useCrudList.ts b/frontend/new-web/src/components/Crud/useCrudList.ts deleted file mode 100644 index 518ac6d3..00000000 --- a/frontend/new-web/src/components/Crud/useCrudList.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { ElMessage } from "element-plus"; -import { ref } from "vue"; -import type { IObject, CrudContentInstance, CrudSearchInstance } from "./types"; - -/** - * 仅列表查询区 + 表格区时复用:searchRef / contentRef 与查询、重置拉数逻辑。 - * 合并 `CrudSearch` 查询参数与 `CrudContent.getFilterParams()`(表头筛选等),与 usePage 中同名逻辑一致。 - * 业务页可替换手写 `handleQueryClick` / `handleResetClick` + 双 ref,参见 `module_example/demo`。 - */ -export function useCrudList() { - const searchRef = ref(); - const contentRef = ref(); - - function handleQueryClick(queryParams: IObject) { - try { - const filterParams = contentRef.value?.getFilterParams() || {}; - contentRef.value?.fetchPageData({ ...queryParams, ...filterParams }, true); - } catch (error) { - console.error("查询数据失败:", error); - ElMessage.error("查询数据失败: " + (error instanceof Error ? error.message : String(error))); - } - } - - function handleResetClick(queryParams: IObject) { - try { - const filterParams = contentRef.value?.getFilterParams() || {}; - contentRef.value?.fetchPageData({ ...queryParams, ...filterParams }, true); - } catch (error) { - console.error("重置数据失败:", error); - ElMessage.error("重置数据失败: " + (error instanceof Error ? error.message : String(error))); - } - } - - /** 弹窗提交后等与「查询」同参刷新:合并搜索条件 + 表头筛选 */ - function refreshList() { - try { - const q = searchRef.value?.getQueryParams() ?? {}; - const f = contentRef.value?.getFilterParams() ?? {}; - contentRef.value?.fetchPageData({ ...q, ...f }, true); - } catch (error) { - console.error("刷新列表失败:", error); - ElMessage.error("刷新列表失败: " + (error instanceof Error ? error.message : String(error))); - } - } - - return { - searchRef, - contentRef, - handleQueryClick, - handleResetClick, - refreshList, - }; -} diff --git a/frontend/new-web/src/components/DatePicker/index.vue b/frontend/new-web/src/components/DatePicker/index.vue index 6982b4d0..1c791696 100644 --- a/frontend/new-web/src/components/DatePicker/index.vue +++ b/frontend/new-web/src/components/DatePicker/index.vue @@ -1,7 +1,7 @@ diff --git a/frontend/new-web/src/components/core/tables/art-table-header/index.vue b/frontend/new-web/src/components/core/tables/art-table-header/index.vue index 97eddc1e..e24bb1e6 100644 --- a/frontend/new-web/src/components/core/tables/art-table-header/index.vue +++ b/frontend/new-web/src/components/core/tables/art-table-header/index.vue @@ -6,6 +6,7 @@
+
+ +
+
@@ -49,6 +53,7 @@ +
diff --git a/frontend/new-web/src/components/core/text-effect/art-festival-text-scroll/index.vue b/frontend/new-web/src/components/core/text-effect/art-festival-text-scroll/index.vue index 704a61c9..27af1494 100644 --- a/frontend/new-web/src/components/core/text-effect/art-festival-text-scroll/index.vue +++ b/frontend/new-web/src/components/core/text-effect/art-festival-text-scroll/index.vue @@ -1,32 +1,55 @@ - + diff --git a/frontend/new-web/src/config/modules/fastEnter.ts b/frontend/new-web/src/config/modules/fastEnter.ts index cb638a70..67a0c8dd 100644 --- a/frontend/new-web/src/config/modules/fastEnter.ts +++ b/frontend/new-web/src/config/modules/fastEnter.ts @@ -107,13 +107,13 @@ const fastEnterConfig: FastEnterConfig = { name: "定价", enabled: true, order: 4, - routeName: "Pricing", + routeName: "DashboardPricing", }, { name: "个人中心", enabled: true, order: 5, - routeName: "UserCenter", + routeName: "Profile", }, { name: "留言管理", diff --git a/frontend/new-web/src/config/modules/festival.ts b/frontend/new-web/src/config/modules/festival.ts index 4bebc975..dd82d40c 100644 --- a/frontend/new-web/src/config/modules/festival.ts +++ b/frontend/new-web/src/config/modules/festival.ts @@ -12,6 +12,8 @@ * - image: 烟花图片(需要预先导入) * - scrollText: 滚动显示的祝福文本 * - count: 烟花播放次数(可选,默认为 3 次) + * - skipFireworks: 为 true 时不放烟花,仅显示 scrollText(适合长期顶栏公告) + * - scrollText 可使用占位符 {{version}}、{{introduceUrl}}(构建时替换为版本号与演示链接) * * ## 注意事项 * @@ -26,11 +28,37 @@ import { FestivalConfig } from "@/types/config"; // 导入烟花图片(根据需要取消注释) -// import sd from '@imgs/ceremony/sd.png' -// import yd from '@imgs/ceremony/yd.png' +// import sd from "@imgs/ceremony/sd.png"; +// import yd from "@imgs/ceremony/yd.png"; export const festivalConfigList: FestivalConfig[] = [ - // 跨日期示例 + /** + * 全年默认顶栏公告(与多条日期重叠时,区间更短的配置优先,例如上面的五月条) + */ + { + name: "系统公告", + date: "2026-01-01", + endDate: "2026-12-31", + image: "", + skipFireworks: true, + count: 3, + scrollText: + '🎉 {{version}}版本正式上线!能力全面提升,配套完整交付方案,助力高效开发与商业落地。 👉 立即体验演示', + }, + /** + * 五月示例(2026-05-01~05-31 生效,含当前日期则会出现节日滚动条;烟花需当日首次进入且未在同日标记已播) + * 上线前请改成真实活动日期与文案;需要自定义烟花图时在配置里 import 并填入 image + */ + // { + // name: "五月温馨提示", + // date: "2026-05-04", + // endDate: "2026-05-05", + // image: yd, + // count: 3, + // scrollText: + // "🎉 五月快乐!FastAPI Admin 祝您工作顺利、迭代顺利。本月请关注备份与安全策略,遇到问题可先查看文档或联系运维。", + // }, + // 单日示例(圣诞节):需取消注释并 import 图片 // { // name: 'v3.0 Sass 升级至 TailwindCSS', // date: '2025-11-03', diff --git a/frontend/new-web/src/hooks/core/useCeremony.ts b/frontend/new-web/src/hooks/core/useCeremony.ts index abeffafc..b159ecc3 100644 --- a/frontend/new-web/src/hooks/core/useCeremony.ts +++ b/frontend/new-web/src/hooks/core/useCeremony.ts @@ -46,6 +46,7 @@ import { computed } from "vue"; import { useSettingsStore } from "@/store/modules/setting.store"; import { mittBus } from "@/utils/sys"; import { festivalConfigList } from "@/config/modules/festival"; +import { formatToDate } from "@/utils/common/dateUtil"; /** * 节日庆祝配置常量 @@ -95,19 +96,32 @@ export function useCeremony() { return current >= start && current <= end; }; + /** 区间越短越「具体」,重叠时优先展示(如五月条优先于全年公告) */ + const festivalRangeSpanDays = (item: (typeof festivalConfigList)[number]): number => { + if (!item.endDate) return 1; + const s = new Date(item.date).getTime(); + const e = new Date(item.endDate).getTime(); + return Math.max(1, Math.round((e - s) / 86400000) + 1); + }; + /** - * 获取当前日期对应的节日数据 + * 获取当前日期对应的节日数据(同日多条命中时取区间最短的一条) */ const currentFestivalData = computed(() => { const currentDate = useDateFormat(new Date(), "YYYY-MM-DD").value; - return festivalConfigList.find((item) => isDateInRange(currentDate, item.date, item.endDate)); + const matches = festivalConfigList.filter((item) => + isDateInRange(currentDate, item.date, item.endDate) + ); + if (!matches.length) return undefined; + matches.sort((a, b) => festivalRangeSpanDays(a) - festivalRangeSpanDays(b)); + return matches[0]; }); /** - * 更新节日日期到 store + * 标记「今日已完成烟花流程」,用于 store 按自然日防抖(与节日配置的 date 字段无关) */ const updateFestivalDate = () => { - settingStore.setFestivalDate(currentFestivalData.value?.date || ""); + settingStore.setFestivalDate(formatToDate(new Date())); }; /** @@ -151,10 +165,30 @@ export function useCeremony() { }; /** - * 开启节日庆祝 + * 顶栏纯文案关闭(仅 skipFireworks)持久化 key + */ + const festivalScrollDismissKey = (cur: (typeof festivalConfigList)[number]): string => + `festival_scroll_dismissed_${cur.date}_${cur.endDate ?? ""}`; + + /** + * 开启节日庆祝:skipFireworks 时直接显示滚动条;否则走烟花再出字 */ const openFestival = () => { - if (!currentFestivalData.value || !isShowFireworks.value) { + const cur = currentFestivalData.value; + if (!cur) return; + + if (cur.skipFireworks) { + if ( + typeof localStorage !== "undefined" && + localStorage.getItem(festivalScrollDismissKey(cur)) === "1" + ) { + return; + } + settingStore.setShowFestivalText(true); + return; + } + + if (!isShowFireworks.value) { return; } @@ -171,7 +205,15 @@ export function useCeremony() { fireworksInterval = null; } settingStore.setShowFestivalText(false); - updateFestivalDate(); + }; + + /** 关闭顶栏滚动:skipFireworks 时写入 localStorage,下次不再自动展开 */ + const closeFestivalScroll = () => { + const cur = currentFestivalData.value; + settingStore.setShowFestivalText(false); + if (cur?.skipFireworks && typeof localStorage !== "undefined") { + localStorage.setItem(festivalScrollDismissKey(cur), "1"); + } }; return { @@ -180,5 +222,7 @@ export function useCeremony() { holidayFireworksLoaded, currentFestivalData, isShowFireworks, + festivalScrollDismissKey, + closeFestivalScroll, }; } diff --git a/frontend/new-web/src/layouts/art-screen-lock/index.vue b/frontend/new-web/src/layouts/art-screen-lock/index.vue index 8d90a343..cfc0e3a1 100644 --- a/frontend/new-web/src/layouts/art-screen-lock/index.vue +++ b/frontend/new-web/src/layouts/art-screen-lock/index.vue @@ -20,7 +20,7 @@
- {{ t("navbar.lock") }} - +
- + {{ t("lock.unlock") }}
@@ -93,7 +93,7 @@ {{ t("lock.message") }}
- {{ t("common.back") }} - - + - + {{ t("lock.entrySystem") }} - +
@@ -143,7 +143,7 @@ import { Lock } from "@element-plus/icons-vue"; import type { FormInstance, FormRules } from "element-plus"; import { ElInput } from "element-plus"; -import EnhancedDialog from "@/components/Core/overlays/EnhancedDialog.vue"; +import ArtDialog from "@/components/Core/modal/art-dialog/index.vue"; import { useI18n } from "vue-i18n"; import { useRoute, useRouter } from "vue-router"; import CryptoJS from "crypto-js"; diff --git a/frontend/new-web/src/layouts/art-settings-panel/widget/SettingActions.vue b/frontend/new-web/src/layouts/art-settings-panel/widget/SettingActions.vue index 8a0e4732..cfad733d 100644 --- a/frontend/new-web/src/layouts/art-settings-panel/widget/SettingActions.vue +++ b/frontend/new-web/src/layouts/art-settings-panel/widget/SettingActions.vue @@ -93,7 +93,11 @@ const CONFIG_ITEMS: ConfigItem[] = [ { comment: "标签页样式", key: "tabStyle" }, { comment: "自定义圆角", key: "customRadius" }, { comment: "容器宽度", key: "containerWidth", enumMap: ENUM_MAPS.containerWidth }, - { comment: "节日日期", key: "festivalDate", forceValue: "" }, + { + comment: "上次完成烟花播放的自然日(YYYY-MM-DD),留空可重新触发", + key: "festivalDate", + forceValue: "", + }, ]; /** diff --git a/frontend/new-web/src/locales/langs/en.json b/frontend/new-web/src/locales/langs/en.json index 128fe780..c3fff7c2 100644 --- a/frontend/new-web/src/locales/langs/en.json +++ b/frontend/new-web/src/locales/langs/en.json @@ -384,6 +384,7 @@ }, "password": { "required": "Please enter Password", + "currentRequired": "Please enter your current password", "min": "The password cannot be less than 6 characters", "confirm": "Please confirm the password again", "inconformity": "The two password entries are inconsistent" @@ -534,10 +535,15 @@ "title": "Dashboard", "console": "Console", "analysis": "Analysis", - "ecommerce": "Ecommerce" + "ecommerce": "Ecommerce", + "map": "Map", + "pricing": "Pricing" }, "widgets": { "title": "Components", + "cards": "Cards", + "banners": "Banners", + "charts": "Charts", "icon": "Icon", "imageCrop": "Image Crop", "excel": "Excel Import Export", @@ -549,17 +555,8 @@ "qrcode": "QR Code", "drag": "Drag", "textScroll": "Text Scroll", - "fireworks": "Fireworks" - }, - "template": { - "title": "Template Center", - "chat": "Chat", - "cards": "Cards", - "banners": "Banners", - "charts": "Charts", - "map": "Map", - "calendar": "Calendar", - "pricing": "Pricing" + "fireworks": "Fireworks", + "changeLog": "Changelog" }, "article": { "title": "Article", @@ -596,7 +593,7 @@ } }, "system": { - "title": "System Settings", + "title": "Template System", "user": "User Manage", "role": "Role Manage", "userCenter": "User Center", diff --git a/frontend/new-web/src/locales/langs/zh.json b/frontend/new-web/src/locales/langs/zh.json index 72d02350..b0f248cf 100644 --- a/frontend/new-web/src/locales/langs/zh.json +++ b/frontend/new-web/src/locales/langs/zh.json @@ -384,6 +384,7 @@ }, "password": { "required": "请输入密码", + "currentRequired": "请输入当前密码", "min": "密码不能少于6位", "confirm": "请再次确认密码", "inconformity": "两次密码输入不一致" @@ -534,10 +535,15 @@ "title": "仪表盘", "console": "控制台", "analysis": "分析页", - "ecommerce": "电子商务" + "ecommerce": "电子商务", + "map": "地图", + "pricing": "定价" }, "widgets": { "title": "组件中心", + "cards": "卡片", + "banners": "横幅", + "charts": "图表", "icon": "图标", "imageCrop": "图像裁剪", "excel": "Excel 导入导出", @@ -549,17 +555,8 @@ "qrcode": "二维码", "drag": "拖拽", "textScroll": "文字滚动", - "fireworks": "礼花" - }, - "template": { - "title": "模板中心", - "chat": "聊天", - "cards": "卡片", - "banners": "横幅", - "charts": "图表", - "map": "地图", - "calendar": "日历", - "pricing": "定价" + "fireworks": "礼花", + "changeLog": "更新日志" }, "article": { "title": "文章管理", @@ -596,7 +593,7 @@ } }, "system": { - "title": "系统管理", + "title": "模板系统", "user": "用户管理", "role": "角色管理", "userCenter": "个人中心", diff --git a/frontend/new-web/src/mock/upgrade/changeLog.ts b/frontend/new-web/src/mock/upgrade/changeLog.ts index 3c7b7656..d227bcf8 100644 --- a/frontend/new-web/src/mock/upgrade/changeLog.ts +++ b/frontend/new-web/src/mock/upgrade/changeLog.ts @@ -1,4 +1,4 @@ -interface UpgradeLog { +export interface UpgradeLog { version: string; // 版本号 title: string; // 更新标题 date: string; // 更新日期 diff --git a/frontend/new-web/src/router/core/MenuProcessor.ts b/frontend/new-web/src/router/core/MenuProcessor.ts index 4777fbdd..f5ee12c8 100644 --- a/frontend/new-web/src/router/core/MenuProcessor.ts +++ b/frontend/new-web/src/router/core/MenuProcessor.ts @@ -8,6 +8,7 @@ */ import type { AppRouteRecord } from "@/types/router"; +import type { UserInfo } from "@/api/module_system/user"; import { useUserStore } from "@/store/modules/user.store"; import { useAppMode } from "@/hooks/core/useAppMode"; import MenuAPI from "@/api/module_system/menu"; @@ -45,15 +46,18 @@ export class MenuProcessor { */ private async processFrontendMenu(): Promise { const userStore = useUserStore(); - const roles = userStore.info?.roles; - let menuList = [...asyncRoutes]; - // 根据角色过滤菜单(仅当能解析出角色 code 时才过滤;否则勿用空数组误杀全部 meta.roles) + // 超管不做前端 meta.roles 过滤,避免与接口未返回 code 或编码不一致时整棵模板路由被误删 + if (userStore.info?.is_superuser) { + return this.filterEmptyMenus(menuList); + } + + const roles = userStore.info?.roles; + + // 根据角色过滤菜单(仅当能解析出角色标识时才过滤;否则勿用空数组误杀全部 meta.roles) if (roles && roles.length > 0) { - const roleCodes = roles - .map((role) => (role as any).code) - .filter((code): code is string => !!code); + const roleCodes = this.extractRoleCodesFromUserRoles(roles); if (roleCodes.length > 0) { menuList = this.filterMenuByRoles(menuList, roleCodes); } @@ -62,6 +66,21 @@ export class MenuProcessor { return this.filterEmptyMenus(menuList); } + /** + * 从用户信息中的角色解析与路由 meta.roles 对齐的标识(code,以及形如 R_XXX 的 name) + */ + private extractRoleCodesFromUserRoles(roles: NonNullable): string[] { + const codes = new Set(); + for (const role of roles) { + const r = role as { code?: string; name?: string }; + const c = r.code?.trim(); + if (c) codes.add(c); + const n = r.name?.trim(); + if (n && /^R_[A-Z0-9_]+$/i.test(n)) codes.add(n); + } + return Array.from(codes); + } + /** * 混合模式:后端菜单 + 前端 asyncRoutes(按路由 name 去重,后端优先) */ diff --git a/frontend/new-web/src/router/guards/beforeEach.ts b/frontend/new-web/src/router/guards/beforeEach.ts index ed56e6d3..0eca146a 100644 --- a/frontend/new-web/src/router/guards/beforeEach.ts +++ b/frontend/new-web/src/router/guards/beforeEach.ts @@ -174,7 +174,12 @@ async function handleRouteGuard( } // 3. 处理动态路由注册 - if (!routeRegistry?.isRegistered() && userStore.isLogin) { + const menuStore = useMenuStore(); + /** 未注册动态路由,或菜单已被清空(登出延迟 reset 与再登录竞态下可能出现「已注册但 menuList 为空」) */ + const shouldInitRoutes = + userStore.isLogin && (!routeRegistry?.isRegistered() || menuStore.menuList.length === 0); + + if (shouldInitRoutes) { // 防止并发请求(快速连续导航场景) if (routeInitInProgress) { // 正在初始化中,等待完成后重新导航 @@ -284,6 +289,21 @@ function isStaticRoute(path: string): boolean { return checkRoute(staticRoutes, path); } +/** + * 动态路由仍标记为已注册但侧边菜单已被清空时,先卸下动态路由再拉菜单。 + * 典型场景:`logout` 中 `resetRouterState(500)` 延迟执行,用户在 500ms 内再次登录, + * 守卫若仅判断 `isRegistered()` 会跳过拉菜单,侧栏空白。 + */ +function repairDynamicRoutesIfMenuEmpty(): void { + if (!routeRegistry?.isRegistered()) return; + const ms = useMenuStore(); + if (ms.menuList.length > 0) return; + routeRegistry.unregister(); + IframeRouteManager.getInstance().clear(); + ms.removeAllDynamicRoutes(); + resetRouteInitState(); +} + /** * 处理动态路由注册 */ @@ -292,6 +312,8 @@ async function handleDynamicRoutes( next: NavigationGuardNext, router: Router ): Promise { + repairDynamicRoutesIfMenuEmpty(); + // 标记初始化进行中 routeInitInProgress = true; diff --git a/frontend/new-web/src/router/modules/article.ts b/frontend/new-web/src/router/modules/article.ts deleted file mode 100644 index c12e9035..00000000 --- a/frontend/new-web/src/router/modules/article.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { AppRouteRecord } from "@/types/router"; - -export const articleRoutes: AppRouteRecord = { - path: "/article", - name: "Article", - component: "/index/index", - meta: { - title: "menus.article.title", - icon: "ri:book-2-line", - roles: ["R_SUPER", "R_ADMIN"], - }, - children: [ - { - path: "article-list", - name: "ArticleList", - component: "/article/list", - meta: { - title: "menus.article.articleList", - icon: "ri:article-line", - keepAlive: true, - authList: [ - { title: "新增", authMark: "add" }, - { title: "编辑", authMark: "edit" }, - ], - }, - }, - { - path: "detail/:id", - name: "ArticleDetail", - component: "/article/detail", - meta: { - title: "menus.article.articleDetail", - isHide: true, - keepAlive: true, - activePath: "/article/article-list", - }, - }, - { - path: "comment", - name: "ArticleComment", - component: "/article/comment", - meta: { - title: "menus.article.comment", - icon: "ri:mail-line", - keepAlive: true, - }, - }, - { - path: "publish", - name: "ArticlePublish", - component: "/article/publish", - meta: { - title: "menus.article.articlePublish", - icon: "ri:telegram-2-line", - keepAlive: true, - authList: [{ title: "发布", authMark: "add" }], - }, - }, - ], -}; diff --git a/frontend/new-web/src/router/modules/dashboard.ts b/frontend/new-web/src/router/modules/dashboard.ts deleted file mode 100644 index 1cb5b884..00000000 --- a/frontend/new-web/src/router/modules/dashboard.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { RoutesAlias } from "@/router/routesAlias"; -import type { AppRouteRecord } from "@/types/router"; - -/** 前端仪表盘(`/dashboard`);与后端同 path/name 时 mergeAppRouteRecords 保留后端 */ -export const dashboardRoutes: AppRouteRecord = { - name: "Dashboard", - path: "/dashboard", - component: RoutesAlias.Layout, - redirect: "/dashboard/workplace", - meta: { - title: "menus.dashboard.title", - icon: "ri:pie-chart-line", - alwaysShow: true, - }, - children: [ - { - path: "workplace", - name: "DashboardWorkplace", - component: "/dashboard/workplace", - meta: { - title: "menus.workplace.title", - icon: "ri:layout-grid-line", - keepAlive: true, - }, - }, - { - path: "console", - name: "DashboardConsole", - component: "/dashboard/console", - meta: { - title: "menus.dashboard.console", - icon: "ri:home-smile-2-line", - keepAlive: false, - fixedTab: true, - }, - }, - { - path: "analysis", - name: "DashboardAnalysis", - component: "/dashboard/analysis", - meta: { - title: "menus.dashboard.analysis", - icon: "ri:align-item-bottom-line", - keepAlive: false, - }, - }, - { - path: "ecommerce", - name: "DashboardEcommerce", - component: "/dashboard/ecommerce", - meta: { - title: "menus.dashboard.ecommerce", - icon: "ri:bar-chart-box-line", - keepAlive: false, - }, - }, - ], -}; diff --git a/frontend/new-web/src/router/modules/examples.ts b/frontend/new-web/src/router/modules/examples.ts deleted file mode 100644 index 76738dd8..00000000 --- a/frontend/new-web/src/router/modules/examples.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { AppRouteRecord } from "@/types/router"; - -export const examplesRoutes: AppRouteRecord = { - path: "/examples", - name: "Examples", - component: "/index/index", - meta: { - title: "menus.examples.title", - icon: "ri:sparkling-line", - }, - children: [ - { - path: "permission", - name: "Permission", - component: "", - meta: { - title: "menus.examples.permission.title", - icon: "ri:fingerprint-line", - }, - children: [ - { - path: "switch-role", - name: "PermissionSwitchRole", - component: "/examples/permission/switch-role", - meta: { - title: "menus.examples.permission.switchRole", - icon: "ri:contacts-line", - keepAlive: true, - }, - }, - { - path: "button-auth", - name: "PermissionButtonAuth", - component: "/examples/permission/button-auth", - meta: { - title: "menus.examples.permission.buttonAuth", - icon: "ri:mouse-line", - keepAlive: true, - authList: [ - { title: "新增", authMark: "add" }, - { title: "编辑", authMark: "edit" }, - { title: "删除", authMark: "delete" }, - { title: "导出", authMark: "export" }, - { title: "查看", authMark: "view" }, - { title: "发布", authMark: "publish" }, - { title: "配置", authMark: "config" }, - { title: "管理", authMark: "manage" }, - ], - }, - }, - { - path: "page-visibility", - name: "PermissionPageVisibility", - component: "/examples/permission/page-visibility", - meta: { - title: "menus.examples.permission.pageVisibility", - icon: "ri:user-3-line", - keepAlive: true, - roles: ["R_SUPER"], - }, - }, - ], - }, - { - path: "tabs", - name: "Tabs", - component: "/examples/tabs", - meta: { - title: "menus.examples.tabs", - icon: "ri:price-tag-line", - }, - }, - { - path: "tables/basic", - name: "TablesBasic", - component: "/examples/tables/basic", - meta: { - title: "menus.examples.tablesBasic", - icon: "ri:layout-grid-line", - keepAlive: true, - }, - }, - { - path: "tables", - name: "Tables", - component: "/examples/tables", - meta: { - title: "menus.examples.tables", - icon: "ri:table-3", - keepAlive: true, - }, - }, - { - path: "forms", - name: "Forms", - component: "/examples/forms", - meta: { - title: "menus.examples.forms", - icon: "ri:table-view", - keepAlive: true, - }, - }, - { - path: "form/search-bar", - name: "SearchBar", - component: "/examples/forms/search-bar", - meta: { - title: "menus.examples.searchBar", - icon: "ri:table-line", - keepAlive: true, - }, - }, - { - path: "tables/tree", - name: "TablesTree", - component: "/examples/tables/tree", - meta: { - title: "menus.examples.tablesTree", - icon: "ri:layout-2-line", - keepAlive: true, - }, - }, - { - path: "socket-chat", - name: "SocketChat", - component: "/examples/socket-chat", - meta: { - title: "menus.examples.socketChat", - icon: "ri:shake-hands-line", - keepAlive: true, - }, - }, - ], -}; diff --git a/frontend/new-web/src/router/modules/index.ts b/frontend/new-web/src/router/modules/index.ts index b598549f..b8509787 100644 --- a/frontend/new-web/src/router/modules/index.ts +++ b/frontend/new-web/src/router/modules/index.ts @@ -1,23 +1,9 @@ import { AppRouteRecord } from "@/types/router"; -import { dashboardRoutes } from "./dashboard"; -import { templateRoutes } from "./template"; import { widgetsRoutes } from "./widgets"; -import { examplesRoutes } from "./examples"; import { systemRoutes } from "./system"; -import { articleRoutes } from "./article"; -import { resultRoutes } from "./result"; import { exceptionRoutes } from "./exception"; /** * 导出所有模块化路由 */ -export const routeModules: AppRouteRecord[] = [ - dashboardRoutes, - templateRoutes, - widgetsRoutes, - examplesRoutes, - systemRoutes, - articleRoutes, - resultRoutes, - exceptionRoutes, -]; +export const routeModules: AppRouteRecord[] = [widgetsRoutes, systemRoutes, exceptionRoutes]; diff --git a/frontend/new-web/src/router/modules/result.ts b/frontend/new-web/src/router/modules/result.ts deleted file mode 100644 index 98b6c8a5..00000000 --- a/frontend/new-web/src/router/modules/result.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { AppRouteRecord } from "@/types/router"; - -export const resultRoutes: AppRouteRecord = { - path: "/result", - name: "Result", - component: "/index/index", - meta: { - title: "menus.result.title", - icon: "ri:checkbox-circle-line", - }, - children: [ - { - path: "success", - name: "ResultSuccess", - component: "/result/success", - meta: { - title: "menus.result.success", - icon: "ri:checkbox-circle-line", - keepAlive: true, - }, - }, - { - path: "fail", - name: "ResultFail", - component: "/result/fail", - meta: { - title: "menus.result.fail", - icon: "ri:close-circle-line", - keepAlive: true, - }, - }, - ], -}; diff --git a/frontend/new-web/src/router/modules/system.ts b/frontend/new-web/src/router/modules/system.ts index 0999a867..ca7c2422 100644 --- a/frontend/new-web/src/router/modules/system.ts +++ b/frontend/new-web/src/router/modules/system.ts @@ -1,58 +1,43 @@ import { AppRouteRecord } from "@/types/router"; +/** Art 模板自带演示路由:与后端「系统管理」路径隔离,避免合并时被覆盖或冲突 */ export const systemRoutes: AppRouteRecord = { - path: "/system", - name: "System", + path: "/art-system", + name: "ArtSystem", component: "/index/index", meta: { title: "menus.system.title", icon: "ri:user-3-line", - roles: ["R_SUPER", "R_ADMIN"], }, children: [ { path: "user", - name: "User", + name: "ArtTplUser", component: "/system/user", meta: { title: "menus.system.user", icon: "ri:user-line", keepAlive: true, - roles: ["R_SUPER", "R_ADMIN"], }, }, { path: "role", - name: "Role", + name: "ArtTplRole", component: "/system/role", meta: { title: "menus.system.role", icon: "ri:user-settings-line", keepAlive: true, - roles: ["R_SUPER"], - }, - }, - { - path: "user-center", - name: "UserCenter", - component: "/system/user-center", - meta: { - title: "menus.system.userCenter", - icon: "ri:user-line", - isHide: true, - keepAlive: true, - isHideTab: true, }, }, { path: "menu", - name: "Menus", + name: "ArtTplMenus", component: "/system/menu", meta: { title: "menus.system.menu", icon: "ri:menu-line", keepAlive: true, - roles: ["R_SUPER"], authList: [ { title: "新增", authMark: "add" }, { title: "编辑", authMark: "edit" }, @@ -60,90 +45,5 @@ export const systemRoutes: AppRouteRecord = { ], }, }, - { - path: "nested", - name: "Nested", - component: "", - meta: { - title: "menus.system.nested", - icon: "ri:menu-unfold-3-line", - keepAlive: true, - }, - children: [ - { - path: "menu1", - name: "NestedMenu1", - component: "/system/nested/menu1", - meta: { - title: "menus.system.menu1", - icon: "ri:align-justify", - keepAlive: true, - }, - }, - { - path: "menu2", - name: "NestedMenu2", - component: "", - meta: { - title: "menus.system.menu2", - icon: "ri:align-justify", - keepAlive: true, - }, - children: [ - { - path: "menu2-1", - name: "NestedMenu2-1", - component: "/system/nested/menu2", - meta: { - title: "menus.system.menu21", - icon: "ri:align-justify", - keepAlive: true, - }, - }, - ], - }, - { - path: "menu3", - name: "NestedMenu3", - component: "", - meta: { - title: "menus.system.menu3", - icon: "ri:align-justify", - keepAlive: true, - }, - children: [ - { - path: "menu3-1", - name: "NestedMenu3-1", - component: "/system/nested/menu3", - meta: { - title: "menus.system.menu31", - keepAlive: true, - }, - }, - { - path: "menu3-2", - name: "NestedMenu3-2", - component: "", - meta: { - title: "menus.system.menu32", - keepAlive: true, - }, - children: [ - { - path: "menu3-2-1", - name: "NestedMenu3-2-1", - component: "/system/nested/menu3/menu3-2", - meta: { - title: "menus.system.menu321", - keepAlive: true, - }, - }, - ], - }, - ], - }, - ], - }, ], }; diff --git a/frontend/new-web/src/router/modules/template.ts b/frontend/new-web/src/router/modules/template.ts deleted file mode 100644 index 91db8b2a..00000000 --- a/frontend/new-web/src/router/modules/template.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { AppRouteRecord } from "@/types/router"; - -export const templateRoutes: AppRouteRecord = { - path: "/template", - name: "Template", - component: "/index/index", - meta: { - title: "menus.template.title", - icon: "ri:apps-2-line", - }, - children: [ - { - path: "cards", - name: "Cards", - component: "/template/cards", - meta: { - title: "menus.template.cards", - icon: "ri:wallet-line", - keepAlive: false, - }, - }, - { - path: "banners", - name: "Banners", - component: "/template/banners", - meta: { - title: "menus.template.banners", - icon: "ri:rectangle-line", - keepAlive: false, - }, - }, - { - path: "charts", - name: "Charts", - component: "/template/charts", - meta: { - title: "menus.template.charts", - icon: "ri:bar-chart-box-line", - keepAlive: false, - }, - }, - { - path: "map", - name: "Map", - component: "/template/map", - meta: { - title: "menus.template.map", - icon: "ri:map-pin-line", - keepAlive: true, - }, - }, - { - path: "chat", - name: "Chat", - component: "/template/chat", - meta: { - title: "menus.template.chat", - icon: "ri:message-3-line", - keepAlive: true, - }, - }, - { - path: "calendar", - name: "Calendar", - component: "/template/calendar", - meta: { - title: "menus.template.calendar", - icon: "ri:calendar-2-line", - keepAlive: true, - }, - }, - { - path: "pricing", - name: "Pricing", - component: "/template/pricing", - meta: { - title: "menus.template.pricing", - icon: "ri:money-cny-box-line", - keepAlive: true, - isFullPage: true, - }, - }, - ], -}; diff --git a/frontend/new-web/src/router/modules/widgets.ts b/frontend/new-web/src/router/modules/widgets.ts index 20fc9465..87d91789 100644 --- a/frontend/new-web/src/router/modules/widgets.ts +++ b/frontend/new-web/src/router/modules/widgets.ts @@ -9,6 +9,36 @@ export const widgetsRoutes: AppRouteRecord = { icon: "ri:apps-2-add-line", }, children: [ + { + path: "cards", + name: "Cards", + component: "/widgets/cards", + meta: { + title: "menus.widgets.cards", + icon: "ri:wallet-line", + keepAlive: false, + }, + }, + { + path: "banners", + name: "Banners", + component: "/widgets/banners", + meta: { + title: "menus.widgets.banners", + icon: "ri:rectangle-line", + keepAlive: false, + }, + }, + { + path: "charts", + name: "Charts", + component: "/widgets/charts", + meta: { + title: "menus.widgets.charts", + icon: "ri:bar-chart-box-line", + keepAlive: false, + }, + }, { path: "icon", name: "Icon", @@ -130,5 +160,255 @@ export const widgetsRoutes: AppRouteRecord = { showTextBadge: "Hot", }, }, + + /** 结果页(原 /result) */ + { + path: "result", + name: "Result", + component: "", + meta: { + title: "menus.result.title", + icon: "ri:checkbox-circle-line", + }, + children: [ + { + path: "success", + name: "ResultSuccess", + component: "/widgets/result/success", + meta: { + title: "menus.result.success", + icon: "ri:checkbox-circle-line", + keepAlive: true, + }, + }, + { + path: "fail", + name: "ResultFail", + component: "/widgets/result/fail", + meta: { + title: "menus.result.fail", + icon: "ri:close-circle-line", + keepAlive: true, + }, + }, + ], + }, + + /** 功能示例(原 /examples) */ + { + path: "examples", + name: "Examples", + component: "", + meta: { + title: "menus.examples.title", + icon: "ri:sparkling-line", + }, + children: [ + { + path: "permission", + name: "Permission", + component: "", + meta: { + title: "menus.examples.permission.title", + icon: "ri:fingerprint-line", + }, + children: [ + { + path: "switch-role", + name: "PermissionSwitchRole", + component: "/widgets/examples/permission/switch-role", + meta: { + title: "menus.examples.permission.switchRole", + icon: "ri:contacts-line", + keepAlive: true, + }, + }, + { + path: "button-auth", + name: "PermissionButtonAuth", + component: "/widgets/examples/permission/button-auth", + meta: { + title: "menus.examples.permission.buttonAuth", + icon: "ri:mouse-line", + keepAlive: true, + authList: [ + { title: "新增", authMark: "add" }, + { title: "编辑", authMark: "edit" }, + { title: "删除", authMark: "delete" }, + { title: "导出", authMark: "export" }, + { title: "查看", authMark: "view" }, + { title: "发布", authMark: "publish" }, + { title: "配置", authMark: "config" }, + { title: "管理", authMark: "manage" }, + ], + }, + }, + { + path: "page-visibility", + name: "PermissionPageVisibility", + component: "/widgets/examples/permission/page-visibility", + meta: { + title: "menus.examples.permission.pageVisibility", + icon: "ri:user-3-line", + keepAlive: true, + roles: ["R_SUPER"], + }, + }, + ], + }, + { + path: "tabs", + name: "Tabs", + component: "/widgets/examples/tabs", + meta: { + title: "menus.examples.tabs", + icon: "ri:price-tag-line", + }, + }, + { + path: "tables/basic", + name: "TablesBasic", + component: "/widgets/examples/tables/basic", + meta: { + title: "menus.examples.tablesBasic", + icon: "ri:layout-grid-line", + keepAlive: true, + }, + }, + { + path: "tables", + name: "Tables", + component: "/widgets/examples/tables", + meta: { + title: "menus.examples.tables", + icon: "ri:table-3", + keepAlive: true, + }, + }, + { + path: "forms", + name: "Forms", + component: "/widgets/examples/forms", + meta: { + title: "menus.examples.forms", + icon: "ri:table-view", + keepAlive: true, + }, + }, + { + path: "form/search-bar", + name: "SearchBar", + component: "/widgets/examples/forms/search-bar", + meta: { + title: "menus.examples.searchBar", + icon: "ri:table-line", + keepAlive: true, + }, + }, + { + path: "tables/tree", + name: "TablesTree", + component: "/widgets/examples/tables/tree", + meta: { + title: "menus.examples.tablesTree", + icon: "ri:layout-2-line", + keepAlive: true, + }, + }, + { + path: "socket-chat", + name: "SocketChat", + component: "/widgets/examples/socket-chat", + meta: { + title: "menus.examples.socketChat", + icon: "ri:shake-hands-line", + keepAlive: true, + }, + }, + ], + }, + + /** 文章演示(原 /article) */ + { + path: "article", + name: "Article", + component: "", + meta: { + title: "menus.article.title", + icon: "ri:book-2-line", + roles: ["R_SUPER", "R_ADMIN"], + }, + children: [ + { + path: "article-list", + name: "ArticleList", + component: "/widgets/article/list", + meta: { + title: "menus.article.articleList", + icon: "ri:article-line", + keepAlive: true, + authList: [ + { title: "新增", authMark: "add" }, + { title: "编辑", authMark: "edit" }, + ], + }, + }, + { + path: "detail/:id", + name: "ArticleDetail", + component: "/widgets/article/detail", + meta: { + title: "menus.article.articleDetail", + isHide: true, + keepAlive: true, + activePath: "/widgets/article/article-list", + }, + }, + { + path: "comment", + name: "ArticleComment", + component: "/widgets/article/comment", + meta: { + title: "menus.article.comment", + icon: "ri:mail-line", + keepAlive: true, + }, + }, + { + path: "publish", + name: "ArticlePublish", + component: "/widgets/article/publish", + meta: { + title: "menus.article.articlePublish", + icon: "ri:telegram-2-line", + keepAlive: true, + authList: [{ title: "发布", authMark: "add" }], + }, + }, + ], + }, + + /** 更新日志(原 views/change/log) */ + { + path: "change", + name: "Change", + component: "", + meta: { + title: "menus.widgets.changeLog", + icon: "ri:gamepad-line", + }, + children: [ + { + path: "log", + name: "ChangeLog", + component: "/widgets/change/log", + meta: { + title: "menus.widgets.changeLog", + icon: "ri:gamepad-line", + keepAlive: true, + }, + }, + ], + }, ], }; diff --git a/frontend/new-web/src/router/routes/staticRoutes.ts b/frontend/new-web/src/router/routes/staticRoutes.ts index e728ae3e..fa05d48e 100644 --- a/frontend/new-web/src/router/routes/staticRoutes.ts +++ b/frontend/new-web/src/router/routes/staticRoutes.ts @@ -64,7 +64,7 @@ export const staticRoutes: AppRouteRecordRaw[] = [ redirect: "/home", component: Layout, children: [ - /** 首页;壳层菜单见 mergeShellMenus */ + /** 首页(壳层菜单见 mergeShellMenus);仪表盘同挂在下方 `dashboard` 子树 */ { path: "home", name: "Home", @@ -78,9 +78,85 @@ export const staticRoutes: AppRouteRecordRaw[] = [ { path: "profile", name: "Profile", - meta: { title: "个人中心", icon: "user", hidden: true }, + meta: { title: "个人中心", icon: "ri:user-line", hidden: true }, component: () => import("@/views/current/profile.vue"), }, + /** 仪表盘:嵌套在根 Layout 下,与 `/home`、`/profile` 同级挂载 */ + { + path: "dashboard", + name: "Dashboard", + redirect: "/dashboard/workplace", + component: () => import("@/views/nested/router-view-parent/index.vue"), + meta: { + title: "menus.dashboard.title", + icon: "ri:pie-chart-line", + alwaysShow: true, + }, + children: [ + { + path: "workplace", + name: "DashboardWorkplace", + component: () => import("@/views/dashboard/workplace/index.vue"), + meta: { + title: "menus.workplace.title", + icon: "ri:layout-grid-line", + keepAlive: true, + }, + }, + { + path: "console", + name: "DashboardConsole", + component: () => import("@/views/dashboard/console/index.vue"), + meta: { + title: "menus.dashboard.console", + icon: "ri:home-smile-2-line", + keepAlive: false, + fixedTab: true, + }, + }, + { + path: "analysis", + name: "DashboardAnalysis", + component: () => import("@/views/dashboard/analysis/index.vue"), + meta: { + title: "menus.dashboard.analysis", + icon: "ri:align-item-bottom-line", + keepAlive: false, + }, + }, + { + path: "ecommerce", + name: "DashboardEcommerce", + component: () => import("@/views/dashboard/ecommerce/index.vue"), + meta: { + title: "menus.dashboard.ecommerce", + icon: "ri:bar-chart-box-line", + keepAlive: false, + }, + }, + { + path: "map", + name: "DashboardMap", + component: () => import("@/views/dashboard/map/index.vue"), + meta: { + title: "menus.dashboard.map", + icon: "ri:map-pin-line", + keepAlive: true, + }, + }, + { + path: "pricing", + name: "DashboardPricing", + component: () => import("@/views/dashboard/pricing/index.vue"), + meta: { + title: "menus.dashboard.pricing", + icon: "ri:money-cny-box-line", + keepAlive: true, + isFullPage: true, + }, + }, + ], + }, ], }, { diff --git a/frontend/new-web/src/router/utils/mergeShellMenus.ts b/frontend/new-web/src/router/utils/mergeShellMenus.ts index 4f32d4d2..66fd4c2b 100644 --- a/frontend/new-web/src/router/utils/mergeShellMenus.ts +++ b/frontend/new-web/src/router/utils/mergeShellMenus.ts @@ -1,5 +1,4 @@ import type { AppRouteRecord } from "@/types/router"; -import { dashboardRoutes } from "@/router/modules/dashboard"; function normalizeMenuPath(path?: string): string { if (!path || !path.trim()) return ""; @@ -16,6 +15,86 @@ function collectPathsAndNames(items: AppRouteRecord[], paths: Set, names } } +/** 静态路由 /home 不在后端菜单树中,补侧栏入口 */ +const HOME_SHELL: AppRouteRecord = { + path: "/home", + name: "Home", + meta: { + title: "menus.home.title", + icon: "ri:presentation-line", + keepAlive: true, + shellRoute: true, + }, +}; + +/** 与 `staticRoutes` 根 Layout 下 `/dashboard/*` 一致,仅侧栏用(无 component) */ +const dashboardMenuSource: AppRouteRecord = { + name: "Dashboard", + path: "/dashboard", + meta: { + title: "menus.dashboard.title", + icon: "ri:pie-chart-line", + alwaysShow: true, + }, + children: [ + { + path: "workplace", + name: "DashboardWorkplace", + meta: { + title: "menus.workplace.title", + icon: "ri:layout-grid-line", + keepAlive: true, + }, + }, + { + path: "console", + name: "DashboardConsole", + meta: { + title: "menus.dashboard.console", + icon: "ri:home-smile-2-line", + keepAlive: false, + }, + }, + { + path: "analysis", + name: "DashboardAnalysis", + meta: { + title: "menus.dashboard.analysis", + icon: "ri:align-item-bottom-line", + keepAlive: false, + }, + }, + { + path: "ecommerce", + name: "DashboardEcommerce", + meta: { + title: "menus.dashboard.ecommerce", + icon: "ri:bar-chart-box-line", + keepAlive: false, + }, + }, + { + path: "map", + name: "DashboardMap", + meta: { + title: "menus.dashboard.map", + icon: "ri:map-pin-line", + keepAlive: true, + }, + }, + { + path: "pricing", + name: "DashboardPricing", + meta: { + title: "menus.dashboard.pricing", + icon: "ri:money-cny-box-line", + keepAlive: true, + isFullPage: true, + }, + }, + ], +}; + function dashboardRoutesToShellMenu(route: AppRouteRecord, parentAbs = ""): AppRouteRecord { const raw = route.path?.trim() ?? ""; const fullPath = @@ -36,17 +115,6 @@ function dashboardRoutesToShellMenu(route: AppRouteRecord, parentAbs = ""): AppR }; } -const HOME_SHELL: AppRouteRecord = { - path: "/home", - name: "Home", - meta: { - title: "menus.home.title", - icon: "ri:presentation-line", - keepAlive: true, - shellRoute: true, - }, -}; - export function mergeShellRoutesIntoMenu(menuList: AppRouteRecord[]): AppRouteRecord[] { const paths = new Set(); const names = new Set(); @@ -70,7 +138,7 @@ export function mergeShellRoutesIntoMenu(menuList: AppRouteRecord[]): AppRouteRe tryPush(HOME_SHELL); if (!paths.has("/dashboard")) { - tryPush(dashboardRoutesToShellMenu(structuredClone(dashboardRoutes))); + tryPush(dashboardRoutesToShellMenu(structuredClone(dashboardMenuSource))); } if (additions.length === 0) return menuList; diff --git a/frontend/new-web/src/store/modules/setting.store.ts b/frontend/new-web/src/store/modules/setting.store.ts index ba48782f..aa0e37f3 100644 --- a/frontend/new-web/src/store/modules/setting.store.ts +++ b/frontend/new-web/src/store/modules/setting.store.ts @@ -36,7 +36,7 @@ import { MenuThemeType } from "@/types/store"; import AppConfig from "@/config"; import { SystemThemeEnum, MenuThemeEnum, MenuTypeEnum, ContainerWidthEnum } from "@/enums/appEnum"; import { setElementThemeColor } from "@/utils/ui"; -import { useCeremony } from "@/hooks/core/useCeremony"; +import { formatToDate } from "@/utils/common/dateUtil"; import { StorageConfig } from "@/utils/storage/storage-config"; import { SETTING_DEFAULT_CONFIG } from "@/config/setting"; import { @@ -202,8 +202,10 @@ export const useSettingsStore = defineStore( return customRadius.value + "rem" || SETTING_DEFAULT_CONFIG.customRadius + "rem"; }); + /** festivalDate 存「上次完成烟花播放」的自然日 YYYY-MM-DD,与今天相同则当天不再播 */ const isShowFireworks = computed((): boolean => { - return festivalDate.value === useCeremony().currentFestivalData.value?.date ? false : true; + const today = formatToDate(new Date()); + return festivalDate.value !== today; }); // ============================================== diff --git a/frontend/new-web/src/store/modules/user.store.ts b/frontend/new-web/src/store/modules/user.store.ts index a8184432..6b01d29c 100755 --- a/frontend/new-web/src/store/modules/user.store.ts +++ b/frontend/new-web/src/store/modules/user.store.ts @@ -314,6 +314,8 @@ export const useUserStore = defineStore( resetAllState(); sessionStorage.removeItem("iframeRoutes"); useMenuStore().setHomePath(""); + // 与 RouteRegistry 并行:立即清理 permissionStore 中的动态路由标记与实例,避免仅依赖延迟 reset 时侧栏/守卫状态不一致 + usePermissionStore(store).resetRouter(); resetRouterState(500); if (shouldNavigate) { diff --git a/frontend/new-web/src/styles/index.scss b/frontend/new-web/src/styles/index.scss index 9f237442..030aef4f 100644 --- a/frontend/new-web/src/styles/index.scss +++ b/frontend/new-web/src/styles/index.scss @@ -46,6 +46,7 @@ } // ==================== 搜索区域样式 ==================== + /* 与 art-card-xs 并存时边框由主题 art 卡片统一绘制,避免双层描边 */ .search-container:not(.art-card-xs) { border: 1px solid var(--el-border-color-light); diff --git a/frontend/new-web/src/types/config/index.ts b/frontend/new-web/src/types/config/index.ts index d0a0b675..a40b61b6 100644 --- a/frontend/new-web/src/types/config/index.ts +++ b/frontend/new-web/src/types/config/index.ts @@ -71,6 +71,11 @@ export interface FestivalConfig { isActive?: boolean; /** 烟花播放次数(可选,默认为 3 次) */ count?: number; + /** + * 为 true 时不放烟花,进入系统后直接显示 `scrollText`(适合长期顶栏公告) + * 多条时间重叠时优先使用日期区间更短的那条 + */ + skipFireworks?: boolean; } // 系统基础配置 diff --git a/frontend/new-web/src/utils/constants/links.ts b/frontend/new-web/src/utils/constants/links.ts index e60fd512..142dd5cb 100644 --- a/frontend/new-web/src/utils/constants/links.ts +++ b/frontend/new-web/src/utils/constants/links.ts @@ -7,32 +7,32 @@ */ export const WEB_LINKS = { // Github 主页 - GITHUB_HOME: "https://github.com/Daymychen/art-design-pro", + GITHUB_HOME: "https://github.com/fastapiadmin", // 项目 Github 主页 - GITHUB: "https://github.com/Daymychen/art-design-pro", + GITHUB: "https://github.com/fastapiadmin/FastapiAdmin", /** 备用镜像 / 国内仓库(与旧版顶栏一致时可指向业务 Gitee) */ GITEE: "https://gitee.com/fastapiadmin/FastapiAdmin", // 个人博客 - BLOG: "https://www.artd.pro", + BLOG: "https://blog.csdn.net/weixin_46768253?type=blog", // 项目文档 - DOCS: "https://www.artd.pro/docs/zh/", + DOCS: "https://service.fastapiadmin.com/overview/", // 精简版本 - LiteVersion: "https://www.artd.pro/docs/zh/guide/lite-version.html", + LiteVersion: "https://gitee.com/fastapiadmin/FastCloud", // v2.6.1版本 - OldVersion: "https://www.artd.pro/v2/", + OldVersion: "https://github.com/fastapiadmin/FastapiAdmin/tree/v2.0.0", // 项目社区 - COMMUNITY: "https://www.artd.pro/docs/zh/community/communicate.html", + COMMUNITY: "https://service.fastapiadmin.com", // 个人 Bilibili 主页 BILIBILI: "https://space.bilibili.com/425500936?spm_id_from=333.1007.0.0", // 项目介绍 - INTRODUCE: "https://www.artd.pro/docs/zh/guide/introduce.html", + INTRODUCE: "https://service.fastapiadmin.com", }; diff --git a/frontend/new-web/src/utils/sys/upgrade.ts b/frontend/new-web/src/utils/sys/upgrade.ts index e2f73181..767b824b 100644 --- a/frontend/new-web/src/utils/sys/upgrade.ts +++ b/frontend/new-web/src/utils/sys/upgrade.ts @@ -241,13 +241,13 @@ class VersionManager { // 首次访问处理 if (this.isFirstVisit(storedVersion)) { this.setStoredVersion(StorageConfig.CURRENT_VERSION); - // console.info('[Upgrade] 首次访问,已设置当前版本') + console.info("[Upgrade] 首次访问,已设置当前版本"); return; } // 版本相同,无需升级 if (this.isSameVersion(storedVersion!)) { - // console.debug('[Upgrade] 版本相同,无需升级') + console.debug("[Upgrade] 版本相同,无需升级"); return; } diff --git a/frontend/new-web/src/views/current/profile.vue b/frontend/new-web/src/views/current/profile.vue index 5d341395..2d6745d5 100644 --- a/frontend/new-web/src/views/current/profile.vue +++ b/frontend/new-web/src/views/current/profile.vue @@ -1,333 +1,266 @@ + diff --git a/frontend/new-web/src/views/template/calendar/index.vue b/frontend/new-web/src/views/dashboard/components/HomeCalendar.vue similarity index 66% rename from frontend/new-web/src/views/template/calendar/index.vue rename to frontend/new-web/src/views/dashboard/components/HomeCalendar.vue index 269edc4a..c0a4284e 100644 --- a/frontend/new-web/src/views/template/calendar/index.vue +++ b/frontend/new-web/src/views/dashboard/components/HomeCalendar.vue @@ -1,25 +1,23 @@