From 2a8610b8da750e3aefd9c34c52bb72da630eb947 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Mon, 3 Aug 2026 14:09:20 +0800 Subject: [PATCH] docs: plan student home new module dashboard --- .../2026-08-03-student-home-new-modules.md | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 docs/superpowers/plans/2026-08-03-student-home-new-modules.md diff --git a/docs/superpowers/plans/2026-08-03-student-home-new-modules.md b/docs/superpowers/plans/2026-08-03-student-home-new-modules.md new file mode 100644 index 0000000..36fe1f2 --- /dev/null +++ b/docs/superpowers/plans/2026-08-03-student-home-new-modules.md @@ -0,0 +1,160 @@ +# 学生首页新版实训模块展示 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:** Replace every student-home module display with the current training-report modules and remove the legacy five-module dashboard. + +**Architecture:** `src/views/student/index.vue` will request `GET /api/student/experiment-report/current` and derive the score chart, score table, and task-progress chart from its participating modules. The legacy study-time request remains only to show one aggregate effective-learning-time number; it supplies no module names, chart slices, or module rows. + +**Tech Stack:** Vue 3 Composition API, Element Plus, ECharts 5, existing Axios request wrapper, Node `assert` static checks, Vite 3. + +## Global Constraints + +- The homepage must show only: 互联网产品开发基础认知、市场洞察与需求分析、产品规划与设计、产品开发与测试验证、产品上线与运营推广,以及已发布时的综合实训。 +- `综合实训` is rendered only when the report module has `participating !== false`. +- No homepage component may call `getStuWeightScore`, `getRouters`, or use the old five-module field names for module-level display. +- Score, score share, and completion progress must derive from the same `getCurrentExperimentReport()` response. +- Preserve effective learning time only as a single aggregate number; do not map legacy time fields to new modules. + +--- + +## File Structure + +- `src/views/student/index.vue` — student-home dashboard; replaces hard-coded old modules with report-driven score and progress views. +- `tests/student-home-new-modules.static.test.cjs` — guards the report-data contract and prevents reintroduction of the old module dashboard. + +### Task 1: Report-driven student-home dashboard + +**Files:** +- Modify: `src/views/student/index.vue` +- Create: `tests/student-home-new-modules.static.test.cjs` + +**Interfaces:** +- Consumes: `getCurrentExperimentReport(): Promise<{ data: { totalScore: number, modules: Array<{ moduleName: string, weight: number, score: number, participating: boolean, completedTaskCount: number, totalTaskCount: number }> } }>` from `src/api/index.js`. +- Consumes: `getStudyTime({ userId }): Promise<{ data: Record }>` only to calculate a single aggregate duration. +- Produces: `participatingModules`, a computed list used by both ECharts options and the score/progress tables. + +- [ ] **Step 1: Write the failing static contract test** + +Create `tests/student-home-new-modules.static.test.cjs` with the following checks: + +```js +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); + +const root = path.resolve(__dirname, '..'); +const page = fs.readFileSync(path.join(root, 'src/views/student/index.vue'), 'utf8'); + +assert(/getCurrentExperimentReport/.test(page)); +assert(/participatingModules/.test(page)); +assert(/completedTaskCount/.test(page)); +assert(/totalTaskCount/.test(page)); +assert(/moduleName/.test(page)); +assert(!/getStuWeightScore\(/.test(page)); +assert(!/getRouters\(/.test(page)); +assert(!/市场需求挖掘|产品投放测试|供应渠道管理|产品评估与考核/.test(page)); + +console.log('student home new module static checks passed'); +``` + +- [ ] **Step 2: Run the test to verify it fails** + +Run: `node tests/student-home-new-modules.static.test.cjs` + +Expected: failure because `src/views/student/index.vue` still uses `getStuWeightScore`, `getRouters`, and hard-coded old module labels. + +- [ ] **Step 3: Replace the hard-coded dashboard with report data** + +In `src/views/student/index.vue`: + +```js +const report = ref({ totalScore: 0, modules: [] }); +const loading = ref(true); +const loadError = ref(''); +const participatingModules = computed(() => + (report.value.modules || []).filter((module) => module.participating !== false) +); +const totalTime = computed(() => + Object.values(studyTime.value || {}).reduce((total, value) => total + (Number(value) || 0), 0) +); +``` + +Replace the score pie data with: + +```js +data: participatingModules.value.map((module, index) => ({ + name: module.moduleName, + value: Number(module.score) || 0, + itemStyle: { color: MODULE_COLORS[index % MODULE_COLORS.length] } +})) +``` + +Render the score table with `v-for` rows from `participatingModules`, showing `moduleName`, `weight * 100`, `score`, and `completedTaskCount / totalTaskCount`. Replace the second legacy “我的成绩” card with “实训进度概览”: an ECharts bar chart whose series are `completedTaskCount` and remaining task count, plus a compact module-progress list. Keep the effective-learning-time card but remove the legacy doughnut chart and old five-row time list. + +Load dashboard data through `getCurrentExperimentReport()` and `getStudyTime({ userId })`. On report failure, set `loadError` and render an `el-alert`; do not create old-module fallback rows. Create ECharts instances once, resize them through one lifecycle-managed listener, and dispose both in `onBeforeUnmount`. + +- [ ] **Step 4: Run the static contract test to verify it passes** + +Run: `node tests/student-home-new-modules.static.test.cjs` + +Expected: `student home new module static checks passed`. + +- [ ] **Step 5: Commit the dashboard change** + +```bash +git add src/views/student/index.vue tests/student-home-new-modules.static.test.cjs +git commit -m "feat: show new training modules on student home" +``` + +### Task 2: Build and visual verification + +**Files:** +- Verify: `src/views/student/index.vue` +- Verify: `tests/student-home-new-modules.static.test.cjs` + +**Interfaces:** +- Consumes: Task 1’s report-driven dashboard and static contract test. +- Produces: a production Vite bundle that contains no old-module dashboard source. + +- [ ] **Step 1: Run all relevant static checks** + +Run: + +```bash +node tests/student-home-new-modules.static.test.cjs +node tests/student-experiment-report.static.test.cjs +``` + +Expected: both commands exit with status 0. + +- [ ] **Step 2: Build the frontend production bundle** + +Run: `npm run build:prod` + +Expected: Vite completes successfully. Existing warnings about `::v-deep`, `top1.png`, or large chunks may be recorded but must not become build errors. + +- [ ] **Step 3: Verify the rendered student homepage** + +Run the local frontend and, with an authenticated student whose class has published comprehensive training, verify: + +```text +成绩饼图、成绩表、实训进度概览都显示六个新版模块; +综合实训未发布时只显示前五个新版模块; +页面上不存在旧五模块名称或旧模块时间占比图。 +``` + +- [ ] **Step 4: Commit verification-only changes if any** + +If Step 1–3 created no source changes, do not create an empty commit. If a source correction was needed, add only that correction and commit it with: + +```bash +git add src/views/student/index.vue tests/student-home-new-modules.static.test.cjs +git commit -m "fix: complete student home module dashboard" +``` + +## Self-Review + +- Spec coverage: Task 1 replaces the legacy five-module score and time dashboard, filters unpublished comprehensive training, uses one report response for all module-level cards, retains only aggregate study time, and adds explicit load-error handling. Task 2 validates the contract, build, and both comprehensive-training visibility states. +- Placeholder scan: no deferred implementation markers or unspecified test steps remain. +- Type consistency: `participatingModules` is the shared source for score and progress visualizations; all module fields match `StudentExperimentReportModuleDTO`.