293 lines
7.5 KiB
JavaScript
293 lines
7.5 KiB
JavaScript
/**
|
||
* 岗位信息管理API - 后台管理
|
||
* 提供岗位信息的查询和管理功能
|
||
*/
|
||
|
||
const Framework = require("../../framework/node-core-framework.js");
|
||
const jobManager = require("../middleware/job/jobManager.js");
|
||
|
||
module.exports = {
|
||
/**
|
||
* @swagger
|
||
* /admin_api/job/list:
|
||
* post:
|
||
* summary: 获取岗位列表
|
||
* description: 分页获取所有岗位信息
|
||
* tags: [后台-岗位管理]
|
||
* requestBody:
|
||
* required: true
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* properties:
|
||
* page:
|
||
* type: integer
|
||
* description: 页码
|
||
* pageSize:
|
||
* type: integer
|
||
* description: 每页数量
|
||
* platform:
|
||
* type: string
|
||
* description: 平台(可选)
|
||
* isOutsourcing:
|
||
* type: boolean
|
||
* description: 是否外包(可选)
|
||
* responses:
|
||
* 200:
|
||
* description: 获取成功
|
||
*/
|
||
'POST /job/list': async (ctx) => {
|
||
const models = Framework.getModels();
|
||
const { job_postings, op } = models;
|
||
const body = ctx.getBody();
|
||
const { platform, isOutsourcing, minSalary, maxSalary, searchText } = ctx.getBody();
|
||
|
||
// 获取分页参数
|
||
const { limit, offset } = ctx.getPageSize();
|
||
|
||
|
||
const where = {};
|
||
if (platform) {
|
||
where.platform = platform;
|
||
}
|
||
if (isOutsourcing) {
|
||
where.isOutsourcing = isOutsourcing;
|
||
}
|
||
|
||
|
||
// 薪资范围筛选
|
||
if (minSalary) {
|
||
where.salaryMin = { [op.gte]: minSalary };
|
||
}
|
||
if (maxSalary) {
|
||
where.salaryMax = { [op.lte]: maxSalary };
|
||
}
|
||
|
||
// 支持搜索岗位名称、公司名称
|
||
if (searchText) {
|
||
where[op.or] = [
|
||
{ jobTitle: { [op.like]: `%${searchText}%` } },
|
||
{ companyName: { [op.like]: `%${searchText}%` } }
|
||
];
|
||
}
|
||
|
||
const result = await job_postings.findAndCountAll({
|
||
where,
|
||
limit,
|
||
offset,
|
||
order: [
|
||
['aiMatchScore', 'DESC'],
|
||
['id', 'DESC']
|
||
]
|
||
});
|
||
|
||
return ctx.success(result);
|
||
|
||
},
|
||
|
||
/**
|
||
* @swagger
|
||
* /admin_api/job/statistics:
|
||
* get:
|
||
* summary: 获取岗位统计
|
||
* description: 获取岗位信息的统计数据
|
||
* tags: [后台-岗位管理]
|
||
* responses:
|
||
* 200:
|
||
* description: 获取成功
|
||
*/
|
||
'GET /job/statistics': async (ctx) => {
|
||
const models = Framework.getModels();
|
||
const { job_postings } = models;
|
||
|
||
|
||
const [
|
||
totalJobs,
|
||
outsourcingJobs,
|
||
directJobs,
|
||
highMatchJobs
|
||
] = await Promise.all([
|
||
job_postings.count(),
|
||
job_postings.count({ where: { isOutsourcing: true } }),
|
||
job_postings.count({ where: { isOutsourcing: false } }),
|
||
job_postings.count({ where: { aiMatchScore: { [models.op.gte]: 80 } } })
|
||
]);
|
||
|
||
// 按平台统计
|
||
const platformStats = await job_postings.findAll({
|
||
attributes: [
|
||
'platform',
|
||
[models.sequelize.fn('COUNT', models.sequelize.col('*')), 'count']
|
||
],
|
||
group: ['platform'],
|
||
raw: true
|
||
});
|
||
|
||
// 平均匹配度
|
||
const avgMatchScore = await job_postings.findAll({
|
||
attributes: [
|
||
[models.sequelize.fn('AVG', models.sequelize.col('aiMatchScore')), 'avgScore']
|
||
],
|
||
raw: true
|
||
});
|
||
|
||
// 薪资统计
|
||
const salaryStats = await job_postings.findAll({
|
||
attributes: [
|
||
[models.sequelize.fn('AVG', models.sequelize.col('salaryMin')), 'avgMinSalary'],
|
||
[models.sequelize.fn('AVG', models.sequelize.col('salaryMax')), 'avgMaxSalary'],
|
||
[models.sequelize.fn('MAX', models.sequelize.col('salaryMax')), 'maxSalary'],
|
||
[models.sequelize.fn('MIN', models.sequelize.col('salaryMin')), 'minSalary']
|
||
],
|
||
raw: true
|
||
});
|
||
|
||
return ctx.success({
|
||
totalJobs,
|
||
outsourcingJobs,
|
||
directJobs,
|
||
highMatchJobs,
|
||
outsourcingRate: totalJobs > 0 ? ((outsourcingJobs / totalJobs) * 100).toFixed(2) : 0,
|
||
averageMatchScore: parseFloat(avgMatchScore[0]?.avgScore || 0).toFixed(2),
|
||
platformStats,
|
||
salaryStats: salaryStats[0] || {}
|
||
});
|
||
|
||
},
|
||
|
||
/**
|
||
* @swagger
|
||
* /admin_api/job/detail:
|
||
* get:
|
||
* summary: 获取岗位详情
|
||
* description: 根据岗位ID获取详细信息
|
||
* tags: [后台-岗位管理]
|
||
* parameters:
|
||
* - in: query
|
||
* name: jobId
|
||
* required: true
|
||
* schema:
|
||
* type: string
|
||
* description: 岗位ID
|
||
* responses:
|
||
* 200:
|
||
* description: 获取成功
|
||
*/
|
||
'GET /job/detail': async (ctx) => {
|
||
const models = Framework.getModels();
|
||
const { job_postings } = models;
|
||
const { jobId } = ctx.query;
|
||
|
||
if (!jobId) {
|
||
return ctx.fail('岗位ID不能为空');
|
||
}
|
||
|
||
|
||
const job = await job_postings.findOne({ where: { jobId } });
|
||
|
||
if (!job) {
|
||
return ctx.fail('岗位不存在');
|
||
}
|
||
|
||
return ctx.success(job);
|
||
|
||
},
|
||
|
||
/**
|
||
* @swagger
|
||
* /admin_api/job/delete:
|
||
* post:
|
||
* summary: 删除岗位
|
||
* description: 删除指定的岗位信息
|
||
* tags: [后台-岗位管理]
|
||
* requestBody:
|
||
* required: true
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* required:
|
||
* - jobId
|
||
* properties:
|
||
* jobId:
|
||
* type: string
|
||
* description: 岗位ID
|
||
* responses:
|
||
* 200:
|
||
* description: 删除成功
|
||
*/
|
||
'POST /job/delete': async (ctx) => {
|
||
const models = Framework.getModels();
|
||
const { job_postings } = models;
|
||
const body = ctx.getBody();
|
||
const { jobId } = body;
|
||
|
||
if (!jobId) {
|
||
return ctx.fail('岗位ID不能为空');
|
||
}
|
||
|
||
|
||
const result = await job_postings.destroy({ where: { jobId } });
|
||
|
||
if (result === 0) {
|
||
return ctx.fail('岗位不存在');
|
||
}
|
||
|
||
return ctx.success({ message: '岗位删除成功' });
|
||
|
||
},
|
||
|
||
/**
|
||
* @swagger
|
||
* /admin_api/job/greet:
|
||
* post:
|
||
* summary: 职位打招呼
|
||
* description: 向指定职位的HR打招呼(通过MQTT发送指令到boss-automation-nodejs)
|
||
* tags: [后台-岗位管理]
|
||
* requestBody:
|
||
* required: true
|
||
* content:
|
||
* application/json:
|
||
* schema:
|
||
* type: object
|
||
* required:
|
||
* - sn_code
|
||
* - encryptJobId
|
||
* properties:
|
||
* sn_code:
|
||
* type: string
|
||
* description: 设备SN码
|
||
* encryptJobId:
|
||
* type: string
|
||
* description: 加密的职位ID
|
||
* securityId:
|
||
* type: string
|
||
* description: 安全ID(可选)
|
||
* brandName:
|
||
* type: string
|
||
* description: 公司名称
|
||
* platform:
|
||
* type: string
|
||
* description: 平台(默认boss)
|
||
* responses:
|
||
* 200:
|
||
* description: 打招呼成功
|
||
*/
|
||
'POST /job/greet': async (ctx) => {
|
||
const body = ctx.getBody();
|
||
const { sn_code, encryptJobId, securityId, brandName, platform = 'boss' } = body;
|
||
|
||
const result = await jobManager.job_greet({
|
||
sn_code,
|
||
encryptJobId,
|
||
securityId,
|
||
brandName,
|
||
platform
|
||
});
|
||
|
||
return ctx.success(result);
|
||
}
|
||
};
|
||
|