diff --git a/src/api/studentTrainingAnswer.js b/src/api/studentTrainingAnswer.js index 7cf4307..5bdf7fe 100644 --- a/src/api/studentTrainingAnswer.js +++ b/src/api/studentTrainingAnswer.js @@ -1759,3 +1759,57 @@ export function checkIndustryDemandAnalysisStepOne(payload) { const value = payl export function checkIndustryDemandAnalysisStepTwo(payload) { const value = payload || {}; if (isStudentDemo()) { try { return Promise.resolve({ code: 200, data: checkIndustryDemandDemo(value, ["political", "economic", "social", "technology"]) }); } catch (error) { return Promise.reject(error); } } return request({ url: "/api/student-training-answers/industry-demand-analysis/step-2/validate", method: "post", data: value, headers: { repeatSubmit: false } }); } export function checkIndustryDemandAnalysisStepThree(payload) { const rows = Array.isArray(payload?.rows) ? payload.rows : []; if (isStudentDemo()) { const valid = rows.length === 4 && ["political", "economic", "social", "technology"].every((dimension) => rows.some((row) => row?.dimension === dimension && String(row?.opportunities || "").trim() && String(row?.challenges || "").trim() && String(row?.strategies || "").trim())); return Promise.resolve({ code: 200, data: { valid, message: valid ? "校验通过" : "请完成四个维度的机会、挑战和策略" } }); } return request({ url: "/api/student-training-answers/industry-demand-analysis/step-3/validate", method: "post", data: { rows }, headers: { repeatSubmit: false } }); } export function checkIndustryDemandAnalysisStepFour(payload) { const value = payload || {}; if (isStudentDemo()) { const valid = ["高度友好", "较为友好", "中性", "存在风险", "风险较高"].includes(String(value.overallAssessment || "").trim()) && ["建议进入", "谨慎进入", "建议暂缓"].includes(String(value.marketDecision || "").trim()) && String(value.decisionReason || "").trim(); return Promise.resolve({ code: 200, data: { valid, message: valid ? "校验通过" : "请完整填写总体评估、市场进入结论和理由" } }); } return request({ url: "/api/student-training-answers/industry-demand-analysis/step-4/validate", method: "post", data: value, headers: { repeatSubmit: false } }); } + +export function checkTargetUserProfileStepOne(payload) { + const value = payload || {}; + if (isStudentDemo()) { + const fileName = String(value.excelName || "").trim(); + const fileUrl = String(value.excelUrl || "").trim(); + if (!fileUrl || !/\.xlsx?$/i.test(fileName)) return Promise.reject(new Error("请上传 RFM 用户分层分析结果 Excel 数据")); + if (Number(value.previewRowCount || 0) < 1 || Number(value.previewColumnCount || 0) < 1) return Promise.reject(new Error("Excel 文件需要包含可预览的表头和数据")); + return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } }); + } + return request({ url: "/api/student-training-answers/target-user-profile/step-1/validate", method: "post", data: value, headers: { repeatSubmit: false } }); +} +export function checkTargetUserProfileStepTwo(payload) { + const charts = Array.isArray(payload?.charts) ? payload.charts : []; + if (isStudentDemo()) { + const expectedTypes = ["segment-share", "average-spend", "score-heatmap"]; + const types = new Set(charts.map((chart) => chart?.type)); + const invalid = charts.find((chart) => !String(chart?.url || "").trim() || !/\.(png|jpe?g|webp)$/i.test(String(chart?.name || ""))); + if (charts.length !== expectedTypes.length || expectedTypes.some((type) => !types.has(type)) || invalid) return Promise.reject(new Error("请上传三类 RFM 分析图")); + return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } }); + } + return request({ url: "/api/student-training-answers/target-user-profile/step-2/validate", method: "post", data: { charts }, headers: { repeatSubmit: false } }); +} +export function checkTargetUserProfileStepThree(payload) { + const insights = Array.isArray(payload?.insights) ? payload.insights : []; + if (isStudentDemo()) { + const expected = ["高价值用户占比", "用户活跃度", "消费能力", "用户忠诚度", "重点客户群特征"]; + const dimensions = new Set(insights.map((item) => item?.dimension)); + if (insights.length !== expected.length || expected.some((item) => !dimensions.has(item)) || insights.some((item) => !String(item?.analysis || "").trim())) return Promise.reject(new Error("请完成五个 RFM 用户群体特点分析维度")); + return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } }); + } + return request({ url: "/api/student-training-answers/target-user-profile/step-3/validate", method: "post", data: { insights }, headers: { repeatSubmit: false } }); +} +export function checkTargetUserProfileStepFour(payload) { + const records = Array.isArray(payload?.records) ? payload.records : []; + if (isStudentDemo()) { + const expected = ["U01", "U02", "U03"]; + const codes = new Set(records.map((item) => item?.code)); + const fields = ["user", "basicAttributes", "tags", "behavior", "painPoints", "psychology"]; + if (records.length !== expected.length || expected.some((code) => !codes.has(code)) || records.some((item) => fields.some((field) => !String(item?.[field] || "").trim()))) return Promise.reject(new Error("请完成三位重点用户的完整画像")); + return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } }); + } + return request({ url: "/api/student-training-answers/target-user-profile/step-4/validate", method: "post", data: { records }, headers: { repeatSubmit: false } }); +} +export function checkTargetUserProfileStepFive(payload) { + const value = payload || {}; + const segments = Array.isArray(value.segments) ? value.segments : []; + if (isStudentDemo()) { + const fields = ["market", "attractiveness", "painPoints", "behaviorCharacteristics", "productOpportunity"]; + if (!segments.length || segments.length > 6 || !String(value.marketSelection || "").trim() || segments.some((item) => fields.some((field) => !String(item?.[field] || "").trim()))) return Promise.reject(new Error("请完成细分市场分析表和市场选择结论")); + return Promise.resolve({ code: 200, data: { valid: true, message: "校验通过" } }); + } + return request({ url: "/api/student-training-answers/target-user-profile/step-5/validate", method: "post", data: { segments, marketSelection: String(value.marketSelection || "") }, headers: { repeatSubmit: false } }); +} diff --git a/src/views/demand/people.vue b/src/views/demand/people.vue index 2622c94..9fa9253 100644 --- a/src/views/demand/people.vue +++ b/src/views/demand/people.vue @@ -51,34 +51,117 @@

- 通过电商数据平台,搜索“智能吸顶灯”、助眠产品等产品的客户群画像。如没有电商数据平台账号,可通过百度指数进行搜索,并将搜索结果截图,进行分析。 + 公司团队通过第三方数据公司采集了电商数据上购买相关产品的用户行为数据,包含用户 ID、最近购买天数(R)、购买次数(F)、消费金额(M)等字段。请完成 RFM 分析和用户分层后,上传分析结果 Excel 数据。

- + - 上传客户群画像搜索结果 + 上传 RFM 用户分层分析结果 Excel 数据
{{ form.profileFileName }}
+ + 预览数据 +
+

仅支持 .xls、.xlsx 文件,上传后可预览首个工作表的表头和前 20 行数据。

-