const Framework = require("../../framework/node-core-framework.js"); module.exports = { /** * @swagger * /api/user/login: * post: * summary: 用户登录 * description: 通过手机号和密码登录,返回token、device_id和用户信息 * tags: [前端-用户管理] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - phone * - password * properties: * phone: * type: string * description: 手机号(登录名) * example: '13800138000' * password: * type: string * description: 密码 * example: 'password123' * device_id: * type: string * description: 设备ID(客户端生成,可选,如果提供则使用提供的,否则使用数据库中的) * example: 'device_1234567890abcdef' * responses: * 200: * description: 登录成功 * content: * application/json: * schema: * type: object * properties: * code: * type: integer * description: 状态码,0表示成功 * example: 0 * message: * type: string * description: 响应消息 * example: 'success' * data: * type: object * properties: * token: * type: string * description: 认证token * example: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' * device_id: * type: string * description: 设备ID * example: 'device_123456' * user: * type: object * description: 用户信息 * 400: * description: 参数错误或用户不存在 * content: * application/json: * schema: * type: object * properties: * code: * type: integer * example: 400 * message: * type: string * example: '用户不存在或密码错误' */ "POST /user/login": async (ctx) => { const { phone, password, device_id: client_device_id } = ctx.getBody(); const dayjs = require('dayjs'); // 验证参数 if (!phone || !password) { return ctx.fail('手机号和密码不能为空'); } const { pla_account } = await Framework.getModels(); // 根据手机号(login_name)和密码查找用户 const user = await pla_account.findOne({ where: { login_name: phone, pwd: password } }); if (!user) { return ctx.fail('手机号或密码错误'); } // 检查账号是否启用 if (!user.is_enabled) { return ctx.fail('账号已被禁用'); } // 检查授权状态 const userData = user.toJSON(); const authDate = userData.authorization_date; const authDays = userData.authorization_days || 0; if (authDate && authDays > 0) { const startDate = dayjs(authDate); const endDate = startDate.add(authDays, 'day'); const now = dayjs(); const remaining = endDate.diff(now, 'day', true); const remaining_days = Math.max(0, Math.ceil(remaining)); if (remaining_days <= 0) { return ctx.fail('账号授权已过期,请联系管理员续费'); } } // 处理设备ID:优先使用客户端传递的 device_id,如果没有则使用数据库中的 let device_id = client_device_id || user.device_id; // 如果客户端提供了 device_id 且与数据库中的不同,则更新数据库 if (client_device_id && client_device_id !== user.device_id) { await pla_account.update( { device_id: client_device_id }, { where: { id: user.id } } ); device_id = client_device_id; } // 如果既没有客户端传递的,数据库中也为空,则返回错误(不应该发生,因为客户端会生成) if (!device_id) { return ctx.fail('设备ID不能为空,请重新登录'); } // 创建token const token = Framework.getServices().tokenService.create({ sn_code: user.sn_code, device_id: device_id, id: user.id }); // 计算剩余天数 let remaining_days = 0; if (authDate && authDays > 0) { const startDate = dayjs(authDate); const endDate = startDate.add(authDays, 'day'); const now = dayjs(); const remaining = endDate.diff(now, 'day', true); remaining_days = Math.max(0, Math.ceil(remaining)); } const userInfo = user.toJSON(); userInfo.remaining_days = remaining_days; // 不返回密码 delete userInfo.pwd; return ctx.success({ token, device_id, user: userInfo }); }, /** * @swagger * /api/user/delivery-config/get: * post: * summary: 获取投递配置 * description: 根据设备SN码获取用户的投递配置,返回 account_config 表中的 auto_deliver_config 对象 * tags: [前端-用户管理] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - sn_code * properties: * sn_code: * type: string * description: 设备SN码 * responses: * 200: * description: 获取成功 * content: * application/json: * schema: * type: object * properties: * code: * type: integer * example: 0 * message: * type: string * example: 'success' * data: * type: object * properties: * auto_deliver_config: * type: object * description: 自动投递配置对象,如果不存在则返回 null * nullable: true */ 'POST /user/delivery-config/get': async (ctx) => { try { console.log('[User Controller] 收到获取投递配置请求'); const body = ctx.getBody(); const { sn_code } = body; console.log('[User Controller] sn_code:', sn_code); if (!sn_code) { return ctx.fail('请提供设备SN码'); } const { pla_account, account_config } = await Framework.getModels(); // 根据 sn_code 查找账号 const user = await pla_account.findOne({ where: { sn_code } }); if (!user) { return ctx.fail('用户不存在'); } // 从 account_config 表获取配置 const accountConfig = await account_config.findOne({ where: { account_id: user.id } }); // 直接返回 auto_deliver_config 对象 const auto_deliver_config = accountConfig?.auto_deliver_config || null; return ctx.success({ auto_deliver_config }); } catch (error) { console.error('获取投递配置失败:', error); return ctx.fail('获取投递配置失败: ' + error.message); } }, /** * @swagger * /api/user/delivery-config/save: * post: * summary: 保存投递配置 * description: 根据设备SN码保存用户的投递配置到 account_config 表的 auto_deliver_config 字段 * tags: [前端-用户管理] * requestBody: * required: true * content: * application/json: * schema: * type: object * required: * - sn_code * - auto_deliver_config * properties: * sn_code: * type: string * description: 设备SN码 * auto_deliver_config: * type: object * description: 自动投递配置对象 * properties: * auto_delivery: * type: boolean * description: 是否启用自动投递 * interval: * type: integer * description: 投递间隔(分钟) * min_salary: * type: integer * description: 最低薪资 * max_salary: * type: integer * description: 最高薪资 * scroll_pages: * type: integer * description: 滚动页数 * max_per_batch: * type: integer * description: 每批最多投递数 * filter_keywords: * type: string * description: 过滤关键词 * exclude_keywords: * type: string * description: 排除关键词 * start_time: * type: string * description: 开始时间(格式:HH:mm) * end_time: * type: string * description: 结束时间(格式:HH:mm) * workdays_only: * type: boolean * description: 仅工作日 * responses: * 200: * description: 保存成功 */ 'POST /user/delivery-config/save': async (ctx) => { try { console.log('[User Controller] 收到保存投递配置请求'); const body = ctx.getBody(); const { sn_code, auto_deliver_config } = body; console.log('[User Controller] sn_code:', sn_code, 'auto_deliver_config:', JSON.stringify(auto_deliver_config)); if (!sn_code) { return ctx.fail('请提供设备SN码'); } if (!auto_deliver_config) { return ctx.fail('请提供 auto_deliver_config 配置对象'); } const { pla_account, account_config } = await Framework.getModels(); // 根据 sn_code 查找账号 const user = await pla_account.findOne({ where: { sn_code } }); if (!user) { return ctx.fail('用户不存在'); } // 查找或创建 account_config 记录 const accountConfig = await account_config.findOne({ where: { account_id: user.id } }); if (accountConfig) { // 更新现有配置 await account_config.update( { auto_deliver_config: auto_deliver_config }, { where: { account_id: user.id } } ); } else { // 创建新配置 await account_config.create({ account_id: user.id, platform_type: user.platform_type || 'boss', auto_deliver_config: auto_deliver_config }); } // 更新 pla_account 表的 auto_deliver 字段 await pla_account.update( { auto_deliver: auto_deliver_config.autoDelivery ? 1 : 0 }, { where: { id: user.id } } ); return ctx.success({ message: '配置保存成功' }); } catch (error) { console.error('保存投递配置失败:', error); return ctx.fail('保存投递配置失败: ' + error.message); } } }