Files
Toolbox/dev_test_scripts/debug/debug_weekly_reminder.js
yangxiangyuan 6a7a2b089a feat: 新增免费演出雷达工具与定投评估功能,优化周报提醒逻辑
1. 新增免费演出雷达工具:含秀动/猫眼/大麦平台抓取、本地代理鉴权配置
2. 新增建行定投评估模块:四大指数PE-TTM估值与定投档位建议
3. 新增推送告警白名单过滤功能,限制推送指定指数告警
4. 重构周报首页提醒逻辑,移至服务端处理并减少前端请求
5. 新增多套调试探针脚本与单元测试用例
2026-08-04 17:33:14 +08:00

100 lines
4.9 KiB
JavaScript
Raw Permalink 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.
// 调试:排查首页「每周周报提醒」的判定依据
// 读取最近 3 周(W30/W31/W32)周报的真实标题/内容,并模拟前端 isWeeklyMeaningfulReport 判定
// 用法:node dev_test_scripts/debug/debug_weekly_reminder.js
const path = require('path')
const fs = require('fs')
const os = require('os')
// 复刻 index.js 的 env 加载逻辑(凭据零硬编码)
const userProfile = process.env.USERPROFILE || process.env.HOME || os.homedir()
const candidates = [path.join(userProfile, 'Toolbox_local_creds.env.local')]
try {
const usersRoot = path.join(path.parse(userProfile).root, 'Users')
if (fs.existsSync(usersRoot)) {
fs.readdirSync(usersRoot).forEach(name => {
const dir = path.join(usersRoot, name)
if (dir !== userProfile && fs.existsSync(dir)) candidates.push(path.join(dir, 'Toolbox_local_creds.env.local'))
})
}
} catch {}
for (const p of candidates) {
if (!fs.existsSync(p)) continue
fs.readFileSync(p, 'utf-8').split(/\r?\n/).forEach(line => {
const t = line.trim()
if (!t || t.startsWith('#')) return
const i = t.indexOf('=')
if (i > 0) {
const k = t.slice(0, i).trim()
const v = t.slice(i + 1).trim()
if (!process.env[k]) process.env[k] = v
}
})
}
process.chdir(path.join(__dirname, '..', '..'))
// 按 weekly.js 的启动顺序初始化
const { initCrypto } = require('../../src/server/weekly_crypto')
const { initDB } = require('../../src/server/weekly_db')
const cfgPath = path.join(process.cwd(), 'config', 'weekly.json')
let machineSalt = 'salt'
try { machineSalt = JSON.parse(fs.readFileSync(cfgPath, 'utf-8')).machine_salt || 'salt' } catch {}
initCrypto(process.env.SYSTEM_AUTH_PASS_93220 || process.env.WEEKLY_PASSWORD || '', machineSalt)
initDB(path.join(process.cwd(), 'data', 'weekly.db'), path.join(process.cwd(), 'data', 'weekly.enc'))
const core = require('../../src/server/weekly_core')
// 与 public/index.js 的 isWeeklyAutoTitle / isWeeklyMeaningfulReport 保持一致
const TEMPLATE_TEXT = '' // 前端 getWeeklyTemplatePlainText 的纯文本,这里只做关键项判断
const isAutoTitle = (title, weekId) => {
const t = String(title || '').trim()
if (!t) return true
if (t.includes('(自动新增)')) return true
if (weekId && t === `${weekId} 周报`) return true
return false
}
const isMeaningful = (report, weekId) => {
if (!report) return { ok: false, reason: '无周报记录' }
const title = String(report.title || '').trim()
const content = String(report.content || '').trim()
if (!title || !content) return { ok: false, reason: '标题或内容为空' }
if (isAutoTitle(title, weekId)) return { ok: false, reason: '标题仍为自动标题(含「自动新增」或等于「<weekId> 周报」)' }
if (content === '这是自动新增的周报。你可以修改。') return { ok: false, reason: '内容仍为自动占位文本' }
return { ok: true, reason: '' }
}
for (const w of ['2026-W30', '2026-W31', '2026-W32']) {
const r = core.getReportByWeek(w)
if (!r) {
console.log(`\n[${w}] 无周报记录 => 提醒判定:缺`)
continue
}
const judge = isMeaningful(r, w)
console.log(`\n[${w}] id=${r.id} updated_at=${r.updated_at}`)
console.log(` 标题: ${JSON.stringify(r.title)}`)
console.log(` 内容前80字: ${JSON.stringify(String(r.content || '').replace(/\s+/g, ' ').slice(0, 80))}`)
console.log(` 内容长度: ${String(r.content || '').length}`)
console.log(` 提醒判定: ${judge.ok ? '已写(不算缺)' : '缺(' + judge.reason + ')'}`)
}
// ---- 追加排查:reports 全表时间线 + W31/W32 下的 events + 相关日志 ----
const { getDB } = require('../../src/server/weekly_db')
const { dec } = require('../../src/server/weekly_crypto')
const db = getDB()
console.log('\n===== reports 时间线(最近 10 条) =====')
db.prepare(`SELECT id, week_id, created_at, updated_at FROM reports ORDER BY id DESC LIMIT 10`).all()
.forEach(r => console.log(` id=${r.id} week=${r.week_id} created=${r.created_at} updated=${r.updated_at}`))
for (const rid of [149, 150]) {
console.log(`\n===== report ${rid} 下的 events =====`)
const evs = db.prepare(`SELECT id, title_enc, title_iv, title_tag, deadline, created_at, updated_at FROM events WHERE report_id=? ORDER BY id`).all(rid)
if (evs.length === 0) console.log(' (无 events)')
evs.forEach(e => console.log(` ev_id=${e.id} title=${JSON.stringify(dec(e.title_enc, e.title_iv, e.title_tag))} deadline=${e.deadline} created=${e.created_at} updated=${e.updated_at}`))
}
console.log('\n===== logs 中 fitness/ext 相关(最近 15 条) =====')
try {
db.prepare(`SELECT action, details, created_at FROM logs WHERE action LIKE '%ext%' OR action LIKE '%fitness%' ORDER BY id DESC LIMIT 15`).all()
.forEach(l => console.log(` ${l.created_at} ${l.action} ${String(l.details || '').slice(0, 120)}`))
} catch (e) { console.log(' logs 查询失败:', e.message) }