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.
dianshang-qianduan/docs/superpowers/plans/2026-08-07-product-developm...

13 KiB

产品开发关键因素第 2 步 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: 为学生端产品开发关键因素的第 2 步提供技术与合规两行对比表、服务端四项非空校验,以及仅保存并进入第 3 步的流程。

Architecture: 前端将第 1 步和第 2 步的固定行数据分开维护,分别写入已有答案记录的 step1Answerstep2Answer;第 2 步校验成功后以 SAVE 写入 currentStep: 3。后端参照第 1 步新增独立 DTO、校验服务和控制器路由保留已有答案服务的字段合并行为不新增表或改动教师端。

Tech Stack: Vue 3 Composition API、Element Plus、Vite、Spring Boot、JUnit 5、Mockito、Maven。

Global Constraints

  • 仅修改学生端 product-development-factors 第 2 步和其校验接口;不改教师端、管理员端、数据库结构、材料下载或第 3 步业务内容。
  • 第 2 步表格只能出现“技术应用”“合规与认证”两行及原型的四列表头,且不显示产品名称输入框。
  • 四个分析值去除首尾空白后必须非空;服务端拒绝缺失、重复或不在白名单内的维度。
  • 推进使用 saveAction: "SAVE"currentStep: 3,不得提交整项任务或触发成绩结算。
  • 仅提交本计划列出的文件,保留主工作区既有未跟踪文件。

文件结构

前端仓库 E:/workspace/dianshang/e-commerce-internet

  • 修改:src/views/foundation/product-development-factors.vue — 同屏步骤状态分离、第 2 步表格、答案恢复与保存推进。
  • 修改:src/api/studentTrainingAnswer.js — 第 2 步真实/Demo 校验封装。
  • 修改:tests/product-development-factors-step-one.static.test.cjs — 扩展为覆盖第 1、2 步共同页面的静态契约。
  • 新建:entity/dto/ProductDevelopmentFactorsStepTwoValidationRequest.java — 两行分析请求。
  • 新建:entity/dto/ProductDevelopmentFactorsStepTwoValidationResult.java — 校验响应。
  • 新建:service/ProductDevelopmentFactorsStepTwoService.javaservice/impl/ProductDevelopmentFactorsStepTwoServiceImpl.java — 学生身份和二行四项文本校验。
  • 修改:controller/stu/StudentTrainingAnswerController.java — 第 2 步校验路由。
  • 新建:service/impl/ProductDevelopmentFactorsStepTwoServiceImplTest.java — 服务校验行为。
  • 修改:controller/stu/StudentTrainingAnswerControllerTest.java — 控制器认证传递。

Task 1: 实现第 2 步后端校验服务

Files:

  • Create: link_commerce/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepTwoValidationRequest.java
  • Create: link_commerce/src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepTwoValidationResult.java
  • Create: link_commerce/src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepTwoService.java
  • Create: link_commerce/src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepTwoServiceImpl.java
  • Create: link_commerce/src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepTwoServiceImplTest.java

Interfaces:

  • Consumes: JwtUserServiceExceptionStringUtils 和第 1 步服务的校验模式。

  • Produces: ProductDevelopmentFactorsStepTwoService#validate(ProductDevelopmentFactorsStepTwoValidationRequest request, JwtUser user),成功返回 valid=truemessage="校验通过"

  • Step 1: 写服务失败测试

测试完整的“技术应用”“合规与认证”两行通过;将任一成功或失败文本设为空、替换成重复维度或未知维度、使用教师用户时均断言 ServiceException

ProductDevelopmentFactorsStepTwoValidationResult result = service.validate(validRequest(), student());
assertTrue(result.isValid());
assertThrows(ServiceException.class, () -> service.validate(requestWithBlankAnalysis(), student()));
assertThrows(ServiceException.class, () -> service.validate(validRequest(), teacher()));
  • Step 2: 运行失败测试

Run: mvn -B '-Dtest=ProductDevelopmentFactorsStepTwoServiceImplTest' test

Expected: FAIL因为第 2 步 DTO 和服务尚未存在。

  • Step 3: 写最小服务实现

