pm 5 місяців тому
батько
коміт
76aad27ade

+ 1 - 1
.env

@@ -4,7 +4,7 @@ VITE_APP_TITLE=能量隔离系统
 # 项目本地运行端口号
 VITE_PORT=81
 # 请求路径
-VITE_BASE_URL='http://120.27.232.27:48080'
+VITE_BASE_URL='http://192.168.0.10:48080'
 # open 运行 npm run dev 时自动打开浏览器
 VITE_OPEN=true
 

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
build/assets/index-CgdPl1P3.css


Різницю між файлами не показано, бо вона завелика
+ 0 - 8
build/assets/index-DYNIqP4U.js


+ 0 - 16
build/index.html

@@ -1,16 +0,0 @@
-
-  <!DOCTYPE html>
-  <html lang="en">
-    <head>
-      <meta charset="UTF-8" />
-      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-      <title>能量隔离系统</title>
-      <script type="module" crossorigin src="/assets/index-DYNIqP4U.js"></script>
-      <link rel="stylesheet" crossorigin href="/assets/index-CgdPl1P3.css">
-    </head>
-
-    <body>
-      <div id="root"></div>
-    </body>
-  </html>
-  

+ 37 - 17
src/Dashboard.tsx

@@ -716,7 +716,7 @@ export default function Dashboard() {
                             setShowDropdownMenu(item.key);
                           }}
                           onMouseLeave={() => {
-                            const timer = setTimeout(() => setShowDropdownMenu(null), 200);
+                            const timer = setTimeout(() => setShowDropdownMenu(null), 2000);
                             setDropdownTimer(timer);
                           }}
                         >
