diff --git a/fe-admin/src/App.tsx b/fe-admin/src/App.tsx
index bb532a1..d402f63 100644
--- a/fe-admin/src/App.tsx
+++ b/fe-admin/src/App.tsx
@@ -37,6 +37,7 @@ function App() {
} />
} />
} />
+ } />
} />
} />
} />
diff --git a/fe-admin/src/components/Layout.tsx b/fe-admin/src/components/Layout.tsx
index 7c65f9c..1bd7370 100644
--- a/fe-admin/src/components/Layout.tsx
+++ b/fe-admin/src/components/Layout.tsx
@@ -52,11 +52,19 @@ function resolvePath(key: string): string | null {
if (action === 'Create') return `/contracts/new?type=${typeInt}`
if (action === 'Pending') return `/contracts?type=${typeInt}&pendingMe=1`
}
+
+ // Workflow admin per ContractType: Wf_ → /system/workflows/
+ const wfMatch = key.match(/^Wf_(.+)$/)
+ if (wfMatch) {
+ const code = wfMatch[1]
+ if (TYPE_CODE_TO_INT[code]) return `/system/workflows/${code}`
+ }
+
return null
}
-// Admin side: hide the per-ContractType submenu (Ct_*) — that's a user-app
-// concern. Admin manages workflow config via /system/workflows instead.
+// Admin side: hide the per-ContractType contract submenu (Ct_*) — that's a
+// user-app concern. Keep Wf_* workflow-admin leaves.
function isAdminHidden(key: string): boolean {
return key.startsWith('Ct_')
}
diff --git a/fe-admin/src/pages/system/WorkflowsPage.tsx b/fe-admin/src/pages/system/WorkflowsPage.tsx
index eb14438..53b2dd8 100644
--- a/fe-admin/src/pages/system/WorkflowsPage.tsx
+++ b/fe-admin/src/pages/system/WorkflowsPage.tsx
@@ -1,4 +1,5 @@
import { useMemo, useState, type FormEvent } from 'react'
+import { useParams } from 'react-router-dom'
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
import { GitBranch, Plus, Trash2, CheckCircle2, Info, History } from 'lucide-react'
import { toast } from 'sonner'
@@ -63,16 +64,31 @@ function copyFromDefinition(d: DefinitionDto): EditStep[] {
// ===== Page =====
+// Map URL type code → int. Mirror Wf_ menu key.
+const TYPE_CODE_TO_INT: Record = {
+ ThauPhu: 1,
+ GiaoKhoan: 2,
+ NhaCungCap: 3,
+ DichVu: 4,
+ MuaBan: 5,
+ NguyenTacNcc: 6,
+ NguyenTacDv: 7,
+}
+
export function WorkflowsPage() {
const qc = useQueryClient()
+ const { typeCode } = useParams<{ typeCode?: string }>()
const overview = useQuery({
queryKey: ['workflow-overview'],
queryFn: async () => (await api.get<{ types: TypeSummaryDto[] }>('/workflows')).data,
})
- const [activeType, setActiveType] = useState(null)
- const tab = activeType ?? overview.data?.types[0]?.contractType ?? 1
- const currentType = overview.data?.types.find(t => t.contractType === tab)
+ // URL drives which type to show. `/system/workflows` (no param) → show
+ // landing hint to pick from sidebar; `/system/workflows/` → open that.
+ const selectedTypeInt = typeCode ? TYPE_CODE_TO_INT[typeCode] : null
+ const currentType = selectedTypeInt
+ ? overview.data?.types.find(t => t.contractType === selectedTypeInt)
+ : null
return (
@@ -80,38 +96,41 @@ export function WorkflowsPage() {
title={
- Quy trình duyệt hợp đồng
+ {currentType ? `Quy trình: ${currentType.contractTypeLabel}` : 'Quy trình duyệt hợp đồng'}
}
- description="Mỗi loại HĐ có quy trình riêng, hỗ trợ versioning. Tạo version mới → HĐ tương lai chạy theo. HĐ cũ vẫn giữ quy trình cũ."
+ description={
+ currentType
+ ? 'Tạo version mới → HĐ tương lai dùng. HĐ đã tạo giữ version cũ (pinned lúc tạo).'
+ : 'Chọn loại HĐ từ menu bên trái để xem + chỉnh quy trình duyệt.'
+ }
/>
- {/* Tabs */}
- {overview.data && (
-
+ {overview.isLoading &&
Đang tải…
}
+
+ {/* Landing: no type picked yet */}
+ {overview.data && !currentType && (
+