feat(自学情况): 按学生加姓名/学号搜索,后端补稳定排序
Some checks failed
Deploy / deploy (push) Has been cancelled

搜索是纯前端过滤(整表本来就一次拉完),和班级筛选可以叠加。

学生查询原来没有 orderBy,前端默认按「已读」升序排之后,同分的一大批
(尤其一堆 0)落回聚合的任意顺序,刷新一次换一个样;按班级、学号兜底。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-17 02:23:01 -06:00
parent 3cc2be77a9
commit f90d01338e
2 changed files with 31 additions and 2 deletions

View File

@@ -123,7 +123,11 @@ adminLearnRoutes.get("/learn-analytics/students", requireTeacher, async (c) => {
schema.user.username,
schema.userProfile.realName,
schema.user.className,
),
)
// 前端默认按「已读」升序排,同分的一大批(尤其一堆 0就落回这里的次序。
// 不给 orderBy 的话那是聚合吐出来的任意顺序,刷一次换一个样 —— 按班级、
// 学号排稳住它。className 为空的推不出班级的ASC 默认排在最后
.orderBy(asc(schema.user.className), asc(schema.user.username)),
db
.select({
userId: schema.exerciseAttempt.userId,

View File

@@ -28,6 +28,8 @@ const type = ref<"python" | "c">("python")
// 3-4 位是具体班级1-2 位当年级前缀(后端 classFilter 分的岔)
const className = ref("")
const tab = ref("students")
// 按学生那张表的姓名/学号搜索,纯前端过滤(整表本来就一次拉完)
const keyword = ref("")
const loading = ref(false)
const students = ref<LearnStudentProgress[]>([])
@@ -48,6 +50,18 @@ const startedCount = computed(
() => students.value.filter((row) => row.readCount > 0).length,
)
// 姓名和学号都已经在手里,不再打接口。学号是纯数字,姓名是中文,
// 一个框同时匹配两列就够了 —— 老师要么记得学号要么记得名字
const filteredStudents = computed(() => {
const value = keyword.value.trim().toLowerCase()
if (!value) return students.value
return students.value.filter(
(row) =>
row.username.toLowerCase().includes(value) ||
(row.realName ?? "").toLowerCase().includes(value),
)
})
const studentColumns = computed<DataTableColumn<LearnStudentProgress>[]>(() => [
{ title: "班级", key: "className", width: 90, sorter: "default" },
{ title: "学号", key: "username", width: 140 },
@@ -300,10 +314,21 @@ onMounted(load)
<n-tabs v-model:value="tab" type="line" animated>
<n-tab-pane name="students" tab="按学生">
<n-flex align="center" style="margin-bottom: 12px">
<n-input
v-model:value="keyword"
placeholder="搜索姓名或学号"
clearable
style="width: 200px"
/>
<n-text v-if="keyword.trim()" depth="3">
找到 {{ filteredStudents.length }}
</n-text>
</n-flex>
<n-data-table
:loading="loading"
:columns="studentColumns"
:data="students"
:data="filteredStudents"
:row-key="(row: LearnStudentProgress) => row.userId"
striped
:pagination="{ pageSize: 20 }"