388 lines
11 KiB
JavaScript
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 |