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.

302 lines
12 KiB
Markdown

# Class Management V1 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:** Implement the first working slice of the merged class-management requirements: administrative/teaching class types, school-wide class-name uniqueness, teaching-class membership, dependency-safe deletes, and teaching-class data initialization entry points.
**Architecture:** Keep the existing `UserController` endpoints compatible while adding small focused model objects and mapper methods. `school_class` remains the class master table and gains type/source fields; a new `teaching_class_student` table records many-to-many student membership/history for teaching classes. Frontend class management remains under the teacher end but is split into administrative and teaching tabs.
**Tech Stack:** Spring Boot, MyBatis XML mappers, JUnit 5 + Mockito, Vue 3, Element Plus, Vite.
---
## File Structure
- Backend SQL:
- Create `docs/sql/2026-06-23-class-management-v1.sql` with new columns and new mapping tables.
- Backend model:
- Modify `src/main/java/com/sztzjy/linkCommerce/entity/SchoolClass.java` for `classType`, `dataSource`, and `sourceClassIds`.
- Modify `src/main/java/com/sztzjy/linkCommerce/entity/SchoolClassExample.java` for class-type criteria.
- Create `src/main/java/com/sztzjy/linkCommerce/entity/TeachingClassStudent.java`.
- Create `src/main/java/com/sztzjy/linkCommerce/entity/ExternalResourceMapping.java`.
- Backend mapper:
- Modify `src/main/java/com/sztzjy/linkCommerce/mapper/SchoolClassMapper.java` and `src/main/resources/mappers/SchoolClassMapper.xml`.
- Create `src/main/java/com/sztzjy/linkCommerce/mapper/TeachingClassStudentMapper.java`.
- Create `src/main/resources/mappers/TeachingClassStudentMapper.xml`.
- Create `src/main/java/com/sztzjy/linkCommerce/mapper/ExternalResourceMappingMapper.java`.
- Create `src/main/resources/mappers/ExternalResourceMappingMapper.xml`.
- Backend service/controller:
- Modify `src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java` for type-aware create/update/delete/list and initialization endpoints.
- Reuse existing `/api/cptf/restartTrainingByAll` for current class initialization, and add user/controller endpoints that explicitly check teaching-class ownership before calling it in frontend.
- Backend tests:
- Modify `src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java`.
- Create `src/test/java/com/sztzjy/linkCommerce/entity/TeachingClassStudentModelTest.java`.
- Frontend API:
- Modify `E:/workspace/dianshang/e-commerce-internet/src/api/teacher.js`.
- Frontend views:
- Modify `E:/workspace/dianshang/e-commerce-internet/src/views/teacherEnd/class/index.vue`.
- Modify `E:/workspace/dianshang/e-commerce-internet/src/views/teacherEnd/student/index.vue`.
---
### Task 1: Backend Model And SQL
**Files:**
- Create: `docs/sql/2026-06-23-class-management-v1.sql`
- Modify: `src/main/java/com/sztzjy/linkCommerce/entity/SchoolClass.java`
- Modify: `src/main/resources/mappers/SchoolClassMapper.xml`
- Modify: `src/main/java/com/sztzjy/linkCommerce/entity/SchoolClassExample.java`
- Create: `src/main/java/com/sztzjy/linkCommerce/entity/TeachingClassStudent.java`
- Create: `src/main/java/com/sztzjy/linkCommerce/mapper/TeachingClassStudentMapper.java`
- Create: `src/main/resources/mappers/TeachingClassStudentMapper.xml`
- Create: `src/main/java/com/sztzjy/linkCommerce/entity/ExternalResourceMapping.java`
- Create: `src/main/java/com/sztzjy/linkCommerce/mapper/ExternalResourceMappingMapper.java`
- Create: `src/main/resources/mappers/ExternalResourceMappingMapper.xml`
- Test: `src/test/java/com/sztzjy/linkCommerce/entity/TeachingClassStudentModelTest.java`
- [ ] **Step 1: Write failing model tests**
Add tests asserting `SchoolClass` can store `ADMIN`/`TEACHING` class types and `TeachingClassStudent` stores member status.
Run: `mvn -Dtest=TeachingClassStudentModelTest test`
Expected before implementation: compilation fails because `TeachingClassStudent` does not exist and `SchoolClass#getClassType` does not exist.
- [ ] **Step 2: Implement model fields and mapper XML**
Add:
```java
private String classType;
private String dataSource;
private String sourceClassIds;
```
to `SchoolClass`; map columns `class_type`, `data_source`, and `source_class_ids`.
Create `TeachingClassStudent` with fields:
```java
private String id;
private String teachingClassId;
private String studentUserId;
private String adminClassId;
private String status;
private String joinReason;
private Date joinTime;
private Date exitTime;
private Date createTime;
```
Create mapper methods:
```java
long countByTeachingClassId(String teachingClassId);
long countByStudentUserIdAndTeachingClassId(@Param("studentUserId") String studentUserId, @Param("teachingClassId") String teachingClassId);
int insertSelective(TeachingClassStudent record);
int deleteByTeachingClassId(String teachingClassId);
```
Create `ExternalResourceMapping` and mapper as the reserved foundation for Zhiyun duplicate external account mapping.
- [ ] **Step 3: Run model tests**
Run: `mvn -Dtest=TeachingClassStudentModelTest test`
Expected after implementation: tests pass.
---
### Task 2: Backend Class Rules
**Files:**
- Modify: `src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java`
- Modify: `src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java`
- [ ] **Step 1: Write failing controller tests**
Add tests for:
```java
addSchoolClassRejectsDuplicateNameInSameSchool()
addSchoolClassDefaultsToTeachingClassWhenTeacherCreatesIt()
deleteFacultyRejectsWhenMajorExists()
deleteMajorRejectsWhenClassExists()
deleteClassRejectsWhenStudentsExist()
```
Run: `mvn -Dtest=UserControllerTeacherAdminTest test`
Expected before implementation: duplicate-by-school and dependency-delete tests fail.
- [ ] **Step 2: Implement class uniqueness and class type**
Change `addSchoolClass` to accept optional `classType`; default to `TEACHING` when a teacher creates the class and to `ADMIN` when omitted by platform/admin contexts. Check duplicates by `school_id + class_name`, not by `school_major_id + class_name`.
Change `updateSchoolClass` to reject updates that would duplicate `school_id + class_name` on a different `school_class_id`.
- [ ] **Step 3: Implement dependency delete checks**
Before deleting:
```java
deleteSchoolFaculty -> reject if SchoolMajor exists under faculty
deleteSchoolMajor -> reject if SchoolClass exists under major
deleteSchoolClass -> reject if Userinfo students exist in admin class or TeachingClassStudent members exist in teaching class
```
Expected error messages can be simple Chinese user-facing strings such as `院系下存在专业,不能删除`.
- [ ] **Step 4: Run controller tests**
Run: `mvn -Dtest=UserControllerTeacherAdminTest test`
Expected after implementation: tests pass.
---
### Task 3: Backend Teaching-Class Membership And Initialization
**Files:**
- Modify: `src/main/java/com/sztzjy/linkCommerce/controller/stu/UserController.java`
- Modify: `src/test/java/com/sztzjy/linkCommerce/controller/stu/UserControllerTeacherAdminTest.java`
- [ ] **Step 1: Write failing tests**
Add tests for:
```java
addStudentToTeachingClassCreatesMembershipInsteadOfChangingAdminClass()
teacherCannotInitializeTeachingClassCreatedByAnotherTeacher()
teacherCanInitializeSingleStudentOnlyInOwnedTeachingClass()
```
Run: `mvn -Dtest=UserControllerTeacherAdminTest test`
Expected before implementation: tests fail because membership mapper/initialization endpoints are missing.
- [ ] **Step 2: Add membership creation**
When adding a student to a teaching class, preserve the student `schoolClassId` as the administrative class and insert a `TeachingClassStudent` row linking `student_user_id` to `teaching_class_id`.
For compatibility, keep existing student account creation working for administrative classes.
- [ ] **Step 3: Add initialization endpoints**
Add:
```java
@PostMapping("/initializeTeachingClassTrainingData")
ResultEntity initializeTeachingClassTrainingData(@RequestParam String teachingClassId, @RequestParam String operatorId)
@PostMapping("/initializeTeachingClassStudentTrainingData")
ResultEntity initializeTeachingClassStudentTrainingData(@RequestParam String teachingClassId, @RequestParam String studentUserId, @RequestParam String operatorId)
```
Both endpoints must check that the class is `TEACHING` and owned by `operatorId`. The first initializes all teaching-class members; the second initializes one member. In V1, return success after validation and keep the actual existing training cleanup call delegated to current module endpoints until training-data table ownership is mapped in a follow-up.
- [ ] **Step 4: Run controller tests**
Run: `mvn -Dtest=UserControllerTeacherAdminTest test`
Expected after implementation: tests pass.
---
### Task 4: Frontend Class Tabs And Init Buttons
**Files:**
- Modify: `E:/workspace/dianshang/e-commerce-internet/src/api/teacher.js`
- Modify: `E:/workspace/dianshang/e-commerce-internet/src/views/teacherEnd/class/index.vue`
- [ ] **Step 1: Update API helpers**
Add:
```javascript
export function initializeTeachingClassTrainingData(params) {
return request({ url: "/api/user/initializeTeachingClassTrainingData", method: "POST", params });
}
```
Update class list requests to pass `classType`.
- [ ] **Step 2: Split UI into tabs**
Use `el-tabs` with `ADMIN` and `TEACHING`. Administrative tab hides data initialization. Teaching tab shows edit/delete/member/data-init actions according to ownership.
- [ ] **Step 3: Verify build**
Run: `npm run build:prod`
Expected: build exits 0.
---
### Task 5: Frontend Student Teaching-Class Actions
**Files:**
- Modify: `E:/workspace/dianshang/e-commerce-internet/src/api/teacher.js`
- Modify: `E:/workspace/dianshang/e-commerce-internet/src/views/teacherEnd/student/index.vue`
- [ ] **Step 1: Update API helper**
Add:
```javascript
export function initializeTeachingClassStudentTrainingData(params) {
return request({ url: "/api/user/initializeTeachingClassStudentTrainingData", method: "POST", params });
}
```
- [ ] **Step 2: Scope student initialization to teaching class**
Require a teaching class selection before single-student data initialization. Send `teachingClassId`, `studentUserId`, and `operatorId`.
- [ ] **Step 3: Verify build**
Run: `npm run build:prod`
Expected: build exits 0.
---
### Task 6: Full Verification And Restart
**Files:**
- No new source files unless verification reveals failures.
- [ ] **Step 1: Run backend tests**
Run: `mvn test`
Expected: all tests pass.
- [ ] **Step 2: Run frontend build**
Run: `npm run build:prod`
Expected: build exits 0.
- [ ] **Step 3: Restart services**
Stop listeners on ports `7548` and `147`, then start backend and frontend dev server:
```powershell
cd E:\workspace\dianshang\link_commerce
mvn spring-boot:run -Dspring-boot.run.profiles=dev
cd E:\workspace\dianshang\e-commerce-internet
npm run dev -- --host 0.0.0.0 --port 147
```
Expected: backend listens on `7548`, frontend listens on `147`.
---
## Plan Self-Review
- Spec coverage in V1: class tabs, class type, school-wide class-name uniqueness, delete dependency checks, teaching-class membership foundation, student one-admin-class/many-teaching-class model, initialization entry points, and Zhiyun external mapping foundation.
- Deferred by design: full historical migration of existing student/class data, actual deletion of every training module table during initialization, complete Zhiyun pull/push synchronization policy, and score-center query rewrites across every report. These require a separate implementation plan after V1 lands because they touch many scoring/training modules.
- No placeholder tasks remain in this plan; every task has concrete files, commands, and expected results.