Files
autoAiWorkSys/api/controller_front/job_postings.js
张成 df0aacc782 11
2026-04-16 14:01:52 +08:00

179 lines
5.0 KiB
JavaScript
Raw 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.
/**
* 岗位表job_postings客户端接口仅查本表字段不连表
*/
const Framework = require('../../framework/node-core-framework.js');
/**
* 从 resume_info.job_listings 解析 Boss Tab 文案列表(与 get_job_listings 一致)
* @param {unknown} job_listings
* @returns {string[]}
*/
function parse_resume_tab_labels(job_listings) {
if (job_listings == null) return [];
let arr = job_listings;
if (typeof arr === 'string') {
try {
arr = JSON.parse(arr);
} catch (e) {
return [];
}
}
if (!Array.isArray(arr)) return [];
const out = [];
arr.forEach((item) => {
if (item == null) return;
if (typeof item === 'string') {
const s = item.trim();
if (s) out.push(s);
return;
}
if (typeof item === 'object' && item.text != null) {
const s = String(item.text).trim();
if (s) out.push(s);
}
});
return [...new Set(out)];
}
module.exports = {
/**
* 按设备 SN 拉取 jobId -> 投递结果字段is_delivered、deliver_failed_reason、applyStatus
* 用于 Electron 职位列表页合并展示,不查 apply_records
*/
'POST /job_postings/deliver_status_map': async (ctx) => {
const models = Framework.getModels();
const { job_postings, op } = models;
const body = ctx.getBody() || {};
const sn_code = body.sn_code || ctx.query?.sn_code;
const platform = body.platform || 'boss';
const startTime = body.startTime;
const endTime = body.endTime;
if (!sn_code) {
return ctx.fail('请提供设备SN码');
}
const where = { sn_code, platform };
if (startTime || endTime) {
where.last_modify_time = {};
if (startTime) {
where.last_modify_time[op.gte] = new Date(startTime);
}
if (endTime) {
const end = new Date(endTime);
end.setHours(23, 59, 59, 999);
where.last_modify_time[op.lte] = end;
}
}
const rows = await job_postings.findAll({
where,
attributes: ['jobId', 'is_delivered', 'deliver_failed_reason', 'applyStatus', 'last_modify_time'],
order: [['last_modify_time', 'DESC']],
limit: Math.min(Number(body.limit) || 2000, 5000)
});
const list = rows.map((r) => {
const j = r.toJSON ? r.toJSON() : r;
return {
jobId: j.jobId,
is_delivered: !!j.is_delivered,
deliver_failed_reason: j.deliver_failed_reason || '',
applyStatus: j.applyStatus || 'pending',
last_modify_time: j.last_modify_time
};
});
return ctx.success({ list });
},
/**
* 按设备 SN 分页查询 job_postings仅本表字段用于 Electron 职位列表只读展示)
*/
'POST /job_postings/page_list': async (ctx) => {
const models = Framework.getModels();
const { job_postings, resume_info, op } = models;
const body = ctx.getBody() || {};
const sn_code = body.sn_code || ctx.query?.sn_code;
const platform = body.platform || 'boss';
if (!sn_code) {
return ctx.fail('请提供设备SN码');
}
const page = Math.max(1, Number(body.page) || 1);
const raw_page_size = body.page_size ?? body.pageSize ?? 20;
const page_size = Math.min(100, Math.max(1, Number(raw_page_size) || 20));
const offset = (page - 1) * page_size;
const base_where = { sn_code, platform };
const startTime = body.startTime;
const endTime = body.endTime;
if (startTime || endTime) {
base_where.last_modify_time = {};
if (startTime) {
base_where.last_modify_time[op.gte] = new Date(startTime);
}
if (endTime) {
const end = new Date(endTime);
end.setHours(23, 59, 59, 999);
base_where.last_modify_time[op.lte] = end;
}
}
let tab_labels = [];
if (resume_info) {
const resume = await resume_info.findOne({
where: { sn_code, platform, isActive: true },
order: [['last_modify_time', 'DESC']]
});
if (resume) {
const rj = resume.toJSON ? resume.toJSON() : resume;
tab_labels = parse_resume_tab_labels(rj.job_listings);
}
}
/** 不按「当前投递标签」过滤;列表为设备+平台下库中全部职位(各标签写入的 keyword 均会出现在列表中。tab_labels 供前端展示「账户已同步的全部 Tab」 */
const where = base_where;
const { rows, count } = await job_postings.findAndCountAll({
where,
attributes: [
'id',
'jobId',
'jobTitle',
'companyName',
'salary',
'location',
'education',
'experience',
'last_modify_time',
'create_time',
'is_delivered',
'deliver_failed_reason',
'applyStatus',
'platform',
'keyword',
'aiMatchScore'
],
limit: page_size,
offset,
order: [['last_modify_time', 'DESC']]
});
const list = rows.map((r) => {
const j = r.toJSON ? r.toJSON() : r;
return j;
});
return ctx.success({
list,
total: count,
page,
page_size,
tab_labels
});
}
};