This commit is contained in:
张成
2026-04-16 14:01:52 +08:00
parent 7ef0c68ad1
commit df0aacc782
10 changed files with 531 additions and 22 deletions

View File

@@ -0,0 +1,178 @@
/**
* 岗位表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
});
}
};

View File

@@ -308,6 +308,98 @@ module.exports = {
console.error('[任务管理] 获取任务统计失败:', error);
return ctx.fail('获取任务统计失败: ' + (error.message || '未知错误'));
}
},
/**
* 按设备 SN 分页查询任务指令列表(展示请求参数与响应结果)
*/
'POST /task/command/page_list': async (ctx) => {
try {
const body = ctx.getBody() || {};
const sn_code = body.sn_code || ctx.query?.sn_code;
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;
if (!sn_code) {
return ctx.fail('请提供设备SN码');
}
const { task_status, task_commands, op } = await Framework.getModels();
// 先查当前账号对应任务,再按 task_id 关联查指令
const task_rows = await task_status.findAll({
where: { sn_code },
attributes: ['id'],
order: [['id', 'DESC']],
limit: 2000
});
const task_ids = task_rows.map((row) => row.id).filter((id) => id != null);
if (!task_ids.length) {
return ctx.success({
list: [],
total: 0,
page,
page_size
});
}
const where = {
task_id: { [op.in]: task_ids }
};
if (body.command_type) {
where.command_type = String(body.command_type).trim();
}
if (body.status) {
where.status = String(body.status).trim();
}
const { rows, count } = await task_commands.findAndCountAll({
where,
attributes: [
'id',
'task_id',
'command_type',
'command_name',
'command_params',
'status',
'priority',
'sequence',
'retry_count',
'max_retries',
'start_time',
'end_time',
'duration',
'result',
'error_message',
'progress'
],
order: [['id', 'DESC']],
limit: page_size,
offset
});
const list = rows.map((r) => {
const j = r.toJSON ? r.toJSON() : r;
return {
...j,
// 前端直接展示,避免超长字段压垮 UI
command_params_preview: j.command_params ? String(j.command_params).slice(0, 1200) : '',
result_preview: j.result ? String(j.result).slice(0, 1200) : ''
};
});
return ctx.success({
list,
total: count,
page,
page_size
});
} catch (error) {
console.error('[任务管理] 获取指令分页失败:', error);
return ctx.fail('获取指令分页失败: ' + (error.message || '未知错误'));
}
}
};