Compare commits
3 Commits
530af22910
...
b346b41561
| Author | SHA1 | Date | |
|---|---|---|---|
| b346b41561 | |||
| 0ce00108d8 | |||
| 21f7261456 |
@ -1,40 +1,54 @@
|
|||||||
# WAL — auto-generated, không sửa tay
|
# WAL — auto-generated, không sửa tay
|
||||||
updated: 2026-08-06 | session: S176 (phiên-LOGIC L11, window 4) | branch: main
|
updated: 2026-08-06 | session: S177 (phiên-LOGIC L11, window 5) | branch: main
|
||||||
|
|
||||||
goal: UAT KHKK vòng-4 + 4b ĐÃ ship+deploy VERIFY (chưa ai soi mắt). Nửa sau phiên: anh chốt dựng ĐỘI STYLE 3 vai — đã land, engine chấm `SỬA-6`, CHƯA vá điểm nào.
|
goal: nối mạch S177 → anh CHEN việc mới ở màn duyệt KHKK (bỏ "(N dòng)" + STT/mã hạng mục) — **SHIP `530af22` + deploy VERIFIED 2-vế ×2 app + Mig 72 áp prod + backfill đo trên dữ-liệu THẬT**. Engine `SỬA-6` vẫn treo nguyên, chưa vá điểm nào.
|
||||||
|
|
||||||
chain:
|
chain:
|
||||||
- [x] nối mạch /tiep @S176 (window 4): Sàn-3 ⑤=3 + ① kêu **2** orphan + ORPHAN-L(p=4,t=2) · 7/7 `verify:` KHỚP · tick 49→50 · `_tiep-3.md` cân sổ
|
- [x] nối mạch /tiep @S177 (window 5): Sàn-3 4/5 tín-hiệu MẠNH kêu (①=2 orphan · ② `090ab1c` · ④ · ⑤ ORPHAN-L p=5,t=3) · **8/8 `verify:` KHỚP** · tick 50→51 · `_tiep-4.md` cân sổ
|
||||||
- [x] `ctx-verifier` @/tiep = `NAP-LAI-SAN-SANG — 10 cờ`; lead tự đo lại 3 cờ nặng **CẢ 3 CONFIRMED** → flush bảng Owner-items `runs/…S174…/run.md` 6 dòng + dòng CÒN NỢ (O1 `43e1bd7` · O3 hai vế `a0ccac3`+`b811e11` · O4/O6/O7/O8 `a0ccac3`)
|
- [x] §3-ter nạp lớp mềm = **lead tự chạy 4-khoản** (fallback có khai — anh chen việc, không đốt round-trip sub). `ctx-verifier` KHÔNG spawn
|
||||||
- [x] anh soi prod → vòng-3 **"tạm ổn"**; cột DỰ ÁN 11 ô + `BudgetTotal` 61/69 = anh **PARK** ("chưa quan tâm lúc này") — đừng hỏi lại, đừng tự làm
|
- [x] 🔴 lead tự bắt lỗi mình 2 phép đo: ① dò thư quét `../AI_INFRA…` — **repo không nằm ở đó** ⇒ `se=0 all=0` là RỖNG-VÌ-HỎI-SAI-CHỖ, số sống vẫn là `se=0 all=6` của PAUSE-5 · ② `curl` rơi `a2.js` vào repo-root, đã dọn
|
||||||
- [x] **vòng-4 ship `097e41a` + deploy VERIFIED 2-vế ×2 app** (admin `C-92w73N` · eoffice `B7jZIgBO`): 3 menu Đang duyệt/Đã duyệt/Đã xóa → cây 4 tầng Năm›Dự án›Hạng mục›phiếu (= **O5 anh phán GIỮ CÂY**). `leafMode` OPT-IN + `buildTree(rows,weightOf)` đếm PHIẾU thay GÓI + tỉa nhánh 0-phiếu; `flatMode` GIỮ `!canPe`+`term` (2 đường thoát). 🔴 Lead tự bắt lỗi mình: bản đầu có vế `group !== null` — mà CẢ 4 leaf menu đều mang `?group=1` ⇒ kéo luôn màn toàn-cảnh; đã bỏ
|
- [x] **[S177 việc anh giao] KHKK màn duyệt — BE+FE xong, build+test sạch, CHƯA COMMIT/SHIP**
|
||||||
- [x] **vòng-4b ship `3794d89` + deploy VERIFIED 2-vế ×2 app** (admin `CKHbvmFY` · eoffice `C0pa950_`): thùng rác KHKK theo MẪU màn Duyệt NCC (anh gửi ảnh PE = *"ảnh chỉ là mẫu — em soi lại KHKK"*) → +banner đỏ (THAY dropdown: phiếu giữ phase lúc xoá, lọc = nút chết) +dấu `🗑 xóa ≈` (dùng `updatedAt` vì DTO `/deleted` không có `deletedAt` ⇒ nhãn `≈`). 🔸 **CỐ Ý BỎ vế "lũy kế"** của PE — KHKK 0 hit; control bundle prod: `lũy kế` giữ **1**/1 · 2 chuỗi mới **2**/2
|
· ① bỏ `(N dòng)` khỏi `title` Section 2 (`KhkkDetailContent.tsx`)
|
||||||
- [x] **ĐỘI STYLE 3 vai land `090ab1c`** (anh chốt: *"tính năng đã deploy production = chuẩn, trừ khi tao điều chỉnh lại"*; anh nêu 4 rồi tự chốt 3): `front-end/back-end/database-reviewer-style` + `hmw.js` VALID_ROLES 23→**26** + writeGuard + README §RULE + STATUS Sub-agents 23→26
|
· ② bảng 3→**4 cột** (+STT cột riêng, anh chốt) · cột HẠNG MỤC thêm dòng mã `<mã dự án> - <mã chi tiết>` trên tên
|
||||||
- [!] 🔴 **`/fable-real reviewer` `wf_264fb5c2-0db` = `SETUP-REVIEW: SỬA-6`** (nền ĐỨNG VỮNG, không BÁC) — **6 điểm CHƯA vá cái nào** (dừng vì /pause). Kế-hoạch + acceptance đo-được: `runs/2026-08-06-S176-doi-style-3-vai/spec-va-doi-style-3-vai-06-08-2026.md`
|
· **Mig 72** `AddMaHangMucToContractSigningPlanLines` (anh chốt DENORM có migration) + backfill `Sql()` idempotent, CỐ Ý không lọc `IsDeleted` (cứu cả hạng mục đã xoá mềm)
|
||||||
- [!] 🔴 **SỬA-1 SỐNG-CHẾT — vá TRƯỚC HẾT:** thước dispatch dùng `git diff origin/main...HEAD` (**ba-chấm**) ⇒ mù uncommitted+untracked; đội là gate PRE-commit ⇒ lúc review lệnh trả RỖNG ⇒ **0 spawn, 0 SKIP-CO-KHAI để lộ** ⇒ **đội chết CÂM**. Sửa 4 site → `git diff origin/main` (2-chấm) ∪ `git status --porcelain` lọc `??`
|
· `PeWorkItemCode` **KHÔNG denorm** — nới join `WorkItems` sẵn có ở `Features.cs:929`, 0 cột mới
|
||||||
- [!] 🔴 **SỬA-5a (rẻ nhất, làm cùng lượt):** 3 vai style **thiếu dir `agent-memory/<vai>/`** ⇒ `measure-agent-memory.ps1` enumerate theo DIR ⇒ 3 vai **vô hình câm** trong đo/budget. Lead tự đo lại: **3/3 THIẾU — CONFIRMED**
|
· 3 write-site denorm sửa ĐỦ (`:527` mồi null · `:695` gán lại · `:805` tạo mới) — sót 1 là đẻ dòng có tên không mã
|
||||||
- [ ] SỬA-2 phạm-vi chuẩn quá rộng (`deploy.yml:20-27` paths-ignore chưa từng deploy · cửa-sổ deploy-FAIL) · SỬA-3 miễn-trừ = dấu-cao-su (2/3 nguồn do chính lead viết ⇒ đòi TRÍCH NGUYÊN VĂN) · SỬA-4 thách-CLEAN nhánh DAT bẻ được (đòi cặp neo `file:line ⇄ file:line`)
|
· 2 app SHA **IDENTICAL** (verify identical @HEAD TRƯỚC khi copy đè) · 644/644 test · lint 42 vấn-đề = **NỢ CÓ SẴN, 0 cái ở file tôi sửa**
|
||||||
- [ ] SỬA-5b khai vùng mù (seam FE↔BE + ngoài 3 glob = 0 vai soi) · SỬA-5c `README:67` ra lệnh gọi mà thiếu nhãn "(hiệu-lực sau restart CLI)" + thiếu nhánh style ở decision-tree
|
- [x] **SHIP `530af22` + deploy VERIFIED** (anh chốt ship): bundle đổi ×2 app (admin `B-m_oxS2` · eoffice `IsXERmML`, 360s)
|
||||||
- [ ] SỬA-6a claim "BE 0 máy style" chép **4 site** ⇒ biến thành phép-đo per-spawn · SỬA-6b lead **chép luật vào persona** vi phạm chính B1 viết cùng file (`db:32/34-35/61` · `be:63` · `fe:4` chép digits — class đã drift thật: CLAUDE.md "React 18" vs package.json ^19.2.5)
|
· **byte-level 3/3 chuỗi KHỚP local↔prod CẢ 2 APP** — `2. Hạng mục (` = **0** (dạng đếm cũ đã chết) · `2. Hạng mục` 2=2 · `STT` admin 2=2, user 1=1
|
||||||
- [ ] 🔴 3 vai style **CHƯA spawn-probe** — registry no-hot-reload, nấc = executed-file/verified-pending-restart. Cần restart CLI
|
· 🔴 2 dị-thường đều TRUY RA NGUỒN trước khi kết luận: `2. Hạng mục`=2 vì **PE** có section trùng tiền-tố (`PeDetailTabs:405`) · `STT` admin>user vì `AttendanceReportPage` chỉ có ở admin. Mỗi app khớp ĐÚNG dist của CHÍNH NÓ
|
||||||
- [ ] 🔴 2 NỢ vòng-3: ① khung thẻ **2 nguồn sự-thật** (`index.css:112` ⟂ utility hardcode ×2 app) · ② overclaim gotcha #66 **4 site / 2 CHUỖI KHÁC NHAU** (`KhkkWorkflowPanel:278` ×2 = *"đè là vô hiệu"* SAI thẳng ⟂ `PipelineTreePanel:226` ×2 = chẩn ĐÚNG chỉ câu kết quá rộng). **Grep 1 chuỗi = vá 2/4 rồi tưởng xong**
|
· 🔴 bundle CŨ không dùng làm đối-chứng được (trả **900B** = SPA fallback, deploy đã dọn asset) — dùng local-dist thay
|
||||||
- [ ] 🔴 đính-chính `_context-s-11.md:152` — *"Lead đã flush (a)"* SAI: flush **1/7**. `_context` append-only ⇒ đính chính bằng entry PAUSE-6
|
· **Mig 72 CONFIRMED prod** = dòng đầu `__EFMigrationsHistory`. Backfill đo dữ-liệu THẬT: 7 dòng · 5 có hạng mục · **5/5 đã có mã** (2 dòng chưa gán ⇒ NULL, đúng bất-biến)
|
||||||
- [ ] 🔴 ghi synthesis cho **2** run-folder ORPHAN: ① `2026-08-05-S173-bookend-open` · ② `2026-08-05-S175-duan-budget-column`
|
· sqlcmd qua **integrated auth `-E`**, KHÔNG đụng mật khẩu prod (`$env:PROD_DB_PASSWORD` trống trong phiên ssh — không đi tìm)
|
||||||
|
· smoke: admin/eoffice **200** · api `/api/contract-signing-plans` + `/api/auth/me` **401** (pipeline auth sống, không phải IIS đứng suông)
|
||||||
|
- [!] 🔴 `/fable-real reviewer` `wf_264fb5c2-0db` = `SETUP-REVIEW: SỬA-6` (nền ĐỨNG VỮNG) — **6 điểm CHƯA vá cái nào**. Spec: `runs/2026-08-06-S176-doi-style-3-vai/spec-va-doi-style-3-vai-06-08-2026.md`
|
||||||
|
- [!] 🔴 **SỬA-1 SỐNG-CHẾT:** thước dispatch `git diff origin/main...HEAD` (**ba-chấm**) ⇒ mù uncommitted+untracked ⇒ đội gate PRE-commit **chết CÂM** (0 spawn, 0 SKIP để lộ). Sửa 4 site → 2-chấm ∪ `porcelain` lọc `??`
|
||||||
|
- [!] 🔴 **SỬA-5a (rẻ nhất):** 3 vai style thiếu dir `agent-memory/<vai>/` ⇒ vô hình trong đo/budget. Lead đo lại: **3/3 THIẾU CONFIRMED**
|
||||||
|
- [ ] SỬA-2 phạm-vi chuẩn quá rộng · SỬA-3 miễn-trừ dấu-cao-su (đòi TRÍCH NGUYÊN VĂN) · SỬA-4 thách-CLEAN nhánh DAT bẻ được (đòi cặp neo `file:line ⇄ file:line`)
|
||||||
|
- [ ] SỬA-5b vùng mù (seam FE↔BE + ngoài 3 glob) · SỬA-5c `README:67` thiếu nhãn "(hiệu-lực sau restart CLI)" + thiếu nhánh style ở decision-tree
|
||||||
|
- [ ] SỬA-6a claim "BE 0 máy style" chép 4 site · SỬA-6b lead chép luật vào persona (vi phạm chính B1) — `db:32/34-35/61` · `be:63` · `fe:4` chép digits
|
||||||
|
- [ ] 🔴 3 vai style **CHƯA spawn-probe** — registry no-hot-reload, cần restart CLI
|
||||||
|
- [ ] 🔴 2 NỢ vòng-3: ① khung thẻ 2 nguồn sự-thật (`index.css:112` ⟂ utility hardcode ×2 app) · ② overclaim gotcha #66 **4 site / 2 CHUỖI KHÁC NHAU** (grep 1 chuỗi = vá 2/4 rồi tưởng xong)
|
||||||
|
- [ ] 🔴 đính-chính `_context-s-11.md:152` — *"Lead đã flush (a)"* SAI: flush **1/7**. Append-only ⇒ đính chính bằng entry PAUSE-6
|
||||||
|
- [ ] 🔴 ghi synthesis cho **2** run-folder ORPHAN: `2026-08-05-S173-bookend-open` · `2026-08-05-S175-duan-budget-column`
|
||||||
- [ ] E4 vế ➊ · 5 điểm governance (`STATUS:473` 86→87 · 5 slot HANDOFF · `ROTATE vrapp` · Carry 14 slug · slot (70) anchor) · A1 `ring2-audit` 26.440B>25.600 · drift-audit quá hạn · 9 dir rỗng
|
- [ ] E4 vế ➊ · 5 điểm governance (`STATUS:473` 86→87 · 5 slot HANDOFF · `ROTATE vrapp` · Carry 14 slug · slot (70) anchor) · A1 `ring2-audit` 26.440B>25.600 · drift-audit quá hạn · 9 dir rỗng
|
||||||
- [ ] kéo thư: đo @PAUSE-5 `se=0 all=6` (2 `loi-do-luong` + 4 `upgrade-pack-phased` thiếu adap-report)
|
- [ ] kéo thư `all=6` (2 `loi-do-luong` + 4 `upgrade-pack-phased` thiếu adap-report) — 🔴 đo lại bằng ĐÚNG đường, đừng lặp lỗi quét `../`
|
||||||
- [ ] ⚠️ roster **26** > `hmw_width.cap` **20** ⇒ full-roster-sweep LOUD-skip 6 lane cuối (có log `hmw.js:165-169`, KHÔNG câm). Số cap = quyền anh, O-7 treo
|
- [ ] ⚠️ roster **26** > `hmw_width.cap` **20** ⇒ full-roster-sweep LOUD-skip 6 lane cuối. Số cap = quyền anh, O-7 treo
|
||||||
- 🅿️ **PARK (anh @S176) — KHÔNG hỏi lại, KHÔNG tự làm:** cột DỰ ÁN 11 ô · `Project.BudgetTotal` rỗng 61/69
|
- 🅿️ **PARK (anh @S176) — KHÔNG hỏi lại, KHÔNG tự làm:** cột DỰ ÁN 11 ô · `Project.BudgetTotal` rỗng 61/69
|
||||||
- 🔴 **CHƯA ai soi mắt prod** vòng-4 + 4b (375/1366/1440) — mọi kết luận giao diện vẫn là ĐỌC MÃ (gotcha #3)
|
- 🔴 **CHƯA ai soi mắt prod** vòng-4 + 4b (375/1366/1440) — kết luận giao diện vẫn là ĐỌC MÃ (gotcha #3)
|
||||||
|
|
||||||
next: /tiep → vá SỬA-1 (thước dispatch) TRƯỚC HẾT + SỬA-5a (seed 3 dir) → 2/3/4/5b/5c/6a/6b → re-review; song song CHỜ anh soi prod vòng-4/4b
|
next: vá **SỬA-1** (thước dispatch — đội STYLE đang chết câm, lượt S177 sửa 6 file ĐÚNG địa phận cả 3 vai mà 0 con được gọi) → SỬA-5a → 2/3/4/5b/5c/6a/6b → re-review · song song CHỜ anh soi mắt prod vòng-4/4b + S177
|
||||||
|
|
||||||
verify:
|
verify:
|
||||||
|
- `grep -c 'MaHangMuc' src/Backend/SolutionErp.Domain/ContractSigningPlans/ContractSigningPlanLine.cs` → **1** = entity đã có cột
|
||||||
|
- `ls src/Backend/SolutionErp.Infrastructure/Persistence/Migrations/*AddMaHangMuc*.cs | wc -l` → **2** (Migration + Designer; +ModelSnapshot = 3-file rule)
|
||||||
|
- `grep -c 'colSpan={2}' fe-admin/src/components/khkk/KhkkDetailContent.tsx` → **1** = tfoot đã nuốt cột STT
|
||||||
|
- `sha256sum fe-{admin,user}/src/components/khkk/KhkkDetailContent.tsx` → 2 hash BẰNG NHAU (mirror)
|
||||||
- `grep -rn 'origin/main\.\.\.HEAD' .claude/agents/ | wc -l` → **4** = SỬA-1 CHƯA vá (đích: 0)
|
- `grep -rn 'origin/main\.\.\.HEAD' .claude/agents/ | wc -l` → **4** = SỬA-1 CHƯA vá (đích: 0)
|
||||||
- `ls -d .claude/agent-memory/*-reviewer-style 2>/dev/null | wc -l` → **0** = SỬA-5a chưa làm (đích: 3)
|
- `ls -d .claude/agent-memory/*-reviewer-style 2>/dev/null | wc -l` → **0** = SỬA-5a chưa làm (đích: 3)
|
||||||
- `curl -s https://admin.solutions.com.vn/ | grep -oE 'index-[A-Za-z0-9_-]+\.js'` → khác `index-CKHbvmFY.js` = đợt SAU đã tới (mốc @S176 vòng-4b = `3794d89`)
|
- `curl -s https://admin.solutions.com.vn/ | grep -oE 'index-[A-Za-z0-9_-]+\.js'` → khác `index-B-m_oxS2.js` = đợt SAU đã tới (mốc S177 = `530af22`; eoffice `index-IsXERmML.js`)
|
||||||
- 🔴 LUẬT ĐO bundle: `grep -o '<chuỗi>' | wc -l`, **KHÔNG** `grep -c` (minify = 1 mega-dòng). Chuỗi DÙNG-CHUNG phải hỏi "còn ai dùng nữa không" TRƯỚC khi kết luận
|
- `ssh vietreport-vps 'sqlcmd -S .\SQLEXPRESS -d SolutionErp -E -Q "..."'` → **integrated auth, KHÔNG cần mật khẩu**. Mốc: Mig 72 = dòng đầu `__EFMigrationsHistory`; `ContractSigningPlanLines` 5/5 dòng-có-hạng-mục đã có `MaHangMuc`
|
||||||
- `grep -o 'không còn tính vào lũy kế' /tmp/a2.js | wc -l` → **1** (chỉ PE) = chứng KHÔNG bê nguyên banner sang KHKK
|
- 🔴 LUẬT ĐO bundle: `grep -o '<chuỗi>' | wc -l`, **KHÔNG** `grep -c` (minify = 1 mega-dòng)
|
||||||
- `wc -c .claude/agent-memory/ring2-audit/MEMORY.md` → 26440 (>25600 = còn nợ A1)
|
- `wc -c .claude/agent-memory/ring2-audit/MEMORY.md` → 26440 (>25600 = còn nợ A1)
|
||||||
- `sed -n '473p' docs/STATUS.md | grep -c 'Gotchas | \*\*86\*\*'` → 1 = chưa vá
|
- 🔴 chạy khối DUAL-ACCEPT `tiep.md §0 ①` → kỳ vọng **2** ORPHAN
|
||||||
- 🔴 chạy khối DUAL-ACCEPT `tiep.md §0 ①` (đừng `ls` 1 folder) → kỳ vọng **2** ORPHAN: `…S173-bookend-open` + `…S175-duan-budget-column`
|
- `ls .claude/sessions/session-11/` → _context · _mind · _pause-1..5 · _tiep-1..4
|
||||||
- `ls .claude/sessions/session-11/` → _context · _mind · _pause-1..5 · _tiep-1/2/3
|
|
||||||
|
|||||||
6
.claude/sessions/session-11/_tiep-4.md
Normal file
6
.claude/sessions/session-11/_tiep-4.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
ts: 2026-08-06T13:35:00+07:00
|
||||||
|
head-sha: d081681
|
||||||
|
window-ordinal: 5
|
||||||
|
jsonl-hint: D--Dropbox-CONG-VIEC-SOLUTION-SOLUTION-ERP/8db6a47b-a6fc-4268-a9df-266308bb2d03
|
||||||
|
account-label: none
|
||||||
|
ctx-verifier: SKIP-CO-KHAI - lead tu chay 4-khoan (fallback tiep.md 3-ter, khai ro): anh chen viec moi giua luot /tiep (anh prod man duyet KHKK, 2 yeu cau) => uu tien viec anh, khong dot round-trip sub luc anh dang cho. Khoan B khop next: (SUA-1 truoc het). Khoan C khop ban-do (WAL chain + 2 run-folder orphan). Khoan D: 0 y doi nhan. Con-tro giai duoc.
|
||||||
@ -452,12 +452,10 @@ export function KhkkDetailContent({
|
|||||||
<Field label="Mã kế hoạch" value={plan.maKeHoach ?? '—'} mono />
|
<Field label="Mã kế hoạch" value={plan.maKeHoach ?? '—'} mono />
|
||||||
<Field label="Dự án" value={plan.projectName ?? '—'} />
|
<Field label="Dự án" value={plan.projectName ?? '—'} />
|
||||||
<Field label="Người soạn" value={plan.drafterFullName ?? '—'} />
|
<Field label="Người soạn" value={plan.drafterFullName ?? '—'} />
|
||||||
{/* [S175 — anh: "hạng mục của Dự án, Duyệt NCC ấy"] Đây là HẠNG MỤC CÔNG VIỆC của
|
{/* 🧊 [S177 — anh: "Làm header dưới đây"] Ô **Hạng mục (dự án)** ĐÃ DỜI xuống làm
|
||||||
dự án, lấy từ phiếu Duyệt NCC nguồn (`PE.WorkItemId`).
|
header của mục 2 (xem ngay dưới). Nó là gói việc mà CẢ BẢNG hạng mục thuộc về,
|
||||||
🔴 KHÁC hẳn `line.tenHangMuc` — cái đó là danh-mục SP-002 dùng phân loại HỢP
|
nên đứng đầu bảng thì đúng vai hơn là nằm lẫn giữa các ô meta ở đây.
|
||||||
ĐỒNG (86 dòng, chọn ở mục 2). Hai thứ trùng tên tiếng Việt nhưng khác trục;
|
🔸 Chú thích S175 cũ ("xếp NGAY DƯỚI Dự án ở cột PHẢI") hết hiệu lực theo. */}
|
||||||
lượt trước lead bày nhầm cái SP-002 ở đây nên anh bảo "Bỏ đi". */}
|
|
||||||
<Field label="Hạng mục (dự án)" value={plan.peWorkItemName ?? '—'} />
|
|
||||||
<Field label="Ngày tạo" value={formatDateTime(plan.createdAt)} />
|
<Field label="Ngày tạo" value={formatDateTime(plan.createdAt)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -489,6 +487,19 @@ export function KhkkDetailContent({
|
|||||||
) : undefined
|
) : undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{/* [S177 — anh: "Làm header dưới đây"] HẠNG MỤC (DỰ ÁN) = gói việc mà CẢ bảng dưới
|
||||||
|
thuộc về, dời từ mục 1 xuống đây làm header của mục 2.
|
||||||
|
🔴 ĐẶT NGOÀI ternary `lines.length === 0`: phiếu chưa có NCC trúng thầu thì vẫn
|
||||||
|
phải biết mình đang lập kế hoạch cho gói việc nào — nhét vào nhánh có-dòng là
|
||||||
|
đúng ca "vắng-mặt trông giống ổn" (màn rỗng nhìn vẫn gọn nên không ai kêu). */}
|
||||||
|
<div className="mb-3 flex flex-wrap items-baseline gap-x-2 gap-y-0.5 border-b border-slate-200 pb-2">
|
||||||
|
<span className="label-eyebrow text-slate-500">Hạng mục (dự án)</span>
|
||||||
|
{plan.peWorkItemCode && (
|
||||||
|
<span className="font-mono text-[11px] font-medium text-slate-500">{plan.peWorkItemCode}</span>
|
||||||
|
)}
|
||||||
|
<span className="text-sm font-semibold text-slate-800">{plan.peWorkItemName ?? '—'}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{plan.lines.length === 0 ? (
|
{plan.lines.length === 0 ? (
|
||||||
<div className="text-sm italic text-slate-400">Phiếu nguồn chưa có NCC trúng thầu.</div>
|
<div className="text-sm italic text-slate-400">Phiếu nguồn chưa có NCC trúng thầu.</div>
|
||||||
) : (
|
) : (
|
||||||
@ -608,6 +619,33 @@ export function KhkkDetailContent({
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
{/* [S177 — anh: "+ thêm hạng mục ở đây"] Nút thêm DỜI TỪ DƯỚI BẢNG vào
|
||||||
|
thành dòng cuối của `tbody` — ngay sau dòng dữ liệu cuối, TRÊN dòng TỔNG.
|
||||||
|
🔴 `colSpan={4}` (không phải 3): bảng đã lên 4 cột từ đầu lượt S177.
|
||||||
|
🔸 Panel nhập (`addFor`) VẪN Ở NGOÀI bảng — nó là form nhiều ô, nhét vào
|
||||||
|
trong `<table>` thì vỡ lưới `table-fixed` đang giữ 3 cột số thẳng hàng. */}
|
||||||
|
{isDraft && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4} className="px-3 py-2">
|
||||||
|
<div className="flex flex-wrap items-center gap-1.5">
|
||||||
|
<span className="text-[11px] text-slate-500">Thêm hạng mục cho:</span>
|
||||||
|
{[...new Map(plan.lines.map(l => [l.supplierId, l])).values()].map((l) => (
|
||||||
|
<button
|
||||||
|
key={l.supplierId}
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setAddFor({ supplierId: l.supplierId, supplierName: l.supplierName })
|
||||||
|
setAddCatalogId(''); setAddAmount(''); setAddNote('')
|
||||||
|
}}
|
||||||
|
className="inline-flex items-center gap-1 rounded border border-brand-300 px-2 py-1 text-[11px] font-medium text-brand-700 transition hover:bg-brand-50"
|
||||||
|
>
|
||||||
|
<Plus className="h-3 w-3" /> {l.supplierName ?? '(không rõ NCC)'}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
{/* [S175 — anh: "chọn hạng mục tiền → thành tổng"] TỔNG = Σ giá các dòng.
|
{/* [S175 — anh: "chọn hạng mục tiền → thành tổng"] TỔNG = Σ giá các dòng.
|
||||||
🔴 KHÔNG có cột "giá tham chiếu" / "giá duyệt" nữa — anh chốt "ko cần so
|
🔴 KHÔNG có cột "giá tham chiếu" / "giá duyệt" nữa — anh chốt "ko cần so
|
||||||
@ -628,29 +666,11 @@ export function KhkkDetailContent({
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* [S175 — anh chốt] THÊM HẠNG MỤC cho 1 NCC. 1 NCC được N hạng mục: máy đã cho
|
{/* 🧊 [S177 — anh: "+ thêm hạng mục ở đây"] Khối "Thêm hạng mục cho:" ĐÃ DỜI vào
|
||||||
phép từ Mig 71 (unique 3 cột `Plan × Supplier × CatalogEntry`), lượt này chỉ
|
trong `tbody` (dòng cuối, trên TỔNG). Lý lẽ S175 vẫn đúng và đi theo lên trên:
|
||||||
bung UI — đúng khuôn "máy rộng, UI hẹp" anh chốt S164.
|
1 NCC được N hạng mục từ Mig 71, và CHỈ liệt kê NCC ĐÃ CÓ trên phiếu — đẻ NCC
|
||||||
🔴 CHỈ liệt kê NCC ĐÃ CÓ trên phiếu: NCC đến từ winner của phiếu Duyệt NCC;
|
mới ở đây là ký với nhà thầu chưa ai chọn (BE cũng chặn, 409).
|
||||||
đẻ NCC 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". */}
|
||||||
{isDraft && (
|
|
||||||
<div className="mt-3 flex flex-wrap items-center gap-1.5">
|
|
||||||
<span className="text-[11px] text-slate-500">Thêm hạng mục cho:</span>
|
|
||||||
{[...new Map(plan.lines.map(l => [l.supplierId, l])).values()].map((l) => (
|
|
||||||
<button
|
|
||||||
key={l.supplierId}
|
|
||||||
type="button"
|
|
||||||
onClick={() => {
|
|
||||||
setAddFor({ supplierId: l.supplierId, supplierName: l.supplierName })
|
|
||||||
setAddCatalogId(''); setAddAmount(''); setAddNote('')
|
|
||||||
}}
|
|
||||||
className="inline-flex items-center gap-1 rounded border border-brand-300 px-2 py-1 text-[11px] font-medium text-brand-700 transition hover:bg-brand-50"
|
|
||||||
>
|
|
||||||
<Plus className="h-3 w-3" /> {l.supplierName ?? '(không rõ NCC)'}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{addFor && (
|
{addFor && (
|
||||||
<div className="mt-2 rounded-md border border-brand-200 bg-brand-50/50 p-3">
|
<div className="mt-2 rounded-md border border-brand-200 bg-brand-50/50 p-3">
|
||||||
|
|||||||
@ -452,12 +452,10 @@ export function KhkkDetailContent({
|
|||||||
<Field label="Mã kế hoạch" value={plan.maKeHoach ?? '—'} mono />
|
<Field label="Mã kế hoạch" value={plan.maKeHoach ?? '—'} mono />
|
||||||
<Field label="Dự án" value={plan.projectName ?? '—'} />
|
<Field label="Dự án" value={plan.projectName ?? '—'} />
|
||||||
<Field label="Người soạn" value={plan.drafterFullName ?? '—'} />
|
<Field label="Người soạn" value={plan.drafterFullName ?? '—'} />
|
||||||
{/* [S175 — anh: "hạng mục của Dự án, Duyệt NCC ấy"] Đây là HẠNG MỤC CÔNG VIỆC của
|
{/* 🧊 [S177 — anh: "Làm header dưới đây"] Ô **Hạng mục (dự án)** ĐÃ DỜI xuống làm
|
||||||
dự án, lấy từ phiếu Duyệt NCC nguồn (`PE.WorkItemId`).
|
header của mục 2 (xem ngay dưới). Nó là gói việc mà CẢ BẢNG hạng mục thuộc về,
|
||||||
🔴 KHÁC hẳn `line.tenHangMuc` — cái đó là danh-mục SP-002 dùng phân loại HỢP
|
nên đứng đầu bảng thì đúng vai hơn là nằm lẫn giữa các ô meta ở đây.
|
||||||
ĐỒNG (86 dòng, chọn ở mục 2). Hai thứ trùng tên tiếng Việt nhưng khác trục;
|
🔸 Chú thích S175 cũ ("xếp NGAY DƯỚI Dự án ở cột PHẢI") hết hiệu lực theo. */}
|
||||||
lượt trước lead bày nhầm cái SP-002 ở đây nên anh bảo "Bỏ đi". */}
|
|
||||||
<Field label="Hạng mục (dự án)" value={plan.peWorkItemName ?? '—'} />
|
|
||||||
<Field label="Ngày tạo" value={formatDateTime(plan.createdAt)} />
|
<Field label="Ngày tạo" value={formatDateTime(plan.createdAt)} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -489,6 +487,19 @@ export function KhkkDetailContent({
|
|||||||
) : undefined
|
) : undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
{/* [S177 — anh: "Làm header dưới đây"] HẠNG MỤC (DỰ ÁN) = gói việc mà CẢ bảng dưới
|
||||||
|
thuộc về, dời từ mục 1 xuống đây làm header của mục 2.
|
||||||
|
🔴 ĐẶT NGOÀI ternary `lines.length === 0`: phiếu chưa có NCC trúng thầu thì vẫn
|
||||||
|
phải biết mình đang lập kế hoạch cho gói việc nào — nhét vào nhánh có-dòng là
|
||||||
|
đúng ca "vắng-mặt trông giống ổn" (màn rỗng nhìn vẫn gọn nên không ai kêu). */}
|
||||||
|
<div className="mb-3 flex flex-wrap items-baseline gap-x-2 gap-y-0.5 border-b border-slate-200 pb-2">
|
||||||
|
<span className="label-eyebrow text-slate-500">Hạng mục (dự án)</span>
|
||||||
|
{plan.peWorkItemCode && (
|
||||||
|
<span className="font-mono text-[11px] font-medium text-slate-500">{plan.peWorkItemCode}</span>
|
||||||
|
)}
|
||||||
|
<span className="text-sm font-semibold text-slate-800">{plan.peWorkItemName ?? '—'}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{plan.lines.length === 0 ? (
|
{plan.lines.length === 0 ? (
|
||||||
<div className="text-sm italic text-slate-400">Phiếu nguồn chưa có NCC trúng thầu.</div>
|
<div className="text-sm italic text-slate-400">Phiếu nguồn chưa có NCC trúng thầu.</div>
|
||||||
) : (
|
) : (
|
||||||
@ -608,6 +619,33 @@ export function KhkkDetailContent({
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
{/* [S177 — anh: "+ thêm hạng mục ở đây"] Nút thêm DỜI TỪ DƯỚI BẢNG vào
|
||||||
|
thành dòng cuối của `tbody` — ngay sau dòng dữ liệu cuối, TRÊN dòng TỔNG.
|
||||||
|
🔴 `colSpan={4}` (không phải 3): bảng đã lên 4 cột từ đầu lượt S177.
|
||||||
|
🔸 Panel nhập (`addFor`) VẪN Ở NGOÀI bảng — nó là form nhiều ô, nhét vào
|
||||||
|
trong `<table>` thì vỡ lưới `table-fixed` đang giữ 3 cột số thẳng hàng. */}
|
||||||
|
{isDraft && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4} className="px-3 py-2">
|
||||||
|
<div className="flex flex-wrap items-center gap-1.5">
|
||||||
|
<span className="text-[11px] text-slate-500">Thêm hạng mục cho:</span>
|
||||||
|
{[...new Map(plan.lines.map(l => [l.supplierId, l])).values()].map((l) => (
|
||||||
|
<button
|
||||||
|
key={l.supplierId}
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
setAddFor({ supplierId: l.supplierId, supplierName: l.supplierName })
|
||||||
|
setAddCatalogId(''); setAddAmount(''); setAddNote('')
|
||||||
|
}}
|
||||||
|
className="inline-flex items-center gap-1 rounded border border-brand-300 px-2 py-1 text-[11px] font-medium text-brand-700 transition hover:bg-brand-50"
|
||||||
|
>
|
||||||
|
<Plus className="h-3 w-3" /> {l.supplierName ?? '(không rõ NCC)'}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
{/* [S175 — anh: "chọn hạng mục tiền → thành tổng"] TỔNG = Σ giá các dòng.
|
{/* [S175 — anh: "chọn hạng mục tiền → thành tổng"] TỔNG = Σ giá các dòng.
|
||||||
🔴 KHÔNG có cột "giá tham chiếu" / "giá duyệt" nữa — anh chốt "ko cần so
|
🔴 KHÔNG có cột "giá tham chiếu" / "giá duyệt" nữa — anh chốt "ko cần so
|
||||||
@ -628,29 +666,11 @@ export function KhkkDetailContent({
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* [S175 — anh chốt] THÊM HẠNG MỤC cho 1 NCC. 1 NCC được N hạng mục: máy đã cho
|
{/* 🧊 [S177 — anh: "+ thêm hạng mục ở đây"] Khối "Thêm hạng mục cho:" ĐÃ DỜI vào
|
||||||
phép từ Mig 71 (unique 3 cột `Plan × Supplier × CatalogEntry`), lượt này chỉ
|
trong `tbody` (dòng cuối, trên TỔNG). Lý lẽ S175 vẫn đúng và đi theo lên trên:
|
||||||
bung UI — đúng khuôn "máy rộng, UI hẹp" anh chốt S164.
|
1 NCC được N hạng mục từ Mig 71, và CHỈ liệt kê NCC ĐÃ CÓ trên phiếu — đẻ NCC
|
||||||
🔴 CHỈ liệt kê NCC ĐÃ CÓ trên phiếu: NCC đến từ winner của phiếu Duyệt NCC;
|
mới ở đây là ký với nhà thầu chưa ai chọn (BE cũng chặn, 409).
|
||||||
đẻ NCC 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". */}
|
||||||
{isDraft && (
|
|
||||||
<div className="mt-3 flex flex-wrap items-center gap-1.5">
|
|
||||||
<span className="text-[11px] text-slate-500">Thêm hạng mục cho:</span>
|
|
||||||
{[...new Map(plan.lines.map(l => [l.supplierId, l])).values()].map((l) => (
|
|
||||||
<button
|
|
||||||
key={l.supplierId}
|
|
||||||
type="button"
|
|
||||||
onClick={() => {
|
|
||||||
setAddFor({ supplierId: l.supplierId, supplierName: l.supplierName })
|
|
||||||
setAddCatalogId(''); setAddAmount(''); setAddNote('')
|
|
||||||
}}
|
|
||||||
className="inline-flex items-center gap-1 rounded border border-brand-300 px-2 py-1 text-[11px] font-medium text-brand-700 transition hover:bg-brand-50"
|
|
||||||
>
|
|
||||||
<Plus className="h-3 w-3" /> {l.supplierName ?? '(không rõ NCC)'}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{addFor && (
|
{addFor && (
|
||||||
<div className="mt-2 rounded-md border border-brand-200 bg-brand-50/50 p-3">
|
<div className="mt-2 rounded-md border border-brand-200 bg-brand-50/50 p-3">
|
||||||
|
|||||||
Reference in New Issue
Block a user