fix_all_broken.mjs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172
  1. // 修复全库所有 DayNumber 异常用户:去重(每天保留最完整一条) + 按天连续重编号。
  2. import moment from 'moment';
  3. import Miaoguo from '../src/model/miaoguo.js';
  4. import constantClass from '../src/util/constant/index.js';
  5. import { stringUtils } from '../src/util/stringClass.js';
  6. const dayKey = (x) => moment(x.CreateTime).format('YYYY-MM-DD');
  7. const score = (x) => (x.IsShare > 0 ? 4 : 0) + (x.MilestoneDayNumber > 0 ? 2 : 0) + (x.AphorismID > 0 ? 1 : 0);
  8. async function fixUser(userID) {
  9. const tasks = await Miaoguo.RunSql([userID],
  10. "SELECT * FROM MiaoguoTask where CardTask>0 and UserID=? order by CreateTime, ID desc;");
  11. if (!tasks || tasks.length === 0) return `User ${userID}: 无记录`;
  12. const dayBest = new Map();
  13. for (const t of tasks) {
  14. const key = dayKey(t);
  15. const best = dayBest.get(key);
  16. if (!best) dayBest.set(key, t);
  17. else if (score(t) > score(best) || (score(t) === score(best) && t.ID > best.ID))
  18. dayBest.set(key, t);
  19. }
  20. let deleted = 0;
  21. for (const t of tasks) {
  22. if (dayBest.get(dayKey(t)).ID !== t.ID) {
  23. await Miaoguo.RunSql([t.ID], "delete from MiaoguoTask where ID=?;");
  24. deleted++;
  25. }
  26. }
  27. const dayTasks = [...dayBest.values()].sort((a, b) =>
  28. a.CreateTime < b.CreateTime ? -1 : a.CreateTime > b.CreateTime ? 1 : a.ID - b.ID);
  29. const milestone = constantClass.GetMilestone();
  30. let milestoneIDs = [];
  31. for (let i = 0; i < 40; i++) milestoneIDs.push(i + 1);
  32. milestoneIDs = stringUtils.RandomArray(milestoneIDs);
  33. let milestoneIndex = 0, hardworkingIndex = 0;
  34. for (let i = 0; i < dayTasks.length; i++) {
  35. const t = dayTasks[i];
  36. const update = { ID: t.ID, DayNumber: i + 1 };
  37. const milestoneItem = milestone.find(item => item.DayNumber == i + 1);
  38. if (milestoneItem) {
  39. update.MilestoneDayNumber = milestoneItem.DayNumber;
  40. update.MilestoneID = milestoneIDs[milestoneIndex++];
  41. }
  42. if (t.IsShare > 0 || update.MilestoneDayNumber > 0 || t.AphorismID > 0)
  43. update.HardworkingNumber = ++hardworkingIndex;
  44. await Miaoguo.UpdateMiaoguoTask(update);
  45. }
  46. return `User ${userID}: 删除重复 ${deleted} 条,重编号 ${dayTasks.length} 天 (1..${dayTasks.length})`;
  47. }
  48. const rows = await Miaoguo.RunSql([], `
  49. SELECT UserID,
  50. COUNT(DISTINCT DATE(CreateTime)) as days,
  51. MAX(DayNumber) as maxDay,
  52. SUM(CASE WHEN DayNumber=0 THEN 1 ELSE 0 END) as zeroCnt
  53. FROM MiaoguoTask
  54. WHERE CardTask>0
  55. GROUP BY UserID
  56. HAVING zeroCnt>0 OR maxDay<>days
  57. ORDER BY UserID;`);
  58. console.log('待修复用户数:', rows.length);
  59. for (const r of rows)
  60. console.log(await fixUser(r.UserID));
  61. console.log('\n全部完成。');
  62. process.exit(0);