[CLAUDE] FE-Admin: KHKK dong nhap thang hang, bo chu thich NCC + ve khoi rieng (FE-only, 0-mig)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 6m50s

Anh khoanh 2 diem tren dong nhap. 🔴 HAI CAU TRA LOI CUA ANH MAU THUAN NHAU, khai
thang de sau nay truy duoc:
  - cau 1 anh chon: GIU dong nhap, chi bo dong chu "Them cho: NCC" cho thang hang
    (anh xem truoc cua option do VAN CON dong nhap).
  - cau 2 anh chon: "bo ca khoi dong nhap" — mo ta cua option ghi ro la mat luon
    duong them hang muc.
  Bo han thi cau 1 thanh vo nghia, VA khong con cach nao them hang muc (may KHONG
  cho de dong trong roi nhap tai cho — unique index chan 2 dong NULL cung NCC).
  => Doc theo huong lam CA HAI khop: "bo ca khoi" = bo VE KHOI RIENG (nen brand +
  vien brand khien no trong nhu mot hop la chen giua bang), dung bang anh xem truoc
  cua cau 1. Sai huong nay thi anh noi 1 cau la sua; sai huong kia la mat tinh nang
  tren prod.

Da lam:
 (1) Go dong chu-thich "Them cho: <NCC>" — no day select xuong 1 dong nen o hang muc
     lech han voi o gia + nut ben phai; go di thi ca dong nhap thang hang y nhu dong
     that (= "dua len day").
     🔴 CAI MAT, khai thang: bang KHONG co cot NCC => phieu nhieu NCC thi dong nhap
     khong con tu noi no thuoc nha cung cap nao. Anh da duoc neu danh doi va chot go.
     Neu ve sau vuong: re nhat la chen dong nhap NGAY DUOI dong vua bam + (vi tri tu
     noi NCC) thay vi them lai chu.
 (2) Go ve khoi rieng: dung dung class cua dong du lieu that
     (border-slate-100 + hover:bg-slate-50/60).
 (3) Don rac lo ra tu (1): addFor.supplierName gio duoc GAN ma khong ai doc => go
     khoi state. Ten NCC van doc duoc tu chinh dong bam + (l.supplierName cho
     title/aria-label).

Do duoc (moi ve co doi chung, va lead lai dat ky vong SAI 1 lan nua):
  - "Them cho: " = 0 ca 2 dist => chu thich da go.
  - CONTROL "Them hang muc cho " = 2 ca 2 dist => nut + van con, chung to phep do
    dang hoat dong (khong phai 0-vi-do-hong).
  - 🔸 Ky vong dau: "bg-brand-50/40" = 0 sau khi go. Do ra 12/10 — vi day la class
    DUNG CHUNG (DataTable, PeDetailTabs, PeWorkflowPanel, 3 page khac). Doi sang cum
    class NGUYEN VEN "border-b border-brand-200 bg-brand-50/40": nguon 1->0, dist 0
    ca 2 app. Day la lan thu 3 trong phien dinh bay chuoi-dung-chung.

Diff CHI 2 file FE, 0 file BE => .NET test khong the bi anh huong, bo qua vong test do
(khai ro). 2 app build sach · SHA IDENTICAL (verify identical @HEAD TRUOC khi copy de).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-08-06 16:32:59 +07:00
parent 0115c9af74
commit 1fa079d5b7
2 changed files with 38 additions and 18 deletions

View File

