diff --git a/src/components/SideNav.vue b/src/components/SideNav.vue index 7158cf5..47c437f 100644 --- a/src/components/SideNav.vue +++ b/src/components/SideNav.vue @@ -389,8 +389,11 @@ const showMessageDialog = ref(false) const showFeedbackDialog = ref(false) /** 当前hover的菜单索引,-1表示无hover */ const hoverIndex = ref(-1) -/** 会员权限拦截弹窗 */ -const showMemberAccessDialog = ref(false) +/** 会员权限拦截弹窗 — 读写 store 全局状态(路由守卫也可触发) */ +const showMemberAccessDialog = computed({ + get: () => store.state.showMemberAccessDialog, + set: (val: boolean) => store.commit('SET_SHOW_MEMBER_ACCESS_DIALOG', val), +}) /** 会员购买弹窗 */ const showMemberDialog = ref(false) const showSettingsDialog = computed({ diff --git a/src/router/index.ts b/src/router/index.ts index 550aef2..202d6ff 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -2,6 +2,7 @@ import { createRouter, createWebHistory } from 'vue-router' import type { RouteRecordRaw } from 'vue-router' import store from '@/stores' import { checkLogin } from '@/api/auth' +import { fetchMemberStatus } from '@/api/member' /** * 静态路由 — 不需要权限,应用启动就注册 @@ -125,6 +126,33 @@ router.beforeEach(async (to, _from, next) => { return } + // Agent 页面需要会员权限 — 等待会员信息加载后判断 + if (to.name === 'Agent') { + try { + // 确保会员信息已加载到 store + if (!store.state.memberStatus) { + const res = await fetchMemberStatus() + if (res.code === '0' && res.data) { + store.commit('SET_MEMBER_STATUS', res.data) + } + } + const status = store.state.memberStatus + // 试用会员(memberType=2)或正式会员(memberType=1)才能进入 + if (status && status.isMember && (status.memberType === 1 || status.memberType === 2)) { + next() + } else { + // 免费用户 — 弹出会员权限拦截弹窗,阻止跳转 + store.commit('SET_SHOW_MEMBER_ACCESS_DIALOG', true) + next(false) + } + } catch { + // 接口异常时弹窗提示,不放行 + store.commit('SET_SHOW_MEMBER_ACCESS_DIALOG', true) + next(false) + } + return + } + // 非鉴权路由 — 静默同步登录状态(节流:5 分钟内不重复请求) if (Date.now() - lastCheckTime > CHECK_INTERVAL) { checkLogin() diff --git a/src/stores/index.ts b/src/stores/index.ts index 19ac476..1e01e16 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -159,6 +159,11 @@ export interface RootState { * 登录成功后自动清空,避免重复发送 */ inviteCode: string + + /** + * 全局会员权限拦截弹窗 — 路由守卫或页面检测到免费用户时触发 + */ + showMemberAccessDialog: boolean } export default createStore({ @@ -189,6 +194,7 @@ export default createStore({ showSettings: false, settingsTab: 'account', inviteCode: '', + showMemberAccessDialog: false, }, getters: { getAppName: (state) => state.appName, @@ -261,6 +267,9 @@ export default createStore({ SET_INVITE_CODE(state, code: string) { state.inviteCode = code }, + SET_SHOW_MEMBER_ACCESS_DIALOG(state, show: boolean) { + state.showMemberAccessDialog = show + }, }, actions: { updateAppName({ commit }, name: string) { diff --git a/src/views/Agent.vue b/src/views/Agent.vue index bc84d50..a940c70 100644 --- a/src/views/Agent.vue +++ b/src/views/Agent.vue @@ -242,6 +242,8 @@