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' * 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 } = ctx.getBody(); const dayjs = require('dayjs'); const crypto = require('crypto'); // 验证参数 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(如果不存在,基于手机号和机器特征生成) let device_id = user.device_id; if (!device_id) { // 生成唯一设备ID const machineInfo = `${phone}_${Date.now()}_${Math.random()}`; device_id = crypto.createHash('sha256').update(machineInfo).digest('hex').substring(0, 32); // 保存设备ID到账号表 await pla_account.update( { device_id: device_id }, { where: { id: user.id } } ); } // 创建token const token = Framework.getServices().tokenService.create({ sn_code: user.sn_code, device_id: device_id, user_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 }); } }