@@ -736,22 +736,41 @@ export default function Dashboard() {
                         
                         {/* 下拉菜单 - 使用 fixed 定位,避免被父容器裁剪 */}
                         {isDropdownOpen && dropdownPosition && (
-                          <div
-                            className="fixed bg-white rounded-xl shadow-xl border border-gray-200/50 p-3 animate-in fade-in slide-in-from-top-2 duration-200 z-[100]"
-                            style={{
-                              top: `${dropdownPosition.top}px`,
-                              left: `${dropdownPosition.left}px`,
-                              width: '340px',
-                            }}
-                            onMouseEnter={() => {
-                              if (dropdownTimer) clearTimeout(dropdownTimer);
-                              setShowDropdownMenu(item.key);
-                            }}
-                            onMouseLeave={() => {
-                              const timer = setTimeout(() => setShowDropdownMenu(null), 200);
-                              setDropdownTimer(timer);
-                            }}
-                          >
+                          <>
+                            {/* 连接区域 - 填充按钮和下拉菜单之间的间隙 */}
+                            <div
+                              className="fixed z-[99]"
+                              style={{
+                                top: `${dropdownPosition.top - 8}px`,
+                                left: `${dropdownPosition.left}px`,
+                                width: '340px',
+                                height: '8px',
+                              }}
+                              onMouseEnter={() => {
+                                if (dropdownTimer) clearTimeout(dropdownTimer);
+                                setShowDropdownMenu(item.key);
+                              }}
+                              onMouseLeave={() => {
+                                const timer = setTimeout(() => setShowDropdownMenu(null), 2000);
+                                setDropdownTimer(timer);
+                              }}
+                            />
+                            <div
+                              className="fixed bg-white rounded-xl shadow-xl border border-gray-200/50 p-3 animate-in fade-in slide-in-from-top-2 duration-200 z-[100]"
+                              style={{
+                                top: `${dropdownPosition.top}px`,
+                                left: `${dropdownPosition.left}px`,
+                                width: '340px',
+                              }}
+                              onMouseEnter={() => {
+                                if (dropdownTimer) clearTimeout(dropdownTimer);
+                                setShowDropdownMenu(item.key);
+                              }}
+                              onMouseLeave={() => {
+                                const timer = setTimeout(() => setShowDropdownMenu(null), 1000);
+                                setDropdownTimer(timer);
+                              }}
+                            >
                             <div className="grid grid-cols-2 gap-2">
                               {(filteredSubMenuConfig[item.key] || []).map((subItem) => {
                                 const IconComponent = subItem.icon;
@@ -786,6 +805,7 @@ export default function Dashboard() {
                               })}
                             </div>
                           </div>
+                          </>
                         )}
                       </>
                     );

+ 17 - 13
src/components/DepartmentManagement.tsx

@@ -258,20 +258,24 @@ export default function DepartmentManagement() {
 
           {/* 操作按钮组 */}
           <Space className="flex-shrink-0">
-            <AntButton
-              type="primary"
-              icon={<Search className="w-4 h-4" />}
-              onClick={handleQuery}
-            >
-              搜索
-            </AntButton>
+            <PermissionWrapper permission="system:dept:query">
+              <AntButton
+                type="primary"
+                icon={<Search className="w-4 h-4" />}
+                onClick={handleQuery}
+              >
+                搜索
+              </AntButton>
+            </PermissionWrapper>
             
-            <AntButton
-              icon={<RefreshCw className="w-4 h-4" />}
-              onClick={resetQuery}
-            >
-              重置
-            </AntButton>
+            <PermissionWrapper permission="system:dept:query">
+              <AntButton
+                icon={<RefreshCw className="w-4 h-4" />}
+                onClick={resetQuery}
+              >
+                重置
+              </AntButton>
+            </PermissionWrapper>
             
             <PermissionWrapper permission="system:dept:create">
               <AntButton

+ 92 - 72
src/components/DictTypeManagement.tsx

@@ -12,6 +12,8 @@ import { Table as UITable, TableBody, TableCell, TableHead, TableHeader, TableRo
 import DictTypeForm, { DictTypeFormRef } from './DictTypeForm';
 import DictDataForm, { DictDataFormRef } from './DictDataForm';
 import type { ColumnsType } from 'antd/es/table';
+import PermissionWrapper from './PermissionWrapper';
+import { hasPermission } from '../utils/permission';
 
 const { Search: AntSearch } = Input;
 const AntButton = Button;
@@ -301,24 +303,28 @@ export default function DictTypeManagement() {
       fixed: 'right',
       render: (_: any, record: DictDataVO) => (
         <div className="flex items-center gap-2 justify-center">
-          <UIButton
-            variant="ghost"
-            size="sm"
-            onClick={() => openDictDataForm('update', record.id)}
-            className="h-8 px-2"
-          >
-            <Edit2 className="w-4 h-4" />
-            <span className="ml-1">编辑</span>
-          </UIButton>
-          <UIButton
-            variant="ghost"
-            size="sm"
-            onClick={() => handleDeleteDictData(record.id!, record.label)}
-            className="h-8 px-2 text-red-600 hover:text-red-700"
-          >
-            <Trash2 className="w-4 h-4" />
-            <span className="ml-1">删除</span>
-          </UIButton>
+          <PermissionWrapper permission="system:dict:update">
+            <UIButton
+              variant="ghost"
+              size="sm"
+              onClick={() => openDictDataForm('update', record.id)}
+              className="h-8 px-2"
+            >
+              <Edit2 className="w-4 h-4" />
+              <span className="ml-1">编辑</span>
+            </UIButton>
+          </PermissionWrapper>
+          <PermissionWrapper permission="system:dict:delete">
+            <UIButton
+              variant="ghost"
+              size="sm"
+              onClick={() => handleDeleteDictData(record.id!, record.label)}
+              className="h-8 px-2 text-red-600 hover:text-red-700"
+            >
+              <Trash2 className="w-4 h-4" />
+              <span className="ml-1">删除</span>
+            </UIButton>
+          </PermissionWrapper>
         </div>
       ),
     },
@@ -357,28 +363,34 @@ export default function DictTypeManagement() {
 
           {/* 操作按钮组 */}
           <Space className="flex-shrink-0">
-            <Button
-              type="primary"
-              icon={<Search className="w-4 h-4" />}
-              onClick={handleQuery}
-            >
-              搜索
-            </Button>
+            <PermissionWrapper permission="system:dict:query">
+              <Button
+                type="primary"
+                icon={<Search className="w-4 h-4" />}
+                onClick={handleQuery}
+              >
+                搜索
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              icon={<RefreshCw className="w-4 h-4" />}
-              onClick={resetQuery}
-            >
-              重置
-            </Button>
+            <PermissionWrapper permission="system:dict:query">
+              <Button
+                icon={<RefreshCw className="w-4 h-4" />}
+                onClick={resetQuery}
+              >
+                重置
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              type="primary"
-              icon={<Plus className="w-4 h-4" />}
-              onClick={() => openForm('create')}
-            >
-              新增
-            </Button>
+            <PermissionWrapper permission="system:dict:create">
+              <Button
+                type="primary"
+                icon={<Plus className="w-4 h-4" />}
+                onClick={() => openForm('create')}
+              >
+                新增
+              </Button>
+            </PermissionWrapper>
           </Space>
         </div>
       </div>
@@ -430,33 +442,39 @@ export default function DictTypeManagement() {
                   </TableCell>
                   <TableCell>
                     <div className="flex items-center gap-2 justify-center">
-                      <UIButton
-                        variant="ghost"
-                        size="sm"
-                        onClick={() => openForm('update', row.id)}
-                        className="h-8 px-2"
-                      >
-                        <Edit2 className="w-4 h-4" />
-                        <span className="ml-1">编辑</span>
-                      </UIButton>
-                      <UIButton
-                        variant="ghost"
-                        size="sm"
-                        onClick={() => openDictDataModal(row)}
-                        className="h-8 px-2"
-                      >
-                        <Eye className="w-4 h-4" />
-                        <span className="ml-1">数据</span>
-                      </UIButton>
-                      <UIButton
-                        variant="ghost"
-                        size="sm"
-                        onClick={() => handleDelete(row.id!, row.name)}
-                        className="h-8 px-2 text-red-600 hover:text-red-700"
-                      >
-                        <Trash2 className="w-4 h-4" />
-                        <span className="ml-1">删除</span>
-                      </UIButton>
+                      <PermissionWrapper permission="system:dict:update">
+                        <UIButton
+                          variant="ghost"
+                          size="sm"
+                          onClick={() => openForm('update', row.id)}
+                          className="h-8 px-2"
+                        >
+                          <Edit2 className="w-4 h-4" />
+                          <span className="ml-1">编辑</span>
+                        </UIButton>
+                      </PermissionWrapper>
+                      <PermissionWrapper permission="system:dict:query">
+                        <UIButton
+                          variant="ghost"
+                          size="sm"
+                          onClick={() => openDictDataModal(row)}
+                          className="h-8 px-2"
+                        >
+                          <Eye className="w-4 h-4" />
+                          <span className="ml-1">数据</span>
+                        </UIButton>
+                      </PermissionWrapper>
+                      <PermissionWrapper permission="system:dict:delete">
+                        <UIButton
+                          variant="ghost"
+                          size="sm"
+                          onClick={() => handleDelete(row.id!, row.name)}
+                          className="h-8 px-2 text-red-600 hover:text-red-700"
+                        >
+                          <Trash2 className="w-4 h-4" />
+                          <span className="ml-1">删除</span>
+                        </UIButton>
+                      </PermissionWrapper>
                     </div>
                   </TableCell>
                 </TableRow>
@@ -520,13 +538,15 @@ export default function DictTypeManagement() {
               style={{ width: 300 }}
               enterButton
             />
-            <UIButton
-              onClick={() => openDictDataForm('create')}
-              className="flex items-center gap-2"
-            >
-              <Plus className="w-4 h-4" />
-              新增字典项
-            </UIButton>
+            <PermissionWrapper permission="system:dict:create">
+              <UIButton
+                onClick={() => openDictDataForm('create')}
+                className="flex items-center gap-2"
+              >
+                <Plus className="w-4 h-4" />
+                新增字典项
+              </UIButton>
+            </PermissionWrapper>
           </div>
 
           {/* 表格 */}

+ 59 - 46
src/components/KeyManagement.tsx

@@ -10,6 +10,7 @@ import { DICT_TYPE, getStrDictOptions } from '../utils/dict';
 import { dateFormatter } from '../utils/formatTime';
 import { Button as UIButton } from './ui/button';
 import { useTranslation } from 'react-i18next';
+import PermissionWrapper from './PermissionWrapper';
 
 interface KeyManagementProps {
   subMenu?: string;
@@ -202,24 +203,28 @@ export default function KeyManagement({ subMenu }: KeyManagementProps) {
       fixed: 'right',
       render: (_: any, record: KeyVO) => (
         <div className="flex items-center gap-2 justify-center">
-          <UIButton
-            variant="ghost"
-            size="sm"
-            onClick={() => openKeyForm('update', record.keyId || record.id)}
-            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.keyId || 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>
+          <PermissionWrapper permission="iscs:key:update">
+            <UIButton
+              variant="ghost"
+              size="sm"
+              onClick={() => openKeyForm('update', record.keyId || record.id)}
+              className="h-8 px-2"
+            >
+              <Edit2 className="w-4 h-4" />
+              <span className="ml-1">编辑</span>
+            </UIButton>
+          </PermissionWrapper>
+          <PermissionWrapper permission="iscs:key:delete">
+            <UIButton
+              variant="ghost"
+              size="sm"
+              onClick={() => handleDelete(record.keyId || 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>
+          </PermissionWrapper>
         </div>
       ),
     },
@@ -249,37 +254,45 @@ export default function KeyManagement({ subMenu }: KeyManagementProps) {
 
             {/* 操作按钮组 */}
             <Space className="flex-shrink-0">
-              <Button
-                type="primary"
-                icon={<Search className="w-4 h-4" />}
-                onClick={handleQuery}
-              >
-                搜索
-              </Button>
+              <PermissionWrapper permission="iscs:key:query">
+                <Button
+                  type="primary"
+                  icon={<Search className="w-4 h-4" />}
+                  onClick={handleQuery}
+                >
+                  搜索
+                </Button>
+              </PermissionWrapper>
               
-              <Button
-                icon={<RefreshCw className="w-4 h-4" />}
-                onClick={resetQuery}
-              >
-                重置
-              </Button>
+              <PermissionWrapper permission="iscs:key:query">
+                <Button
+                  icon={<RefreshCw className="w-4 h-4" />}
+                  onClick={resetQuery}
+                >
+                  重置
+                </Button>
+              </PermissionWrapper>
               
-              <Button
-                type="primary"
-                icon={<Plus className="w-4 h-4" />}
-                onClick={() => openKeyForm('create')}
-              >
-                新增
-              </Button>
+              <PermissionWrapper permission="iscs:key:create">
+                <Button
+                  type="primary"
+                  icon={<Plus className="w-4 h-4" />}
+                  onClick={() => openKeyForm('create')}
+                >
+                  新增
+                </Button>
+              </PermissionWrapper>
               
-              <Button
-                danger
-                icon={<Trash2 className="w-4 h-4" />}
-                onClick={() => handleDelete()}
-                disabled={selectedRowKeys.length === 0}
-              >
-                批量删除
-              </Button>
+              <PermissionWrapper permission="iscs:key:delete">
+                <Button
+                  danger
+                  icon={<Trash2 className="w-4 h-4" />}
+                  onClick={() => handleDelete()}
+                  disabled={selectedRowKeys.length === 0}
+                >
+                  批量删除
+                </Button>
+              </PermissionWrapper>
             </Space>
           </div>
         </div>

+ 60 - 47
src/components/MenuManagement.tsx

@@ -18,6 +18,7 @@ import { Button as UIButton } from './ui/button';
 import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './ui/table';
 import { Switch } from './ui/switch';
 import MenuForm, { MenuFormRef } from './MenuForm';
+import PermissionWrapper from './PermissionWrapper';
 
 interface MenuNode extends MenuVO, TreeNode {
   children?: MenuNode[];
@@ -371,33 +372,39 @@ export default function MenuManagement() {
           </TableCell>
           <TableCell>
             <div className="flex items-center gap-2 justify-center">
-              <UIButton
-                variant="ghost"
-                size="sm"
-                onClick={() => openForm('update', node.id)}
-                className="h-8 px-2"
-              >
-                <Edit2 className="w-4 h-4" />
-                <span className="ml-1">编辑</span>
-              </UIButton>
-              <UIButton
-                variant="ghost"
-                size="sm"
-                onClick={() => openForm('create', undefined, node.id)}
-                className="h-8 px-2"
-              >
-                <Plus className="w-4 h-4" />
-                <span className="ml-1">新增</span>
-              </UIButton>
-              <UIButton
-                variant="ghost"
-                size="sm"
-                onClick={() => handleDelete(node.id!, node.name)}
-                className="h-8 px-2 text-red-600 hover:text-red-700"
-              >
-                <Trash2 className="w-4 h-4" />
-                <span className="ml-1">删除</span>
-              </UIButton>
+              <PermissionWrapper permission="system:menu:update">
+                <UIButton
+                  variant="ghost"
+                  size="sm"
+                  onClick={() => openForm('update', node.id)}
+                  className="h-8 px-2"
+                >
+                  <Edit2 className="w-4 h-4" />
+                  <span className="ml-1">编辑</span>
+                </UIButton>
+              </PermissionWrapper>
+              <PermissionWrapper permission="system:menu:create">
+                <UIButton
+                  variant="ghost"
+                  size="sm"
+                  onClick={() => openForm('create', undefined, node.id)}
+                  className="h-8 px-2"
+                >
+                  <Plus className="w-4 h-4" />
+                  <span className="ml-1">新增</span>
+                </UIButton>
+              </PermissionWrapper>
+              <PermissionWrapper permission="system:menu:delete">
+                <UIButton
+                  variant="ghost"
+                  size="sm"
+                  onClick={() => handleDelete(node.id!, node.name)}
+                  className="h-8 px-2 text-red-600 hover:text-red-700"
+                >
+                  <Trash2 className="w-4 h-4" />
+                  <span className="ml-1">删除</span>
+                </UIButton>
+              </PermissionWrapper>
             </div>
           </TableCell>
         </TableRow>
@@ -432,28 +439,34 @@ export default function MenuManagement() {
 
           {/* 操作按钮组 */}
           <Space className="flex-shrink-0">
-            <Button
-              type="primary"
-              icon={<Search className="w-4 h-4" />}
-              onClick={handleQuery}
-            >
-              搜索
-            </Button>
+            <PermissionWrapper permission="system:menu:query">
+              <Button
+                type="primary"
+                icon={<Search className="w-4 h-4" />}
+                onClick={handleQuery}
+              >
+                搜索
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              icon={<RefreshCw className="w-4 h-4" />}
-              onClick={resetQuery}
-            >
-              重置
-            </Button>
+            <PermissionWrapper permission="system:menu:query">
+              <Button
+                icon={<RefreshCw className="w-4 h-4" />}
+                onClick={resetQuery}
+              >
+                重置
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              type="primary"
-              icon={<Plus className="w-4 h-4" />}
-              onClick={() => openForm('create')}
-            >
-              新增
-            </Button>
+            <PermissionWrapper permission="system:menu:create">
+              <Button
+                type="primary"
+                icon={<Plus className="w-4 h-4" />}
+                onClick={() => openForm('create')}
+              >
+                新增
+              </Button>
+            </PermissionWrapper>
             
             <Button
               icon={isExpandAll ? <ChevronDown className="w-4 h-4" /> : <ChevronRight className="w-4 h-4" />}

+ 102 - 81
src/components/PadLockManagement.tsx

@@ -13,6 +13,7 @@ import { dateFormatter } from '../utils/formatTime';
 import UploadImg from './lockCabinet/UploadImg';
 import { Button as UIButton } from './ui/button';
 import { useTranslation } from 'react-i18next';
+import PermissionWrapper from './PermissionWrapper';
 
 interface PadLockManagementProps {
   subMenu?: string;
@@ -400,24 +401,28 @@ export default function PadLockManagement({ subMenu }: PadLockManagementProps) {
       fixed: 'right',
       render: (_: any, record: PadLockVO) => (
         <div className="flex items-center gap-2 justify-center">
-          <UIButton
-            variant="ghost"
-            size="sm"
-            onClick={() => openPadLockForm('update', record.lockId || record.id)}
-            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.lockId || 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>
+          <PermissionWrapper permission="iscs:lock:update">
+            <UIButton
+              variant="ghost"
+              size="sm"
+              onClick={() => openPadLockForm('update', record.lockId || record.id)}
+              className="h-8 px-2"
+            >
+              <Edit2 className="w-4 h-4" />
+              <span className="ml-1">编辑</span>
+            </UIButton>
+          </PermissionWrapper>
+          <PermissionWrapper permission="iscs:lock:delete">
+            <UIButton
+              variant="ghost"
+              size="sm"
+              onClick={() => handleDelete(record.lockId || 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>
+          </PermissionWrapper>
         </div>
       ),
     },
@@ -487,15 +492,17 @@ export default function PadLockManagement({ subMenu }: PadLockManagementProps) {
       fixed: 'right',
       render: (_: any, record: PadLockTypeVO) => (
         <div className="flex items-center gap-2 justify-center">
-          <UIButton
-            variant="ghost"
-            size="sm"
-            onClick={() => openTypeForm('update', record.lockTypeId || record.id)}
-            className="h-8 px-2"
-          >
-            <Edit2 className="w-4 h-4" />
-            <span className="ml-1">修改</span>
-          </UIButton>
+          <PermissionWrapper permission="iscs:lock:update">
+            <UIButton
+              variant="ghost"
+              size="sm"
+              onClick={() => openTypeForm('update', record.lockTypeId || record.id)}
+              className="h-8 px-2"
+            >
+              <Edit2 className="w-4 h-4" />
+              <span className="ml-1">修改</span>
+            </UIButton>
+          </PermissionWrapper>
           <UIButton
             variant="ghost"
             size="sm"
@@ -547,44 +554,52 @@ export default function PadLockManagement({ subMenu }: PadLockManagementProps) {
 
                 {/* 操作按钮组 */}
                 <Space className="flex-shrink-0">
-                  <Button
-                    type="primary"
-                    icon={<Search className="w-4 h-4" />}
-                    onClick={handleQuery}
-                  >
-                    搜索
-                  </Button>
+                  <PermissionWrapper permission="iscs:lock:query">
+                    <Button
+                      type="primary"
+                      icon={<Search className="w-4 h-4" />}
+                      onClick={handleQuery}
+                    >
+                      搜索
+                    </Button>
+                  </PermissionWrapper>
+                  
+                  <PermissionWrapper permission="iscs:lock:query">
+                    <Button
+                      icon={<RefreshCw className="w-4 h-4" />}
+                      onClick={resetQuery}
+                    >
+                      重置
+                    </Button>
+                  </PermissionWrapper>
+                  
+                  <PermissionWrapper permission="iscs:lock:create">
+                    <Button
+                      type="primary"
+                      icon={<Plus className="w-4 h-4" />}
+                      onClick={() => openPadLockForm('create')}
+                    >
+                      新增
+                    </Button>
+                  </PermissionWrapper>
+                  
+                  <PermissionWrapper permission="iscs:lock:delete">
+                    <Button
+                      danger
+                      icon={<Trash2 className="w-4 h-4" />}
+                      onClick={() => handleDelete()}
+                      disabled={selectedRowKeys.length === 0}
+                    >
+                      批量删除
+                    </Button>
+                  </PermissionWrapper>
                   
                   <Button
-                    icon={<RefreshCw className="w-4 h-4" />}
-                    onClick={resetQuery}
+                    icon={<Settings className="w-4 h-4" />}
+                    onClick={() => setViewMode('type')}
                   >
-                    重置
+                    设置挂锁类型
                   </Button>
-                  
-                <Button
-                  type="primary"
-                  icon={<Plus className="w-4 h-4" />}
-                  onClick={() => openPadLockForm('create')}
-                >
-                  新增
-                </Button>
-                
-                <Button
-                  danger
-                  icon={<Trash2 className="w-4 h-4" />}
-                  onClick={() => handleDelete()}
-                  disabled={selectedRowKeys.length === 0}
-                >
-                  批量删除
-                </Button>
-                
-                <Button
-                  icon={<Settings className="w-4 h-4" />}
-                  onClick={() => setViewMode('type')}
-                >
-                  设置挂锁类型
-                </Button>
                 </Space>
               </div>
             </div>
@@ -669,28 +684,34 @@ export default function PadLockManagement({ subMenu }: PadLockManagementProps) {
 
                 {/* 操作按钮组 */}
                 <Space className="flex-shrink-0">
-                  <Button
-                    type="primary"
-                    icon={<Search className="w-4 h-4" />}
-                    onClick={handleTypeQuery}
-                  >
-                    搜索
-                  </Button>
+                  <PermissionWrapper permission="iscs:lock:query">
+                    <Button
+                      type="primary"
+                      icon={<Search className="w-4 h-4" />}
+                      onClick={handleTypeQuery}
+                    >
+                      搜索
+                    </Button>
+                  </PermissionWrapper>
                   
-                  <Button
-                    icon={<RefreshCw className="w-4 h-4" />}
-                    onClick={resetTypeQuery}
-                  >
-                    重置
-                  </Button>
+                  <PermissionWrapper permission="iscs:lock:query">
+                    <Button
+                      icon={<RefreshCw className="w-4 h-4" />}
+                      onClick={resetTypeQuery}
+                    >
+                      重置
+                    </Button>
+                  </PermissionWrapper>
                   
-                  <Button
-                    type="primary"
-                    icon={<Plus className="w-4 h-4" />}
-                    onClick={() => openTypeForm('create')}
-                  >
-                    新增
-                  </Button>
+                  <PermissionWrapper permission="iscs:lock:create">
+                    <Button
+                      type="primary"
+                      icon={<Plus className="w-4 h-4" />}
+                      onClick={() => openTypeForm('create')}
+                    >
+                      新增
+                    </Button>
+                  </PermissionWrapper>
                   
                   <Button
                     icon={<ArrowUpDown className="w-4 h-4" />}

+ 58 - 45
src/components/PostManagement.tsx

@@ -8,6 +8,7 @@ import { ExclamationCircleOutlined } from '@ant-design/icons';
 import { Button as UIButton } from './ui/button';
 import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './ui/table';
 import PostForm, { PostFormRef } from './PostForm';
+import PermissionWrapper from './PermissionWrapper';
 
 export default function PostManagement() {
   const [loading, setLoading] = useState(true);
@@ -218,36 +219,44 @@ export default function PostManagement() {
 
           {/* 操作按钮组 */}
           <Space className="flex-shrink-0">
-            <Button
-              type="primary"
-              icon={<Search className="w-4 h-4" />}
-              onClick={handleQuery}
-            >
-              搜索
-            </Button>
+            <PermissionWrapper permission="system:post:query">
+              <Button
+                type="primary"
+                icon={<Search className="w-4 h-4" />}
+                onClick={handleQuery}
+              >
+                搜索
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              icon={<RefreshCw className="w-4 h-4" />}
-              onClick={resetQuery}
-            >
-              重置
-            </Button>
+            <PermissionWrapper permission="system:post:query">
+              <Button
+                icon={<RefreshCw className="w-4 h-4" />}
+                onClick={resetQuery}
+              >
+                重置
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              type="primary"
-              icon={<Plus className="w-4 h-4" />}
-              onClick={() => openForm('create')}
-            >
-              新增
-            </Button>
+            <PermissionWrapper permission="system:post:create">
+              <Button
+                type="primary"
+                icon={<Plus className="w-4 h-4" />}
+                onClick={() => openForm('create')}
+              >
+                新增
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              icon={<Download className="w-4 h-4" />}
-              onClick={handleExport}
-              loading={exportLoading}
-            >
-              导出
-            </Button>
+            <PermissionWrapper permission="system:post:export">
+              <Button
+                icon={<Download className="w-4 h-4" />}
+                onClick={handleExport}
+                loading={exportLoading}
+              >
+                导出
+              </Button>
+            </PermissionWrapper>
           </Space>
         </div>
       </div>
@@ -298,24 +307,28 @@ export default function PostManagement() {
                   </TableCell>
                   <TableCell>
                     <div className="flex items-center gap-2 justify-center">
-                      <UIButton
-                        variant="ghost"
-                        size="sm"
-                        onClick={() => openForm('update', row.id)}
-                        className="h-8 px-2"
-                      >
-                        <Edit2 className="w-4 h-4" />
-                        <span className="ml-1">编辑</span>
-                      </UIButton>
-                      <UIButton
-                        variant="ghost"
-                        size="sm"
-                        onClick={() => handleDelete(row.id!, row.name)}
-                        className="h-8 px-2 text-red-600 hover:text-red-700"
-                      >
-                        <Trash2 className="w-4 h-4" />
-                        <span className="ml-1">删除</span>
-                      </UIButton>
+                      <PermissionWrapper permission="system:post:update">
+                        <UIButton
+                          variant="ghost"
+                          size="sm"
+                          onClick={() => openForm('update', row.id)}
+                          className="h-8 px-2"
+                        >
+                          <Edit2 className="w-4 h-4" />
+                          <span className="ml-1">编辑</span>
+                        </UIButton>
+                      </PermissionWrapper>
+                      <PermissionWrapper permission="system:post:delete">
+                        <UIButton
+                          variant="ghost"
+                          size="sm"
+                          onClick={() => handleDelete(row.id!, row.name)}
+                          className="h-8 px-2 text-red-600 hover:text-red-700"
+                        >
+                          <Trash2 className="w-4 h-4" />
+                          <span className="ml-1">删除</span>
+                        </UIButton>
+                      </PermissionWrapper>
                     </div>
                   </TableCell>
                 </TableRow>

+ 81 - 63
src/components/RoleManagement.tsx

@@ -11,6 +11,8 @@ import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '.
 import RoleForm, { RoleFormRef } from './RoleForm';
 import RoleAssignMenuForm, { RoleAssignMenuFormRef } from './RoleAssignMenuForm';
 import RoleDataPermissionForm, { RoleDataPermissionFormRef } from './RoleDataPermissionForm';
+import PermissionWrapper from './PermissionWrapper';
+import { hasPermission } from '../utils/permission';
 
 export default function RoleManagement() {
   const [loading, setLoading] = useState(true);
@@ -208,36 +210,44 @@ export default function RoleManagement() {
 
           {/* 操作按钮组 */}
           <Space className="flex-shrink-0">
-            <Button
-              type="primary"
-              icon={<Search className="w-4 h-4" />}
-              onClick={handleQuery}
-            >
-              搜索
-            </Button>
+            <PermissionWrapper permission="system:role:query">
+              <Button
+                type="primary"
+                icon={<Search className="w-4 h-4" />}
+                onClick={handleQuery}
+              >
+                搜索
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              icon={<RefreshCw className="w-4 h-4" />}
-              onClick={resetQuery}
-            >
-              重置
-            </Button>
+            <PermissionWrapper permission="system:role:query">
+              <Button
+                icon={<RefreshCw className="w-4 h-4" />}
+                onClick={resetQuery}
+              >
+                重置
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              type="primary"
-              icon={<Plus className="w-4 h-4" />}
-              onClick={() => openForm('create')}
-            >
-              新增
-            </Button>
+            <PermissionWrapper permission="system:role:create">
+              <Button
+                type="primary"
+                icon={<Plus className="w-4 h-4" />}
+                onClick={() => openForm('create')}
+              >
+                新增
+              </Button>
+            </PermissionWrapper>
             
-            <Button
-              icon={<Download className="w-4 h-4" />}
-              onClick={handleExport}
-              loading={exportLoading}
-            >
-              导出
-            </Button>
+            <PermissionWrapper permission="system:role:export">
+              <Button
+                icon={<Download className="w-4 h-4" />}
+                onClick={handleExport}
+                loading={exportLoading}
+              >
+                导出
+              </Button>
+            </PermissionWrapper>
           </Space>
         </div>
       </div>
@@ -292,42 +302,50 @@ export default function RoleManagement() {
                   </TableCell>
                   <TableCell>
                     <div className="flex items-center gap-2 justify-center">
-                      <UIButton
-                        variant="ghost"
-                        size="sm"
-                        onClick={() => openForm('update', row.id)}
-                        className="h-8 px-2"
-                      >
-                        <Edit2 className="w-4 h-4" />
-                        <span className="ml-1">编辑</span>
-                      </UIButton>
-                      <UIButton
-                        variant="ghost"
-                        size="sm"
-                        onClick={() => openAssignMenuForm(row)}
-                        className="h-8 px-2"
-                      >
-                        <Settings className="w-4 h-4" />
-                        <span className="ml-1">菜单权限</span>
-                      </UIButton>
-                      <UIButton
-                        variant="ghost"
-                        size="sm"
-                        onClick={() => openDataPermissionForm(row)}
-                        className="h-8 px-2"
-                      >
-                        <Shield className="w-4 h-4" />
-                        <span className="ml-1">数据权限</span>
-                      </UIButton>
-                      <UIButton
-                        variant="ghost"
-                        size="sm"
-                        onClick={() => handleDelete(row.id!, row.name)}
-                        className="h-8 px-2 text-red-600 hover:text-red-700"
-                      >
-                        <Trash2 className="w-4 h-4" />
-                        <span className="ml-1">删除</span>
-                      </UIButton>
+                      <PermissionWrapper permission="system:role:update">
+                        <UIButton
+                          variant="ghost"
+                          size="sm"
+                          onClick={() => openForm('update', row.id)}
+                          className="h-8 px-2"
+                        >
+                          <Edit2 className="w-4 h-4" />
+                          <span className="ml-1">编辑</span>
+                        </UIButton>
+                      </PermissionWrapper>
+                      <PermissionWrapper permission="system:permission:assign-role-menu">
+                        <UIButton
+                          variant="ghost"
+                          size="sm"
+                          onClick={() => openAssignMenuForm(row)}
+                          className="h-8 px-2"
+                        >
+                          <Settings className="w-4 h-4" />
+                          <span className="ml-1">菜单权限</span>
+                        </UIButton>
+                      </PermissionWrapper>
+                      <PermissionWrapper permission="system:permission:assign-role-data-scope">
+                        <UIButton
+                          variant="ghost"
+                          size="sm"
+                          onClick={() => openDataPermissionForm(row)}
+                          className="h-8 px-2"
+                        >
+                          <Shield className="w-4 h-4" />
+                          <span className="ml-1">数据权限</span>
+                        </UIButton>
+                      </PermissionWrapper>
+                      <PermissionWrapper permission="system:role:delete">
+                        <UIButton
+                          variant="ghost"
+                          size="sm"
+                          onClick={() => handleDelete(row.id!, row.name)}
+                          className="h-8 px-2 text-red-600 hover:text-red-700"
+                        >
+                          <Trash2 className="w-4 h-4" />
+                          <span className="ml-1">删除</span>
+                        </UIButton>
+                      </PermissionWrapper>
                     </div>
                   </TableCell>
                 </TableRow>

+ 59 - 46
src/components/SegregationPointManagement.tsx

@@ -12,6 +12,7 @@ import { handleTree } from '../utils/tree';
 import { getStrDictOptions, DICT_TYPE } from '../utils/dict';
 import SegregationPointForm, { SegregationPointFormRef } from './SegregationPointForm';
 import { Button as UIButton } from './ui/button';
+import PermissionWrapper from './PermissionWrapper';
 
 interface SegregationPointManagementProps {
   subMenu?: string;
@@ -275,24 +276,28 @@ export default function SegregationPointManagement({ subMenu }: SegregationPoint
       fixed: 'right',
       render: (_: any, record: SegregationPointVO) => (
         <div className="flex items-center gap-2 justify-center">
-          <UIButton
-            variant="ghost"
-            size="sm"
-            onClick={() => openForm('update', record.pointId)}
-            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.pointId)}
-            className="h-8 px-2 text-red-600 hover:text-red-700"
-          >
-            <Trash2 className="w-4 h-4" />
-            <span className="ml-1">删除</span>
-          </UIButton>
+          <PermissionWrapper permission="iscs:point:update">
+            <UIButton
+              variant="ghost"
+              size="sm"
+              onClick={() => openForm('update', record.pointId)}
+              className="h-8 px-2"
+            >
+              <Edit2 className="w-4 h-4" />
+              <span className="ml-1">编辑</span>
+            </UIButton>
+          </PermissionWrapper>
+          <PermissionWrapper permission="iscs:point:delete">
+            <UIButton
+              variant="ghost"
+              size="sm"
+              onClick={() => handleDelete(record.pointId)}
+              className="h-8 px-2 text-red-600 hover:text-red-700"
+            >
+              <Trash2 className="w-4 h-4" />
+              <span className="ml-1">删除</span>
+            </UIButton>
+          </PermissionWrapper>
         </div>
       ),
     },
@@ -364,34 +369,42 @@ export default function SegregationPointManagement({ subMenu }: SegregationPoint
 
           {/* 操作按钮组 */}
           <Space className="flex-shrink-0">
-            <Button
-              type="primary"
-              icon={<Search />}
-              onClick={handleQuery}
-            >
-              搜索
-            </Button>
-            <Button
-              icon={<RefreshCw />}
-              onClick={resetQuery}
-            >
-              重置
-            </Button>
-            <Button
-              type="primary"
-              icon={<Plus />}
-              onClick={() => openForm('create')}
-            >
-              新增
-            </Button>
-            <Button
-              danger
-              icon={<Trash2 className="w-4 h-4" />}
-              disabled={selectedRowKeys.length === 0}
-              onClick={() => handleDelete()}
-            >
-              批量删除
-            </Button>
+            <PermissionWrapper permission="iscs:point:query">
+              <Button
+                type="primary"
+                icon={<Search />}
+                onClick={handleQuery}
+              >
+                搜索
+              </Button>
+            </PermissionWrapper>
+            <PermissionWrapper permission="iscs:point:query">
+              <Button
+                icon={<RefreshCw />}
+                onClick={resetQuery}
+              >
+                重置
+              </Button>
+            </PermissionWrapper>
+            <PermissionWrapper permission="iscs:point:create">
+              <Button
+                type="primary"
+                icon={<Plus />}
+                onClick={() => openForm('create')}
+              >
+                新增
+              </Button>
+            </PermissionWrapper>
+            <PermissionWrapper permission="iscs:point:delete">
+              <Button
+                danger
+                icon={<Trash2 className="w-4 h-4" />}
+                disabled={selectedRowKeys.length === 0}
+                onClick={() => handleDelete()}
+              >
+                批量删除
+              </Button>
+            </PermissionWrapper>
           </Space>
         </div>
       </div>

+ 82 - 53
src/components/UserManagement.tsx

@@ -15,6 +15,8 @@ import UserImportForm, { UserImportFormRef } from './user/UserImportForm';
 import UserAssignRoleForm, { UserAssignRoleFormRef } from './user/UserAssignRoleForm';
 import FaceOrFingerForm, { FaceOrFingerFormRef } from './user/FaceOrFingerForm';
 import { useTranslation } from 'react-i18next';
+import PermissionWrapper from './PermissionWrapper';
+import { hasPermission } from '../utils/permission';
 
 interface UserManagementProps {
   subMenu: string;
@@ -384,27 +386,43 @@ export default function UserManagement({ subMenu }: UserManagementProps) {
           },
         ];
 
+        const filteredMenuItems = menuItems.filter(item => {
+          if (item.key === 'delete') {
+            return hasPermission('system:user:delete');
+          }
+          if (item.key === 'resetPwd') {
+            return hasPermission('system:user:update-password');
+          }
+          if (item.key === 'assignRole') {
+            return hasPermission('system:permission:assign-user-role');
+          }
+          return true;
+        });
+
         return (
           <div className="flex items-center gap-2 justify-center">
-            <UIButton
-              variant="ghost"
-              size="sm"
-              onClick={() => openForm('update', record.id)}
-              className="h-8 px-2"
-            >
-              <Edit2 className="w-4 h-4" />
-              <span className="ml-1">编辑</span>
-            </UIButton>
-            <Dropdown
-              menu={{ items: menuItems }}
-              trigger={['hover']}
-              getPopupContainer={() => document.body}
-              placement="bottomRight"
-              popupStyle={{ zIndex: 1050 }}
-              mouseEnterDelay={0.1}
-              mouseLeaveDelay={0.1}
-            >
-              <a
+            <PermissionWrapper permission="system:user:update">
+              <UIButton
+                variant="ghost"
+                size="sm"
+                onClick={() => openForm('update', record.id)}
+                className="h-8 px-2"
+              >
+                <Edit2 className="w-4 h-4" />
+                <span className="ml-1">编辑</span>
+              </UIButton>
+            </PermissionWrapper>
+            {filteredMenuItems.length > 0 && (
+              <Dropdown
+                menu={{ items: filteredMenuItems }}
+                trigger={['hover']}
+                getPopupContainer={() => document.body}
+                placement="bottomRight"
+                popupStyle={{ zIndex: 1050 }}
+                mouseEnterDelay={0.1}
+                mouseLeaveDelay={0.1}
+              >
+                <a
                 onClick={(e) => {
                   e.stopPropagation();
                 }}
@@ -421,7 +439,8 @@ export default function UserManagement({ subMenu }: UserManagementProps) {
                 <MoreVertical className="w-4 h-4" />
                 <span>更多</span>
               </a>
-            </Dropdown>
+              </Dropdown>
+            )}
           </div>
         );
       },
@@ -471,43 +490,53 @@ export default function UserManagement({ subMenu }: UserManagementProps) {
 
               {/* 操作按钮组 */}
               <Space className="flex-shrink-0">
-                <Button
-                  type="primary"
-                  icon={<Search className="w-4 h-4" />}
-                  onClick={handleQuery}
-                >
-                  搜索
-                </Button>
+                <PermissionWrapper permission="system:user:query">
+                  <Button
+                    type="primary"
+                    icon={<Search className="w-4 h-4" />}
+                    onClick={handleQuery}
+                  >
+                    搜索
+                  </Button>
+                </PermissionWrapper>
                 
-                <Button
-                  icon={<RefreshCw className="w-4 h-4" />}
-                  onClick={resetQuery}
-                >
-                  重置
-                </Button>
+                <PermissionWrapper permission="system:user:query">
+                  <Button
+                    icon={<RefreshCw className="w-4 h-4" />}
+                    onClick={resetQuery}
+                  >
+                    重置
+                  </Button>
+                </PermissionWrapper>
                 
-                <Button
-                  type="primary"
-                  icon={<Plus className="w-4 h-4" />}
-                  onClick={() => openForm('create')}
-                >
-                  新增
-                </Button>
+                <PermissionWrapper permission="system:user:create">
+                  <Button
+                    type="primary"
+                    icon={<Plus className="w-4 h-4" />}
+                    onClick={() => openForm('create')}
+                  >
+                    新增
+                  </Button>
+                </PermissionWrapper>
                 
-                <Button
-                  icon={<Upload className="w-4 h-4" />}
-                  onClick={handleImport}
-                >
-                  导入
-                </Button>
+                <PermissionWrapper permission="system:user:create">
+                  <Button
+                    icon={<Upload className="w-4 h-4" />}
+                    onClick={handleImport}
+                  >
+                    导入
+                  </Button>
+                </PermissionWrapper>
                 
-                <Button
-                  icon={<Download className="w-4 h-4" />}
-                  onClick={handleExport}
-                  loading={exportLoading}
-                >
-                  导出
-                </Button>
+                <PermissionWrapper permission="system:user:export">
+                  <Button
+                    icon={<Download className="w-4 h-4" />}
+                    onClick={handleExport}
+                    loading={exportLoading}
+                  >
+                    导出
+                  </Button>
+                </PermissionWrapper>
               </Space>
             </div>
           </div>

+ 70 - 55
src/components/lockCabinet/SystemLockCabinetManagement.tsx

@@ -11,6 +11,7 @@ import type { ColumnsType } from 'antd/es/table';
 import LockCabinetForm, { LockCabinetFormRef } from './LockCabinetForm';
 import { ImageWithFallback } from '../figma/ImageWithFallback';
 import { useNavigate } from 'react-router-dom';
+import PermissionWrapper from '../PermissionWrapper';
 
 export default function SystemLockCabinetManagement() {
   const navigate = useNavigate();
@@ -241,37 +242,45 @@ export default function SystemLockCabinetManagement() {
 
           {/* 操作按钮组 */}
           <Space className="flex-shrink-0">
-            <AntButton
-              type="primary"
-              icon={<SearchOutlined />}
-              onClick={handleQuery}
-            >
-              搜索
-            </AntButton>
+            <PermissionWrapper permission="iscs:lock-cabinet:query">
+              <AntButton
+                type="primary"
+                icon={<SearchOutlined />}
+                onClick={handleQuery}
+              >
+                搜索
+              </AntButton>
+            </PermissionWrapper>
             
-            <AntButton
-              icon={<ReloadOutlined />}
-              onClick={resetQuery}
-            >
-              重置
-            </AntButton>
+            <PermissionWrapper permission="iscs:lock-cabinet:query">
+              <AntButton
+                icon={<ReloadOutlined />}
+                onClick={resetQuery}
+              >
+                重置
+              </AntButton>
+            </PermissionWrapper>
 
-            <AntButton
-              type="primary"
-              icon={<PlusOutlined />}
-              onClick={() => openForm('create')}
-            >
-              新增
-            </AntButton>
+            <PermissionWrapper permission="iscs:lock-cabinet:create">
+              <AntButton
+                type="primary"
+                icon={<PlusOutlined />}
+                onClick={() => openForm('create')}
+              >
+                新增
+              </AntButton>
+            </PermissionWrapper>
 
-            <AntButton
-              danger
-              icon={<DeleteOutlined />}
-              onClick={handleDelete}
-              disabled={selectedIds.length === 0}
-            >
-              批量删除
-            </AntButton>
+            <PermissionWrapper permission="iscs:lock-cabinet:delete">
+              <AntButton
+                danger
+                icon={<DeleteOutlined />}
+                onClick={handleDelete}
+                disabled={selectedIds.length === 0}
+              >
+                批量删除
+              </AntButton>
+            </PermissionWrapper>
           </Space>
         </div>
       </div>
@@ -394,15 +403,17 @@ export default function SystemLockCabinetManagement() {
               width: 80,
               align: 'center',
               render: (_: any, record: LockCabinetVO) => (
-                <Button 
-                  variant="ghost"
-                  size="sm"
-                  onClick={() => lookDetail(record)}
-                  className="h-8 px-2"
-                >
-                  <Eye className="w-4 h-4" />
-                  <span className="ml-1">查看</span>
-                </Button>
+                <PermissionWrapper permission="iscs:lock-cabinet:query">
+                  <Button 
+                    variant="ghost"
+                    size="sm"
+                    onClick={() => lookDetail(record)}
+                    className="h-8 px-2"
+                  >
+                    <Eye className="w-4 h-4" />
+                    <span className="ml-1">查看</span>
+                  </Button>
+                </PermissionWrapper>
               ),
             },
             {
@@ -412,24 +423,28 @@ export default function SystemLockCabinetManagement() {
               align: 'center',
               render: (_: any, record: LockCabinetVO) => (
                 <div className="flex items-center gap-2 justify-center">
-                  <Button
-                    variant="ghost"
-                    size="sm"
-                    onClick={() => openForm('update', record.cabinetId || (record as any).id)}
-                    className="h-8 px-2"
-                  >
-                    <Edit2 className="w-4 h-4" />
-                    <span className="ml-1">编辑</span>
-                  </Button>
-                  <Button
-                    variant="ghost"
-                    size="sm"
-                    onClick={() => handleDelete(record.cabinetId || (record as any).id)}
-                    className="h-8 px-2 text-red-600 hover:text-red-700"
-                  >
-                    <Trash2 className="w-4 h-4" />
-                    <span className="ml-1">删除</span>
-                  </Button>
+                  <PermissionWrapper permission="iscs:lock-cabinet:update">
+                    <Button
+                      variant="ghost"
+                      size="sm"
+                      onClick={() => openForm('update', record.cabinetId || (record as any).id)}
+                      className="h-8 px-2"
+                    >
+                      <Edit2 className="w-4 h-4" />
+                      <span className="ml-1">编辑</span>
+                    </Button>
+                  </PermissionWrapper>
+                  <PermissionWrapper permission="iscs:lock-cabinet:delete">
+                    <Button
+                      variant="ghost"
+                      size="sm"
+                      onClick={() => handleDelete(record.cabinetId || (record as any).id)}
+                      className="h-8 px-2 text-red-600 hover:text-red-700"
+                    >
+                      <Trash2 className="w-4 h-4" />
+                      <span className="ml-1">删除</span>
+                    </Button>
+                  </PermissionWrapper>
                 </div>
               ),
             },

+ 4 - 3
vite.config.ts

@@ -55,14 +55,15 @@
     },
     build: {
       target: 'esnext',
-      outDir: 'build',
+      outDir: 'dist-v1.0',
     },
     server: {
-      port: Number(env.VITE_PORT) || 3000,
+      host: '0.0.0.0', // 允许外部访问
+      port: Number(env.VITE_PORT) || 81,
       open: env.VITE_OPEN === 'true' || false,
       hmr: {
         // 配置 HMR WebSocket 连接,使用与服务器相同的端口
-        clientPort: Number(env.VITE_PORT) || 3000,
+        clientPort: Number(env.VITE_PORT) || 81,
         // 如果连接失败,不显示错误(静默失败)
         overlay: false,
       },

Деякі файли не було показано, через те що забагато файлів було змінено