Files
crawler-plugin/frontend-vue/src/router/index.ts
T
huangzd1997 82a782550e feat(密钥): 用户 API 密钥服务端化——V115 按账号绑定存储 + 后台密钥管理页 + 桌面端全站拦截与配置引导
- 新增 usersecret 模块:外观专利/货源查询密钥从本地 localStorage 迁移至 biz_user_api_secret(AES 加密、按 uid 绑定)
- 后台「密钥管理」页:脱敏展示、立即检测、清空;每日 04:30 分布式锁定时巡检
- 桌面端:密钥设置面板走服务端、未配齐引导 /setup-secrets、代理余量展示
- 删除专利汇令牌全链路与密钥保留时长选择器
2026-09-13 10:03:59 +08:00

177 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { createRouter, createWebHistory } from 'vue-router'
/**
* 数富AI 桌面前端 SPA 路由(无 .html 后缀)
*
* 原 MPA22 个 html 入口 + 22 个 *-main.ts)合并为单入口 index.html
* 页面组件懒加载(每个工具页独立 chunk),URL 统一为 /xxx 路径形式。
*/
const routes = [
{ path: '/', redirect: '/home' },
{
path: '/login',
name: 'login',
component: () => import('@/pages/login/DesktopLoginPage.vue'),
},
{
path: '/home',
name: 'home',
component: () => import('@/pages/home/DesktopHomePage.vue'),
},
{
// 密钥未配置完整时的强制引导页(全站拦截落点)
path: '/setup-secrets',
name: 'setup-secrets',
component: () => import('@/pages/setup/DesktopSecretSetupPage.vue'),
},
{
path: '/amazon-console',
name: 'amazon-console',
component: () => import('@/pages/amazon/AmazonConsolePage.vue'),
},
{
path: '/image-video',
name: 'image-video',
// 视图切换走 ?view=delivery(菜单页 / 带货视频工作台)
component: () => import('@/pages/image-video/ImageVideoPage.vue'),
},
// ---- 亚马逊运营工具(品牌工具,右侧统一任务面板)----
{
path: '/collect-data',
name: 'collect-data',
component: () => import('@/pages/brand/components/BrandCollectDataTab.vue'),
},
{
path: '/variant-collection',
name: 'variant-collection',
component: () => import('@/pages/brand/components/BrandVariantTab.vue'),
},
{
path: '/dedupe',
name: 'dedupe',
component: () => import('@/pages/brand/components/BrandDedupeTab.vue'),
},
{
path: '/similar-asin',
name: 'similar-asin',
component: () => import('@/pages/brand/components/BrandSimilarAsinTab.vue'),
},
{
path: '/brand',
name: 'brand',
component: () => import('@/pages/brand/components/BrandBrandTab.vue'),
},
{
path: '/appearance-patent',
name: 'appearance-patent',
component: () => import('@/pages/brand/components/BrandAppearancePatentTab.vue'),
},
{
path: '/split',
name: 'split',
component: () => import('@/pages/brand/components/BrandSplitTab.vue'),
},
{
path: '/convert',
name: 'convert',
component: () => import('@/pages/brand/components/BrandConvertTab.vue'),
},
{
path: '/publish',
name: 'publish',
component: () => import('@/pages/brand/components/BrandPublishTab.vue'),
},
{
path: '/delete-brand',
name: 'delete-brand',
component: () => import('@/pages/brand/components/BrandDeleteBrandTab.vue'),
},
{
path: '/product-risk',
name: 'product-risk',
component: () => import('@/pages/brand/components/BrandProductRiskTab.vue'),
},
{
path: '/shop-match',
name: 'shop-match',
component: () => import('@/pages/brand/components/BrandShopMatchTab.vue'),
},
{
path: '/price-track',
name: 'price-track',
component: () => import('@/pages/brand/components/BrandPriceTrackTab.vue'),
},
{
path: '/patrol-delete',
name: 'patrol-delete',
component: () => import('@/pages/brand/components/BrandPatrolDeleteTab.vue'),
},
{
path: '/query-asin',
name: 'query-asin',
component: () => import('@/pages/brand/components/BrandQueryAsinTab.vue'),
},
{
path: '/shop-data-crawl',
name: 'shop-data-crawl',
component: () => import('@/pages/brand/components/BrandShopDataCrawlTab.vue'),
},
{
path: '/withdraw',
name: 'withdraw',
component: () => import('@/pages/brand/components/BrandWithdrawTab.vue'),
},
// ---- 兜底:未匹配路径回首页(保持与 MPA 时代"未知页 404 后回首页"一致体验)----
{ path: '/:pathMatch(.*)*', redirect: '/home' },
]
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(_to, _from, savedPosition) {
// 返回工具台的 #group-xxx 锚点由组件 onMounted 处理;普通滚动回顶部
if (savedPosition) return savedPosition
return { top: 0 }
},
})
// 懒加载 chunk 加载失败(网络抖动/瞬间断流)会被 vue-router 静默吞掉,
// 菜单点击表现为"点了没反应";此处统一重载页面(重新拉最新 index.html 与新 chunk)。
// 用会话内计数做保险丝,网络持续异常时最多重载 2 次,不再死循环。
router.onError((error) => {
const message = String((error as Error)?.message || '')
const isChunkLoadError =
message.includes('Failed to fetch dynamically imported module') ||
message.includes('Importing a module script failed')
if (isChunkLoadError) {
const RELOAD_KEY = 'spa-chunk-reload-count'
let count = 0
try {
count = Number(sessionStorage.getItem(RELOAD_KEY) || '0') || 0
} catch {
/* 存储不可用时按首次处理 */
}
if (count < 2) {
try {
sessionStorage.setItem(RELOAD_KEY, String(count + 1))
} catch {
/* 忽略存储异常 */
}
console.error(`[router] 页面资源加载失败,重载页面(第 ${count + 1} 次):`, error)
window.location.reload()
return
}
try {
sessionStorage.removeItem(RELOAD_KEY)
} catch {
/* 忽略存储异常 */
}
console.error('[router] 页面资源多次加载失败,停止重载:', error)
} else {
console.error('[router] 路由导航失败:', error)
}
})
export default router