|
|
|
|
|
# New Product Survey Step Four 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:** Deliver the student-only fourth step that collects three AI application-value analyses and blocks final task submission until all are filled.
|
|
|
|
|
|
|
|
|
|
|
|
**Architecture:** Keep the existing `StudentTrainingAnswer.step4Answer` JSON persistence and add a stateless student-only validation endpoint. The Vue page retains a local draft and calls the validation endpoint only on final submission; the demo client enforces the same non-empty rule locally.
|
|
|
|
|
|
|
|
|
|
|
|
**Tech Stack:** Vue 3 Composition API, Element Plus, Vite, Spring Boot, Java 8, JUnit 5, Mockito.
|
|
|
|
|
|
|
|
|
|
|
|
## Global Constraints
|
|
|
|
|
|
|
|
|
|
|
|
- Only change the student `new-product-survey` page and its supporting student validation API; do not change teacher, admin, table schema, prior steps, or material download behavior.
|
|
|
|
|
|
- Persist `{ coreValue, tangibleValue, extendedValue }` in the existing `step4Answer` field.
|
|
|
|
|
|
- A value is valid only when `trim()` leaves non-empty text; validation does not score analysis quality.
|
|
|
|
|
|
- Saving a draft remains allowed with empty fields; final `SUBMIT` is guarded by validation.
|
|
|
|
|
|
- Keep legacy fourth-step JSON restoration compatible.
|
|
|
|
|
|
- Do not start the backend automatically; the user starts it manually.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### Task 1: Add server-side fourth-step validation
|
|
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
- Create: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/entity/dto/NewProductSurveyStepFourValidationRequest.java`
|
|
|
|
|
|
- Create: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/entity/dto/NewProductSurveyStepFourValidationResult.java`
|
|
|
|
|
|
- Create: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/service/NewProductSurveyStepFourService.java`
|
|
|
|
|
|
- Create: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/service/impl/NewProductSurveyStepFourServiceImpl.java`
|
|
|
|
|
|
- Modify: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java`
|
|
|
|
|
|
- Test: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/test/java/com/sztzjy/linkCommerce/service/impl/NewProductSurveyStepFourServiceImplTest.java`
|
|
|
|
|
|
- Test: `E:/workspace/dianshang/link_commerce/.worktrees/new-product-survey-step3/src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java`
|
|
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
- Consumes: authenticated `JwtUser` and `NewProductSurveyStepFourValidationRequest { String coreValue, String tangibleValue, String extendedValue }`.
|
|
|
|
|
|
- Produces: `NewProductSurveyStepFourValidationResult { boolean valid, String message }` from `POST /api/student-training-answers/new-product-survey/step-4/validate`.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: Write the failing service tests**
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
@Test
|
|
|
|
|
|
void acceptsStudentWithAllThreeNonBlankValues() {
|
|
|
|
|
|
NewProductSurveyStepFourValidationRequest request = request("核心分析", "有形分析", "延伸分析");
|
|
|
|
|
|
assertTrue(service.validate(request, student()).isValid());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ParameterizedTest
|
|
|
|
|
|
@NullAndEmptySource
|
|
|
|
|
|
@ValueSource(strings = {" ", "\t"})
|
|
|
|
|
|
void rejectsBlankCoreValue(String value) {
|
|
|
|
|
|
assertThrows(ServiceException.class, () -> service.validate(request(value, "有形", "延伸"), student()));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Test
|
|
|
|
|
|
void rejectsNonStudent() {
|
|
|
|
|
|
assertThrows(ServiceException.class, () -> service.validate(request("核心", "有形", "延伸"), teacher()));
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: Run the service test to verify it fails**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B '-Dtest=NewProductSurveyStepFourServiceImplTest' test`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: FAIL because fourth-step request and service types do not exist.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: Implement DTOs and service**
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
public interface NewProductSurveyStepFourService {
|
|
|
|
|
|
NewProductSurveyStepFourValidationResult validate(NewProductSurveyStepFourValidationRequest request, JwtUser user);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void requireNonBlank(String value, String message) {
|
|
|
|
|
|
if (StringUtils.isBlank(value)) {
|
|
|
|
|
|
throw new ServiceException(HttpStatus.BAD_REQUEST, message);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Require the existing student role and user id, then require `coreValue`, `tangibleValue`, and `extendedValue` after trimming. Return `valid=true` and `校验通过` on success.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: Run the service test to verify it passes**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B '-Dtest=NewProductSurveyStepFourServiceImplTest' test`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: PASS with nonblank, blank, and authorization behavior covered.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 5: Write the failing controller test**
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
@Test
|
|
|
|
|
|
void validateStepFourUsesAuthenticatedStudentAndReturnsValidationResult() {
|
|
|
|
|
|
NewProductSurveyStepFourValidationResult result = new NewProductSurveyStepFourValidationResult(true, "校验通过");
|
|
|
|
|
|
when(newProductSurveyStepFourService.validate(any(), any())).thenReturn(result);
|
|
|
|
|
|
ResultEntity<NewProductSurveyStepFourValidationResult> response = controller
|
|
|
|
|
|
.validateNewProductSurveyStepFour(request("核心", "有形", "延伸"), authenticatedRequest());
|
|
|
|
|
|
assertEquals(HttpStatus.OK, response.getCode());
|
|
|
|
|
|
assertSame(result, response.getData());
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 6: Run the controller test to verify it fails**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B '-Dtest=StudentTrainingAnswerControllerTest' test`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: FAIL because `validateNewProductSurveyStepFour` does not exist.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 7: Add the controller endpoint**
|
|
|
|
|
|
|
|
|
|
|
|
```java
|
|
|
|
|
|
@PostMapping("/new-product-survey/step-4/validate")
|
|
|
|
|
|
public ResultEntity<NewProductSurveyStepFourValidationResult> validateNewProductSurveyStepFour(
|
|
|
|
|
|
@RequestBody NewProductSurveyStepFourValidationRequest answer, HttpServletRequest request) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
return new ResultEntity<>(HttpStatus.OK, "校验通过",
|
|
|
|
|
|
newProductSurveyStepFourService.validate(answer, TokenProvider.getJWTUser(request)));
|
|
|
|
|
|
} catch (ServiceException e) {
|
|
|
|
|
|
return new ResultEntity<>(e.getCode(), e.getMessage());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 8: Run focused server tests**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B '-Dtest=NewProductSurveyStepFourServiceImplTest,StudentTrainingAnswerControllerTest' test`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: PASS with fourth-step service behavior and endpoint delegation covered.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 9: Commit server validation**
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
git add src/main/java/com/sztzjy/linkCommerce/entity/dto/NewProductSurveyStepFourValidationRequest.java src/main/java/com/sztzjy/linkCommerce/entity/dto/NewProductSurveyStepFourValidationResult.java src/main/java/com/sztzjy/linkCommerce/service/NewProductSurveyStepFourService.java src/main/java/com/sztzjy/linkCommerce/service/impl/NewProductSurveyStepFourServiceImpl.java src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerController.java src/test/java/com/sztzjy/linkCommerce/service/impl/NewProductSurveyStepFourServiceImplTest.java src/test/java/com/sztzjy/linkCommerce/controller/stu/StudentTrainingAnswerControllerTest.java
|
|
|
|
|
|
git commit -m "feat: validate new product survey step four"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Task 2: Update the fourth-step student UI and submission flow
|
|
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
- Modify: `E:/workspace/dianshang/e-commerce-internet/.worktrees/new-product-survey-step3/src/api/studentTrainingAnswer.js`
|
|
|
|
|
|
- Modify: `E:/workspace/dianshang/e-commerce-internet/.worktrees/new-product-survey-step3/src/views/foundation/new-product-survey.vue`
|
|
|
|
|
|
- Modify: `E:/workspace/dianshang/e-commerce-internet/.worktrees/new-product-survey-step3/tests/new-product-survey-step-one.static.test.cjs`
|
|
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
- Consumes: `checkNewProductSurveyStepFour(payload)` returning `{ code: 200, data: { valid: true, message: "校验通过" } }`.
|
|
|
|
|
|
- Produces: guarded `submitTask()` that saves `step4Answer` only after successful validation.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: Add failing static source assertions**
|
|
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
|
assert.match(page, /AI技术是否实现产品功能突破?是否形成差异化卖点?/, "step four must show the core-layer prototype question");
|
|
|
|
|
|
assert.match(page, /AI技术是否影响产品形态?如产品外形包装、电商主图设计、参数配置、价格带定位。/, "step four must show the tangible-layer prototype question");
|
|
|
|
|
|
assert.match(page, /AI技术如何通过服务升级、内容更新提升用户粘性,推动付费服务?/, "step four must show the extended-layer prototype question");
|
|
|
|
|
|
assert.match(page, /checkNewProductSurveyStepFour\(step4Form\.value\)/, "step four must validate before submission");
|
|
|
|
|
|
assert.match(api, /new-product-survey\/step-4\/validate/, "the API must expose the step-four validation route");
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: Run the static test to verify it fails**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `& 'E:\Program Files\nodejs\node.exe' tests\new-product-survey-step-one.static.test.cjs`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: FAIL because the fourth-step question copy and validation call are absent.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: Implement client validation and prototype-aligned form**
|
|
|
|
|
|
|
|
|
|
|
|
```js
|
|
|
|
|
|
function validateNewProductSurveyStepFourDemo(form) {
|
|
|
|
|
|
const value = form || {};
|
|
|
|
|
|
for (const [field, label] of [["coreValue", "核心层"], ["tangibleValue", "有形层"], ["extendedValue", "延伸层"]]) {
|
|
|
|
|
|
if (!String(value[field] || "").trim()) throw new Error(`请填写${label}AI应用价值分析`);
|
|
|
|
|
|
}
|
|
|
|
|
|
return { valid: true, message: "校验通过" };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function submitTask() {
|
|
|
|
|
|
checking.value = true;
|
|
|
|
|
|
try {
|
|
|
|
|
|
await checkNewProductSurveyStepFour(step4Form.value);
|
|
|
|
|
|
await saveAnswer("SUBMITTED");
|
|
|
|
|
|
} catch (error) {
|
|
|
|
|
|
proxy?.$modal?.msgWarning(error?.message || "请完成三层次AI应用价值分析");
|
|
|
|
|
|
} finally {
|
|
|
|
|
|
checking.value = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Replace the existing generic field labels with the three prototype questions, keep their bindings as `coreValue`, `tangibleValue`, and `extendedValue`, and preserve draft saving and restoration.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: Run the static test to verify it passes**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `& 'E:\Program Files\nodejs\node.exe' tests\new-product-survey-step-one.static.test.cjs`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: PASS with prior step contracts still intact.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 5: Commit student UI and client validation**
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
git add src/api/studentTrainingAnswer.js src/views/foundation/new-product-survey.vue tests/new-product-survey-step-one.static.test.cjs
|
|
|
|
|
|
git commit -m "feat: add new product survey step four"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Task 3: Run full verification
|
|
|
|
|
|
|
|
|
|
|
|
**Files:**
|
|
|
|
|
|
- Modify: none.
|
|
|
|
|
|
|
|
|
|
|
|
**Interfaces:**
|
|
|
|
|
|
- Consumes: both committed fourth-step implementations.
|
|
|
|
|
|
- Produces: verification evidence before integration; no application process is started.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 1: Run complete backend tests**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `mvn -B test`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: Maven reports `BUILD SUCCESS` and zero failures.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 2: Run the frontend source contract**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `& 'E:\Program Files\nodejs\node.exe' tests\new-product-survey-step-one.static.test.cjs`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: `new product survey step-one contract passed`.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 3: Run the production frontend build**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `& 'E:\Program Files\nodejs\node.exe' 'E:\workspace\dianshang\e-commerce-internet\node_modules\vite\bin\vite.js' build`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: Vite exits with code 0. Existing `::v-deep`, unresolved `Navbar.vue` top1 asset, and large-chunk warnings may remain.
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] **Step 4: Inspect repository state**
|
|
|
|
|
|
|
|
|
|
|
|
Run: `git status --short; git log --oneline --max-count=5`
|
|
|
|
|
|
|
|
|
|
|
|
Expected: only the intended fourth-step commits are present; do not start the backend.
|