diff --git a/docs/superpowers/plans/2026-08-26-market-opportunity-step2-weight.md b/docs/superpowers/plans/2026-08-26-market-opportunity-step2-weight.md new file mode 100644 index 0000000..c17df58 --- /dev/null +++ b/docs/superpowers/plans/2026-08-26-market-opportunity-step2-weight.md @@ -0,0 +1,94 @@ +# 市场机会识别第二步权重设置 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:** 让学生在市场机会识别第二步完成符合原型的指标权重设定、实时计算和可靠保存。 + +**Architecture:** 前端页面负责按固定分组渲染权重表、输入状态和即时总计;既有第二步接口负责服务器端最终校验。答案继续存放在学生实训答案的 `step2Answer`,不新增数据表或接口字段。 + +**Tech Stack:** Vue 3、Element Plus、Vite、Spring Boot、JUnit 5。 + +--- + +## 文件结构 + +- 修改:`src/views/product/market-opportunity-selection.vue` — 第二步表格、状态提示、交互和保存回显。 +- 修改:`tests/market-opportunity-step2.static.test.cjs` — 前端结构与计算契约。 +- 修改:`E:/workspace/dianshang/dianshang-houduan/src/test/java/com/sztzjy/linkCommerce/service/impl/MarketOpportunitySelectionStepTwoServiceImplTest.java` — 后端校验回归测试。 + +### Task 1: 前端第二步权重表契约 + +**Files:** +- Create: `tests/market-opportunity-step2.static.test.cjs` +- Modify: `src/views/product/market-opportunity-selection.vue` + +- [ ] **Step 1: 编写失败的前端契约测试** + +断言页面按以下固定顺序含有一级指标和二级指标:市场规模(搜索次数、成交金额)、市场潜力(成交金额增速、类目成交增速)、竞争强度(需供比、在线商品数、在线商家数)、运营难度(自然流占比、退货率);同时断言 25–35、65–75、55–65、35–45、20–30、10–20 建议区间、一级/对应总权重统计、实时错误状态和公式计算函数存在。 + +- [ ] **Step 2: 运行测试确认失败** + +Run(`E:/workspace/dianshang/dianshang-qianduan`): `node --test tests/market-opportunity-step2.static.test.cjs` + +Expected: 因新的原型布局和输入反馈契约尚未实现而失败。 + +- [ ] **Step 3: 最小化实现原型布局与即时反馈** + +让第二步使用分组表格:一级权重输入使用合并单元格,二级权重按指标逐行输入,对应总权重只读显示;在总计不满足 100% 时显示错误提示。 + +- [ ] **Step 4: 运行前端测试确认通过** + +Run(`E:/workspace/dianshang/dianshang-qianduan`): `node --test tests/market-opportunity-step2.static.test.cjs` + +Expected: PASS。 + +### Task 2: 后端权重规则回归 + +**Files:** +- Modify: `E:/workspace/dianshang/dianshang-houduan/src/test/java/com/sztzjy/linkCommerce/service/impl/MarketOpportunitySelectionStepTwoServiceImplTest.java` + + +- [ ] **Step 1: 编写失败的后端测试** + +新增一个请求:一级权重合法,但某个维度缺少预期的二级指标(或包含未知二级指标),断言服务拒绝。测试请求严格使用既有数组契约:`primaryWeights[].group`、`primaryWeights[].weight`、`dimensionWeights[].id`、`dimensionWeights[].weight`。 + +- [ ] **Step 2: 运行后端定向测试确认失败或暴露缺口** + +Run(`E:/workspace/dianshang/dianshang-houduan`): `mvn -Dtest=MarketOpportunitySelectionStepTwoServiceImplTest test` + +Expected: 若服务未覆盖该边界则失败;若现有服务已覆盖,记录现有实现满足约束并保持测试通过。 + +- [ ] **Step 3: 只在测试暴露缺口时补充最小校验代码** + +保持请求字段和答案存储格式不变,确保服务拒绝缺失或未知的二级指标。 + +- [ ] **Step 4: 运行定向测试确认通过** + +Run(`E:/workspace/dianshang/dianshang-houduan`): `mvn -Dtest=MarketOpportunitySelectionStepTwoServiceImplTest test` + +Expected: PASS。 + +### Task 3: 集成验证 + +**Files:** +- Modify: `src/views/product/market-opportunity-selection.vue` + +- [ ] **Step 1: 验证答案保存与回显数据结构** + +确认 `buildStepTwoOutcome` 保存 `primaryWeights`、`dimensionWeights` 和自动计算的 `correspondingWeights`;确认 `loadSavedAnswer` 使用同名字段恢复数据。 + +- [ ] **Step 2: 运行前端生产构建** + +Run(`E:/workspace/dianshang/dianshang-qianduan`): `npm run build:prod` + +Expected: exit code 0。 + +- [ ] **Step 3: 运行后端完整测试** + +Run(`E:/workspace/dianshang/dianshang-houduan`): `mvn test` + +Expected: 0 failures,0 errors。 + +- [ ] **Step 4: 提交本次功能修改** + +仅提交本次页面、测试和必要的后端修复,不包含本地日志或无关设计文档。 diff --git a/docs/superpowers/specs/2026-08-26-market-opportunity-step2-weight-design.md b/docs/superpowers/specs/2026-08-26-market-opportunity-step2-weight-design.md new file mode 100644 index 0000000..179488d --- /dev/null +++ b/docs/superpowers/specs/2026-08-26-market-opportunity-step2-weight-design.md @@ -0,0 +1,57 @@ +# 数据化选品与市场机会识别第二步设计 + +## 目标 + +将“数据化选品与市场机会识别”的第二步实现为可填写、自动计算、可校验和可回显的指标权重设置页面,并保持学生端既有深色实训工作台风格。 + +## 范围 + +- 页面:`/product/market-opportunity-selection` 的第二步“指标权重设置”。 +- 一级指标固定为市场规模、市场潜力、竞争强度、运营难度。 +- 二级指标固定为 9 项,分组、顺序和建议区间以原型为准。 +- 不新增文件上传控件;顶部通用案例资料按钮继续沿用现有的图片和 PDF 预览能力。 + +## 交互与计算 + +1. 学生必须先通过并保存第一步的指标分类,第二步才可填写。 +2. 每个一级指标填写一个 1–100 的整数权重,四项合计必须为 100%。 +3. 每个二级指标填写维度内的 1–100 整数权重;同一一级指标下的二级权重合计必须为 100%。 +4. 对应总权重实时显示,计算公式为:一级指标权重 × 二级指标维度内权重 ÷ 100。 +5. 全部对应总权重合计必须为 100%。未满足任一规则时,页面即时提示,保存时由后端再次校验。 +6. 保存成功后,将第二步答案写入 `step2Answer` 并进入第三步;再次打开页面时回显已保存权重。 + +## 指标清单与顺序 + +| 一级指标 | 一级建议区间 | 二级指标(顺序固定) | 二级建议区间 | +| --- | --- | --- | --- | +| 市场规模 | 25–35 | 搜索次数(万次)、成交金额(万元) | 25–35、65–75 | +| 市场潜力 | 25–35 | 成交金额增速(%)、类目成交增速(%) | 55–65、35–45 | +| 竞争强度 | 20–30 | 需供比、在线商品数、在线商家数 | 25–35、35–45、25–35 | +| 运营难度 | 10–20 | 自然流占比(%)、退货率(%) | 55–65、35–45 | + +## 保存与校验数据契约 + +保存到 `step2Answer` 的 JSON 结构固定为: + +```json +{ + "title": "市场机会识别与选品", + "primaryWeights": { "市场规模": 30, "市场潜力": 25, "竞争强度": 25, "运营难度": 20 }, + "dimensionWeights": { "search-count": 30, "transaction-amount": 70 }, + "correspondingWeights": { "search-count": 9, "transaction-amount": 21 } +} +``` + +校验接口请求继续使用数组字段 `primaryWeights`(`group`、`weight`)和 `dimensionWeights`(`id`、`weight`);服务端不接受客户端传入的对应总权重,并自行复核总和。 + +## 后端边界 + +现有第二步校验接口已经校验第一步完成状态、四类一级权重、九项二级权重及对应总权重总和。此次不改变接口字段或数据表结构,仅补充回归测试,确保上述规则持续有效。 + +## 验收标准 + +- 原型中的四类一级指标、九项二级指标、建议区间与顺序一致。 +- 权重输入、组内合计、对应总权重和总计均实时可见。 +- 不合格数据不能保存并进入第三步。 +- 合格数据可以保存、刷新后仍能回显。 +- 页面不含原型未提供的上传控件;已配置的案例资料维持预览与下载行为。