(null)
+ // Mig 31 (S23 t1) — F2 Approver duyệt thẳng Cấp cuối. Default false (admin opt-in
+ // per slot tick → checkbox visible trong dialog Approve, default unchecked).
+ const [skipToFinalApprover, setSkipToFinalApprover] = useState(false)
const qc = useQueryClient()
const { user: currentUser } = useAuth()
const isAdmin = currentUser?.roles?.includes('Admin') ?? false
@@ -97,6 +100,9 @@ export function PeWorkflowPanel({
returnMode: isTraLaiAction ? returnMode : null,
returnTargetUserId: isTraLaiAction && returnMode === WorkflowReturnMode.Assignee
? returnTargetUserId : null,
+ // Mig 31 (S23 t1) — F2 Approver scope ChoDuyet duyệt thẳng Cấp cuối.
+ // BE check matchingLevel.AllowApproverSkipToFinal (admin opt-in per slot).
+ skipToFinal: !isReject && skipToFinalApprover,
})
},
onSuccess: () => {
@@ -108,6 +114,7 @@ export function PeWorkflowPanel({
setComment('')
setReturnMode(WorkflowReturnMode.Drafter)
setReturnTargetUserId(null)
+ setSkipToFinalApprover(false)
},
onError: e => toast.error(getErrorMessage(e)),
})
@@ -397,6 +404,32 @@ export function PeWorkflowPanel({
>
)}
+ {/* Mig 31 (S23 t1) — F2 Approver toggle: chỉ visible khi Approve forward
+ + admin tick AllowApproverSkipToFinal cho slot Cấp hiện tại. */}
+ {!isCancel && !isSendBack && levelOptions?.allowApproverSkipToFinal && (
+
+
+
+ )}
+ {!isCancel && !isSendBack && skipToFinalApprover && (
+
+ ⚠ Hành động KHÔNG quay lại được (trừ khi Drafter reset toàn bộ). Phiếu sẽ
+ skip qua tất cả Cấp/Bước còn lại và chuyển thẳng "Đã duyệt".
+
+ )}