@ -176,7 +176,10 @@ export function KhkkDetailContent({
// [S175] File đang xem-trước inline trong khối "File đính kèm" đã gộp.
const [previewAtt, setPreviewAtt] = useState<KhkkAttachmentDto | null>(null)
// [S175] NCC đang mở form "thêm hạng mục" (null = không mở form nào).
const [addFor, setAddFor] = useState<{ supplierId: string; supplierName: string | null } | null>(null)
// [S177] Chỉ còn `supplierId`: `supplierName` đi cùng khi dòng nhập có chú-thích "Thêm cho:
// <NCC>"; anh chốt gỡ chú-thích đó ⇒ giữ lại field là **gán mà không ai đọc**. Tên NCC vẫn
// đọc được từ chính dòng bấm `+` (`l.supplierName`, dùng cho `title`/`aria-label`).
const [addFor, setAddFor] = useState<{ supplierId: string } | null>(null)
const [addCatalogId, setAddCatalogId] = useState('')
const [addAmount, setAddAmount] = useState('')
const [addNote, setAddNote] = useState('')
@ -620,7 +623,7 @@ export function KhkkDetailContent({
<button
type="button"
onClick={() => {
setAddFor({ supplierId: l.supplierId, supplierName: l.supplierName })
setAddFor({ supplierId: l.supplierId })
setAddCatalogId(''); setAddAmount(''); setAddNote('')
}}
title={`Thêm hạng mục cho ${l.supplierName ?? 'NCC này'}`}
@ -658,16 +661,23 @@ export function KhkkDetailContent({
⇒ Dòng này là **dòng nháp phía client**: trông và xếp cột y hệt dòng thật,
nhưng chỉ gọi API MỘT LẦN khi đã có hạng mục ⇒ máy giữ nguyên bất biến. */}
{isDraft && addFor && (
<tr className="border-b border-brand-200 bg-brand-50/40">
<td className="px-3 py-2 text-right align-top text-brand-500">
// [S177 — anh: "bỏ cả khối dòng nhập"] Bỏ VẺ KHỐI RIÊNG (nền brand + viền
// brand) — dùng đúng class của dòng dữ liệu thật ở trên, để nó đọc thành
// "một dòng nữa của bảng" chứ không phải "một hộp lạ chen vào giữa bảng".
<tr className="border-b border-slate-100 hover:bg-slate-50/60">
<td className="px-3 py-2 text-right align-top text-slate-400">
<Plus className="ml-auto h-3.5 w-3.5" />
</td>
<td className="px-3 py-2 align-top">
{/* NCC hiện ở đây vì bảng KHÔNG có cột NCC — không nói thì người dùng
không biết dòng mới sẽ thuộc nhà cung cấp nào. */}
<div className="mb-1 text-[11px] font-medium text-brand-700">
Thêm cho: {addFor.supplierName ?? '(không rõ NCC)'}
</div>
{/* 🧊 [S177 — anh chọn "Bỏ dòng «Thêm cho: NCC» → mọi thứ tự thẳng hàng"]
Dòng chú-thích tên NCC ĐÃ GỠ. Nó đẩy `select` xuống 1 dòng nên ô hạng
mục lệch hẳn với ô giá + nút bên phải; gỡ đi thì cả dòng nhập thẳng
hàng y như dòng thật — đó chính là "đưa lên đây".
🔴 CÁI MẤT, khai thẳng: bảng KHÔNG có cột NCC ⇒ phiếu nhiều NCC thì
dòng nhập không còn tự nói nó thuộc nhà cung cấp nào; người dùng phải
nhớ mình vừa bấm `+` ở dòng nào. Anh đã được nêu đánh đổi này và chốt
gỡ. Nếu về sau vướng: rẻ nhất là chèn dòng nhập NGAY DƯỚI dòng vừa bấm
(vị trí tự nói NCC) thay vì thêm lại chữ. */}
<select
value={addCatalogId}
onChange={(e) => setAddCatalogId(e.target.value)}

View File

@ -176,7 +176,10 @@ export function KhkkDetailContent({
// [S175] File đang xem-trước inline trong khối "File đính kèm" đã gộp.
const [previewAtt, setPreviewAtt] = useState<KhkkAttachmentDto | null>(null)
// [S175] NCC đang mở form "thêm hạng mục" (null = không mở form nào).
const [addFor, setAddFor] = useState<{ supplierId: string; supplierName: string | null } | null>(null)
// [S177] Chỉ còn `supplierId`: `supplierName` đi cùng khi dòng nhập có chú-thích "Thêm cho:
// <NCC>"; anh chốt gỡ chú-thích đó ⇒ giữ lại field là **gán mà không ai đọc**. Tên NCC vẫn
// đọc được từ chính dòng bấm `+` (`l.supplierName`, dùng cho `title`/`aria-label`).
const [addFor, setAddFor] = useState<{ supplierId: string } | null>(null)
const [addCatalogId, setAddCatalogId] = useState('')
const [addAmount, setAddAmount] = useState('')
const [addNote, setAddNote] = useState('')
@ -620,7 +623,7 @@ export function KhkkDetailContent({
<button
type="button"
onClick={() => {
setAddFor({ supplierId: l.supplierId, supplierName: l.supplierName })
setAddFor({ supplierId: l.supplierId })
setAddCatalogId(''); setAddAmount(''); setAddNote('')
}}
title={`Thêm hạng mục cho ${l.supplierName ?? 'NCC này'}`}
@ -658,16 +661,23 @@ export function KhkkDetailContent({
⇒ Dòng này là **dòng nháp phía client**: trông và xếp cột y hệt dòng thật,
nhưng chỉ gọi API MỘT LẦN khi đã có hạng mục ⇒ máy giữ nguyên bất biến. */}
{isDraft && addFor && (
<tr className="border-b border-brand-200 bg-brand-50/40">
<td className="px-3 py-2 text-right align-top text-brand-500">
// [S177 — anh: "bỏ cả khối dòng nhập"] Bỏ VẺ KHỐI RIÊNG (nền brand + viền
// brand) — dùng đúng class của dòng dữ liệu thật ở trên, để nó đọc thành
// "một dòng nữa của bảng" chứ không phải "một hộp lạ chen vào giữa bảng".
<tr className="border-b border-slate-100 hover:bg-slate-50/60">
<td className="px-3 py-2 text-right align-top text-slate-400">
<Plus className="ml-auto h-3.5 w-3.5" />
</td>
<td className="px-3 py-2 align-top">
{/* NCC hiện ở đây vì bảng KHÔNG có cột NCC — không nói thì người dùng
không biết dòng mới sẽ thuộc nhà cung cấp nào. */}
<div className="mb-1 text-[11px] font-medium text-brand-700">
Thêm cho: {addFor.supplierName ?? '(không rõ NCC)'}
</div>
{/* 🧊 [S177 — anh chọn "Bỏ dòng «Thêm cho: NCC» → mọi thứ tự thẳng hàng"]
Dòng chú-thích tên NCC ĐÃ GỠ. Nó đẩy `select` xuống 1 dòng nên ô hạng
mục lệch hẳn với ô giá + nút bên phải; gỡ đi thì cả dòng nhập thẳng
hàng y như dòng thật — đó chính là "đưa lên đây".
🔴 CÁI MẤT, khai thẳng: bảng KHÔNG có cột NCC ⇒ phiếu nhiều NCC thì
dòng nhập không còn tự nói nó thuộc nhà cung cấp nào; người dùng phải
nhớ mình vừa bấm `+` ở dòng nào. Anh đã được nêu đánh đổi này và chốt
gỡ. Nếu về sau vướng: rẻ nhất là chèn dòng nhập NGAY DƯỚI dòng vừa bấm
(vị trí tự nói NCC) thay vì thêm lại chữ. */}
<select
value={addCatalogId}
onChange={(e) => setAddCatalogId(e.target.value)}