| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- // 补齐近两个月:有学习记录(Flag=0)但缺 MiaoguoTask 记录的练习日,并对受影响用户完整重算 DayNumber/里程碑/勤勉号。
- import moment from 'moment';
- import Miaoguo from '../src/model/miaoguo.js';
- import constantClass from '../src/util/constant/index.js';
- import { stringUtils } from '../src/util/stringClass.js';
- const startDate = new Date(Date.now() - 60 * 86400000).toISOString().slice(0, 10);
- const dayKey = (x) => moment(x.CreateTime).format('YYYY-MM-DD');
- const score = (x) => (x.IsShare > 0 ? 4 : 0) + (x.MilestoneDayNumber > 0 ? 2 : 0) + (x.AphorismID > 0 ? 1 : 0);
- // 1) 找出缺失的练习日
- const missing = await Miaoguo.RunSql([startDate], `
- SELECT mc.UserID, DATE_FORMAT(r.CreateTime,'%Y-%m-%d') d,
- COUNT(DISTINCT r.CardID) CardCount, SUM(r.Duration) Duration
- FROM MiaoguoLearningRecord r
- INNER JOIN MiaoguoCard mc ON mc.MiaoguoCardID = r.CardID
- LEFT JOIN MiaoguoTask t ON t.UserID = mc.UserID AND DATE(t.CreateTime) = DATE(r.CreateTime)
- WHERE r.Flag=0 AND r.CreateTime >= ? AND t.ID IS NULL
- GROUP BY mc.UserID, DATE_FORMAT(r.CreateTime,'%Y-%m-%d')
- ORDER BY mc.UserID, d;`);
- console.log('待补齐的练习日:', missing.length, '涉及用户:', [...new Set(missing.map(r => r.UserID))].length);
- if (missing.length === 0) process.exit(0);
- const byUser = new Map();
- for (const r of missing) {
- if (!byUser.has(r.UserID)) byUser.set(r.UserID, []);
- byUser.get(r.UserID).push(r);
- }
- // 2) 插入缺失行(带存在性保护)
- let inserted = 0;
- for (const [userID, days] of byUser) {
- for (const d of days) {
- const createTime = d.d + ' 00:00:00';
- await Miaoguo.RunSql([userID, createTime, d.CardCount, d.Duration, userID, createTime],
- "insert into MiaoguoTask (UserID,CreateTime,CardTask,Duration,IsShare,Flag) " +
- "select ?,?,?,?,0,0 from dual where not exists " +
- "(select UserID,CreateTime from MiaoguoTask where UserID=? and CreateTime=?) limit 1;");
- inserted++;
- }
- console.log(`U${userID}: 补插 ${days.length} 天 ->`, days.map(x => x.d).join(','));
- }
- console.log('补插完成,共', inserted, '天。\n');
- // 3) 对受影响用户完整重算(与夜间重算一致)
- const users = [...byUser.keys()].map(Number);
- const placeholders = users.map(() => '?').join(',');
- await Miaoguo.RunSql(users, `update MiaoguoTask set MilestoneID=0,MilestoneDayNumber=0,HardworkingNumber=0 where UserID in (${placeholders});`);
- const milestone = constantClass.GetMilestone();
- for (const userID of users) {
- const tasks = await Miaoguo.RunSql([userID],
- "SELECT * FROM MiaoguoTask where CardTask>0 and UserID=? order by CreateTime, ID desc;");
- if (!tasks || tasks.length === 0) continue;
- const dayBest = new Map();
- for (const t of tasks) {
- const key = dayKey(t);
- const best = dayBest.get(key);
- if (!best) dayBest.set(key, t);
- else if (score(t) > score(best) || (score(t) === score(best) && t.ID > best.ID))
- dayBest.set(key, t);
- }
- for (const t of tasks) {
- if (dayBest.get(dayKey(t)).ID !== t.ID)
- await Miaoguo.RunSql([t.ID], "delete from MiaoguoTask where ID=?;");
- }
- const dayTasks = [...dayBest.values()].sort((a, b) =>
- a.CreateTime < b.CreateTime ? -1 : a.CreateTime > b.CreateTime ? 1 : a.ID - b.ID);
- 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(`U${userID}: 重算完成,共 ${dayTasks.length} 天 (1..${dayTasks.length})`);
- }
- console.log('\n全部补齐完成。');
- process.exit(0);
|