refactor: restructure entire project for human maintainability

Server:
- Add Express framework, replace custom router/request parser
- Create DAO layer (12 files) centralizing all 73 SQL queries
- Rewrite 7 route files as thin Express controllers calling DAOs
- Add SCF-to-Express adapter (lib/serverless.js)
- Add auth middleware (middleware/auth.js)
- Remove dead code from lib/auth.js

Admin console:
- Extract DataTable component (table + pagination)
- Extract ConfirmModal component (modal + form styles)
- Create listMixin for paginated list pages
- Move form styles to common.css for slot compatibility
- Refactor device + subscription pages as examples

Miniprogram:
- Split 734-line BLE monolith into 4 focused modules
  (protocol, connection, commands, barrel index)
- Create API module (utils/api.js) with named functions
- Create page utilities (utils/page.js)
- Refactor index + profile pages to use API module
这个提交包含在:
Guoguo
2026-04-29 05:58:20 -07:00
父节点 9f0e629c82
当前提交 bb4b80f867
修改 46 个文件,包含 4306 行新增2020 行删除
+59 -62
查看文件
@@ -1,78 +1,75 @@
const jwt = require('jsonwebtoken')
const { one, query } = require('../lib/db')
const router = require('express').Router()
const { ok, fail } = require('../lib/response')
const { signUser, readBearer } = require('../lib/auth')
const { code2Session } = require('../lib/wechat')
const { writeLog } = require('../lib/log')
const config = require('../config')
const userDao = require('../dao/user.dao')
const logDao = require('../dao/log.dao')
function register(router) {
router.post('/api/v1/auth/login', async ctx => {
const session = await code2Session(ctx.body.code || '')
let user = await one('SELECT * FROM users WHERE openid = :openid', { openid: session.openid })
if (!user) {
const result = await query(
'INSERT INTO users (openid, nickname, avatar, status) VALUES (:openid, :nickname, :avatar, 1)',
{ openid: session.openid, nickname: '', avatar: '' }
)
user = await one('SELECT * FROM users WHERE user_id = :user_id', { user_id: result.insertId })
await writeLog({ user_id: user.user_id, action: 'user_register', detail: '新用户注册', ip: ctx.ip })
}
const token = signUser(user)
await writeLog({ user_id: user.user_id, action: 'user_login', detail: '用户登录', ip: ctx.ip })
return ok({
token,
const wrap = fn => (req, res, next) => fn(req, res, next).catch(next)
router.post('/auth/login', wrap(async (req, res) => {
const session = await code2Session(req.body.code || '')
let user = await userDao.findByOpenid(session.openid)
if (!user) {
const result = await userDao.create(session.openid)
user = await userDao.findById(result.insertId)
await logDao.write({ user_id: user.user_id, action: 'user_register', detail: '新用户注册', ip: req.ip })
}
const token = signUser(user)
await logDao.write({ user_id: user.user_id, action: 'user_login', detail: '用户登录', ip: req.ip })
res.json(ok({
token,
user_id: String(user.user_id),
user_info: {
user_id: String(user.user_id),
user_info: {
user_id: String(user.user_id),
nickname: user.nickname || '用户' + String(user.user_id),
avatar: user.avatar || '',
phone: user.phone || '',
gender: user.gender || 0
},
expires_in: 604800
})
})
nickname: user.nickname || '用户' + String(user.user_id),
avatar: user.avatar || '',
phone: user.phone || '',
gender: user.gender || 0
},
expires_in: 604800
}))
}))
router.post('/api/v1/auth/refresh', async ctx => {
const token = readBearer(ctx.headers)
if (!token) return fail(1001, 'token_expired')
router.post('/auth/refresh', wrap(async (req, res) => {
const token = readBearer(req.headers)
if (!token) return res.json(fail(1001, 'token_expired'))
let payload
try {
payload = jwt.verify(token, config.jwt.secret)
} catch (err) {
if (err.name === 'TokenExpiredError') {
try {
payload = jwt.verify(token, config.jwt.secret, { ignoreExpiration: true })
} catch (_) {
return fail(1001, 'token_expired')
}
const now = Math.floor(Date.now() / 1000)
const gracePeriod = 3 * 24 * 60 * 60
if (now - payload.exp > gracePeriod) {
return fail(1001, 'token_expired')
}
} else {
return fail(1001, 'token_expired')
let payload
try {
payload = jwt.verify(token, config.jwt.secret)
} catch (err) {
if (err.name === 'TokenExpiredError') {
try {
payload = jwt.verify(token, config.jwt.secret, { ignoreExpiration: true })
} catch (_) {
return res.json(fail(1001, 'token_expired'))
}
const now = Math.floor(Date.now() / 1000)
const gracePeriod = 3 * 24 * 60 * 60
if (now - payload.exp > gracePeriod) {
return res.json(fail(1001, 'token_expired'))
}
} else {
return res.json(fail(1001, 'token_expired'))
}
}
if (payload.type !== 'user') return fail(1001, 'token_expired')
if (payload.type !== 'user') return res.json(fail(1001, 'token_expired'))
// Check if token is within 7 days of expiry (for non-expired tokens)
const now = Math.floor(Date.now() / 1000)
const sevenDays = 7 * 24 * 60 * 60
if (payload.exp && payload.exp > now && (payload.exp - now) > sevenDays) {
return ok({ token, expires_in: payload.exp - now })
}
const now = Math.floor(Date.now() / 1000)
const sevenDays = 7 * 24 * 60 * 60
if (payload.exp && payload.exp > now && (payload.exp - now) > sevenDays) {
return res.json(ok({ token, expires_in: payload.exp - now }))
}
const user = await one('SELECT * FROM users WHERE user_id = :user_id AND status = 1', { user_id: payload.user_id })
if (!user) return fail(1001, 'token_expired')
const user = await userDao.findById(payload.user_id)
if (!user) return res.json(fail(1001, 'token_expired'))
const newToken = signUser(user)
return ok({ token: newToken, expires_in: 604800 })
})
}
const newToken = signUser(user)
res.json(ok({ token: newToken, expires_in: 604800 }))
}))
module.exports = register
module.exports = router