[CLAUDE] FE-Admin FE-User: Chunk E — K6 Workspace DROP Drafter checkbox + ADD Approver toggle (Mig 31 F2 refactor)
Plan K Chunk E mirror 2 app rule §3.9. Refactor F2 UX flow:
DROP fe-admin + fe-user Workspace Drafter checkbox:
- PeDetailTabs.tsx Workspace action bar: REMOVE "Gửi thẳng Cấp cuối (skip trung gian)"
violet label + state skipToFinal + allowSkipToFinal lookup + skipToFinal payload
- submitForApproval mutation signature simplify: opts: { skipToFinal: boolean } → void
- Confirm dialog text + button label drop skipToFinal conditional
ADD fe-admin + fe-user Approver toggle trong PeWorkflowPanel dialog:
- State skipToFinalApprover default false
- Visible khi Approve forward (NOT Cancel + NOT SendBack) + currentLevelOptions?.allowApproverSkipToFinal
- Checkbox violet panel với description "Phiếu sẽ tiến thẳng tới Đã duyệt (terminal)"
- Amber warning khi checked: "Hành động KHÔNG quay lại được"
- Mutation payload +skipToFinal: !isReject && skipToFinalApprover
- onSuccess reset state
Type ApprovalWorkflowOptions × 2 app: +allowApproverSkipToFinal: boolean (7th)
Type PeDetailBundle × 2 app: REMOVE drafterAllowSkipToFinal field + comment Mig 29+30+31
UX design Dialog approach (consistent với Trả lại Mode picker pattern):
- Skip thẳng Cấp cuối = destructive action → confirm dialog amber warning
- Mirror Mig 28 Trả lại 4 mode picker UX consistency
- Em main solo K6 per UX flow decision criteria
Per bro decision Plan K S23 t1: "Chỗ cấu hình cho phép skip → duyệt thẳng cho phép
trong trạng thái đang duyệt" + "Tất cả đều cấu hình ngay trong chỗ setup quy trình duyệt".
Verify:
- npm run build × 2 app pass clean (0 TS err)
- Pre-existing warnings unchanged (chunk size + INEFFECTIVE_DYNAMIC_IMPORT)
- Bundle hash rotated × 2 app
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -117,19 +117,17 @@ export function PeDetailTabs({
|
||||
// "Lưu & Gửi Duyệt" workspace mode (user 2026-05-07): trigger transition
|
||||
// sang phase tiếp theo (= Đã gửi duyệt). nextPhases[0] thường là ChoPurchasing
|
||||
// (skip TuChoi). Sau success → toast + invalidate + onBack đóng workspace.
|
||||
// Mig 29 (S21 t5) — F2: per-Drafter user flag (User Management page).
|
||||
const [skipToFinal, setSkipToFinal] = useState(false)
|
||||
const allowSkipToFinal = evaluation.drafterAllowSkipToFinal ?? false
|
||||
// Mig 31 (S23 t1) — F2 Drafter-from-Nháp semantic deprecated. skipToFinal moved
|
||||
// sang Approver scope ChoDuyet (per-Level slot — xem PeWorkflowPanel).
|
||||
|
||||
const submitForApproval = useMutation({
|
||||
mutationFn: async (opts: { skipToFinal: boolean }) => {
|
||||
mutationFn: async () => {
|
||||
const next = evaluation.workflow.nextPhases.find(p => p !== PurchaseEvaluationPhase.TuChoi && p !== PurchaseEvaluationPhase.TraLai)
|
||||
if (!next) throw new Error('Không có phase tiếp theo để gửi duyệt')
|
||||
return api.post(`/purchase-evaluations/${evaluation.id}/transitions`, {
|
||||
targetPhase: next,
|
||||
decision: 1,
|
||||
comment: null,
|
||||
skipToFinal: opts.skipToFinal,
|
||||
})
|
||||
},
|
||||
onSuccess: () => {
|
||||
@ -283,33 +281,19 @@ export function PeDetailTabs({
|
||||
>
|
||||
Lưu
|
||||
</Button>
|
||||
{/* Mig 28 (S21 t4) — F2: Drafter skip checkbox */}
|
||||
{allowSkipToFinal && canSubmitForApproval && (
|
||||
<label className="flex cursor-pointer items-center gap-1.5 rounded border border-violet-200 bg-violet-50 px-2 py-1 text-[11px] text-violet-800">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="h-3 w-3"
|
||||
checked={skipToFinal}
|
||||
onChange={e => setSkipToFinal(e.target.checked)}
|
||||
/>
|
||||
<span>Gửi thẳng Cấp cuối (skip trung gian)</span>
|
||||
</label>
|
||||
)}
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!forwardPhase) return
|
||||
const confirmMsg = skipToFinal
|
||||
? `Gửi THẲNG CẤP CUỐI bỏ qua các Cấp trung gian? Hệ thống sẽ ghi audit "Drafter skip" — không quay lại được trừ khi approver Trả lại.`
|
||||
: `Gửi phiếu vào quy trình duyệt? Sẽ chuyển sang "${PurchaseEvaluationPhaseLabel[forwardPhase]}". Sau khi gửi sẽ KHÔNG sửa được nữa (trừ khi approver Trả lại).`
|
||||
const confirmMsg = `Gửi phiếu vào quy trình duyệt? Sẽ chuyển sang "${PurchaseEvaluationPhaseLabel[forwardPhase]}". Sau khi gửi sẽ KHÔNG sửa được nữa (trừ khi approver Trả lại).`
|
||||
if (confirm(confirmMsg)) {
|
||||
submitForApproval.mutate({ skipToFinal })
|
||||
submitForApproval.mutate()
|
||||
}
|
||||
}}
|
||||
disabled={!canSubmitForApproval || submitForApproval.isPending}
|
||||
title={submitDisabledReason ?? `Gửi phiếu sang "${forwardPhase ? PurchaseEvaluationPhaseLabel[forwardPhase] : '?'}"`}
|
||||
className="text-xs"
|
||||
>
|
||||
{submitForApproval.isPending ? 'Đang gửi…' : skipToFinal ? 'Lưu & Gửi thẳng CẤP CUỐI →' : 'Lưu & Gửi Duyệt →'}
|
||||
{submitForApproval.isPending ? 'Đang gửi…' : 'Lưu & Gửi Duyệt →'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user