Files
autoAiWorkSys/api/controller_admin/resume_info.js
张成 7ee92b8905 1
2025-12-25 22:11:34 +08:00

364 lines
9.3 KiB
JavaScript

/**
* 简历信息管理API - 后台管理
* 提供简历信息的查询和管理功能
*/
const Framework = require("../../framework/node-core-framework.js");
module.exports = {
/**
* @swagger
* /admin_api/resume/list:
* post:
* summary: 获取简历列表
* description: 分页获取所有简历信息
* tags: [后台-简历管理]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* properties:
* page:
* type: integer
* description: 页码
* pageSize:
* type: integer
* description: 每页数量
* minCompetitiveness:
* type: integer
* description: 最小竞争力评分(可选)
* responses:
* 200:
* description: 获取成功
*/
'POST /resume/list': async (ctx) => {
const models = Framework.getModels();
const { resume_info, op } = models;
const body = ctx.getBody();
const { minCompetitiveness, searchText} = ctx.getBody();
// 获取分页参数
const { limit, offset } = ctx.getPageSize();
const where = {};
// 竞争力评分筛选
if (minCompetitiveness !== undefined) {
where.aiCompetitiveness = { [op.gte]: minCompetitiveness };
}
// 支持搜索姓名或技能
if (searchText) {
where[op.or] = [
{ fullName: { [op.like]: `%${searchText}%` } },
{ skills: { [op.like]: `%${searchText}%` } }
];
}
const result = await resume_info.findAndCountAll({
where,
limit,
offset,
order: [
['aiCompetitiveness', 'DESC'],
['id', 'DESC']
]
});
return ctx.success({
rows: result.rows,
count: result.count
});
},
/**
* @swagger
* /admin_api/resume/statistics:
* get:
* summary: 获取简历统计
* description: 获取简历信息的统计数据
* tags: [后台-简历管理]
* responses:
* 200:
* description: 获取成功
*/
'GET /resume/statistics': async (ctx) => {
const models = Framework.getModels();
const { resume_info } = models;
const totalResumes = await resume_info.count();
// 平均竞争力
const avgCompetitiveness = await resume_info.findAll({
attributes: [
[models.sequelize.fn('AVG', models.sequelize.col('aiCompetitiveness')), 'avgScore']
],
raw: true
});
// 按工作年限统计
const workYearsStats = await resume_info.findAll({
attributes: [
'workYears',
[models.sequelize.fn('COUNT', models.sequelize.col('*')), 'count']
],
group: ['workYears'],
raw: true
});
// 竞争力分布
const [
highCompetitiveness,
mediumCompetitiveness,
lowCompetitiveness
] = await Promise.all([
resume_info.count({ where: { aiCompetitiveness: { [models.op.gte]: 80 } } }),
resume_info.count({ where: { aiCompetitiveness: { [models.op.gte]: 60, [models.op.lt]: 80 } } }),
resume_info.count({ where: { aiCompetitiveness: { [models.op.lt]: 60 } } })
]);
return ctx.success({
totalResumes,
averageCompetitiveness: parseFloat(avgCompetitiveness[0]?.avgScore || 0).toFixed(2),
workYearsStats,
competitivenessDistribution: {
high: highCompetitiveness,
medium: mediumCompetitiveness,
low: lowCompetitiveness
}
});
},
/**
* @swagger
* /admin_api/resume/detail:
* get:
* summary: 获取简历详情
* description: 根据简历ID获取详细信息
* tags: [后台-简历管理]
* parameters:
* - in: query
* name: resumeId
* required: true
* schema:
* type: string
* description: 简历ID
* responses:
* 200:
* description: 获取成功
*/
'POST /resume/detail': async (ctx) => {
const models = Framework.getModels();
const { resume_info } = models;
const { resumeId } = ctx.getBody();
if (!resumeId) {
return ctx.fail('简历ID不能为空');
}
const resume = await resume_info.findOne({ where: { resumeId } });
if (!resume) {
return ctx.fail('简历不存在');
}
// 解析 JSON 字段
const resumeDetail = resume.toJSON();
const jsonFields = ['skills', 'certifications', 'projectExperience', 'workExperience', 'aiSkillTags'];
jsonFields.forEach(field => {
if (resumeDetail[field]) {
try {
resumeDetail[field] = JSON.parse(resumeDetail[field]);
} catch (e) {
console.error(`解析字段 ${field} 失败:`, e);
}
}
});
// 解析原始数据(如果存在)
if (resumeDetail.originalData) {
try {
resumeDetail.originalData = JSON.parse(resumeDetail.originalData);
} catch (e) {
console.error('解析原始数据失败:', e);
}
}
return ctx.success(resumeDetail);
},
/**
* @swagger
* /admin_api/resume/delete:
* post:
* summary: 删除简历
* description: 删除指定的简历信息
* tags: [后台-简历管理]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - resumeId
* properties:
* resumeId:
* type: string
* description: 简历ID
* responses:
* 200:
* description: 删除成功
*/
'POST /resume/delete': async (ctx) => {
const models = Framework.getModels();
const { resume_info } = models;
const body = ctx.getBody();
const { resumeId } = body;
if (!resumeId) {
return ctx.fail('简历ID不能为空');
}
const result = await resume_info.destroy({ where: { resumeId } });
if (result === 0) {
return ctx.fail('简历不存在');
}
return ctx.success({ message: '简历删除成功' });
},
/**
* @swagger
* /admin_api/resume/get-by-device:
* get:
* summary: 根据设备获取简历
* description: 获取指定设备和平台的活跃简历
* tags: [后台-简历管理]
* parameters:
* - in: query
* name: sn_code
* required: true
* schema:
* type: string
* description: 设备SN码
* - in: query
* name: platform
* required: true
* schema:
* type: string
* description: 平台
* responses:
* 200:
* description: 获取成功
*/
'GET /resume/get-by-device': async (ctx) => {
const models = Framework.getModels();
const { resume_info } = models;
const { sn_code, platform } = ctx.query;
if (!sn_code || !platform) {
return ctx.fail('设备SN码和平台不能为空');
}
const resume = await resume_info.findOne({
where: { sn_code, platform, isActive: true },
order: [['syncTime', 'DESC']]
});
if (!resume) {
return ctx.fail('未找到活跃简历');
}
const resumeDetail = resume.toJSON();
const jsonFields = ['skills', 'certifications', 'projectExperience', 'workExperience', 'aiSkillTags'];
jsonFields.forEach(field => {
if (resumeDetail[field]) {
resumeDetail[field] = JSON.parse(resumeDetail[field]);
}
});
return ctx.success(resumeDetail);
},
/**
* @swagger
* /admin_api/resume/analyze-with-ai:
* post:
* summary: AI 分析简历
* description: 使用 AI 分析简历并更新 AI 字段
* tags: [后台-简历管理]
* requestBody:
* required: true
* content:
* application/json:
* schema:
* type: object
* required:
* - resumeId
* properties:
* resumeId:
* type: string
* description: 简历ID
* responses:
* 200:
* description: 分析成功
*/
'POST /resume/analyze-with-ai': async (ctx) => {
const models = Framework.getModels();
const { resume_info } = models;
const { resumeId } = ctx.getBody();
if (!resumeId) {
return ctx.fail('简历ID不能为空');
}
const resume = await resume_info.findOne({ where: { resumeId } });
if (!resume) {
return ctx.fail('简历不存在');
}
try {
const resumeManager = require('../middleware/job/resumeManager');
const resumeData = resume.toJSON();
// 调用 AI 分析
await resumeManager.analyze_resume_with_ai(resumeId, resumeData);
// 重新获取更新后的数据
const updatedResume = await resume_info.findOne({ where: { resumeId } });
const resumeDetail = updatedResume.toJSON();
// 解析 JSON 字段
const jsonFields = ['skills', 'certifications', 'projectExperience', 'workExperience', 'aiSkillTags'];
jsonFields.forEach(field => {
if (resumeDetail[field]) {
try {
resumeDetail[field] = JSON.parse(resumeDetail[field]);
} catch (e) {
console.error(`解析字段 ${field} 失败:`, e);
}
}
});
return ctx.success(resumeDetail);
} catch (error) {
console.error('AI 分析失败:', error);
return ctx.fail('AI 分析失败: ' + error.message);
}
}
};