You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
dianshang-qianduan/docs/superpowers/plans/2026-07-30-score-reference-...

8.7 KiB

成绩中心参考成绩与实训进度 Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 在教师端成绩中心展示不参与评分的参考成绩和基于教学班任务分配的实训进度。

Architecture: 后端在查询和导出学生排名记录后,按教学班可用任务及学生已提交模块对每条记录补充进度;不修改 stu_rankstu_grade 或权限规则。前端仅消费新增的只读进度字段,并将原成绩展示名称调整为参考成绩。

Tech Stack: Spring Boot、MyBatis、JUnit 5/Mockito、Vue 3、Element Plus、Vite。

Global Constraints

  • score 仍是现有排名和计算的输入,本功能只能修改其展示名称。
  • 分母使用当前教学班可访问且未禁用的任务;班级没有任务时显示 --
  • 已完成数按任务模块去重,且只能计入该班已分配模块。
  • 不新增数据库字段或迁移脚本,不改变教师、学校管理员、学生的权限判断。

Task 1: 为成绩列表和导出补充实训进度

Files:

  • Modify: E:/workspace/dianshang/link_commerce/.worktrees/optional-administrative-class/src/main/java/com/sztzjy/linkCommerce/entity/StuRank.java
  • Modify: E:/workspace/dianshang/link_commerce/.worktrees/optional-administrative-class/src/main/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreController.java
  • Create: E:/workspace/dianshang/link_commerce/.worktrees/optional-administrative-class/src/test/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreControllerProgressTest.java

Interfaces:

  • Consumes: TaskAllocationMapper.selectByExample(TaskAllocationExample)StuGradeMapper.selectByExample(StuGradeExample)StuRankMapper.selectByExample(StuRankExample)

  • Produces: StuRank.trainingProgressBigDecimal,范围 0100 或 null)、completedTaskCountInteger)、totalTaskCountInteger),由 selectStuRankAndScoreexportStuScore 一致返回/导出。

  • Step 1: Write the failing backend tests

Create TeaScoreControllerProgressTest with a mocked class task list containing active 任务A、active 任务B 和 disabled 任务C,以及同一学生的 two duplicate 任务A 成绩记录和 one 任务C 成绩记录. Assert the returned StuRank has completedTaskCount == 1, totalTaskCount == 2, and trainingProgress == new BigDecimal("50.00"). Add a second test with an empty class task list and an empty default task list that asserts trainingProgress == null and totalTaskCount == 0.

assertEquals(1, row.getCompletedTaskCount());
assertEquals(2, row.getTotalTaskCount());
assertEquals(new BigDecimal("50.00"), row.getTrainingProgress());
assertNull(rowWithoutTasks.getTrainingProgress());
  • Step 2: Run the backend test to verify it fails

Run: mvn -q -Dtest=TeaScoreControllerProgressTest test

Expected: compilation failure because StuRank does not yet expose the progress fields.

  • Step 3: Implement the minimal progress enrichment

Add trainingProgress, completedTaskCount, and totalTaskCount fields with getters/setters to StuRank; they remain transient API/export values and are not added to any mapper XML. Inject TaskAllocationMapper into TeaScoreController. Add a private enrichTrainingProgress(List<StuRank> ranks, String requestedClassId) method that resolves each row's class as requestedClassId when supplied, otherwise rank.getSchoolClassId(); uses that class's task allocations, falls back to 999999999 only when the class list is empty, ignores disabledStatus == 1, and counts distinct StuGrade.module values for the same student/class that belong to the active task-module set. Set trainingProgress to null when the active set is empty; otherwise use completed * 100 / total rounded to two decimal places.

Call this helper immediately after both rank-list mapper reads. Change export headers and properties to:

String[] headers = {"学号", "学生姓名", "班级名称", "排名", "参考成绩", "实训进度"};
List<String> listColumn = Arrays.asList("username", "name", "className", "stuRank", "score", "trainingProgress");
  • Step 4: Run the backend tests to verify they pass

