fix: clarify diagnosis sentiment validation

bugfix/ai-assessment-evidence-rescore
chenyuan 1 month ago
parent 962f3e5243
commit 10b1d140a1

@ -490,7 +490,7 @@ export function validateProductDiagnosisIterationStepTwo(payload) {
if (sentiments.length !== 3) throw new Error("请填写正面、中性、负面三类情感数据");
const total = sentiments.reduce((sum, item) => sum + Number(item?.count), 0);
if (!Number.isFinite(total) || total <= 0) throw new Error("情感评论数量合计必须大于 0");
sentiments.forEach((item) => { const expected = Number((Number(item?.count) * 100 / total).toFixed(2)); if (!Number.isFinite(Number(item?.count)) || Number(item?.count) < 0 || Number(item?.percentage) !== expected) throw new Error(`${item?.type || "情感"}评论占比计算不正确`); });
sentiments.forEach((item) => { const expected = Number((Number(item?.count) * 100 / total).toFixed(2)); if (!Number.isFinite(Number(item?.count)) || Number(item?.count) < 0 || Number(item?.percentage) !== expected) throw new Error("正面、中性、负面评论占比之和应为100%。"); });
return Promise.resolve({ code: 200, data: { valid: true, message: "情感评论占比计算校验通过" } });
} catch (error) { return Promise.reject(error); }
}

@ -120,6 +120,11 @@ function createAnomalyRow() { return { channelId: "", channel: "", linkNode: "",
function createSentiments() { return ["正面", "中性", "负面"].map((type) => ({ type, count: null, percentage: null })); }
function createAbRows() { return ["点击-加购转化率", "加购-下单转化率", "下单-好评转化率", "详情页跳出率", "退货率"].map((metric) => ({ metric, controlValue: null, experimentValue: null, analysis: "" })); }
function isRate(value) { return value !== null && value !== "" && Number.isFinite(Number(value)); }
function diagnosisErrorMessage(error, fallback) {
const serverMessage = String(error?.response?.data?.msg || "").trim();
const message = serverMessage || String(error?.message || "").trim();
return /Request failed with status code|系统接口\d{3}异常/i.test(message) ? fallback : message || fallback;
}
function buildStepOne() {
const channelSnapshot = channels.value.map((channel) => ({ id: channel.id, name: channel.name.trim() }));
return {
@ -168,7 +173,7 @@ function runSentimentAnalysis() {
}));
proxy?.$modal?.msgSuccess?.("情感评论数量与占比已自动计算");
}
async function saveStepTwoDraft() { if (saving.value) return false; saving.value = true; try { await saveStudentTrainingAnswer(TASK_KEY, { step2Answer: JSON.stringify(buildStepTwo()), currentStep: 2, submitted: false, saveAction: "SAVE" }); proxy?.$modal?.msgSuccess?.("当前步骤已保存"); return true; } catch (error) { proxy?.$modal?.msgError?.(error?.message || "保存失败,请重试"); return false; } finally { saving.value = false; } } async function validateStepTwo() { if (saving.value) return false; saving.value = true; try { const data = buildStepTwo(); await validateProductDiagnosisIterationStepTwo(data); await saveStudentTrainingAnswer(TASK_KEY, { step2Answer: JSON.stringify(data), currentStep: 2, submitted: false, saveAction: "SAVE" }); proxy?.$modal?.msgSuccess?.("第 2 步校验通过,已保存"); return true; } catch (error) { proxy?.$modal?.msgError?.(error?.message || "请检查词云、情感占比和根因分析"); return false; } finally { saving.value = false; } }
async function saveStepTwoDraft() { if (saving.value) return false; saving.value = true; try { await saveStudentTrainingAnswer(TASK_KEY, { step2Answer: JSON.stringify(buildStepTwo()), currentStep: 2, submitted: false, saveAction: "SAVE" }); proxy?.$modal?.msgSuccess?.("当前步骤已保存"); return true; } catch (error) { proxy?.$modal?.msgError?.(error?.message || "保存失败,请重试"); return false; } finally { saving.value = false; } } async function validateStepTwo() { if (saving.value) return false; saving.value = true; try { const data = buildStepTwo(); await validateProductDiagnosisIterationStepTwo(data); await saveStudentTrainingAnswer(TASK_KEY, { step2Answer: JSON.stringify(data), currentStep: 2, submitted: false, saveAction: "SAVE" }); proxy?.$modal?.msgSuccess?.("第 2 步校验通过,已保存"); return true; } catch (error) { proxy?.$modal?.msgError?.(diagnosisErrorMessage(error, "请检查词云、情感占比和根因分析")); return false; } finally { saving.value = false; } }
function clearAbChart() { if (abChart.value.url.startsWith("blob:")) URL.revokeObjectURL(abChart.value.url); abChart.value = { url: "", name: "" }; }
async function handleAbChartUpload(event) { const file = event.target?.files?.[0]; if (!file) return; const accepted = ["image/jpeg", "image/png", "image/webp"]; if (!accepted.includes(file.type) || file.size > 5 * 1024 * 1024) { proxy?.$modal?.msgError?.("请上传不超过 5MB 的 PNG、JPG 或 WEBP 图片"); event.target.value = ""; return; } uploading.value = true; try { let url = ""; if (isStudentDemo()) url = URL.createObjectURL(file); else { const data = new FormData(); data.append("file", file); const response = await uploadStudentTrainingFile(data); url = response?.url || response?.data?.url || ""; } if (!url) throw new Error("上传成功但未返回图片地址"); clearAbChart(); abChart.value = { url, name: file.name }; proxy?.$modal?.msgSuccess?.("AB 测试结果对比图上传成功,可点击图片预览"); } catch (error) { proxy?.$modal?.msgError?.(error?.message || "图片上传失败,请重试"); } finally { uploading.value = false; event.target.value = ""; } }
async function saveStepThreeDraft() { if (saving.value) return; saving.value = true; try { await saveStudentTrainingAnswer(TASK_KEY, { step3Answer: JSON.stringify(buildStepThree()), currentStep: 3, submitted: false, saveAction: "SAVE" }); proxy?.$modal?.msgSuccess?.("草稿已保存"); } catch (error) { proxy?.$modal?.msgError?.(error?.message || "保存失败,请重试"); } finally { saving.value = false; } }
@ -199,7 +204,7 @@ async function submitTask() {
proxy?.$modal?.msgSuccess?.("实训任务已提交");
return true;
} catch (error) {
proxy?.$modal?.msgError?.(error?.message || "提交失败,请检查三个步骤的填写内容");
proxy?.$modal?.msgError?.(diagnosisErrorMessage(error, "提交失败,请检查三个步骤的填写内容"));
return false;
} finally {
saving.value = false;

@ -42,4 +42,7 @@ test("三个步骤的后端校验错误均交由页面显示单条中文提示",
api.indexOf("export function validatePromotionEffectOptimizationStepOne")
);
assert.equal((validationBlock.match(/skipErrorMessage:\s*true/g) || []).length, 3);
assert.match(api, /throw new Error\("正面、中性、负面评论占比之和应为100%。"\)/);
assert.match(page, /function diagnosisErrorMessage[\s\S]*?Request failed with status code/);
assert.match(page, /validateStepTwo[\s\S]*?diagnosisErrorMessage\(error/);
});

Loading…
Cancel
Save