From 9c920ad4c3bff05e549aa135bde928142c99b580 Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Thu, 25 Jun 2026 15:32:34 +0700 Subject: [PATCH] =?UTF-8?q?[CLAUDE]=20FE-User=20=C2=B7=20FE-Admin:=20PE=20?= =?UTF-8?q?flow=20s=C6=A1-=C4=91=E1=BB=93=20=E2=80=94=20badge=20"Duy?= =?UTF-8?q?=E1=BB=87t=20thay=20CEO"=20tr=C3=AAn=20c=E1=BA=A5p=20finalize?= =?UTF-8?q?=20+=20l=C3=A0m=20m=E1=BB=9D=20B=C6=B0=E1=BB=9Bc=20CEO=20"kh?= =?UTF-8?q?=C3=B4ng=20tr=C3=ACnh=20t=E1=BB=9Bi"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trong khối "Quy trình duyệt" của phiếu (PeWorkflowPanel, sơ đồ Bước→Cấp→NV), cấp được cấu hình AllowApproverFinalize (Mig 58) giờ hiện badge tím "⚑ Duyệt thay CEO" + tooltip; các Bước/Cấp SAU cấp finalize (vd Ban Giám đốc / CEO) làm mờ + nhãn "không trình tới" → người xem phiếu biết NGAY trong sơ đồ rằng quy trình DỪNG ở cấp này (duyệt thay CEO), không lên CEO (anh Kiệt FDC). Dùng field allowApproverFinalize đã expose ở flow-level (S89 #3). first-reachable theo Step.Order→ Level.Order (khớp BE finalize). Bổ sung cho callout note (#3) = chỉ-dẫn trong chính sơ đồ flow. FE-only, 2 app SHA-mirror, build xanh. Co-Authored-By: Claude Opus 4.8 --- .../src/components/pe/PeWorkflowPanel.tsx | 30 ++++++++++++++++++- fe-user/src/components/pe/PeWorkflowPanel.tsx | 30 ++++++++++++++++++- 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/fe-admin/src/components/pe/PeWorkflowPanel.tsx b/fe-admin/src/components/pe/PeWorkflowPanel.tsx index 763e56e..b88b948 100644 --- a/fe-admin/src/components/pe/PeWorkflowPanel.tsx +++ b/fe-admin/src/components/pe/PeWorkflowPanel.tsx @@ -114,6 +114,16 @@ export function PeWorkflowPanel({ // (admin bật per-slot ở Designer). Duyệt tới cấp này = TỰ kết thúc (BE auto theo cờ cấp, // KHÔNG cần ô-tích). FE dùng cờ này để: (1) hiện banner cảnh báo + (2) bắt chọn giá chốt. const approverFinalizeEligible = levelOptions?.allowApproverFinalize === true + // [S89 anh Kiệt FDC] Cấp "Duyệt thay CEO" (finalize) ĐẦU-TIÊN theo thứ tự duyệt trong flow → + // badge cấp đó + làm mờ Bước/Cấp SAU ("không trình tới") để người xem phiếu biết quy trình + // DỪNG ở cấp này (duyệt thay CEO), không lên Ban Giám đốc. + const finalizeFlowStep = evaluation.approvalFlow?.steps.find(s => s.levels.some(l => l.allowApproverFinalize)) ?? null + const finalizeFlowLevelOrder = finalizeFlowStep?.levels.find(l => l.allowApproverFinalize)?.order ?? null + const isStepAfterFinalize = (stepOrder: number) => finalizeFlowStep != null && stepOrder > finalizeFlowStep.order + const isLevelAfterFinalize = (stepOrder: number, levelOrder: number) => + isStepAfterFinalize(stepOrder) + || (finalizeFlowStep != null && stepOrder === finalizeFlowStep.order + && finalizeFlowLevelOrder != null && levelOrder > finalizeFlowLevelOrder) // Ứng viên giá chốt — chỉ giá nào đã có giá trị (≠ null). const priceCandidates = ([ { source: 'Ncc', label: 'Giá NCC (giá chào thầu)', amount: evaluation.winnerQuoteTotal }, @@ -288,6 +298,7 @@ export function PeWorkflowPanel({ step.status === 'Current' && 'border-brand-300 bg-brand-50/50', step.status === 'Done' && 'border-emerald-200 bg-emerald-50/40', step.status === 'Pending' && 'border-slate-200 bg-white', + isStepAfterFinalize(step.order) && 'opacity-50', )} >
@@ -305,13 +316,21 @@ export function PeWorkflowPanel({ {step.departmentName} )} + {isStepAfterFinalize(step.order) && ( + + không trình tới + + )}
{step.levels.length > 0 && (