feat(卡点分析): 「卡住」原来数的是错过一次的人,做的人多的题全排在前面;改成看一次就对、交几次才对,能按班级和时间段筛
- 卡点按「人 × 题」算:一次就对、做对之前交了几次、还没做对几人,带知识点;一道题给每个人的情况、错在哪、全站历年一次就对 - 年度趋势换成历年概况:学年按 9 月切(原来按自然年),进行中的学年和去年同期并排 - 删掉旧的 /problem-analytics/stuck 全站前 40 和 /ac-trend Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9e23d28f62
commit
b2c802174c
6 files changed
+465
-355
No files matched your search
@@ -95,6 +95,21 @@ export function termStart(now: Date | number | string = new Date()): string {
|
||||
return fromWallClock(new Date(Date.UTC(termYear, termMonth - 1, 1))).toISOString()
|
||||
}
|
||||
|
||||
/**
|
||||
* 学年从哪天零点(东八区)算起:9 月 1 日。返回 `{ year, start }`,`year` 是起始年
|
||||
* (2025 = 25–26 学年),`start` 是 ISO 字符串。SQL 里按学年分组用 `schoolYearOf()`,两边同一个口径。
|
||||
*/
|
||||
export function schoolYearStart(now: Date | number | string = new Date()) {
|
||||
const wall = toWallClock(now)
|
||||
const year = wall.getUTCMonth() + 1 >= 9 ? wall.getUTCFullYear() : wall.getUTCFullYear() - 1
|
||||
return { year, start: schoolYearStartOf(year) }
|
||||
}
|
||||
|
||||
/** 某个学年起始年的 9 月 1 日零点(东八区),ISO 字符串 */
|
||||
export function schoolYearStartOf(year: number): string {
|
||||
return fromWallClock(new Date(Date.UTC(year, 8, 1))).toISOString()
|
||||
}
|
||||
|
||||
/** 按北京时间的日历做月份平移,日号超出目标月长度时截到月末,时分秒毫秒原样保留 */
|
||||
export function shiftMonthsByCalendar(instant: Date, months: number): Date {
|
||||
const wall = toWallClock(instant)
|
||||
@@ -121,3 +136,8 @@ const TIME_ZONE_SQL = sql.raw(`'${TIME_ZONE}'`)
|
||||
export function localTime(column: SQLWrapper) {
|
||||
return sql`(${column} at time zone ${TIME_ZONE_SQL})`
|
||||
}
|
||||
|
||||
/** 时刻所在学年的起始年(9 月起算),和 `schoolYearStart()` 同一个口径 */
|
||||
export function schoolYearOf(column: SQLWrapper) {
|
||||
return sql<number>`extract(year from ${localTime(column)} - interval '8 months')::int`
|
||||
}
|
||||
Reference in new issue
Block a user