Преглед изворни кода

新增表单管理路由与流程设计页面

pm пре 5 месеци
родитељ
комит
eb07c73b3a
4 измењених фајлова са 833 додато и 18 уклоњено
  1. 15 0
      menu-config.json
  2. 32 2
      src/Dashboard.tsx
  3. 778 11
      src/components/IsolationWork.tsx
  4. 8 5
      src/utils/permission.ts

+ 15 - 0
menu-config.json

@@ -315,6 +315,21 @@
           "order": 3,
           "children": null,
           "description": "组件文件: src/components/IsolationWork.tsx, subMenu: 作业管理"
+        },
+        {
+          "id": 64,
+          "parentId": 6,
+          "name": "流程设计",
+          "path": "/jobTicket/design",
+          "component": null,
+          "componentName": null,
+          "icon": "ep:workflow",
+          "visible": true,
+          "keepAlive": false,
+          "alwaysShow": false,
+          "order": 4,
+          "children": null,
+          "description": "组件文件: src/components/IsolationWork.tsx, subMenu: 流程设计"
         }
       ],
       "description": "隔离作业 - 组件文件: src/components/IsolationWork.tsx"

+ 32 - 2
src/Dashboard.tsx

@@ -58,6 +58,15 @@ export default function Dashboard() {
   const mapBackendPathToFrontendKey = (path: string): string | null => {
     // 客户端系统路径(支持 /clientSystem/xxx 格式)
     if (path.startsWith('/clientSystem')) {
+      // 隔离作业子菜单路径(优先处理)
+      if (path.startsWith('/clientSystem/IsolationWork/')) {
+        if (path.includes('/processDesign') || path.endsWith('/processDesign')) return 'processDesign';
+        if (path.includes('/sop') || path.endsWith('/sop')) return 'sopManagement';
+        if (path.includes('/job') || path.endsWith('/job')) return 'workManagement';
+        if (path.includes('/form') || path.endsWith('/form')) return 'formManagement';
+        return 'isolationWork';
+      }
+      // 其他客户端系统路径
       if (path.includes('SystemConfig') || path.endsWith('/SystemConfig')) return 'systemConfig';
       if (path.includes('UserManagement') || path.endsWith('/UserManagement')) return 'userManagement';
       if (path.includes('HardwareManagement') || path.endsWith('/HardwareManagement')) return 'hardwareManagement';
@@ -97,6 +106,7 @@ export default function Dashboard() {
     if (path === '/jobTicket' || path.startsWith('/jobTicket') || path === '/isolation' || path.startsWith('/isolation') || path === '/CustomWorkflow' || path.startsWith('/CustomWorkflow') || path === '/sopm' || path.startsWith('/sopm')) {
       if (path.includes('job') || path.endsWith('/job')) return 'workManagement';
       if (path.includes('sop') || path.endsWith('/sop')) return 'sopManagement';
+      if (path.includes('design') || path.endsWith('/design')) return 'processDesign';
       if (path.includes('step') || path.includes('template') || path.includes('process') || path.includes('CW') || path.includes('CS')) return 'processTemplate';
       return 'isolationWork';
     }
@@ -169,6 +179,7 @@ export default function Dashboard() {
             { key: 'processTemplate', icon: Layers, path: '/isolation/approval', name: '流程模板' },
             { key: 'sopManagement', icon: BookOpen, path: '/isolation/record', name: 'SOP管理' },
             { key: 'workManagement', icon: Activity, path: '/isolation/list', name: '作业管理' },
+            { key: 'processDesign', icon: Workflow, path: '/jobTicket/design', name: '流程设计' },
           ],
         }
       };
@@ -209,6 +220,8 @@ export default function Dashboard() {
         'processTemplate': Workflow,
         'sopManagement': ClipboardList,
         'workManagement': Activity,
+        'processDesign': Workflow,
+        'formManagement': FileText,
       };
       
       if (iconMap[key]) {
@@ -360,7 +373,20 @@ export default function Dashboard() {
             let childKey: string = mapBackendPathToFrontendKey(child.path) || '';
             if (!childKey) {
               // 如果无法映射,尝试根据路径推断
-              if (child.path.includes('/dept')) {
+              // 优先处理 clientSystem/IsolationWork 路径
+              if (child.path.startsWith('/clientSystem/IsolationWork/')) {
+                if (child.path.includes('/processDesign') || child.path.endsWith('/processDesign')) {
+                  childKey = 'processDesign';
+                } else if (child.path.includes('/sop') || child.path.endsWith('/sop')) {
+                  childKey = 'sopManagement';
+                } else if (child.path.includes('/job') || child.path.endsWith('/job')) {
+                  childKey = 'workManagement';
+                } else if (child.path.includes('/form') || child.path.endsWith('/form')) {
+                  childKey = 'formManagement';
+                } else {
+                  childKey = 'isolationWork';
+                }
+              } else if (child.path.includes('/dept')) {
                 childKey = 'departmentManagement';
               } else if (child.path.includes('/menu')) {
                 childKey = 'menuManagement';
@@ -481,6 +507,8 @@ export default function Dashboard() {
             'processTemplate': Workflow,
             'sopManagement': ClipboardList,
             'workManagement': Activity,
+            'processDesign': Workflow,
+            'formManagement': FileText,
           };
           if (iconMap[childKey]) {
             ChildIcon = iconMap[childKey];
@@ -989,7 +1017,9 @@ export default function Dashboard() {
         ) : activeMenu === 'locationManagement' ? (
           <SegregationPointManagement />
         ) : activeMenu === 'isolationWork' ? (
-          <IsolationWork subMenu={activeSubMenu} />
+          <IsolationWork subMenu={
+            filteredSubMenuConfig[activeMenu]?.find(item => item.key === activeSubMenu)?.name || activeSubMenu
+          } />
         ) : activeMenu === 'notificationManagement' ? (
           <NotificationManagement />
         ) : (

+ 778 - 11
src/components/IsolationWork.tsx

@@ -1,7 +1,8 @@
 import React, { useState } from 'react';
-import { Plus, Search, Edit2, Trash2, MoreVertical, FileText, Eye, Play, CheckCircle } from 'lucide-react';
-import { Button } from 'antd';
+import { Plus, Search, Edit2, Trash2, MoreVertical, FileText, Eye, Play, CheckCircle, RefreshCw, Workflow } from 'lucide-react';
+import { Button, Input, Space, Select, Table as AntdTable } from 'antd';
 import { Button as UIButton } from './ui/button';
+import type { ColumnsType } from 'antd/es/table';
 
 interface TableRow {
   id: number;
@@ -141,6 +142,110 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
     },
   ];
 
+  // 表单管理数据
+  const formManagementData: TableRow[] = [
+    { 
+      id: 1, 
+      name: '高压作业申请表', 
+      creator: '张三',
+      createTime: '2024-01-10 14:30',
+      version: 'V1.0',
+      status: '启用',
+      description: '用于高压设备作业申请的表单',
+      useCount: 45
+    },
+    { 
+      id: 2, 
+      name: '低压作业申请表', 
+      creator: '李四',
+      createTime: '2024-01-15 09:20',
+      version: 'V1.2',
+      status: '启用',
+      description: '用于低压设备作业申请的表单',
+      useCount: 128
+    },
+    { 
+      id: 3, 
+      name: '紧急抢修申请表', 
+      creator: '王五',
+      createTime: '2024-02-01 16:45',
+      version: 'V2.0',
+      status: '启用',
+      description: '用于紧急故障抢修申请的表单',
+      useCount: 12
+    },
+    { 
+      id: 4, 
+      name: '定期维护申请表', 
+      creator: '张三',
+      createTime: '2024-02-10 11:15',
+      version: 'V1.5',
+      status: '停用',
+      description: '用于定期维护申请的表单',
+      useCount: 67
+    },
+  ];
+
+  // 表单管理搜索参数
+  const [formManagementQuery, setFormManagementQuery] = useState({
+    name: '',
+    status: undefined as string | undefined,
+  });
+  const [formManagementPagination, setFormManagementPagination] = useState({
+    pageNo: 1,
+    pageSize: 10,
+  });
+
+  // 流程设计数据
+  const processDesignData: TableRow[] = [
+    { 
+      id: 1, 
+      name: '高压设备隔离流程设计', 
+      designer: '张三',
+      designTime: '2024-01-10 14:30',
+      nodeCount: 8,
+      description: '适用于10kV及以上高压设备的隔离作业流程',
+      status: '启用'
+    },
+    { 
+      id: 2, 
+      name: '低压配电柜隔离流程设计', 
+      designer: '李四',
+      designTime: '2024-01-15 09:20',
+      nodeCount: 6,
+      description: '适用于380V配电柜的隔离作业流程',
+      status: '启用'
+    },
+    { 
+      id: 3, 
+      name: '紧急抢修隔离流程设计', 
+      designer: '王五',
+      designTime: '2024-02-01 16:45',
+      nodeCount: 5,
+      description: '用于紧急故障抢修的快速隔离流程',
+      status: '启用'
+    },
+    { 
+      id: 4, 
+      name: '定期维护隔离流程设计', 
+      designer: '张三',
+      designTime: '2024-02-10 11:15',
+      nodeCount: 7,
+      description: '用于定期维护保养的隔离流程',
+      status: '停用'
+    },
+  ];
+
+  // 流程设计搜索参数
+  const [processDesignQuery, setProcessDesignQuery] = useState({
+    name: '',
+    status: undefined as string | undefined,
+  });
+  const [processDesignPagination, setProcessDesignPagination] = useState({
+    pageNo: 1,
+    pageSize: 10,
+  });
+
   // 作业管理数据
   const workData: TableRow[] = [
     { 
@@ -230,9 +335,80 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
     },
   ];
 
+  // 表单管理搜索处理
+  const handleFormManagementQuery = () => {
+    // 这里可以添加搜索逻辑
+    console.log('搜索表单管理:', formManagementQuery);
+  };
+
+  const resetFormManagementQuery = () => {
+    setFormManagementQuery({
+      name: '',
+      status: undefined,
+    });
+  };
+
+  // 流程设计搜索处理
+  const handleProcessDesignQuery = () => {
+    // 这里可以添加搜索逻辑
+    console.log('搜索流程设计:', processDesignQuery);
+  };
+
+  const resetProcessDesignQuery = () => {
+    setProcessDesignQuery({
+      name: '',
+      status: undefined,
+    });
+  };
+
   // 根据当前子菜单获取数据和列配置
   const getTableConfig = () => {
-    if (subMenu === '流程模板') {
+    if (subMenu === '表单管理') {
+      // 表单管理使用单独的过滤逻辑
+      let filtered = formManagementData;
+      if (formManagementQuery.name) {
+        filtered = filtered.filter(item => 
+          item.name.toLowerCase().includes(formManagementQuery.name.toLowerCase())
+        );
+      }
+      if (formManagementQuery.status) {
+        filtered = filtered.filter(item => item.status === formManagementQuery.status);
+      }
+      return {
+        data: filtered,
+        columns: [
+          { key: 'name', label: '名称', width: '20%' },
+          { key: 'creator', label: '创建人', width: '10%' },
+          { key: 'createTime', label: '创建时间', width: '15%' },
+          { key: 'version', label: '版本', width: '10%' },
+          { key: 'status', label: '状态', width: '10%' },
+          { key: 'description', label: '描述', width: '25%' },
+          { key: 'useCount', label: '使用次数', width: '10%' },
+        ],
+      };
+    } else if (subMenu === '流程设计') {
+      // 流程设计使用单独的过滤逻辑
+      let filtered = processDesignData;
+      if (processDesignQuery.name) {
+        filtered = filtered.filter(item => 
+          item.name.toLowerCase().includes(processDesignQuery.name.toLowerCase())
+        );
+      }
+      if (processDesignQuery.status) {
+        filtered = filtered.filter(item => item.status === processDesignQuery.status);
+      }
+      return {
+        data: filtered,
+        columns: [
+          { key: 'name', label: '名称', width: '20%' },
+          { key: 'designer', label: '设计人', width: '10%' },
+          { key: 'designTime', label: '设计时间', width: '15%' },
+          { key: 'nodeCount', label: '节点数量', width: '10%' },
+          { key: 'description', label: '描述', width: '25%' },
+          { key: 'status', label: '状态', width: '10%' },
+        ],
+      };
+    } else if (subMenu === '流程模板') {
       return {
         data: templateData,
         columns: [
@@ -286,12 +462,14 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
 
   const { data, columns } = getTableConfig();
 
-  // 过滤数据
-  const filteredData = data.filter((item) =>
-    Object.values(item).some((value) =>
-      String(value).toLowerCase().includes(searchTerm.toLowerCase())
-    )
-  );
+  // 过滤数据(表单管理和流程设计除外,因为它们有自己的搜索逻辑)
+  const filteredData = (subMenu === '表单管理' || subMenu === '流程设计')
+    ? data 
+    : data.filter((item) =>
+        Object.values(item).some((value) =>
+          String(value).toLowerCase().includes(searchTerm.toLowerCase())
+        )
+      );
 
   const handleDelete = (id: number) => {
     if (confirm('确定要删除这条数据吗?')) {
@@ -304,6 +482,11 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
     setShowAddModal(true);
   };
 
+  const handleDesign = (item: TableRow) => {
+    console.log('设计流程:', item);
+    // 这里可以跳转到流程设计页面
+  };
+
   // 获取表单字段
   const getFormFields = () => {
     if (subMenu === '流程模板') {
@@ -563,6 +746,590 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
     return null;
   };
 
+  // 表单管理表格列配置
+  const formManagementColumns: ColumnsType<TableRow> = [
+    {
+      title: '序号',
+      width: '5%',
+      render: (_: any, __: TableRow, index: number) => index + 1,
+    },
+    {
+      title: '名称',
+      dataIndex: 'name',
+      width: '20%',
+    },
+    {
+      title: '创建人',
+      dataIndex: 'creator',
+      width: '10%',
+    },
+    {
+      title: '创建时间',
+      dataIndex: 'createTime',
+      width: '15%',
+    },
+    {
+      title: '版本',
+      dataIndex: 'version',
+      width: '10%',
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: '10%',
+      render: (status: string) => (
+        <span
+          className={`inline-flex px-3 py-1 rounded-lg text-xs ${
+            status === '启用'
+              ? 'bg-green-100 text-green-700'
+              : 'bg-gray-100 text-gray-700'
+          }`}
+        >
+          {status}
+        </span>
+      ),
+    },
+    {
+      title: '描述',
+      dataIndex: 'description',
+      width: '25%',
+      ellipsis: true,
+    },
+    {
+      title: '使用次数',
+      dataIndex: 'useCount',
+      width: '10%',
+    },
+    {
+      title: '操作',
+      width: '15%',
+      align: 'center',
+      render: (_: any, record: TableRow) => (
+        <div className="flex items-center justify-center gap-2">
+          <UIButton
+            variant="ghost"
+            size="sm"
+            onClick={() => handleEdit(record)}
+            className="h-8 px-2"
+          >
+            <Edit2 className="w-4 h-4" />
+            <span className="ml-1">编辑</span>
+          </UIButton>
+          <UIButton
+            variant="ghost"
+            size="sm"
+            onClick={() => handleDelete(record.id)}
+            className="h-8 px-2 text-red-600 hover:text-red-700"
+          >
+            <Trash2 className="w-4 h-4" />
+            <span className="ml-1">删除</span>
+          </UIButton>
+        </div>
+      ),
+    },
+  ];
+
+  // 流程设计表格列配置
+  const processDesignColumns: ColumnsType<TableRow> = [
+    {
+      title: '序号',
+      width: '5%',
+      render: (_: any, __: TableRow, index: number) => index + 1,
+    },
+    {
+      title: '名称',
+      dataIndex: 'name',
+      width: '20%',
+    },
+    {
+      title: '设计人',
+      dataIndex: 'designer',
+      width: '10%',
+    },
+    {
+      title: '设计时间',
+      dataIndex: 'designTime',
+      width: '15%',
+    },
+    {
+      title: '节点数量',
+      dataIndex: 'nodeCount',
+      width: '10%',
+    },
+    {
+      title: '描述',
+      dataIndex: 'description',
+      width: '25%',
+      ellipsis: true,
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: '10%',
+      render: (status: string) => (
+        <span
+          className={`inline-flex px-3 py-1 rounded-lg text-xs ${
+            status === '启用'
+              ? 'bg-green-100 text-green-700'
+              : 'bg-gray-100 text-gray-700'
+          }`}
+        >
+          {status}
+        </span>
+      ),
+    },
+    {
+      title: '操作',
+      width: '15%',
+      align: 'center',
+      render: (_: any, record: TableRow) => (
+        <div className="flex items-center justify-center gap-2">
+          <UIButton
+            variant="ghost"
+            size="sm"
+            onClick={() => handleDesign(record)}
+            className="h-8 px-2"
+          >
+            <Workflow className="w-4 h-4" />
+            <span className="ml-1">设计</span>
+          </UIButton>
+          <UIButton
+            variant="ghost"
+            size="sm"
+            onClick={() => handleEdit(record)}
+            className="h-8 px-2"
+          >
+            <Edit2 className="w-4 h-4" />
+            <span className="ml-1">编辑</span>
+          </UIButton>
+          <UIButton
+            variant="ghost"
+            size="sm"
+            onClick={() => handleDelete(record.id)}
+            className="h-8 px-2 text-red-600 hover:text-red-700"
+          >
+            <Trash2 className="w-4 h-4" />
+            <span className="ml-1">删除</span>
+          </UIButton>
+        </div>
+      ),
+    },
+  ];
+
+  // 如果是表单管理页面,使用特殊的布局
+  if (subMenu === '表单管理') {
+    // 计算分页数据
+    const formManagementTotal = filteredData.length;
+    const formManagementStartIndex = (formManagementPagination.pageNo - 1) * formManagementPagination.pageSize;
+    const formManagementEndIndex = formManagementStartIndex + formManagementPagination.pageSize;
+    const formManagementPageData = filteredData.slice(formManagementStartIndex, formManagementEndIndex);
+    const formManagementTotalPages = Math.ceil(formManagementTotal / formManagementPagination.pageSize) || 1;
+
+    return (
+      <div className="space-y-6">
+        {/* 搜索栏和表格容器 */}
+        <div className="bg-white rounded-2xl border border-gray-200/50 shadow-sm overflow-hidden">
+          {/* 搜索栏 */}
+          <div className="p-4 lg:p-5 border-b border-gray-200/50">
+            <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
+              {/* 搜索输入框 */}
+              <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+                <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
+                  <label className="text-sm font-medium text-gray-700 whitespace-nowrap">名称:</label>
+                  <Input
+                    value={formManagementQuery.name}
+                    onChange={(e) => setFormManagementQuery({ ...formManagementQuery, name: e.target.value })}
+                    onPressEnter={handleFormManagementQuery}
+                    placeholder="请输入名称"
+                    className="min-w-[150px] max-w-[200px]"
+                    allowClear
+                  />
+                </div>
+                <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
+                  <label className="text-sm font-medium text-gray-700 whitespace-nowrap">状态:</label>
+                  <Select
+                    value={formManagementQuery.status}
+                    onChange={(value) => setFormManagementQuery({ ...formManagementQuery, status: value })}
+                    placeholder="请选择状态"
+                    className="min-w-[150px] max-w-[200px]"
+                    allowClear
+                  >
+                    <Select.Option value="启用">启用</Select.Option>
+                    <Select.Option value="停用">停用</Select.Option>
+                  </Select>
+                </div>
+              </div>
+
+              {/* 操作按钮组 */}
+              <Space className="flex-shrink-0">
+                <Button
+                  type="primary"
+                  icon={<Search className="w-4 h-4" />}
+                  onClick={handleFormManagementQuery}
+                >
+                  搜索
+                </Button>
+                
+                <Button
+                  icon={<RefreshCw className="w-4 h-4" />}
+                  onClick={() => {
+                    resetFormManagementQuery();
+                    setFormManagementPagination({ pageNo: 1, pageSize: 10 });
+                  }}
+                >
+                  重置
+                </Button>
+                
+                <Button
+                  type="primary"
+                  icon={<Plus className="w-4 h-4" />}
+                  onClick={() => {
+                    setEditingItem(null);
+                    setShowAddModal(true);
+                  }}
+                >
+                  新建表单
+                </Button>
+              </Space>
+            </div>
+          </div>
+
+          {/* 表格容器 */}
+          <div className="overflow-hidden min-w-0">
+            <AntdTable
+              columns={formManagementColumns}
+              dataSource={formManagementPageData}
+              rowKey="id"
+              pagination={false}
+              scroll={{ x: 'max-content' }}
+            />
+          </div>
+        </div>
+
+        {/* 分页 */}
+        {formManagementTotal > 0 && (
+          <div className="bg-white rounded-lg border border-gray-200 px-6 py-4">
+            <div className="flex items-center justify-between">
+              <div className="text-sm text-gray-600">
+                共 <span className="text-blue-600 font-medium">{formManagementTotal}</span> 条记录
+              </div>
+              <div className="flex gap-2">
+                <Button
+                  onClick={() => setFormManagementPagination({ ...formManagementPagination, pageNo: formManagementPagination.pageNo - 1 })}
+                  disabled={formManagementPagination.pageNo <= 1}
+                >
+                  上一页
+                </Button>
+                <span className="px-4 py-2 text-sm text-gray-600 flex items-center">
+                  {formManagementPagination.pageNo} / {formManagementTotalPages}
+                </span>
+                <Button
+                  onClick={() => setFormManagementPagination({ ...formManagementPagination, pageNo: formManagementPagination.pageNo + 1 })}
+                  disabled={formManagementPagination.pageNo >= formManagementTotalPages}
+                >
+                  下一页
+                </Button>
+              </div>
+            </div>
+          </div>
+        )}
+
+        {/* 新增/编辑弹窗 */}
+        {showAddModal && (
+          <div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 animate-in fade-in duration-200">
+            <div className="bg-white rounded-2xl shadow-2xl w-full max-w-3xl mx-4 max-h-[90vh] overflow-y-auto animate-in zoom-in duration-200">
+              <div className="px-6 py-4 border-b border-gray-200 flex items-center justify-between sticky top-0 bg-white z-10">
+                <h3 className="text-lg text-gray-900">
+                  {editingItem ? '编辑表单管理' : '新建表单管理'}
+                </h3>
+                <button
+                  onClick={() => setShowAddModal(false)}
+                  className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
+                >
+                  <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
+                  </svg>
+                </button>
+              </div>
+              <div className="px-6 py-6">
+                <div className="grid grid-cols-2 gap-4">
+                  <div>
+                    <label className="block text-sm text-gray-700 mb-2">名称 *</label>
+                    <input
+                      type="text"
+                      className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm"
+                      placeholder="请输入名称"
+                      defaultValue={editingItem?.name || ''}
+                    />
+                  </div>
+                  <div>
+                    <label className="block text-sm text-gray-700 mb-2">创建人 *</label>
+                    <input
+                      type="text"
+                      className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm"
+                      placeholder="请输入创建人"
+                      defaultValue={editingItem?.creator || ''}
+                    />
+                  </div>
+                  <div>
+                    <label className="block text-sm text-gray-700 mb-2">版本</label>
+                    <input
+                      type="text"
+                      className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm"
+                      placeholder="如:V1.0"
+                      defaultValue={editingItem?.version || ''}
+                    />
+                  </div>
+                  <div>
+                    <label className="block text-sm text-gray-700 mb-2">状态 *</label>
+                    <select className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm">
+                      <option value="">请选择</option>
+                      <option value="启用">启用</option>
+                      <option value="停用">停用</option>
+                    </select>
+                  </div>
+                  <div className="col-span-2">
+                    <label className="block text-sm text-gray-700 mb-2">描述</label>
+                    <textarea
+                      rows={3}
+                      className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm resize-none"
+                      placeholder="请输入描述"
+                      defaultValue={editingItem?.description || ''}
+                    ></textarea>
+                  </div>
+                </div>
+              </div>
+              <div className="px-6 py-4 bg-gray-50/50 border-t border-gray-200 flex justify-end gap-3 rounded-b-2xl">
+                <button
+                  onClick={() => setShowAddModal(false)}
+                  className="px-5 py-2.5 text-sm text-gray-600 bg-white border border-gray-200 rounded-xl hover:bg-gray-50 transition-colors"
+                >
+                  取消
+                </button>
+                <button
+                  onClick={() => {
+                    console.log('保存:', editingItem);
+                    setShowAddModal(false);
+                  }}
+                  className="px-5 py-2.5 text-sm text-white bg-gradient-to-r from-blue-500 to-blue-600 rounded-xl hover:shadow-lg hover:shadow-blue-400/40 transition-all"
+                >
+                  {editingItem ? '保存修改' : '确定'}
+                </button>
+              </div>
+            </div>
+          </div>
+        )}
+      </div>
+    );
+  }
+
+  // 如果是流程设计页面,使用特殊的布局
+  if (subMenu === '流程设计') {
+    // 计算分页数据
+    const processDesignTotal = filteredData.length;
+    const processDesignStartIndex = (processDesignPagination.pageNo - 1) * processDesignPagination.pageSize;
+    const processDesignEndIndex = processDesignStartIndex + processDesignPagination.pageSize;
+    const processDesignPageData = filteredData.slice(processDesignStartIndex, processDesignEndIndex);
+    const processDesignTotalPages = Math.ceil(processDesignTotal / processDesignPagination.pageSize) || 1;
+
+    return (
+      <div className="space-y-6">
+        {/* 搜索栏和表格容器 */}
+        <div className="bg-white rounded-2xl border border-gray-200/50 shadow-sm overflow-hidden">
+          {/* 搜索栏 */}
+          <div className="p-4 lg:p-5 border-b border-gray-200/50">
+            <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
+              {/* 搜索输入框 */}
+              <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+                <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
+                  <label className="text-sm font-medium text-gray-700 whitespace-nowrap">名称:</label>
+                  <Input
+                    value={processDesignQuery.name}
+                    onChange={(e) => setProcessDesignQuery({ ...processDesignQuery, name: e.target.value })}
+                    onPressEnter={handleProcessDesignQuery}
+                    placeholder="请输入名称"
+                    className="min-w-[150px] max-w-[200px]"
+                    allowClear
+                  />
+                </div>
+                <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
+                  <label className="text-sm font-medium text-gray-700 whitespace-nowrap">状态:</label>
+                  <Select
+                    value={processDesignQuery.status}
+                    onChange={(value) => setProcessDesignQuery({ ...processDesignQuery, status: value })}
+                    placeholder="请选择状态"
+                    className="min-w-[150px] max-w-[200px]"
+                    allowClear
+                  >
+                    <Select.Option value="启用">启用</Select.Option>
+                    <Select.Option value="停用">停用</Select.Option>
+                  </Select>
+                </div>
+              </div>
+
+              {/* 操作按钮组 */}
+              <Space className="flex-shrink-0">
+                <Button
+                  type="primary"
+                  icon={<Search className="w-4 h-4" />}
+                  onClick={handleProcessDesignQuery}
+                >
+                  搜索
+                </Button>
+                
+                <Button
+                  icon={<RefreshCw className="w-4 h-4" />}
+                  onClick={() => {
+                    resetProcessDesignQuery();
+                    setProcessDesignPagination({ pageNo: 1, pageSize: 10 });
+                  }}
+                >
+                  重置
+                </Button>
+                
+                <Button
+                  type="primary"
+                  icon={<Plus className="w-4 h-4" />}
+                  onClick={() => {
+                    setEditingItem(null);
+                    setShowAddModal(true);
+                  }}
+                >
+                  新建流程
+                </Button>
+              </Space>
+            </div>
+          </div>
+
+          {/* 表格容器 */}
+          <div className="overflow-hidden min-w-0">
+            <AntdTable
+              columns={processDesignColumns}
+              dataSource={processDesignPageData}
+              rowKey="id"
+              pagination={false}
+              scroll={{ x: 'max-content' }}
+            />
+          </div>
+        </div>
+
+        {/* 分页 */}
+        {processDesignTotal > 0 && (
+          <div className="bg-white rounded-lg border border-gray-200 px-6 py-4">
+            <div className="flex items-center justify-between">
+              <div className="text-sm text-gray-600">
+                共 <span className="text-blue-600 font-medium">{processDesignTotal}</span> 条记录
+              </div>
+              <div className="flex gap-2">
+                <Button
+                  onClick={() => setProcessDesignPagination({ ...processDesignPagination, pageNo: processDesignPagination.pageNo - 1 })}
+                  disabled={processDesignPagination.pageNo <= 1}
+                >
+                  上一页
+                </Button>
+                <span className="px-4 py-2 text-sm text-gray-600 flex items-center">
+                  {processDesignPagination.pageNo} / {processDesignTotalPages}
+                </span>
+                <Button
+                  onClick={() => setProcessDesignPagination({ ...processDesignPagination, pageNo: processDesignPagination.pageNo + 1 })}
+                  disabled={processDesignPagination.pageNo >= processDesignTotalPages}
+                >
+                  下一页
+                </Button>
+              </div>
+            </div>
+          </div>
+        )}
+
+        {/* 新增/编辑弹窗 */}
+        {showAddModal && (
+          <div className="fixed inset-0 bg-black/50 backdrop-blur-sm flex items-center justify-center z-50 animate-in fade-in duration-200">
+            <div className="bg-white rounded-2xl shadow-2xl w-full max-w-3xl mx-4 max-h-[90vh] overflow-y-auto animate-in zoom-in duration-200">
+              <div className="px-6 py-4 border-b border-gray-200 flex items-center justify-between sticky top-0 bg-white z-10">
+                <h3 className="text-lg text-gray-900">
+                  {editingItem ? '编辑流程设计' : '新建流程设计'}
+                </h3>
+                <button
+                  onClick={() => setShowAddModal(false)}
+                  className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
+                >
+                  <svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
+                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
+                  </svg>
+                </button>
+              </div>
+              <div className="px-6 py-6">
+                <div className="grid grid-cols-2 gap-4">
+                  <div>
+                    <label className="block text-sm text-gray-700 mb-2">名称 *</label>
+                    <input
+                      type="text"
+                      className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm"
+                      placeholder="请输入名称"
+                      defaultValue={editingItem?.name || ''}
+                    />
+                  </div>
+                  <div>
+                    <label className="block text-sm text-gray-700 mb-2">设计人 *</label>
+                    <input
+                      type="text"
+                      className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm"
+                      placeholder="请输入设计人"
+                      defaultValue={editingItem?.designer || ''}
+                    />
+                  </div>
+                  <div>
+                    <label className="block text-sm text-gray-700 mb-2">节点数量</label>
+                    <input
+                      type="number"
+                      className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm"
+                      placeholder="请输入节点数量"
+                      defaultValue={editingItem?.nodeCount || ''}
+                    />
+                  </div>
+                  <div>
+                    <label className="block text-sm text-gray-700 mb-2">状态 *</label>
+                    <select className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm">
+                      <option value="">请选择</option>
+                      <option value="启用">启用</option>
+                      <option value="停用">停用</option>
+                    </select>
+                  </div>
+                  <div className="col-span-2">
+                    <label className="block text-sm text-gray-700 mb-2">描述</label>
+                    <textarea
+                      rows={3}
+                      className="w-full px-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl outline-none focus:border-blue-400 focus:ring-4 focus:ring-blue-100 transition-all text-sm resize-none"
+                      placeholder="请输入描述"
+                      defaultValue={editingItem?.description || ''}
+                    ></textarea>
+                  </div>
+                </div>
+              </div>
+              <div className="px-6 py-4 bg-gray-50/50 border-t border-gray-200 flex justify-end gap-3 rounded-b-2xl">
+                <button
+                  onClick={() => setShowAddModal(false)}
+                  className="px-5 py-2.5 text-sm text-gray-600 bg-white border border-gray-200 rounded-xl hover:bg-gray-50 transition-colors"
+                >
+                  取消
+                </button>
+                <button
+                  onClick={() => {
+                    console.log('保存:', editingItem);
+                    setShowAddModal(false);
+                  }}
+                  className="px-5 py-2.5 text-sm text-white bg-gradient-to-r from-blue-500 to-blue-600 rounded-xl hover:shadow-lg hover:shadow-blue-400/40 transition-all"
+                >
+                  {editingItem ? '保存修改' : '确定'}
+                </button>
+              </div>
+            </div>
+          </div>
+        )}
+      </div>
+    );
+  }
+
   return (
     <div className="space-y-6">
       {/* 表格容器 - 合并工具栏和列表 */}
@@ -734,8 +1501,8 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
             <div className="px-6 py-4 border-b border-gray-200 flex items-center justify-between sticky top-0 bg-white z-10">
               <h3 className="text-lg text-gray-900">
                 {editingItem 
-                  ? (subMenu === '流程模板' ? '编辑流程模板' : subMenu === 'SOP管理' ? '编辑SOP' : '编辑作业')
-                  : (subMenu === '流程模板' ? '新增流程模板' : subMenu === 'SOP管理' ? '新增SOP' : '新建作业')
+                  ? (subMenu === '流程模板' ? '编辑流程模板' : subMenu === 'SOP管理' ? '编辑SOP' : subMenu === '作业管理' ? '编辑作业' : subMenu === '表单管理' ? '编辑表单管理' : subMenu === '流程设计' ? '编辑流程设计' : '编辑')
+                  : (subMenu === '流程模板' ? '新增流程模板' : subMenu === 'SOP管理' ? '新增SOP' : subMenu === '作业管理' ? '新建作业' : subMenu === '表单管理' ? '新建表单管理' : subMenu === '流程设计' ? '新建流程设计' : '新建')
                 }
               </h3>
               <button

+ 8 - 5
src/utils/permission.ts

@@ -209,14 +209,17 @@ export const mapMenuPathToKey = (path: string): string | null => {
     return 'hardwareManagement';
   }
   
-  // 隔离作业相关
-  if (path === '/isolation' || path.startsWith('/isolation/')) {
-    if (path.includes('/isolation/list')) return 'workManagement';
-    if (path.includes('/isolation/approval')) return 'processTemplate';
-    if (path.includes('/isolation/record')) return 'sopManagement';
+  // 隔离作业相关 - clientSystem 路径(优先处理)
+  if (path.startsWith('/clientSystem/IsolationWork/')) {
+    if (path.includes('/processDesign') || path.endsWith('/processDesign')) return 'processDesign';
+    if (path.includes('/sop') || path.endsWith('/sop')) return 'sopManagement';
+    if (path.includes('/job') || path.endsWith('/job')) return 'workManagement';
+    if (path.includes('/form') || path.endsWith('/form')) return 'formManagement';
     return 'isolationWork';
   }
   
+ 
+  
   // 点位管理
   if (path === '/points' || path.startsWith('/points/')) {
     return 'locationManagement';