Run: mvn -q -Dtest=TeaScoreControllerProgressTest,TeaScoreControllerTeachingClassTest test

Expected: both progress edge cases and existing teaching-class member filtering pass.

  • Step 5: Commit backend changes
git -C E:/workspace/dianshang/link_commerce/.worktrees/optional-administrative-class add src/main/java/com/sztzjy/linkCommerce/entity/StuRank.java src/main/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreController.java src/test/java/com/sztzjy/linkCommerce/controller/stu/TeaScoreControllerProgressTest.java
git -C E:/workspace/dianshang/link_commerce/.worktrees/optional-administrative-class commit -m "feat: add training progress to score center"

Task 2: 在教师端展示参考成绩和实训进度

Files:

  • Modify: src/views/teacherEnd/score/index.vue:45-65
  • Create: tests/score-reference-progress.static.test.cjs

Interfaces:

  • Consumes: getScoreList 返回的每行 scoretrainingProgresscompletedTaskCounttotalTaskCount

  • Produces: 主表“参考成绩”和“实训进度”列;进度为 --0% 或两位小数百分比,提示已完成/总任务数。

  • Step 1: Write the failing frontend regression test

Create tests/score-reference-progress.static.test.cjs that loads src/views/teacherEnd/score/index.vue and asserts it defines formatTrainingProgress, renders label="参考成绩" with prop="score", renders label="实训进度", and renders the -- fallback for null progress.

assert.match(source, /label="参考成绩"\s+prop="score"/);
assert.match(source, /label="实训进度"/);
assert.match(source, /formatTrainingProgress/);
assert.match(source, /return "--"/);
  • Step 2: Run the frontend test to verify it fails

Run: node tests/score-reference-progress.static.test.cjs

Expected: assertion failure because the page still labels score as “实训成绩” and has no formatter.

  • Step 3: Implement the display-only table changes

In src/views/teacherEnd/score/index.vue, replace the 实训成绩 table-column label with 参考成绩. Insert an 实训进度 column after it whose cell invokes formatTrainingProgress(row). Add:

const formatTrainingProgress = (row) => {
  if (row.trainingProgress === null || row.trainingProgress === undefined) return "--";
  const percentage = Number(row.trainingProgress);
  if (!Number.isFinite(percentage)) return "--";
  return `${percentage.toFixed(2).replace(/\.00$/, "")}%`;
};

Render 已完成 ${row.completedTaskCount}/${row.totalTaskCount} 项 as the column tooltip/title when trainingProgress is present. Do not add a form control, request parameter, or ranking calculation to the frontend.

  • Step 4: Run the frontend checks to verify they pass

Run: node tests/score-reference-progress.static.test.cjs && npm run build:prod

Expected: regression assertions pass and Vite production build completes with exit code 0.

  • Step 5: Commit frontend changes
git add src/views/teacherEnd/score/index.vue tests/score-reference-progress.static.test.cjs
git commit -m "feat: show reference score and training progress"

Task 3: End-to-end verification and development-service refresh

Files:

  • Verify only: backend and frontend files changed in Tasks 12.

Interfaces:

  • Consumes: the score-center API output and teacher score table changes.

  • Produces: a verified local backend/frontend service without uncommitted changes.

  • Step 1: Run complete backend verification

Run: mvn -q -DforkCount=0 test

Expected: all backend unit tests pass, including TeaScoreControllerProgressTest.

  • Step 2: Run relevant frontend regressions and inspect the worktree

Run: node tests/score-reference-progress.static.test.cjs && node tests/school-product-config.static.test.cjs && git diff --check && git status --short

Expected: both tests pass, diff check prints no errors, and frontend worktree is clean.

  • Step 3: Refresh and probe local services

Restart only the backend if it changed, restart the Vite server at 127.0.0.1:147, then request http://127.0.0.1:147/index.html and the backend root endpoint. Expect HTTP 200 from both.

  • Step 4: Report the fixed data contract

State that the list and Excel export call the existing score field “参考成绩”, progress is read-only, -- means no enabled task, and historical scoring/ranking and permission behavior remain unchanged.