diff --git a/fe-admin/src/components/khkk/KhkkDetailContent.tsx b/fe-admin/src/components/khkk/KhkkDetailContent.tsx
index cb68a42..7218b54 100644
--- a/fe-admin/src/components/khkk/KhkkDetailContent.tsx
+++ b/fe-admin/src/components/khkk/KhkkDetailContent.tsx
@@ -645,6 +645,80 @@ export function KhkkDetailContent({
))}
+ {/* [S177 — anh: "Cho 2 cái này về làm một đc ko?"] Form thêm giờ là MỘT DÒNG
+ của chính bảng, dùng ĐÚNG lưới 4 cột — không còn panel rời bên dưới.
+ 🔴 Vì sao KHÔNG làm kiểu "bấm + đẻ ngay dòng trống rồi nhập tại chỗ" (đúng
+ lối inline của các dòng khác): `AddContractSigningPlanLineCommand:759` khai
+ `CatalogEntryId` là `Guid` **không nullable** + validator `NotEmpty()`, vì
+ unique index (Plan, Supplier, CatalogEntry) **CỐ Ý không lọc NULL**
+ (`ContractSigningPlanLineConfiguration.cs:35-38`) — trong UNIQUE của SQL
+ Server thì NULL == NULL, nên dòng trống thứ hai của CÙNG một NCC sẽ đụng
+ ngay dòng gốc của chính nó. Nới index để lách = "thả trôi vô hạn dòng
+ trùng", đúng thứ chú-thích ở đó cấm.
+ ⇒ 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 && (
+
+
+
+
+
+ {/* 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. */}
+
+
+ {/* Ghi chú xuống DÒNG PHỤ — y hệt dòng dữ liệu thật ở trên, để hai thứ
+ đọc thành CÙNG một hình dạng chứ không phải hai kiểu form. */}
+ setAddNote(e.target.value)}
+ placeholder="Ghi chú (tùy chọn)…"
+ aria-label="Ghi chú của dòng mới"
+ className="mt-1 h-7 w-full rounded border border-transparent bg-transparent px-2 text-[11px] text-slate-500 hover:border-slate-200 focus-visible:border-brand-500 focus-visible:bg-white focus-visible:outline-none"
+ />
+
+ )}
{/* 🧊 [S177 — anh: "bỏ đi"] Khối "Thêm hạng mục cho: [NCC…]" ĐÃ GỠ HẲN.
Vòng đời đủ 3 nấc trong CÙNG lượt S177, giữ vết để khỏi ai dựng lại:
(1) S175 đặt DƯỚI bảng → (2) anh: "+ thêm hạng mục ở đây" ⇒ dời vào
@@ -678,63 +752,11 @@ export function KhkkDetailContent({
mới ở đây là ký với nhà thầu chưa ai chọn (BE cũng chặn, 409).
🔴 Giữ 1 dòng vết vì đây là chỗ người sau sẽ tìm khi hỏi "nút thêm đâu rồi". */}
- {addFor && (
-
- )}
+ {/* 🧊 [S177 — anh: "Cho 2 cái này về làm một đc ko?"] Panel "Thêm hạng mục" rời
+ ĐÃ GỠ — nội dung của nó nay là 1 DÒNG trong `tbody` (xem trên), dùng chung lưới
+ 4 cột với các dòng thật. Giữ vết vì đây là chỗ người sau tìm khi hỏi form đâu.
+ 🔴 Đúng 3 trường cũ (hạng mục / giá / ghi chú) đi theo nguyên vẹn — gộp là gộp
+ CHỖ VẼ, không cắt bớt trường nào. */}
>
)}
{/* 🧊 [S175] 3 dòng chú-thích dưới bảng ĐÃ GỠ — anh: "Bỏ mấy dòng này đi".
diff --git a/fe-user/src/components/khkk/KhkkDetailContent.tsx b/fe-user/src/components/khkk/KhkkDetailContent.tsx
index cb68a42..7218b54 100644
--- a/fe-user/src/components/khkk/KhkkDetailContent.tsx
+++ b/fe-user/src/components/khkk/KhkkDetailContent.tsx
@@ -645,6 +645,80 @@ export function KhkkDetailContent({
))}
+ {/* [S177 — anh: "Cho 2 cái này về làm một đc ko?"] Form thêm giờ là MỘT DÒNG
+ của chính bảng, dùng ĐÚNG lưới 4 cột — không còn panel rời bên dưới.
+ 🔴 Vì sao KHÔNG làm kiểu "bấm + đẻ ngay dòng trống rồi nhập tại chỗ" (đúng
+ lối inline của các dòng khác): `AddContractSigningPlanLineCommand:759` khai
+ `CatalogEntryId` là `Guid` **không nullable** + validator `NotEmpty()`, vì
+ unique index (Plan, Supplier, CatalogEntry) **CỐ Ý không lọc NULL**
+ (`ContractSigningPlanLineConfiguration.cs:35-38`) — trong UNIQUE của SQL
+ Server thì NULL == NULL, nên dòng trống thứ hai của CÙNG một NCC sẽ đụng
+ ngay dòng gốc của chính nó. Nới index để lách = "thả trôi vô hạn dòng
+ trùng", đúng thứ chú-thích ở đó cấm.
+ ⇒ 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 && (
+
+
+
+
+
+ {/* 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. */}
+
+
+ {/* Ghi chú xuống DÒNG PHỤ — y hệt dòng dữ liệu thật ở trên, để hai thứ
+ đọc thành CÙNG một hình dạng chứ không phải hai kiểu form. */}
+ setAddNote(e.target.value)}
+ placeholder="Ghi chú (tùy chọn)…"
+ aria-label="Ghi chú của dòng mới"
+ className="mt-1 h-7 w-full rounded border border-transparent bg-transparent px-2 text-[11px] text-slate-500 hover:border-slate-200 focus-visible:border-brand-500 focus-visible:bg-white focus-visible:outline-none"
+ />
+
+ )}
{/* 🧊 [S177 — anh: "bỏ đi"] Khối "Thêm hạng mục cho: [NCC…]" ĐÃ GỠ HẲN.
Vòng đời đủ 3 nấc trong CÙNG lượt S177, giữ vết để khỏi ai dựng lại:
(1) S175 đặt DƯỚI bảng → (2) anh: "+ thêm hạng mục ở đây" ⇒ dời vào
@@ -678,63 +752,11 @@ export function KhkkDetailContent({
mới ở đây là ký với nhà thầu chưa ai chọn (BE cũng chặn, 409).
🔴 Giữ 1 dòng vết vì đây là chỗ người sau sẽ tìm khi hỏi "nút thêm đâu rồi". */}
- {addFor && (
-
- )}
+ {/* 🧊 [S177 — anh: "Cho 2 cái này về làm một đc ko?"] Panel "Thêm hạng mục" rời
+ ĐÃ GỠ — nội dung của nó nay là 1 DÒNG trong `tbody` (xem trên), dùng chung lưới
+ 4 cột với các dòng thật. Giữ vết vì đây là chỗ người sau tìm khi hỏi form đâu.
+ 🔴 Đúng 3 trường cũ (hạng mục / giá / ghi chú) đi theo nguyên vẹn — gộp là gộp
+ CHỖ VẼ, không cắt bớt trường nào. */}
>
)}
{/* 🧊 [S175] 3 dòng chú-thích dưới bảng ĐÃ GỠ — anh: "Bỏ mấy dòng này đi".