简历优化和岗位简历

This commit is contained in:
2026-04-13 21:34:40 +08:00
parent a39835be01
commit 1c91818494
32 changed files with 3850 additions and 320 deletions
+253
View File
@@ -1,5 +1,7 @@
import request from '@/utils/request'
import aiService from '@/utils/aiRequest'
import type { ApiResult } from '@/api/auth'
import type { AiResult } from '@/utils/aiRequest'
// ==================== 匹配详情 ====================
@@ -363,3 +365,254 @@ export function fetchJobDetail(jobId: string) {
params: { jobId },
})
}
// ==================== 技能差距分析(AI 接口) ====================
/** 技能差距分析 — 岗位信息 */
export interface SkillGapJob {
/** 岗位 ID */
jobId: string
/** 岗位标题 */
title: string
/** 技能标签列表 */
skillTags: string[]
}
/** 技能差距分析 — 简历信息 */
export interface SkillGapResume {
/** 简历 ID */
resumeId: string
/** 简历名称 */
resumeName: string
/** 目标岗位 */
targetPosition: string
}
/** 技能差距分析返回数据 */
export interface SkillGapData {
/** 匹配度分数 */
score: number
/** 岗位信息 */
job: SkillGapJob
/** 简历信息 */
resume: SkillGapResume
/** 缺少的技能列表 */
missingSkills: string[]
}
/**
* 技能差距分析(AI 接口)
* POST /job/skill-gap
* @param jobId 岗位 ID(字符串,避免大整数精度丢失)
*/
export function fetchSkillGap(jobId: string) {
// jobId 作为字符串发送,避免 JS 大整数精度丢失
return aiService.post<any, { data: AiResult<SkillGapData> }>('/job/skill-gap', { jobId }, {
transformResponse: [(data: string) => {
try {
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}
// ==================== 定制简历(AI 接口) ====================
/** 定制简历接口返回的简历数据 */
export interface CustomizeResumeData {
/** 简历基本信息 */
resume: {
avatarUrl?: string
name?: string
email?: string
mobileNumber?: string
city?: string
wechatNumber?: string
portfolioUrl?: string
skills?: string[]
certificates?: string[]
summary?: string
}
/** 教育经历 */
education?: Array<{
id?: string
school?: string
major?: string
degree?: string
studyType?: string
startDate?: string
endDate?: string
description?: Array<{ id?: string; text?: string }>
}>
/** 工作经历 */
work?: Array<{
id?: string
companyName?: string
position?: string
startDate?: string
endDate?: string
description?: Array<{ id?: string; text?: string }>
}>
/** 实习经历 */
internship?: Array<{
id?: string
companyName?: string
position?: string
startDate?: string
endDate?: string
description?: Array<{ id?: string; text?: string }>
}>
/** 项目经历 */
project?: Array<{
id?: string
projectName?: string
companyName?: string
role?: string
startDate?: string
endDate?: string
description?: Array<{ id?: string; text?: string }>
}>
/** 竞赛经历 */
competition?: Array<{
id?: string
competitionName?: string
award?: string
awardDate?: string
description?: Array<{ id?: string; text?: string }>
}>
}
/**
* 查询定制简历结果(AI 接口)
* GET /job/customize-resume
*/
export function fetchCustomizeResume() {
return aiService.get<any, { data: AiResult<CustomizeResumeData | null> }>('/job/customize-resume', {
transformResponse: [(data: string) => {
try {
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}
/** 生成定制简历请求参数 */
export interface GenerateCustomizeResumeParams {
/** 岗位 ID(字符串,避免大整数精度丢失) */
jobId: string
/** 简历 ID(字符串,避免大整数精度丢失) */
resumeId: string
/** 要优化的模块列表 */
optimizeModules: string[]
/** 要新增的技能关键词 */
addSkills?: string[]
}
/**
* 生成定制简历(AI 接口)
* POST /job/customize-resume
* @param params 生成参数
*/
export function generateCustomizeResume(params: GenerateCustomizeResumeParams) {
return aiService.post<any, { data: AiResult<{ success: boolean }> }>('/job/customize-resume', params, {
transformResponse: [(data: string) => {
try {
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}
// ==================== AI对话编辑简历(AI 接口) ====================
/** AI对话编辑简历的聊天记录项 */
export interface AiEditChatMessage {
/** 角色:user-用户 assistant-AI助手 */
role: 'user' | 'assistant'
/** 消息内容 */
content: string
}
/** AI对话编辑简历请求参数 */
export interface AiEditResumeParams {
/** 岗位 ID(字符串,避免大整数精度丢失) */
jobId: string
/** 用户输入的指令 */
instruction: string
/** 对话历史记录 */
chatHistory?: AiEditChatMessage[]
}
/** AI对话编辑简历返回数据 */
export interface AiEditResumeResponse {
/** 返回类型:message-对话消息 updated-简历已更新 */
type: 'message' | 'updated'
/** AI回复的消息内容 */
message: string
}
/**
* AI对话编辑简历(AI 接口)
* POST /job/customize-resume/ai-edit
* @param params 请求参数
*/
export function aiEditResume(params: AiEditResumeParams) {
// 强制确保 jobId 为字符串,避免大整数精度丢失
const safeParams = { ...params, jobId: String(params.jobId) }
return aiService.post<any, { data: AiResult<AiEditResumeResponse> }>('/job/customize-resume/ai-edit', safeParams, {
transformResponse: [(data: string) => {
try {
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}
/**
* 撤销AI对话编辑简历的修改(AI 接口)
* POST /job/customize-resume/rollback
*/
export function rollbackCustomizeResume() {
return aiService.post<any, { data: AiResult<null> }>('/job/customize-resume/rollback', null, {
transformResponse: [(data: string) => {
try {
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}
/**
* 修改定制简历(AI 接口)
* PUT /job/customize-resume
* 输入框失焦或选择器选中后自动调用
* @param data 定制简历完整数据
*/
export function updateCustomizeResume(data: CustomizeResumeData) {
return aiService.put<any, { data: AiResult<null> }>('/job/customize-resume', data, {
transformResponse: [(raw: string) => {
try {
const processed = raw.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return raw
}
}],
}).then(res => res.data)
}
+2 -2
View File
@@ -27,9 +27,9 @@ export interface MenuItemRaw {
export async function fetchUserRoutes(): Promise<MenuItemRaw[]> {
// TODO: 替换为真实接口 → return axios.get('/api/user/menus').then(res => res.data)
return [
{ path: '/agent', name: 'Agent', component: 'Agent', meta: { label: 'AI助手', icon: 'nav-agent-icon', badge: 'NEW' } },
{ path: '/profile', name: 'Profile', component: 'Profile', meta: { label: '个人资料', icon: 'nav-profile-icon' } },
{ path: '/resume', name: 'Resume', component: 'Resume', meta: { label: '简历', icon: 'nav-resume-icon' } },
{ path: '/profile', name: 'Profile', component: 'Profile', meta: { label: '个人资料', icon: 'nav-profile-icon' } },
{ path: '/agent', name: 'Agent', component: 'Agent', meta: { label: 'AI助手', icon: 'nav-agent-icon', badge: 'NEW' } },
{ path: '/settings', name: 'Settings', component: 'Settings', meta: { label: '设置', icon: 'nav-setting-icon', position: 'footer' } },
]
}
+184
View File
@@ -1,5 +1,7 @@
import request from '@/utils/request'
import aiService from '@/utils/aiRequest'
import type { ApiResult } from '@/api/auth'
import type { AiResult } from '@/utils/aiRequest'
// ==================== 简历列表相关 ====================
@@ -370,3 +372,185 @@ export interface SaveResumeCompetitionItem {
export function saveResumeCompetition(resumeId: string, data: SaveResumeCompetitionItem[]) {
return request.post<any, ApiResult>('/resume/competition', { resumeId, items: data })
}
/**
* 删除简历
* POST /resume/delete
*/
export function deleteResume(resumeId: string) {
return request.post<any, ApiResult>('/resume/delete', null, {
params: { resumeId },
})
}
// ==================== 简历诊断相关 ====================
/** 诊断报告数据 */
export interface DiagnosisReport {
/** 报告 ID */
id?: string
/** 简历 ID */
resumeId?: string
/** 评级 A/B/C/D */
grade?: string
/** AI 整体评价 */
summary?: string
/** 紧急修复总数 */
urgentTotal?: number
/** 重点优化总数 */
importantTotal?: number
/** 表达提升总数 */
expressionTotal?: number
/** 创建时间 */
createTime?: string
}
/** 诊断问题子类型计数 */
export interface IssueSubCounts {
[key: string]: number
}
/** 诊断问题项 */
export interface DiagnosisIssue {
/** 问题 ID */
id?: string
/** 模块类型: summary/education/work/internship/project/competition */
moduleType?: string
/** 模块记录 IDsummary 时为 resume_id */
moduleRecordId?: string
/** 诊断发现 */
finding?: string
/** 为什么重要 */
importance?: string
/** 改进建议 */
suggestion?: string
/** 紧急修复子类型计数 */
urgentIssues?: IssueSubCounts
/** 重点优化子类型计数 */
importantIssues?: IssueSubCounts
/** 表达提升子类型计数 */
expressionIssues?: IssueSubCounts
/** AI 改写后的内容 */
optimizedContent?: any
/** 0=待处理 1=已处理 */
status?: number
/** 0=未评价 1=符合 2=不符合 */
userFeedback?: number
}
/** 诊断接口返回的 data 结构 */
export interface DiagnosisData {
/** 诊断报告 */
report: DiagnosisReport
/** 诊断问题列表 */
issues: DiagnosisIssue[]
}
/**
* 查询简历诊断报告(AI 接口)
* GET /resume/diagnose/{resume_id}
*/
export function fetchResumeDiagnosis(resumeId: string) {
return aiService.get<AiResult<DiagnosisData | null>>(`/resume/diagnose/${resumeId}`, {
transformResponse: [(data: string) => {
try {
// 大整数安全解析
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}
/** 触发诊断返回的 data 结构 */
export interface TriggerDiagnosisData {
/** 诊断报告 ID */
reportId?: string
}
/**
* 触发简历诊断(AI 接口)
* POST /resume/diagnose
*/
export function triggerResumeDiagnosis(resumeId: string) {
return aiService.post<AiResult<TriggerDiagnosisData>>('/resume/diagnose', { resumeId }, {
transformResponse: [(data: string) => {
try {
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}
// ==================== 问题润色(AI 优化用户改写内容) ====================
/** 润色接口返回的 data 结构 */
export interface PolishIssueData {
/** AI 润色后的文本段落数组 */
content: string[]
}
/**
* 对诊断问题进行 AI 润色(AI 接口)
* POST /resume/diagnose/issue/{issue_id}/polish
* @param issueId 问题 ID
* @param content 用户编辑后的文本段落数组
*/
export function polishDiagnosisIssue(issueId: string, content: string[]) {
return aiService.post<AiResult<PolishIssueData>>(`/resume/diagnose/issue/${issueId}/polish`, { content }, {
transformResponse: [(data: string) => {
try {
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}
// ==================== 问题用户评价 ====================
/**
* 提交诊断问题的用户评价(AI 接口)
* PUT /resume/diagnose/issue/{issue_id}/feedback
* @param issueId 问题 ID
* @param userFeedback 1=符合(有用) 2=不符合(无用)
*/
export function feedbackDiagnosisIssue(issueId: string, userFeedback: number) {
return aiService.put<AiResult<null>>(`/resume/diagnose/issue/${issueId}/feedback`, { userFeedback }, {
transformResponse: [(data: string) => {
try {
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}
// ==================== 标记问题已处理 ====================
/**
* 标记诊断问题为已处理(AI 接口)
* PUT /resume/diagnose/issue/{issue_id}/resolve
* @param issueId 问题 ID
*/
export function resolveDiagnosisIssue(issueId: string) {
return aiService.put<AiResult<null>>(`/resume/diagnose/issue/${issueId}/resolve`, null, {
transformResponse: [(data: string) => {
try {
const processed = data.replace(/:\s*(\d{16,})/g, ':"$1"')
return JSON.parse(processed)
} catch {
return data
}
}],
}).then(res => res.data)
}