Ver Fonte

新增岗位管理

pm há 5 meses atrás
pai
commit
80f6ca3ac0

+ 2 - 1
src/Dashboard.tsx

@@ -1,7 +1,7 @@
 import React, { useState } from 'react';
 import { useNavigate } from 'react-router-dom';
 import { useTranslation } from 'react-i18next';
-import { Shield, Settings, Users, Cpu, MapPin, Layers, Bell, User, LogOut, ChevronDown, Activity, Radio, Lock, AlertCircle, CheckCircle, Clock, Menu, Building2, UserCog, BookOpen, Server, Globe, Gauge } from 'lucide-react';
+import { Shield, Settings, Users, Cpu, MapPin, Layers, Bell, User, LogOut, ChevronDown, Activity, Radio, Lock, AlertCircle, CheckCircle, Clock, Menu, Building2, UserCog, BookOpen, Server, Globe, Gauge, Briefcase } from 'lucide-react';
 import SystemConfig from './components/SystemConfig';
 import UserManagement from './components/UserManagement';
 import HardwareManagement from './components/HardwareManagement';
@@ -60,6 +60,7 @@ export default function Dashboard() {
     systemConfig: [
       { key: 'menuManagement', icon: Menu },
       { key: 'departmentManagement', icon: Building2 },
+      { key: 'positionManagement', icon: Briefcase },
       { key: 'roleManagement', icon: UserCog },
       { key: 'dictionaryManagement', icon: BookOpen },
       { key: 'cabinetManagement', icon: Server },

+ 769 - 0
src/components/PositionManagement.tsx

@@ -0,0 +1,769 @@
+import React, { useState } from 'react';
+import { Plus, Search, Edit2, Trash2, MoreVertical, ChevronRight, ChevronDown, Briefcase } from 'lucide-react';
+
+interface PositionNode {
+  id: number;
+  name: string;
+  code?: string;
+  department?: string;
+  description?: string;
+  status?: string;
+  userCount?: number;
+  createTime?: string;
+  parentId?: number;
+  children?: PositionNode[];
+}
+
+export default function PositionManagement() {
+  const [expandedPositionIds, setExpandedPositionIds] = useState<number[]>([1]); // 默认展开
+  const [selectedPositionId, setSelectedPositionId] = useState<number | null>(1); // 选中的岗位ID
+  const [searchTerm, setSearchTerm] = useState('');
+  const [showAddModal, setShowAddModal] = useState(false);
+  const [editingItem, setEditingItem] = useState<any>(null);
+
+  // 岗位树形数据
+  const positionTree: PositionNode[] = [
+    {
+      id: 1,
+      name: '管理岗位',
+      code: 'MGMT',
+      department: '总公司',
+      description: '管理类岗位',
+      status: '启用',
+      userCount: 15,
+      createTime: '2024-01-01',
+      children: [
+        {
+          id: 2,
+          name: '高级管理',
+          code: 'MGMT-HIGH',
+          department: '总公司',
+          description: '高级管理岗位',
+          status: '启用',
+          userCount: 5,
+          createTime: '2024-01-05',
+          parentId: 1,
+          children: [
+            {
+              id: 21,
+              name: 'CEO',
+              code: 'CEO',
+              department: '总公司',
+              description: '首席执行官',
+              status: '启用',
+              userCount: 1,
+              createTime: '2024-01-10',
+              parentId: 2
+            },
+            {
+              id: 22,
+              name: 'CTO',
+              code: 'CTO',
+              department: '技术中心',
+              description: '首席技术官',
+              status: '启用',
+              userCount: 1,
+              createTime: '2024-01-10',
+              parentId: 2
+            },
+            {
+              id: 23,
+              name: 'CFO',
+              code: 'CFO',
+              department: '行政中心',
+              description: '首席财务官',
+              status: '启用',
+              userCount: 1,
+              createTime: '2024-01-10',
+              parentId: 2
+            }
+          ]
+        },
+        {
+          id: 3,
+          name: '部门管理',
+          code: 'MGMT-DEPT',
+          department: '各部门',
+          description: '部门管理岗位',
+          status: '启用',
+          userCount: 8,
+          createTime: '2024-01-05',
+          parentId: 1,
+          children: [
+            {
+              id: 31,
+              name: '部门经理',
+              code: 'DEPT-MGR',
+              department: '各部门',
+              description: '部门经理',
+              status: '启用',
+              userCount: 5,
+              createTime: '2024-01-10',
+              parentId: 3
+            },
+            {
+              id: 32,
+              name: '部门副经理',
+              code: 'DEPT-DMGR',
+              department: '各部门',
+              description: '部门副经理',
+              status: '启用',
+              userCount: 3,
+              createTime: '2024-01-10',
+              parentId: 3
+            }
+          ]
+        }
+      ]
+    },
+    {
+      id: 4,
+      name: '技术岗位',
+      code: 'TECH',
+      department: '技术中心',
+      description: '技术类岗位',
+      status: '启用',
+      userCount: 45,
+      createTime: '2024-01-01',
+      children: [
+        {
+          id: 5,
+          name: '研发岗位',
+          code: 'TECH-RD',
+          department: '研发部',
+          description: '研发类岗位',
+          status: '启用',
+          userCount: 25,
+          createTime: '2024-01-05',
+          parentId: 4,
+          children: [
+            {
+              id: 51,
+              name: '高级工程师',
+              code: 'RD-SENIOR',
+              department: '研发部',
+              description: '高级研发工程师',
+              status: '启用',
+              userCount: 8,
+              createTime: '2024-01-10',
+              parentId: 5
+            },
+            {
+              id: 52,
+              name: '工程师',
+              code: 'RD-ENG',
+              department: '研发部',
+              description: '研发工程师',
+              status: '启用',
+              userCount: 12,
+              createTime: '2024-01-10',
+              parentId: 5
+            },
+            {
+              id: 53,
+              name: '助理工程师',
+              code: 'RD-ASSIST',
+              department: '研发部',
+              description: '助理研发工程师',
+              status: '启用',
+              userCount: 5,
+              createTime: '2024-01-10',
+              parentId: 5
+            }
+          ]
+        },
+        {
+          id: 6,
+          name: '测试岗位',
+          code: 'TECH-QA',
+          department: '测试部',
+          description: '测试类岗位',
+          status: '启用',
+          userCount: 12,
+          createTime: '2024-01-05',
+          parentId: 4,
+          children: [
+            {
+              id: 61,
+              name: '测试工程师',
+              code: 'QA-ENG',
+              department: '测试部',
+              description: '测试工程师',
+              status: '启用',
+              userCount: 8,
+              createTime: '2024-01-10',
+              parentId: 6
+            },
+            {
+              id: 62,
+              name: '测试助理',
+              code: 'QA-ASSIST',
+              department: '测试部',
+              description: '测试助理',
+              status: '启用',
+              userCount: 4,
+              createTime: '2024-01-10',
+              parentId: 6
+            }
+          ]
+        },
+        {
+          id: 7,
+          name: '运维岗位',
+          code: 'TECH-OPS',
+          department: '运维部',
+          description: '运维类岗位',
+          status: '启用',
+          userCount: 8,
+          createTime: '2024-01-05',
+          parentId: 4,
+          children: [
+            {
+              id: 71,
+              name: '运维工程师',
+              code: 'OPS-ENG',
+              department: '运维部',
+              description: '运维工程师',
+              status: '启用',
+              userCount: 6,
+              createTime: '2024-01-10',
+              parentId: 7
+            },
+            {
+              id: 72,
+              name: '运维助理',
+              code: 'OPS-ASSIST',
+              department: '运维部',
+              description: '运维助理',
+              status: '启用',
+              userCount: 2,
+              createTime: '2024-01-10',
+              parentId: 7
+            }
+          ]
+        }
+      ]
+    },
+    {
+      id: 8,
+      name: '行政岗位',
+      code: 'ADMIN',
+      department: '行政中心',
+      description: '行政类岗位',
+      status: '启用',
+      userCount: 25,
+      createTime: '2024-01-01',
+      children: [
+        {
+          id: 9,
+          name: '人力资源',
+          code: 'ADMIN-HR',
+          department: '人力资源部',
+          description: '人力资源岗位',
+          status: '启用',
+          userCount: 10,
+          createTime: '2024-01-05',
+          parentId: 8,
+          children: [
+            {
+              id: 91,
+              name: 'HR经理',
+              code: 'HR-MGR',
+              department: '人力资源部',
+              description: '人力资源经理',
+              status: '启用',
+              userCount: 1,
+              createTime: '2024-01-10',
+              parentId: 9
+            },
+            {
+              id: 92,
+              name: 'HR专员',
+              code: 'HR-SPEC',
+              department: '人力资源部',
+              description: '人力资源专员',
+              status: '启用',
+              userCount: 6,
+              createTime: '2024-01-10',
+              parentId: 9
+            },
+            {
+              id: 93,
+              name: 'HR助理',
+              code: 'HR-ASSIST',
+              department: '人力资源部',
+              description: '人力资源助理',
+              status: '启用',
+              userCount: 3,
+              createTime: '2024-01-10',
+              parentId: 9
+            }
+          ]
+        },
+        {
+          id: 10,
+          name: '财务岗位',
+          code: 'ADMIN-FIN',
+          department: '财务部',
+          description: '财务类岗位',
+          status: '启用',
+          userCount: 8,
+          createTime: '2024-01-05',
+          parentId: 8,
+          children: [
+            {
+              id: 101,
+              name: '财务经理',
+              code: 'FIN-MGR',
+              department: '财务部',
+              description: '财务经理',
+              status: '启用',
+              userCount: 1,
+              createTime: '2024-01-10',
+              parentId: 10
+            },
+            {
+              id: 102,
+              name: '会计',
+              code: 'FIN-ACC',
+              department: '财务部',
+              description: '会计',
+              status: '启用',
+              userCount: 4,
+              createTime: '2024-01-10',
+              parentId: 10
+            },
+            {
+              id: 103,
+              name: '出纳',
+              code: 'FIN-CASH',
+              department: '财务部',
+              description: '出纳',
+              status: '启用',
+              userCount: 3,
+              createTime: '2024-01-10',
+              parentId: 10
+            }
+          ]
+        },
+        {
+          id: 11,
+          name: '行政岗位',
+          code: 'ADMIN-OFF',
+          department: '行政部',
+          description: '行政类岗位',
+          status: '启用',
+          userCount: 7,
+          createTime: '2024-01-05',
+          parentId: 8,
+          children: [
+            {
+              id: 111,
+              name: '行政经理',
+              code: 'OFF-MGR',
+              department: '行政部',
+              description: '行政经理',
+              status: '启用',
+              userCount: 1,
+              createTime: '2024-01-10',
+              parentId: 11
+            },
+            {
+              id: 112,
+              name: '行政专员',
+              code: 'OFF-SPEC',
+              department: '行政部',
+              description: '行政专员',
+              status: '启用',
+              userCount: 4,
+              createTime: '2024-01-10',
+              parentId: 11
+            },
+            {
+              id: 113,
+              name: '前台',
+              code: 'OFF-REC',
+              department: '行政部',
+              description: '前台接待',
+              status: '启用',
+              userCount: 2,
+              createTime: '2024-01-10',
+              parentId: 11
+            }
+          ]
+        }
+      ]
+    }
+  ];
+
+  // 切换展开/收起
+  const togglePositionExpand = (id: number) => {
+    setExpandedPositionIds(prev =>
+      prev.includes(id) ? prev.filter(item => item !== id) : [...prev, id]
+    );
+  };
+
+  // 获取所有岗位(扁平化)
+  const getAllPositions = (nodes: PositionNode[], result: PositionNode[] = []): PositionNode[] => {
+    nodes.forEach(node => {
+      result.push(node);
+      if (node.children) {
+        getAllPositions(node.children, result);
+      }
+    });
+    return result;
+  };
+
+  const allPositions = getAllPositions(positionTree);
+  
+  // 根据选中的岗位ID过滤显示的岗位列表
+  const getFilteredPositions = () => {
+    if (!selectedPositionId) return allPositions;
+    
+    // 找到选中的岗位
+    const selectedPosition = allPositions.find(p => p.id === selectedPositionId);
+    if (!selectedPosition) return allPositions;
+    
+    // 如果有子岗位,只显示直接子岗位
+    if (selectedPosition.children && selectedPosition.children.length > 0) {
+      return selectedPosition.children;
+    }
+    
+    // 如果没有子岗位,返回自己
+    return [selectedPosition];
+  };
+
+  const displayedPositions = getFilteredPositions().filter((position) =>
+    position.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
+    position.code?.toLowerCase().includes(searchTerm.toLowerCase()) ||
+    position.department?.toLowerCase().includes(searchTerm.toLowerCase())
+  );
+
+  // 递归渲染树形节点
+  const renderTreeNode = (node: PositionNode, level: number = 0) => {
+    const isExpanded = expandedPositionIds.includes(node.id);
+    const isSelected = selectedPositionId === node.id;
+    const hasChildren = node.children && node.children.length > 0;
+
+    return (
+      <div key={node.id}>
+        <div
+          className={`flex items-center gap-2 px-3 py-2.5 cursor-pointer transition-all rounded-lg ${
+            isSelected 
+              ? 'bg-blue-100 text-blue-700' 
+              : 'hover:bg-gray-100 text-gray-700'
+          }`}
+          style={{ paddingLeft: `${level * 16 + 12}px` }}
+          onClick={() => setSelectedPositionId(node.id)}
+        >
+          {hasChildren ? (
+            <button
+              onClick={(e) => {
+                e.stopPropagation();
+                togglePositionExpand(node.id);
+              }}
+              className="p-0.5 hover:bg-gray-200 rounded transition-colors"
+            >
+              {isExpanded ? (
+                <ChevronDown className="w-4 h-4" />
+              ) : (
+                <ChevronRight className="w-4 h-4" />
+              )}
+            </button>
+          ) : (
+            <span className="w-5"></span>
+          )}
+          <Briefcase className="w-4 h-4" />
+          <span className="text-sm flex-1">{node.name}</span>
+          {node.userCount && (
+            <span className="text-xs px-2 py-0.5 bg-gray-200 rounded">
+              {node.userCount}人
+            </span>
+          )}
+        </div>
+        
+        {isExpanded && hasChildren && (
+          <div>
+            {node.children!.map(child => renderTreeNode(child, level + 1))}
+          </div>
+        )}
+      </div>
+    );
+  };
+
+  const handleDelete = (id: number) => {
+    if (confirm('确定要删除这个岗位吗?')) {
+      console.log('删除岗位:', id);
+    }
+  };
+
+  const handleEdit = (item: any) => {
+    setEditingItem(item);
+    setShowAddModal(true);
+  };
+
+  // 获取所有部门(用于下拉选择)
+  const departments = ['总公司', '技术中心', '市场中心', '行政中心', '安全部', '研发部', '测试部', '运维部', '市场部', '销售部', '人力资源部', '财务部', '行政部'];
+
+  return (
+    <div className="flex gap-6 h-full">
+      {/* 左侧树形结构 */}
+      <div className="w-80 flex-shrink-0">
+        <div className="bg-white rounded-2xl border border-gray-200/50 shadow-sm p-4 h-full flex flex-col">
+          <div className="flex items-center justify-between mb-4 pb-3 border-b border-gray-200">
+            <h3 className="text-base text-gray-900">岗位分类</h3>
+            <button
+              onClick={() => {
+                setEditingItem(null);
+                setShowAddModal(true);
+              }}
+              className="p-2 text-blue-600 hover:bg-blue-50 rounded-lg transition-colors"
+              title="新增岗位"
+            >
+              <Plus className="w-4 h-4" />
+            </button>
+          </div>
+          
+          <div className="flex-1 overflow-y-auto">
+            {positionTree.map(node => renderTreeNode(node))}
+          </div>
+        </div>
+      </div>
+
+      {/* 右侧列表 */}
+      <div className="flex-1 space-y-6">
+        {/* 工具栏 */}
+        <div className="bg-white rounded-2xl border border-gray-200/50 shadow-sm p-4">
+          <div className="flex items-center justify-between">
+            <div className="relative w-80">
+              <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-5 h-5 text-gray-400" />
+              <input
+                type="text"
+                placeholder="搜索岗位..."
+                value={searchTerm}
+                onChange={(e) => setSearchTerm(e.target.value)}
+                className="w-full h-10 pl-10 pr-4 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"
+              />
+            </div>
+
+            <button
+              onClick={() => {
+                setEditingItem(null);
+                setShowAddModal(true);
+              }}
+              className="flex items-center gap-2 px-4 py-2.5 bg-gradient-to-r from-blue-500 to-blue-600 text-white rounded-xl hover:shadow-lg hover:shadow-blue-400/40 transition-all duration-300"
+            >
+              <Plus className="w-4 h-4" strokeWidth={2.5} />
+              <span className="text-sm">新增岗位</span>
+            </button>
+          </div>
+        </div>
+
+        {/* 表格 */}
+        <div className="bg-white rounded-2xl border border-gray-200/50 shadow-sm overflow-hidden">
+          <div className="overflow-x-auto">
+            <table className="w-full">
+              <thead>
+                <tr className="bg-gradient-to-r from-gray-50 to-gray-100/50 border-b border-gray-200">
+                  <th className="px-6 py-4 text-left text-xs text-gray-600 uppercase tracking-wider" style={{ width: '5%' }}>
+                    序号
+                  </th>
+                  <th className="px-6 py-4 text-left text-xs text-gray-600 uppercase tracking-wider" style={{ width: '15%' }}>
+                    岗位名称
+                  </th>
+                  <th className="px-6 py-4 text-left text-xs text-gray-600 uppercase tracking-wider" style={{ width: '12%' }}>
+                    岗位编码
+                  </th>
+                  <th className="px-6 py-4 text-left text-xs text-gray-600 uppercase tracking-wider" style={{ width: '15%' }}>
+                    所属部门
+                  </th>
+                  <th className="px-6 py-4 text-left text-xs text-gray-600 uppercase tracking-wider" style={{ width: '20%' }}>
+                    岗位描述
+                  </th>
+                  <th className="px-6 py-4 text-left text-xs text-gray-600 uppercase tracking-wider" style={{ width: '8%' }}>
+                    人员数
+                  </th>
+                  <th className="px-6 py-4 text-left text-xs text-gray-600 uppercase tracking-wider" style={{ width: '10%' }}>
+                    状态
+                  </th>
+                  <th className="px-6 py-4 text-left text-xs text-gray-600 uppercase tracking-wider" style={{ width: '10%' }}>
+                    创建时间
+                  </th>
+                  <th className="px-6 py-4 text-center text-xs text-gray-600 uppercase tracking-wider" style={{ width: '10%' }}>
+                    操作
+                  </th>
+                </tr>
+              </thead>
+              <tbody className="divide-y divide-gray-100">
+                {displayedPositions.map((position, index) => (
+                  <tr
+                    key={position.id}
+                    className="hover:bg-blue-50/30 transition-colors"
+                  >
+                    <td className="px-6 py-4 text-sm text-gray-900">
+                      {index + 1}
+                    </td>
+                    <td className="px-6 py-4 text-sm text-gray-900">{position.name}</td>
+                    <td className="px-6 py-4 text-sm text-gray-900">{position.code}</td>
+                    <td className="px-6 py-4 text-sm text-gray-900">{position.department}</td>
+                    <td className="px-6 py-4 text-sm text-gray-900">{position.description}</td>
+                    <td className="px-6 py-4 text-sm text-gray-900">{position.userCount}</td>
+                    <td className="px-6 py-4">
+                      <span className={`inline-flex px-3 py-1 rounded-lg text-xs ${
+                        position.status === '启用' ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-700'
+                      }`}>
+                        {position.status}
+                      </span>
+                    </td>
+                    <td className="px-6 py-4 text-sm text-gray-900">{position.createTime}</td>
+                    <td className="px-6 py-4">
+                      <div className="flex items-center justify-center gap-2">
+                        <button
+                          onClick={() => handleEdit(position)}
+                          className="p-2 text-blue-600 hover:bg-blue-100 rounded-lg transition-colors"
+                          title="编辑"
+                        >
+                          <Edit2 className="w-4 h-4" />
+                        </button>
+                        <button
+                          onClick={() => handleDelete(position.id)}
+                          className="p-2 text-red-600 hover:bg-red-100 rounded-lg transition-colors"
+                          title="删除"
+                        >
+                          <Trash2 className="w-4 h-4" />
+                        </button>
+                        <button
+                          className="p-2 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors"
+                          title="更多"
+                        >
+                          <MoreVertical className="w-4 h-4" />
+                        </button>
+                      </div>
+                    </td>
+                  </tr>
+                ))}
+              </tbody>
+            </table>
+          </div>
+
+          {/* 分页 */}
+          <div className="px-6 py-4 bg-gray-50/50 border-t border-gray-200">
+            <div className="flex items-center justify-between">
+              <div className="text-sm text-gray-600">
+                共 <span className="text-blue-600">{displayedPositions.length}</span> 个岗位
+              </div>
+              <div className="flex gap-2">
+                <button className="px-4 py-2 text-sm text-gray-600 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors">
+                  上一页
+                </button>
+                <button className="px-4 py-2 text-sm text-white bg-blue-500 rounded-lg hover:bg-blue-600 transition-colors">
+                  1
+                </button>
+                <button className="px-4 py-2 text-sm text-gray-600 bg-white border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors">
+                  下一页
+                </button>
+              </div>
+            </div>
+          </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-2xl mx-4 animate-in zoom-in duration-200">
+            {/* 弹窗标题 */}
+            <div className="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
+              <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?.code || ''}
+                  />
+                </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"
+                    defaultValue={editingItem?.department || ''}
+                  >
+                    <option value="">请选择部门</option>
+                    {departments.map(dept => (
+                      <option key={dept} value={dept}>{dept}</option>
+                    ))}
+                  </select>
+                </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"
+                    defaultValue={editingItem?.status || '启用'}
+                  >
+                    <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"
+              >
+                确定
+              </button>
+            </div>
+          </div>
+        </div>
+      )}
+    </div>
+  );
+}
+

