task-283(后台迁移收尾/发布): admin-vue 后台工程入库 + Flask 后台整体退役

- 新后台 admin-frontend-vue 整工程入库(base=/admin-vue/、History 路由、Nginx 静态托管方案与 verify-dist 校验)
- Java AdminConsoleController 改为入口重定向: /admin|/admin.html、/login|/login.html -> /admin-vue/; 删除 classpath:static 旧 admin.html/login.html 单页与 admin.js 副本
- Flask 后台整体退役: 删除 admin_api/auth/main 蓝图、web_source 页面、static 脚本与 admin 相关测试; app.py 收敛为仅注册 version_bp(/api/version、/api/version/latest, 供桌面端更新检查)
- AdminApiGuardFilterTest 豁免样例路径 /admin.html -> /admin-vue/
This commit is contained in:
2026-09-06 10:41:47 +08:00
parent 6bd935dc6b
commit 4c88964473
71 changed files with 974 additions and 39150 deletions
+11
View File
@@ -1,5 +1,6 @@
import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router'
import AdminLayout from '@/layout/AdminLayout.vue'
import LoginPage from '@/pages/login/LoginPage.vue'
import NotFoundPage from '@/pages/error/NotFoundPage.vue'
import { useAdminSessionStore } from '@/stores/admin-session'
import { APP_BASE_PATH } from '@/config/app'
@@ -10,6 +11,11 @@ import { isRouteAllowed } from './helpers'
const router = createRouter({
history: createWebHistory(APP_BASE_PATH),
routes: [
{
path: '/login',
component: LoginPage,
meta: { title: '登录' },
},
{
path: '/',
component: AdminLayout,
@@ -26,10 +32,15 @@ const router = createRouter({
router.beforeEach(async (to) => {
const session = useAdminSessionStore()
// 登录页是公开页;已登录访问则回根路由。
if (to.path === '/login') {
return session.initialized && session.user ? '/' : true
}
if (!session.initialized) {
try {
await session.initialize()
} catch {
// 未登录:401 由 http 拦截器整页跳转 SPA 登录页;此处放行当前导航由守卫收口。
return false
}
}
@@ -0,0 +1,27 @@
/** 菜单树 route 归一:column_key → 前端注册的规范页面路径。
* 共享库 columns.route_path 仍是旧式 slug(切机迁移未应用),这里按注册表 key 映射为新 Vue 路由,
* 保证侧边栏/面包屑/首页跳转都能命中已注册页面,无需改写共享库。纯逻辑。 */
import { adminPages } from './routes'
import type { AdminMenuNode } from '@/types/admin'
const CANONICAL_BY_KEY = new Map<string, string>()
for (const page of adminPages) {
if (page.menuKey) {
CANONICAL_BY_KEY.set(page.menuKey, `/${page.path.replace(/^\/+/, '')}`)
}
}
/** column_key → 规范路由(带前导 /,无 base 前缀);未登记返回 undefined。 */
export function canonicalRouteOf(key: string | undefined | null): string | undefined {
return typeof key === 'string' ? CANONICAL_BY_KEY.get(key) : undefined
}
/** 递归把菜单树节点的 route 替换为规范路由;分组/未登记节点保持原值。 */
export function canonicalizeMenuTree(nodes: AdminMenuNode[] | null | undefined): AdminMenuNode[] {
return (nodes || []).map((node) => {
const canonical = canonicalRouteOf(node.key)
const children = canonicalizeMenuTree(node.children)
const route = canonical && node.route != null ? canonical : node.route
return { ...node, route, children }
})
}
+13
View File
@@ -17,6 +17,19 @@ export const adminPages: AdminPageDef[] = [
{ path: 'account/users', menuKey: 'admin_users', title: '用户管理', load: () => import('@/pages/account/UsersPage.vue') },
{ path: 'account/menus', menuKey: 'admin_columns', title: '菜单管理', load: () => import('@/pages/account/MenusPage.vue') },
{ path: 'account/groups', menuKey: 'admin_group_manage', title: '数据权限分组', load: () => import('@/pages/account/GroupsPage.vue') },
{ path: 'shop-center/duplicate-check', menuKey: 'admin_shop_data_duplicate_check', title: '店铺撞款监控', load: () => import('@/pages/tasks/DuplicateCheckPage.vue') },
{ path: 'shop-center/keys', menuKey: 'admin_shop_keys', title: '店铺密钥管理', load: () => import('@/pages/shop/ShopKeysPage.vue') },
{ path: 'shop-center/shops', menuKey: 'admin_shop_manage', title: '店铺管理', load: () => import('@/pages/shop/ShopManagePage.vue') },
{ path: 'records/history', menuKey: 'admin_history', title: '生成记录', load: () => import('@/pages/records/RecordsHistoryPage.vue') },
{ path: 'records/software-version', menuKey: 'admin_version', title: '软件版本管理', load: () => import('@/pages/records/RecordsSoftwareVersionPage.vue') },
{ path: 'records/digital-human-version', menuKey: 'digital_human_version', title: '数字人版本管理', load: () => import('@/pages/records/RecordsDigitalHumanVersionPage.vue') },
{ path: 'records/image-video-tasks', menuKey: 'admin_image_video_tasks', title: '视频任务记录', load: () => import('@/pages/tasks/ImageVideoTasksPage.vue') },
{ path: 'shop-center/data-tasks', menuKey: 'admin_shop_data_crawl_tasks', title: '店铺数据任务/记录', load: () => import('@/pages/tasks/ShopDataTasksPage.vue') },
{ path: 'asin-center/registry', menuKey: 'admin_dedupe_total_data', title: '数据去重总数据', load: () => import('@/pages/asin/DedupeRegistryPage.vue') },
{ path: 'asin-center/invalid', menuKey: 'admin_invalid_asin_data', title: '不符合ASIN数据', load: () => import('@/pages/asin/AsinInvalidPage.vue') },
{ path: 'asin-center/query', menuKey: 'admin_query_asin', title: '查询ASIN', load: () => import('@/pages/asin/QueryAsinPage.vue') },
{ path: 'asin-center/categories', menuKey: 'admin_product_categories', title: '商品类目', load: () => import('@/pages/asin/ProductCategoryPage.vue') },
{ path: 'asin-center/skip-price', menuKey: 'admin_skip_price_asin', title: '最低价ASIN', load: () => import('@/pages/asin/SkipPricePage.vue') },
]
export function routeOf(page: AdminPageDef): RouteRecordRaw {