请求 DTO 定义 List<Row> factors,内嵌 Row 提供 dimensionsuccessAnalysisfailedAnalysis getter/setter结果 DTO 提供 boolean validString message getter/setter。服务实现的唯一维度集合为

private static final Set<String> DIMENSIONS = new LinkedHashSet<>(Arrays.asList(
        "技术应用", "合规与认证"));

validate 先拒绝未登录和非 roleId == 4 的用户;随后要求恰好两行、每个维度属于集合且只出现一次、每行成功/失败文本均 StringUtils.isNotBlank,最后确认提交集合与 DIMENSIONS 完全相等。请求内容错误使用 HttpStatus.BAD_REQUEST,登录/权限错误分别使用 UNAUTHORIZED/FORBIDDEN

  • Step 4: 运行服务测试

Run: mvn -B '-Dtest=ProductDevelopmentFactorsStepTwoServiceImplTest' test

Expected: PASS所有新增服务行为通过。

  • Step 5: 提交服务变更
git add src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepTwoValidationRequest.java src/main/java/com/sztzjy/linkCommerce/entity/dto/ProductDevelopmentFactorsStepTwoValidationResult.java src/main/java/com/sztzjy/linkCommerce/service/ProductDevelopmentFactorsStepTwoService.java src/main/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepTwoServiceImpl.java src/test/java/com/sztzjy/linkCommerce/service/impl/ProductDevelopmentFactorsStepTwoServiceImplTest.java
git commit -m "feat: validate product factors step two"

Task 2: 暴露第 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 的 ProductDevelopmentFactorsStepTwoService#validate

  • Produces: POST /api/student-training-answers/product-development-factors/step-2/validate

  • Step 1: 写控制器失败测试

mock 第 2 步服务,注入控制器,调用 validateProductDevelopmentFactorsStepTwo(answer, authenticatedStudentRequest()),断言 HTTP 200、响应对象不变且服务获得了认证学生。

when(service.validate(any(ProductDevelopmentFactorsStepTwoValidationRequest.class), any(JwtUser.class))).thenReturn(validation);
assertEquals(HttpStatus.OK, result.getStatusCode());
verify(service).validate(any(ProductDevelopmentFactorsStepTwoValidationRequest.class), any(JwtUser.class));
  • Step 2: 运行控制器测试确认失败

Run: mvn -B '-Dtest=StudentTrainingAnswerControllerTest' test

Expected: FAIL因为控制器还没有第 2 步方法。

  • Step 3: 新增路由

添加 DTO/服务 import 与 @Autowired ProductDevelopmentFactorsStepTwoService productDevelopmentFactorsStepTwoService,并按第 1 步模式新增:

@PostMapping("/product-development-factors/step-2/validate")
public ResultEntity<ProductDevelopmentFactorsStepTwoValidationResult> validateProductDevelopmentFactorsStepTwo(
        @RequestBody ProductDevelopmentFactorsStepTwoValidationRequest answer, HttpServletRequest request) {
    try {
        return new ResultEntity<>(HttpStatus.OK, "校验通过",
                productDevelopmentFactorsStepTwoService.validate(answer, TokenProvider.getJWTUser(request)));
    } catch (ServiceException e) {
        return new ResultEntity<>(e.getCode(), e.getMessage());
    }
}
  • Step 4: 运行聚焦后端测试

Run: mvn -B '-Dtest=ProductDevelopmentFactorsStepOneServiceImplTest,ProductDevelopmentFactorsStepTwoServiceImplTest,StudentTrainingAnswerControllerTest' test

Expected: PASS第 1 步回归、新服务和两条控制器路由均通过。

  • 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 two validation"

Task 3: 实现学生端第 2 步页面与保存流程

Files:

  • Modify: e-commerce-internet/src/api/studentTrainingAnswer.js
  • Modify: e-commerce-internet/src/views/foundation/product-development-factors.vue
  • Modify: e-commerce-internet/tests/product-development-factors-step-one.static.test.cjs

