From 8cd21e7b98bc45d6ad84ed1fcc19a2e549f168ce Mon Sep 17 00:00:00 2001 From: xuxin <15279969124@163.com> Date: Fri, 10 Jul 2026 16:29:31 +0800 Subject: [PATCH] =?UTF-8?q?ai=E5=8A=A9=E6=89=8B=E6=8A=95=E9=80=92=E5=81=8F?= =?UTF-8?q?=E5=A5=BD=E8=AE=BE=E7=BD=AE=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/agent.ts | 6 +- .../components/agent-apply-progress.scss | 5 + src/assets/styles/pages/jobs.scss | 17 +- src/assets/styles/pages/resume-detail.scss | 2 +- src/assets/styles/pages/resume.scss | 13 +- src/components/AgentApplyProgress.vue | 4 +- src/components/AgentSettingPanel.vue | 7 +- src/views/Agent.vue | 207 ++++++++++++++---- src/views/JobDetail.vue | 5 +- src/views/Jobs.vue | 2 +- src/views/Resume.vue | 2 +- 11 files changed, 219 insertions(+), 51 deletions(-) diff --git a/src/api/agent.ts b/src/api/agent.ts index b2f4aa6..0983dda 100644 --- a/src/api/agent.ts +++ b/src/api/agent.ts @@ -23,7 +23,7 @@ export interface AgentConfig { autoOptimizeResume?: number /** 自动匹配分析 0=关闭 1=开启 */ autoMatchAnalysis?: number - /** 是否愿意接受部门调剂 */ + /** 是否开启深度人岗匹配分析,可选值:是/否(null或空字符串视为关闭) */ acceptDeptTransfer?: string /** 是否接受地点调剂 */ acceptLocationTransfer?: string @@ -312,7 +312,9 @@ export function optimizeAgentResume(params: OptimizeResumeParams) { /** 匹配度评分请求参数 */ export interface MatchScoreParams { /** 定制简历 ID(字符串,避免大整数精度丢失) */ - customizeResumeId: string + customizeResumeId?: string + /** 普通简历 ID(关闭优化时使用) */ + resumeId?: string /** 岗位 ID(字符串,避免大整数精度丢失) */ jobId: string } diff --git a/src/assets/styles/components/agent-apply-progress.scss b/src/assets/styles/components/agent-apply-progress.scss index c126146..bbaf109 100644 --- a/src/assets/styles/components/agent-apply-progress.scss +++ b/src/assets/styles/components/agent-apply-progress.scss @@ -189,6 +189,11 @@ color: #F59E0B; } + // 匹配度偏低(红橙色) + &--low-match { + color: #FE6D52; + } + // 强调色(品牌色) &--accent { color: $accent; diff --git a/src/assets/styles/pages/jobs.scss b/src/assets/styles/pages/jobs.scss index 571d91a..ac797f7 100644 --- a/src/assets/styles/pages/jobs.scss +++ b/src/assets/styles/pages/jobs.scss @@ -131,10 +131,25 @@ &__ai-tip { position: relative; background: $bg-white; - border: 1px solid $accent; border-radius: 0.08rem; padding: 0.08rem 0.12rem 0.07rem 0.12rem; z-index: 1; + + // 渐变边框:从上到下 #9FD051 → #52CAD1(与导师页 stats 一致) + &::before { + content: ''; + position: absolute; + inset: 0; + border-radius: 0.08rem; + padding: 0.01rem; + background: linear-gradient(180deg, #9FD051 0%, #52CAD1 100%); + -webkit-mask: + linear-gradient(#fff 0 0) content-box, + linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + pointer-events: none; + } } // 提示条内容行 diff --git a/src/assets/styles/pages/resume-detail.scss b/src/assets/styles/pages/resume-detail.scss index 5078619..0fabd2e 100644 --- a/src/assets/styles/pages/resume-detail.scss +++ b/src/assets/styles/pages/resume-detail.scss @@ -21,7 +21,7 @@ margin-bottom: 0.16rem; background: #fff; >h2{ - font-size: 0.24rem; + font-size: 0.18rem; font-weight: 700; color: $text-dark; } diff --git a/src/assets/styles/pages/resume.scss b/src/assets/styles/pages/resume.scss index 98f0927..0e3490a 100644 --- a/src/assets/styles/pages/resume.scss +++ b/src/assets/styles/pages/resume.scss @@ -23,7 +23,7 @@ } &__title { - font-size: 0.24rem; + font-size: 0.18rem; font-weight: 700; color: $text-dark; margin: 0; @@ -138,6 +138,13 @@ opacity: 0; transition: opacity 0.15s; } + + &--ellipsis { + max-width: 3.6rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } &__row:hover &__td--action { @@ -166,6 +173,10 @@ &__name { font-weight: 500; + max-width: 3.6rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } &__default-tag { diff --git a/src/components/AgentApplyProgress.vue b/src/components/AgentApplyProgress.vue index bf38823..32c8203 100644 --- a/src/components/AgentApplyProgress.vue +++ b/src/components/AgentApplyProgress.vue @@ -187,7 +187,7 @@ const hintText = computed(() => { return '正在根据岗位信息优化简历...' } if (props.currentStep === 2) { - if (props.stepPhase === 'low-match') return '当前匹配度偏低,是否仍要继续投递?' + if (props.stepPhase === 'low-match') return `当前匹配度偏低:${props.matchScore ?? 0}分,是否仍要继续投递?` return '正在根据最终投递简历复核岗位匹配度...' } if (props.currentStep === 3) { @@ -203,7 +203,7 @@ const hintText = computed(() => { const hintClass = computed(() => { if (isCompleted.value) return '' if (props.currentStep === 1 && props.stepPhase === 'done') return 'agent-apply-progress__hint--warning' - if (props.currentStep === 2 && props.stepPhase === 'low-match') return 'agent-apply-progress__hint--warning' + if (props.currentStep === 2 && props.stepPhase === 'low-match') return 'agent-apply-progress__hint--low-match' if (props.currentStep === 3) return 'agent-apply-progress__hint--accent' if (props.currentStep === 4) return 'agent-apply-progress__hint--accent' return '' diff --git a/src/components/AgentSettingPanel.vue b/src/components/AgentSettingPanel.vue index f95eee1..3200626 100644 --- a/src/components/AgentSettingPanel.vue +++ b/src/components/AgentSettingPanel.vue @@ -621,7 +621,7 @@ function handleSelectResume(r: ResumeListItem) { // ==================== 投递偏好 ==================== const autoOptimizeSwitch = ref(false) -const autoMatchAnalysisSwitch = ref(true) +const autoMatchAnalysisSwitch = ref(false) /** 切换简历优化开关 */ function toggleOptimize() { @@ -641,7 +641,8 @@ async function loadAgentConfigData() { const res = await fetchAgentConfig() if (res.code === '0' && res.data) { if (res.data.autoOptimizeResume !== undefined) autoOptimizeSwitch.value = res.data.autoOptimizeResume === 1 - if (res.data.autoMatchAnalysis !== undefined) autoMatchAnalysisSwitch.value = res.data.autoMatchAnalysis === 1 + // acceptDeptTransfer: "是"=开启,null/空字符串/"否"=关闭 + autoMatchAnalysisSwitch.value = res.data.acceptDeptTransfer === '是' } } catch { /* 静默 */ } } @@ -651,7 +652,7 @@ async function handleSavePreference() { try { await saveAgentConfig({ autoOptimizeResume: autoOptimizeSwitch.value ? 1 : 0, - autoMatchAnalysis: autoMatchAnalysisSwitch.value ? 1 : 0, + acceptDeptTransfer: autoMatchAnalysisSwitch.value ? '是' : '否', }) } catch { /* 静默 */ } } diff --git a/src/views/Agent.vue b/src/views/Agent.vue index 5e7f7a9..bc84d50 100644 --- a/src/views/Agent.vue +++ b/src/views/Agent.vue @@ -814,6 +814,14 @@ async function handleStartApply() { if (isApplying.value) return isApplying.value = true + // 刷新最新配置(确保优化开关状态准确) + try { + const configRes = await fetchAgentConfig() + if (configRes.code === '0' && configRes.data) { + agentConfig.value = configRes.data + } + } catch { /* 静默 */ } + await loadApplyList() if (applyJobList.value.length === 0) { @@ -825,22 +833,60 @@ async function handleStartApply() { // 取第一个岗位 const targetJob = applyJobList.value[0] - // 创建进度条目 - const progressItem: ApplyProgressItem = { - id: Date.now(), - jobInfo: targetJob, - step: 1, - stepPhase: 'loading', - resumeName: '岗位专属简历', + // 判断是否开启简历针对性优化(从配置中读取) + const isOptimizeEnabled = agentConfig.value?.autoOptimizeResume === 1 + // 判断是否开启深度人岗匹配分析 + const isMatchEnabled = agentConfig.value?.acceptDeptTransfer === '是' + + if (isOptimizeEnabled) { + // 开启优化:从第1步开始 + const progressItem: ApplyProgressItem = { + id: Date.now(), + jobInfo: targetJob, + step: 1, + stepPhase: 'loading', + resumeName: '岗位专属简历', + } + applyProgressList.value = [progressItem] + saveProgressToStorage() + + await nextTick() + scrollContentToBottom() + + // 开始第1步:优化简历 + await startResumeOptimization(targetJob) + } else if (isMatchEnabled) { + // 关闭优化但开启匹配分析:跳过第1步,直接进入第2步 + const progressItem: ApplyProgressItem = { + id: Date.now(), + jobInfo: targetJob, + step: 2, + stepPhase: 'loading', + resumeName: '默认简历', + } + applyProgressList.value = [progressItem] + saveProgressToStorage() + + await nextTick() + scrollContentToBottom() + + // 直接进入第2步:匹配分析(使用默认简历ID) + await startMatchAnalysisWithResumeId() + } else { + // 优化和匹配分析都关闭:跳过第1、2步,直接进入第3步 + const progressItem: ApplyProgressItem = { + id: Date.now(), + jobInfo: targetJob, + step: 3, + stepPhase: 'ready', + resumeName: '默认简历', + } + applyProgressList.value = [progressItem] + saveProgressToStorage() + + await nextTick() + scrollContentToBottom() } - applyProgressList.value = [progressItem] - saveProgressToStorage() - - await nextTick() - scrollContentToBottom() - - // 开始第1步:优化简历 - await startResumeOptimization(targetJob) } /** 执行简历优化(第1步) */ @@ -916,22 +962,33 @@ async function handleViewResumeStep() { } } -/** 第1步完成:确认简历 → 自动进入第2步匹配分析 */ +/** 第1步完成:确认简历 → 自动进入第2步匹配分析(或跳过) */ async function handleConfirmResumeStep() { const progressItem = applyProgressList.value[0] if (!progressItem) return - // 进入第2步 - progressItem.step = 2 - progressItem.stepPhase = 'loading' - applyProgressList.value = [...applyProgressList.value] - saveProgressToStorage() - // 关闭简历预览抽屉 showResumeDrawer.value = false - // 调用匹配分析流程 - await startMatchAnalysis() + // 判断是否开启深度人岗匹配分析 + const isMatchEnabled = agentConfig.value?.acceptDeptTransfer === '是' + + if (isMatchEnabled) { + // 进入第2步 + progressItem.step = 2 + progressItem.stepPhase = 'loading' + applyProgressList.value = [...applyProgressList.value] + saveProgressToStorage() + + // 调用匹配分析流程 + await startMatchAnalysis() + } else { + // 匹配分析关闭:跳过第2步直接进入第3步 + progressItem.step = 3 + progressItem.stepPhase = 'ready' + applyProgressList.value = [...applyProgressList.value] + saveProgressToStorage() + } } /** 执行匹配分析(第2步) */ @@ -984,6 +1041,42 @@ async function startMatchAnalysis() { } } +/** 执行匹配分析(第2步) — 关闭优化时使用默认简历ID */ +async function startMatchAnalysisWithResumeId() { + const progressItem = applyProgressList.value[0] + if (!progressItem) return + + try { + // 使用默认简历ID调用匹配分析接口 + const scoreRes = await fetchMatchScore({ + resumeId: defaultResumeId.value, + jobId: String(progressItem.jobInfo.id), + }) + + if (applyCancelled.value) return + + const score = scoreRes?.data ?? 0 + progressItem.matchScore = score + + if (score >= 40) { + // 匹配度 >= 40,直接进入第3步 + progressItem.step = 3 + progressItem.stepPhase = 'ready' + } else { + // 匹配度 < 40,显示低匹配提示 + progressItem.step = 2 + progressItem.stepPhase = 'low-match' + } + // 触发响应式更新 + applyProgressList.value = [...applyProgressList.value] + saveProgressToStorage() + } catch (e) { + if (applyCancelled.value) return + console.error('[Agent] 匹配分析失败(默认简历)', e) + ElMessage.error('匹配分析失败,请重试') + } +} + /** 第2步匹配度低:不投递 — 取消该岗位 */ async function handleNotApplyStep() { const progressItem = applyProgressList.value[0] @@ -1095,21 +1188,59 @@ async function autoStartNextApply() { // 取下一个岗位 const targetJob = applyJobList.value[0] - const progressItem: ApplyProgressItem = { - id: Date.now(), - jobInfo: targetJob, - step: 1, - stepPhase: 'loading', - resumeName: '岗位专属简历', + + // 判断是否开启简历针对性优化 + const isOptimizeEnabled = agentConfig.value?.autoOptimizeResume === 1 + // 判断是否开启深度人岗匹配分析 + const isMatchEnabled = agentConfig.value?.acceptDeptTransfer === '是' + + if (isOptimizeEnabled) { + const progressItem: ApplyProgressItem = { + id: Date.now(), + jobInfo: targetJob, + step: 1, + stepPhase: 'loading', + resumeName: '岗位专属简历', + } + applyProgressList.value = [progressItem] + saveProgressToStorage() + + await nextTick() + scrollContentToBottom() + + // 开始第1步:优化简历 + await startResumeOptimization(targetJob) + } else if (isMatchEnabled) { + // 关闭优化但开启匹配分析:跳过第1步,直接进入第2步 + const progressItem: ApplyProgressItem = { + id: Date.now(), + jobInfo: targetJob, + step: 2, + stepPhase: 'loading', + resumeName: '默认简历', + } + applyProgressList.value = [progressItem] + saveProgressToStorage() + + await nextTick() + scrollContentToBottom() + + await startMatchAnalysisWithResumeId() + } else { + // 优化和匹配分析都关闭:跳过第1、2步,直接进入第3步 + const progressItem: ApplyProgressItem = { + id: Date.now(), + jobInfo: targetJob, + step: 3, + stepPhase: 'ready', + resumeName: '默认简历', + } + applyProgressList.value = [progressItem] + saveProgressToStorage() + + await nextTick() + scrollContentToBottom() } - applyProgressList.value = [progressItem] - saveProgressToStorage() - - await nextTick() - scrollContentToBottom() - - // 开始第1步:优化简历 - await startResumeOptimization(targetJob) } diff --git a/src/views/JobDetail.vue b/src/views/JobDetail.vue index 463824b..32c012a 100644 --- a/src/views/JobDetail.vue +++ b/src/views/JobDetail.vue @@ -3,7 +3,7 @@
- +
@@ -218,6 +218,9 @@ const fullLoadingText = ref('') /** 当前岗位 ID,从路由参数中获取 */ const jobId = route.params.id as string +/** 从 store 缓存中读取 Jobs 页面上次切换的 Tab,保持切换记录 */ +const cachedTab = computed(() => store.state.jobListCache?.tab || 'recommend') + // ==================== 工具函数 ==================== /** 工作类型映射:使用全局统一的 formatEmploymentType */ diff --git a/src/views/Jobs.vue b/src/views/Jobs.vue index a44db2b..8bdd4d8 100644 --- a/src/views/Jobs.vue +++ b/src/views/Jobs.vue @@ -110,7 +110,7 @@
- +
diff --git a/src/views/Resume.vue b/src/views/Resume.vue index 26faf5c..04ab477 100644 --- a/src/views/Resume.vue +++ b/src/views/Resume.vue @@ -50,7 +50,7 @@ 默认
- {{ item.targetJob }} + {{ item.targetJob }} {{ item.updatedAt }}