[CLAUDE] Domain+FE: PE thêm phase TraLai + pencil always visible + edit gating
Some checks failed
Deploy SOLUTION_ERP / build-deploy (push) Failing after 2m0s
Some checks failed
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>
This commit is contained in:
@ -27,6 +27,7 @@ import {
|
||||
PurchaseEvaluationPhaseLabel,
|
||||
PurchaseEvaluationTypeLabel,
|
||||
getPeDisplayStatus,
|
||||
isEditablePhase,
|
||||
type PeAttachment,
|
||||
type PeChangelog,
|
||||
type PeDepartmentOpinion,
|
||||
@ -69,7 +70,9 @@ export function PeDetailTabs({
|
||||
autoEditHeader?: boolean
|
||||
}) {
|
||||
const navigate = useNavigate()
|
||||
const isDraft = evaluation.phase === PurchaseEvaluationPhase.DangSoanThao
|
||||
// isDraft renamed → canEditPhase: bao gồm cả TraLai (per user 2026-05-07).
|
||||
// Header bar action buttons (Sửa header / Xóa) hiện khi phase editable + !readOnly.
|
||||
const canEditPhase = isEditablePhase(evaluation.phase)
|
||||
const opinionsReadOnly = readOnly || mode === 'workspace'
|
||||
|
||||
return (
|
||||
@ -107,7 +110,7 @@ export function PeDetailTabs({
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex gap-2">
|
||||
{isDraft && !readOnly && (
|
||||
{canEditPhase && !readOnly && (
|
||||
<>
|
||||
<Button variant="ghost" onClick={() => navigate(`/purchase-evaluations/new?id=${evaluation.id}`)} className="gap-1.5 text-xs">
|
||||
<Pencil className="h-3.5 w-3.5" /> Sửa header
|
||||
@ -303,14 +306,14 @@ export function PeHistorySection({ ev }: { ev: PeDetailBundle }) {
|
||||
}
|
||||
|
||||
// ===== Section 1 — Thông tin gói thầu (spec: a. Tên gói thầu / b. Dự án) =====
|
||||
// Inline editable khi canEdit (=!readOnly && isDraft). Edit pencil button "Sửa"
|
||||
// flip display ↔ form mode. Save dùng existing PUT /pe/:id endpoint với current
|
||||
// entity values + new header fields. Dự án + Type LOCKED sau create — chỉ Tên/
|
||||
// Địa điểm/Mô tả/Payment editable inline. autoEdit prop cho phép trigger edit
|
||||
// mode từ pencil icon trong PeListPanel (URL flag ?editHeader=1).
|
||||
// Inline editable khi canEdit (=!readOnly && phase editable). Edit pencil button
|
||||
// "Sửa" flip display ↔ form mode. Save dùng existing PUT /pe/:id endpoint với
|
||||
// current entity values + new header fields. Dự án + Type LOCKED sau create —
|
||||
// chỉ Tên/Địa điểm/Mô tả/Payment editable inline. autoEdit prop cho phép trigger
|
||||
// edit mode từ pencil icon trong PeListPanel (URL flag ?editHeader=1).
|
||||
// Phase editable = DangSoanThao + TraLai (user 2026-05-07).
|
||||
function InfoTab({ ev, readOnly, autoEdit }: { ev: PeDetailBundle; readOnly: boolean; autoEdit: boolean }) {
|
||||
const isDraft = ev.phase === PurchaseEvaluationPhase.DangSoanThao
|
||||
const canEdit = !readOnly && isDraft
|
||||
const canEdit = !readOnly && isEditablePhase(ev.phase)
|
||||
const qc = useQueryClient()
|
||||
const [editing, setEditing] = useState(autoEdit && canEdit)
|
||||
const [tenGoiThau, setTenGoiThau] = useState(ev.tenGoiThau)
|
||||
@ -443,12 +446,11 @@ function InfoTab({ ev, readOnly, autoEdit }: { ev: PeDetailBundle; readOnly: boo
|
||||
// ===== b. Ngân sách inline editor (Mig 17) =====
|
||||
// Hiển thị + edit budget link / manual fields ngay trong Section 2 — KHÔNG cần
|
||||
// đi tới "Sửa header" page. Visible trong cả 3 view (Workspace / Danh sách /
|
||||
// Duyệt). Edit chỉ enable khi !readOnly + isDraft (Drafter sửa). Read-only
|
||||
// khi pendingMe=1 hoặc phase đã chuyển khỏi DangSoanThao. Empty values hiển
|
||||
// thị empty (per user 2026-05-07).
|
||||
// Duyệt). Edit chỉ enable khi !readOnly + phase editable (DangSoanThao /
|
||||
// TraLai). Read-only khi pendingMe=1 hoặc phase đã gửi duyệt / đã duyệt /
|
||||
// từ chối. Empty values hiển thị empty (per user 2026-05-07).
|
||||
function BudgetFieldRow({ ev, readOnly }: { ev: PeDetailBundle; readOnly: boolean }) {
|
||||
const isDraft = ev.phase === PurchaseEvaluationPhase.DangSoanThao
|
||||
const canEdit = !readOnly && isDraft
|
||||
const canEdit = !readOnly && isEditablePhase(ev.phase)
|
||||
const qc = useQueryClient()
|
||||
|
||||
// Detect mode khi mount/refresh: prefer manual mode nếu đã có data manual + ko link
|
||||
|
||||
Reference in New Issue
Block a user