5.0 KiB
sub-d2-fe-2 — ĐỢT 2 FRONTEND (nút Xóa màn duyệt + menu + màn "Đã xóa")
- role: implementer-frontend · run:
2026-07-27-S155-pe-delete-approver· đợt: 2 - scope:
fe-admin/src/**+fe-user/src/**ONLY. KHÔNG chạmsrc/Backend/**, KHÔNG chạmtests/. - ghi TRONG LÚC LÀM (flush từng phần, tự
wc -csau mỗi flush).
0. Nền đã ĐO (trước khi sửa) — số thật, không phải trí nhớ
| Đo | Kết quả |
|---|---|
PeWorkflowPanel.tsx md5 ×2 app |
02671be6334110028c55fe82f5e70dee (IDENTICAL, 942 dòng) |
PurchaseEvaluationsListPage.tsx md5 ×2 app |
99e38e167d2f745ea7628174f1d2d6bf (IDENTICAL — bonus, spec không nói) |
usePermission.ts md5 ×2 app |
2b210b753e8fe2704407c787cb82779d (IDENTICAL) |
Layout.tsx |
DIVERGE admin ca59f56c… / user cab674f4… (đúng như thiết kế — 2 app khác staticMap) |
lib/menuKeys.ts |
DIVERGE đúng 2 dòng (Off_AttendanceReport admin-only) |
git status lúc bắt đầu |
sạch (chỉ .session-counter.json) ⇒ lane BE chưa land gì |
1. 🔴 PHỤ THUỘC LIÊN-LANE — FE gọi gì, BE phải có gì
Hợp-đồng run.md:139-154 chốt 3 route + 2 menu-key. FE bám ĐÚNG. NHƯNG hợp-đồng
không đặt tên cho 2 thứ FE bắt buộc phải có — khai ở đây để lead verify, KHÔNG tự chế lung tung:
(D1) Cờ F6 per-NGƯỜI trong bundle chi tiết phiếu
- FE đọc:
evaluation.currentLevelOptions.allowApproverDelete - BE PHẢI thêm:
bool AllowApproverDeletelàm member positional thứ 9 củaApprovalWorkflowOptionsDto(src/Backend/…/PurchaseEvaluations/Dtos/PurchaseEvaluationDtos.cs:123-131)- gán từ
curLevel.AllowApproverDeletetạiPurchaseEvaluationFeatures.cs:1088-1096.
- gán từ
- Vì sao chỗ này mà không phải chỗ khác:
currentLevelOptionslà kênh DUY NHẤT per-NGƯỜI — nó resolve bằngl.ApproverUserId == currentUser.UserId(PurchaseEvaluationFeatures.cs:1083-1085). Kênh còn lạiapprovalFlow.steps[].levels[].allowApproverFinalizelà OR-of-N per-CẤP (:1182 g.Any(...)) — dùng nó là vi phạm B2 (run.md:159per-ROW). - Nếu BE quên: field về
undefined→ gate=== truefalse → nút KHÔNG BAO GIỜ HIỆN, build 2 bên vẫn xanh. Đúng dạng silent-drop đợt 1. ⇒ lead phải grep xác nhận.
(D2) Chỗ chứa "lý do xóa" trong request
- Hợp-đồng chỉ ghi
DELETE /api/purchase-evaluations/{id}/by-approver, không nói payload. - FE gửi CẢ HAI đường cho tương thích mọi kiểu binding BE:
api.delete(url, { params: { reason }, data: { reason } })→ BE bind[FromQuery] string? reason✅ · bind[FromBody] {Reason}✅ · không nhận gì ✅ (bị bỏ qua). - Chủ ý: thà thừa 1 query-param còn hơn mất vết audit vì lệch tên. Ghi rõ để reviewer không tưởng là cẩu thả.
(D3) DTO list "Đã xóa"
- FE khai
PeDeletedListItem = PeListItem + { deletedAt?, deletedBy?, deletedByName? }— tất cả optional, render phòng thủ (—khi thiếu). BE trả thêm/thiếu đều không vỡ. Tên bámAuditableEntity(src/Backend/SolutionErp.Domain/Common/AuditableEntity.cs:5-7:IsDeleted/DeletedAt/DeletedBy).
2. 🚩 FLAG — mục "vá WfView cho fe-admin" TÔI KHÔNG LÀM (tiền-đề của lệnh sai)
Lệnh: "vá lệch sẵn có: fe-admin:107 THIẾU WfView so với fe-user:120".
Đo trước khi làm thì tiền-đề không đứng:
| Bằng chứng | fe-user | fe-admin |
|---|---|---|
Page pages/pe/WorkflowMatrixViewPage.tsx |
CÓ (323 dòng) | KHÔNG CÓ |
Route /purchase-evaluations/workflow-matrix |
App.tsx:60 |
KHÔNG CÓ (App.tsx:78-81 chỉ 4 route PE) |
Types types/approvalWorkflowV2.ts |
CÓ | KHÔNG CÓ (admin để type inline trong ApprovalWorkflowsV2Page.tsx) |
| Catch-all | — | App.tsx:107-114 render "Trang này chưa được build" |
⇒ Thêm WfView vào regex admin một mình = đẻ link chết dẫn tới "Trang này chưa được build".
Đó là regression nhìn thấy được, tệ hơn trạng-thái-hiện-tại (leaf bị drop im lặng).
Sửa cho đúng cần 3 file mới bên admin (page + types + route) = ngoài phạm vi đợt 2, và là
lựa-chọn UX (admin nên thấy matrix read-only hay Designer sửa được?) ⇒ thuộc quyền owner/lead.
3 đường cho lead chọn (đều ≤ 1 lượt):
- (a) mirror hẳn: copy
WorkflowMatrixViewPage.tsx+types/approvalWorkflowV2.tssang admin + route + regex. - (b) rẻ nhất: admin map
Pe_{code}_WfView→/system/approval-workflows-v2/{code}(Designer đã sống,Layout.tsx:130-136). - (c) giữ nguyên: coi lệch này là CỐ Ý (admin có Designer rồi, không cần bản read-only) → ghi 1 dòng comment cho người sau khỏi "vá" lại.
Tôi để nguyên trạng (đường c de facto) + không chèn comment tránh đụng byte thừa. Chờ lead.