import express from 'express' import crypto from 'crypto' import { users } from '../data/users.js' import { menuTree, flattenButtons } from '../data/menu.js' import { accessTokens, refreshTokens, ACCESS_TOKEN_TTL_MS, REFRESH_TOKEN_TTL_MS, FIXED_SMS_CODE } from '../state.js' import { requireAuth } from '../middleware/requireAuth.js' const router = express.Router() function findUser(username) { return users.find((u) => u.username === username) } router.post('/sms/send', (req, res) => { const { username, password } = req.body || {} const user = findUser(username) if (!user) return res.json({ code: 40001, msg: '账号或密码错误', data: null }) if (user.status === 'locked') return res.json({ code: 40002, msg: '账号已锁定,请联系管理员', data: null }) if (user.password !== password) return res.json({ code: 40001, msg: '账号或密码错误', data: null }) console.log(`[mock-server] 验证码已发送至 ${user.phone}: ${FIXED_SMS_CODE}`) res.json({ code: 200, msg: 'ok', data: null }) }) router.post('/login', (req, res) => { const { username, password, code } = req.body || {} const user = findUser(username) if (!user) return res.json({ code: 40001, msg: '账号或密码错误', data: null }) if (user.status === 'locked') return res.json({ code: 40002, msg: '账号已锁定,请联系管理员', data: null }) if (user.password !== password) { user.failCount += 1 if (user.failCount >= 5) { user.status = 'locked' return res.json({ code: 40002, msg: '连续输错5次,账号已锁定', data: null }) } return res.json({ code: 40001, msg: '账号或密码错误', data: null }) } if (code !== FIXED_SMS_CODE) return res.json({ code: 40003, msg: '验证码错误或已过期', data: null }) user.failCount = 0 user.lastLoginAt = new Date().toISOString().slice(0, 19).replace('T', ' ') const accessToken = crypto.randomUUID() const refreshToken = crypto.randomUUID() accessTokens.set(accessToken, { userId: user.id, expireAt: Date.now() + ACCESS_TOKEN_TTL_MS }) refreshTokens.set(refreshToken, { userId: user.id, expireAt: Date.now() + REFRESH_TOKEN_TTL_MS }) res.cookie('refresh_token', refreshToken, { httpOnly: true, maxAge: REFRESH_TOKEN_TTL_MS, sameSite: 'lax' }) res.json({ code: 200, msg: 'ok', data: { accessToken, userInfo: { id: user.id, username: user.username, realName: user.realName, orgId: user.orgId, roleIds: user.roleIds }, menuTree, buttonCodes: flattenButtons(menuTree), mustChangePassword: !!user.mustChangePassword } }) }) router.post('/refresh', (req, res) => { const refreshToken = req.cookies?.refresh_token const record = refreshToken && refreshTokens.get(refreshToken) if (!record || record.expireAt < Date.now()) { return res.status(401).json({ code: 40100, msg: '登录已过期,请重新登录', data: null }) } const accessToken = crypto.randomUUID() accessTokens.set(accessToken, { userId: record.userId, expireAt: Date.now() + ACCESS_TOKEN_TTL_MS }) res.json({ code: 200, msg: 'ok', data: { accessToken } }) }) router.post('/logout', (req, res) => { const refreshToken = req.cookies?.refresh_token if (refreshToken) refreshTokens.delete(refreshToken) res.clearCookie('refresh_token') res.json({ code: 200, msg: 'ok', data: null }) }) router.get('/userinfo', requireAuth, (req, res) => { const user = users.find((u) => u.id === req.userId) res.json({ code: 200, msg: 'ok', data: { id: user.id, username: user.username, realName: user.realName, orgId: user.orgId, roleIds: user.roleIds } }) }) router.get('/menu', requireAuth, (req, res) => { res.json({ code: 200, msg: 'ok', data: { menuTree, buttonCodes: flattenButtons(menuTree) } }) }) export default router