Interfaces:

  • Consumes: Task 2 路由与已有 saveStudentTrainingAnswer

  • Produces: checkProductDevelopmentFactorsStepTwo(payload);保存 { step2Answer, currentStep: 3, submitted: false, saveAction: "SAVE" } 并进入索引 2。

  • Step 1: 写前端静态契约失败测试

扩展测试以断言 STEP_TWO_FACTOR_ROWS、两个中文维度、checkProductDevelopmentFactorsStepTwo、第 2 步路由、v-else-if="currentStep === 1"step2Answer: JSON.stringify(buildStepTwoOutcome())buildStepTwoAnswerPayload("SAVE", 3) 都存在;断言源码不出现 buildStepTwoAnswerPayload("SUBMIT"

assert.match(page, /const STEP_TWO_FACTOR_ROWS = \[/);
assert.match(page, /await checkProductDevelopmentFactorsStepTwo\(buildStepTwoValidationPayload\(\)\)/);
assert.match(api, /product-development-factors\/step-2\/validate/);
  • Step 2: 运行静态测试确认失败

Run: node tests/product-development-factors-step-one.static.test.cjs

Expected: FAIL因为第 2 步常量、API 和保存动作未实现。

  • Step 3: 添加 API 与 Demo 校验

在 API 文件新增 checkProductDevelopmentFactorsStepTwo(payload)。Demo 模式只接受两行固定维度且四项分析非空,失败时拒绝 Promise真实模式调用

return request({
  url: "/api/student-training-answers/product-development-factors/step-2/validate",
  method: "post",
  data: payload,
  headers: { repeatSubmit: false },
});
  • Step 4: 分离两步数据并渲染第 2 步

将现有 factorRows 重命名为 stepOneRows,新增 STEP_TWO_FACTOR_ROWSstepTwoRows,并为两步分别提供 create...Rowsbuild...Outcomebuild...ValidationPayload。模板保留第 1 步 v-if="currentStep === 0",新增 v-else-if="currentStep === 1" 的原型表格和“保存并进入第 3 步”按钮,最后 v-else 才保留第 3 步待配置占位。

loadSavedAnswer() 分别读取 answer.step1Answeranswer.step2Answer 并按维度恢复;本地草稿保存两个步骤的内容和当前步骤,读取时兼容旧第 1 步草稿。第 2 步保存函数先校验,再调用 saveStudentTrainingAnswer(TASK_KEY, buildStepTwoAnswerPayload("SAVE", 3)),步骤配置不少于三步时设置 currentStep.value = 2,否则显示已保存但未配置第 3 步。重置时清空两步行数据、将当前步骤设为 0并保持既有 RESET 行为。

  • Step 5: 运行前端契约测试

Run: node tests/product-development-factors-step-one.static.test.cjs

Expected: PASS两个步骤结构、校验和无 SUBMIT 约束均满足。

  • Step 6: 构建生产前端

Run: npm run build:prod

Expected: PASSVite 生产构建成功。

  • 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 two analysis"

Task 4: 合并前回归验证

Files:

  • Modify: 无;仅验证 Task 13 的提交。

Interfaces:

  • Consumes: 前端第 1、2 步保存/恢复逻辑和后端两条校验路由。

  • 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:prod

Expected: PASS契约和构建均通过。

  • Step 3: 检查分支状态

Run: git status --short(两个 worktree 分别执行)

Expected: 没有本功能未提交改动;不处理主工作区无关未跟踪文件。

  • Step 4: 报告提交与验证结果

报告前后端提交号、测试结果和“保存并进入第 3 步”的用户可见行为。除非用户明确要求,不合并、推送、发布或启动本地后端。

自检结果

  • 规格覆盖Task 12 负责后端身份和四项文本校验Task 3 负责两步页面分离、恢复、Demo/真实 API 与保存推进Task 4 负责完整回归。
  • 占位扫描:计划没有未定义的后续实现项;第 3 步仅为现有导航承接所需的待配置状态,不添加业务。
  • 类型一致性:前后端请求字段统一为 factors[].dimension/successAnalysis/failedAnalysis;第 2 步路由统一为 /product-development-factors/step-2/validate