|
|
|
@ -0,0 +1,221 @@
|
|
|
|
|
|
|
|
# 产品开发关键因素第 3 步 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:** 为学生端产品开发关键因素实训实现第 3 步商业化及市场反馈分析、服务端校验与只保存进入第 4 步的流程。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Architecture:** 前端在现有 `product-development-factors.vue` 中增加固定三行的第 3 步表格,并把数据独立写入 `step3Answer`。后端按前两步的分层模式新增 DTO、服务及控制器入口,严格验证学生身份、三项固定维度及六个非空分析字段。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Tech Stack:** Vue 3 Composition API、Element Plus、现有 request API;Spring Boot、JUnit 5、Mockito、Maven。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Global Constraints
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- 仅修改学生端页面及学生答案校验接口;不调整教师端或任务配置。
|
|
|
|
|
|
|
|
- 不新增数据库表或字段,使用既有答案记录的 `step3Answer` 与 `currentStep`。
|
|
|
|
|
|
|
|
- 第 3 步保存固定使用 `SAVE`、`submitted: false`、`currentStep: 4`,不得提交任务。
|
|
|
|
|
|
|
|
- 保存前必须通过正式或演示模式的一致校验:三个固定维度、六个分析字段全部非空。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Task 1: 第 3 步后端校验服务
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
|
|
- Create: `src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepThreeValidationRequest.java`
|
|
|
|
|
|
|
|
- Create: `src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepThreeValidationResult.java`
|
|
|
|
|
|
|
|
- Create: `src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepThreeService.java`
|
|
|
|
|
|
|
|
- Create: `src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepThreeServiceImpl.java`
|
|
|
|
|
|
|
|
- Test: `src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepThreeServiceImplTest.java`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
|
|
- Consumes: `JwtUser`、`ServiceException`、Spring HTTP status conventions。
|
|
|
|
|
|
|
|
- Produces: `ProductDevelopmentFactorsStepThreeService#validate(ProductDevelopmentFactorsStepThreeValidationRequest, JwtUser)`,返回 `{ valid, message }`。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: 写失败服务测试**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
@Test void acceptsCompleteStudentAnalyses() {
|
|
|
|
|
|
|
|
assertTrue(new ProductDevelopmentFactorsStepThreeServiceImpl().validate(valid(), student()).isValid());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test void rejectsBlankOrForgedAnalyses() {
|
|
|
|
|
|
|
|
ProductDevelopmentFactorsStepThreeValidationRequest blank = valid();
|
|
|
|
|
|
|
|
blank.getFactors().get(2).setFailedAnalysis(" ");
|
|
|
|
|
|
|
|
assertThrows(ServiceException.class, () -> service.validate(blank, student()));
|
|
|
|
|
|
|
|
ProductDevelopmentFactorsStepThreeValidationRequest forged = valid();
|
|
|
|
|
|
|
|
forged.getFactors().get(2).setDimension("伪造维度");
|
|
|
|
|
|
|
|
assertThrows(ServiceException.class, () -> service.validate(forged, student()));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: 运行测试确认失败**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B -Dtest=ProductDevelopmentFactorsStepThreeServiceImplTest test`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected: FAIL,因为 DTO 和服务尚不存在。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: 实现最小服务**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
private static final Set<String> DIMENSIONS = new LinkedHashSet<>(Arrays.asList(
|
|
|
|
|
|
|
|
"供应链与成本控制", "商业模式", "市场反馈"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (user == null || StringUtils.isBlank(user.getUserId())) throw new ServiceException(HttpStatus.UNAUTHORIZED, "请先登录后再提交");
|
|
|
|
|
|
|
|
if (user.getRoleId() != 4) throw new ServiceException(HttpStatus.FORBIDDEN, "仅学生可提交实训答案");
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
校验 `factors` 数量为 3、每个维度只出现一次且属于 `DIMENSIONS`,并要求每个 `successAnalysis`、`failedAnalysis` 均非空;合法时返回 `valid=true`、`message="校验通过"`。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: 运行服务测试确认通过**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B -Dtest=ProductDevelopmentFactorsStepThreeServiceImplTest test`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected: PASS,覆盖合法、空值、伪造维度和非学生身份。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 5: 提交后端服务**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
git add src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepThreeValidationRequest.java src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepThreeValidationResult.java src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepThreeService.java src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepThreeServiceImpl.java src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepThreeServiceImplTest.java
|
|
|
|
|
|
|
|
git commit -m "feat: validate product factors step three"
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Task 2: 第 3 步校验控制器入口
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
|
|
- Modify: `src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java`
|
|
|
|
|
|
|
|
- Modify: `src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
|
|
- Consumes: Task 1 的 `ProductDevelopmentFactorsStepThreeService`。
|
|
|
|
|
|
|
|
- Produces: `POST /api/student-training-answers/product-development-factors/step-3/validate`。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: 写失败控制器测试**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
@Test void validateProductDevelopmentFactorsStepThreeUsesTheAuthenticatedStudentAndReturnsTheValidationResult() {
|
|
|
|
|
|
|
|
ProductDevelopmentFactorsStepThreeService service = mock(ProductDevelopmentFactorsStepThreeService.class);
|
|
|
|
|
|
|
|
ReflectionTestUtils.setField(controller, "productDevelopmentFactorsStepThreeService", service);
|
|
|
|
|
|
|
|
when(service.validate(any(ProductDevelopmentFactorsStepThreeValidationRequest.class), any(JwtUser.class))).thenReturn(validation);
|
|
|
|
|
|
|
|
ResultEntity<ProductDevelopmentFactorsStepThreeValidationResult> result = controller.validateProductDevelopmentFactorsStepThree(new ProductDevelopmentFactorsStepThreeValidationRequest(), authenticatedStudentRequest());
|
|
|
|
|
|
|
|
assertEquals(HttpStatus.OK, result.getStatusCode());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: 运行测试确认失败**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B -Dtest=StudentTrainingAnswerControllerTest test`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected: FAIL,因为第 3 步服务注入字段和控制器方法尚不存在。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: 增加路由与转发**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
|
|
@PostMapping("/product-development-factors/step-3/validate")
|
|
|
|
|
|
|
|
public ResultEntity<ProductDevelopmentFactorsStepThreeValidationResult> validateProductDevelopmentFactorsStepThree(
|
|
|
|
|
|
|
|
@RequestBody ProductDevelopmentFactorsStepThreeValidationRequest request,
|
|
|
|
|
|
|
|
HttpServletRequest servletRequest) {
|
|
|
|
|
|
|
|
return ResultEntity.ok(productDevelopmentFactorsStepThreeService.validate(request, getJwtUser(servletRequest)));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: 运行控制器测试确认通过**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B -Dtest=StudentTrainingAnswerControllerTest,ProductDevelopmentFactorsStepThreeServiceImplTest test`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected: PASS。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 5: 提交控制器**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
git add src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java
|
|
|
|
|
|
|
|
git commit -m "feat: expose product factors step three validation"
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Task 3: 第 3 步学生页面、草稿和 API
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
|
|
- Modify: `src/views/foundation/product-development-factors.vue`
|
|
|
|
|
|
|
|
- Modify: `src/api/studentTrainingAnswer.js`
|
|
|
|
|
|
|
|
- Modify: `tests/product-development-factors-step-one.static.test.cjs`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
|
|
- Consumes: Task 2 的正式校验 URL、既有 `saveStudentTrainingAnswer`、`getStudentTrainingAnswer`。
|
|
|
|
|
|
|
|
- Produces: 第 3 步固定三行分析页面;`step3Answer`、`currentStep: 4`、`checkProductDevelopmentFactorsStepThree(payload)`。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: 先扩展前端静态契约测试**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
|
|
|
assert.match(pageSource, /STEP_THREE_FACTOR_ROWS/);
|
|
|
|
|
|
|
|
assert.match(pageSource, /供应链与成本控制/);
|
|
|
|
|
|
|
|
assert.match(pageSource, /商业模式/);
|
|
|
|
|
|
|
|
assert.match(pageSource, /市场反馈/);
|
|
|
|
|
|
|
|
assert.match(pageSource, /step3Answer/);
|
|
|
|
|
|
|
|
assert.match(pageSource, /saveAndGoToStepFour/);
|
|
|
|
|
|
|
|
assert.match(apiSource, /product-development-factors\/step-3\/validate/);
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: 运行静态测试确认失败**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Run: `node tests/product-development-factors-step-one.static.test.cjs`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected: FAIL,因为第 3 步常量、保存函数和 API 尚不存在。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: 实现前端最小改动**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在 `currentStep === 2` 增加表格;建立 `STEP_THREE_FACTOR_ROWS`、`createStepThreeRows`、`stepThreeRows`,并扩展草稿、答案恢复、导出与清空。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
|
|
|
function buildStepThreeAnswerPayload(saveAction = "SAVE", persistedStep = 4) {
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
step3Answer: JSON.stringify(buildStepThreeOutcome()),
|
|
|
|
|
|
|
|
currentStep: persistedStep,
|
|
|
|
|
|
|
|
submitted: false,
|
|
|
|
|
|
|
|
saveAction,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
实现正式 API 和演示模式的一致校验;`saveAndGoToStepFour` 成功后清理草稿并在第 4 步存在时将 `currentStep` 设为 `3`,否则显示已保存但未配置第 4 步的提示。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: 运行前端测试与生产构建**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Run: `node tests/product-development-factors-step-one.static.test.cjs; npm run build:prod`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected: 静态契约测试与生产构建均 PASS。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 5: 提交前端改动**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
|
|
git add src/views/foundation/product-development-factors.vue src/api/studentTrainingAnswer.js tests/product-development-factors-step-one.static.test.cjs
|
|
|
|
|
|
|
|
git commit -m "feat: add product factors step three analysis"
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Task 4: 全量回归与交付检查
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
|
|
- Verify only: 前后端工作树的已提交变更。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
|
|
- Consumes: Tasks 1–3。
|
|
|
|
|
|
|
|
- Produces: 经过完整回归验证的前后端功能分支。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: 运行后端全量测试**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B test`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected: BUILD SUCCESS,所有测试通过。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: 运行前端完整验证**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Run: `node tests/product-development-factors-step-one.static.test.cjs; npm run build:prod`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected: 静态契约测试和生产构建成功。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: 审查工作树**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Run: `git status --short; git log --oneline -3`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Expected: 仅本功能的预期提交;不纳入主工作区已有未跟踪文件。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: 汇报并等待集成指令**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
报告功能、提交和验证结果,等待用户明确指示合并、推送或发布。
|