From 3f4763bc0f54d9d39dddce025758e3a290f95438 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Fri, 7 Aug 2026 18:12:37 +0800 Subject: [PATCH 1/4] feat: add market opportunity selection step one --- src/api/studentTrainingAnswer.js | 14 +++++ src/router/index.js | 2 +- .../product/market-opportunity-selection.vue | 58 +++++++++++++++++++ 3 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/views/product/market-opportunity-selection.vue diff --git a/src/api/studentTrainingAnswer.js b/src/api/studentTrainingAnswer.js index 161310f..8762849 100644 --- a/src/api/studentTrainingAnswer.js +++ b/src/api/studentTrainingAnswer.js @@ -95,6 +95,20 @@ export function checkNewProductSurveyStepOne(items) { }); } +export function checkMarketOpportunitySelectionStepOne(items) { + const expected = { + "search-count": "市场规模", "demand-supply-ratio": "竞争强度", "transaction-amount": "市场规模", "transaction-growth": "市场潜力", + "category-transaction-growth": "市场潜力", "online-products": "竞争强度", "online-merchants": "竞争强度", "organic-traffic-ratio": "运营难度", + }; + if (isStudentDemo()) { + const list = Array.isArray(items) ? items : []; + const incorrect = list.find((item) => expected[item?.id] !== item?.category); + if (list.length !== Object.keys(expected).length || incorrect) return Promise.reject(new Error("指标分类有误,请根据提示重新选择")); + return Promise.resolve({ code: 200, data: { correctCount: Object.keys(expected).length, totalCount: Object.keys(expected).length, allCorrect: true, message: "校验通过" } }); + } + return request({ url: "/api/student-training-answers/market-opportunity-selection/step-1/check", method: "post", data: { items }, headers: { repeatSubmit: false } }); +} + function validateNewProductSurveyStepTwoDemo(form) { const value = form || {}; const images = Array.isArray(value.images) ? value.images : []; diff --git a/src/router/index.js b/src/router/index.js index e0d49b8..1a2dbf7 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -286,7 +286,7 @@ export const dynamicRoutes = [ // 产品定位 { path: "index", - component: () => import("@/views/product/index.vue"), + component: () => import("@/views/product/market-opportunity-selection.vue"), name: "product", meta: { title: "市场机会识别与选品", icon: "产品规划", affix: true, pageKey: "market-opportunity-selection" }, }, diff --git a/src/views/product/market-opportunity-selection.vue b/src/views/product/market-opportunity-selection.vue new file mode 100644 index 0000000..b092468 --- /dev/null +++ b/src/views/product/market-opportunity-selection.vue @@ -0,0 +1,58 @@ + + + + + From a3649d9f5e9a9c60395f4419a0dcf2d333266aa4 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Fri, 7 Aug 2026 18:51:17 +0800 Subject: [PATCH 2/4] feat: add market opportunity selection step two --- src/api/studentTrainingAnswer.js | 14 ++++++++ .../product/market-opportunity-selection.vue | 32 +++++++++++++------ 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/api/studentTrainingAnswer.js b/src/api/studentTrainingAnswer.js index 8762849..dcaf94f 100644 --- a/src/api/studentTrainingAnswer.js +++ b/src/api/studentTrainingAnswer.js @@ -109,6 +109,20 @@ export function checkMarketOpportunitySelectionStepOne(items) { return request({ url: "/api/student-training-answers/market-opportunity-selection/step-1/check", method: "post", data: { items }, headers: { repeatSubmit: false } }); } +export function checkMarketOpportunitySelectionStepTwo(payload) { + const weights = Array.isArray(payload?.weights) ? payload.weights : []; + const expectedIds = ["search-count", "transaction-amount", "transaction-growth", "category-transaction-growth", "demand-supply-ratio", "online-products", "online-merchants", "organic-traffic-ratio"]; + if (isStudentDemo()) { + const ids = new Set(weights.map((item) => item?.id)); + const total = weights.reduce((sum, item) => sum + Number(item?.weight || 0), 0); + if (weights.length !== expectedIds.length || expectedIds.some((id) => !ids.has(id)) || weights.some((item) => !Number.isInteger(Number(item?.weight)) || Number(item.weight) < 1 || Number(item.weight) > 100) || total !== 100) { + return Promise.reject(new Error("二级指标权重需为 1 至 100 的整数,且合计必须为 100%")); + } + return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } }); + } + return request({ url: "/api/student-training-answers/market-opportunity-selection/step-2/validate", method: "post", data: { weights }, headers: { repeatSubmit: false } }); +} + function validateNewProductSurveyStepTwoDemo(form) { const value = form || {}; const images = Array.isArray(value.images) ? value.images : []; diff --git a/src/views/product/market-opportunity-selection.vue b/src/views/product/market-opportunity-selection.vue index b092468..e0d9379 100644 --- a/src/views/product/market-opportunity-selection.vue +++ b/src/views/product/market-opportunity-selection.vue @@ -13,7 +13,15 @@
序号指标分类
{{ index + 1 }}{{ item.name }}
-

第 {{ currentStep }} 步内容待配置

第 1 步指标分类已保存,可返回查看。
+ +

第 {{ currentStep }} 步内容待配置

已保存的步骤可从上方步骤栏返回查看。
@@ -23,7 +31,7 @@ From cdb9a51035417dc103a91af903350d322fe876f8 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Fri, 7 Aug 2026 18:58:13 +0800 Subject: [PATCH 3/4] feat: add market opportunity selection step three --- src/api/studentTrainingAnswer.js | 13 +++++++++ .../product/market-opportunity-selection.vue | 28 +++++++++++++++---- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/api/studentTrainingAnswer.js b/src/api/studentTrainingAnswer.js index dcaf94f..00a5308 100644 --- a/src/api/studentTrainingAnswer.js +++ b/src/api/studentTrainingAnswer.js @@ -123,6 +123,19 @@ export function checkMarketOpportunitySelectionStepTwo(payload) { return request({ url: "/api/student-training-answers/market-opportunity-selection/step-2/validate", method: "post", data: { weights }, headers: { repeatSubmit: false } }); } +export function checkMarketOpportunitySelectionStepThree(payload) { + const scores = Array.isArray(payload?.scores) ? payload.scores : []; + const expectedIds = ["smart-fitness-mirror", "smart-bathroom-mirror", "smart-beauty-mirror"]; + if (isStudentDemo()) { + const ids = new Set(scores.map((item) => item?.id)); + if (scores.length !== expectedIds.length || expectedIds.some((id) => !ids.has(id)) || scores.some((item) => !Number.isFinite(Number(item?.score)) || Number(item.score) < 0 || Number(item.score) > 100)) { + return Promise.reject(new Error("请为三类产品填写 0 至 100 分的综合得分")); + } + return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } }); + } + return request({ url: "/api/student-training-answers/market-opportunity-selection/step-3/validate", method: "post", data: { scores }, headers: { repeatSubmit: false } }); +} + function validateNewProductSurveyStepTwoDemo(form) { const value = form || {}; const images = Array.isArray(value.images) ? value.images : []; diff --git a/src/views/product/market-opportunity-selection.vue b/src/views/product/market-opportunity-selection.vue index e0d9379..4dc7982 100644 --- a/src/views/product/market-opportunity-selection.vue +++ b/src/views/product/market-opportunity-selection.vue @@ -21,6 +21,14 @@
一级指标二级指标权重(%)
{{ item.group }}({{ groupWeight(item.group) }}%){{ item.name }}%
+

第 {{ currentStep }} 步内容待配置

已保存的步骤可从上方步骤栏返回查看。
@@ -31,7 +39,7 @@ From a98aa2989939aeed97c3d3d0703e867ca8dded38 Mon Sep 17 00:00:00 2001 From: chenyuan Date: Fri, 7 Aug 2026 19:36:28 +0800 Subject: [PATCH 4/4] feat: add market opportunity selection step four --- src/api/studentTrainingAnswer.js | 9 ++++++ .../product/market-opportunity-selection.vue | 30 +++++++++++++++---- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/api/studentTrainingAnswer.js b/src/api/studentTrainingAnswer.js index 00a5308..4be51d4 100644 --- a/src/api/studentTrainingAnswer.js +++ b/src/api/studentTrainingAnswer.js @@ -136,6 +136,15 @@ export function checkMarketOpportunitySelectionStepThree(payload) { return request({ url: "/api/student-training-answers/market-opportunity-selection/step-3/validate", method: "post", data: { scores }, headers: { repeatSubmit: false } }); } +export function checkMarketOpportunitySelectionStepFour(payload) { + const visualizationUrl = String(payload?.visualizationUrl || "").trim(); + if (isStudentDemo()) { + if (!visualizationUrl) return Promise.reject(new Error("请上传数据可视化结果图")); + return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } }); + } + return request({ url: "/api/student-training-answers/market-opportunity-selection/step-4/validate", method: "post", data: { visualizationUrl }, headers: { repeatSubmit: false } }); +} + function validateNewProductSurveyStepTwoDemo(form) { const value = form || {}; const images = Array.isArray(value.images) ? value.images : []; diff --git a/src/views/product/market-opportunity-selection.vue b/src/views/product/market-opportunity-selection.vue index 4dc7982..fb80dcb 100644 --- a/src/views/product/market-opportunity-selection.vue +++ b/src/views/product/market-opportunity-selection.vue @@ -29,6 +29,19 @@

推荐工具及方法如下,自行选择:

1. Excel/WPS 表格,自行操作计算,可参考《实训操作说明》完成。

2. 下载 Excel 模板,填写关键数据,完成指标计算。

3. 导出实训数据表,上传到通用 AI 大模型,参考提示词完成计算。

请根据数据表及各指标权重设定表,通过 Min-Max 归一法计算各二级指标得分,采用加权评分法计算综合得分。

+

第 {{ currentStep }} 步内容待配置

已保存的步骤可从上方步骤栏返回查看。
@@ -38,9 +51,10 @@