14 KiB
sub-invest-fe-fable — S182 KHKK AWF-v2 mirror NCC (lens FE UI, "ko lệch")
Fable deep-pass đơn lẻ, /fable-real investigator-codebase. Đề: 8 mục sidebar "Duyệt KHKK — Nhóm 1..8" phải ra ĐÚNG trang
system/approval-workflows-v2/DuyetNcckhuôn ảnh anh gửi. 0 sửa code.
§1 Trang DuyetNcc render từ đâu (route + page + KIND_CONFIG + dialog)
Route: fe-admin/src/App.tsx:79-80 — /system/approval-workflows-v2 + /system/approval-workflows-v2/:typeCode → cùng 1 component ApprovalWorkflowsV2Page (named export, fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx 1355 dòng).
KIND map (KHÔNG phải KIND_CONFIG object đầy đủ kiểu S29/S35 — chỉ 2 Record thưa):
TYPE_CODE_TO_INT:164-172={ DuyetNcc:1, DuyetNccPhuongAn:2, Contract:3, ContractSigningPlan:10 }— 0 entryKhkkN*.DEFAULT_CODE_BY_TYPE:173-180={1:'QT-DN-V2-001', 2:'QT-DN-PA-V2-001', 3:'QT-HD-V2-001', 10:'QT-KHKK-V2-001'}(chỉ gợi-ý ô Mã).- Nhãn hiển thị KHÔNG có bảng FE — lấy từ BE
applicableTypeLabel(AwLabels.Type,ApprovalWorkflowV2AdminFeatures.cs:97có entry type-10 "Kế hoạch ký kết HĐ").
Cơ chế render :286-353: selectedTypeInt = TYPE_CODE_TO_INT[typeCode]; unknown typeCode ⇒ undefined ⇒ currentType=null ⇒ render LANDING GRID mọi type (:323-343) thay vì panel. Panel thật = TypePanel :357-459 (active card + "Lịch sử versions" + nút "Tạo quy trình mới") — mỗi panel khoá vào ĐÚNG 1 applicableType, active = type.active (BE tính), history render filter !d.isActive (:419,:426).
Cột nút phải (khuôn ảnh): DefinitionCard:577-612 — Sửa tại chỗ :587 / Tạo phiên bản mới :596 / Ghim-Bỏ ghim :606 / Xoá version :610. Badge: Đang áp dụng :490 · Cho user chọn :502 · Ngưỡng CEO :506-513. Badge NS PRO/CCM per NV :560-565 (display-only suy từ role).
Dialog Sửa tại chỗ / Tạo mới: cùng component Designer:620-1354, isEdit = editTarget !== null :638; title "Sửa tại chỗ — {code} v{NN} (giữ nguyên phiên bản)" :868. Khối cam "QUYỀN DUYỆT {TÊN}" :1228-1329 = 9 checkbox map field TS (EditLevelEntry:100-123 / API LevelDto:37-62):
| # | Label UI | Field |
|---|---|---|
| 1 | Trả về 1 Cấp trước | allowReturnOneLevel |
| 2 | Trả về 1 Bước trước | allowReturnOneStep |
| 3 | Trả về Người chỉ định | allowReturnToAssignee |
| 4 | Trả về Drafter (mặc định) — tick sẵn | allowReturnToDrafter (default true :231) |
| 5 | Chỉnh sửa Section 2 (Hạng mục/NCC/Báo giá) | allowApproverEditDetails :1275 |
| 6 | Chỉnh sửa Section ngân sách | allowApproverEditBudget :1284 |
| 7 | Duyệt thẳng Cấp cuối | allowApproverSkipToFinal — 🔴 DISABLED khi type=10 :1292-1302 (K3: service KHKK chưa port SkipToFinal, BE ép-false) |
| 8 | Duyệt là KẾT THÚC quy trình (xanh emerald) | allowApproverFinalize :1307-1315 |
| 9 | Cho phép NV này XÓA phiếu (đỏ rose) | allowApproverDelete :1320-1328 |
9 cờ gửi qua 1 hàm chung levelFlagsPayload:255-267 (2 call-site POST :820 + PUT :788 — chống silent-drop F6/F-7 S155). Rule-box xanh cuối dialog :1343-1350. Ô "Ngưỡng CEO" :944-961 render cho MỌI type (kể cả 10). |
§2 8 mục KHKK sidebar hiện map đi đâu (4-chỗ pattern 16-bis)
| Chỗ | File:line | Trạng thái |
|---|---|---|
1. BE const + All |
MenuKeys.cs:127-134 + :248-249 |
✅ 8 key AwV2_KhkkN1..8 VÀO All (⇒ 32 policy) |
| 2. BE menu-row seed | DbInitializer.cs:1988-1995 |
✅ label "Duyệt KHKK — Nhóm {n}", parent ApprovalWorkflowsV2 (root :1981 dưới System), order 3..10, icon FileSignature; Admin auto-grant qua SeedAdminPermissionsAsync (comment :1984-1987) |
3. FE lib/menuKeys.ts mirror |
fe-admin:31-32 / fe-user:31-32 |
❌ chỉ có AwV2_DuyetNcc(+PhuongAn) — 0 KhkkN. VÔ HẠI runtime: sidebar render BE-tree + resolvePath string thô; 0 call-site can('AwV2_*'); route /system/approval-workflows-v2 KHÔNG PermissionGuard (App.tsx:79-80 route trần). Optional mirror-completeness |
4. FE resolvePath |
fe-admin/src/components/Layout.tsx:188 |
✅ /^KhkkN[1-8]$/ → /system/approval-workflows-v2/KhkkN{n} (K3 S164/S165, CHỈ nới họ AwV2_*) |
Bấm vào hôm nay ra gì: route khớp App.tsx:80 → ApprovalWorkflowsV2Page, nhưng TYPE_CODE_TO_INT['KhkkN3'] = undefined ⇒ currentType=null ⇒ LANDING GRID mọi type (:323-343, header "Quy trình duyệt (Mới)" + hint "chọn loại từ menu"). CẢ 8 mục ra CÙNG landing — KHÔNG ra khuôn DuyetNcc panel. Đây chính là "lệch". (Không phải ComingSoon, không 404.)
Sibling: root AwV2 có leaf 1-2 = DuyetNcc/PhuongAn (:1982-1983); KHÔNG có leaf AwV2_Contract seed (Layout :178 chỉ phục vụ deep-link).
§3 Delta "ko lệch" — cần thêm gì + hardcode-PE-label sites
Danh tính nhóm = Code, KHÔNG phải ApplicableType. 8 workflow seed SeedKhkkGroupWorkflowsAsync (DbInitializer.cs:549-625): Code="KHKK-N{n}", CÙNG ApplicableType=10, Version=1, IsActive=true cả 8, IsUserSelectable=true, 3 trạm PRO→CCM→BGĐ sao roster Duyệt NCC prod. BE guard pin: regex ^KHKK-N([1-8])$ phải khớp plan.ApprovalGroup (ContractSigningPlanFeatures.cs:479-486). FE helper sẵn 2 app identical: khkkGroupWorkflowCode(n)='KHKK-N{n}' + khkkGroupMenuLabel(n) (fe-{admin,user}/src/types/khkk.ts:159-168). Precedent slice-by-code đã chạy ở fe-user WorkflowMatrixViewPage.tsx:84-99 (K4c: client-side filter wf.code === khkkGroupWorkflowCode(g), không thêm trục group vào queryKey).
Delta CHÍNH — 1 file fe-admin/src/pages/system/ApprovalWorkflowsV2Page.tsx (page đã generic theo :typeCode; KHÔNG thêm route/menu/BE-seed):
:164-172— thêm chiều parse:const khkkKindMatch = typeCode?.match(/^KhkkN([1-8])$/)→khkkGroup: 1..8 | null;selectedTypeInt = khkkGroup ? 10 : TYPE_CODE_TO_INT[typeCode](overview query giữ nguyênapplicableType=10).:299-301—currentTypecho kind nhóm = synthetic slice: từtypes.find(t=>t.applicableType===10)lấyversions = history.filter(d => d.code === khkkGroupWorkflowCode(g));active = versions.find(v=>v.isActive) ?? null;applicableTypeLabel = 'Duyệt KHKK — Nhóm {g}'(menu-label BE:1988) — D4 anh chọn nhãn này hay nhãn nghiệp vụkhkkGroupMenuLabel(g)= "{g}. Thiết bị, máy móc…" (đề xuất: title menu-label + phụ đề nghiệp vụ).TypePanel:357+Designer:620— prop mớilockedCode?: string: DesignerdefaultCode → lockedCode ?? DEFAULT_CODE_BY_TYPE[...](:650-651), ô Mãdisabled={isEdit || !!lockedCode}(:927), POST gửilockedCode ?? code(:798). Thiếu khoá này thì "Tạo quy trình mới" từ panel nhóm 3 với mã tự gõ sẽ đẻ version rơi khỏi slice → biến mất khỏi panel (và không được guard:482nhận là workflow nhóm).- Không đổi gì khác của khuôn: 4 nút phải, badge, Lịch sử versions, dialog 9-checkbox, rule-box — dùng nguyên
TypePanel/DefinitionCard/Designer(đúng "ko lệch"). SkipToFinal đã tự disable cho type-10 (:1292-1302) — 8 kind thừa hưởng vì cùng applicableType=10.
Hardcode-label sites trong khuôn chung (đánh dấu — KHÔNG tự quyết):
:1275"Cho phép chỉnh sửa Section 2 (Hạng mục/NCC/Báo giá) lúc đang duyệt" — từ vựng PE. KHKK service KHÔNG đọc cờ này (0-hitAllowApproverEditDetailstrongContractSigningPlan*.cs).:1284"Section ngân sách" — tương tự, 0-hitAllowApproverEditBudget.:944-961ô "Ngưỡng giá trị gói CEO" render mọi type — KHKK service CỐ Ý KHÔNG portCeoApprovalThreshold(ContractSigningPlanWorkflowService.cs:46-47: NĐUQ = human-gate vĩnh viễn, OG-3) ⇒ nhập cho kind KHKK = config-lie class #78. Khuôn disable-có-tooltip sẵn ở:1292.- Badge "✎ NS PRO/NS CCM" (
:560-565) — suy từ role PE-budget; hiển thị trên panel KHKK như đang hiển thị cho type-10 hiện nay. - Răng thật của 9 checkbox với KHKK hôm nay: CHỈ #8
AllowApproverFinalizesống (ContractSigningPlanWorkflowService.cs:276); 4 cờ Trả-về không đọc — Trả lại KHKK = TOÀN PHẦN luôn-được (:48,:354-362); Delete/EditDetails/EditBudget/SkipToFinal: 0-hit. D3: giữ nguyên khuôn (đúng "ko lệch", như panel ContractSigningPlan đang render) hay disable 7 ô chết theo khuôn SkipToFinal — anh/lead chốt; mặc định nghiêng GIỮ (uniform, cờ nằm chờ port).
§4 fe-user — IsUserSelectable tại create KHKK + designer admin-only proof
- Tạo phiếu KHKK KHÔNG có dropdown chọn quy trình — workflow GÁN CỨNG theo nhóm (owner S174):
fe-user/src/pages/khkk/KhkkCreatePage.tsx:96-116queryapplicableType=10→ filterw.isUserSelectable:104→autoWorkflow = find(code === 'KHKK-N{group}'):113-116; thiếu mã ⇒ CHẶN tạo + báo "Chưa có quy trình KHKK-N{n}" (:128,:155).fe-admin/src/pages/khkk/KhkkCreatePage.tsxmirror cùng khuôn (:97-100). ⇒ Bỏ ghim (IsUserSelectable=false) 1 workflow nhóm = CHẶN TẠO PHIẾU nhóm đó ở cả 2 app — nút Ghim/Bỏ ghim trên 8 panel mới có hệ quả nghiệp vụ thật. - Consumer thứ 2
fe-user/src/pages/khkk/KhkkDetailPage.tsx:214-227= bridge KHKK→HĐ, queryapplicableType=3lọcisUserSelectable && isActive— không liên quan nhóm. - Designer admin-only — CHỨNG: grep
approval-workflows-v2toànfe-user/src= chỉ API-consumer (Create/Detail/Matrix/Proposal/WorkflowApp) — 0 page designer, 0 route/system/approval-workflows-v2, Layout fe-user 0 nhánhAwV2_*(grep 0-hit ngoàilib/menuKeys.ts:31-32const chết). fe-user chỉ có view read-onlypages/pe/WorkflowMatrixViewPage.tsx(/khkk/workflow-matrix?type=10&group=n, K4c slice cùng convention code).
§5 Wave FE đề xuất + acceptance
W-FE1 (fe-admin, 1 file): ApprovalWorkflowsV2Page.tsx — 4 chạm §3 (parse kind :164-172 · synthetic slice :299-301 · lockedCode xuyên TypePanel:345-350/:357/:447-455 → Designer:620/:650/:798/:927 · title). Import từ types/khkk.ts (đã có sẵn trong fe-admin). Ước ~60-90 dòng diff.
W-FE2 (optional): fe-{admin,user}/src/lib/menuKeys.ts +8 const AwV2_KhkkN* (mirror-completeness, 0 hệ quả runtime).
SHA-mirror 2 app: KHÔNG áp dụng — trang system Designer là fe-admin-only (chứng §4); types/khkk.ts 2 app đã identical sẵn, không chạm.
BE: 0 bắt buộc cho khuôn hiển thị; D1 (khuyến nghị làm cùng wave): ApprovalWorkflowV2AdminFeatures.cs:339-343 deactivate-per-TYPE — sửa thành per-Code khi code khớp ^KHKK-N[1-8]$ (hoặc per-Code toàn cục — semantic đổi, anh chốt).
Acceptance đo được:
- Login admin → sidebar Hệ thống › Quy trình duyệt (Mới) hiện 10 leaf; bấm "Duyệt KHKK — Nhóm 3" → URL
/system/approval-workflows-v2/KhkkN3→ header "Quy trình duyệt (Mới): Duyệt KHKK — Nhóm 3" + cardKHKK-N3 v01badge "Đang áp dụng"+"Cho user chọn" + 3 Bước (PRO 4NV+TP·CCM 4NV+TP·BGĐ CEO) + cột 4 nút phải + "Lịch sử versions"/"Tạo quy trình mới". 8/8 leaf → 8 slice khác nhau, hết landing grid. - "Sửa tại chỗ" → dialog title "Sửa tại chỗ — KHKK-N3 v01 (giữ nguyên phiên bản)", per-NV khối cam "QUYỀN DUYỆT …" 9 checkbox 2 cột, "Trả về Drafter (mặc định)" tick sẵn, dòng xanh KẾT THÚC + dòng đỏ XÓA phiếu, SkipToFinal mờ + tooltip, rule-box cuối.
- "Tạo quy trình mới" từ panel nhóm: ô Mã khoá
KHKK-N3→ lưu ra v02 nằm ĐÚNG panel nhóm 3; (nếu D1 làm) badge "Đang áp dụng" 7 nhóm khác KHÔNG mất. - Regression:
/DuyetNcc/DuyetNccPhuongAn/Contract/ContractSigningPlanrender như cũ; fe-user tạo phiếu nhóm 3 vẫn auto-pinKHKK-N3(không đổi API).
§6 Surprises ngoài đề
- 🔴 Panel
ContractSigningPlan(đích củaKhkk_WfViewadmin,Layout.tsx:40) hôm nay GIẤU 7/8 workflow nhóm: BEActive = FirstOrDefault(IsActive)per-type (ApprovalWorkflowV2AdminFeatures.cs:210, tie-break Version DESC không xác định giữa 8 bản v1) + FE history filter!d.isActive(:419,:426) ⇒ 8 bản đều active thì 1 hiện card, 7 KHÔNG hiện đâu cả. Slice-by-code của wave này vá đúng bệnh; cân nhắc re-pointKhkk_WfViewhoặc để panel aggregate liệt theo code. - 🔴 Bom deactivate-per-TYPE (
:339-343): bấm "Tạo quy trình mới"/"Lưu + kích hoạt" cho BẤT KỲ mã nào thuộc type-10 ⇒IsActive=falseCẢ 8 nhóm (seeder không re-set — idempotent per-Code:610skip). Runtime tạo phiếu KHÔNG hỏng (pin theoIsUserSelectable, guard typeEnsureWorkflowTypeAsync:307-318không đòi IsActive) nhưng badge/active-slice sai toàn bộ. = D1. - Seeder KHKK resolve người duyệt THEO EMAIL, thiếu user ⇒ bỏ slot/cấp/bước + log warning (
DbInitializer.cs:544-548,:597-600) — DB dev thiếu người thật thì 8 panel có thể hiện bước rỗng/thiếu NV; không phải bug FE. AwV2_Contractkhông có menu-leaf seed (chỉ deep-linkLayout.tsx:178) — sibling lệch nhẹ, không thuộc scope.- Route FE
/system/approval-workflows-v2KHÔNG PermissionGuard (App.tsx:79-80) — 2-tầng gotcha #82: hiển thị dựa menu-grant, authz thật ở BE controller.