diff --git a/fe-admin/src/components/pe/PeDetailTabs.tsx b/fe-admin/src/components/pe/PeDetailTabs.tsx index 0ee33ad..4746bcd 100644 --- a/fe-admin/src/components/pe/PeDetailTabs.tsx +++ b/fe-admin/src/components/pe/PeDetailTabs.tsx @@ -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({
- {isDraft && !readOnly && ( + {canEditPhase && !readOnly && ( <>
- {list.data?.total ?? 0} + {rows.length}
@@ -100,17 +103,17 @@ export function PeListPanel({ className="pl-8" />
- {forcedPhase === undefined ? ( + {editableOnly ? ( +
+ Lọc cố định: Bản nháp + Trả lại (chỉ phiếu sửa được) +
+ ) : ( - ) : ( -
- Lọc cố định: {PeDisplayStatusLabel[getPeDisplayStatus(forcedPhase)]} -
)} @@ -179,16 +182,30 @@ export function PeListPanel({
✓ Đã tạo HĐ
)} - {/* Edit pencil — visible on hover (chỉ khi onEditClick được truyền) */} - {onEditClick && ( - - )} + {/* Edit pencil — LUÔN visible (user 2026-05-07). + Bright/active khi phase editable (DangSoanThao + TraLai). + Dim/disabled khi phase không edit được (Đã gửi duyệt / Đã duyệt + / Từ chối) — click không có tác dụng. */} + {onEditClick && (() => { + const editable = isEditablePhase(p.phase) + return ( + + ) + })()} ))} diff --git a/fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx b/fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx index 4870150..ed4ac91 100644 --- a/fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx +++ b/fe-admin/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx @@ -20,7 +20,6 @@ import { PeWorkspaceCreateView } from '@/components/pe/PeWorkspaceCreateView' import { api } from '@/lib/api' import { getErrorMessage } from '@/lib/apiError' import { - PurchaseEvaluationPhase, PurchaseEvaluationType, PurchaseEvaluationTypeLabel, type PeDetailBundle, @@ -93,7 +92,7 @@ export function PurchaseEvaluationWorkspacePage() { showCreateButton onCreate={() => setParams({ mode: 'new', id: null, editHeader: null })} onEditClick={id => setParams({ id, mode: null, editHeader: '1' })} - forcedPhase={PurchaseEvaluationPhase.DangSoanThao} + editableOnly /> {/* Panel 2: Empty | Header form | Detail tabs (workspace mode) */} diff --git a/fe-admin/src/types/purchaseEvaluation.ts b/fe-admin/src/types/purchaseEvaluation.ts index 400ba6a..149b05f 100644 --- a/fe-admin/src/types/purchaseEvaluation.ts +++ b/fe-admin/src/types/purchaseEvaluation.ts @@ -24,7 +24,8 @@ export const PurchaseEvaluationPhase = { ChoCEODuyetPA: 5, ChoCEODuyetNCC: 6, DaDuyet: 7, - TuChoi: 99, + TraLai: 98, // approver trả về Drafter sửa — vẫn cho edit + TuChoi: 99, // terminal từ chối — KHÔNG edit } as const export type PurchaseEvaluationPhase = typeof PurchaseEvaluationPhase[keyof typeof PurchaseEvaluationPhase] @@ -36,6 +37,7 @@ export const PurchaseEvaluationPhaseLabel: Record = { 5: 'Chờ CEO duyệt PA', 6: 'Chờ CEO duyệt NCC', 7: 'Đã duyệt', + 98: 'Trả lại', 99: 'Từ chối', } @@ -47,9 +49,17 @@ export const PurchaseEvaluationPhaseColor: Record = { 5: 'bg-fuchsia-100 text-fuchsia-700', 6: 'bg-pink-100 text-pink-700', 7: 'bg-emerald-100 text-emerald-700', + 98: 'bg-yellow-100 text-yellow-800', 99: 'bg-red-100 text-red-700', } +// Phase nào được phép edit phiếu (Drafter sửa header + detail). +// User 2026-05-07: chỉ Đang soạn thảo + Trả lại (Từ chối là terminal, không edit). +export function isEditablePhase(phase: number): boolean { + return phase === PurchaseEvaluationPhase.DangSoanThao + || phase === PurchaseEvaluationPhase.TraLai +} + // Display status meta — gom các phase chi tiết thành 4 nhóm hiển thị end-user // friendly. Workflow timeline + workflow service vẫn dùng phase chi tiết. // User 2026-05-07 chỉnh: @@ -60,6 +70,7 @@ export const PurchaseEvaluationPhaseColor: Record = { export const PeDisplayStatus = { BanNhap: 'BanNhap', DaGuiDuyet: 'DaGuiDuyet', + TraLai: 'TraLai', DaDuyet: 'DaDuyet', TuChoi: 'TuChoi', } as const @@ -68,6 +79,7 @@ export type PeDisplayStatus = typeof PeDisplayStatus[keyof typeof PeDisplayStatu export const PeDisplayStatusLabel: Record = { BanNhap: 'Bản nháp', DaGuiDuyet: 'Đã gửi duyệt', + TraLai: 'Trả lại', DaDuyet: 'Đã duyệt', TuChoi: 'Từ chối', } @@ -75,6 +87,7 @@ export const PeDisplayStatusLabel: Record = { export const PeDisplayStatusColor: Record = { BanNhap: 'bg-slate-100 text-slate-700', DaGuiDuyet: 'bg-amber-100 text-amber-700', + TraLai: 'bg-yellow-100 text-yellow-800', DaDuyet: 'bg-emerald-100 text-emerald-700', TuChoi: 'bg-red-100 text-red-700', } @@ -82,6 +95,7 @@ export const PeDisplayStatusColor: Record = { export function getPeDisplayStatus(phase: number): PeDisplayStatus { if (phase === PurchaseEvaluationPhase.DangSoanThao) return PeDisplayStatus.BanNhap if (phase === PurchaseEvaluationPhase.DaDuyet) return PeDisplayStatus.DaDuyet + if (phase === PurchaseEvaluationPhase.TraLai) return PeDisplayStatus.TraLai if (phase === PurchaseEvaluationPhase.TuChoi) return PeDisplayStatus.TuChoi return PeDisplayStatus.DaGuiDuyet } diff --git a/fe-user/src/components/pe/PeDetailTabs.tsx b/fe-user/src/components/pe/PeDetailTabs.tsx index 0ee33ad..4746bcd 100644 --- a/fe-user/src/components/pe/PeDetailTabs.tsx +++ b/fe-user/src/components/pe/PeDetailTabs.tsx @@ -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({
- {isDraft && !readOnly && ( + {canEditPhase && !readOnly && ( <>
- {list.data?.total ?? 0} + {rows.length}
@@ -100,17 +103,17 @@ export function PeListPanel({ className="pl-8" />
- {forcedPhase === undefined ? ( + {editableOnly ? ( +
+ Lọc cố định: Bản nháp + Trả lại (chỉ phiếu sửa được) +
+ ) : ( - ) : ( -
- Lọc cố định: {PeDisplayStatusLabel[getPeDisplayStatus(forcedPhase)]} -
)} @@ -179,16 +182,30 @@ export function PeListPanel({
✓ Đã tạo HĐ
)} - {/* Edit pencil — visible on hover (chỉ khi onEditClick được truyền) */} - {onEditClick && ( - - )} + {/* Edit pencil — LUÔN visible (user 2026-05-07). + Bright/active khi phase editable (DangSoanThao + TraLai). + Dim/disabled khi phase không edit được (Đã gửi duyệt / Đã duyệt + / Từ chối) — click không có tác dụng. */} + {onEditClick && (() => { + const editable = isEditablePhase(p.phase) + return ( + + ) + })()} ))} diff --git a/fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx b/fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx index 4870150..ed4ac91 100644 --- a/fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx +++ b/fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx @@ -20,7 +20,6 @@ import { PeWorkspaceCreateView } from '@/components/pe/PeWorkspaceCreateView' import { api } from '@/lib/api' import { getErrorMessage } from '@/lib/apiError' import { - PurchaseEvaluationPhase, PurchaseEvaluationType, PurchaseEvaluationTypeLabel, type PeDetailBundle, @@ -93,7 +92,7 @@ export function PurchaseEvaluationWorkspacePage() { showCreateButton onCreate={() => setParams({ mode: 'new', id: null, editHeader: null })} onEditClick={id => setParams({ id, mode: null, editHeader: '1' })} - forcedPhase={PurchaseEvaluationPhase.DangSoanThao} + editableOnly /> {/* Panel 2: Empty | Header form | Detail tabs (workspace mode) */} diff --git a/fe-user/src/types/purchaseEvaluation.ts b/fe-user/src/types/purchaseEvaluation.ts index 400ba6a..149b05f 100644 --- a/fe-user/src/types/purchaseEvaluation.ts +++ b/fe-user/src/types/purchaseEvaluation.ts @@ -24,7 +24,8 @@ export const PurchaseEvaluationPhase = { ChoCEODuyetPA: 5, ChoCEODuyetNCC: 6, DaDuyet: 7, - TuChoi: 99, + TraLai: 98, // approver trả về Drafter sửa — vẫn cho edit + TuChoi: 99, // terminal từ chối — KHÔNG edit } as const export type PurchaseEvaluationPhase = typeof PurchaseEvaluationPhase[keyof typeof PurchaseEvaluationPhase] @@ -36,6 +37,7 @@ export const PurchaseEvaluationPhaseLabel: Record = { 5: 'Chờ CEO duyệt PA', 6: 'Chờ CEO duyệt NCC', 7: 'Đã duyệt', + 98: 'Trả lại', 99: 'Từ chối', } @@ -47,9 +49,17 @@ export const PurchaseEvaluationPhaseColor: Record = { 5: 'bg-fuchsia-100 text-fuchsia-700', 6: 'bg-pink-100 text-pink-700', 7: 'bg-emerald-100 text-emerald-700', + 98: 'bg-yellow-100 text-yellow-800', 99: 'bg-red-100 text-red-700', } +// Phase nào được phép edit phiếu (Drafter sửa header + detail). +// User 2026-05-07: chỉ Đang soạn thảo + Trả lại (Từ chối là terminal, không edit). +export function isEditablePhase(phase: number): boolean { + return phase === PurchaseEvaluationPhase.DangSoanThao + || phase === PurchaseEvaluationPhase.TraLai +} + // Display status meta — gom các phase chi tiết thành 4 nhóm hiển thị end-user // friendly. Workflow timeline + workflow service vẫn dùng phase chi tiết. // User 2026-05-07 chỉnh: @@ -60,6 +70,7 @@ export const PurchaseEvaluationPhaseColor: Record = { export const PeDisplayStatus = { BanNhap: 'BanNhap', DaGuiDuyet: 'DaGuiDuyet', + TraLai: 'TraLai', DaDuyet: 'DaDuyet', TuChoi: 'TuChoi', } as const @@ -68,6 +79,7 @@ export type PeDisplayStatus = typeof PeDisplayStatus[keyof typeof PeDisplayStatu export const PeDisplayStatusLabel: Record = { BanNhap: 'Bản nháp', DaGuiDuyet: 'Đã gửi duyệt', + TraLai: 'Trả lại', DaDuyet: 'Đã duyệt', TuChoi: 'Từ chối', } @@ -75,6 +87,7 @@ export const PeDisplayStatusLabel: Record = { export const PeDisplayStatusColor: Record = { BanNhap: 'bg-slate-100 text-slate-700', DaGuiDuyet: 'bg-amber-100 text-amber-700', + TraLai: 'bg-yellow-100 text-yellow-800', DaDuyet: 'bg-emerald-100 text-emerald-700', TuChoi: 'bg-red-100 text-red-700', } @@ -82,6 +95,7 @@ export const PeDisplayStatusColor: Record = { export function getPeDisplayStatus(phase: number): PeDisplayStatus { if (phase === PurchaseEvaluationPhase.DangSoanThao) return PeDisplayStatus.BanNhap if (phase === PurchaseEvaluationPhase.DaDuyet) return PeDisplayStatus.DaDuyet + if (phase === PurchaseEvaluationPhase.TraLai) return PeDisplayStatus.TraLai if (phase === PurchaseEvaluationPhase.TuChoi) return PeDisplayStatus.TuChoi return PeDisplayStatus.DaGuiDuyet } diff --git a/src/Backend/SolutionErp.Domain/PurchaseEvaluations/PurchaseEvaluationPhase.cs b/src/Backend/SolutionErp.Domain/PurchaseEvaluations/PurchaseEvaluationPhase.cs index bc6dcd0..f18dd54 100644 --- a/src/Backend/SolutionErp.Domain/PurchaseEvaluations/PurchaseEvaluationPhase.cs +++ b/src/Backend/SolutionErp.Domain/PurchaseEvaluations/PurchaseEvaluationPhase.cs @@ -16,5 +16,6 @@ public enum PurchaseEvaluationPhase ChoCEODuyetPA = 5, // chỉ B (duyệt phương án trước) ChoCEODuyetNCC = 6, // chung cả A & B — duyệt chọn đơn vị DaDuyet = 7, // terminal thành công - TuChoi = 99, // terminal từ chối + TraLai = 98, // approver trả về cho Drafter sửa (vẫn cho edit, khác TuChoi) + TuChoi = 99, // terminal từ chối — KHÔNG cho edit/thao tác }