Files
Toolbox/dev_test_scripts/tools/tool_check_data_integrity.js
T
yangxiangyuan a3e8911deb feat: 新增作息报时器功能并替换短链接前缀为/to/
- 新增作息报时器独立模块,包含完整的日程管理、语音播报和待机功能
- 短链接正式前缀由/l/改为/to/,解决手机小屏下与I、i、1字形混淆问题
- 保留旧前缀/l/、/L/、/I/、/i/兼容已分发的旧短链
- 新增短码大小写兜底匹配,仅唯一匹配时生效避免歧义
- 新增防爆紧急替换功能,可轮换首页鉴权并替换短链接
- 新增多个调试和集成测试脚本,保障数据安全和功能回归
2026-10-09 14:05:36 +08:00

89 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 数据体检工具:确认关键私有数据是否完好、有无测试残留
*
* 由来:2026-09-30 调试脚本曾误删用户真实日程;此后每次涉及数据的操作,
* 都跑一遍本工具确认「用户数据没少、测试垃圾没留」。只读,不修改任何数据。
*
* 运行:node dev_test_scripts/tools/tool_check_data_integrity.js
*/
const path = require('path')
const fs = require('fs')
const Database = require('better-sqlite3')
const dataDir = path.join(process.cwd(), 'data')
let problems = 0
const report = (label, value, ok = true) => {
if (!ok) problems += 1
console.log(` ${ok ? '✔' : '✘'} ${label}: ${value}`)
}
const openReadonly = name => {
const p = path.join(dataDir, name)
if (!fs.existsSync(p)) return null
return new Database(p, { readonly: true })
}
console.log('=== 数据体检(只读) ===\n')
// ---------- 1. 短链接 ----------
console.log('[1] 短链接 data/short_link.db')
const sdb = openReadonly('short_link.db')
if (!sdb) {
console.log(' (数据库不存在,跳过)')
} else {
const links = sdb.prepare('SELECT code, title, click_count, is_active FROM short_links ORDER BY id').all()
const clicks = sdb.prepare('SELECT COUNT(1) AS c FROM short_link_clicks').get().c
console.log(` 共 ${links.length} 条短链接:`)
links.forEach(r => console.log(` [${r.code}] ${r.title || '(无标题)'} clicks=${r.click_count} active=${r.is_active}`))
console.log(` 点击记录总数:${clicks}`)
// 测试残留短码:本工具测过的临时短码统一以 zz 开头
const stray = links.filter(r => String(r.code).startsWith('zz'))
report('测试残留短码(应为 0)', stray.length, stray.length === 0)
if (stray.length) stray.forEach(r => console.log(` → 残留 ${r.code}`))
// 点击记录里的孤立短码(短链已删但点击记录还在)
const codes = links.map(r => r.code)
const clickCodes = sdb.prepare('SELECT DISTINCT code FROM short_link_clicks').all().map(r => r.code)
const orphans = clickCodes.filter(c => codes.indexOf(c) < 0)
report('点击记录中的孤立短码(应为 0)', orphans.length, orphans.length === 0)
if (orphans.length) orphans.forEach(c => console.log(` → 孤立 ${c}`))
sdb.close()
}
// ---------- 2. 作息报时器 ----------
console.log('\n[2] 作息报时器 data/app_order_box_schedule_reminder.db')
const odb = openReadonly('app_order_box_schedule_reminder.db')
if (!odb) {
console.log(' (数据库不存在,跳过)')
} else {
const alive = odb.prepare('SELECT title, items_json FROM schedules WHERE deleted = 0').all()
const softDeleted = odb.prepare('SELECT COUNT(1) AS c FROM schedules WHERE deleted = 1').get().c
console.log(` 未删除的日程 ${alive.length} 套:`)
alive.forEach(r => {
let n = 0
try { n = JSON.parse(r.items_json || '[]').length } catch (_) {}
console.log(` ${r.title}(${n} 个时刻)`)
})
console.log(` 已软删除的历史行:${softDeleted}(这些是测试残留或用户主动删除,不影响使用)`)
const logs = odb.prepare('SELECT COUNT(1) AS c FROM logs').get().c
const testLogs = odb.prepare('SELECT COUNT(1) AS c FROM logs WHERE schedule_title != ?').get('周三在公司').c
console.log(` 播报记录:${logs} 条(非用户日程的:${testLogs})`)
report('用户日程仍存在(至少 1 套)', alive.length, alive.length >= 1)
odb.close()
}
// ---------- 3. 运动提醒宝(框子另一个 kit) ----------
console.log('\n[3] 运动提醒宝 data/app_order_box_motion_reminder.db')
const mdb = openReadonly('app_order_box_motion_reminder.db')
if (!mdb) {
console.log(' (数据库不存在,跳过)')
} else {
const cards = mdb.prepare('SELECT title FROM cards WHERE deleted = 0').all()
console.log(` 未删除的流程卡片 ${cards.length} 张:${cards.map(c => c.title).join(' / ') || '(无)'}`)
mdb.close()
}
console.log(`\n=== 体检完成:${problems === 0 ? '未发现异常' : '发现 ' + problems + ' 处异常'} ===`)
process.exit(problems === 0 ? 0 : 1)