[CLAUDE] FE-Admin: Chunk C — ApprovalWorkflowDesigner section "Cấu hình nâng cao" 6 checkbox (F1+F2+F3)
Thêm section "Cấu hình nâng cao" trong Designer modal (giữa Description và Steps), 3 sub-group 6 checkbox per workflow version: 1. Mode Trả lại (Approver chọn khi nhấn ← Trả lại): - Trả về 1 Cấp trước (peer review chain trong cùng Bước) - Trả về 1 Bước trước (Cấp cuối Bước trước nhận lại) - Trả về Người chỉ định (pick runtime từ list NV đã duyệt) - Trả về Người soạn thảo (default checked = backward compat S17) 2. Drafter gửi duyệt: - Cho phép Drafter gửi thẳng Cấp cuối (F2 skip mọi Bước/Cấp trung gian) 3. Approver chỉnh sửa phiếu: - Cho phép Approver chỉnh sửa Section 2 Hạng mục/NCC/Báo giá (F3, giữ Cấp) DTO types update: - DefinitionDto +6 boolean field (mirror BE AwDefinitionDto) - 6 useState cho 6 flag, default từ cloneFrom (giữ config version trước) hoặc S17 backward compat (chỉ AllowReturnToDrafter=true) - POST body extend 6 field gửi BE Styling: - Container amber-50/30 + border amber-200 (visual distinction với Steps section) - Mỗi checkbox: card border-slate-200 bg-white, hover bg-amber-50/40 - Helper text [10px] text-slate-500 dưới label giải thích mode - Headers [11px] uppercase text-slate-500 group sub-section fe-user KHÔNG mirror — ApprovalWorkflowsV2Page admin-only. PeWorkspaceCreateView chỉ filter IsUserSelectable, không cần Allow* flag lúc create phiếu. Verify: - npm run build fe-admin pass (8.72s, 0 TS6 err) - Warning chunk size pre-existing Pending Chunk D: FE eOffice (Trả lại modal dropdown + Skip submit + Edit Section 2 enable conditional theo workflow.options) mirror 2 app. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -60,6 +60,13 @@ type DefinitionDto = {
|
||||
description: string | null
|
||||
isActive: boolean
|
||||
isUserSelectable: boolean // Mig 25 — admin toggle cho user pick
|
||||
// Mig 28 (S21 t4) — 6 advanced options per workflow version
|
||||
allowReturnOneLevel: boolean
|
||||
allowReturnOneStep: boolean
|
||||
allowReturnToAssignee: boolean
|
||||
allowReturnToDrafter: boolean // default true backward compat S17
|
||||
allowDrafterSkipToFinal: boolean
|
||||
allowApproverEditDetails: boolean
|
||||
activatedAt: string | null
|
||||
createdAt: string
|
||||
steps: StepDto[]
|
||||
@ -445,6 +452,15 @@ function Designer({
|
||||
const [description, setDescription] = useState(cloneFrom?.description ?? '')
|
||||
const [steps, setSteps] = useState<EditStep[]>(initialSteps)
|
||||
|
||||
// Mig 28 (S21 t4) — 6 advanced options. Default clone từ cloneFrom (giữ
|
||||
// config version trước) hoặc backward compat S17 (chỉ Drafter mode).
|
||||
const [allowReturnOneLevel, setAllowReturnOneLevel] = useState(cloneFrom?.allowReturnOneLevel ?? false)
|
||||
const [allowReturnOneStep, setAllowReturnOneStep] = useState(cloneFrom?.allowReturnOneStep ?? false)
|
||||
const [allowReturnToAssignee, setAllowReturnToAssignee] = useState(cloneFrom?.allowReturnToAssignee ?? false)
|
||||
const [allowReturnToDrafter, setAllowReturnToDrafter] = useState(cloneFrom?.allowReturnToDrafter ?? true)
|
||||
const [allowDrafterSkipToFinal, setAllowDrafterSkipToFinal] = useState(cloneFrom?.allowDrafterSkipToFinal ?? false)
|
||||
const [allowApproverEditDetails, setAllowApproverEditDetails] = useState(cloneFrom?.allowApproverEditDetails ?? false)
|
||||
|
||||
const usersList = useQuery({
|
||||
queryKey: ['users-for-approver-v2'],
|
||||
queryFn: async () =>
|
||||
@ -503,6 +519,13 @@ function Designer({
|
||||
approverUserId: e.approverUserId,
|
||||
})),
|
||||
})),
|
||||
// Mig 28 (S21 t4) — 6 advanced options
|
||||
allowReturnOneLevel,
|
||||
allowReturnOneStep,
|
||||
allowReturnToAssignee,
|
||||
allowReturnToDrafter,
|
||||
allowDrafterSkipToFinal,
|
||||
allowApproverEditDetails,
|
||||
})
|
||||
},
|
||||
onSuccess: () => {
|
||||
@ -561,6 +584,118 @@ function Designer({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mig 28 (S21 t4) — Section Cấu hình nâng cao (F1+F2+F3 advanced options).
|
||||
6 checkbox per workflow: 4 mode Trả lại + 1 Skip CEO + 1 Approver edit. */}
|
||||
<div className="space-y-2 rounded-lg border border-amber-200 bg-amber-50/30 p-3">
|
||||
<Label className="text-amber-900">
|
||||
Cấu hình nâng cao — quyền duyệt mở rộng
|
||||
</Label>
|
||||
<p className="text-[11px] leading-relaxed text-slate-600">
|
||||
Bật/tắt mode duyệt mở rộng cho workflow này. Mặc định chỉ "Trả về Người soạn thảo" enabled
|
||||
(tương thích quy trình cũ). Các mode khác opt-in để audit nghiêm.
|
||||
</p>
|
||||
|
||||
<div className="mt-2 space-y-3">
|
||||
<div>
|
||||
<div className="mb-1 text-[11px] font-semibold uppercase text-slate-500">
|
||||
Mode Trả lại (Approver chọn khi nhấn ← Trả lại)
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-1.5">
|
||||
<label className="flex items-start gap-2 rounded border border-slate-200 bg-white px-2 py-1.5 text-[12px] hover:bg-amber-50/40">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5 h-3.5 w-3.5"
|
||||
checked={allowReturnOneLevel}
|
||||
onChange={e => setAllowReturnOneLevel(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="font-medium">Trả về 1 Cấp trước</span>
|
||||
<span className="block text-[10px] text-slate-500">Lùi 1 Cấp trong cùng Bước, peer review chain</span>
|
||||
</span>
|
||||
</label>
|
||||
<label className="flex items-start gap-2 rounded border border-slate-200 bg-white px-2 py-1.5 text-[12px] hover:bg-amber-50/40">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5 h-3.5 w-3.5"
|
||||
checked={allowReturnOneStep}
|
||||
onChange={e => setAllowReturnOneStep(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="font-medium">Trả về 1 Bước trước</span>
|
||||
<span className="block text-[10px] text-slate-500">Lùi sang Bước trước, Cấp cuối nhận lại</span>
|
||||
</span>
|
||||
</label>
|
||||
<label className="flex items-start gap-2 rounded border border-slate-200 bg-white px-2 py-1.5 text-[12px] hover:bg-amber-50/40">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5 h-3.5 w-3.5"
|
||||
checked={allowReturnToAssignee}
|
||||
onChange={e => setAllowReturnToAssignee(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="font-medium">Trả về Người chỉ định</span>
|
||||
<span className="block text-[10px] text-slate-500">Pick runtime từ list NV đã duyệt</span>
|
||||
</span>
|
||||
</label>
|
||||
<label className="flex items-start gap-2 rounded border border-slate-200 bg-white px-2 py-1.5 text-[12px] hover:bg-amber-50/40">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5 h-3.5 w-3.5"
|
||||
checked={allowReturnToDrafter}
|
||||
onChange={e => setAllowReturnToDrafter(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="font-medium">Trả về Người soạn thảo</span>
|
||||
<span className="block text-[10px] text-slate-500">Phase=TraLai, Drafter sửa rồi gửi lại (mặc định)</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="mb-1 text-[11px] font-semibold uppercase text-slate-500">
|
||||
Drafter gửi duyệt (Workspace "Lưu & Gửi Duyệt")
|
||||
</div>
|
||||
<label className="flex items-start gap-2 rounded border border-slate-200 bg-white px-2 py-1.5 text-[12px] hover:bg-amber-50/40">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5 h-3.5 w-3.5"
|
||||
checked={allowDrafterSkipToFinal}
|
||||
onChange={e => setAllowDrafterSkipToFinal(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="font-medium">Cho phép Drafter gửi thẳng Cấp cuối</span>
|
||||
<span className="block text-[10px] text-slate-500">
|
||||
Skip mọi Bước/Cấp trung gian → đi thẳng NV Cấp cuối (vd CEO).
|
||||
Workspace hiện dropdown 2 option "Gửi tuần tự" vs "Gửi thẳng Cấp cuối".
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className="mb-1 text-[11px] font-semibold uppercase text-slate-500">
|
||||
Approver chỉnh sửa phiếu
|
||||
</div>
|
||||
<label className="flex items-start gap-2 rounded border border-slate-200 bg-white px-2 py-1.5 text-[12px] hover:bg-amber-50/40">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="mt-0.5 h-3.5 w-3.5"
|
||||
checked={allowApproverEditDetails}
|
||||
onChange={e => setAllowApproverEditDetails(e.target.checked)}
|
||||
/>
|
||||
<span>
|
||||
<span className="font-medium">Cho phép Approver chỉnh sửa Section 2 (Hạng mục + NCC + Báo giá)</span>
|
||||
<span className="block text-[10px] text-slate-500">
|
||||
NV Cấp đang duyệt được edit chi tiết phiếu (không reset workflow,
|
||||
giữ Cấp hiện tại). Mọi thay đổi log vào Lịch sử chỉnh sửa.
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 rounded-lg border border-slate-200 p-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<Label>
|
||||
|
||||
Reference in New Issue
Block a user