diff --git a/fe-admin/src/components/pe/PeDetailTabs.tsx b/fe-admin/src/components/pe/PeDetailTabs.tsx index c853b99..5096a2d 100644 --- a/fe-admin/src/components/pe/PeDetailTabs.tsx +++ b/fe-admin/src/components/pe/PeDetailTabs.tsx @@ -1324,16 +1324,11 @@ function HangMucCard({
-
KL
-
{detail.khoiLuongNganSach}
-
-
-
ĐG ngân sách
-
{fmtMoney(detail.donGiaNganSach)}
-
-
-
Thành tiền NS
-
{fmtMoney(detail.thanhTienNganSach)}
+
Số tiền ngân sách
+
+ {fmtMoney(detail.thanhTienNganSach)} + đ +
{showBudgetCol && bgValue != null && (
@@ -1409,7 +1404,6 @@ function HangMucCard({ const hasQuotes = ev.details.some(dd => dd.quotes.some(qq => qq.purchaseEvaluationSupplierId === s.id)) const canDelete = !isWinner && !hasQuotes const openQuote = () => setQuoteEdit({ supplier: s, existing: q }) - const cellHover = !readOnly && 'cursor-pointer hover:bg-brand-50' return ( @@ -1438,16 +1432,28 @@ function HangMucCard({ readOnly={readOnly} /> - + {!readOnly ? ( + + ) : ( +
+ {q ? `${fmtMoney(q.thanhTien)} đ` : } +
)} - title={!readOnly ? 'Click để nhập / sửa số tiền' : undefined} - > - {q ? fmtMoney(q.thanhTien) : } {!readOnly && ( @@ -1519,14 +1525,18 @@ function HangMucCard({ function DetailDialog({ evaluationId, row, onClose }: { evaluationId: string; row: PeDetailRow | null; onClose: () => void }) { const qc = useQueryClient() + // Session 20 turn 5: user yêu cầu rút gọn — chỉ Tên hạng mục + Số tiền + // ngân sách (VND format) + Ghi chú. Các field schema khác (groupCode/ + // groupName/itemCode/donViTinh/khoiLuongs/donGia) giữ default cho BE + // schema backward compat — KHÔNG expose UI cho user. const [form, setForm] = useState({ - groupCode: row?.groupCode ?? 'A.I', - groupName: row?.groupName ?? '', + groupCode: row?.groupCode ?? '01', + groupName: row?.groupName ?? 'Hạng mục chính', itemCode: row?.itemCode ?? '', noiDung: row?.noiDung ?? '', - donViTinh: row?.donViTinh ?? '', - khoiLuongNganSach: row?.khoiLuongNganSach ?? 0, - khoiLuongThiCong: row?.khoiLuongThiCong ?? 0, + donViTinh: row?.donViTinh ?? 'gói', + khoiLuongNganSach: row?.khoiLuongNganSach ?? 1, + khoiLuongThiCong: row?.khoiLuongThiCong ?? 1, donGiaNganSach: row?.donGiaNganSach ?? 0, thanhTienNganSach: row?.thanhTienNganSach ?? 0, ghiChu: row?.ghiChu ?? '', @@ -1540,11 +1550,10 @@ function DetailDialog({ evaluationId, row, onClose }: { evaluationId: string; ro onError: e => toast.error(getErrorMessage(e)), }) - const updateAndRecalc = (patch: Partial) => { - const next = { ...form, ...patch } - // Auto-compute ThanhTien = KL ngân sách × ĐG ngân sách - next.thanhTienNganSach = Number(next.khoiLuongNganSach) * Number(next.donGiaNganSach) - setForm(next) + // Sync ngân sách: user nhập "Số tiền ngân sách" → set cả donGia + thanhTien + // (KL = 1 ngầm). BE giữ schema 3 field. + const setBudgetAmount = (n: number) => { + setForm({ ...form, donGiaNganSach: n, thanhTienNganSach: n }) } return ( @@ -1552,24 +1561,38 @@ function DetailDialog({ evaluationId, row, onClose }: { evaluationId: string; ro open onClose={onClose} title={(row ? 'Sửa' : 'Thêm') + ' hạng mục'} - size="lg" footer={<> } >
-
-
setForm({ ...form, groupCode: e.target.value })} />
-
setForm({ ...form, groupName: e.target.value })} placeholder="Bê tông / Phụ gia..." />
-
setForm({ ...form, itemCode: e.target.value })} />
-
setForm({ ...form, noiDung: e.target.value })} />
-
setForm({ ...form, donViTinh: e.target.value })} />
-
updateAndRecalc({ khoiLuongNganSach: Number(e.target.value) })} />
-
setForm({ ...form, khoiLuongThiCong: Number(e.target.value) })} />
-
updateAndRecalc({ donGiaNganSach: Number(e.target.value) })} />
-
setForm({ ...form, thanhTienNganSach: Number(e.target.value) })} />
-
setForm({ ...form, ghiChu: e.target.value })} />
+
+ + setForm({ ...form, noiDung: e.target.value })} + placeholder="vd Cung cấp bê tông M250" + /> +
+
+ +
+ setBudgetAmount(parseVnd(e.target.value))} + placeholder="0" + className="pr-12 font-mono text-right" + /> + đ +
+

VND — nhập số, tự format dấu chấm ngàn (vd 1.000.000)

+
+
+ + setForm({ ...form, ghiChu: e.target.value })} />
diff --git a/fe-user/src/components/pe/PeDetailTabs.tsx b/fe-user/src/components/pe/PeDetailTabs.tsx index c853b99..5096a2d 100644 --- a/fe-user/src/components/pe/PeDetailTabs.tsx +++ b/fe-user/src/components/pe/PeDetailTabs.tsx @@ -1324,16 +1324,11 @@ function HangMucCard({
-
KL
-
{detail.khoiLuongNganSach}
-
-
-
ĐG ngân sách
-
{fmtMoney(detail.donGiaNganSach)}
-
-
-
Thành tiền NS
-
{fmtMoney(detail.thanhTienNganSach)}
+
Số tiền ngân sách
+
+ {fmtMoney(detail.thanhTienNganSach)} + đ +
{showBudgetCol && bgValue != null && (
@@ -1409,7 +1404,6 @@ function HangMucCard({ const hasQuotes = ev.details.some(dd => dd.quotes.some(qq => qq.purchaseEvaluationSupplierId === s.id)) const canDelete = !isWinner && !hasQuotes const openQuote = () => setQuoteEdit({ supplier: s, existing: q }) - const cellHover = !readOnly && 'cursor-pointer hover:bg-brand-50' return ( @@ -1438,16 +1432,28 @@ function HangMucCard({ readOnly={readOnly} /> - + {!readOnly ? ( + + ) : ( +
+ {q ? `${fmtMoney(q.thanhTien)} đ` : } +
)} - title={!readOnly ? 'Click để nhập / sửa số tiền' : undefined} - > - {q ? fmtMoney(q.thanhTien) : } {!readOnly && ( @@ -1519,14 +1525,18 @@ function HangMucCard({ function DetailDialog({ evaluationId, row, onClose }: { evaluationId: string; row: PeDetailRow | null; onClose: () => void }) { const qc = useQueryClient() + // Session 20 turn 5: user yêu cầu rút gọn — chỉ Tên hạng mục + Số tiền + // ngân sách (VND format) + Ghi chú. Các field schema khác (groupCode/ + // groupName/itemCode/donViTinh/khoiLuongs/donGia) giữ default cho BE + // schema backward compat — KHÔNG expose UI cho user. const [form, setForm] = useState({ - groupCode: row?.groupCode ?? 'A.I', - groupName: row?.groupName ?? '', + groupCode: row?.groupCode ?? '01', + groupName: row?.groupName ?? 'Hạng mục chính', itemCode: row?.itemCode ?? '', noiDung: row?.noiDung ?? '', - donViTinh: row?.donViTinh ?? '', - khoiLuongNganSach: row?.khoiLuongNganSach ?? 0, - khoiLuongThiCong: row?.khoiLuongThiCong ?? 0, + donViTinh: row?.donViTinh ?? 'gói', + khoiLuongNganSach: row?.khoiLuongNganSach ?? 1, + khoiLuongThiCong: row?.khoiLuongThiCong ?? 1, donGiaNganSach: row?.donGiaNganSach ?? 0, thanhTienNganSach: row?.thanhTienNganSach ?? 0, ghiChu: row?.ghiChu ?? '', @@ -1540,11 +1550,10 @@ function DetailDialog({ evaluationId, row, onClose }: { evaluationId: string; ro onError: e => toast.error(getErrorMessage(e)), }) - const updateAndRecalc = (patch: Partial) => { - const next = { ...form, ...patch } - // Auto-compute ThanhTien = KL ngân sách × ĐG ngân sách - next.thanhTienNganSach = Number(next.khoiLuongNganSach) * Number(next.donGiaNganSach) - setForm(next) + // Sync ngân sách: user nhập "Số tiền ngân sách" → set cả donGia + thanhTien + // (KL = 1 ngầm). BE giữ schema 3 field. + const setBudgetAmount = (n: number) => { + setForm({ ...form, donGiaNganSach: n, thanhTienNganSach: n }) } return ( @@ -1552,24 +1561,38 @@ function DetailDialog({ evaluationId, row, onClose }: { evaluationId: string; ro open onClose={onClose} title={(row ? 'Sửa' : 'Thêm') + ' hạng mục'} - size="lg" footer={<> } >
-
-
setForm({ ...form, groupCode: e.target.value })} />
-
setForm({ ...form, groupName: e.target.value })} placeholder="Bê tông / Phụ gia..." />
-
setForm({ ...form, itemCode: e.target.value })} />
-
setForm({ ...form, noiDung: e.target.value })} />
-
setForm({ ...form, donViTinh: e.target.value })} />
-
updateAndRecalc({ khoiLuongNganSach: Number(e.target.value) })} />
-
setForm({ ...form, khoiLuongThiCong: Number(e.target.value) })} />
-
updateAndRecalc({ donGiaNganSach: Number(e.target.value) })} />
-
setForm({ ...form, thanhTienNganSach: Number(e.target.value) })} />
-
setForm({ ...form, ghiChu: e.target.value })} />
+
+ + setForm({ ...form, noiDung: e.target.value })} + placeholder="vd Cung cấp bê tông M250" + /> +
+
+ +
+ setBudgetAmount(parseVnd(e.target.value))} + placeholder="0" + className="pr-12 font-mono text-right" + /> + đ +
+

VND — nhập số, tự format dấu chấm ngàn (vd 1.000.000)

+
+
+ + setForm({ ...form, ghiChu: e.target.value })} />