feat(profitability): 运行前校验报价口径,避免静默生成收入0元的盈利分析
- handleRun 在运行前按报价模式校验收入口径: - per_head/volume: 无对客单价且无管理费 → 提示并阻止 - cost_plus: 无成本加成率且无岗位人月单价 → 提示并阻止 - fixed_total: 无合同总额 → 提示并阻止 - 成本加成率字段 hint 补充必填说明
This commit is contained in:
@@ -681,6 +681,25 @@ export function NewAssessment(): JSX.Element {
|
||||
}
|
||||
}
|
||||
|
||||
// —— 收入口径校验:避免报价信息不足时静默生成「收入 0 元」的盈利分析。——
|
||||
const anyUnitPrice = apiPositions.some((p) => p.unitPrice !== undefined && p.unitPrice > 0);
|
||||
if (pricingModel === 'per_head' || pricingModel === 'volume') {
|
||||
if (!anyUnitPrice && mf === undefined) {
|
||||
setError('报价信息不足:请在「报价与成本」步骤为岗位填写对客月单价,或填写管理费(元/人/月),否则盈利分析收入将为 0。');
|
||||
return;
|
||||
}
|
||||
} else if (pricingModel === 'cost_plus') {
|
||||
if (mr === undefined && !anyUnitPrice) {
|
||||
setError('报价信息不足:业务/服务外包(成本加成)需填写「成本加成率」(如 0.15)或为岗位填写「人月单价」,否则盈利分析收入将为 0。');
|
||||
return;
|
||||
}
|
||||
} else if (pricingModel === 'fixed_total') {
|
||||
if (ct === undefined || ct <= 0) {
|
||||
setError('报价信息不足:固定总价模式请填写「合同总额(含税,元)」,否则盈利分析收入将为 0。');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 估算基准报价(供既有报告费用区):人头/产能=Σ人数×单价×月;固定总价=合同总额。
|
||||
let baselineQuote = 0;
|
||||
if (pricingModel === 'fixed_total') {
|
||||
@@ -996,7 +1015,7 @@ export function NewAssessment(): JSX.Element {
|
||||
<input style={inputStyle} value={clientTotalHeadcount} onChange={(e) => setClientTotalHeadcount(e.target.value)} placeholder="如 500" inputMode="numeric" />
|
||||
</Field>
|
||||
{pricingModel === 'cost_plus' && (
|
||||
<Field label="成本加成率(小数)" tip="在全口径成本之上加价的比例。报价 = 成本 ×(1+加成率),用于成本加成(T&M)模式。" hint="如 0.15 表示加成 15%">
|
||||
<Field label="成本加成率(小数)" tip="在全口径成本之上加价的比例。报价 = 成本 ×(1+加成率),用于成本加成(T&M)模式。" hint="必填(或填岗位人月单价);如 0.15 表示加成 15%">
|
||||
<input style={inputStyle} value={markupRate} onChange={(e) => setMarkupRate(e.target.value)} placeholder="0.15" inputMode="decimal" />
|
||||
</Field>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user