+ 11 - 4
src/components/SystemConfig.tsx

@@ -1,6 +1,7 @@
 import React, { useState } from 'react';
 import { Plus, Search, Edit2, Trash2, MoreVertical, ChevronRight, ChevronDown } from 'lucide-react';
 import DepartmentManagement from './DepartmentManagement';
+import PositionManagement from './PositionManagement';
 
 interface TableRow {
   id: number;
@@ -47,9 +48,10 @@ export default function SystemConfig({ subMenu }: SystemConfigProps) {
       children: [
         { id: 21, name: '菜单管理', path: '/system/menu', icon: '菜单', order: 1, status: '启用', createTime: '2025-01-02', parentId: 2 },
         { id: 22, name: '部门管理', path: '/system/dept', icon: '部门', order: 2, status: '启用', createTime: '2025-01-02', parentId: 2 },
-        { id: 23, name: '角色管理', path: '/system/role', icon: '角色', order: 3, status: '启用', createTime: '2025-01-02', parentId: 2 },
-        { id: 24, name: '字典管理', path: '/system/dict', icon: '字典', order: 4, status: '启用', createTime: '2025-01-02', parentId: 2 },
-        { id: 25, name: '机柜管理', path: '/system/cabinet', icon: '机柜', order: 5, status: '启用', createTime: '2025-01-02', parentId: 2 },
+        { id: 26, name: '岗位管理', path: '/system/position', icon: '岗位', order: 3, status: '启用', createTime: '2025-01-02', parentId: 2 },
+        { id: 23, name: '角色管理', path: '/system/role', icon: '角色', order: 4, status: '启用', createTime: '2025-01-02', parentId: 2 },
+        { id: 24, name: '字典管理', path: '/system/dict', icon: '字典', order: 5, status: '启用', createTime: '2025-01-02', parentId: 2 },
+        { id: 25, name: '机柜管理', path: '/system/cabinet', icon: '机柜', order: 6, status: '启用', createTime: '2025-01-02', parentId: 2 },
       ]
     },
     {
@@ -701,10 +703,15 @@ export default function SystemConfig({ subMenu }: SystemConfigProps) {
   }
 
   // 部门管理使用左右分栏布局
-  if (subMenu === '部门管理') {
+  if (subMenu === '部门管理' || subMenu === 'departmentManagement') {
     return <DepartmentManagement />;
   }
 
+  // 岗位管理使用左右分栏布局
+  if (subMenu === '岗位管理' || subMenu === 'positionManagement') {
+    return <PositionManagement />;
+  }
+
   // 其他菜单使用表格展示
   return (
     <div className="space-y-6">

+ 2 - 0
src/i18n.ts

@@ -73,6 +73,7 @@ export const translations = {
     systemConfig: {
       menuManagement: '菜单管理',
       departmentManagement: '部门管理',
+      positionManagement: '岗位管理',
       roleManagement: '角色管理',
       dictionaryManagement: '字典管理',
       cabinetManagement: '机柜管理',
@@ -167,6 +168,7 @@ export const translations = {
     systemConfig: {
       menuManagement: 'Menu',
       departmentManagement: 'Department',
+      positionManagement: 'Position',
       roleManagement: 'Role',
       dictionaryManagement: 'Dictionary',
       cabinetManagement: 'Cabinet',

+ 1 - 0
src/locales/en.json

@@ -66,6 +66,7 @@
   "systemConfig": {
     "menuManagement": "Menu",
     "departmentManagement": "Department",
+    "positionManagement": "Position",
     "roleManagement": "Role",
     "dictionaryManagement": "Dictionary",
     "cabinetManagement": "Cabinet"

+ 1 - 0
src/locales/zh.json

@@ -66,6 +66,7 @@
   "systemConfig": {
     "menuManagement": "菜单管理",
     "departmentManagement": "部门管理",
+    "positionManagement": "岗位管理",
     "roleManagement": "角色管理",
     "dictionaryManagement": "字典管理",
     "cabinetManagement": "机柜管理"