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/src/api/studentTrainingAnswer.js

495 lines
21 KiB
JavaScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import request from "@/utils/request";
import { getDemoAnswerKey, getStudentDemoSession, isStudentDemo } from "@/utils/studentDemo";
const newProductSurveyStepOneAnswers = {
"selling-point-1": "核心层",
"selling-point-2": "有形层",
"selling-point-3": "核心层",
"selling-point-4": "核心层",
"selling-point-5": "有形层",
"selling-point-6": "有形层",
"selling-point-7": "有形层",
"selling-point-8": "延伸层",
"selling-point-9": "延伸层",
"selling-point-10": "延伸层",
"selling-point-11": "有形层",
};
function demoResult(taskKey) {
try { return JSON.parse(sessionStorage.getItem(getDemoAnswerKey(taskKey)) || "null"); } catch (error) { return null; }
}
export function getStudentTrainingAnswer(taskKey, params) {
if (isStudentDemo()) return Promise.resolve({ code: 200, data: demoResult(taskKey) });
return request({
url: `/api/student-training-answers/${taskKey}`,
method: "get",
params,
});
}
export function saveStudentTrainingAnswer(taskKey, data) {
if (isStudentDemo()) {
const answer = { ...data, teachingClassId: getStudentDemoSession()?.userInfo?.demoTeachingClassId };
sessionStorage.setItem(getDemoAnswerKey(taskKey), JSON.stringify(answer));
return Promise.resolve({ code: 200, data: answer });
}
return request({
url: `/api/student-training-answers/${taskKey}`,
method: "post",
data,
headers: { repeatSubmit: false },
});
}
export function deleteStudentTrainingAnswer(taskKey, params) {
if (isStudentDemo()) { sessionStorage.removeItem(getDemoAnswerKey(taskKey)); return Promise.resolve({ code: 200 }); }
return request({
url: `/api/student-training-answers/${taskKey}`,
method: "delete",
params,
});
}
export function uploadStudentTrainingFile(data) {
if (isStudentDemo()) return Promise.reject(new Error("演示模式不上传文件"));
return request({
url: "/common/upload",
method: "post",
data,
headers: {
"Content-Type": "multipart/form-data",
repeatSubmit: false,
},
});
}
export function checkNewProductSurveyStepOne(items) {
if (isStudentDemo()) {
const results = Array.isArray(items)
? items.map((item) => {
const correct = newProductSurveyStepOneAnswers[item?.id] === item?.category;
return {
id: item?.id,
correct,
message: correct ? "分类正确" : "分类有误,请重新选择",
};
})
: [];
const correctCount = results.filter((item) => item.correct).length;
return Promise.resolve({
code: 200,
data: {
items: results,
correctCount,
totalCount: results.length,
allCorrect: results.length === Object.keys(newProductSurveyStepOneAnswers).length && correctCount === results.length,
},
});
}
return request({
url: "/api/student-training-answers/new-product-survey/step-1/check",
method: "post",
data: { items },
headers: { repeatSubmit: false },
});
}
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 } });
}
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 } });
}
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 } });
}
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 : [];
if (!['京东', '天猫', '抖音电商'].includes(String(value.platform || '').trim())) {
throw new Error('请选择调查平台');
}
if (!String(value.scene || '').trim()) {
throw new Error('请选择调查场景');
}
if (value.scene === '其他场景' && !String(value.customScene || '').trim()) {
throw new Error('请填写自定义调查场景');
}
if (!String(value.keyword || '').trim()) {
throw new Error('请填写搜索关键词');
}
if (!String(value.productName || '').trim()) {
throw new Error('请填写产品名称');
}
if (images.length < 1 || images.length > 5 || images.some((image) => !String(image?.url || '').trim())) {
throw new Error('请上传 1 至 5 张产品图片');
}
return { valid: true, message: '校验通过' };
}
export function checkNewProductSurveyStepTwo(form) {
if (isStudentDemo()) {
try {
return Promise.resolve({ code: 200, data: validateNewProductSurveyStepTwoDemo(form) });
} catch (error) {
return Promise.reject(error);
}
}
return request({
url: '/api/student-training-answers/new-product-survey/step-2/validate',
method: 'post',
data: { ...form, imageUrls: (form?.images || []).map((image) => image?.url) },
headers: { repeatSubmit: false },
});
}
function validateNewProductSurveyStepThreeDemo(payload) {
const expectedDimensions = ["核心层", "有形层", "延伸层"];
const rows = Array.isArray(payload?.rows) ? payload.rows : [];
if (rows.length !== expectedDimensions.length) {
throw new Error("请完成核心层、有形层、延伸层分析");
}
const dimensions = rows.map((row) => String(row?.dimension || "").trim());
if (new Set(dimensions).size !== expectedDimensions.length || expectedDimensions.some((dimension) => !dimensions.includes(dimension))) {
throw new Error("分析维度不完整或重复");
}
const invalidRow = rows.find((row) => {
const points = Array.isArray(row?.points) ? row.points : [];
return points.map((point) => String(point || "").trim()).filter(Boolean).length < 2;
});
if (invalidRow) {
throw new Error(`${invalidRow.dimension || "该层"}至少填写 2 条分析要点`);
}
return { valid: true, message: "校验通过" };
}
export function checkNewProductSurveyStepThree(payload) {
if (isStudentDemo()) {
try {
return Promise.resolve({ code: 200, data: validateNewProductSurveyStepThreeDemo(payload) });
} catch (error) {
return Promise.reject(error);
}
}
return request({
url: "/api/student-training-answers/new-product-survey/step-3/validate",
method: "post",
data: payload,
headers: { repeatSubmit: false },
});
}
function validateNewProductSurveyStepFourDemo(form) {
const value = form || {};
const fields = [
["coreValue", "核心层"],
["tangibleValue", "有形层"],
["extendedValue", "延伸层"],
];
for (const [field, label] of fields) {
if (!String(value[field] || "").trim()) {
throw new Error(`请填写${label}AI应用价值分析`);
}
}
return { valid: true, message: "校验通过" };
}
export function checkNewProductSurveyStepFour(form) {
if (isStudentDemo()) {
try {
return Promise.resolve({ code: 200, data: validateNewProductSurveyStepFourDemo(form) });
} catch (error) {
return Promise.reject(error);
}
}
return request({
url: "/api/student-training-answers/new-product-survey/step-4/validate",
method: "post",
data: form,
headers: { repeatSubmit: false },
});
}
const productDevelopmentFactorsStepOneDimensions = ["用户需求真实性", "产品体验闭环", "生态与兼容"];
function validateProductDevelopmentFactorsStepOneDemo(payload) {
const factors = Array.isArray(payload?.factors) ? payload.factors : [];
if (factors.length !== productDevelopmentFactorsStepOneDimensions.length) {
throw new Error("请完成用户需求真实性、产品体验闭环和生态与兼容分析");
}
const dimensions = factors.map((factor) => String(factor?.dimension || "").trim());
if (new Set(dimensions).size !== productDevelopmentFactorsStepOneDimensions.length
|| productDevelopmentFactorsStepOneDimensions.some((dimension) => !dimensions.includes(dimension))) {
throw new Error("提交的分析维度不完整或重复");
}
const incompleteFactor = factors.find((factor) => !String(factor?.successAnalysis || "").trim()
|| !String(factor?.failedAnalysis || "").trim());
if (incompleteFactor) {
throw new Error(`请完成${incompleteFactor.dimension || "该项"}的成功产品和失败产品分析`);
}
return { valid: true, message: "校验通过" };
}
export function checkProductDevelopmentFactorsStepOne(payload) {
if (isStudentDemo()) {
try {
return Promise.resolve({ code: 200, data: validateProductDevelopmentFactorsStepOneDemo(payload) });
} catch (error) {
return Promise.reject(error);
}
}
return request({
url: "/api/student-training-answers/product-development-factors/step-1/validate",
method: "post",
data: payload,
headers: { repeatSubmit: false },
});
}
const productDevelopmentFactorsStepTwoDimensions = ["技术应用", "合规与认证"];
function validateProductDevelopmentFactorsStepTwoDemo(payload) {
const factors = Array.isArray(payload?.factors) ? payload.factors : [];
const dimensions = factors.map((factor) => String(factor?.dimension || "").trim());
if (factors.length !== 2 || new Set(dimensions).size !== 2 || productDevelopmentFactorsStepTwoDimensions.some((dimension) => !dimensions.includes(dimension))) throw new Error("请完成技术应用和合规与认证分析");
const incomplete = factors.find((factor) => !String(factor?.successAnalysis || "").trim() || !String(factor?.failedAnalysis || "").trim());
if (incomplete) throw new Error(`请完成${incomplete.dimension || "该项"}的成功产品和失败产品分析`);
return { valid: true, message: "校验通过" };
}
export function checkProductDevelopmentFactorsStepTwo(payload) {
if (isStudentDemo()) { try { return Promise.resolve({ code: 200, data: validateProductDevelopmentFactorsStepTwoDemo(payload) }); } catch (error) { return Promise.reject(error); } }
return request({ url: "/api/student-training-answers/product-development-factors/step-2/validate", method: "post", data: payload, headers: { repeatSubmit: false } });
}
const productDevelopmentFactorsStepThreeDimensions = ["供应链与成本控制", "商业模式", "市场反馈"];
function validateProductDevelopmentFactorsStepThreeDemo(payload) {
const factors = Array.isArray(payload?.factors) ? payload.factors : [];
const dimensions = factors.map((factor) => String(factor?.dimension || "").trim());
if (factors.length !== productDevelopmentFactorsStepThreeDimensions.length
|| new Set(dimensions).size !== productDevelopmentFactorsStepThreeDimensions.length
|| productDevelopmentFactorsStepThreeDimensions.some((dimension) => !dimensions.includes(dimension))) {
throw new Error("请完成供应链与成本控制、商业模式和市场反馈分析");
}
const incomplete = factors.find((factor) => !String(factor?.successAnalysis || "").trim()
|| !String(factor?.failedAnalysis || "").trim());
if (incomplete) throw new Error(`请完成${incomplete.dimension || "该项"}的成功产品和失败产品分析`);
return { valid: true, message: "校验通过" };
}
export function checkProductDevelopmentFactorsStepThree(payload) {
if (isStudentDemo()) {
try { return Promise.resolve({ code: 200, data: validateProductDevelopmentFactorsStepThreeDemo(payload) }); }
catch (error) { return Promise.reject(error); }
}
return request({ url: "/api/student-training-answers/product-development-factors/step-3/validate", method: "post", data: payload, headers: { repeatSubmit: false } });
}
export function checkProductDevelopmentFactorsStepFour(payload) {
const value = payload || {};
if (isStudentDemo()) {
if (!String(value.successFactors || "").trim()) return Promise.reject(new Error("请填写产品成功的关键因素"));
if (!String(value.failedFactors || "").trim()) return Promise.reject(new Error("请填写产品失败的关键因素"));
return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } });
}
return request({ url: "/api/student-training-answers/product-development-factors/step-4/validate", method: "post", data: payload, headers: { repeatSubmit: false } });
}
export function checkConsumerBehaviorStepOne(payload) {
const hypotheses = Array.isArray(payload?.hypotheses) ? payload.hypotheses : [];
if (isStudentDemo()) {
const incomplete = hypotheses.find((item) => ["targetGroup", "keyFinding", "coreHypothesis"].some((field) => !String(item?.[field] || "").trim()));
if (!hypotheses.length || incomplete) {
return Promise.reject(new Error("请完整填写目标人群、实训8关键发现和问卷核心假设"));
}
return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } });
}
return request({
url: "/api/student-training-answers/consumer-behavior/step-1/validate",
method: "post",
data: { hypotheses },
headers: { repeatSubmit: false },
});
}
export function checkConsumerBehaviorStepTwo(payload) {
const needs = Array.isArray(payload?.needs) ? payload.needs : [];
const allowedTypes = ["基本型", "期望型", "兴奋型", "无差异型", "反向型"];
if (isStudentDemo()) {
const incomplete = needs.find((item) => !String(item?.feature || "").trim()
|| !allowedTypes.includes(item?.kanoType) || !String(item?.featureDirection || "").trim());
if (!needs.length || needs.length > 20 || incomplete) {
return Promise.reject(new Error("请完整填写功能、KANO类型和对应功能方向最多20行"));
}
return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } });
}
return request({
url: "/api/student-training-answers/consumer-behavior/step-2/validate",
method: "post",
data: { needs },
headers: { repeatSubmit: false },
});
}
export function checkConsumerBehaviorStepThree(payload) {
if (isStudentDemo()) {
const importedDocumentUrl = String(payload?.importedDocumentUrl || "").trim();
const questions = Array.isArray(payload?.questions) ? payload.questions : [];
const requiredSections = ["基本信息", "购买行为", "需求偏好", "开放建议"];
const validQuestions = questions.filter((item) => String(item?.title || "").trim());
const complete = requiredSections.every((section) => validQuestions.some((item) => item.section === section))
&& validQuestions.some((item) => item.section === "需求偏好" && item.type === "LIKERT");
if (!importedDocumentUrl && !complete) {
return Promise.reject(new Error("请完整设计包含四个部分且含Likert五级量表的问卷或导入Word问卷"));
}
return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } });
}
return request({
url: "/api/student-training-answers/consumer-behavior/step-3/validate",
method: "post",
data: payload,
headers: { repeatSubmit: false },
});
}
export function previewConsumerBehaviorQuestionnaireWord(data) {
if (isStudentDemo()) {
return Promise.reject(new Error("演示模式不支持 Word 文档预览"));
}
return request({
url: "/api/student-training-answers/consumer-behavior/step-3/word-preview",
method: "post",
data,
headers: {
"Content-Type": "multipart/form-data",
repeatSubmit: false,
},
});
}
export function checkConsumerBehaviorStepFour(payload) {
if (isStudentDemo()) {
const rows = Array.isArray(payload?.rows) ? payload.rows : [];
if (rows.length < 5 || rows.some((item) => !String(item?.title || "").trim() || !String(item?.content || "").trim())) {
return Promise.reject(new Error("请完整填写 5 个问卷调研报告模块的标题和内容"));
}
return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } });
}
return request({
url: "/api/student-training-answers/consumer-behavior/step-4/validate",
method: "post",
data: payload,
headers: { repeatSubmit: false },
});
}
export function checkProductValuePositioningStepOne(payload) {
const rows = Array.isArray(payload?.rows) ? payload.rows : [];
const types = ["核心痛点1", "核心痛点2", "核心痛点3", "弱需求", "伪需求"];
if (isStudentDemo()) {
const valid = rows.length === types.length && rows.every((row, index) => row?.id === index + 1
&& row?.type === types[index]
&& Boolean(String(row?.description || "").trim())
&& Boolean(String(row?.scene || "").trim()));
return Promise.resolve({
code: 200,
data: {
valid,
message: valid ? "核心痛点分类填写完整。" : "请完成 3 个核心痛点、弱需求和伪需求的描述与场景。",
},
});
}
return request({
url: "/api/student-training-answers/product-value-positioning/step-1/validate",
method: "post",
data: { rows },
headers: { repeatSubmit: false },
});
}
export function checkProductValuePositioningStepTwo(payload) {
const customerProfile = payload?.customerProfile || {};
const valueMap = payload?.valueMap || {};
if (isStudentDemo()) {
const requiredValues = [
customerProfile.jobs, customerProfile.pains, customerProfile.gains,
valueMap.products, valueMap.painRelievers, valueMap.gainCreators,
payload?.canvasUrl,
];
const valid = requiredValues.every((item) => Boolean(String(item || "").trim()));
return Promise.resolve({
code: 200,
data: {
valid,
message: valid ? "价值主张画布填写完整。" : "请完整填写用户档案、产品价值地图并上传产品价值主张画布。",
},
});
}
return request({
url: "/api/student-training-answers/product-value-positioning/step-2/validate",
method: "post",
data: payload,
headers: { repeatSubmit: false },
});
}
export function checkProductValuePositioningStepThree(payload) {
const statements = Array.isArray(payload?.statements) ? payload.statements : [];
const requiredFields = ["targetUser", "productName", "productCategory", "coreValue", "differentiationReason"];
if (isStudentDemo()) {
const valid = statements.length === 2 && statements.every((statement, index) => statement?.id === index + 1
&& requiredFields.every((field) => Boolean(String(statement?.[field] || "").trim())));
return Promise.resolve({
code: 200,
data: { valid, message: valid ? "两版定位陈述填写完整。" : "请完整填写两个产品价值定位陈述版本。" },
});
}
return request({
url: "/api/student-training-answers/product-value-positioning/step-3/validate",
method: "post",
data: { statements },
headers: { repeatSubmit: false },
});
}