feat: 新增运动节拍训练工具套件与子工具页面

新增运动节拍RepClock全套小程序页面、后端API与数据库服务,新增subhub子工具汇总页面,优化全局主页样式与配置,为web静态资源添加版本缓存参数,补充配套调试脚本
This commit is contained in:
yangxiangyuan
2026-09-09 14:43:06 +08:00
parent db7648eb4d
commit d4bf3627fd
69 changed files with 5759 additions and 297 deletions
@@ -0,0 +1,58 @@
const path = require('path')
process.chdir('d:/Trae_Files/TRAE-Toolbox')
const http = require('http')
const db = require(path.join(process.cwd(), 'src/server/mp_rep_clock/db'))
const locks = require(path.join(process.cwd(), 'src/server/mp_rep_clock/locks'))
const store = require(path.join(process.cwd(), 'src/server/mp_rep_clock/kits/rep_clock/store'))
// 清锁先
locks.resetRunningLock()
const nowIso = () => new Date().toISOString()
db.getDb().prepare(`UPDATE rc_sessions SET status='abandoned', ended_at=?, updated_at=?, manual_stopped=1 WHERE status='running' AND deleted=0`).run(nowIso(), nowIso())
const cardId = 'rc_card_c6aebdfb-7330-43c1-b42c-a6a856a715f2'
// 1. 直接 Node 层 reserve + createSession,模拟"第一发start成功"
const s1 = store.createSession({ cardId })
const r1 = locks.reserveRunningLock(s1.id)
console.log('== 1st createSession OK ==')
console.log('session1 id:', s1.id, 'status=', s1.status)
console.log('lock reserve1:', JSON.stringify(r1))
// 2. 再调用一次 createSession(第二发 start 模拟冲突),但不清锁
const s2 = store.createSession({ cardId })
const r2 = locks.reserveRunningLock(s2.id)
console.log('\n== 2nd 故意冲突 ==')
console.log('session2 id:', s2.id)
console.log('lock reserve2:', JSON.stringify(r2))
console.log('字段检查:expiresInMs 存在?', typeof r2.expiresInMs, r2.expiresInMs, '秒=', Math.ceil(r2.expiresInMs/1000))
// 3. 再用 HTTP 调 sessions/start 直接看 409 body(等价于用户 curl)
console.log('\n== 3rd HTTP POST sessions/start ==')
const payload = JSON.stringify({ cardId })
const req = http.request({
hostname: '127.0.0.1', port: 8976,
path: '/api/mp_rep_clock/kits/rep_clock/sessions/start',
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': Buffer.byteLength(payload),
'X-Mp-Timeassistant': 'probe_v1',
}
}, (res) => {
let buf = ''
res.on('data', c => buf += c)
res.on('end', () => {
console.log('HTTP', res.statusCode)
console.log('BODY:', buf)
try {
const j = JSON.parse(buf)
console.log('字段检查 expiresInMs =', j.expiresInMs, '秒=', Math.ceil(j.expiresInMs/1000))
console.log('字段检查 conflictSessionId =', j.conflictSessionId)
console.log('字段检查 expiredLockCleared =', j.expiredLockCleared)
} catch(e){ console.log('not json:', e.message) }
})
})
req.on('error', e => console.log('err', e.message))
req.write(payload)
req.end()