2025 秋平均每节课有 14 个平时在用的学生一道都没交(三分之一),交了 3 次以上还没过的 平均不到 1 个;而老师原来只能一道题一道题打开统计弹窗看。 - 新表 class_lesson(迁移 0023,仅建表):一个班一天一行,存老师布置的 problem.id 与顺序; day 存东八区日历日文本,created_by CASCADE - GET /classroom/board:这个班今天的题 × 全班学生(通过与否不限今天、今天交了几次、 最后提交时间);不给班级时猜最近两小时提交人数最多的班,不记老师上次选的 - PUT /classroom/lesson:按展示题号布置,对不上的题号点名拒绝,空数组 = 清掉 - /me/class-activity 优先返回老师布置的题(source = teacher),否则照旧推断 - 前端 /classroom:没交过的名单置顶,按 没交过 → 卡住 → 在做 → 做完 排序,15 秒刷新; 投影模式只显示每题完成人数、不出名字;用户菜单给老师加入口 - 学生首页:老师布置的标题写「今天老师布置的题」,没人交时不显示 0/0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
354 lines
10 KiB
TypeScript
354 lines
10 KiB
TypeScript
import type { RouteRecordRaw } from "vue-router"
|
||
|
||
export const ojs: RouteRecordRaw = {
|
||
path: "/",
|
||
component: () => import("shared/layout/default.vue"),
|
||
children: [
|
||
// 登录后是个人首页,没登录还是题目列表(见 oj/home/index.vue)
|
||
{ path: "", component: () => import("oj/home/index.vue"), name: "home" },
|
||
{ path: "problem", component: () => import("oj/problem/list.vue"), name: "problems" },
|
||
{
|
||
path: "problem/:problemID",
|
||
component: () => import("oj/problem/detail.vue"),
|
||
props: true,
|
||
name: "problem",
|
||
},
|
||
{
|
||
path: "submission",
|
||
component: () => import("oj/submission/list.vue"),
|
||
name: "submissions",
|
||
},
|
||
{
|
||
path: "submission/:submissionID",
|
||
component: () => import("oj/submission/detail.vue"),
|
||
props: true,
|
||
meta: { requiresAuth: true },
|
||
},
|
||
{
|
||
path: "contest",
|
||
component: () => import("oj/contest/list.vue"),
|
||
name: "contests",
|
||
},
|
||
{
|
||
path: "contest/:contestID",
|
||
component: () => import("oj/contest/detail.vue"),
|
||
props: true,
|
||
meta: { requiresAuth: true },
|
||
children: [
|
||
{
|
||
path: "",
|
||
component: () => import("oj/contest/pages/problems.vue"),
|
||
props: true,
|
||
meta: { requiresAuth: true },
|
||
name: "contest problems",
|
||
},
|
||
{
|
||
path: "submission",
|
||
component: () => import("oj/submission/list.vue"),
|
||
meta: { requiresAuth: true },
|
||
name: "contest submissions",
|
||
},
|
||
{
|
||
path: "rank",
|
||
component: () => import("oj/contest/pages/rank.vue"),
|
||
props: true,
|
||
meta: { requiresAuth: true },
|
||
name: "contest rank",
|
||
},
|
||
],
|
||
},
|
||
{
|
||
path: "contest/:contestID/problem/:problemID",
|
||
component: () => import("oj/problem/detail.vue"),
|
||
props: true,
|
||
name: "contest problem",
|
||
meta: { requiresAuth: true },
|
||
},
|
||
{
|
||
path: "rank",
|
||
name: "rank",
|
||
component: () => import("oj/rank/list.vue"),
|
||
},
|
||
{
|
||
path: "classroom",
|
||
name: "classroom board",
|
||
component: () => import("oj/classroom/board.vue"),
|
||
meta: { requiresAuth: true, requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "class",
|
||
name: "class",
|
||
component: () => import("oj/class/pk.vue"),
|
||
},
|
||
{
|
||
path: "announcement",
|
||
name: "announcements",
|
||
component: () => import("oj/announcement/list.vue"),
|
||
},
|
||
{
|
||
path: "user",
|
||
component: () => import("oj/user/index.vue"),
|
||
meta: { requiresAuth: true },
|
||
},
|
||
{
|
||
path: "achievement",
|
||
name: "achievement",
|
||
component: () => import("oj/achievement/index.vue"),
|
||
meta: { requiresAuth: true },
|
||
},
|
||
{
|
||
path: "setting",
|
||
component: () => import("oj/user/setting.vue"),
|
||
meta: { requiresAuth: true },
|
||
},
|
||
{
|
||
path: "message",
|
||
component: () => import("oj/user/message.vue"),
|
||
meta: { requiresAuth: true },
|
||
},
|
||
{
|
||
path: "learn/:type/:step",
|
||
name: "learn",
|
||
component: () => import("oj/learn/index.vue"),
|
||
props: true,
|
||
},
|
||
{
|
||
path: "ai-analysis",
|
||
name: "ai",
|
||
component: () => import("oj/ai/analysis.vue"),
|
||
meta: { requiresAuth: true },
|
||
},
|
||
{
|
||
path: "flowchart",
|
||
name: "flowchart",
|
||
component: () => import("oj/flowchart/index.vue"),
|
||
},
|
||
{
|
||
path: "problemset",
|
||
component: () => import("oj/problemset/list.vue"),
|
||
name: "problemsets",
|
||
},
|
||
{
|
||
path: "problemset/:problemSetId",
|
||
component: () => import("oj/problemset/detail.vue"),
|
||
props: true,
|
||
name: "problemset",
|
||
},
|
||
{
|
||
path: "problemset/:problemSetId/problem/:problemID",
|
||
component: () => import("oj/problem/detail.vue"),
|
||
props: true,
|
||
name: "problemset problem",
|
||
meta: { requiresAuth: true },
|
||
},
|
||
],
|
||
}
|
||
|
||
export const admins: RouteRecordRaw = {
|
||
path: "/admin",
|
||
component: () => import("shared/layout/admin.vue"),
|
||
children: [
|
||
{
|
||
path: "",
|
||
name: "admin home",
|
||
component: () => import("admin/setting/home.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "config",
|
||
name: "admin config",
|
||
component: () => import("admin/setting/config.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "user/list",
|
||
name: "admin user list",
|
||
component: () => import("admin/user/list.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "user/generate",
|
||
name: "admin user generate",
|
||
component: () => import("admin/user/generate.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
// admin和super_admin都可以访问的路由 (需要题目权限)
|
||
{
|
||
path: "problem/list",
|
||
name: "admin problem list",
|
||
component: () => import("admin/problem/list.vue"),
|
||
meta: { requiresProblemPermission: true },
|
||
},
|
||
{
|
||
path: "problem/tags",
|
||
name: "admin tag list",
|
||
component: () => import("admin/problem/tags.vue"),
|
||
meta: { requiresProblemPermission: true },
|
||
},
|
||
{
|
||
path: "problem/create",
|
||
name: "admin problem create",
|
||
component: () => import("admin/problem/detail.vue"),
|
||
meta: { requiresProblemPermission: true },
|
||
},
|
||
{
|
||
path: "problem/edit/:problemID",
|
||
name: "admin problem edit",
|
||
component: () => import("admin/problem/detail.vue"),
|
||
props: true,
|
||
meta: { requiresProblemPermission: true },
|
||
},
|
||
{
|
||
path: "contest/list",
|
||
name: "admin contest list",
|
||
component: () => import("admin/contest/list.vue"),
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "contest/create",
|
||
name: "admin contest create",
|
||
component: () => import("admin/contest/detail.vue"),
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "contest/edit/:contestID",
|
||
name: "admin contest edit",
|
||
component: () => import("admin/contest/detail.vue"),
|
||
props: true,
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "contest/:contestID/problem/list",
|
||
name: "admin contest problem list",
|
||
component: () => import("admin/problem/list.vue"),
|
||
props: true,
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "contest/:contestID/problem/create",
|
||
name: "admin contest problem create",
|
||
component: () => import("admin/problem/detail.vue"),
|
||
props: true,
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "contest/:contestID/problem/edit/:problemID",
|
||
name: "admin contest problem edit",
|
||
component: () => import("admin/problem/detail.vue"),
|
||
props: true,
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "contest/:contestID/helper",
|
||
name: "admin contest helper",
|
||
component: () => import("admin/contest/helper.vue"),
|
||
props: true,
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
// 只有super_admin可以访问的路由
|
||
{
|
||
path: "announcement/list",
|
||
name: "admin announcement list",
|
||
component: () => import("admin/announcement/list.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "announcement/create",
|
||
name: "admin announcement create",
|
||
component: () => import("admin/announcement/detail.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "announcement/edit/:announcementID",
|
||
name: "admin announcement edit",
|
||
component: () => import("admin/announcement/detail.vue"),
|
||
props: true,
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "message/list",
|
||
name: "admin message list",
|
||
component: () => import("admin/communication/messages.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "tutorial/list",
|
||
name: "admin tutorial list",
|
||
component: () => import("admin/tutorial/list.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "tutorial/create",
|
||
name: "admin tutorial create",
|
||
component: () => import("admin/tutorial/detail.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "tutorial/edit/:tutorialID",
|
||
name: "admin tutorial edit",
|
||
component: () => import("admin/tutorial/detail.vue"),
|
||
props: true,
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "problem/stuck",
|
||
name: "admin stuck problems",
|
||
component: () => import("admin/problem/Stuck.vue"),
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "problem/top_ac_trend",
|
||
name: "admin top ac trend",
|
||
component: () => import("admin/problem/TopACTrend.vue"),
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
// 题单管理路由
|
||
{
|
||
path: "problemset/list",
|
||
name: "admin problemset list",
|
||
component: () => import("admin/problemset/list.vue"),
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "achievement/list",
|
||
name: "admin achievement list",
|
||
// 后端 admin 接口是 super_admin_required,这里必须跟着用
|
||
// requiresSuperAdmin,否则教师能进页面但每个请求都 403
|
||
component: () => import("admin/achievement/list.vue"),
|
||
meta: { requiresSuperAdmin: true },
|
||
},
|
||
{
|
||
path: "problemset/create",
|
||
name: "admin problemset create",
|
||
component: () => import("admin/problemset/edit.vue"),
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "problemset/edit/:problemSetId",
|
||
name: "admin problemset edit",
|
||
component: () => import("admin/problemset/edit.vue"),
|
||
props: true,
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "problemset/:problemSetId",
|
||
name: "admin problemset detail",
|
||
component: () => import("admin/problemset/detail.vue"),
|
||
props: true,
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "ai/reports",
|
||
name: "admin ai reports",
|
||
component: () => import("admin/ai/list.vue"),
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
{
|
||
path: "learn",
|
||
name: "admin learn analytics",
|
||
component: () => import("admin/learn/index.vue"),
|
||
meta: { requiresTeacherAdmin: true },
|
||
},
|
||
],
|
||
}
|