diff --git a/fe-admin/src/components/pe/PeDetailTabs.tsx b/fe-admin/src/components/pe/PeDetailTabs.tsx index 2dca7ce..ae3788e 100644 --- a/fe-admin/src/components/pe/PeDetailTabs.tsx +++ b/fe-admin/src/components/pe/PeDetailTabs.tsx @@ -933,95 +933,46 @@ function InfoTab({ ev, readOnly, autoEdit }: { ev: PeDetailBundle; readOnly: boo ) } -// ===== a. NCC / TP được chọn — MULTI-WINNER picker [Mig 58 anh Kiệt FDC] ===== -// Mỗi đơn vị tham gia có 1 checkbox "Chọn trúng thầu" (chọn ≥2 = liên danh). Trạng -// thái tích = supplier.isWinner (KHÔNG dùng selectedSupplierId — null khi ≥2 winner). -// Toggle → POST select-winner với TOÀN BỘ tập ID đang tích `{ supplierIds: [...] }`; -// bỏ tích hết = []. Tổng chi phí = ev.winnerQuoteTotal (BE = SUM mọi isWinner). -function NccSelectorRow({ ev, readOnly }: { ev: PeDetailBundle; readOnly: boolean }) { - const canEdit = !readOnly && isEditablePhase(ev.phase) - const qc = useQueryClient() - // gotcha #70 — chặn echo-cũ: trong lúc refetch pe-detail, bỏ qua optimistic flicker. - const peFetching = useIsFetching({ queryKey: ['pe-detail', ev.id] }) > 0 - const setWinners = useMutation({ - mutationFn: async (supplierIds: string[]) => - api.post(`/purchase-evaluations/${ev.id}/select-winner`, { supplierIds }), - onSuccess: () => { - toast.success('Đã cập nhật đơn vị trúng thầu.') - qc.invalidateQueries({ queryKey: ['pe-detail', ev.id] }) - qc.invalidateQueries({ queryKey: ['pe-list'] }) - }, - onError: e => toast.error(getErrorMessage(e)), - }) - const winnerIds = ev.suppliers.filter(s => s.isWinner).map(s => s.supplierId) - const toggle = (supplierId: string, on: boolean) => - setWinners.mutate(on - ? [...winnerIds, supplierId] - : winnerIds.filter(id => id !== supplierId)) - const busy = setWinners.isPending || peFetching - - if (!canEdit) { - const winners = ev.suppliers.filter(s => s.isWinner) - return ( - 0 - ? ✓ {winners.map(s => s.supplierName).join(', ')} - : — (chưa chọn)} - /> - ) - } - +// ===== a. NCC / TP được chọn — TÓM TẮT read-only [multi-NCC per hạng mục] ===== +// Winner giờ CHỌN THEO TỪNG HẠNG MỤC ở bảng NCC (Mục 2) — nguồn sự thật = quote.isSelected +// mỗi cặp (hạng mục × NCC). Picker phiếu-wide cũ MẤT NGHĨA → hạ-cấp thành ô TÓM TẮT: mỗi +// đơn vị trúng + các hạng mục nó thắng (derive ev.details[].quotes IsSelected). Tổng = +// ev.winnerQuoteTotal (BE = SUM mọi quote IsSelected). +function NccSelectorRow({ ev }: { ev: PeDetailBundle }) { + const winners = ev.suppliers.filter(s => s.isWinner) + // Các hạng mục mà supplier-row `rowId` thắng (có ≥1 quote IsSelected trong hạng mục đó). + const wonItems = (rowId: string) => + ev.details + .filter(d => d.quotes.some(q => q.purchaseEvaluationSupplierId === rowId && q.isSelected)) + .map(d => d.groupCode || d.noiDung) return ( -
- a. NCC / TP được chọn -
- {ev.suppliers.length === 0 ? ( -

- Thêm NCC ở Section 3 trước rồi mới chọn trúng thầu. -

- ) : ( -
- {ev.suppliers.map(s => ( -