16 KiB
产品开发关键因素第 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。
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。实现类固定使用以下维度集合:
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: 提交后端服务层变更
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)) 被调用。
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 响应方式。
@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: 提交后端控制器变更
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"。
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));真实模式发起:
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: 提交前端实现
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 封装字符串一致。