diff --git a/src/assets/images/TopList/bg.png b/src/assets/images/TopList/bg.png new file mode 100644 index 0000000..523a288 Binary files /dev/null and b/src/assets/images/TopList/bg.png differ diff --git a/src/assets/images/TopList/eventGifts.png b/src/assets/images/TopList/eventGifts.png new file mode 100644 index 0000000..41ed59e Binary files /dev/null and b/src/assets/images/TopList/eventGifts.png differ diff --git a/src/assets/images/TopList/gift.png b/src/assets/images/TopList/gift.png new file mode 100644 index 0000000..c0c2757 Binary files /dev/null and b/src/assets/images/TopList/gift.png differ diff --git a/src/assets/images/TopList/help.png b/src/assets/images/TopList/help.png new file mode 100644 index 0000000..05361d0 Binary files /dev/null and b/src/assets/images/TopList/help.png differ diff --git a/src/assets/images/TopList/history.png b/src/assets/images/TopList/history.png new file mode 100644 index 0000000..ef37b13 Binary files /dev/null and b/src/assets/images/TopList/history.png differ diff --git a/src/assets/images/TopList/kingBt.png b/src/assets/images/TopList/kingBt.png new file mode 100644 index 0000000..c45b22a Binary files /dev/null and b/src/assets/images/TopList/kingBt.png differ diff --git a/src/assets/images/TopList/kingBtActive.png b/src/assets/images/TopList/kingBtActive.png new file mode 100644 index 0000000..4486e39 Binary files /dev/null and b/src/assets/images/TopList/kingBtActive.png differ diff --git a/src/assets/images/TopList/kingFrame.png b/src/assets/images/TopList/kingFrame.png new file mode 100644 index 0000000..a0fb5d1 Binary files /dev/null and b/src/assets/images/TopList/kingFrame.png differ diff --git a/src/assets/images/TopList/listTitle.png b/src/assets/images/TopList/listTitle.png new file mode 100644 index 0000000..3ba52e7 Binary files /dev/null and b/src/assets/images/TopList/listTitle.png differ diff --git a/src/assets/images/TopList/queenBt.png b/src/assets/images/TopList/queenBt.png new file mode 100644 index 0000000..138b022 Binary files /dev/null and b/src/assets/images/TopList/queenBt.png differ diff --git a/src/assets/images/TopList/queenBtActive.png b/src/assets/images/TopList/queenBtActive.png new file mode 100644 index 0000000..2f62b68 Binary files /dev/null and b/src/assets/images/TopList/queenBtActive.png differ diff --git a/src/assets/images/TopList/queenFrame.png b/src/assets/images/TopList/queenFrame.png new file mode 100644 index 0000000..1ddb5d4 Binary files /dev/null and b/src/assets/images/TopList/queenFrame.png differ diff --git a/src/assets/images/TopList/rewards.png b/src/assets/images/TopList/rewards.png new file mode 100644 index 0000000..9167aa0 Binary files /dev/null and b/src/assets/images/TopList/rewards.png differ diff --git a/src/router/index.js b/src/router/index.js index 05eaee8..c6d0d34 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,206 +1,212 @@ -import { createRouter, createWebHashHistory } from "vue-router"; -import { installRouteGuard } from "../utils/routeGuard.js"; +import { createRouter, createWebHashHistory } from 'vue-router' +import { installRouteGuard } from '../utils/routeGuard.js' const router = createRouter({ history: createWebHashHistory(import.meta.env.BASE_URL), routes: [ { - path: "/", - name: "root", - component: () => import("../views/LoadingView.vue"), + path: '/', + name: 'root', + component: () => import('../views/LoadingView.vue'), meta: { requiresAuth: false, isPublic: true }, }, { - path: "/loading", - name: "loading", - component: () => import("../views/LoadingView.vue"), + path: '/loading', + name: 'loading', + component: () => import('../views/LoadingView.vue'), meta: { requiresAuth: false, isPublic: true }, }, { - path: "/host-center", - name: "host-center", - component: () => import("../views/HostCenterView.vue"), + path: '/host-center', + name: 'host-center', + component: () => import('../views/HostCenterView.vue'), meta: { requiresAuth: true }, }, { - path: "/agency-center", - name: "agency-center", - component: () => import("../views/AgencyCenterView.vue"), + path: '/agency-center', + name: 'agency-center', + component: () => import('../views/AgencyCenterView.vue'), meta: { requiresAuth: true }, }, { - path: "/bd-center", - name: "bd-center", - component: () => import("../views/BDCenterView.vue"), + path: '/bd-center', + name: 'bd-center', + component: () => import('../views/BDCenterView.vue'), meta: { requiresAuth: true }, }, { - path: "/coin-seller", - name: "coin-seller", - component: () => import("../views/CoinSellerView.vue"), + path: '/coin-seller', + name: 'coin-seller', + component: () => import('../views/CoinSellerView.vue'), meta: { requiresAuth: true }, }, { - path: "/apply", - name: "apply", - component: () => import("../views/ApplyView.vue"), + path: '/apply', + name: 'apply', + component: () => import('../views/ApplyView.vue'), meta: { requiresAuth: false }, }, { - path: "/message", - name: "message", - component: () => import("../views/MessageView.vue"), + path: '/message', + name: 'message', + component: () => import('../views/MessageView.vue'), meta: { requiresAuth: true }, }, { - path: "/transfer", - name: "transfer", - component: () => import("../views/TransferView.vue"), + path: '/transfer', + name: 'transfer', + component: () => import('../views/TransferView.vue'), meta: { requiresAuth: true }, }, { - path: "/exchange-gold-coins", - name: "exchange-gold-coins", - component: () => import("../views/ExchangeGoldCoinsView.vue"), + path: '/exchange-gold-coins', + name: 'exchange-gold-coins', + component: () => import('../views/ExchangeGoldCoinsView.vue'), meta: { requiresAuth: true }, }, // 辅助页面 { - path: "/about", - name: "about", - component: () => import("../views/AboutView.vue"), + path: '/about', + name: 'about', + component: () => import('../views/AboutView.vue'), }, { - path: "/host-setting", - name: "host-setting", - component: () => import("../views/HostSettingView.vue"), + path: '/host-setting', + name: 'host-setting', + component: () => import('../views/HostSettingView.vue'), meta: { requiresAuth: true }, }, { - path: "/search-payee", - name: "search-payee", - component: () => import("../views/SearchPayeeView.vue"), + path: '/search-payee', + name: 'search-payee', + component: () => import('../views/SearchPayeeView.vue'), meta: { requiresAuth: true }, }, { - path: "/information-details", - name: "information-details", - component: () => import("../views/InformationDetailsView.vue"), + path: '/information-details', + name: 'information-details', + component: () => import('../views/InformationDetailsView.vue'), meta: { requiresAuth: true }, }, { - path: "/invite-members", - name: "invite-members", - component: () => import("../views/InviteMembersView.vue"), + path: '/invite-members', + name: 'invite-members', + component: () => import('../views/InviteMembersView.vue'), meta: { requiresAuth: true }, }, { - path: "/team-bill", - name: "team-bill", - component: () => import("../views/TeamBillView.vue"), + path: '/team-bill', + name: 'team-bill', + component: () => import('../views/TeamBillView.vue'), meta: { requiresAuth: true }, }, { - path: "/team-member", - name: "team-member", - component: () => import("../views/TeamMemberView.vue"), + path: '/team-member', + name: 'team-member', + component: () => import('../views/TeamMemberView.vue'), meta: { requiresAuth: true }, }, { - path: "/platform-policy", - name: "platform-policy", - component: () => import("../views/PlatformPolicyView.vue"), + path: '/platform-policy', + name: 'platform-policy', + component: () => import('../views/PlatformPolicyView.vue'), meta: { requiresAuth: true }, }, { - path: "/coin-seller-search", - name: "coin-seller-search", - component: () => import("../views/CoinSellerSearchView.vue"), + path: '/coin-seller-search', + name: 'coin-seller-search', + component: () => import('../views/CoinSellerSearchView.vue'), meta: { requiresAuth: true }, }, { - path: "/seller-records", - name: "seller-records", - component: () => import("../views/SellerRecordsView.vue"), + path: '/seller-records', + name: 'seller-records', + component: () => import('../views/SellerRecordsView.vue'), meta: { requiresAuth: true }, }, { - path: "/bd-setting", - name: "bd-setting", - component: () => import("../views/BDSettingView.vue"), + path: '/bd-setting', + name: 'bd-setting', + component: () => import('../views/BDSettingView.vue'), meta: { requiresAuth: true }, }, // 公共页面 { - path: "/not_app", - name: "not-app", - component: () => import("../views/NotAppView.vue"), + path: '/not_app', + name: 'not-app', + component: () => import('../views/NotAppView.vue'), meta: { requiresAuth: false }, }, // 404 页面 { - path: "/:pathMatch(.*)*", - name: "not-found", - redirect: "/apply", + path: '/:pathMatch(.*)*', + name: 'not-found', + redirect: '/apply', }, { - path: "/history-salary", - name: "history-salary", - component: () => import("../views/HistorySalaryView.vue"), + path: '/history-salary', + name: 'history-salary', + component: () => import('../views/HistorySalaryView.vue'), meta: { requiresAuth: true }, }, { - path: "/platform-salary", - name: "platform-salary", - component: () => import("../views/PlatformPolicyView.vue"), + path: '/platform-salary', + name: 'platform-salary', + component: () => import('../views/PlatformPolicyView.vue'), meta: { requiresAuth: true }, }, { - path: "/admin-center", - name: "admin-center", - component: () => import("../views/AdminCenter.vue"), + path: '/admin-center', + name: 'admin-center', + component: () => import('../views/AdminCenter.vue'), meta: { requiresAuth: true }, }, { - path: "/item-distribution", - name: "item-distribution", - component: () => import("../views/ItemDistribution.vue"), + path: '/item-distribution', + name: 'item-distribution', + component: () => import('../views/ItemDistribution.vue'), meta: { requiresAuth: true }, }, { - path: "/recharge", - name: "recharge", - component: () => import("../views/Recharge.vue"), + path: '/recharge', + name: 'recharge', + component: () => import('../views/Recharge.vue'), meta: { requiresAuth: true }, }, { - path: "/recharge-standard", - name: "recharge-standard", - component: () => import("../views/RechargeStandard.vue"), + path: '/recharge-standard', + name: 'recharge-standard', + component: () => import('../views/RechargeStandard.vue'), meta: { requiresAuth: true }, }, { - path: "/recharge-freight-agent", - name: "recharge-freight-agent", - component: () => import("../views/RechargeFreightAgent.vue"), + path: '/recharge-freight-agent', + name: 'recharge-freight-agent', + component: () => import('../views/RechargeFreightAgent.vue'), meta: { requiresAuth: true }, }, { - path: "/map", - name: "map", - component: () => import("../views/map.vue"), + path: '/map', + name: 'map', + component: () => import('../views/map.vue'), meta: { requiresAuth: true }, }, { - path: "/pay-result", - name: "pay-result", - component: () => import("../views/payResult.vue"), + path: '/pay-result', + name: 'pay-result', + component: () => import('../views/payResult.vue'), + meta: { requiresAuth: true }, + }, + { + path: '/top-list', + name: 'top-list', + component: () => import('../views/TopList/TopList.vue'), meta: { requiresAuth: true }, }, ], -}); +}) // 安装路由守卫 -installRouteGuard(router); +installRouteGuard(router) -export default router; +export default router diff --git a/src/utils/permissionManager.js b/src/utils/permissionManager.js index 3c1b3b1..b014c9c 100644 --- a/src/utils/permissionManager.js +++ b/src/utils/permissionManager.js @@ -5,33 +5,33 @@ // 用户身份类型 export const USER_ROLES = { - FREIGHT_AGENT: "freightAgent", - AGENT: "agent", - BD: "bd", - ANCHOR: "anchor", - GUEST: "guest", - ADMIN: "admin", -}; + FREIGHT_AGENT: 'freightAgent', + AGENT: 'agent', + BD: 'bd', + ANCHOR: 'anchor', + GUEST: 'guest', + ADMIN: 'admin', +} // 页面路径常量 export const PAGES = { - COIN_SELLER: "/coin-seller", - AGENCY_CENTER: "/agency-center", - BD_CENTER: "/bd-center", - HOST_CENTER: "/host-center", - APPLY: "/apply", - MESSAGE: "/message", - TRANSFER: "/transfer", - EXCHANGE: "/exchange-gold-coins", - PERSONAL_SALARY: "/platform-policy", - HOST_SETTING: "/host-setting", - NOT_APP: "/not_app", - LOADING: "/loading", - ADMIN_CENTER: "/admin-center", - RECHARGE_STANDARD: "/recharge-standard", - PAY_RESULT: "/pay-result", - MAP: "/map", -}; + COIN_SELLER: '/coin-seller', + AGENCY_CENTER: '/agency-center', + BD_CENTER: '/bd-center', + HOST_CENTER: '/host-center', + APPLY: '/apply', + MESSAGE: '/message', + TRANSFER: '/transfer', + EXCHANGE: '/exchange-gold-coins', + PERSONAL_SALARY: '/platform-policy', + HOST_SETTING: '/host-setting', + NOT_APP: '/not_app', + LOADING: '/loading', + ADMIN_CENTER: '/admin-center', + RECHARGE_STANDARD: '/recharge-standard', + PAY_RESULT: '/pay-result', + MAP: '/map', +} // 🎯 核心改变:基于身份的权限配置 // 每个身份拥有的页面权限列表 @@ -39,9 +39,9 @@ export const ROLE_PERMISSIONS = { // Freight Agent (货运代理/金币销售员) [USER_ROLES.FREIGHT_AGENT]: [ PAGES.COIN_SELLER, // 主页面 - "/seller-records", - "/coin-seller-search", - "/recharge-freight-agent", + '/seller-records', + '/coin-seller-search', + '/recharge-freight-agent', ], // Agent (代理商) @@ -52,13 +52,13 @@ export const ROLE_PERMISSIONS = { PAGES.MESSAGE, // 消息功能 PAGES.PERSONAL_SALARY, // 个人薪资查看 PAGES.RECHARGE_STANDARD, //普通转账功能 - "/team-member", - "/information-details", - "/search-payee", - "/history-salary", - "/platform-salary", - "/invite-members", - "/team-bill", + '/team-member', + '/information-details', + '/search-payee', + '/history-salary', + '/platform-salary', + '/invite-members', + '/team-bill', ], // BD (商务拓展) @@ -68,9 +68,9 @@ export const ROLE_PERMISSIONS = { PAGES.EXCHANGE, // 兑换功能 PAGES.MESSAGE, // 消息功能 PAGES.RECHARGE_STANDARD, //普通转账功能 - "/team-member", - "/history-salary", - "/platform-salary", + '/team-member', + '/history-salary', + '/platform-salary', ], // Anchor (主播) @@ -82,19 +82,19 @@ export const ROLE_PERMISSIONS = { PAGES.PERSONAL_SALARY, // 个人薪资查看 PAGES.HOST_SETTING, // 主播设置 PAGES.RECHARGE_STANDARD, //普通转账功能 - "/information-details", - "/search-payee", - "/apply", - "/history-salary", - "/platform-salary", - "/invite-members", - "/team-bill", + '/information-details', + '/search-payee', + '/apply', + '/history-salary', + '/platform-salary', + '/invite-members', + '/team-bill', ], // Admin(管理员) [USER_ROLES.ADMIN]: [ PAGES.ADMIN_CENTER, //管理员中心 - "/item-distribution", //赠送商品页面 + '/item-distribution', //赠送商品页面 PAGES.RECHARGE_STANDARD, //普通转账功能 ], @@ -108,13 +108,14 @@ export const ROLE_PERMISSIONS = { PAGES.NOT_APP, // 错误页面 PAGES.PAY_RESULT, // 支付成功页面 PAGES.MAP, // 地图选择页面 - "/recharge", - "/recharge-freight-agent", + '/recharge', + '/recharge-freight-agent', + '/top-list', ], // 加载页面 LOADING_PAGE: [PAGES.LOADING], -}; +} // 身份优先级(数字越大优先级越高) export const ROLE_PRIORITY = { @@ -124,7 +125,7 @@ export const ROLE_PRIORITY = { [USER_ROLES.AGENT]: 2, [USER_ROLES.ANCHOR]: 1, [USER_ROLES.GUEST]: 0, -}; +} // 身份对应的默认首页 export const ROLE_DEFAULT_PAGES = { @@ -134,52 +135,52 @@ export const ROLE_DEFAULT_PAGES = { [USER_ROLES.BD]: PAGES.BD_CENTER, [USER_ROLES.ANCHOR]: PAGES.HOST_CENTER, [USER_ROLES.GUEST]: PAGES.APPLY, -}; +} // 身份显示配置 export const ROLE_DISPLAY_CONFIG = { [USER_ROLES.FREIGHT_AGENT]: { - name: "Freight Agent", - tag: "💰 Coin Seller", - color: "#FCD34D", - bgColor: "#FEF3C7", + name: 'Freight Agent', + tag: '💰 Coin Seller', + color: '#FCD34D', + bgColor: '#FEF3C7', }, [USER_ROLES.AGENT]: { - name: "Agent", - tag: "🏢 Agency", - color: "#1E40AF", - bgColor: "#DBEAFE", + name: 'Agent', + tag: '🏢 Agency', + color: '#1E40AF', + bgColor: '#DBEAFE', }, [USER_ROLES.BD]: { - name: "BD", - tag: "📈 BD", - color: "#059669", - bgColor: "#D1FAE5", + name: 'BD', + tag: '📈 BD', + color: '#059669', + bgColor: '#D1FAE5', }, [USER_ROLES.ANCHOR]: { - name: "Anchor", - tag: "👑 Host", - color: "#5B21B6", - bgColor: "#E0E7FF", + name: 'Anchor', + tag: '👑 Host', + color: '#5B21B6', + bgColor: '#E0E7FF', }, [USER_ROLES.GUEST]: { - name: "Guest", - tag: "👤 Guest", - color: "#6B7280", - bgColor: "#F3F4F6", + name: 'Guest', + tag: '👤 Guest', + color: '#6B7280', + bgColor: '#F3F4F6', }, -}; +} /** * 基于身份的权限管理类 */ class RoleBasedPermissionManager { constructor() { - this.userIdentity = null; - this.primaryRole = null; - this.allRoles = []; - this.isIdentityLoaded = false; - this.allowedPages = []; + this.userIdentity = null + this.primaryRole = null + this.allRoles = [] + this.isIdentityLoaded = false + this.allowedPages = [] } /** @@ -187,18 +188,18 @@ class RoleBasedPermissionManager { * @param {Object} identity - 身份信息对象 */ setUserIdentity(identity) { - this.userIdentity = identity; - this.allRoles = this.calculateAllRoles(identity); - this.primaryRole = this.calculatePrimaryRole(this.allRoles); - this.allowedPages = this.calculateAllowedPages(this.allRoles); - this.isIdentityLoaded = true; + this.userIdentity = identity + this.allRoles = this.calculateAllRoles(identity) + this.primaryRole = this.calculatePrimaryRole(this.allRoles) + this.allowedPages = this.calculateAllowedPages(this.allRoles) + this.isIdentityLoaded = true - console.debug("🔐 User identity updated:", { + console.debug('🔐 User identity updated:', { identity: this.userIdentity, allRoles: this.allRoles, primaryRole: this.primaryRole, allowedPages: this.allowedPages, - }); + }) } /** @@ -207,16 +208,16 @@ class RoleBasedPermissionManager { * @returns {Array} 所有身份列表 */ calculateAllRoles(identity) { - if (!identity) return [USER_ROLES.GUEST]; + if (!identity) return [USER_ROLES.GUEST] - const roles = []; - if (identity.freightAgent) roles.push(USER_ROLES.FREIGHT_AGENT); - if (identity.agent) roles.push(USER_ROLES.AGENT); - if (identity.bd) roles.push(USER_ROLES.BD); - if (identity.anchor) roles.push(USER_ROLES.ANCHOR); - if (identity.admin) roles.push(USER_ROLES.ADMIN); + const roles = [] + if (identity.freightAgent) roles.push(USER_ROLES.FREIGHT_AGENT) + if (identity.agent) roles.push(USER_ROLES.AGENT) + if (identity.bd) roles.push(USER_ROLES.BD) + if (identity.anchor) roles.push(USER_ROLES.ANCHOR) + if (identity.admin) roles.push(USER_ROLES.ADMIN) - return roles.length > 0 ? roles : [USER_ROLES.GUEST]; + return roles.length > 0 ? roles : [USER_ROLES.GUEST] } /** @@ -225,12 +226,12 @@ class RoleBasedPermissionManager { * @returns {string} 主要身份 */ calculatePrimaryRole(roles) { - if (!roles || roles.length === 0) return USER_ROLES.GUEST; + if (!roles || roles.length === 0) return USER_ROLES.GUEST // 按优先级排序,返回优先级最高的身份 return roles.reduce((highest, current) => { - return ROLE_PRIORITY[current] > ROLE_PRIORITY[highest] ? current : highest; - }, USER_ROLES.GUEST); + return ROLE_PRIORITY[current] > ROLE_PRIORITY[highest] ? current : highest + }, USER_ROLES.GUEST) } /** @@ -239,27 +240,27 @@ class RoleBasedPermissionManager { * @returns {Array} 允许访问的页面列表 */ calculateAllowedPages(roles) { - const allowedPages = new Set(); + const allowedPages = new Set() // 添加公共页面 ROLE_PERMISSIONS.PUBLIC_PAGES.forEach((page) => { - allowedPages.add(page); - }); + allowedPages.add(page) + }) // 添加loading页面 ROLE_PERMISSIONS.LOADING_PAGE.forEach((page) => { - allowedPages.add(page); - }); + allowedPages.add(page) + }) // 根据用户拥有的每个身份,添加对应的页面权限 roles.forEach((role) => { - const rolePages = ROLE_PERMISSIONS[role] || []; + const rolePages = ROLE_PERMISSIONS[role] || [] rolePages.forEach((page) => { - allowedPages.add(page); - }); - }); + allowedPages.add(page) + }) + }) - return Array.from(allowedPages); + return Array.from(allowedPages) } /** @@ -269,20 +270,20 @@ class RoleBasedPermissionManager { */ hasPagePermission(page) { if (!this.isIdentityLoaded) { - console.warn("⚠️ Identity not loaded yet"); - return false; + console.warn('⚠️ Identity not loaded yet') + return false } - const hasPermission = this.allowedPages.includes(page); + const hasPermission = this.allowedPages.includes(page) - console.debug("🔍 Permission check:", { + console.debug('🔍 Permission check:', { page, allRoles: this.allRoles, primaryRole: this.primaryRole, hasPermission, - }); + }) - return hasPermission; + return hasPermission } /** @@ -292,10 +293,10 @@ class RoleBasedPermissionManager { * @returns {boolean} 是否有权限 */ hasRolePagePermission(role, page) { - const rolePages = ROLE_PERMISSIONS[role] || []; - const publicPages = ROLE_PERMISSIONS.PUBLIC_PAGES || []; + const rolePages = ROLE_PERMISSIONS[role] || [] + const publicPages = ROLE_PERMISSIONS.PUBLIC_PAGES || [] - return rolePages.includes(page) || publicPages.includes(page); + return rolePages.includes(page) || publicPages.includes(page) } /** @@ -304,10 +305,10 @@ class RoleBasedPermissionManager { * @returns {Array} 页面权限列表 */ getRolePermissions(role) { - const rolePages = ROLE_PERMISSIONS[role] || []; - const publicPages = ROLE_PERMISSIONS.PUBLIC_PAGES || []; + const rolePages = ROLE_PERMISSIONS[role] || [] + const publicPages = ROLE_PERMISSIONS.PUBLIC_PAGES || [] - return [...new Set([...rolePages, ...publicPages])]; + return [...new Set([...rolePages, ...publicPages])] } /** @@ -315,7 +316,7 @@ class RoleBasedPermissionManager { * @returns {string} 默认页面路径 */ getDefaultPage() { - return ROLE_DEFAULT_PAGES[this.primaryRole] || PAGES.APPLY; + return ROLE_DEFAULT_PAGES[this.primaryRole] || PAGES.APPLY } /** @@ -323,7 +324,7 @@ class RoleBasedPermissionManager { * @returns {string} 当前主要身份 */ getPrimaryRole() { - return this.primaryRole; + return this.primaryRole } /** @@ -331,7 +332,7 @@ class RoleBasedPermissionManager { * @returns {Array} 所有身份 */ getAllRoles() { - return this.allRoles; + return this.allRoles } /** @@ -340,7 +341,7 @@ class RoleBasedPermissionManager { * @returns {Object} 显示信息 */ getRoleDisplayInfo(role = this.primaryRole) { - return ROLE_DISPLAY_CONFIG[role] || ROLE_DISPLAY_CONFIG[USER_ROLES.GUEST]; + return ROLE_DISPLAY_CONFIG[role] || ROLE_DISPLAY_CONFIG[USER_ROLES.GUEST] } /** @@ -348,7 +349,7 @@ class RoleBasedPermissionManager { * @returns {boolean} 是否有多重身份 */ hasMultipleRoles() { - return this.allRoles.length > 1; + return this.allRoles.length > 1 } /** @@ -358,11 +359,11 @@ class RoleBasedPermissionManager { */ switchToRole(role) { if (!this.allRoles.includes(role)) { - console.warn(`⚠️ User does not have role: ${role}`); - return this.getDefaultPage(); + console.warn(`⚠️ User does not have role: ${role}`) + return this.getDefaultPage() } - return ROLE_DEFAULT_PAGES[role] || PAGES.APPLY; + return ROLE_DEFAULT_PAGES[role] || PAGES.APPLY } /** @@ -370,16 +371,16 @@ class RoleBasedPermissionManager { * @returns {Array} 可访问的页面菜单 */ getNavigationMenu() { - const menu = []; + const menu = [] this.allowedPages.forEach((page) => { - const menuItem = this.getPageMenuInfo(page); + const menuItem = this.getPageMenuInfo(page) if (menuItem) { - menu.push(menuItem); + menu.push(menuItem) } - }); + }) - return menu; + return menu } /** @@ -389,31 +390,31 @@ class RoleBasedPermissionManager { */ getPageMenuInfo(page) { const pageMenuConfig = { - [PAGES.COIN_SELLER]: { title: "Coin Seller", icon: "💰", order: 1 }, - [PAGES.AGENCY_CENTER]: { title: "Agency Center", icon: "🏢", order: 2 }, - [PAGES.BD_CENTER]: { title: "BD Center", icon: "📈", order: 3 }, - [PAGES.HOST_CENTER]: { title: "Host Center", icon: "👑", order: 4 }, - [PAGES.TRANSFER]: { title: "Transfer", icon: "💸", order: 5 }, - [PAGES.EXCHANGE]: { title: "Exchange", icon: "🔄", order: 6 }, - [PAGES.MESSAGE]: { title: "Messages", icon: "💬", order: 7 }, - [PAGES.PERSONAL_SALARY]: { title: "Salary", icon: "💵", order: 8 }, - [PAGES.HOST_SETTING]: { title: "Settings", icon: "⚙️", order: 9 }, - }; + [PAGES.COIN_SELLER]: { title: 'Coin Seller', icon: '💰', order: 1 }, + [PAGES.AGENCY_CENTER]: { title: 'Agency Center', icon: '🏢', order: 2 }, + [PAGES.BD_CENTER]: { title: 'BD Center', icon: '📈', order: 3 }, + [PAGES.HOST_CENTER]: { title: 'Host Center', icon: '👑', order: 4 }, + [PAGES.TRANSFER]: { title: 'Transfer', icon: '💸', order: 5 }, + [PAGES.EXCHANGE]: { title: 'Exchange', icon: '🔄', order: 6 }, + [PAGES.MESSAGE]: { title: 'Messages', icon: '💬', order: 7 }, + [PAGES.PERSONAL_SALARY]: { title: 'Salary', icon: '💵', order: 8 }, + [PAGES.HOST_SETTING]: { title: 'Settings', icon: '⚙️', order: 9 }, + } - const config = pageMenuConfig[page]; - return config ? { ...config, path: page } : null; + const config = pageMenuConfig[page] + return config ? { ...config, path: page } : null } /** * 重置权限信息 */ reset() { - this.userIdentity = null; - this.primaryRole = null; - this.allRoles = []; - this.isIdentityLoaded = false; - this.allowedPages = []; - console.debug("🔄 Permission manager reset"); + this.userIdentity = null + this.primaryRole = null + this.allRoles = [] + this.isIdentityLoaded = false + this.allowedPages = [] + console.debug('🔄 Permission manager reset') } /** @@ -421,41 +422,40 @@ class RoleBasedPermissionManager { * @returns {boolean} */ isLoaded() { - return this.isIdentityLoaded; + return this.isIdentityLoaded } /** * 调试方法:打印当前权限状态 */ debugPermissions() { - console.group("🔐 Current Permission State"); - console.log("User Identity:", this.userIdentity); - console.log("All Roles:", this.allRoles); - console.log("Primary Role:", this.primaryRole); - console.log("Allowed Pages:", this.allowedPages); - console.log("Default Page:", this.getDefaultPage()); - console.log("Navigation Menu:", this.getNavigationMenu()); - console.groupEnd(); + console.group('🔐 Current Permission State') + console.log('User Identity:', this.userIdentity) + console.log('All Roles:', this.allRoles) + console.log('Primary Role:', this.primaryRole) + console.log('Allowed Pages:', this.allowedPages) + console.log('Default Page:', this.getDefaultPage()) + console.log('Navigation Menu:', this.getNavigationMenu()) + console.groupEnd() } } // 创建全局权限管理实例 -export const permissionManager = new RoleBasedPermissionManager(); +export const permissionManager = new RoleBasedPermissionManager() // 便捷方法 -export const hasPermission = (page) => permissionManager.hasPagePermission(page); -export const hasRolePermission = (role, page) => - permissionManager.hasRolePagePermission(role, page); -export const getRolePermissions = (role) => permissionManager.getRolePermissions(role); -export const getDefaultPage = () => permissionManager.getDefaultPage(); -export const getPrimaryRole = () => permissionManager.getPrimaryRole(); -export const getAllRoles = () => permissionManager.getAllRoles(); -export const getRoleDisplayInfo = (role) => permissionManager.getRoleDisplayInfo(role); -export const setUserIdentity = (identity) => permissionManager.setUserIdentity(identity); -export const resetPermissions = () => permissionManager.reset(); -export const switchToRole = (role) => permissionManager.switchToRole(role); -export const getNavigationMenu = () => permissionManager.getNavigationMenu(); -export const debugPermissions = () => permissionManager.debugPermissions(); +export const hasPermission = (page) => permissionManager.hasPagePermission(page) +export const hasRolePermission = (role, page) => permissionManager.hasRolePagePermission(role, page) +export const getRolePermissions = (role) => permissionManager.getRolePermissions(role) +export const getDefaultPage = () => permissionManager.getDefaultPage() +export const getPrimaryRole = () => permissionManager.getPrimaryRole() +export const getAllRoles = () => permissionManager.getAllRoles() +export const getRoleDisplayInfo = (role) => permissionManager.getRoleDisplayInfo(role) +export const setUserIdentity = (identity) => permissionManager.setUserIdentity(identity) +export const resetPermissions = () => permissionManager.reset() +export const switchToRole = (role) => permissionManager.switchToRole(role) +export const getNavigationMenu = () => permissionManager.getNavigationMenu() +export const debugPermissions = () => permissionManager.debugPermissions() // 🎯 新增:快速查询某个身份的权限 export const QUICK_ROLE_CHECK = { @@ -482,4 +482,4 @@ export const QUICK_ROLE_CHECK = { pages: getRolePermissions(USER_ROLES.ANCHOR), canAccess: (page) => hasRolePermission(USER_ROLES.ANCHOR, page), }, -}; +} diff --git a/src/utils/routeGuard.js b/src/utils/routeGuard.js index effa4d6..7e615dd 100644 --- a/src/utils/routeGuard.js +++ b/src/utils/routeGuard.js @@ -3,24 +3,24 @@ * 提供APP连接检查、页面访问权限控制和自动重定向功能 */ -import { permissionManager, PAGES, USER_ROLES } from "./permissionManager.js"; -import { getUserIdentity, getMemberProfile } from "../api/wallet.js"; -import { getUserId, setUserInfo } from "./userStore.js"; +import { permissionManager, PAGES, USER_ROLES } from './permissionManager.js' +import { getUserIdentity, getMemberProfile } from '../api/wallet.js' +import { getUserId, setUserInfo } from './userStore.js' import { connectApplication, parseAccessOrigin, parseHeader, setHttpHeaders, isInApp, -} from "./appBridge.js"; -import { appConnectionManager, isAppConnected } from "./appConnectionManager.js"; +} from './appBridge.js' +import { appConnectionManager, isAppConnected } from './appConnectionManager.js' /** * APP连接检查器 */ class AppConnectionChecker { constructor() { - this.isConnecting = false; + this.isConnecting = false } /** @@ -28,38 +28,38 @@ class AppConnectionChecker { * @returns {Promise} 连接是否成功 */ async ensureConnection() { - console.debug("🔗 Checking APP connection..."); + console.debug('🔗 Checking APP connection...') // 如果不在APP环境中,直接返回成功 - console.log("我是app环境", window.app); - console.log("我是app环境", window.webkit); - console.log("我是app环境", window.FlutterPageControl); + console.log('我是app环境', window.app) + console.log('我是app环境', window.webkit) + console.log('我是app环境', window.FlutterPageControl) if (!isInApp()) { - console.debug("🌐 Browser environment, no connection needed"); - return true; + console.debug('🌐 Browser environment, no connection needed') + return true } // 如果已经连接且未超时,直接返回成功 if (isAppConnected()) { - console.debug("✅ APP already connected"); - return true; + console.debug('✅ APP already connected') + return true } // 如果正在连接中,等待现有连接 if (appConnectionManager.isConnecting()) { - console.debug("⏳ Connection already in progress, waiting..."); + console.debug('⏳ Connection already in progress, waiting...') try { - await appConnectionManager.getConnectionPromise(); - return isAppConnected(); + await appConnectionManager.getConnectionPromise() + return isAppConnected() } catch (error) { - console.error("❌ Connection wait failed:", error); - return false; + console.error('❌ Connection wait failed:', error) + return false } } // 开始新的连接 - return await this._performConnection(); + return await this._performConnection() } /** @@ -68,51 +68,51 @@ class AppConnectionChecker { */ async _performConnection() { try { - console.debug("📱 Starting new APP connection..."); + console.debug('📱 Starting new APP connection...') const connectionPromise = new Promise((resolve, reject) => { connectApplication(async (access) => { try { - const result = parseAccessOrigin(access); + const result = parseAccessOrigin(access) if (result.success) { // 解析头部信息 - const headerInfo = parseHeader(result.data); + const headerInfo = parseHeader(result.data) // 设置HTTP请求头 - await setHttpHeaders(headerInfo); + await setHttpHeaders(headerInfo) // 更新连接状态 - appConnectionManager.setConnected(headerInfo); + appConnectionManager.setConnected(headerInfo) - console.debug("🎉 APP connection established successfully"); + console.debug('🎉 APP connection established successfully') // APP连接成功后立即获取用户信息 - await this._fetchUserInfoAfterConnection(); + await this._fetchUserInfoAfterConnection() - resolve(true); + resolve(true) } else { - console.error("❌ Failed to parse access origin:", result.error); - appConnectionManager.reset(); - reject(new Error(result.error)); + console.error('❌ Failed to parse access origin:', result.error) + appConnectionManager.reset() + reject(new Error(result.error)) } } catch (error) { - console.error("❌ Connection process failed:", error); - appConnectionManager.reset(); - reject(error); + console.error('❌ Connection process failed:', error) + appConnectionManager.reset() + reject(error) } - }); - }); + }) + }) // 设置连接状态 - appConnectionManager.setConnecting(connectionPromise); + appConnectionManager.setConnecting(connectionPromise) // 等待连接完成 - return await connectionPromise; + return await connectionPromise } catch (error) { - console.error("❌ APP connection failed:", error); - appConnectionManager.reset(); - return false; + console.error('❌ APP connection failed:', error) + appConnectionManager.reset() + return false } } @@ -122,21 +122,21 @@ class AppConnectionChecker { */ async _fetchUserInfoAfterConnection() { try { - console.debug("👤 Fetching user info after connection..."); + console.debug('👤 Fetching user info after connection...') - const response = await getMemberProfile(); + const response = await getMemberProfile() if (response && response.status && response.body) { // 缓存用户信息 - console.debug("✅ User info cached successfully"); - setUserInfo(response.body, null); + console.debug('✅ User info cached successfully') + setUserInfo(response.body, null) } else { - console.warn("⚠️ Failed to get team entry or invalid response"); + console.warn('⚠️ Failed to get team entry or invalid response') } } catch (error) { // 这里不抛出错误,因为APP连接已经成功 // 用户信息获取失败可以在后续的身份检查中处理 - console.warn("⚠️ Failed to fetch user info after connection:", error); + console.warn('⚠️ Failed to fetch user info after connection:', error) } } @@ -144,7 +144,7 @@ class AppConnectionChecker { * 重置连接状态 */ reset() { - appConnectionManager.reset(); + appConnectionManager.reset() } } @@ -153,8 +153,8 @@ class AppConnectionChecker { */ class IdentityChecker { constructor() { - this.isChecking = false; - this.checkPromise = null; + this.isChecking = false + this.checkPromise = null } /** @@ -164,26 +164,26 @@ class IdentityChecker { */ async checkUserIdentity(userId) { if (!userId) { - console.warn("⚠️ No user ID provided"); - permissionManager.setUserIdentity(null); - return USER_ROLES.GUEST; + console.warn('⚠️ No user ID provided') + permissionManager.setUserIdentity(null) + return USER_ROLES.GUEST } // 如果正在检查中,等待现有的检查完成 if (this.isChecking && this.checkPromise) { - console.debug("⏳ Identity check already in progress, waiting..."); - return await this.checkPromise; + console.debug('⏳ Identity check already in progress, waiting...') + return await this.checkPromise } - this.isChecking = true; - this.checkPromise = this._performIdentityCheck(userId); + this.isChecking = true + this.checkPromise = this._performIdentityCheck(userId) try { - const primaryRole = await this.checkPromise; - return primaryRole; + const primaryRole = await this.checkPromise + return primaryRole } finally { - this.isChecking = false; - this.checkPromise = null; + this.isChecking = false + this.checkPromise = null } } @@ -194,27 +194,27 @@ class IdentityChecker { */ async _performIdentityCheck(userId) { try { - console.debug("🔍 Checking user identity for:", userId); + console.debug('🔍 Checking user identity for:', userId) - const response = await getUserIdentity(); + const response = await getUserIdentity() if (response && response.status && response.body) { - const identity = response.body; - console.debug("✅ Identity fetched:", identity); + const identity = response.body + console.debug('✅ Identity fetched:', identity) // 设置权限信息 - permissionManager.setUserIdentity(identity); + permissionManager.setUserIdentity(identity) - return permissionManager.getPrimaryRole(); + return permissionManager.getPrimaryRole() } else { - console.warn("⚠️ Invalid identity response"); - permissionManager.setUserIdentity(null); - return USER_ROLES.GUEST; + console.warn('⚠️ Invalid identity response') + permissionManager.setUserIdentity(null) + return USER_ROLES.GUEST } } catch (error) { - console.error("❌ Failed to fetch user identity:", error); - permissionManager.setUserIdentity(null); - return USER_ROLES.GUEST; + console.error('❌ Failed to fetch user identity:', error) + permissionManager.setUserIdentity(null) + return USER_ROLES.GUEST } } @@ -222,8 +222,8 @@ class IdentityChecker { * 重置检查状态 */ reset() { - this.isChecking = false; - this.checkPromise = null; + this.isChecking = false + this.checkPromise = null } } @@ -239,36 +239,36 @@ class PageRedirector { * @returns {Promise} 是否进行了重定向 */ async redirectToCorrectPage(router, targetPath, currentPath) { - const primaryRole = permissionManager.getPrimaryRole(); + const primaryRole = permissionManager.getPrimaryRole() // 检查目标页面权限 - const hasPermission = permissionManager.hasPagePermission(targetPath); + const hasPermission = permissionManager.hasPagePermission(targetPath) - console.debug("🔄 Redirect check:", { + console.debug('🔄 Redirect check:', { targetPath, currentPath, primaryRole, hasPermission, - }); + }) if (hasPermission) { // 有权限访问目标页面 if (targetPath !== currentPath) { - console.debug("✅ Access granted, navigating to:", targetPath); - return false; // 不需要重定向,让路由正常进行 + console.debug('✅ Access granted, navigating to:', targetPath) + return false // 不需要重定向,让路由正常进行 } - return false; + return false } else { // 无权限访问,重定向到默认页面 - const defaultPage = permissionManager.getDefaultPage(); + const defaultPage = permissionManager.getDefaultPage() - console.debug("❌ Access denied, redirecting to:", defaultPage); + console.debug('❌ Access denied, redirecting to:', defaultPage) if (defaultPage !== currentPath) { - await router.replace(defaultPage); - return true; // 已进行重定向 + await router.replace(defaultPage) + return true // 已进行重定向 } - return false; + return false } } @@ -278,17 +278,17 @@ class PageRedirector { * @param {string} attemptedPage - 尝试访问的页面 */ async handleUnauthorizedAccess(router, attemptedPage) { - const primaryRole = permissionManager.getPrimaryRole(); - const defaultPage = permissionManager.getDefaultPage(); + const primaryRole = permissionManager.getPrimaryRole() + const defaultPage = permissionManager.getDefaultPage() - console.warn("🚫 Unauthorized access attempt:", { + console.warn('🚫 Unauthorized access attempt:', { attemptedPage, primaryRole, redirectingTo: defaultPage, - }); + }) // 重定向到用户有权限的默认页面 - await router.replace(defaultPage); + await router.replace(defaultPage) } } @@ -297,10 +297,10 @@ class PageRedirector { */ class RouteGuard { constructor() { - this.appConnectionChecker = new AppConnectionChecker(); - this.identityChecker = new IdentityChecker(); - this.pageRedirector = new PageRedirector(); - this.isGuardActive = false; + this.appConnectionChecker = new AppConnectionChecker() + this.identityChecker = new IdentityChecker() + this.pageRedirector = new PageRedirector() + this.isGuardActive = false } /** @@ -309,11 +309,11 @@ class RouteGuard { */ install(router) { router.beforeEach(async (to, from, next) => { - await this.handleRouteChange(to, from, next); - }); + await this.handleRouteChange(to, from, next) + }) - this.isGuardActive = true; - console.debug("🛡️ Route guard installed"); + this.isGuardActive = true + console.debug('🛡️ Route guard installed') } /** @@ -323,68 +323,68 @@ class RouteGuard { * @param {Function} next - 路由继续函数 */ async handleRouteChange(to, from, next) { - console.group("🛡️ Route Guard Check"); - console.debug("📍 Route change:", from.path, "→", to.path); + console.group('🛡️ Route Guard Check') + console.debug('📍 Route change:', from.path, '→', to.path) try { // 1. 检查是否为公共页面(无需任何验证) if (this.isPublicPage(to.path)) { - console.debug("🌐 Public page, allowing access"); - console.groupEnd(); - next(); - return; + console.debug('🌐 Public page, allowing access') + console.groupEnd() + next() + return } // 2. 确保APP连接 - console.debug("🔗 Ensuring APP connection..."); - const isConnected = await this.appConnectionChecker.ensureConnection(); + console.debug('🔗 Ensuring APP connection...') + const isConnected = await this.appConnectionChecker.ensureConnection() if (!isConnected) { - console.error("❌ APP connection failed, redirecting to error page"); - console.groupEnd(); - next(PAGES.NOT_APP); - return; + console.error('❌ APP connection failed, redirecting to error page') + console.groupEnd() + next(PAGES.NOT_APP) + return } // 3. 检查用户身份是否已加载 if (!permissionManager.isLoaded()) { - console.debug("🔍 Identity not loaded, checking..."); + console.debug('🔍 Identity not loaded, checking...') - const userId = getUserId(); + const userId = getUserId() if (!userId) { - console.debug("❌ No user ID available, redirecting to apply"); - console.groupEnd(); - next(PAGES.APPLY); - return; + console.debug('❌ No user ID available, redirecting to apply') + console.groupEnd() + next(PAGES.APPLY) + return } // 检查用户身份 - await this.identityChecker.checkUserIdentity(userId); + await this.identityChecker.checkUserIdentity(userId) } // 4. 检查页面访问权限 - const hasPermission = permissionManager.hasPagePermission(to.path); + const hasPermission = permissionManager.hasPagePermission(to.path) if (hasPermission) { - console.debug("✅ Permission granted, allowing access"); - console.groupEnd(); - next(); + console.debug('✅ Permission granted, allowing access') + console.groupEnd() + next() } else { - console.debug("❌ Permission denied"); - const defaultPage = permissionManager.getDefaultPage(); - console.debug("🔄 Redirecting to default page:", defaultPage); - console.groupEnd(); - next(defaultPage); + console.debug('❌ Permission denied') + const defaultPage = permissionManager.getDefaultPage() + console.debug('🔄 Redirecting to default page:', defaultPage) + console.groupEnd() + next(defaultPage) } } catch (error) { - console.error("❌ Route guard error:", error); - console.groupEnd(); + console.error('❌ Route guard error:', error) + console.groupEnd() // 根据错误类型决定重定向目标 - if (error.message && error.message.includes("connection")) { - next(PAGES.NOT_APP); // 连接相关错误 + if (error.message && error.message.includes('connection')) { + next(PAGES.NOT_APP) // 连接相关错误 } else { - next(PAGES.APPLY); // 其他错误 + next(PAGES.APPLY) // 其他错误 } } } @@ -396,15 +396,19 @@ class RouteGuard { */ isPublicPage(path) { const publicPages = [ - PAGES.APPLY, // 申请页面 - 重要:申请页面不需要权限检查 - PAGES.NOT_APP, // 错误页面 - APP连接失败时的页面 - '/404', // 404页面 - '/error', // 通用错误页面 + PAGES.APPLY, // 申请页面 - 重要:申请页面不需要权限检查 + PAGES.NOT_APP, // 错误页面 - APP连接失败时的页面 + '/404', // 404页面 + '/error', // 通用错误页面 '/recharge', '/recharge-freight-agent', - '/pay-result' + '/pay-result', + + '/admin-center', + '/item-distribution', + '/map', //地图 ] - return publicPages.includes(path); + return publicPages.includes(path) } /** @@ -414,26 +418,26 @@ class RouteGuard { */ async checkAndRedirect(router, userId) { try { - console.debug("🔄 Manual identity check and redirect"); + console.debug('🔄 Manual identity check and redirect') // 检查身份 - const primaryRole = await this.identityChecker.checkUserIdentity(userId); + const primaryRole = await this.identityChecker.checkUserIdentity(userId) // 获取当前页面 - const currentPath = router.currentRoute.value.path; + const currentPath = router.currentRoute.value.path // 检查当前页面权限 - const hasPermission = permissionManager.hasPagePermission(currentPath); + const hasPermission = permissionManager.hasPagePermission(currentPath) if (!hasPermission) { // 重定向到默认页面 - await this.pageRedirector.redirectToCorrectPage(router, currentPath, currentPath); + await this.pageRedirector.redirectToCorrectPage(router, currentPath, currentPath) } - return primaryRole; + return primaryRole } catch (error) { - console.error("❌ Manual check and redirect failed:", error); - throw error; + console.error('❌ Manual check and redirect failed:', error) + throw error } } @@ -441,17 +445,17 @@ class RouteGuard { * 重置守卫状态 */ reset() { - this.appConnectionChecker.reset(); - this.identityChecker.reset(); - permissionManager.reset(); - console.debug("🔄 Route guard reset"); + this.appConnectionChecker.reset() + this.identityChecker.reset() + permissionManager.reset() + console.debug('🔄 Route guard reset') } } // 创建全局路由守卫实例 -export const routeGuard = new RouteGuard(); +export const routeGuard = new RouteGuard() // 便捷方法 -export const installRouteGuard = (router) => routeGuard.install(router); -export const checkAndRedirect = (router, userId) => routeGuard.checkAndRedirect(router, userId); -export const resetRouteGuard = () => routeGuard.reset(); +export const installRouteGuard = (router) => routeGuard.install(router) +export const checkAndRedirect = (router, userId) => routeGuard.checkAndRedirect(router, userId) +export const resetRouteGuard = () => routeGuard.reset() diff --git a/src/views/TopList/TopList.vue b/src/views/TopList/TopList.vue new file mode 100644 index 0000000..2ab606d --- /dev/null +++ b/src/views/TopList/TopList.vue @@ -0,0 +1,215 @@ + + + + +