diff --git a/web/src/pages/NewAssessment.tsx b/web/src/pages/NewAssessment.tsx index 3a86acb..d2cff7c 100644 --- a/web/src/pages/NewAssessment.tsx +++ b/web/src/pages/NewAssessment.tsx @@ -28,6 +28,8 @@ import { getDraft, saveDraft, deleteDraftApi, + fetchAssessmentDetail, + ApiError, type DraftRecord, type ClassificationResult, type IndicatorQuestion, @@ -693,24 +695,47 @@ export function NewAssessment(): JSX.Element { const fullDescription = `【项目】${projectName || '未命名'}|【客户】${customerName || '未提供'}\n${description}`; - const result = await runAssessment({ + const knownDataArr = Object.entries(answers) + .filter((e): e is [string, number] => typeof e[1] === 'number') + .map(([k, v]): [string, number] => [k, v]); + const runWith = (expected: string | null) => runAssessment({ projectDescription: fullDescription, confirmation: { businessType, ...(industry !== '' ? { industry } : {}) }, region, ...(effectiveEditId !== null ? { assessmentId: effectiveEditId, useLlm: false } : {}), - ...(effectiveEditId !== null && editSavedAt !== null ? { expectedSavedAt: editSavedAt } : {}), + ...(effectiveEditId !== null && expected !== null ? { expectedSavedAt: expected } : {}), ...(Number(clientTotalHeadcount) > 0 ? { clientTotalHeadcount: Number(clientTotalHeadcount) } : {}), ...(user?.id !== undefined ? { assessorId: user.id } : {}), - knownData: Object.entries(answers) - .filter((e): e is [string, number] => typeof e[1] === 'number') - .map(([k, v]) => [k, v]), + knownData: knownDataArr, ...(baselineQuote > 0 ? { costInputs: { baselineQuote } } : {}), profitabilityInputs, }); + + let result; + try { + result = await runWith(editSavedAt); + } catch (e) { + // 乐观锁冲突:自动拉取最新版本号后重试一次(单人编辑场景下不应被卡住)。 + if (e instanceof ApiError && e.status === 409 && effectiveEditId !== null) { + const latest = await fetchAssessmentDetail(effectiveEditId).catch(() => null); + const freshSavedAt = latest?.savedAt ?? null; + if (freshSavedAt !== null && freshSavedAt !== editSavedAt) { + setEditSavedAt(freshSavedAt); + result = await runWith(freshSavedAt); + } else { + throw e; + } + } else { + throw e; + } + } try { await deleteDraftApi(draftId); } catch { /* ignore */ } navigate(`/assessments/${result.assessmentId}`); } catch (err) { - setError(err instanceof Error ? err.message : '评估运行失败'); + const msg = err instanceof ApiError && err.status === 409 + ? '该评估已被他人同时修改,请返回详情页刷新后重试。' + : err instanceof Error ? err.message : '评估运行失败'; + setError(msg); setRunning(false); } }