Files
Vue3/src/router/index.js
2026-06-28 23:59:33 +08:00

388 lines
11 KiB
JavaScript

import { createRouter, createWebHistory } from 'vue-router'
import Layout from '@/views/Layout.vue'
import request from '@/utils/request'
import {
ensureMenuAccess,
getMenuAccess,
getDefaultLandingPath,
getEffectiveVisiblePaths,
isMenuSessionFresh,
JITUAN_API,
} from '@/utils/club-context'
const routes = [
{
path: '/login',
component: () => import('@/views/Login.vue')
},
{
path: '/',
component: Layout,
redirect: () => getDefaultLandingPath() || '/welcome',
children: [
{
path: 'welcome',
component: () => import('@/views/Welcome.vue'),
meta: { title: '首页' }
},
// ========== 板块与财务 ==========
{
path: 'finance/bankuai',
component: () => import('@/views/finance/BankuaiConfig.vue'),
meta: { title: '板块配置' }
},
{
path: 'finance/data',
component: () => import('@/views/finance/FinanceData.vue'),
meta: { title: '财务数据' }
},
// ========== 考核管理 ==========
{
path: 'assessment/examiner',
component: () => import('@/views/assessment/ExaminerManage.vue'),
meta: { title: '考核官管理' }
},
{
path: 'assessment/config',
component: () => import('@/views/assessment/ExamConfig.vue'),
meta: { title: '考核配置' }
},
{
path: 'assessment/record',
component: () => import('@/views/assessment/ExamRecord.vue'),
meta: { title: '考核记录' }
},
// 订单管理(原有)
{
path: 'order/platform',
component: () => import('@/views/order/PlatformOrder.vue'),
meta: { title: '平台订单' }
},
{
path: 'order/merchant',
component: () => import('@/views/order/MerchantOrder.vue'),
meta: { title: '商家订单' }
},
{
path: 'order/detail/:id',
component: () => import('@/views/order/Detail.vue'),
meta: { title: '订单详情' }
},
// 跨平台管理(原有)
{
path: 'cross-order',
component: () => import('@/views/cross-platform/Order.vue'),
meta: { title: '跨平台订单' }
},
{
path: 'cross-settings',
component: () => import('@/views/cross-platform/Settings.vue'),
meta: { title: '跨平台设置' }
},
{
path: 'cross-data',
component: () => import('@/views/cross-platform/Data.vue'),
meta: { title: '跨平台数据' }
},
{
path: 'cross-pre',
component: () => import('@/views/cross-platform/Pre.vue'),
meta: { title: '预结算处理' }
},
{
path: 'cross-order/detail/:id',
component: () => import('@/views/cross-platform/OrderDetail.vue'),
meta: { title: '跨平台订单详情' }
},
// 用户管理(原有)
{
path: 'user/player',
component: () => import('@/views/user/Player.vue'),
meta: { title: '打手管理' }
},
{
path: 'user/player/detail/:playerId',
component: () => import('@/views/user/PlayerDetail.vue'),
meta: { title: '打手详情' }
},
{
path: 'user/guanli',
component: () => import('@/views/user/Guanli.vue'),
meta: { title: '管事管理' }
},
{
path: 'user/guanli/detail/:id',
component: () => import('@/views/user/GuanliDetail.vue'),
meta: { title: '管事详情' }
},
{
path: 'user/shangjia',
component: () => import('@/views/user/Shangjia.vue'),
meta: { title: '商家管理' }
},
{
path: 'user/shangjia/detail/:id',
component: () => import('@/views/user/ShangjiaDetail.vue'),
meta: { title: '商家详情' }
},
{
path: 'user/zuzhang',
component: () => import('@/views/user/Zuzhang.vue'),
meta: { title: '组长管理' }
},
{
path: 'user/zuzhang/detail/:id',
component: () => import('@/views/user/ZuzhangDetail.vue'),
meta: { title: '组长详情' }
},
{
path: 'user/identity-tag',
component: () => import('@/views/user/IdentityTag.vue'),
meta: { title: '身份装饰标签' }
},
// 提现管理(原有)
{
path: 'withdraw/audit',
component: () => import('@/views/withdraw/Audit.vue'),
meta: { title: '提现审核' }
},
{
path: 'withdraw/data',
component: () => import('@/views/withdraw/Data.vue'),
meta: { title: '提现数据' }
},
{
path: 'withdraw/settings',
component: () => import('@/views/withdraw/Settings.vue'),
meta: { title: '提现设置' }
},
{
path: 'withdraw/detail/:id',
component: () => import('@/views/withdraw/Detail.vue'),
meta: { title: '提现详情' }
},
// 管理员管理(原有)
{
path: 'admin/club-config',
component: () => import('@/views/admin/ClubConfig.vue'),
meta: { title: '俱乐部密钥配置' }
},
{
path: 'admin/data-scope',
component: () => import('@/views/admin/DataScope.vue'),
meta: { title: '数据范围配置' }
},
{
path: 'admin/role',
component: () => import('@/views/admin/Role.vue'),
meta: { title: '角色管理' }
},
{
path: 'admin/role/detail/:id',
component: () => import('@/views/admin/RoleDetail.vue'),
meta: { title: '角色详情' }
},
{
path: 'admin/user',
component: () => import('@/views/admin/AdminUser.vue'),
meta: { title: '后台用户' }
},
{
path: 'admin/user/detail/:id',
component: () => import('@/views/admin/AdminUserDetail.vue'),
meta: { title: '后台用户详情' }
},
{
path: 'admin/operation-log',
component: () => import('@/views/admin/OperationLog.vue'),
meta: { title: '操作日志' }
},
// 处罚管理(原有)
{
path: 'punishment',
component: () => import('@/views/Punishment.vue'),
meta: { title: '处罚管理' }
},
{
path: 'punishment/detail/:id',
component: () => import('@/views/punishment/Detail.vue'),
meta: { title: '处罚详情' }
},
// ========== 商品管理(原有) ==========
{
path: 'product/list',
component: () => import('@/views/product/List.vue'),
meta: { title: '商品列表' }
},
{
path: 'product/type-zone',
component: () => import('@/views/product/TypeZone.vue'),
meta: { title: '商品类型专区管理' }
},
{
path: 'product/data',
component: () => import('@/views/product/Data.vue'),
meta: { title: '商品数据分析' }
},
{
path: 'product/detail/:id',
component: () => import('@/views/product/Detail.vue'),
meta: { title: '商品详情' }
},
// ========== 会员管理(原有) ==========
{
path: 'member/list',
component: () => import('@/views/member/List.vue'),
meta: { title: '会员管理' }
},
{
path: 'member/data',
component: () => import('@/views/member/Data.vue'),
meta: { title: '会员数据分析' }
},
{
path: 'miniapp/popup-notice',
component: () => import('@/views/miniapp/PopupNotice.vue'),
meta: { title: '弹窗公告管理' }
},
{
path: 'miniapp/carousel',
component: () => import('@/views/miniapp/CarouselManage.vue'),
meta: { title: '轮播图与公告' }
},
{
path: 'miniapp/assets',
component: () => import('@/views/miniapp/MiniappAssets.vue'),
meta: { title: '图标与频道' }
},
{
path: 'miniapp/leixing',
component: () => import('@/views/miniapp/ShangpinLeixingClub.vue'),
meta: { title: '抢单商品类型' }
},
{
path: 'miniapp/kaohe-tags',
component: () => import('@/views/miniapp/KaoheTagClub.vue'),
meta: { title: '抢单考核标签' }
},
{
path: 'miniapp/dashou-exam',
component: () => import('@/views/miniapp/DashouExam.vue'),
meta: { title: '打手接单考试' }
},
// ========== 店铺管理(原有) ==========
{
path: 'shop/list',
component: () => import('@/views/shop/List.vue'),
meta: { title: '店铺列表' }
},
{
path: 'shop/withdraw-apply',
component: () => import('@/views/shop/WithdrawApply.vue'),
meta: { title: '店铺提现申请' }
},
{
path: 'shop/products',
component: () => import('@/views/shop/Products.vue'),
meta: { title: '店铺商品管理' }
},
// ========== 🔥 新增:客服会话管理 ==========
{
path: 'chat/agent',
component: () => import('@/views/chat/Agent.vue'),
meta: { title: '会话管理' }
}
]
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
/** 详情页等子路由:父模块在 visible_paths 中即允许访问 */
function isRouteAllowed(path, visiblePaths) {
if (!visiblePaths?.length) return true
if (visiblePaths.some((p) => p && (path === p || path.startsWith(`${p}/`)))) {
return true
}
const rules = [
{ prefix: '/withdraw/detail/', parents: ['/withdraw/audit', '/withdraw/data'] },
{ prefix: '/punishment/detail/', parents: ['/punishment'] },
{ prefix: '/order/detail/', parents: ['/order/platform', '/order/merchant'] },
{ prefix: '/cross-order/detail/', parents: ['/cross-order'] },
{ prefix: '/user/player/detail/', parents: ['/user/player'] },
{ prefix: '/user/guanli/detail/', parents: ['/user/guanli'] },
{ prefix: '/user/shangjia/detail/', parents: ['/user/shangjia'] },
{ prefix: '/user/zuzhang/detail/', parents: ['/user/zuzhang'] },
{ prefix: '/product/detail/', parents: ['/product/list'] },
{ prefix: '/admin/role/detail/', parents: ['/admin/role'] },
{ prefix: '/admin/user/detail/', parents: ['/admin/user'] },
{ prefix: '/miniapp/assets', parents: ['/miniapp/carousel', '/miniapp/assets'] },
]
for (const { prefix, parents } of rules) {
if (path.startsWith(prefix)) {
return visiblePaths.some((p) => parents.includes(p))
}
}
return false
}
router.beforeEach(async (to, from, next) => {
const token = localStorage.getItem('token')
if (to.path !== '/login' && !token) {
next('/login')
return
}
if (to.path === '/login') {
next()
return
}
try {
await ensureMenuAccess(async () => {
const res = await request.get(JITUAN_API.menuAccess)
return res.code === 0 ? res.data : null
})
} catch (e) {
console.error('路由加载菜单权限失败:', e)
}
const access = getMenuAccess()
if (!isMenuSessionFresh()) {
next()
return
}
if (to.path === '/welcome') {
next()
return
}
if (!getEffectiveVisiblePaths(access).length) {
if (to.path !== '/welcome') {
next('/welcome')
return
}
next()
return
}
const path = to.path
if (!isRouteAllowed(path, getEffectiveVisiblePaths(access))) {
const fallback = getDefaultLandingPath(access) || '/welcome'
next(fallback)
return
}
next()
})
export default router