[CLAUDE] FE-User: PE Thao tác 2-panel workspace mirror fe-admin

Chunk 2/3 — mirror y hệt Chunk 1 sang fe-user (rule §3.9 duplicate có chủ đích
giữa 2 app — copy + sync tay khi breaking).

Files (cùng diff Chunk 1, content identical):
  + fe-user/src/components/pe/PeListPanel.tsx
  + fe-user/src/components/pe/PeHeaderForm.tsx
  + fe-user/src/pages/pe/PurchaseEvaluationWorkspacePage.tsx
  ~ fe-user/src/components/pe/PeDetailTabs.tsx — add mode prop + Section 5 hint
  ~ fe-user/src/components/Layout.tsx — resolver Pe_*_Create map workspace
  ~ fe-user/src/App.tsx — route /purchase-evaluations/workspace

Verify: npm run build (fe-user) pass. dotnet test 83 không bị ảnh hưởng (đã
verify Chunk 1).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-05-07 10:37:52 +07:00
parent ee0d3608e7
commit ecf3c5945b
6 changed files with 571 additions and 2 deletions

View File

@ -38,20 +38,32 @@ const fmtMoney = (v: number) => v.toLocaleString('vi-VN')
// Main detail content — flat render 3 section không tabs.
// Tên giữ PeDetailTabs để không break callsite (rename gây churn).
//
// `mode` (2026-05-07):
// - 'detail' (default): full UX — Section 5 Ý kiến 4PB editable theo readOnly.
// Dùng ở leaf "Danh sách" + "Duyệt" (3-panel pages).
// - 'workspace': dùng ở leaf "Thao tác" (2-panel workspace). Section 5 LUÔN
// disabled (Q5 user — ý kiến nhập khi duyệt, không phải workspace nhập liệu).
// Workflow Panel + Approvals + History KHÔNG render trong PeDetailTabs (luôn
// ở caller PeWorkflowPanel — workspace caller skip render Panel 3 hoàn toàn).
export function PeDetailTabs({
evaluation,
onBack,
onDelete,
readOnly = false,
mode = 'detail',
}: {
evaluation: PeDetailBundle
onBack: () => void
onDelete: () => void
/** Menu "Duyệt" (pendingMe=1) — ẩn mọi action thêm/sửa/xóa, chỉ xem + duyệt phase. */
readOnly?: boolean
/** 'workspace' = Section 5 LUÔN disabled (ý kiến nhập ở leaf Duyệt). */
mode?: 'detail' | 'workspace'
}) {
const navigate = useNavigate()
const isDraft = evaluation.phase === PurchaseEvaluationPhase.DangSoanThao
const opinionsReadOnly = readOnly || mode === 'workspace'
return (
<div className="rounded-lg border border-slate-200 bg-white shadow-sm">
@ -112,7 +124,12 @@ export function PeDetailTabs({
<ItemsTab ev={evaluation} readOnly={readOnly} />
</Section>
<Section title="5. Ý kiến 4 phòng ban (sign-off)">
<DepartmentOpinionsSection ev={evaluation} readOnly={readOnly} />
{mode === 'workspace' && (
<div className="mb-3 rounded border border-amber-200 bg-amber-50 px-3 py-2 text-[12px] text-amber-800">
Ý kiến + chữ nhập khi duyệt phiếu vào menu &ldquo;Duyệt&rdquo; đ .
</div>
)}
<DepartmentOpinionsSection ev={evaluation} readOnly={opinionsReadOnly} />
</Section>
</div>
</div>