Files
autoAiWorkSys/api/controller_admin/job_postings.js
张成 5d7444cd65 1
2025-11-24 13:23:42 +08:00

293 lines
7.5 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 岗位信息管理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);
}
};