Просмотр исходного кода

fix(admin): keep yearly schedule trend daily

彭峰 1 месяц назад
Родитель
Сommit
c2195a88b7
2 измененных файлов с 4 добавлено и 4 удалено
  1. 3 4
      scripts/deploy-admin-functions.mjs
  2. 1 0
      scripts/smoke-operations-functions.mjs

+ 3 - 4
scripts/deploy-admin-functions.mjs

@@ -2899,11 +2899,10 @@ function addBusinessDays(dateKey,days) { return businessDate(new Date(new Date(d
 function scheduleTrendRange(period,today=businessDate()) { if(!['week','month','year'].includes(period))fail(400,'排课趋势时间维度无效');if(period==='week')return{dateFrom:addBusinessDays(today,-6),dateTo:today,periodLabel:'近 7 天'};if(period==='month')return{dateFrom:today.slice(0,8)+'01',dateTo:today,periodLabel:'本月'};return{dateFrom:today.slice(0,4)+'-01-01',dateTo:today,periodLabel:'本年'}; }
 function scheduleTrendFromSnapshot(snapshot,period,today=businessDate()) {
   const range=scheduleTrendRange(period,today),buckets=[],weekdays=['周日','周一','周二','周三','周四','周五','周六'];
-  if(period==='year'){const year=today.slice(0,4),monthCount=number(today.slice(5,7));for(let month=1;month<=monthCount;month++){const key=year+'-'+String(month).padStart(2,'0');buckets.push({key,label:year+'年'+month+'月',shortLabel:month+'月'});}}
-  else{for(let key=range.dateFrom;key<=range.dateTo;key=addBusinessDays(key,1)){const month=number(key.slice(5,7)),day=number(key.slice(8,10)),weekday=new Date(key+'T12:00:00+08:00').getDay();buckets.push({key,label:month+'月'+day+'日',shortLabel:period==='week'?weekdays[weekday]:day+'日'});}}
+  for(let key=range.dateFrom;key<=range.dateTo;key=addBusinessDays(key,1)){const month=number(key.slice(5,7)),day=number(key.slice(8,10)),weekday=new Date(key+'T12:00:00+08:00').getDay();buckets.push({key,label:month+'月'+day+'日',shortLabel:period==='week'?weekdays[weekday]:period==='year'?month+'/'+day:day+'日'});}
   const byKey=new Map(buckets.map((bucket)=>[bucket.key,{courseCount:0,completedCount:0,students:new Set()}])),allStudents=new Set(),todayStudents=new Set();let todayCourseCount=0;
-  for(const row of snapshot.appointments){if(row.cancelled||!row.startsAt)continue;const date=businessDate(row.startsAt);if(date<range.dateFrom||date>range.dateTo)continue;const key=period==='year'?date.slice(0,7):date,bucket=byKey.get(key);if(!bucket)continue;bucket.courseCount++;if(row.statusCode>=30)bucket.completedCount++;if(row.studentId){bucket.students.add(row.studentId);allStudents.add(row.studentId);}if(date===today){todayCourseCount++;if(row.studentId)todayStudents.add(row.studentId);}}
-  const points=buckets.map((bucket)=>{const value=byKey.get(bucket.key);return{...bucket,courseCount:value.courseCount,studentCount:value.students.size,completedCount:value.completedCount,isToday:period==='year'?bucket.key===today.slice(0,7):bucket.key===today};}),totalCourseCount=points.reduce((sum,point)=>sum+point.courseCount,0),maxValue=Math.max(1,...points.flatMap((point)=>[point.courseCount,point.studentCount]));
+  for(const row of snapshot.appointments){if(row.cancelled||!row.startsAt)continue;const date=businessDate(row.startsAt);if(date<range.dateFrom||date>range.dateTo)continue;const bucket=byKey.get(date);if(!bucket)continue;bucket.courseCount++;if(row.statusCode>=30)bucket.completedCount++;if(row.studentId){bucket.students.add(row.studentId);allStudents.add(row.studentId);}if(date===today){todayCourseCount++;if(row.studentId)todayStudents.add(row.studentId);}}
+  const points=buckets.map((bucket)=>{const value=byKey.get(bucket.key);return{...bucket,courseCount:value.courseCount,studentCount:value.students.size,completedCount:value.completedCount,isToday:bucket.key===today};}),totalCourseCount=points.reduce((sum,point)=>sum+point.courseCount,0),maxValue=Math.max(1,...points.flatMap((point)=>[point.courseCount,point.studentCount]));
   return{period,periodLabel:range.periodLabel,dateFrom:range.dateFrom,dateTo:range.dateTo,points,todayCourseCount,todayStudentCount:todayStudents.size,totalCourseCount,totalStudentCount:allStudents.size,maxValue,refreshedAt:new Date().toISOString(),liveSourceAvailable:snapshot.live.available,liveSourceMessage:snapshot.live.message};
 }
 async function scheduleTrendData(context,input) { const period=text(input.period||'week'),today=businessDate(),range=scheduleTrendRange(period,today),snapshot=await appointmentSnapshot(context,input,range.dateFrom);return scheduleTrendFromSnapshot(snapshot,period,today); }

+ 1 - 0
scripts/smoke-operations-functions.mjs

@@ -44,6 +44,7 @@ try {
   for (const period of ['month', 'year']) {
     const trend = (await ops({ operation: 'ops/dashboard/schedule-trend', period })).data;
     if (trend.period !== period || !trend.points?.length || typeof trend.todayCourseCount !== 'number' || typeof trend.todayStudentCount !== 'number' || !trend.refreshedAt) throw new Error(`${period} 排课趋势返回结构无效`);
+    if (period === 'year' && (trend.points.length <= 12 || trend.points.some((point) => !/^\d{4}-\d{2}-\d{2}$/.test(point.key)))) throw new Error('年趋势没有按天返回数据点');
   }
 
   const users = (await ops({ operation: 'ops/users/list', page: 1, pageSize: 20, search: '' })).data;