From 73f5bde68fbb9fec061f10b6a551b7f1a4546377 Mon Sep 17 00:00:00 2001 From: xuxin <15279969124@163.com> Date: Mon, 6 Jul 2026 21:34:40 +0800 Subject: [PATCH] =?UTF-8?q?=E7=A7=BB=E5=8A=A8=E7=AB=AF=E9=A6=96=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components.d.ts | 2 - src/api/resume.ts | 20 + src/assets/images/home/mobile-qcCode.png | Bin 0 -> 7600 bytes src/assets/styles/index.scss | 1 + src/assets/styles/pages/home-mobile.scss | 623 +++++++++++++++++++++++ src/components/ResumeEditNameDialog.vue | 6 +- src/plugins/remAdapt.ts | 23 +- src/router/dynamicRoutes.ts | 2 +- src/router/index.ts | 29 +- src/utils/dailyJobCount.ts | 16 + src/views/Home.vue | 14 +- src/views/HomeMobile.vue | 198 +++++++ src/views/Resume.vue | 3 - 13 files changed, 913 insertions(+), 24 deletions(-) create mode 100644 src/assets/images/home/mobile-qcCode.png create mode 100644 src/assets/styles/pages/home-mobile.scss create mode 100644 src/utils/dailyJobCount.ts create mode 100644 src/views/HomeMobile.vue diff --git a/components.d.ts b/components.d.ts index bfb7102..ca32517 100644 --- a/components.d.ts +++ b/components.d.ts @@ -25,8 +25,6 @@ declare module 'vue' { AiChat: typeof import('./src/components/AiChat.vue')['default'] AiThinkingIndicator: typeof import('./src/components/tools/AiThinkingIndicator.vue')['default'] ElButton: typeof import('element-plus/es')['ElButton'] - ElCarousel: typeof import('element-plus/es')['ElCarousel'] - ElCarouselItem: typeof import('element-plus/es')['ElCarouselItem'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDialog: typeof import('element-plus/es')['ElDialog'] diff --git a/src/api/resume.ts b/src/api/resume.ts index 26e434c..9031f06 100644 --- a/src/api/resume.ts +++ b/src/api/resume.ts @@ -715,3 +715,23 @@ export function resolveDiagnosisIssue(issueId: string) { }], }).then(res => res.data) } + +// ==================== 修改简历名称和目标岗位(新 Java 后端接口) ==================== + +/** 修改简历名称/目标岗位 请求参数 */ +export interface UpdateResumeInfoParams { + /** 简历 ID(必需,字符串避免大整数精度丢失) */ + resumeId: string + /** 简历名称(可选,<= 100 字符) */ + resumeName?: string + /** 目标岗位(可选,<= 100 字符) */ + targetPosition?: string +} + +/** + * 修改简历名称和目标岗位 + * POST /resume/updateInfo + */ +export function updateResumeInfo(data: UpdateResumeInfoParams) { + return request.post('/resume/updateInfo', data) +} diff --git a/src/assets/images/home/mobile-qcCode.png b/src/assets/images/home/mobile-qcCode.png new file mode 100644 index 0000000000000000000000000000000000000000..6bf298ed445e9bb7fb4a3e7ce69b34f70a0c54d2 GIT binary patch literal 7600 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 import { ref, reactive, watch } from 'vue' -import { saveResumeMain } from '@/api/resume' +import { updateResumeInfo } from '@/api/resume' import { ElMessage } from 'element-plus' // ==================== Props & Emits ==================== @@ -108,7 +108,7 @@ function handleClose() { visible.value = false } -/** 保存简历名称和目标岗位 */ +/** 保存简历名称和目标岗位(调用新 Java 后端接口 /resume/updateInfo) */ async function handleSave() { if (!form.resumeName.trim()) { ElMessage.warning('请输入简历名称') @@ -117,7 +117,7 @@ async function handleSave() { saving.value = true try { - const res = await saveResumeMain({ + const res = await updateResumeInfo({ resumeId: props.resumeId, resumeName: form.resumeName.trim(), targetPosition: form.targetPosition.trim(), diff --git a/src/plugins/remAdapt.ts b/src/plugins/remAdapt.ts index 611cb19..e875c24 100644 --- a/src/plugins/remAdapt.ts +++ b/src/plugins/remAdapt.ts @@ -28,7 +28,26 @@ const remAdaptPlugin: Plugin = { if (!body) return if (isMobile()) { - // 移动端:使用 transform scale 缩放整个页面 + // 移动端首页(/m):不使用 scale 缩放,直接以移动端原生尺寸渲染 + const isMobileHome = window.location.pathname === '/m' + if (isMobileHome) { + body.style.width = '' + body.style.height = '' + body.style.minHeight = '' + body.style.overflowY = '' + body.style.transform = '' + body.style.transformOrigin = '' + docEl.style.height = '' + docEl.style.overflow = '' + // 移动端首页 1rem = 视口宽度 / 3.90(设计稿 390px) + const mobileFontSize = clientWidth / 3.90 + docEl.style.fontSize = mobileFontSize + 'px' + docEl.style.setProperty('--app-height', '100vh') + docEl.style.setProperty('--chat-width', '100%') + return + } + + // 其他页面:使用 transform scale 缩放整个页面 const scale = clientWidth / designWidth body.style.width = designWidth + 'px' body.style.transform = `scale(${scale})` @@ -36,7 +55,7 @@ const remAdaptPlugin: Plugin = { // 屏幕越小 scale 越小,适当增大 rem 基准让字体视觉上更大 // 首页和其他页面使用不同的缩放系数 - const isHomePage = window.location.pathname === '/' || window.location.pathname === '/index.html' + const isHomePage = window.location.pathname === '/' || window.location.pathname === '/index.html' || window.location.pathname === '/m' const homeMultiplier = 0.6 // 首页字体放大系数,可单独调整 const otherMultiplier = 2.0 // 其他页面字体放大系数 const multiplier = isHomePage ? homeMultiplier : otherMultiplier diff --git a/src/router/dynamicRoutes.ts b/src/router/dynamicRoutes.ts index c784ad0..02180f8 100644 --- a/src/router/dynamicRoutes.ts +++ b/src/router/dynamicRoutes.ts @@ -23,7 +23,7 @@ const componentMap: Record Promise> = { * 如果后端返回了一个 component 字符串在映射表里找不到,会跳过该条路由并打印警告 * 已在静态路由中注册的路径(如 /jobs)不再重复注册 */ -const STATIC_PATHS = ['/', '/jobs', '/resume/:id', '/jobs/:id', '/mentor/:id'] +const STATIC_PATHS = ['/', '/m', '/jobs', '/resume/:id', '/jobs/:id', '/mentor/:id'] export function buildDynamicRoutes(menus: MenuItemRaw[]): RouteRecordRaw[] { const routes: RouteRecordRaw[] = [] diff --git a/src/router/index.ts b/src/router/index.ts index bd6b06f..550aef2 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -8,6 +8,7 @@ import { checkLogin } from '@/api/auth' */ const staticRoutes: RouteRecordRaw[] = [ { path: '/', name: 'Home', component: () => import('@/views/Home.vue') }, + { path: '/m', name: 'HomeMobile', component: () => import('@/views/HomeMobile.vue') }, { path: '/login', name: 'Login', component: () => import('@/views/Login.vue') }, { path: '/jobs', @@ -38,6 +39,14 @@ const router = createRouter({ routes: staticRoutes, }) +/** + * 检测是否为移动端设备 + */ +function isMobileDevice(): boolean { + return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) + || window.innerWidth < 768 +} + /** * 上次静默校验登录状态的时间戳,用于节流(5 分钟内不重复请求) */ @@ -55,6 +64,17 @@ const CHECK_INTERVAL = 5 * 60 * 1000 // 5 分钟 * 4. 不需要鉴权的路由 → 静默同步登录状态(不阻止导航、不弹登录框),5 分钟内节流 */ router.beforeEach(async (to, _from, next) => { + // 移动端访问首页时重定向到移动版首页 + if (to.name === 'Home' && isMobileDevice()) { + next({ name: 'HomeMobile', replace: true }) + return + } + // PC端访问移动版首页时重定向到PC首页 + if (to.name === 'HomeMobile' && !isMobileDevice()) { + next({ name: 'Home', replace: true }) + return + } + // 动态路由只需加载一次,与登录状态无关 if (!store.state.routesLoaded) { try { @@ -62,7 +82,14 @@ router.beforeEach(async (to, _from, next) => { next({ ...to, replace: true }) } catch (err) { console.error('[router] 加载动态路由失败', err) - next({ name: 'Home' }) + // 即使接口失败也标记路由已加载,确保首页正常展示 + store.commit('SET_ROUTES_LOADED', true) + // 首页不需要依赖动态路由接口,正常放行 + if (to.name === 'Home' || to.name === 'HomeMobile') { + next() + } else { + next({ name: 'Home' }) + } } return } diff --git a/src/utils/dailyJobCount.ts b/src/utils/dailyJobCount.ts new file mode 100644 index 0000000..3fea752 --- /dev/null +++ b/src/utils/dailyJobCount.ts @@ -0,0 +1,16 @@ +/** + * 每日岗位数量哈希算法工具 + * 根据当前日期生成 3000~4000 之间的确定性数值 + * 同一天所有用户看到的数字一致 + */ + +/** 根据当前日期生成确定性岗位数量 */ +export function getDailyJobCount(): number { + const today = new Date() + const seed = today.getFullYear() * 10000 + (today.getMonth() + 1) * 100 + today.getDate() + let hash = seed + hash = ((hash >> 16) ^ hash) * 0x45d9f3b + hash = ((hash >> 16) ^ hash) * 0x45d9f3b + hash = (hash >> 16) ^ hash + return 3000 + (Math.abs(hash) % 1001) +} diff --git a/src/views/Home.vue b/src/views/Home.vue index 33a395a..330a0d4 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -493,6 +493,7 @@ import IndustrySelector from '@/components/tools/IndustrySelector.vue' import RegionSelector from '@/components/tools/RegionSelector.vue' import JobCategorySelector from '@/components/tools/JobCategorySelector.vue' import AgreementPreviewDialog from '@/components/tools/AgreementPreviewDialog.vue' +import { getDailyJobCount } from '@/utils/dailyJobCount' /** 路由实例 */ const router = useRouter() @@ -502,18 +503,7 @@ const store = useStore() /** 页面是否已向下滚动超过 20px — 用于导航栏背景切换 */ const isScrolled = ref(false) -/** 根据当前日期生成 3000~4000 之间的确定性岗位数量(同一天所有用户看到的数字一致) */ -function getDailyJobCount(): number { - const today = new Date() - const seed = today.getFullYear() * 10000 + (today.getMonth() + 1) * 100 + today.getDate() - let hash = seed - hash = ((hash >> 16) ^ hash) * 0x45d9f3b - hash = ((hash >> 16) ^ hash) * 0x45d9f3b - hash = (hash >> 16) ^ hash - return 3000 + (Math.abs(hash) % 1001) -} - -/** 今日更新岗位数量 — 每日确定性变化 */ +/** 今日更新岗位数量 — 每日确定性变化(使用公共哈希工具) */ const dailyJobCount = getDailyJobCount() /** 当前展开的 FAQ 索引,-1 表示全部收起 */ diff --git a/src/views/HomeMobile.vue b/src/views/HomeMobile.vue new file mode 100644 index 0000000..acce229 --- /dev/null +++ b/src/views/HomeMobile.vue @@ -0,0 +1,198 @@ + + + diff --git a/src/views/Resume.vue b/src/views/Resume.vue index cb4bee0..a064022 100644 --- a/src/views/Resume.vue +++ b/src/views/Resume.vue @@ -37,9 +37,6 @@ >
- - - {{ item.name }} 默认