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 行删除
+39 -46
查看文件
@@ -1,52 +1,45 @@
const { query } = require('../lib/db')
const router = require('express').Router()
const { ok, fail } = require('../lib/response')
const { requireUser } = require('../lib/auth')
const { writeLog } = require('../lib/log')
const { requireUser } = require('../middleware/auth')
const { getPhoneNumber } = require('../lib/wechat')
const userDao = require('../dao/user.dao')
const deviceDao = require('../dao/device.dao')
const logDao = require('../dao/log.dao')
function register(router) {
router.get('/api/v1/user/profile', async ctx => {
const user = await requireUser(ctx)
if (!user) return fail(1001, 'invalid_token')
const binds = await query('SELECT COUNT(*) AS total FROM bindings WHERE user_id = :user_id AND bind_status = 1', { user_id: user.user_id })
return ok({
user_id: String(user.user_id),
nickname: user.nickname || '用户' + String(user.user_id),
avatar: user.avatar || '',
phone: user.phone || '',
gender: user.gender || 0,
bind_time: null,
device_count: binds[0].total
})
const wrap = fn => (req, res, next) => fn(req, res, next).catch(next)
router.get('/user/profile', requireUser, wrap(async (req, res) => {
const user = req.user
const devices = await deviceDao.listByUser(user.user_id)
res.json(ok({
user_id: String(user.user_id),
nickname: user.nickname || '用户' + String(user.user_id),
avatar: user.avatar || '',
phone: user.phone || '',
gender: user.gender || 0,
bind_time: null,
device_count: devices.length
}))
}))
router.put('/user/profile', requireUser, wrap(async (req, res) => {
await userDao.updateProfile(req.user.user_id, {
nickname: req.body.nickname || null,
avatar: req.body.avatar || req.body.avatar_url || null,
gender: req.body.gender === undefined ? null : req.body.gender
})
await logDao.write({ user_id: req.user.user_id, action: 'user_update', detail: '更新用户资料', ip: req.ip })
res.json(ok({ message: 'success' }))
}))
router.put('/api/v1/user/profile', async ctx => {
const user = await requireUser(ctx)
if (!user) return fail(1001, 'invalid_token')
await query('UPDATE users SET nickname = COALESCE(:nickname, nickname), avatar = COALESCE(:avatar, avatar), gender = COALESCE(:gender, gender) WHERE user_id = :user_id', {
user_id: user.user_id,
nickname: ctx.body.nickname || null,
avatar: ctx.body.avatar || ctx.body.avatar_url || null,
gender: ctx.body.gender === undefined ? null : ctx.body.gender
})
await writeLog({ user_id: user.user_id, action: 'user_update', detail: '更新用户资料', ip: ctx.ip })
return ok({ message: 'success' })
})
router.post('/user/phone', requireUser, wrap(async (req, res) => {
const code = String(req.body.code || '').trim()
if (!code) return res.json(fail(2001, 'phone code required'))
const phoneInfo = await getPhoneNumber(code)
if (!phoneInfo || !phoneInfo.phoneNumber) return res.json(fail(2001, 'phone authorization failed'))
await userDao.updatePhone(req.user.user_id, phoneInfo.phoneNumber)
await logDao.write({ user_id: req.user.user_id, action: 'user_phone_bind', detail: '授权手机号', ip: req.ip })
res.json(ok({ phone: phoneInfo.phoneNumber, pure_phone_number: phoneInfo.purePhoneNumber || '', country_code: phoneInfo.countryCode || '' }))
}))
router.post('/api/v1/user/phone', async ctx => {
const user = await requireUser(ctx)
if (!user) return fail(1001, 'invalid_token')
const code = String(ctx.body.code || '').trim()
if (!code) return fail(2001, 'phone code required')
const phoneInfo = await getPhoneNumber(code)
if (!phoneInfo || !phoneInfo.phoneNumber) return fail(2001, 'phone authorization failed')
await query('UPDATE users SET phone = :phone WHERE user_id = :user_id', {
user_id: user.user_id,
phone: phoneInfo.phoneNumber
})
await writeLog({ user_id: user.user_id, action: 'user_phone_bind', detail: '授权手机号', ip: ctx.ip })
return ok({ phone: phoneInfo.phoneNumber, pure_phone_number: phoneInfo.purePhoneNumber || '', country_code: phoneInfo.countryCode || '' })
})
}
module.exports = register
module.exports = router