diff --git a/fe-admin/src/components/khkk/KhkkListPanel.tsx b/fe-admin/src/components/khkk/KhkkListPanel.tsx index 37398a3..b1f4b6c 100644 --- a/fe-admin/src/components/khkk/KhkkListPanel.tsx +++ b/fe-admin/src/components/khkk/KhkkListPanel.tsx @@ -105,12 +105,15 @@ export function KhkkPlanCard({ selected, onSelect, finalize, + deleted, }: { plan: KhkkListItemDto selected: boolean onSelect: (id: string) => void /** Chỉ có khi phiếu ĐANG được chọn (detail đã tải) — list payload không mang cờ này. */ finalize?: { endedByLevelFinalize: boolean; finalizeStepName: string | null } + /** [S176] Đang xem thùng rác ⇒ hiện dấu thời-điểm xóa. Mirror khuôn màn Duyệt NCC. */ + deleted?: boolean }) { const frozen = plan.phase === KhkkPhase.DaDuyet const amount = frozen ? (plan.totalApprovedAmount ?? plan.totalProposedAmount) : plan.totalProposedAmount @@ -160,6 +163,22 @@ export function KhkkPlanCard({ )} · {formatDateTime(plan.createdAt)} + {/* [S176] "Xóa lúc" — mirror khuôn màn Duyệt NCC (`PurchaseEvaluationsListPage:573`). + 🔴 API `/contract-signing-plans/deleted` trả DTO DÙNG CHUNG với list sống ⇒ KHÔNG + có `deletedAt`/`deletedBy`. Mốc dưới là `updatedAt`, mà `AuditingInterceptor` ghi + ngay lượt SaveChanges của thao tác xóa mềm ⇒ XẤP XỈ thời điểm xóa. Nhãn "≈" để + KHÔNG hứa chính xác. Tên người xóa API không trả — cố ý bỏ trống thay vì đoán. */} + {deleted && plan.updatedAt && ( + <> + · + + 🗑 xóa ≈ {formatDateTime(plan.updatedAt)} + + + )}
👤 {plan.drafterFullName ?? '—'} @@ -293,6 +312,7 @@ export function KhkkListPanel({ selected={selectedId === k.id} onSelect={deletedView ? () => { /* phiếu đã xóa: chỉ liệt kê, không mở */ } : onSelect} finalize={selectedId === k.id ? selectedFinalize : undefined} + deleted={deletedView} /> ))} @@ -316,16 +336,30 @@ export function KhkkListPanel({ className="pl-8" />
- + {/* [S176] Thùng rác ⇒ THAY dropdown bằng banner, mirror khuôn màn Duyệt NCC + (`PurchaseEvaluationsListPage:427-431`). + 🔴 Ẩn dropdown là CÓ LÝ DO, không phải cho gọn: phiếu giữ NGUYÊN phase lúc bị xóa, + `IsDeleted` mới là thứ phân loại ⇒ lọc trạng thái ở đây là nút chết. Chính `plansForPe` + bên dưới cũng cố ý KHÔNG lọc phase khi xem thùng rác — để dropdown lại thì người dùng + bấm mà không thấy gì đổi. + 🔸 CỐ Ý BỎ vế "không còn tính vào lũy kế ngân sách" của bản PE: `grep 'lũy kế'` trong + toàn bộ KHKK = 0 hit ⇒ bê nguyên là khai một điều chưa chứng minh cho module này. */} + {deletedView ? ( +
+ 🗑 Phiếu đã xóa — chỉ xem. Không khôi phục, không thao tác. +
+ ) : ( + + )} {/* 🧊 [S175] Dòng "Đang lọc — danh sách lấy thẳng từ máy chủ…" ĐÃ GỠ (anh: "Bỏ mấy dòng này đi"). Đó là chú-thích về CƠ-CHẾ bên trong, người dùng không cần biết cây tải 200 phiếu hay lấy thẳng máy chủ — họ chỉ cần thấy đúng phiếu. */} @@ -412,6 +446,7 @@ export function KhkkListPanel({ selected={selectedId === k.id} onSelect={deletedView ? () => { /* phiếu đã xóa: chỉ liệt kê, không mở */ } : onSelect} finalize={selectedId === k.id ? selectedFinalize : undefined} + deleted={deletedView} /> ))} diff --git a/fe-user/src/components/khkk/KhkkListPanel.tsx b/fe-user/src/components/khkk/KhkkListPanel.tsx index 37398a3..b1f4b6c 100644 --- a/fe-user/src/components/khkk/KhkkListPanel.tsx +++ b/fe-user/src/components/khkk/KhkkListPanel.tsx @@ -105,12 +105,15 @@ export function KhkkPlanCard({ selected, onSelect, finalize, + deleted, }: { plan: KhkkListItemDto selected: boolean onSelect: (id: string) => void /** Chỉ có khi phiếu ĐANG được chọn (detail đã tải) — list payload không mang cờ này. */ finalize?: { endedByLevelFinalize: boolean; finalizeStepName: string | null } + /** [S176] Đang xem thùng rác ⇒ hiện dấu thời-điểm xóa. Mirror khuôn màn Duyệt NCC. */ + deleted?: boolean }) { const frozen = plan.phase === KhkkPhase.DaDuyet const amount = frozen ? (plan.totalApprovedAmount ?? plan.totalProposedAmount) : plan.totalProposedAmount @@ -160,6 +163,22 @@ export function KhkkPlanCard({ )} · {formatDateTime(plan.createdAt)} + {/* [S176] "Xóa lúc" — mirror khuôn màn Duyệt NCC (`PurchaseEvaluationsListPage:573`). + 🔴 API `/contract-signing-plans/deleted` trả DTO DÙNG CHUNG với list sống ⇒ KHÔNG + có `deletedAt`/`deletedBy`. Mốc dưới là `updatedAt`, mà `AuditingInterceptor` ghi + ngay lượt SaveChanges của thao tác xóa mềm ⇒ XẤP XỈ thời điểm xóa. Nhãn "≈" để + KHÔNG hứa chính xác. Tên người xóa API không trả — cố ý bỏ trống thay vì đoán. */} + {deleted && plan.updatedAt && ( + <> + · + + 🗑 xóa ≈ {formatDateTime(plan.updatedAt)} + + + )}
👤 {plan.drafterFullName ?? '—'} @@ -293,6 +312,7 @@ export function KhkkListPanel({ selected={selectedId === k.id} onSelect={deletedView ? () => { /* phiếu đã xóa: chỉ liệt kê, không mở */ } : onSelect} finalize={selectedId === k.id ? selectedFinalize : undefined} + deleted={deletedView} /> ))} @@ -316,16 +336,30 @@ export function KhkkListPanel({ className="pl-8" />
- + {/* [S176] Thùng rác ⇒ THAY dropdown bằng banner, mirror khuôn màn Duyệt NCC + (`PurchaseEvaluationsListPage:427-431`). + 🔴 Ẩn dropdown là CÓ LÝ DO, không phải cho gọn: phiếu giữ NGUYÊN phase lúc bị xóa, + `IsDeleted` mới là thứ phân loại ⇒ lọc trạng thái ở đây là nút chết. Chính `plansForPe` + bên dưới cũng cố ý KHÔNG lọc phase khi xem thùng rác — để dropdown lại thì người dùng + bấm mà không thấy gì đổi. + 🔸 CỐ Ý BỎ vế "không còn tính vào lũy kế ngân sách" của bản PE: `grep 'lũy kế'` trong + toàn bộ KHKK = 0 hit ⇒ bê nguyên là khai một điều chưa chứng minh cho module này. */} + {deletedView ? ( +
+ 🗑 Phiếu đã xóa — chỉ xem. Không khôi phục, không thao tác. +
+ ) : ( + + )} {/* 🧊 [S175] Dòng "Đang lọc — danh sách lấy thẳng từ máy chủ…" ĐÃ GỠ (anh: "Bỏ mấy dòng này đi"). Đó là chú-thích về CƠ-CHẾ bên trong, người dùng không cần biết cây tải 200 phiếu hay lấy thẳng máy chủ — họ chỉ cần thấy đúng phiếu. */} @@ -412,6 +446,7 @@ export function KhkkListPanel({ selected={selectedId === k.id} onSelect={deletedView ? () => { /* phiếu đã xóa: chỉ liệt kê, không mở */ } : onSelect} finalize={selectedId === k.id ? selectedFinalize : undefined} + deleted={deletedView} /> ))}