/** * 投递记录管理控制器(客户端接口) * 提供客户端调用的投递记录相关接口 */ const Framework = require("../../framework/node-core-framework.js"); module.exports = { /** * @swagger * /api/apply/list: * post: * summary: 获取投递记录列表 * description: 根据设备SN码分页获取投递记录 * tags: [前端-投递管理] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * sn_code: * type: string * description: 设备SN码 * seachOption: * type: object * description: 搜索条件 * pageOption: * type: object * description: 分页选项 * responses: * 200: * description: 获取成功 */ 'POST /apply/list': async (ctx) => { const models = Framework.getModels(); const { apply_records, op } = models; const body = ctx.getBody(); // 从query或body中获取sn_code,优先从query获取 const sn_code = ctx.query?.sn_code || body.sn_code; if (!sn_code) { return ctx.fail('请提供设备SN码'); } const seachOption = body.seachOption || {}; const pageOption = body.pageOption || {}; // 获取分页参数 const page = pageOption.page || 1; const pageSize = pageOption.pageSize || 20; const limit = pageSize; const offset = (page - 1) * pageSize; const where = { sn_code }; // 平台筛选 if (seachOption.platform) { where.platform = seachOption.platform; } // 投递状态筛选 if (seachOption.applyStatus) { where.applyStatus = seachOption.applyStatus; } // 反馈状态筛选 if (seachOption.feedbackStatus) { where.feedbackStatus = seachOption.feedbackStatus; } // 时间范围筛选 if (seachOption.startTime || seachOption.endTime) { where.create_time = {}; if (seachOption.startTime) { where.create_time[op.gte] = new Date(seachOption.startTime); } if (seachOption.endTime) { const endTime = new Date(seachOption.endTime); endTime.setHours(23, 59, 59, 999); // 设置为当天的最后一刻 where.create_time[op.lte] = endTime; } } // 搜索:岗位名称、公司名称 if (seachOption.key && seachOption.value) { const key = seachOption.key; const value = seachOption.value; if (key === 'jobTitle') { where.jobTitle = { [op.like]: `%${value}%` }; } else if (key === 'companyName') { where.companyName = { [op.like]: `%${value}%` }; } else { // 默认搜索岗位名称或公司名称 where[op.or] = [ { jobTitle: { [op.like]: `%${value}%` } }, { companyName: { [op.like]: `%${value}%` } } ]; } } const result = await apply_records.findAndCountAll({ where, limit, offset, order: [['create_time', 'DESC']] }); return ctx.success({ count: result.count, total: result.count, rows: result.rows, list: result.rows }); }, /** * @swagger * /api/apply/statistics: * get: * summary: 获取投递统计 * description: 根据设备SN码获取投递统计数据(包含今日、本周、本月统计),支持时间范围筛选 * tags: [前端-投递管理] * parameters: * - in: query * name: sn_code * required: true * schema: * type: string * description: 设备SN码 * - in: query * name: startTime * schema: * type: string * format: date-time * description: 开始时间(可选) * - in: query * name: endTime * schema: * type: string * format: date-time * description: 结束时间(可选) * responses: * 200: * description: 获取成功 */ 'GET /apply/statistics': async (ctx) => { const models = Framework.getModels(); const { apply_records, op } = models; const { sn_code, startTime, endTime } = ctx.query; const final_sn_code = sn_code; if (!final_sn_code) { return ctx.fail('请提供设备SN码'); } // 构建基础查询条件 const baseWhere = { sn_code: final_sn_code }; // 如果提供了时间范围,则添加到查询条件中 if (startTime || endTime) { baseWhere.create_time = {}; if (startTime) { baseWhere.create_time[op.gte] = new Date(startTime); } if (endTime) { const endTimeDate = new Date(endTime); endTimeDate.setHours(23, 59, 59, 999); // 设置为当天的最后一刻 baseWhere.create_time[op.lte] = endTimeDate; } } // 计算时间范围(如果未提供时间范围,则使用默认的今日、本周、本月) const now = new Date(); // 今天的开始时间(00:00:00) const todayStart = new Date(now); todayStart.setHours(0, 0, 0, 0); // 本周的开始时间(周一00:00:00) const weekStart = new Date(now); const dayOfWeek = weekStart.getDay(); const diff = dayOfWeek === 0 ? 6 : dayOfWeek - 1; // 周日算作上周 weekStart.setDate(weekStart.getDate() - diff); weekStart.setHours(0, 0, 0, 0); // 本月的开始时间(1号00:00:00) const monthStart = new Date(now.getFullYear(), now.getMonth(), 1); monthStart.setHours(0, 0, 0, 0); // 构建统计查询条件 const buildWhereWithTime = (additionalWhere = {}) => { const where = { ...baseWhere, ...additionalWhere }; // 如果提供了时间范围,则不再使用默认的今日、本周、本月时间 if (startTime || endTime) { return where; } return where; }; const [ totalCount, successCount, failedCount, pendingCount, interviewCount, todayCount, weekCount, monthCount ] = await Promise.all([ // 总计(如果提供了时间范围,则只统计该范围内的) apply_records.count({ where: baseWhere }), apply_records.count({ where: { ...baseWhere, applyStatus: 'success' } }), apply_records.count({ where: { ...baseWhere, applyStatus: 'failed' } }), apply_records.count({ where: { ...baseWhere, applyStatus: 'pending' } }), apply_records.count({ where: { ...baseWhere, feedbackStatus: 'interview' } }), // 今日(如果提供了时间范围,则返回0,否则统计今日) startTime || endTime ? 0 : apply_records.count({ where: { sn_code: final_sn_code, create_time: { [op.gte]: todayStart } } }), // 本周(如果提供了时间范围,则返回0,否则统计本周) startTime || endTime ? 0 : apply_records.count({ where: { sn_code: final_sn_code, create_time: { [op.gte]: weekStart } } }), // 本月(如果提供了时间范围,则返回0,否则统计本月) startTime || endTime ? 0 : apply_records.count({ where: { sn_code: final_sn_code, create_time: { [op.gte]: monthStart } } }) ]); return ctx.success({ totalCount, successCount, failedCount, pendingCount, interviewCount, todayCount, weekCount, monthCount, successRate: totalCount > 0 ? ((successCount / totalCount) * 100).toFixed(2) : 0, interviewRate: totalCount > 0 ? ((interviewCount / totalCount) * 100).toFixed(2) : 0 }); }, /** * @swagger * /api/apply/detail: * get: * summary: 获取投递记录详情 * description: 根据投递ID获取详细信息 * tags: [前端-投递管理] * parameters: * - in: query * name: applyId * required: true * schema: * type: string * description: 投递记录ID * responses: * 200: * description: 获取成功 */ 'GET /apply/detail': async (ctx) => { const models = Framework.getModels(); const { apply_records } = models; // 支持 applyId 和 id 两种参数名(向后兼容) const recordId = ctx.query.applyId || ctx.query.id; if (!recordId) { return ctx.fail('投递记录ID不能为空'); } // 使用 id 字段查询(数据库主键) const record = await apply_records.findOne({ where: { id: recordId } }); if (!record) { return ctx.fail('投递记录不存在'); } return ctx.success(record); }, /** * @swagger * /api/apply/trend: * get: * summary: 获取近7天投递趋势数据 * description: 根据设备SN码获取近7天的投递数量趋势 * tags: [前端-投递管理] * parameters: * - in: query * name: sn_code * required: true * schema: * type: string * description: 设备SN码 * responses: * 200: * description: 获取成功 */ 'GET /apply/trend': async (ctx) => { const models = Framework.getModels(); const { apply_records, op } = models; const { sn_code } = ctx.query; if (!sn_code) { return ctx.fail('请提供设备SN码'); } // 计算近7天的日期范围 const today = new Date(); today.setHours(23, 59, 59, 999); const sevenDaysAgo = new Date(); sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 6); sevenDaysAgo.setHours(0, 0, 0, 0); // 查询近7天的投递记录 const records = await apply_records.findAll({ where: { sn_code: sn_code, create_time: { [op.gte]: sevenDaysAgo, [op.lte]: today } }, attributes: ['create_time'], raw: true }); // 生成7天的日期数组 const trendData = []; for (let i = 6; i >= 0; i--) { const date = new Date(); date.setDate(date.getDate() - i); date.setHours(0, 0, 0, 0); const dateStr = `${date.getMonth() + 1}/${date.getDate()}`; // 统计当天的投递数量 const count = records.filter(record => { const recordDate = new Date(record.create_time); recordDate.setHours(0, 0, 0, 0); return recordDate.getTime() === date.getTime(); }).length; trendData.push({ date: dateStr, value: count }); } return ctx.success(trendData); } };