| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- // 一次性脚本:修复 42792 的 MiaoguoTask 重复记录/DayNumber,并只读扫描最近一个月相似问题用户。
- // 仅对 42792 做写操作;其余用户只做只读统计。
- import Miaoguo from '../src/model/miaoguo.js';
- import constantClass from '../src/util/constant/index.js';
- import { stringUtils } from '../src/util/stringClass.js';
- async function fixUser(userID) {
- const tasks = await Miaoguo.RunSql([userID],
- "SELECT * FROM MiaoguoTask where CardTask>0 and UserID=? order by CreateTime, ID desc;");
- if (!tasks || tasks.length === 0) {
- console.log(`User ${userID}: 无记录`);
- return;
- }
- // 每天只保留“最完整”的一条:优先 IsShare>0 / 有里程碑 / 有格言,其次最新 ID
- const dayBest = new Map();
- const score = (x) => (x.IsShare > 0 ? 4 : 0) + (x.MilestoneDayNumber > 0 ? 2 : 0) + (x.AphorismID > 0 ? 1 : 0);
- for (const t of tasks) {
- const best = dayBest.get(t.CreateTime);
- if (!best) dayBest.set(t.CreateTime, t);
- else if (score(t) > score(best) || (score(t) === score(best) && t.ID > best.ID))
- dayBest.set(t.CreateTime, t);
- }
- let deleted = 0;
- for (const t of tasks) {
- if (dayBest.get(t.CreateTime).ID !== t.ID) {
- await Miaoguo.RunSql([t.ID], "delete from MiaoguoTask where ID=?;");
- deleted++;
- }
- }
- const dayTasks = [...dayBest.values()].sort((a, b) =>
- a.CreateTime < b.CreateTime ? -1 : a.CreateTime > b.CreateTime ? 1 : a.ID - b.ID);
- const milestone = constantClass.GetMilestone();
- let milestoneIDs = [];
- for (let i = 0; i < 40; i++) milestoneIDs.push(i + 1);
- milestoneIDs = stringUtils.RandomArray(milestoneIDs);
- let milestoneIndex = 0, hardworkingIndex = 0;
- for (let i = 0; i < dayTasks.length; i++) {
- const t = dayTasks[i];
- const update = { ID: t.ID, DayNumber: i + 1 };
- const milestoneItem = milestone.find(item => item.DayNumber == i + 1);
- if (milestoneItem) {
- update.MilestoneDayNumber = milestoneItem.DayNumber;
- update.MilestoneID = milestoneIDs[milestoneIndex++];
- }
- if (t.IsShare > 0 || update.MilestoneDayNumber > 0 || t.AphorismID > 0)
- update.HardworkingNumber = ++hardworkingIndex;
- await Miaoguo.UpdateMiaoguoTask(update);
- }
- console.log(`User ${userID}: 删除重复行 ${deleted} 条,重编号 ${dayTasks.length} 天(DayNumber 1..${dayTasks.length})`);
- }
- async function scanRecent() {
- // 信号1:最近一个月存在“同一天多条(MiaoguoTask)记录”的用户(根因)
- const dupDays = await Miaoguo.RunSql([], `
- SELECT UserID, DATE(CreateTime) as d, COUNT(*) as cnt
- FROM MiaoguoTask
- WHERE CardTask>0 AND CreateTime >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
- GROUP BY UserID, DATE(CreateTime)
- HAVING cnt > 1
- ORDER BY UserID, d;`);
- const byUser = {};
- for (const r of dupDays) byUser[r.UserID] = (byUser[r.UserID] || 0) + 1;
- // 信号2:最近一个月 DayNumber 最大值 > 实际不同天数(说明历史上按行编号被撑大,存在断号风险)
- const inflated = await Miaoguo.RunSql([], `
- SELECT UserID,
- COUNT(DISTINCT DATE(CreateTime)) as distinctDays,
- MAX(DayNumber) as maxDayNumber
- FROM MiaoguoTask
- WHERE CardTask>0 AND CreateTime >= DATE_SUB(CURDATE(), INTERVAL 30 DAY)
- GROUP BY UserID
- HAVING maxDayNumber > distinctDays;`);
- const inflatedUsers = inflated.map(r => r.UserID);
- console.log('\n===== 扫描结果(最近一个月)=====');
- console.log('信号1 - 有“同一天多条记录”的用户数:', Object.keys(byUser).length);
- console.log('信号1 - 明细(用户ID: 重复天数):', byUser);
- console.log('\n信号2 - DayNumber>实际天数(历史膨胀)的用户数:', inflatedUsers.length);
- console.log('信号2 - 用户列表:', inflatedUsers);
- const allAffected = new Set([...Object.keys(byUser), ...inflatedUsers]);
- console.log('\n合计受影响用户数(任一信号):', allAffected.size);
- console.log('合计用户ID:', [...allAffected].map(Number).sort((a, b) => a - b));
- }
- await fixUser(42792);
- await scanRecent();
- process.exit(0);
|