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
这个提交包含在:
+51
-61
@@ -1,68 +1,58 @@
|
||||
const { one, query, limitClause } = 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 { toMysqlDate } = require('../lib/utils')
|
||||
const treatmentDao = require('../dao/treatment.dao')
|
||||
const bindingDao = require('../dao/binding.dao')
|
||||
const logDao = require('../dao/log.dao')
|
||||
|
||||
function register(router) {
|
||||
const wrap = fn => (req, res, next) => fn(req, res, next).catch(next)
|
||||
|
||||
router.get('/api/v1/treatment/history', async ctx => {
|
||||
const user = await requireUser(ctx)
|
||||
if (!user) return fail(1001, 'invalid_token')
|
||||
const page = Math.max(1, parseInt(ctx.query.page, 10) || 1)
|
||||
const pageSize = Math.min(Math.max(1, parseInt(ctx.query.page_size, 10) || 20), 100)
|
||||
const offset = (page - 1) * pageSize
|
||||
const total = await query('SELECT COUNT(*) AS total FROM treatment_records WHERE user_id = :user_id', { user_id: user.user_id })
|
||||
const records = await query('SELECT * FROM treatment_records WHERE user_id = :user_id ORDER BY created_at DESC' + limitClause(pageSize, offset), { user_id: user.user_id })
|
||||
return ok({ total: total[0].total, page, page_size: pageSize, records })
|
||||
router.get('/treatment/history', requireUser, wrap(async (req, res) => {
|
||||
const page = Math.max(1, parseInt(req.query.page, 10) || 1)
|
||||
const pageSize = Math.min(Math.max(1, parseInt(req.query.page_size, 10) || 20), 100)
|
||||
const offset = (page - 1) * pageSize
|
||||
const { records, total } = await treatmentDao.listByUser(req.user.user_id, { pageSize, offset })
|
||||
res.json(ok({ total, page, page_size: pageSize, records }))
|
||||
}))
|
||||
|
||||
router.post('/treatment/sync', requireUser, wrap(async (req, res) => {
|
||||
const d = req.body || {}
|
||||
if (!d.device_id) return res.json(fail(2001, 'device_id required'))
|
||||
|
||||
const active = await bindingDao.findActiveByUser(req.user.user_id)
|
||||
if (!active || active.device_id !== d.device_id) return res.json(fail(1006, 'device_not_bound'))
|
||||
|
||||
const sessionId = d.session_id || 'SESS' + Date.now()
|
||||
await treatmentDao.create({
|
||||
session_id: sessionId,
|
||||
device_id: d.device_id,
|
||||
user_id: req.user.user_id,
|
||||
start_time: toMysqlDate(d.start_time),
|
||||
end_time: toMysqlDate(d.end_time),
|
||||
regions: Array.isArray(d.regions) ? d.regions.join(',') : String(d.regions || ''),
|
||||
total_duration_ms: parseInt(d.total_duration_ms, 10) || 0,
|
||||
mode: parseInt(d.mode, 10) || 0,
|
||||
avg_pd: Number(d.avg_pd) || 0,
|
||||
battery: d.battery == null ? null : parseInt(d.battery, 10),
|
||||
temperature: d.temperature == null ? null : parseInt(d.temperature, 10),
|
||||
wavelength: d.wavelength == null ? null : parseInt(d.wavelength, 10),
|
||||
brightness: d.brightness == null ? null : parseInt(d.brightness, 10),
|
||||
pd_json: JSON.stringify(d.pd_values || {})
|
||||
})
|
||||
await treatmentDao.updateDevice(
|
||||
d.device_id,
|
||||
d.battery == null ? null : parseInt(d.battery, 10),
|
||||
d.temperature == null ? null : parseInt(d.temperature, 10)
|
||||
)
|
||||
await logDao.write({ user_id: req.user.user_id, action: 'treatment_sync', detail: '同步护理记录: ' + sessionId, ip: req.ip })
|
||||
res.json(ok({ record_id: sessionId }))
|
||||
}))
|
||||
|
||||
router.post('/api/v1/treatment/sync', async ctx => {
|
||||
const user = await requireUser(ctx)
|
||||
if (!user) return fail(1001, 'invalid_token')
|
||||
const d = ctx.body || {}
|
||||
if (!d.device_id) return fail(2001, 'device_id required')
|
||||
const binding = await one('SELECT binding_id FROM bindings WHERE user_id = :user_id AND device_id = :device_id AND bind_status = 1', { user_id: user.user_id, device_id: d.device_id })
|
||||
if (!binding) return fail(1006, 'device_not_bound')
|
||||
const sessionId = d.session_id || 'SESS' + Date.now()
|
||||
await query(
|
||||
`INSERT INTO treatment_records
|
||||
(session_id, device_id, user_id, start_time, end_time, regions, total_duration_ms, mode, avg_pd, battery, temperature, wavelength, brightness, pd_json)
|
||||
VALUES (:session_id, :device_id, :user_id, :start_time, :end_time, :regions, :total_duration_ms, :mode, :avg_pd, :battery, :temperature, :wavelength, :brightness, :pd_json)
|
||||
ON DUPLICATE KEY UPDATE end_time = VALUES(end_time), total_duration_ms = VALUES(total_duration_ms), avg_pd = VALUES(avg_pd), battery = VALUES(battery), temperature = VALUES(temperature), pd_json = VALUES(pd_json)`,
|
||||
{
|
||||
session_id: sessionId,
|
||||
device_id: d.device_id,
|
||||
user_id: user.user_id,
|
||||
start_time: toMysqlDate(d.start_time),
|
||||
end_time: toMysqlDate(d.end_time),
|
||||
regions: Array.isArray(d.regions) ? d.regions.join(',') : String(d.regions || ''),
|
||||
total_duration_ms: parseInt(d.total_duration_ms, 10) || 0,
|
||||
mode: parseInt(d.mode, 10) || 0,
|
||||
avg_pd: Number(d.avg_pd) || 0,
|
||||
battery: d.battery == null ? null : parseInt(d.battery, 10),
|
||||
temperature: d.temperature == null ? null : parseInt(d.temperature, 10),
|
||||
wavelength: d.wavelength == null ? null : parseInt(d.wavelength, 10),
|
||||
brightness: d.brightness == null ? null : parseInt(d.brightness, 10),
|
||||
pd_json: JSON.stringify(d.pd_values || {})
|
||||
}
|
||||
)
|
||||
await query('UPDATE devices SET battery = COALESCE(:battery, battery), temperature = COALESCE(:temperature, temperature), last_online_at = NOW() WHERE device_id = :device_id', {
|
||||
device_id: d.device_id,
|
||||
battery: d.battery == null ? null : parseInt(d.battery, 10),
|
||||
temperature: d.temperature == null ? null : parseInt(d.temperature, 10)
|
||||
})
|
||||
await writeLog({ user_id: user.user_id, action: 'treatment_sync', detail: '同步护理记录: ' + sessionId, ip: ctx.ip })
|
||||
return ok({ record_id: sessionId })
|
||||
})
|
||||
router.get('/treatment/:record_id', requireUser, wrap(async (req, res) => {
|
||||
const record = await treatmentDao.findBySession(req.params.record_id, req.user.user_id)
|
||||
if (!record) return res.json(fail(1005, 'record_not_found'))
|
||||
res.json(ok(record))
|
||||
}))
|
||||
|
||||
router.get('/api/v1/treatment/:record_id', async ctx => {
|
||||
const user = await requireUser(ctx)
|
||||
if (!user) return fail(1001, 'invalid_token')
|
||||
const record = await one('SELECT * FROM treatment_records WHERE session_id = :session_id AND user_id = :user_id', { session_id: ctx.params.record_id, user_id: user.user_id })
|
||||
if (!record) return fail(1005, 'record_not_found')
|
||||
return ok(record)
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = register
|
||||
module.exports = router
|
||||
|
||||
在新工单中引用
屏蔽一个用户