diff --git a/src/business.config.ts b/src/business.config.ts new file mode 100644 index 0000000..664ae3f --- /dev/null +++ b/src/business.config.ts @@ -0,0 +1,9 @@ +/** + * 业务配置文件 — 集中管理可开关的业务策略 + */ + +/** 是否开启"个人资料为空时强制跳转到登录页简历上传"机制 */ +export const ENABLE_FORCE_RESUME_UPLOAD = true + +/** 浏览器插件目标版本(用于判断用户是否需要更新插件) */ +export const PLUGIN_TARGET_VERSION = '0.1.0' diff --git a/src/router/index.ts b/src/router/index.ts index 2b8d47c..66a3f00 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -3,6 +3,8 @@ import type { RouteRecordRaw } from 'vue-router' import store from '@/stores' import { checkLogin } from '@/api/auth' import { fetchMemberStatus } from '@/api/member' +import { fetchProfile } from '@/api/profile' +import { ENABLE_FORCE_RESUME_UPLOAD } from '@/business.config' /** * 静态路由 — 不需要权限,应用启动就注册 @@ -98,9 +100,13 @@ router.beforeEach(async (to, _from, next) => { // 每次页面切换时静默刷新路由菜单数据(更新权限状态),不阻塞导航 store.dispatch('refreshDynamicMenus') - // 已登录用户访问登录页,直接跳转首页 + // 已登录用户访问登录页,如果带 resumeUpload=1 参数则放行(简历上传流程),否则跳转首页 if (to.name === 'Login' && store.state.isAuthenticated) { - next({ name: 'Home' }) + if (to.query.resumeUpload === '1') { + next() + } else { + next({ name: 'Home' }) + } return } @@ -112,6 +118,16 @@ router.beforeEach(async (to, _from, next) => { if (res.code === '0' && res.data === true) { // Cookie 有效,同步前端状态并放行 store.commit('SET_AUTHENTICATED', true) + // 检查个人资料是否为空(强制简历上传机制) + if (ENABLE_FORCE_RESUME_UPLOAD) { + try { + const profileRes = await fetchProfile() + if (profileRes.code === '0' && !profileRes.data) { + next({ name: 'Login', query: { resumeUpload: '1' } }) + return + } + } catch { /* 接口异常不阻断 */ } + } next() } else { // 未登录或 Cookie 失效 — 跳转登录页 @@ -129,6 +145,16 @@ router.beforeEach(async (to, _from, next) => { // Agent 页面需要会员权限 — 等待会员信息加载后判断 if (to.name === 'Agent') { try { + // 先检查个人资料是否为空(强制简历上传机制) + if (ENABLE_FORCE_RESUME_UPLOAD) { + try { + const profileRes = await fetchProfile() + if (profileRes.code === '0' && !profileRes.data) { + next({ name: 'Login', query: { resumeUpload: '1' } }) + return + } + } catch { /* 接口异常不阻断 */ } + } // 确保会员信息已加载到 store if (!store.state.memberStatus) { const res = await fetchMemberStatus() @@ -169,6 +195,25 @@ router.beforeEach(async (to, _from, next) => { }) } + // 已登录 + 非首页/登录页/移动首页:检查个人资料是否为空,为空则强制跳转简历上传 + const skipProfileCheck = ['Home', 'HomeMobile', 'Login'] + if ( + ENABLE_FORCE_RESUME_UPLOAD && + store.state.isAuthenticated && + !skipProfileCheck.includes(to.name as string) + ) { + try { + const profileRes = await fetchProfile() + if (profileRes.code === '0' && !profileRes.data) { + // 个人资料为空 — 跳转到登录页简历上传步骤 + next({ name: 'Login', query: { resumeUpload: '1' } }) + return + } + } catch { + // 接口异常不阻断导航 + } + } + next() }) diff --git a/src/stores/index.ts b/src/stores/index.ts index 0239dad..cd7af47 100644 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -12,6 +12,7 @@ import type { UserInfo } from '@/api/auth' import { fetchMemberStatus } from '@/api/member' import type { MemberStatus } from '@/api/member' import { createChannelBridge } from '@/utils/channelBridge' +import { PLUGIN_TARGET_VERSION } from '@/business.config' /** 招聘分类选项:label → 接口参数 recruitCategory */ export const JOB_TYPE_OPTIONS: { label: string; value: number }[] = [ @@ -218,7 +219,7 @@ export default createStore({ /** 插件当前使用版本 */ plugUseVersion: '', /** 插件目标版本 */ - plugTargetVersion: '0.1.0', + plugTargetVersion: PLUGIN_TARGET_VERSION, /** 插件是否是最新版本 */ isLatestPlugin: true, }, diff --git a/src/views/Login.vue b/src/views/Login.vue index df23435..7b42d6a 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue @@ -941,6 +941,13 @@ function handleVisibilityChange() { /** 挂载时初始化动画 */ onMounted(() => { + // 如果路由带 resumeUpload=1 参数,直接跳到简历上传步骤 + if (route.query.resumeUpload === '1') { + step.value = 3 + resumeState.value = 'upload' + loginRedirect = (route.query.redirect as string) || '/jobs' + } + // 设置背景图 if (stageRef.value) { stageRef.value.style.backgroundImage = `url(${bgSrc})`