From 3716564b58f9849dcae789318a1c784643f9c085 Mon Sep 17 00:00:00 2001 From: freedakgmail Date: Sun, 14 Jun 2026 10:20:53 +0800 Subject: [PATCH] =?UTF-8?q?feat(profitability):=20=E7=AC=AC=E2=91=A4?= =?UTF-8?q?=E6=AD=A5=E6=8A=A5=E4=BB=B7=E5=A1=AB=E5=86=99=E6=97=B6=E5=AE=9E?= =?UTF-8?q?=E6=97=B6=E6=8F=90=E7=A4=BA=E6=8A=A5=E4=BB=B7=E5=8F=A3=E5=BE=84?= =?UTF-8?q?=E4=B8=8D=E8=B6=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 revenueWarning 实时计算:随岗位单价/加成率/管理费/合同总额变化即时判断 - 报价信息不足时在报价模式区下方显示醒目橙色 alert 横幅,明确指出该填哪个字段 - 与运行前 handleRun 校验形成双重保障(填写时提示+运行时拦截) --- web/src/pages/NewAssessment.tsx | 48 +++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/web/src/pages/NewAssessment.tsx b/web/src/pages/NewAssessment.tsx index 38ffa51..c598dd7 100644 --- a/web/src/pages/NewAssessment.tsx +++ b/web/src/pages/NewAssessment.tsx @@ -763,6 +763,31 @@ export function NewAssessment(): JSX.Element { const answeredCount = Object.values(answers).filter((v) => typeof v === 'number').length; const totalIndicators = indicators.length; + /* --------- 实时报价口径校验:判断当前填写是否足以产生收入(用于第⑤步即时提示) --------- */ + const revenueWarning: string | null = (() => { + const toNum = (s: string): number | undefined => { + const t = s.replace(/,/g, '').trim(); + return t !== '' && Number.isFinite(Number(t)) ? Number(t) : undefined; + }; + const anyUnitPrice = positions.some( + (p) => p.name.trim() !== '' && (toNum(p.unitPrice) ?? 0) > 0, + ); + if (pricingModel === 'per_head' || pricingModel === 'volume') { + if (!anyUnitPrice && toNum(mgmtFeePerHead) === undefined) { + return '尚未填写对客月单价或管理费(元/人/月)。当前报价信息不足,盈利分析收入将为 0。请为岗位填写「对客月单价」,或填写「管理费」。'; + } + } else if (pricingModel === 'cost_plus') { + if (toNum(markupRate) === undefined && !anyUnitPrice) { + return '尚未填写成本加成率或人月单价。业务/服务外包(成本加成)需填写「成本加成率」(如 0.15)或为岗位填写「人月单价」,否则盈利分析收入将为 0。'; + } + } else if (pricingModel === 'fixed_total') { + if ((toNum(contractTotal) ?? 0) <= 0) { + return '尚未填写合同总额。固定总价模式请填写「合同总额(含税,元)」,否则盈利分析收入将为 0。'; + } + } + return null; + })(); + /* ----------------------------- 渲染 ----------------------------- */ return (
@@ -1031,6 +1056,29 @@ export function NewAssessment(): JSX.Element { )}
+ {revenueWarning !== null && ( +
+ + + + 报价信息不足:{revenueWarning} +
+ )} +
岗位明细