refactor(scheduling): 拆分 reason 区为 客户/车辆 两栏
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
详情页的指标区从单列两格网格改为 左:客户 / 右:车辆 两栏。客户日均归 左侧,考核剩余、日均需、年度完成率、可为新车贡献归右侧,便于一眼 识别数据归属。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,8 @@ function fmtRate(rate: number): string {
|
|||||||
return (rate * 100).toFixed(1) + '%';
|
return (rate * 100).toFixed(1) + '%';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CUSTOMER_REASON_LABELS = new Set(['客户日均']);
|
||||||
|
|
||||||
export default function SuggestionDetail({ suggestion: s, onClose, onNotifySuccess }: Props) {
|
export default function SuggestionDetail({ suggestion: s, onClose, onNotifySuccess }: Props) {
|
||||||
const [previewCandidate, setPreviewCandidate] = useState<CandidateVehicle | null>(null);
|
const [previewCandidate, setPreviewCandidate] = useState<CandidateVehicle | null>(null);
|
||||||
const [sentPlates, setSentPlates] = useState<Set<string>>(new Set());
|
const [sentPlates, setSentPlates] = useState<Set<string>>(new Set());
|
||||||
@@ -212,15 +214,39 @@ export default function SuggestionDetail({ suggestion: s, onClose, onNotifySucce
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Reason — structured lines */}
|
{/* Reason — customer vs vehicle columns */}
|
||||||
<div className="px-4 py-2.5 border-b border-slate-100 bg-slate-50/60">
|
<div className="px-4 py-2.5 border-b border-slate-100 bg-slate-50/60">
|
||||||
<div className="grid grid-cols-2 gap-x-3 gap-y-1">
|
<div className="grid grid-cols-2 gap-x-5">
|
||||||
{s.reason.lines.map((line, i) => (
|
{(() => {
|
||||||
<div key={i} className="flex items-center justify-between text-[11px]">
|
const customerLines = s.reason.lines.filter(l => CUSTOMER_REASON_LABELS.has(l.label));
|
||||||
<span className="text-slate-500">{line.label}</span>
|
const vehicleLines = s.reason.lines.filter(l => !CUSTOMER_REASON_LABELS.has(l.label));
|
||||||
<span className="text-slate-700 font-medium">{line.value}</span>
|
return (
|
||||||
</div>
|
<>
|
||||||
))}
|
<div>
|
||||||
|
<div className="text-[9px] font-bold text-slate-400 uppercase tracking-wider mb-1">客户</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
{customerLines.map((line, i) => (
|
||||||
|
<div key={i} className="flex items-center justify-between text-[11px]">
|
||||||
|
<span className="text-slate-500">{line.label}</span>
|
||||||
|
<span className="text-slate-700 font-medium">{line.value}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-[9px] font-bold text-slate-400 uppercase tracking-wider mb-1">车辆</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
{vehicleLines.map((line, i) => (
|
||||||
|
<div key={i} className="flex items-center justify-between text-[11px]">
|
||||||
|
<span className="text-slate-500">{line.label}</span>
|
||||||
|
<span className="text-slate-700 font-medium">{line.value}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 pt-2 border-t border-slate-200">
|
<div className="mt-2 pt-2 border-t border-slate-200">
|
||||||
<span className="text-xs font-bold text-rose-600">{s.reason.conclusion}</span>
|
<span className="text-xs font-bold text-rose-600">{s.reason.conclusion}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user