d15398fafe
[CLAUDE] Domain+FE: PE thêm phase TraLai + pencil always visible + edit gating
...
Deploy SOLUTION_ERP / build-deploy (push) Failing after 2m0s
User feedback 2026-05-07:
1. Pencil edit icon LUÔN hiện (không chỉ hover) trong workspace Panel 1
2. Pencil sáng (active brand-color) khi phase editable, xám/disabled khi không
3. Click pencil khi sáng → row sáng + auto-open edit toàn bộ (header + detail)
4. Thêm phase mới "Trả lại" — approver gửi về Drafter sửa (vs Từ chối terminal)
5. Edit chỉ cho 2 trạng thái: Đang soạn thảo + Trả lại
(Từ chối + Đã gửi duyệt + Đã duyệt → không edit/thao tác gì)
Implementation:
~ Domain/PurchaseEvaluations/PurchaseEvaluationPhase.cs
+ TraLai = 98 (giữa DaDuyet=7 và TuChoi=99)
Comment ghi rõ "approver trả về Drafter sửa, vẫn cho edit, khác TuChoi"
~ types/purchaseEvaluation.ts (× 2 app)
+ PurchaseEvaluationPhase enum: TraLai = 98
+ PurchaseEvaluationPhaseLabel/Color cho TraLai (yellow)
+ isEditablePhase(phase) helper: true cho DangSoanThao + TraLai
+ PeDisplayStatus thêm "TraLai" (separate, không gộp DaGuiDuyet)
+ getPeDisplayStatus map TraLai → "Trả lại" badge yellow
~ components/pe/PeListPanel.tsx (× 2 app)
- Pencil icon: bỏ opacity-0 hover-only → LUÔN visible
- editable=isEditablePhase(p.phase): bright text-brand-600 + cursor-pointer
- !editable: text-slate-300 + cursor-not-allowed + onClick guard ignored
- title tooltip rõ ràng "đã gửi duyệt / đã duyệt / từ chối — không sửa được"
- Bỏ forcedPhase prop → editableOnly prop (filter client-side cả 2 phase
DangSoanThao + TraLai vì BE chưa support multi-phase param)
- Khi editableOnly: hiển thị "Lọc cố định: Bản nháp + Trả lại" indicator
~ components/pe/PeDetailTabs.tsx (× 2 app)
- Header bar: isDraft → canEditPhase = isEditablePhase(phase)
- InfoTab: canEdit = !readOnly && isEditablePhase
- BudgetFieldRow: canEdit = !readOnly && isEditablePhase
→ Đồng nghĩa Drafter sửa được phiếu Trả lại sau approver send back
~ pages/pe/PurchaseEvaluationWorkspacePage.tsx (× 2 app)
- PeListPanel forcedPhase=DangSoanThao → editableOnly
- Bỏ import PurchaseEvaluationPhase
Workflow service BE chưa wire transition → TraLai (defer — user sẽ thêm button
"Trả lại" trong PeWorkflowPanel duyệt sau, hoặc dùng API PATCH manual). Phase
TraLai chỉ là enum value sẵn sàng FE hiển thị + BE ánh xạ HasConversion<int>.
UAT mode: skip verify, push ngay.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-07 15:38:46 +07:00
0c5db1385f
[CLAUDE] FE-Admin+FE-User: PE display status meta — Bản nháp / Đã gửi duyệt / Đã duyệt / Từ chối
...
Deploy SOLUTION_ERP / build-deploy (push) Failing after 1m59s
User feedback 2026-05-07: thêm 2 trạng thái meta hiển thị "Bản nháp" + "Đã
gửi duyệt". Bản nháp chỉ hiện ở Thao tác workspace, không hiện ở Duyệt menu.
Implementation:
~ types/purchaseEvaluation.ts
+ PeDisplayStatus enum (BanNhap / DaGuiDuyet / DaDuyet / TuChoi)
+ PeDisplayStatusLabel + PeDisplayStatusColor
+ getPeDisplayStatus(phase) helper:
DangSoanThao → BanNhap
DaDuyet → DaDuyet
TuChoi → TuChoi
else (any middle phase) → DaGuiDuyet
~ components/pe/PeListPanel.tsx
- Phase Select filter → Display status Select (4 option, "Đã gửi duyệt"
KHÔNG filter exact phase do multi-phase, để client-side TODO BE)
- Row badge dùng display status (gọn 4 màu)
+ Prop forcedPhase?: number — workspace dùng để khóa filter Bản nháp
(DangSoanThao). Khi forcedPhase set: ẩn Select, show "Lọc cố định: Bản
nháp" indicator.
~ components/pe/PeDetailTabs.tsx
- Header badge dùng display status meta + secondary text "(Phase chi tiết)"
nhỏ bên cạnh để approver/dev vẫn biết phase exact
~ pages/pe/PurchaseEvaluationsListPage.tsx
- Phase filter Select → display status options
- Row badge → display status
~ pages/pe/PurchaseEvaluationWorkspacePage.tsx
- PeListPanel forcedPhase={PurchaseEvaluationPhase.DangSoanThao}
→ workspace chỉ list Bản nháp (đúng UX user yêu cầu)
Workflow timeline Panel 3 + workflow service BE KHÔNG đổi (giữ phase chi tiết
DangSoanThao/ChoPurchasing/ChoCCM/etc cho approval logic).
Pe_*_Pending Duyệt: dùng /inbox endpoint vốn đã filter chỉ phiếu cần user duyệt
→ DangSoanThao auto-không xuất hiện (không có active approver). Nên Bản nháp
auto-hidden từ Duyệt menu, không cần filter thêm.
UAT mode: skip verify, push ngay.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-07 15:27:29 +07:00
66fa4691dc
[CLAUDE] FE-Admin+FE-User: PE workspace "new" mode — sectioned create view 5 sections
...
Deploy SOLUTION_ERP / build-deploy (push) Successful in 3m4s
User feedback 2026-05-07: "Thêm mới list ra hết trường dữ liệu giống chỉnh sửa
nhưng trống, mở rộng từng phần. Save header xong mới cho nhập chi tiết."
Implementation:
+ PeWorkspaceCreateView.tsx (~230 LOC, mirror fe-admin + fe-user)
- Sectioned card layout giống PeDetailTabs (5 section divider + title style)
- Section 1 "Thông tin gói thầu": editable inputs (Loại / Tên */Dự án */Địa
điểm/Mô tả/Payment) — 2-col grid responsive
- Section 2 "Chọn NCC/TP":
a. NCC chọn: text "(sau khi thêm NCC + chốt winner)" placeholder
b. Ngân sách: editable inline (toggle "Nhập tay" + Select OR 2 input —
giống BudgetFieldRow pattern)
c. Giá chào thầu: text "(auto-tính sau winner)" placeholder
d. Bản so sánh: LockedHint icon + text "Tải sau khi tạo"
- Section 3 "NCC tham gia (0)": LockedHint "Lưu phiếu trước → thêm NCC..."
- Section 4 "Hạng mục + Báo giá (0)": LockedHint
- Section 5 "Ý kiến 4 PB": amber banner "nhập khi duyệt"
- Action bar bottom: "Tạo phiếu" (disabled khi !tenGoiThau || !projectId)
+ Hủy
- POST /pe full payload (header + budget mode A or B). onSuccess: toast +
invalidate pe-list + onSaved(id, type) callback
~ PurchaseEvaluationWorkspacePage.tsx (× 2 app)
- Replace <PeHeaderForm> → <PeWorkspaceCreateView> trong mode='new'
- PeHeaderForm vẫn còn (dùng cho /new?id= deep-link "Sửa header" cũ)
Helpers duplicate trong PeWorkspaceCreateView (Section + FormRow + LockedHint)
để tránh circular import từ PeDetailTabs.
UAT mode rule applied (per memory feedback_uat_skip_verify): skip dotnet test
+ npm build verify, push ngay.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-07 15:06:31 +07:00
5a89dd2188
[CLAUDE] FE-Admin: PE InfoTab inline edit Section 1 + PeListPanel pencil edit hover
...
User feedback 2026-05-07: muốn thêm nút edit kế bên row trong Panel 1, click →
Panel 2 sáng nội dung Section 1 lên cho user sửa header inline (KHÔNG cần đi
"Sửa header" page). Cũng muốn create new interface gần giống detail view
sectioned (defer cho chunk sau, hoặc keep PeHeaderForm nếu user OK).
Implementation:
~ PeDetailTabs.tsx
- InfoTab thêm prop `readOnly` + `autoEdit` (trigger edit mode tự động khi
mount nếu URL ?editHeader=1)
- canEdit = !readOnly && isDraft (DangSoanThao):
→ display mode: hiển thị FormRow + button "✎ Sửa" góc trên phải Section 1
→ editing mode (click Sửa hoặc autoEdit): card border brand-200 + 4 input
(Tên * / Dự án disabled / Địa điểm / Mô tả / Payment) + nút Lưu/Hủy
- Save: PUT /pe/:id full payload (current ev values + new editable fields).
onSuccess: invalidate ['pe-detail', 'pe-list'] + setEditing(false)
- PeDetailTabs prop `autoEditHeader` mới — pass-through xuống InfoTab
~ PeListPanel.tsx
- Thêm prop `onEditClick?: (id) => void`
- Pencil icon (lucide) absolute right-2 top-2 trong mỗi <li>, opacity-0
group-hover:opacity-100 — chỉ hiện khi user hover row + onEditClick set
- Click → trigger onEditClick(id) callback (different from row click)
~ PurchaseEvaluationWorkspacePage.tsx
- Đọc URL ?editHeader=1 → pass autoEditHeader xuống PeDetailTabs
- PeListPanel onEditClick → setParams({ id, mode: null, editHeader: '1' })
- onSelect (click row thường) → editHeader: null (clear flag)
- onBack → clear editHeader
Verify: npm run build fe-admin pass · 0 TS error.
Pending: workspace "new" mode wrap PeHeaderForm trong sectioned layout giống
detail view (defer — user có thể chấp nhận PeHeaderForm hiện tại nếu OK).
Next: Chunk 2 fe-user mirror.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-07 14:55:49 +07:00
ee0d3608e7
[CLAUDE] FE-Admin: PE Thao tác 2-panel workspace + Panel 1 read-only picker + Section 5 disabled
...
Chunk 1/3 — restructure leaf "Thao tác" (Pe_*_Create) từ page tạo header riêng
sang workspace 2-panel mirror pattern HĐ Thầu phụ ContractCreatePage:
Panel 1 (320px): list pure picker (KHÔNG inline edit/delete per Q1 user) +
sticky "+ Thêm mới" bottom button.
Panel 2 (1fr): empty state | mode=new <PeHeaderForm> | <PeDetailTabs
mode="workspace"> (5 section, Section 5 Ý kiến 4PB DISABLED
per Q5 user — nhập ở leaf "Duyệt").
Workflow Panel + Approvals + History KHÔNG render trong workspace (Q1) — chỉ
hiện ở leaf "Danh sách" + "Duyệt" giữ nguyên 3-panel hiện tại (Q3).
URL: /purchase-evaluations/workspace?type={1|2}[&id=...][&mode=new][&q=][&phase=]
Menu resolver Pe_*_Create: /purchase-evaluations/new?type=N → /workspace?type=N.
Route mới /workspace; route /new giữ tồn tại cho deep-link "Sửa header" button.
Files:
+ fe-admin/src/components/pe/PeListPanel.tsx (~180 LOC) — pure picker reuseable
+ fe-admin/src/components/pe/PeHeaderForm.tsx (~210 LOC) — extract header form
+ fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx (~120 LOC)
~ fe-admin/src/components/pe/PeDetailTabs.tsx — add mode prop + Section 5 hint
~ fe-admin/src/components/Layout.tsx — resolver Pe_*_Create map workspace
~ fe-admin/src/App.tsx — route /purchase-evaluations/workspace
Verify: npm run build pass · dotnet test 83 vẫn pass (54 Domain + 29 Infra).
fe-user mirror = Chunk 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com >
2026-05-07 10:36:06 +07:00