|
|
# 产品开发关键因素第 1 步 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:** 为学生端“产品开发关键因素”第 1 步提供原型对应的三维对比表、服务端非空校验,以及仅保存并进入第 2 步的流程。
|
|
|
|
|
|
**Architecture:** 前端把第 1 步维度收敛为固定常量,以 `step1Answer` 持久化三行成功/失败分析;点击推进时先调用专用校验接口,再使用已有学生答案保存接口保存 `SAVE` 草稿和第 2 步进度。后端新增轻量 DTO、校验服务和控制器路由,复用已有 JWT 学生身份检查与 `StudentTrainingAnswer` 持久化机制,不新建表。
|
|
|
|
|
|
**Tech Stack:** Vue 3 Composition API、Element Plus、Vite、Spring Boot、JUnit 5、Mockito、Maven。
|
|
|
|
|
|
## Global Constraints
|
|
|
|
|
|
- 只修改学生端 `product-development-factors` 的第 1 步和其服务端校验;不修改教师端、管理员端、数据库结构、材料下载或第 2 步的业务内容。
|
|
|
- 页面仅保留原型的四列表头与三个固定维度,不显示成功/失败产品名称输入项。
|
|
|
- 六个分析输入去除首尾空白后必须非空,服务端必须拒绝缺失、重复、额外或伪造维度。
|
|
|
- 第 1 步推进只能使用 `saveAction: "SAVE"`,不得触发 `SUBMIT` 或成绩结算。
|
|
|
- 使用已有隔离 worktree;仅提交本计划列出的文件,避免纳入主工作区已有的无关未跟踪文件。
|
|
|
|
|
|
---
|
|
|
|
|
|
## 文件结构
|
|
|
|
|
|
### 前端仓库 `E:/workspace/dianshang/e-commerce-internet`
|
|
|
|
|
|
- 修改:`src/views/foundation/product-development-factors.vue` — 固定第 1 步表格、恢复/保存进度和“保存并进入第 2 步”交互。
|
|
|
- 修改:`src/api/studentTrainingAnswer.js` — 增加 Demo 与真实环境共用的第 1 步校验 API 封装。
|
|
|
- 新建:`tests/product-development-factors-step-one.static.test.cjs` — 对页面结构、保存行为与 API 路由做静态契约测试。
|
|
|
|
|
|
### 后端仓库 `E:/workspace/dianshang/link_commerce`
|
|
|
|
|
|
- 新建:`src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationRequest.java` — 接收固定维度及两列分析文本。
|
|
|
- 新建:`src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationResult.java` — 返回 `valid` 与 `message`。
|
|
|
- 新建:`src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepOneService.java` — 声明校验入口。
|
|
|
- 新建:`src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImpl.java` — 学生身份、三维度和六项非空校验。
|
|
|
- 修改:`src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java` — 注入服务并暴露校验路由。
|
|
|
- 新建:`src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImplTest.java` — 服务层行为测试。
|
|
|
- 修改:`src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java` — 控制器传递认证学生和返回校验结果的测试。
|
|
|
|
|
|
## Task 1: 后端第 1 步校验契约
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
- Create: `link_commerce/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationRequest.java`
|
|
|
- Create: `link_commerce/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationResult.java`
|
|
|
- Create: `link_commerce/src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepOneService.java`
|
|
|
- Create: `link_commerce/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImpl.java`
|
|
|
- Create: `link_commerce/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImplTest.java`
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
- Consumes: `JwtUser`、`ServiceException`、`StringUtils`、`HttpStatus`,以及 `NewProductSurveyStepThreeServiceImpl` 的角色校验风格。
|
|
|
- Produces: `ProductDevelopmentFactorsStepOneService#validate(ProductDevelopmentFactorsStepOneValidationRequest request, JwtUser user)`,供控制器调用;成功时返回 `{ valid: true, message: "校验通过" }`。
|
|
|
|
|
|
- [ ] **Step 1: 写服务层失败测试**
|
|
|
|
|
|
在 `ProductDevelopmentFactorsStepOneServiceImplTest` 建立三个测试:完整的三个固定维度均有成功/失败文本时返回有效;任一分析为空、维度重复或维度不在白名单时抛出 `ServiceException`;角色不是 `4` 时抛出 `ServiceException`。
|
|
|
|
|
|
```java
|
|
|
ProductDevelopmentFactorsStepOneValidationResult result = service.validate(validRequest(), student());
|
|
|
assertTrue(result.isValid());
|
|
|
assertThrows(ServiceException.class, () -> service.validate(requestWithBlankFailure(), student()));
|
|
|
assertThrows(ServiceException.class, () -> service.validate(validRequest(), teacher()));
|
|
|
```
|
|
|
|
|
|
- [ ] **Step 2: 运行测试确认失败**
|
|
|
|
|
|
Run: `mvn -B '-Dtest=ProductDevelopmentFactorsStepOneServiceImplTest' test`
|
|
|
|
|
|
Expected: FAIL,因为校验 DTO、服务接口及实现尚不存在。
|
|
|
|
|
|
- [ ] **Step 3: 添加请求、结果和服务实现**
|
|
|
|
|
|
请求 DTO 定义 `List<Row> factors`;`Row` 定义 `String dimension`、`String successAnalysis`、`String failedAnalysis` 及标准 getter/setter。实现类固定使用以下维度集合:
|
|
|
|
|
|
```java
|
|
|
private static final Set<String> DIMENSIONS = new LinkedHashSet<>(Arrays.asList(
|
|
|
"用户需求真实性", "产品体验闭环", "生态与兼容"));
|
|
|
```
|
|
|
|
|
|
`validate` 必须先验证登录用户存在且 `roleId == 4`,再验证 `factors` 数量恰为 3、每个维度属于 `DIMENSIONS` 且仅出现一次、`successAnalysis` 和 `failedAnalysis` 都满足 `StringUtils.isNotBlank`,最后验证提交维度集合与 `DIMENSIONS` 完全一致。所有请求内容问题用 `new ServiceException(HttpStatus.BAD_REQUEST, message)` 拒绝;身份问题分别用 `UNAUTHORIZED` 或 `FORBIDDEN`。
|
|
|
|
|
|
- [ ] **Step 4: 运行服务测试确认通过**
|
|
|
|
|
|
Run: `mvn -B '-Dtest=ProductDevelopmentFactorsStepOneServiceImplTest' test`
|
|
|
|
|
|
Expected: PASS,三个测试全部通过。
|
|
|
|
|
|
- [ ] **Step 5: 提交后端服务层变更**
|
|
|
|
|
|
```powershell
|
|
|
git add src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationRequest.java src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepOneValidationResult.java src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepOneService.java src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImpl.java src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepOneServiceImplTest.java
|
|
|
git commit -m "feat: validate product factors step one"
|
|
|
```
|
|
|
|
|
|
## Task 2: 暴露后端校验路由
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
- Modify: `link_commerce/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java`
|
|
|
- Modify: `link_commerce/src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java`
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
- Consumes: Task 1 的 `ProductDevelopmentFactorsStepOneService#validate(request, user)`。
|
|
|
- Produces: `POST /api/student-training-answers/product-development-factors/step-1/validate`,请求体为 `{ "factors": [{ "dimension": "...", "successAnalysis": "...", "failedAnalysis": "..." }] }`。
|
|
|
|
|
|
- [ ] **Step 1: 写控制器失败测试**
|
|
|
|
|
|
在 `StudentTrainingAnswerControllerTest` 添加一个测试,mock `ProductDevelopmentFactorsStepOneService`,通过 `ReflectionTestUtils` 注入控制器,调用 `validateProductDevelopmentFactorsStepOne`,断言状态为 `HttpStatus.OK`、返回体是 mock 的结果,并验证 `service.validate(any(ProductDevelopmentFactorsStepOneValidationRequest.class), any(JwtUser.class))` 被调用。
|
|
|
|
|
|
```java
|
|
|
when(service.validate(any(ProductDevelopmentFactorsStepOneValidationRequest.class), any(JwtUser.class))).thenReturn(validation);
|
|
|
ResultEntity<ProductDevelopmentFactorsStepOneValidationResult> result = controller
|
|
|
.validateProductDevelopmentFactorsStepOne(answer, authenticatedStudentRequest());
|
|
|
assertEquals(HttpStatus.OK, result.getStatusCode());
|
|
|
verify(service).validate(any(ProductDevelopmentFactorsStepOneValidationRequest.class), any(JwtUser.class));
|
|
|
```
|
|
|
|
|
|
- [ ] **Step 2: 运行控制器测试确认失败**
|
|
|
|
|
|
Run: `mvn -B '-Dtest=StudentTrainingAnswerControllerTest' test`
|
|
|
|
|
|
Expected: FAIL,因为控制器尚未注入服务或不存在该方法。
|
|
|
|
|
|
- [ ] **Step 3: 添加控制器依赖与路由**
|
|
|
|
|
|
在控制器添加 DTO 和服务 import、`@Autowired ProductDevelopmentFactorsStepOneService productDevelopmentFactorsStepOneService`,并添加以下方法。方法沿用已有四个新产品调查校验接口的 `try/catch ServiceException` 响应方式。
|
|
|
|
|
|
```java
|
|
|
@PostMapping("/product-development-factors/step-1/validate")
|
|
|
@ApiOperation("产品开发关键因素第一步校验")
|
|
|
public ResultEntity<ProductDevelopmentFactorsStepOneValidationResult> validateProductDevelopmentFactorsStepOne(
|
|
|
@RequestBody ProductDevelopmentFactorsStepOneValidationRequest answer, HttpServletRequest request) {
|
|
|
try {
|
|
|
JwtUser user = TokenProvider.getJWTUser(request);
|
|
|
return new ResultEntity<>(HttpStatus.OK, "校验通过", productDevelopmentFactorsStepOneService.validate(answer, user));
|
|
|
} catch (ServiceException e) {
|
|
|
return new ResultEntity<>(e.getCode(), e.getMessage());
|
|
|
}
|
|
|
}
|
|
|
```
|
|
|
|
|
|
- [ ] **Step 4: 运行控制器和服务测试确认通过**
|
|
|
|
|
|
Run: `mvn -B '-Dtest=ProductDevelopmentFactorsStepOneServiceImplTest,StudentTrainingAnswerControllerTest' test`
|
|
|
|
|
|
Expected: PASS,新增路由通过认证用户调用服务,已有控制器测试保持通过。
|
|
|
|
|
|
- [ ] **Step 5: 提交后端控制器变更**
|
|
|
|
|
|
```powershell
|
|
|
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 one validation"
|
|
|
```
|
|
|
|
|
|
## Task 3: 前端 API 与页面第 1 步交互
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
- Modify: `e-commerce-internet/src/api/studentTrainingAnswer.js`
|
|
|
- Modify: `e-commerce-internet/src/views/foundation/product-development-factors.vue`
|
|
|
- Create: `e-commerce-internet/tests/product-development-factors-step-one.static.test.cjs`
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
- Consumes: Task 2 的 `POST /api/student-training-answers/product-development-factors/step-1/validate`,以及现有 `saveStudentTrainingAnswer(taskKey, data)`。
|
|
|
- Produces: `checkProductDevelopmentFactorsStepOne(payload)`;页面第 1 步调用其校验并保存 `{ step1Answer, currentStep: 2, submitted: false, saveAction: "SAVE" }` 后切到索引 `1`。
|
|
|
|
|
|
- [ ] **Step 1: 写前端静态契约失败测试**
|
|
|
|
|
|
新建 `tests/product-development-factors-step-one.static.test.cjs`,读取 API 和 Vue 源码,断言固定三维度常量与三条中文评估项存在,旧的 `successProduct`/`failedProduct` 输入绑定不存在,存在 `checkProductDevelopmentFactorsStepOne` 和真实路由字符串,推进方法先校验后 `saveStudentTrainingAnswer`,并且保存动作字符串为 `"SAVE"` 而非 `"SUBMIT"`。
|
|
|
|
|
|
```js
|
|
|
assert.match(view, /const STEP_ONE_FACTOR_ROWS = \[/);
|
|
|
assert.doesNotMatch(view, /v-model="form\.successProduct"/);
|
|
|
assert.match(api, /product-development-factors\/step-1\/validate/);
|
|
|
assert.match(view, /await checkProductDevelopmentFactorsStepOne\(buildStepOneValidationPayload\(\)\)/);
|
|
|
```
|
|
|
|
|
|
- [ ] **Step 2: 运行静态测试确认失败**
|
|
|
|
|
|
Run: `node tests/product-development-factors-step-one.static.test.cjs`
|
|
|
|
|
|
Expected: FAIL,因为页面尚未声明固定三行常量或调用新校验 API。
|
|
|
|
|
|
- [ ] **Step 3: 实现 API 封装和 Demo 校验**
|
|
|
|
|
|
在 `studentTrainingAnswer.js` 增加 `checkProductDevelopmentFactorsStepOne(payload)`。Demo 模式以相同固定维度、恰好三行和每行两列非空规则校验,失败时 `Promise.reject(new Error(message))`;真实模式发起:
|
|
|
|
|
|
```js
|
|
|
return request({
|
|
|
url: "/api/student-training-answers/product-development-factors/step-1/validate",
|
|
|
method: "post",
|
|
|
data: payload,
|
|
|
headers: { repeatSubmit: false },
|
|
|
});
|
|
|
```
|
|
|
|
|
|
- [ ] **Step 4: 重构第 1 步页面**
|
|
|
|
|
|
在 `product-development-factors.vue` 以 `STEP_ONE_FACTOR_ROWS` 取代八行工厂,且只包含原型指定的三行和评估项。移除 `form`、`.product-entry`、`.product-field`、`.input-single` 及模板中的产品名称输入区域;`buildOutcome()` 仅保存 `title` 与三行 `factors`。
|
|
|
|
|
|
将表格和第 1 步操作包在 `v-if="currentStep === 0"` 中,非第 1 步渲染不复用第 1 步表格的轻量占位块。新增 `buildStepOneValidationPayload()`,其返回值仅含 `{ factors: factorRows.value.map(({ dimension, successAnalysis, failedAnalysis }) => ({ dimension, successAnalysis, failedAnalysis })) }`。新增 `saveAndGoToStepTwo()`:先等待校验、再调用 `saveStudentTrainingAnswer(TASK_KEY, buildAnswerPayload("SAVE", 2))`、清理本地草稿;当 `trainingSteps.value.length >= 2` 时设置 `currentStep.value = 1`,否则提示任务未配置下一步。替换原“提交任务”按钮为“保存并进入第 2 步”,不再保留第 1 步的 `SUBMIT` 路径。
|
|
|
|
|
|
`loadSavedAnswer()` 在恢复 `step1Answer` 后,将服务端 `answer.currentStep` 的 1 基步骤值转换成合法 0 基索引;历史 JSON 的产品名称字段不读取。`resetTraining()` 重建三行数据、保存 `RESET`,并复位 `currentStep.value = 0`。
|
|
|
|
|
|
- [ ] **Step 5: 运行前端静态测试确认通过**
|
|
|
|
|
|
Run: `node tests/product-development-factors-step-one.static.test.cjs`
|
|
|
|
|
|
Expected: PASS,页面和 API 合同全部满足。
|
|
|
|
|
|
- [ ] **Step 6: 构建前端**
|
|
|
|
|
|
Run: `npm run build`
|
|
|
|
|
|
Expected: PASS,Vite 生产构建完成且没有 Vue 编译错误。
|
|
|
|
|
|
- [ ] **Step 7: 提交前端实现**
|
|
|
|
|
|
```powershell
|
|
|
git add src/api/studentTrainingAnswer.js src/views/foundation/product-development-factors.vue tests/product-development-factors-step-one.static.test.cjs
|
|
|
git commit -m "feat: add product factors step one analysis"
|
|
|
```
|
|
|
|
|
|
## Task 4: 跨端回归验证与交付准备
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
- Modify: 无;只验证 Task 1–3 已提交的文件。
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
- Consumes: 新增前端校验封装、后端校验路由和已有答案保存接口。
|
|
|
- Produces: 可以交付的前后端分支,且不启动本地后端进程。
|
|
|
|
|
|
- [ ] **Step 1: 运行后端完整回归**
|
|
|
|
|
|
Run: `mvn -B test`
|
|
|
|
|
|
Expected: PASS,所有 Maven 测试通过;既有系统依赖警告不视为测试失败。
|
|
|
|
|
|
- [ ] **Step 2: 运行前端相关及完整构建验证**
|
|
|
|
|
|
Run: `node tests/product-development-factors-step-one.static.test.cjs; npm run build`
|
|
|
|
|
|
Expected: PASS,静态契约与生产构建均完成。
|
|
|
|
|
|
- [ ] **Step 3: 检查提交范围**
|
|
|
|
|
|
Run: `git status --short`(分别在两个 worktree 执行)
|
|
|
|
|
|
Expected: 无本功能未提交改动;不暂存或删除主工作区既有未跟踪文件。
|
|
|
|
|
|
- [ ] **Step 4: 记录验证结果并等待集成指令**
|
|
|
|
|
|
报告前后端提交号、测试结果与用户可见的“保存并进入第 2 步”行为。除非用户明确要求,不合并、不推送、不发布,也不启动本地后端。
|
|
|
|
|
|
## 自检结果
|
|
|
|
|
|
- 规格覆盖:Task 1–2 实现身份与六项非空的服务端校验;Task 3 实现原型三行页面、Demo 校验、持久化和仅保存推进;Task 4 覆盖跨端验证与不发布约束。
|
|
|
- 占位扫描:计划没有未定义的后续实现项;第 1 步以外的页面仅在已有步骤导航中显示明确的待配置占位,未扩展第 2 步业务。
|
|
|
- 类型一致性:前端 `factors[].dimension/successAnalysis/failedAnalysis` 与后端请求 DTO 的 `Row` 字段一致;控制器路由与 API 封装字符串一致。
|