- 后台课堂任务 admin/lesson → admin/task(/admin/task),和前台 oj/task 对上 - 后台首页 admin/setting/home.vue → admin/home/,设置 → admin/config/ - 卡点分析、年度趋势从 admin/problem 搬到 admin/analytics(/admin/analytics/stuck|trend),和菜单的「学情分析」、后端 analytics.ts 对上 - 首页 dashboard.vue / TeacherHome.vue → student.vue / teacher.vue;自学首页 home.vue → index.vue,看一课 index.vue → tutorial.vue - lesson 只表示课堂上的一节:自学那边改叫 tutorial(oj/learn/lesson.ts → utils.ts、isLessonDone → isTutorialDone、Lesson*.vue → Tutorial*.vue、自学情况的 lessons 字段 → tutorials) - 旧地址不留跳转 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
29c31640b5
commit
48590eee60
37 files changed
+1238
-1236
No files matched your search
@@ -1195,7 +1195,7 @@ export const problemsetBadge = pgTable(
|
||||
* 冲突目标就是 (user_id, tutorial_id),再挂个 id 序列没有任何用处。
|
||||
*
|
||||
* **只记「读到哪一课 + 停留多久」。** 练一练的作答另有一张表(下面的 `exerciseAttempt`),
|
||||
* 一个学生一道练习一行;「学完」由两张表合起来判(契约的 `isLessonDone`)。
|
||||
* 一个学生一道练习一行;「学完」由两张表合起来判(契约的 `isTutorialDone`)。
|
||||
*
|
||||
* 外键这里**用了库级 CASCADE**,和 Django 建的那些 NO ACTION 外键不同:删教程、删用户
|
||||
* 都不必再记得回来手工清一遍子表(后台删教程的事务里就没清它,靠的就是这里)。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import {
|
||||
FLOWCHART_PASS_GRADES,
|
||||
STUDENT_ROLES,
|
||||
isLessonDone,
|
||||
isTutorialDone,
|
||||
type LearnBoard,
|
||||
type LearnBoardStudent,
|
||||
type LearnExerciseAttemptList,
|
||||
@@ -198,7 +198,7 @@ adminLearnRoutes.get('/learn-analytics/board', requireTeacher, async (c) => {
|
||||
students: students.map((student) => {
|
||||
const opened: number[] = []
|
||||
const done: number[] = []
|
||||
const lessons: LearnBoardStudent['lessons'] = []
|
||||
const attempts: LearnBoardStudent['tutorials'] = []
|
||||
let exerciseSolved = 0
|
||||
let totalSeconds = 0
|
||||
let lastViewedAt: string | null = null
|
||||
@@ -210,26 +210,26 @@ adminLearnRoutes.get('/learn-analytics/board', requireTeacher, async (c) => {
|
||||
exerciseSolved += solvedHere
|
||||
if (exercises) {
|
||||
const { tried, solved, wrongAttempts } = exercises
|
||||
lessons.push({ tutorialId: tutorial.id, tried, solved, wrongAttempts })
|
||||
attempts.push({ tutorialId: tutorial.id, tried, solved, wrongAttempts })
|
||||
}
|
||||
if (row) {
|
||||
opened.push(tutorial.id)
|
||||
totalSeconds += row.totalSeconds
|
||||
if (!lastViewedAt || row.lastViewedAt > lastViewedAt) lastViewedAt = row.lastViewedAt
|
||||
}
|
||||
const lesson = {
|
||||
const here = {
|
||||
viewCount: row?.viewCount ?? 0,
|
||||
exerciseTotal: tutorial.exerciseTotal,
|
||||
exerciseSolved: solvedHere,
|
||||
}
|
||||
if (isLessonDone(lesson)) done.push(tutorial.id)
|
||||
if (isTutorialDone(here)) done.push(tutorial.id)
|
||||
}
|
||||
return {
|
||||
...student,
|
||||
opened,
|
||||
done,
|
||||
exerciseSolved,
|
||||
lessons,
|
||||
tutorials: attempts,
|
||||
problems: problemsOf.get(student.userId) ?? [],
|
||||
totalSeconds,
|
||||
lastViewedAt,
|
||||
@@ -394,27 +394,27 @@ adminLearnRoutes.get('/learn-analytics/students/:id', requireTeacher, async (c)
|
||||
).map((row) => [row.problemId, row]),
|
||||
)
|
||||
|
||||
const byLesson = new Map<number, LearnStudentDetail['lessons'][number]['exercises']>()
|
||||
const byTutorial = new Map<number, LearnStudentDetail['tutorials'][number]['exercises']>()
|
||||
for (const { tutorialId, ...row } of exercises) {
|
||||
const list = byLesson.get(tutorialId) ?? []
|
||||
const list = byTutorial.get(tutorialId) ?? []
|
||||
list.push({
|
||||
...row,
|
||||
attempts: row.attempts ?? 0,
|
||||
solved: row.solved ?? false,
|
||||
})
|
||||
byLesson.set(tutorialId, list)
|
||||
byTutorial.set(tutorialId, list)
|
||||
}
|
||||
|
||||
return success(c, {
|
||||
...student,
|
||||
lessons: tutorials
|
||||
tutorials: tutorials
|
||||
.map((row) => ({
|
||||
tutorialId: row.tutorialId,
|
||||
title: row.title,
|
||||
viewCount: row.viewCount ?? 0,
|
||||
totalSeconds: row.totalSeconds ?? 0,
|
||||
lastViewedAt: row.lastViewedAt,
|
||||
exercises: byLesson.get(row.tutorialId) ?? [],
|
||||
exercises: byTutorial.get(row.tutorialId) ?? [],
|
||||
problems: related
|
||||
.filter((problem) => problem.tutorialId === row.tutorialId)
|
||||
.map(({ id: problemId, displayId, title }) => {
|
||||
|
||||
Reference in new issue
Block a user