|
|
|
|
@ -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<string, number> }>` 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`.
|