1
This commit is contained in:
@@ -197,6 +197,15 @@ class PlaAccountServer {
|
||||
updateAuthorization(param) {
|
||||
return window.framework.http.post('/account/update-authorization', param)
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析账号的在线简历
|
||||
* @param {Number|String} accountId - 账号ID
|
||||
* @returns {Promise}
|
||||
*/
|
||||
parseResume(accountId) {
|
||||
return window.framework.http.post('/pla_account/parse-resume', { id: accountId })
|
||||
}
|
||||
}
|
||||
|
||||
export default new PlaAccountServer()
|
||||
|
||||
@@ -39,6 +39,15 @@ class ResumeInfoServer {
|
||||
del(row) {
|
||||
return window.framework.http.post('/resume/delete', { resumeId: row.resumeId || row.id })
|
||||
}
|
||||
|
||||
/**
|
||||
* AI 分析简历
|
||||
* @param {String} resumeId - 简历ID
|
||||
* @returns {Promise}
|
||||
*/
|
||||
analyzeWithAI(resumeId) {
|
||||
return window.framework.http.post('/resume/analyze-with-ai', { resumeId })
|
||||
}
|
||||
}
|
||||
|
||||
export default new ResumeInfoServer()
|
||||
|
||||
@@ -99,8 +99,11 @@
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
<!-- 简历详情弹窗 -->
|
||||
<Modal v-model="resumeModal.visible" :title="resumeModal.title" width="900" :footer-hide="true">
|
||||
<!-- 简历详情弹窗 - 使用 ResumeInfoDetail 组件 -->
|
||||
<ResumeInfoDetail ref="resumeDetail" @on-close="handleResumeDetailClose" />
|
||||
|
||||
<!-- 原简历详情弹窗(备份,暂时保留) -->
|
||||
<Modal v-model="resumeModal.visible" :title="resumeModal.title" width="900" :footer-hide="true" v-if="false">
|
||||
<div v-if="resumeModal.loading" style="text-align: center; padding: 40px;">
|
||||
<Spin size="large"></Spin>
|
||||
<p style="margin-top: 20px;">加载简历数据中...</p>
|
||||
@@ -276,9 +279,11 @@
|
||||
import plaAccountServer from '@/api/profile/pla_account_server.js'
|
||||
import jobTypesServer from '@/api/work/job_types_server.js'
|
||||
import PlaAccountEdit from './pla_account_edit.vue'
|
||||
import ResumeInfoDetail from './resume_info_detail.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ResumeInfoDetail,
|
||||
PlaAccountEdit
|
||||
},
|
||||
data() {
|
||||
@@ -344,13 +349,12 @@ export default {
|
||||
{ title: '密码', key: 'pwd', com: 'Password', required: true },
|
||||
],
|
||||
listColumns: [
|
||||
{ title: 'ID', key: 'id', minWidth: 80 },
|
||||
{ title: '账户名', key: 'name', minWidth: 150 },
|
||||
{ title: '设备SN码', key: 'sn_code', minWidth: 120 },
|
||||
{ title: 'ID', key: 'id' },
|
||||
{ title: '账户名', key: 'name' },
|
||||
{ title: '设备SN码', key: 'sn_code'},
|
||||
{
|
||||
title: '平台',
|
||||
key: 'platform_type',
|
||||
minWidth: 100,
|
||||
render: (h, params) => {
|
||||
const platformMap = {
|
||||
'boss': { text: 'Boss直聘', color: 'blue' },
|
||||
@@ -360,13 +364,13 @@ export default {
|
||||
return h('Tag', { props: { color: platform.color } }, platform.text)
|
||||
}
|
||||
},
|
||||
{ title: '登录名', key: 'login_name', minWidth: 150 },
|
||||
{ title: '搜索关键词', key: 'keyword', minWidth: 150 },
|
||||
{ title: '用户地址', key: 'user_address', minWidth: 150 },
|
||||
{ title: '登录名', key: 'login_name'},
|
||||
{ title: '搜索关键词', key: 'keyword' },
|
||||
{ title: '用户地址', key: 'user_address' },
|
||||
{
|
||||
title: '经纬度',
|
||||
key: 'location',
|
||||
minWidth: 150,
|
||||
|
||||
render: (h, params) => {
|
||||
const lon = params.row.user_longitude;
|
||||
const lat = params.row.user_latitude;
|
||||
@@ -379,7 +383,7 @@ export default {
|
||||
{
|
||||
title: '在线状态',
|
||||
key: 'is_online',
|
||||
minWidth: 100,
|
||||
|
||||
render: (h, params) => {
|
||||
return h('Tag', {
|
||||
props: { color: params.row.is_online ? 'success' : 'default' }
|
||||
@@ -390,7 +394,7 @@ export default {
|
||||
title: '自动投递',
|
||||
key: 'auto_deliver',
|
||||
com: "Radio",
|
||||
minWidth: 100,
|
||||
|
||||
options: [
|
||||
{ value: 1, label: '开启' },
|
||||
{ value: 0, label: '关闭' }
|
||||
@@ -409,7 +413,6 @@ export default {
|
||||
{ value: 1, label: '开启' },
|
||||
{ value: 0, label: '关闭' }
|
||||
],
|
||||
minWidth: 100,
|
||||
render: (h, params) => {
|
||||
return h('Tag', {
|
||||
props: { color: params.row.auto_chat ? 'success' : 'default' }
|
||||
@@ -419,7 +422,7 @@ export default {
|
||||
{
|
||||
title: '剩余天数',
|
||||
key: 'remaining_days',
|
||||
minWidth: 100,
|
||||
|
||||
render: (h, params) => {
|
||||
const remainingDays = params.row.remaining_days || 0
|
||||
let color = 'success'
|
||||
@@ -436,7 +439,7 @@ export default {
|
||||
{
|
||||
title: '授权日期',
|
||||
key: 'authorization_date',
|
||||
minWidth: 150,
|
||||
|
||||
render: (h, params) => {
|
||||
if (!params.row.authorization_date) {
|
||||
return h('span', { style: { color: '#999' } }, '未授权')
|
||||
@@ -448,7 +451,7 @@ export default {
|
||||
{
|
||||
title: '过期时间',
|
||||
key: 'expire_date',
|
||||
minWidth: 150,
|
||||
|
||||
render: (h, params) => {
|
||||
if (!params.row.authorization_date || !params.row.authorization_days) {
|
||||
return h('span', { style: { color: '#999' } }, '未授权')
|
||||
@@ -469,7 +472,7 @@ export default {
|
||||
{ value: 1, label: '开启' },
|
||||
{ value: 0, label: '关闭' }
|
||||
],
|
||||
minWidth: 100,
|
||||
|
||||
render: (h, params) => {
|
||||
return h('Tag', {
|
||||
props: { color: params.row.auto_active ? 'success' : 'default' }
|
||||
@@ -479,7 +482,6 @@ export default {
|
||||
{
|
||||
title: '启用状态',
|
||||
key: 'is_enabled',
|
||||
minWidth: 100,
|
||||
render: (h, params) => {
|
||||
return h('i-switch', {
|
||||
props: {
|
||||
@@ -494,11 +496,11 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 150 },
|
||||
{ title: '创建时间', key: 'create_time', },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 450,
|
||||
width: 500,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
@@ -661,10 +663,11 @@ export default {
|
||||
},
|
||||
// 查看简历
|
||||
async showResume(row) {
|
||||
this.resumeModal.visible = true
|
||||
this.resumeModal.loading = true
|
||||
this.resumeModal.data = null
|
||||
this.resumeModal.title = `${row.name} - 在线简历`
|
||||
// 显示加载提示
|
||||
const loadingMsg = this.$Message.loading({
|
||||
content: '正在加载简历数据...',
|
||||
duration: 0
|
||||
})
|
||||
|
||||
try {
|
||||
// 根据 sn_code 和 platform 获取简历
|
||||
@@ -677,18 +680,24 @@ export default {
|
||||
// admin 会自动加 /admin_api 前缀
|
||||
const res = await window.framework.http.get(`/resume/get-by-device?sn_code=${row.sn_code}&platform=${platform}`)
|
||||
|
||||
if (res.code === 0) {
|
||||
this.resumeModal.data = res.data
|
||||
loadingMsg()
|
||||
|
||||
if (res.code === 0 && res.data && res.data.resumeId) {
|
||||
// 使用 ResumeInfoDetail 组件显示简历
|
||||
this.$refs.resumeDetail.show(res.data.resumeId)
|
||||
} else {
|
||||
this.$Message.warning(res.message || '未找到简历数据')
|
||||
}
|
||||
} catch (error) {
|
||||
loadingMsg()
|
||||
console.error('获取简历失败:', error)
|
||||
this.$Message.error('获取简历失败:' + (error.message || '请稍后重试'))
|
||||
} finally {
|
||||
this.resumeModal.loading = false
|
||||
}
|
||||
},
|
||||
// 关闭简历详情
|
||||
handleResumeDetailClose() {
|
||||
// 可以在这里添加关闭后的逻辑
|
||||
},
|
||||
// 解析技能标签
|
||||
parseSkills(skills) {
|
||||
if (!skills) return []
|
||||
|
||||
@@ -510,7 +510,7 @@
|
||||
<div v-else-if="qrCodeError" class="qr-code-error">
|
||||
<Icon type="ios-close-circle" size="40" color="#ed4014" />
|
||||
<p>{{ qrCodeError }}</p>
|
||||
|
||||
|
||||
</div>
|
||||
<div v-else-if="qrCodeData" class="qr-code-display">
|
||||
<div v-if="qrCodeData.qrCode || qrCodeData.qr_code_url || qrCodeData.oos_url || qrCodeData.image || qrCodeData.data"
|
||||
@@ -534,6 +534,9 @@
|
||||
<Button type="primary" @click="refreshQrCode" :loading="qrCodeLoading">刷新二维码</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!-- 简历详情弹窗 -->
|
||||
<ResumeInfoDetail ref="resumeDetail" @on-close="handleResumeDetailClose" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -541,9 +544,13 @@
|
||||
import plaAccountServer from '@/api/profile/pla_account_server.js'
|
||||
import taskStatusServer from '@/api/task/task_status_server.js'
|
||||
import jobTypesServer from '@/api/work/job_types_server.js'
|
||||
import ResumeInfoDetail from './resume_info_detail.vue'
|
||||
|
||||
export default {
|
||||
name: 'PlaAccountDetail',
|
||||
components: {
|
||||
ResumeInfoDetail
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
accountInfo: {},
|
||||
@@ -608,6 +615,12 @@ export default {
|
||||
commandType: 'get_online_resume',
|
||||
commandName: '获取在线简历'
|
||||
},
|
||||
{
|
||||
value: 'parse_and_view_resume',
|
||||
label: '解析简历',
|
||||
icon: 'ios-paper',
|
||||
isCustomAction: true
|
||||
},
|
||||
{
|
||||
value: 'search_jobs',
|
||||
label: '搜索岗位',
|
||||
@@ -1168,6 +1181,12 @@ export default {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果是解析简历的自定义操作
|
||||
if (action === 'parse_and_view_resume') {
|
||||
this.handleParseAndViewResume()
|
||||
return
|
||||
}
|
||||
|
||||
// 从菜单列表中查找对应的配置
|
||||
const actionItem = this.actionMenuList.find(item => item.value === action)
|
||||
if (!actionItem) {
|
||||
@@ -1204,6 +1223,42 @@ export default {
|
||||
})
|
||||
},
|
||||
|
||||
// 处理解析并查看简历
|
||||
async handleParseAndViewResume() {
|
||||
this.$Modal.confirm({
|
||||
title: '确认解析简历',
|
||||
content: '确定要解析该账号的在线简历吗?系统会自动获取简历并进行AI分析。',
|
||||
onOk: async () => {
|
||||
const loadingMsg = this.$Message.loading({
|
||||
content: '正在解析简历,请稍候...',
|
||||
duration: 0
|
||||
})
|
||||
|
||||
try {
|
||||
// 调用后端接口解析简历
|
||||
const res = await plaAccountServer.parseResume(this.accountId)
|
||||
|
||||
loadingMsg()
|
||||
this.$Message.success('简历解析成功')
|
||||
|
||||
// 打开简历详情弹窗
|
||||
if (res.data && res.data.resumeId) {
|
||||
this.$refs.resumeDetail.show(res.data.resumeId)
|
||||
}
|
||||
} catch (error) {
|
||||
loadingMsg()
|
||||
console.error('解析简历失败:', error)
|
||||
this.$Message.error('解析简历失败: ' + (error.message || '请稍后重试'))
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 关闭简历详情弹窗
|
||||
handleResumeDetailClose() {
|
||||
// 可以在这里添加关闭后的逻辑
|
||||
},
|
||||
|
||||
// 显示二维码
|
||||
async showQrCode() {
|
||||
this.qrCodeVisible = true
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="table-head-tool">
|
||||
<Button type="primary" @click="showAddWarp">新增简历</Button>
|
||||
<Form ref="formInline" :model="gridOption.param.seachOption" inline :label-width="80">
|
||||
<FormItem :label-width="20" class="flex">
|
||||
<Select v-model="gridOption.param.seachOption.key" style="width: 120px"
|
||||
@@ -29,13 +28,20 @@
|
||||
@changePage="query"></tables>
|
||||
</div>
|
||||
<editModal ref="editModal" :columns="editColumns" :rules="gridOption.rules"></editModal>
|
||||
|
||||
<!-- 详情组件 -->
|
||||
<ResumeInfoDetail ref="resumeDetail" @on-close="handleDetailClose" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import resumeInfoServer from '@/api/profile/resume_info_server.js'
|
||||
import ResumeInfoDetail from './resume_info_detail.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ResumeInfoDetail
|
||||
},
|
||||
data() {
|
||||
let rules = {}
|
||||
rules["sn_code"] = [{ required: true, message: '请填写设备SN码', trigger: 'blur' }]
|
||||
@@ -90,10 +96,17 @@ export default {
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 200,
|
||||
width: 250,
|
||||
type: 'template',
|
||||
render: (h, params) => {
|
||||
let btns = [
|
||||
{
|
||||
title: '查看',
|
||||
type: 'info',
|
||||
click: () => {
|
||||
this.showDetail(params.row)
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '编辑',
|
||||
type: 'primary',
|
||||
@@ -168,6 +181,19 @@ export default {
|
||||
platform: null
|
||||
}
|
||||
this.query(1)
|
||||
},
|
||||
showDetail(row) {
|
||||
// 优先使用 resumeId,如果没有则使用 id
|
||||
const resumeId = row.resumeId || row.id
|
||||
if (resumeId) {
|
||||
this.$refs.resumeDetail.show(resumeId)
|
||||
} else {
|
||||
this.$Message.warning('简历ID不存在')
|
||||
}
|
||||
},
|
||||
handleDetailClose() {
|
||||
// 详情关闭后的回调,可以在这里刷新列表
|
||||
// this.query(this.gridOption.param.pageOption.page)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
488
admin/src/views/account/resume_info_detail.vue
Normal file
488
admin/src/views/account/resume_info_detail.vue
Normal file
@@ -0,0 +1,488 @@
|
||||
<template>
|
||||
<FloatPanel
|
||||
ref="floatPanel"
|
||||
title="简历详情"
|
||||
position="right"
|
||||
:show-back="true"
|
||||
back-text="返回"
|
||||
@back="handleBack"
|
||||
>
|
||||
<template #header-right>
|
||||
<Button type="primary" @click="handleAnalyzeAI" :loading="analyzing">AI 分析</Button>
|
||||
</template>
|
||||
|
||||
<div class="resume-detail-content" v-if="resumeData">
|
||||
<Spin fix v-if="loading">
|
||||
<Icon type="ios-loading" size="18" class="spin-icon-load"></Icon>
|
||||
<div>加载中...</div>
|
||||
</Spin>
|
||||
|
||||
<!-- 基本信息 -->
|
||||
<Card title="基本信息" style="margin-bottom: 16px;">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">姓名:</span>
|
||||
<span class="value">{{ resumeData.fullName || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">性别:</span>
|
||||
<span class="value">{{ resumeData.gender || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">年龄:</span>
|
||||
<span class="value">{{ resumeData.age || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">电话:</span>
|
||||
<span class="value">{{ resumeData.phone || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">邮箱:</span>
|
||||
<span class="value">{{ resumeData.email || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">所在地:</span>
|
||||
<span class="value">{{ resumeData.location || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">工作年限:</span>
|
||||
<span class="value">{{ resumeData.workYears || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">当前职位:</span>
|
||||
<span class="value">{{ resumeData.currentPosition || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">当前公司:</span>
|
||||
<span class="value">{{ resumeData.currentCompany || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<!-- 教育背景 -->
|
||||
<Card title="教育背景" style="margin-bottom: 16px;">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">学历:</span>
|
||||
<span class="value">{{ resumeData.education || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">专业:</span>
|
||||
<span class="value">{{ resumeData.major || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">毕业院校:</span>
|
||||
<span class="value">{{ resumeData.school || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">毕业年份:</span>
|
||||
<span class="value">{{ resumeData.graduationYear || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<!-- 期望信息 -->
|
||||
<Card title="期望信息" style="margin-bottom: 16px;">
|
||||
<Row :gutter="16">
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">期望职位:</span>
|
||||
<span class="value">{{ resumeData.expectedPosition || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">期望薪资:</span>
|
||||
<span class="value">{{ resumeData.expectedSalary || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">期望地点:</span>
|
||||
<span class="value">{{ resumeData.expectedLocation || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="12">
|
||||
<div class="info-item">
|
||||
<span class="label">期望行业:</span>
|
||||
<span class="value">{{ resumeData.expectedIndustry || '-' }}</span>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<!-- 技能标签 -->
|
||||
<Card title="技能标签" style="margin-bottom: 16px;">
|
||||
<div v-if="skillTags && skillTags.length > 0">
|
||||
<Tag v-for="(skill, index) in skillTags" :key="index" color="blue" style="margin: 4px;">{{ skill }}</Tag>
|
||||
</div>
|
||||
<div v-else class="no-data">暂无技能标签</div>
|
||||
</Card>
|
||||
|
||||
<!-- 技能描述 -->
|
||||
<Card title="技能描述" style="margin-bottom: 16px;" v-if="resumeData.skillDescription">
|
||||
<div class="text-content">{{ resumeData.skillDescription }}</div>
|
||||
</Card>
|
||||
|
||||
<!-- 工作经历 -->
|
||||
<Card title="工作经历" style="margin-bottom: 16px;" v-if="workExperience && workExperience.length > 0">
|
||||
<Timeline>
|
||||
<TimelineItem v-for="(work, index) in workExperience" :key="index">
|
||||
<p class="work-title">
|
||||
<strong>{{ work.position }}</strong>
|
||||
<span class="work-company"> - {{ work.company }}</span>
|
||||
</p>
|
||||
<p class="work-time" v-if="work.startDate || work.endDate">
|
||||
{{ work.startDate }} - {{ work.endDate || '至今' }}
|
||||
</p>
|
||||
<p class="work-content" v-if="work.content">{{ work.content }}</p>
|
||||
</TimelineItem>
|
||||
</Timeline>
|
||||
</Card>
|
||||
|
||||
<!-- 项目经验 -->
|
||||
<Card title="项目经验" style="margin-bottom: 16px;" v-if="projectExperience && projectExperience.length > 0">
|
||||
<div v-for="(project, index) in projectExperience" :key="index" class="project-item" style="margin-bottom: 20px;">
|
||||
<p class="project-title">
|
||||
<strong>{{ project.name }}</strong>
|
||||
<span class="project-role" v-if="project.role"> - {{ project.role }}</span>
|
||||
</p>
|
||||
<p class="project-time" v-if="project.startDate || project.endDate">
|
||||
{{ project.startDate }} - {{ project.endDate || '至今' }}
|
||||
</p>
|
||||
<p class="project-desc" v-if="project.description">{{ project.description }}</p>
|
||||
<p class="project-performance" v-if="project.performance">
|
||||
<strong>项目成果:</strong>{{ project.performance }}
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<!-- 简历内容 -->
|
||||
<Card title="简历完整内容" style="margin-bottom: 16px;" v-if="resumeData.resumeContent">
|
||||
<div class="text-content" style="white-space: pre-wrap;">{{ resumeData.resumeContent }}</div>
|
||||
</Card>
|
||||
|
||||
<!-- AI 分析结果 -->
|
||||
<Card title="AI 分析结果" style="margin-bottom: 16px;">
|
||||
<Row :gutter="16">
|
||||
<Col span="24">
|
||||
<div class="info-item">
|
||||
<span class="label">竞争力评分:</span>
|
||||
<span class="value" :style="{ color: getCompetitivenessColor(resumeData.aiCompetitiveness), fontSize: '18px', fontWeight: 'bold' }">
|
||||
{{ resumeData.aiCompetitiveness || 0 }} 分
|
||||
</span>
|
||||
<Progress
|
||||
:percent="resumeData.aiCompetitiveness || 0"
|
||||
:stroke-color="getCompetitivenessColor(resumeData.aiCompetitiveness)"
|
||||
style="margin-top: 8px; width: 300px;"
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="24" v-if="resumeData.aiStrengths">
|
||||
<div class="info-item ai-section">
|
||||
<div class="ai-section-header">
|
||||
<Icon type="ios-thumbs-up" color="#19be6b" size="18" />
|
||||
<span class="label">优势分析</span>
|
||||
</div>
|
||||
<div class="text-content ai-content">{{ resumeData.aiStrengths }}</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="24" v-if="resumeData.aiWeaknesses">
|
||||
<div class="info-item ai-section">
|
||||
<div class="ai-section-header">
|
||||
<Icon type="ios-warning" color="#ff9900" size="18" />
|
||||
<span class="label">劣势分析</span>
|
||||
</div>
|
||||
<div class="text-content ai-content">{{ resumeData.aiWeaknesses }}</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="24" v-if="resumeData.aiCareerSuggestion">
|
||||
<div class="info-item ai-section">
|
||||
<div class="ai-section-header">
|
||||
<Icon type="ios-bulb" color="#2d8cf0" size="18" />
|
||||
<span class="label">职业建议</span>
|
||||
</div>
|
||||
<div class="text-content ai-content">{{ resumeData.aiCareerSuggestion }}</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="24" v-if="aiSkillTags && aiSkillTags.length > 0">
|
||||
<div class="info-item">
|
||||
<span class="label">AI 提取的技能标签:</span>
|
||||
<div style="margin-top: 8px;">
|
||||
<Tag v-for="(skill, index) in aiSkillTags" :key="index" color="green" style="margin: 4px;">{{ skill }}</Tag>
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="24" v-if="!resumeData.aiCompetitiveness && !resumeData.aiStrengths">
|
||||
<div class="no-data">
|
||||
<Icon type="ios-information-circle" size="24" color="#c5c8ce" />
|
||||
<p>暂无 AI 分析结果,请点击上方"AI 分析"按钮进行分析</p>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
<!-- 原始数据(可展开) -->
|
||||
<Card title="原始数据" style="margin-bottom: 16px;">
|
||||
<Collapse>
|
||||
<Panel name="originalData">
|
||||
查看原始 JSON 数据
|
||||
<template slot="content">
|
||||
<pre class="json-preview">{{ JSON.stringify(originalDataObj, null, 2) }}</pre>
|
||||
</template>
|
||||
</Panel>
|
||||
</Collapse>
|
||||
</Card>
|
||||
</div>
|
||||
</FloatPanel>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import resumeInfoServer from '@/api/profile/resume_info_server.js'
|
||||
|
||||
export default {
|
||||
name: 'ResumeInfoDetail',
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
analyzing: false,
|
||||
resumeData: null,
|
||||
skillTags: [],
|
||||
workExperience: [],
|
||||
projectExperience: [],
|
||||
aiSkillTags: [],
|
||||
originalDataObj: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async show(resumeId) {
|
||||
this.$refs.floatPanel.show()
|
||||
await this.loadResumeData(resumeId)
|
||||
},
|
||||
async loadResumeData(resumeId) {
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await resumeInfoServer.getById(resumeId)
|
||||
this.resumeData = res.data || {}
|
||||
|
||||
// 解析 JSON 字段
|
||||
this.skillTags = this.parseJsonField(this.resumeData.skills) || []
|
||||
this.workExperience = this.parseJsonField(this.resumeData.workExperience) || []
|
||||
this.projectExperience = this.parseJsonField(this.resumeData.projectExperience) || []
|
||||
this.aiSkillTags = this.parseJsonField(this.resumeData.aiSkillTags) || []
|
||||
|
||||
// 解析原始数据
|
||||
this.originalDataObj = this.parseJsonField(this.resumeData.originalData) || {}
|
||||
} catch (error) {
|
||||
console.error('加载简历详情失败:', error)
|
||||
this.$Message.error('加载简历详情失败')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
parseJsonField(field) {
|
||||
if (!field) return null
|
||||
if (typeof field === 'string') {
|
||||
try {
|
||||
return JSON.parse(field)
|
||||
} catch (e) {
|
||||
return field
|
||||
}
|
||||
}
|
||||
return field
|
||||
},
|
||||
async handleAnalyzeAI() {
|
||||
if (!this.resumeData || !this.resumeData.resumeId) {
|
||||
this.$Message.warning('简历ID不存在')
|
||||
return
|
||||
}
|
||||
|
||||
this.analyzing = true
|
||||
try {
|
||||
await resumeInfoServer.analyzeWithAI(this.resumeData.resumeId)
|
||||
this.$Message.success('AI 分析完成')
|
||||
// 重新加载数据
|
||||
await this.loadResumeData(this.resumeData.resumeId)
|
||||
} catch (error) {
|
||||
console.error('AI 分析失败:', error)
|
||||
this.$Message.error('AI 分析失败: ' + (error.message || '请稍后重试'))
|
||||
} finally {
|
||||
this.analyzing = false
|
||||
}
|
||||
},
|
||||
handleBack() {
|
||||
this.$refs.floatPanel.hide()
|
||||
this.$emit('on-close')
|
||||
},
|
||||
getCompetitivenessColor(score) {
|
||||
if (!score) return '#666'
|
||||
if (score >= 80) return '#19be6b'
|
||||
if (score >= 60) return '#2d8cf0'
|
||||
return '#ed4014'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.resume-detail-content {
|
||||
padding: 0;
|
||||
position: relative;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.info-item .label {
|
||||
font-weight: 600;
|
||||
color: #515a6e;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.info-item .value {
|
||||
color: #2d8cf0;
|
||||
}
|
||||
|
||||
.text-content {
|
||||
color: #515a6e;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.work-title {
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.work-company {
|
||||
color: #808695;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.work-time {
|
||||
color: #808695;
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.work-content {
|
||||
color: #515a6e;
|
||||
line-height: 1.6;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.project-item {
|
||||
padding-bottom: 16px;
|
||||
border-bottom: 1px solid #e8eaec;
|
||||
}
|
||||
|
||||
.project-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.project-title {
|
||||
font-size: 14px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.project-role {
|
||||
color: #808695;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.project-time {
|
||||
color: #808695;
|
||||
font-size: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.project-desc {
|
||||
color: #515a6e;
|
||||
line-height: 1.6;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.project-performance {
|
||||
color: #19be6b;
|
||||
line-height: 1.6;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.no-data {
|
||||
color: #c5c8ce;
|
||||
text-align: center;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
.no-data p {
|
||||
margin-top: 12px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* AI 分析区域样式 */
|
||||
.ai-section {
|
||||
margin-bottom: 20px;
|
||||
padding: 16px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
border-left: 3px solid #2d8cf0;
|
||||
}
|
||||
|
||||
.ai-section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12px;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.ai-section-header .label {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
color: #17233d;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.ai-content {
|
||||
padding-left: 26px;
|
||||
line-height: 1.8;
|
||||
color: #515a6e;
|
||||
}
|
||||
|
||||
.json-preview {
|
||||
background: #f8f8f9;
|
||||
padding: 16px;
|
||||
border-radius: 4px;
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -167,7 +167,7 @@ export default {
|
||||
return h('Tag', { props: { color: color } }, `${score}%`)
|
||||
}
|
||||
},
|
||||
{ title: '投递时间', key: 'applyTime', minWidth: 250 },
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 250 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
|
||||
@@ -126,7 +126,7 @@ export default {
|
||||
return h('Tag', { props: { color: status.color } }, status.text)
|
||||
}
|
||||
},
|
||||
{ title: '发布时间', key: 'publishTime', minWidth: 150 },
|
||||
{ title: '创建时间', key: 'create_time', minWidth: 220 },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
|
||||
Reference in New Issue
Block a user