Merge branch 'fix/multistep-task-submit'

bugfix/ai-assessment-evidence-rescore
陈沅 1 month ago
commit 88c017ad21

@ -211,6 +211,7 @@ const uploadingPareto = ref(false);
const paretoImage = ref({ url: "", name: "" }); const paretoImage = ref({ url: "", name: "" });
const stepFour = ref(createStepFour()); const stepFour = ref(createStepFour());
const strategyRows = ref(createStrategyRows()); const strategyRows = ref(createStrategyRows());
const dynamicStepAnswers = ref({});
const modules = [ const modules = [
{ name: "帕累托 / ABC 分析", component: defineAsyncComponent(() => import("../portraitModel/components/abcAnalysis.vue")) }, { name: "帕累托 / ABC 分析", component: defineAsyncComponent(() => import("../portraitModel/components/abcAnalysis.vue")) },
{ name: "购物篮分析", component: defineAsyncComponent(() => import("../portraitModel/components/basketAnalysis.vue")) }, { name: "购物篮分析", component: defineAsyncComponent(() => import("../portraitModel/components/basketAnalysis.vue")) },
@ -241,6 +242,7 @@ function buildStepTwoProgress() { return { version: 1, rows: categoryRows.value.
function buildStepThreeProgress() { return { version: 1, imageUrl: paretoImage.value.url, imageName: paretoImage.value.name, updatedAt: new Date().toISOString() }; } function buildStepThreeProgress() { return { version: 1, imageUrl: paretoImage.value.url, imageName: paretoImage.value.name, updatedAt: new Date().toISOString() }; }
function buildStepFourProgress() { return { version: 1, ...stepFour.value, updatedAt: new Date().toISOString() }; } function buildStepFourProgress() { return { version: 1, ...stepFour.value, updatedAt: new Date().toISOString() }; }
function buildStepFiveProgress() { return { version: 1, rows: strategyRows.value.map(({ layer, operationStrategy, inventoryStrategy, resourcePriority }) => ({ layer, operationStrategy, inventoryStrategy, resourcePriority })), updatedAt: new Date().toISOString() }; } function buildStepFiveProgress() { return { version: 1, rows: strategyRows.value.map(({ layer, operationStrategy, inventoryStrategy, resourcePriority }) => ({ layer, operationStrategy, inventoryStrategy, resourcePriority })), updatedAt: new Date().toISOString() }; }
function parseSavedJson(value) { try { const parsed = typeof value === "string" ? JSON.parse(value) : value; return parsed && typeof parsed === "object" ? parsed : null; } catch (error) { return null; } }
function applyProgress(value) { function applyProgress(value) {
if (!value || typeof value !== "object") return; if (!value || typeof value !== "object") return;
activeStep.value = normalizeActiveStep(value.activeStep); activeStep.value = normalizeActiveStep(value.activeStep);
@ -251,7 +253,7 @@ function applyStepTwoProgress(value) { const classifications = new Map((Array.is
function applyStepThreeProgress(value) { paretoImage.value = { url: String(value?.imageUrl || ""), name: String(value?.imageName || "") }; } function applyStepThreeProgress(value) { paretoImage.value = { url: String(value?.imageUrl || ""), name: String(value?.imageName || "") }; }
function applyStepFourProgress(value) { stepFour.value = createStepFour(value); } function applyStepFourProgress(value) { stepFour.value = createStepFour(value); }
function applyStepFiveProgress(value) { strategyRows.value = createStrategyRows(value?.rows); } function applyStepFiveProgress(value) { strategyRows.value = createStrategyRows(value?.rows); }
async function persistProgress(saveAction = "SAVE") { await saveStudentTrainingAnswer(TASK_KEY, { saveAction, currentStep: activeStep.value, step1Answer: JSON.stringify(buildProgress()), step2Answer: JSON.stringify(buildStepTwoProgress()), step3Answer: JSON.stringify(buildStepThreeProgress()), step4Answer: JSON.stringify(buildStepFourProgress()), step5Answer: JSON.stringify(buildStepFiveProgress()) }); } async function persistProgress(saveAction = "SAVE") { dynamicStepAnswers.value = { ...dynamicStepAnswers.value, step5: buildStepFiveProgress() }; await saveStudentTrainingAnswer(TASK_KEY, { saveAction, currentStep: activeStep.value, submitted: saveAction === "SUBMIT", step1Answer: JSON.stringify(buildProgress()), step2Answer: JSON.stringify(buildStepTwoProgress()), step3Answer: JSON.stringify(buildStepThreeProgress()), step4Answer: JSON.stringify(buildStepFourProgress()), dynamicStepAnswers: JSON.stringify(dynamicStepAnswers.value) }); }
function addRow() { if (categoryRows.value.length >= MAX_ROWS) return; categoryRows.value.push(createRow()); } function addRow() { if (categoryRows.value.length >= MAX_ROWS) return; categoryRows.value.push(createRow()); }
function removeLastRow() { categoryRows.value.pop(); } function removeLastRow() { categoryRows.value.pop(); }
async function validateStepOne() { async function validateStepOne() {
@ -349,7 +351,7 @@ async function saveCurrentProgress() {
async function submitTask() { async function submitTask() {
if (saving.value || !(await validateStepOne()) || (hasConfiguredSteps.value && configuredSteps.value.length > 1 && !(await validateStepTwo())) || (hasConfiguredSteps.value && configuredSteps.value.length > 2 && !(await validateStepThree())) || (hasConfiguredSteps.value && configuredSteps.value.length > 3 && !(await validateStepFour())) || (hasConfiguredSteps.value && configuredSteps.value.length > 4 && !(await validateStepFive()))) return; if (saving.value || !(await validateStepOne()) || (hasConfiguredSteps.value && configuredSteps.value.length > 1 && !(await validateStepTwo())) || (hasConfiguredSteps.value && configuredSteps.value.length > 2 && !(await validateStepThree())) || (hasConfiguredSteps.value && configuredSteps.value.length > 3 && !(await validateStepFour())) || (hasConfiguredSteps.value && configuredSteps.value.length > 4 && !(await validateStepFive()))) return;
saving.value = true; saving.value = true;
try { await businessComponent.value?.submitData?.(); await persistProgress("SAVE"); ElMessage.success("任务已提交"); } finally { saving.value = false; } try { await businessComponent.value?.submitData?.(); await persistProgress("SUBMIT"); ElMessage.success("任务已提交"); } finally { saving.value = false; }
} }
async function resetTask() { async function resetTask() {
if (saving.value) return; if (saving.value) return;
@ -374,7 +376,7 @@ function exportOutcome() {
} }
onMounted(async () => { onMounted(async () => {
try { const res = await getTrainingTaskByKey(TASK_KEY); taskConfig.value = res?.data || null; activeStep.value = normalizeActiveStep(activeStep.value); } catch (error) { taskConfig.value = null; } try { const res = await getTrainingTaskByKey(TASK_KEY); taskConfig.value = res?.data || null; activeStep.value = normalizeActiveStep(activeStep.value); } catch (error) { taskConfig.value = null; }
try { const res = await getStudentTrainingAnswer(TASK_KEY); if (res?.data?.step1Answer) applyProgress(JSON.parse(res.data.step1Answer)); if (res?.data?.step2Answer) applyStepTwoProgress(JSON.parse(res.data.step2Answer)); if (res?.data?.step3Answer) applyStepThreeProgress(JSON.parse(res.data.step3Answer)); if (res?.data?.step4Answer) applyStepFourProgress(JSON.parse(res.data.step4Answer)); if (res?.data?.step5Answer) applyStepFiveProgress(JSON.parse(res.data.step5Answer)); } catch (error) {} try { const res = await getStudentTrainingAnswer(TASK_KEY); if (res?.data?.step1Answer) applyProgress(JSON.parse(res.data.step1Answer)); if (res?.data?.step2Answer) applyStepTwoProgress(JSON.parse(res.data.step2Answer)); if (res?.data?.step3Answer) applyStepThreeProgress(JSON.parse(res.data.step3Answer)); if (res?.data?.step4Answer) applyStepFourProgress(JSON.parse(res.data.step4Answer)); dynamicStepAnswers.value = parseSavedJson(res?.data?.dynamicStepAnswers) || {}; if (dynamicStepAnswers.value.step5) applyStepFiveProgress(dynamicStepAnswers.value.step5); } catch (error) {}
}); });
</script> </script>

@ -523,9 +523,9 @@ const labels = {
measuredResult: "测算结果", measuredResult: "测算结果",
finalAnalysisTitle: "最终量产定价分析", finalAnalysisTitle: "最终量产定价分析",
finalAnalysisPlaceholder: "请综合成本、竞品、用户感知价值和 PSM 价格敏感度,说明最终量产定价、定价依据与利润空间。", finalAnalysisPlaceholder: "请综合成本、竞品、用户感知价值和 PSM 价格敏感度,说明最终量产定价、定价依据与利润空间。",
finalPricingSave: "保存最终量产定价", finalPricingSave: "提交并完成实训",
finalPricingSaving: "保存中...", finalPricingSaving: "提交中...",
finalPricingSaveSuccess: "最终量产定价已保存", finalPricingSaveSuccess: "实训任务提交成功",
finalPricingChannelRequired: "请选择用于汇总的成本加成定价渠道。", finalPricingChannelRequired: "请选择用于汇总的成本加成定价渠道。",
finalPricingPrerequisiteRequired: "请先完成前四步定价测算,确保四种定价方法均有测算结果和毛利润率。", finalPricingPrerequisiteRequired: "请先完成前四步定价测算,确保四种定价方法均有测算结果和毛利润率。",
finalPricingAnalysisRequired: "请填写最终量产定价分析。", finalPricingAnalysisRequired: "请填写最终量产定价分析。",
@ -1077,8 +1077,9 @@ async function saveStepFive() {
finalPricingAnalysis.value = validated.finalAnalysis ?? finalPricingAnalysis.value; finalPricingAnalysis.value = validated.finalAnalysis ?? finalPricingAnalysis.value;
dynamicStepAnswers.value = { ...dynamicStepAnswers.value, step5: buildStepFiveProgress() }; dynamicStepAnswers.value = { ...dynamicStepAnswers.value, step5: buildStepFiveProgress() };
await saveStudentTrainingAnswer(TASK_KEY, { await saveStudentTrainingAnswer(TASK_KEY, {
saveAction: "SAVE", saveAction: "SUBMIT",
currentStep: 5, currentStep: 5,
submitted: true,
dynamicStepAnswers: JSON.stringify(dynamicStepAnswers.value), dynamicStepAnswers: JSON.stringify(dynamicStepAnswers.value),
}); });
hasSavedAnswer.value = true; hasSavedAnswer.value = true;

@ -0,0 +1,31 @@
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const test = require("node:test");
function readPage(relativePath) {
return fs.readFileSync(path.resolve(__dirname, "..", relativePath), "utf8");
}
test("实训19第五步提交动态答案并完成任务", () => {
const page = readPage("src/views/product/price.vue");
assert.match(page, /finalPricingSave:\s*"提交并完成实训"/);
assert.match(
page,
/async function saveStepFive\(\)\s*\{[\s\S]*?saveAction:\s*"SUBMIT",[\s\S]*?currentStep:\s*5,[\s\S]*?submitted:\s*true,[\s\S]*?dynamicStepAnswers:/
);
});
test("实训20第五步使用动态答案保存并在提交时完成任务", () => {
const page = readPage("src/views/assessment/optimization.vue");
assert.match(page, /const dynamicStepAnswers = ref\(\{\}\);/);
assert.match(
page,
/async function persistProgress\(saveAction = "SAVE"\)\s*\{[\s\S]*?step5:\s*buildStepFiveProgress\(\)[\s\S]*?dynamicStepAnswers:\s*JSON\.stringify\(dynamicStepAnswers\.value\)/
);
assert.match(page, /async function submitTask\(\)\s*\{[\s\S]*?persistProgress\("SUBMIT"\)/);
assert.match(page, /dynamicStepAnswers\.value = parseSavedJson\(res\?\.data\?\.dynamicStepAnswers\) \|\| \{\};/);
assert.doesNotMatch(page, /step5Answer:/);
});
Loading…
Cancel
Save