Bladeren bron

修复部分字典 角色 岗位 部门等页面接口错误和弹框底部英文

pm 5 maanden geleden
bovenliggende
commit
b8d2bd777d

+ 84 - 39
src/Dashboard.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useMemo, useEffect } from 'react';
+import React, { useState, useMemo, useEffect, useRef } from 'react';
 import { useNavigate, useLocation } 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, Briefcase, MessageSquare, FileText, FolderTree, KeyRound, HardDrive, Database, Network, Workflow, ClipboardList, Wrench, Archive, Package, Box, Grid3x3, List, LayoutGrid, FolderOpen, FileCheck, FileEdit, FileSearch } from 'lucide-react';
@@ -653,25 +653,25 @@ export default function Dashboard() {
     <div className="h-screen flex flex-col bg-gradient-to-br from-gray-50 via-blue-50/30 to-gray-50 overflow-hidden">
       {/* 顶部导航栏 */}
       <nav className="bg-white/80 backdrop-blur-xl border-b border-gray-200/50 flex-shrink-0 z-50 shadow-sm">
-        <div className="px-6 py-4">
-          <div className="flex items-center justify-between">
+        <div className="px-6 py-4 min-w-0">
+          <div className="flex items-center justify-between gap-4 min-w-0">
             {/* Logo区域 */}
-            <div className="flex items-center gap-8">
-              <div className="flex items-center gap-3">
-                <div className="relative">
+            <div className="flex items-center gap-4 lg:gap-8 flex-shrink-0 min-w-0">
+              <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
+                <div className="relative flex-shrink-0">
                   <div className="w-11 h-11 rounded-xl flex items-center justify-center shadow-lg shadow-blue-400/40" style={{ background: 'linear-gradient(135deg, #4d79f8 0%, #6b8ffb 100%)' }}>
                     <Shield className="w-6 h-6 text-white" strokeWidth={2.5} />
                   </div>
                   <div className="absolute -top-0.5 -right-0.5 w-3 h-3 bg-green-400 rounded-full border-2 border-white"></div>
                 </div>
-                <div>
-                  <h1 className="text-lg text-gray-900">{env.appTitle}</h1>
-                  <p className="text-xs text-gray-500">{t('login.subtitle')}</p>
+                <div className="min-w-0">
+                  <h1 className="text-lg text-gray-900 truncate">{env.appTitle}</h1>
+                  <p className="text-xs text-gray-500 truncate">{t('login.subtitle')}</p>
                 </div>
               </div>
 
               {/* 主菜单 */}
-              <div className="hidden lg:flex items-center gap-2 ml-4">
+              <div className="hidden lg:flex items-center gap-2 ml-2 lg:ml-4 flex-shrink min-w-0">
                 {filteredMainMenus.map((item) => {
                   const Icon = item.icon;
                   const isActive = activeMenu === item.key;
@@ -679,34 +679,79 @@ export default function Dashboard() {
                   // 只有系统配置显示下拉菜单,其他菜单的二级菜单在页面内用 tab 标签显示
                   if (item.key === 'systemConfig' && filteredSubMenuConfig[item.key] && filteredSubMenuConfig[item.key].length > 0) {
                     const isDropdownOpen = showDropdownMenu === item.key;
+                    const buttonRef = useRef<HTMLButtonElement>(null);
+                    const [dropdownPosition, setDropdownPosition] = useState<{ top: number; left: number } | null>(null);
+                    
+                    // 计算下拉菜单位置
+                    useEffect(() => {
+                      if (isDropdownOpen && buttonRef.current) {
+                        const updatePosition = () => {
+                          if (buttonRef.current) {
+                            const rect = buttonRef.current.getBoundingClientRect();
+                            setDropdownPosition({
+                              top: rect.bottom + 8,
+                              left: rect.left,
+                            });
+                          }
+                        };
+                        updatePosition();
+                        window.addEventListener('scroll', updatePosition, true);
+                        window.addEventListener('resize', updatePosition);
+                        return () => {
+                          window.removeEventListener('scroll', updatePosition, true);
+                          window.removeEventListener('resize', updatePosition);
+                        };
+                      } else {
+                        setDropdownPosition(null);
+                      }
+                    }, [isDropdownOpen]);
+                    
                     return (
-                      <div
-                        key={item.key}
-                        className="relative"
-                        onMouseEnter={() => {
-                          if (dropdownTimer) clearTimeout(dropdownTimer);
-                          setShowDropdownMenu(item.key);
-                        }}
-                        onMouseLeave={() => {
-                          const timer = setTimeout(() => setShowDropdownMenu(null), 200);
-                          setDropdownTimer(timer);
-                        }}
-                      >
-                        <button
-                          className={`flex items-center gap-2 px-4 py-2.5 rounded-xl transition-all duration-300 ${
-                            isActive
-                              ? 'bg-gradient-to-r from-blue-500 to-blue-600 text-white shadow-lg shadow-blue-400/40'
-                              : 'text-gray-600 hover:bg-blue-50 hover:text-blue-600'
-                          }`}
+                      <>
+                        <div
+                          key={item.key}
+                          className="relative"
+                          onMouseEnter={() => {
+                            if (dropdownTimer) clearTimeout(dropdownTimer);
+                            setShowDropdownMenu(item.key);
+                          }}
+                          onMouseLeave={() => {
+                            const timer = setTimeout(() => setShowDropdownMenu(null), 200);
+                            setDropdownTimer(timer);
+                          }}
                         >
-                          <Icon className={`w-4 h-4 ${isActive ? 'text-white' : ''}`} strokeWidth={2.5} />
-                          <span className={`text-sm ${isActive ? 'text-white' : ''}`}>{item.name || t(`nav.${item.key}`)}</span>
-                          <ChevronDown className={`w-3 h-3 transition-transform ${isDropdownOpen ? 'rotate-180' : ''} ${isActive ? 'text-white' : ''}`} />
-                        </button>
+                          <button
+                            ref={buttonRef}
+                            className={`flex items-center gap-2 px-4 py-2.5 rounded-xl transition-all duration-300 ${
+                              isActive
+                                ? 'bg-gradient-to-r from-blue-500 to-blue-600 text-white shadow-lg shadow-blue-400/40'
+                                : 'text-gray-600 hover:bg-blue-50 hover:text-blue-600'
+                            }`}
+                          >
+                            <Icon className={`w-4 h-4 ${isActive ? 'text-white' : ''}`} strokeWidth={2.5} />
+                            <span className={`text-sm ${isActive ? 'text-white' : ''}`}>{item.name || t(`nav.${item.key}`)}</span>
+                            <ChevronDown className={`w-3 h-3 transition-transform ${isDropdownOpen ? 'rotate-180' : ''} ${isActive ? 'text-white' : ''}`} />
+                          </button>
+                        </div>
                         
-                        {/* 下拉菜单 - 网格布局 */}
-                        {isDropdownOpen && (
-                          <div className="absolute top-full left-0 mt-2 w-[340px] 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-50">
+                        {/* 下拉菜单 - 使用 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="grid grid-cols-2 gap-2">
                               {(filteredSubMenuConfig[item.key] || []).map((subItem) => {
                                 const IconComponent = subItem.icon;
@@ -742,7 +787,7 @@ export default function Dashboard() {
                             </div>
                           </div>
                         )}
-                      </div>
+                      </>
                     );
                   }
                   
@@ -773,7 +818,7 @@ export default function Dashboard() {
             </div>
 
             {/* 右侧功能区 */}
-            <div className="flex items-center gap-4">
+            <div className="flex items-center gap-2 lg:gap-4 flex-shrink-0">
               {/* 语言切换 */}
               <button
                 onClick={toggleLanguage}
@@ -879,7 +924,7 @@ export default function Dashboard() {
            filteredSubMenuConfig[activeMenu]?.length > 1 && 
            activeMenu !== 'systemConfig' && (
             <div className="bg-white rounded-2xl border border-gray-200/50 shadow-sm p-2 mb-6">
-              <div className="flex items-center gap-2 overflow-x-auto">
+              <div className="flex items-center gap-2 overflow-x-auto min-w-0">
                 {filteredSubMenuConfig[activeMenu]?.map((item) => {
                   const isActive = activeSubMenu === item.key;
                   const menuKey = activeMenu === 'userManagement' ? 'userManagement' : 
@@ -890,7 +935,7 @@ export default function Dashboard() {
                     <button
                       key={item.key}
                       onClick={() => setActiveSubMenu(item.key)}
-                      className={`px-4 py-2.5 rounded-xl text-sm transition-all duration-200 whitespace-nowrap ${
+                      className={`px-3 lg:px-4 py-2 lg:py-2.5 rounded-xl text-xs lg:text-sm transition-all duration-200 whitespace-nowrap flex-shrink-0 ${
                         isActive
                           ? 'bg-gradient-to-r from-blue-500 to-blue-600 text-white shadow-lg shadow-blue-400/40'
                           : 'text-gray-700 hover:bg-blue-50 hover:text-blue-600'

+ 8 - 8
src/api/DictData.ts

@@ -1,4 +1,4 @@
-import request from '../utils/axios';
+import axiosInstance from '../utils/axios';
 
 // 分页参数类型
 export interface PageParam {
@@ -24,37 +24,37 @@ export type DictDataVO = {
 export const dictDataApi = {
   // 查询字典数据(精简)列表
   getSimpleDictDataList: async () => {
-    return await request.get({ url: '/system/dict-data/simple-list' });
+    return await axiosInstance.get('/system/dict-data/simple-list');
   },
 
   // 查询字典数据列表
   getDictDataPage: async (params?: PageParam) => {
-    return await request.get({ url: '/system/dict-data/page', params });
+    return await axiosInstance.get('/system/dict-data/page', { params });
   },
 
   // 查询字典数据详情
   getDictData: async (id: number) => {
-    return await request.get({ url: `/system/dict-data/get?id=${id}` });
+    return await axiosInstance.get(`/system/dict-data/get?id=${id}`);
   },
 
   // 新增字典数据
   createDictData: async (data: DictDataVO) => {
-    return await request.post({ url: '/system/dict-data/create', data });
+    return await axiosInstance.post('/system/dict-data/create', data);
   },
 
   // 修改字典数据
   updateDictData: async (data: DictDataVO) => {
-    return await request.put({ url: '/system/dict-data/update', data });
+    return await axiosInstance.put('/system/dict-data/update', data);
   },
 
   // 删除字典数据
   deleteDictData: async (id: number) => {
-    return await request.delete({ url: `/system/dict-data/delete?id=${id}` });
+    return await axiosInstance.delete(`/system/dict-data/delete?id=${id}`);
   },
 
   // 导出字典类型数据
   exportDictData: async (params?: PageParam) => {
-    return await request.download({ url: '/system/dict-data/export', params });
+    return await axiosInstance.get('/system/dict-data/export', { params, responseType: 'blob' });
   },
 };
 

+ 8 - 8
src/api/DictType.ts

@@ -1,4 +1,4 @@
-import { request } from '../utils/axios';
+import axiosInstance from '../utils/axios';
 
 // 分页参数类型
 export interface PageParam {
@@ -21,37 +21,37 @@ export type DictTypeVO = {
 export const dictTypeApi = {
   // 查询字典(精简)列表
   getSimpleDictTypeList: async () => {
-    return await request.get({ url: '/system/dict-type/list-all-simple' });
+    return await axiosInstance.get('/system/dict-type/list-all-simple');
   },
 
   // 查询字典列表
   getDictTypePage: async (params?: PageParam) => {
-    return await request.get({ url: '/system/dict-type/page', params });
+    return await axiosInstance.get('/system/dict-type/page', { params });
   },
 
   // 查询字典详情
   getDictType: async (id: number) => {
-    return await request.get({ url: `/system/dict-type/get?id=${id}` });
+    return await axiosInstance.get(`/system/dict-type/get?id=${id}`);
   },
 
   // 新增字典
   createDictType: async (data: DictTypeVO) => {
-    return await request.post({ url: '/system/dict-type/create', data });
+    return await axiosInstance.post('/system/dict-type/create', data);
   },
 
   // 修改字典
   updateDictType: async (data: DictTypeVO) => {
-    return await request.put({ url: '/system/dict-type/update', data });
+    return await axiosInstance.put('/system/dict-type/update', data);
   },
 
   // 删除字典
   deleteDictType: async (id: number) => {
-    return await request.delete({ url: `/system/dict-type/delete?id=${id}` });
+    return await axiosInstance.delete(`/system/dict-type/delete?id=${id}`);
   },
 
   // 导出字典类型
   exportDictType: async (params?: PageParam) => {
-    return await request.download({ url: '/system/dict-type/export', params });
+    return await axiosInstance.get('/system/dict-type/export', { params, responseType: 'blob' });
   },
 };
 

+ 1 - 1
src/api/Role.ts

@@ -84,7 +84,7 @@ export const roleApi = {
 
   // 获取角色菜单权限列表
   getRoleMenuList: (roleId: number) => {
-    return axiosInstance.get<number[]>(`/system/permission/get-role-menu-list?roleId=${roleId}`);
+    return axiosInstance.get<number[]>(`/system/permission/list-role-menus?roleId=${roleId}`);
   },
 
   // 分配角色菜单权限

+ 6 - 6
src/components/DepartmentManagement.tsx

@@ -239,25 +239,25 @@ export default function DepartmentManagement() {
   return (
     <div className="space-y-4">
       {/* 搜索栏 */}
-      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-5">
-        <div className="flex items-center justify-between gap-4 flex-wrap">
+      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-4 lg:p-5">
+        <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
           {/* 搜索输入框 */}
-          <div className="flex items-center gap-3 flex-wrap flex-1">
-            <div className="flex items-center gap-3">
+          <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">部门名称:</label>
               <Input
                 value={queryParams.name || ''}
                 onChange={(e) => setQueryParams(prev => ({ ...prev, name: e.target.value }))}
                 onPressEnter={handleQuery}
                 placeholder="请输入部门名称"
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 allowClear
               />
             </div>
           </div>
 
           {/* 操作按钮组 */}
-          <Space>
+          <Space className="flex-shrink-0">
             <AntButton
               type="primary"
               icon={<Search className="w-4 h-4" />}

+ 4 - 0
src/components/DictDataForm.tsx

@@ -4,6 +4,7 @@ import { toast } from 'sonner';
 import { Modal, Form, Input, Button, InputNumber, Radio, Select, Spin } from 'antd';
 import { CommonStatusEnum } from '../utils/constants';
 import { getIntDictOptions, DICT_TYPE } from '../utils/dict';
+import { useTranslation } from 'react-i18next';
 
 interface DictDataFormProps {
   onSuccess?: () => void;
@@ -14,6 +15,7 @@ export interface DictDataFormRef {
 }
 
 const DictDataForm = forwardRef<DictDataFormRef, DictDataFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [dialogTitle, setDialogTitle] = useState('');
   const [formType, setFormType] = useState<'create' | 'update'>('create');
@@ -130,6 +132,8 @@ const DictDataForm = forwardRef<DictDataFormRef, DictDataFormProps>(({ onSuccess
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={700}
       destroyOnClose
     >

+ 4 - 0
src/components/DictTypeForm.tsx

@@ -4,6 +4,7 @@ import { toast } from 'sonner';
 import { Modal, Form, Input, Button, Radio, Spin } from 'antd';
 import { CommonStatusEnum } from '../utils/constants';
 import { getIntDictOptions, DICT_TYPE } from '../utils/dict';
+import { useTranslation } from 'react-i18next';
 
 interface DictTypeFormProps {
   onSuccess?: () => void;
@@ -14,6 +15,7 @@ export interface DictTypeFormRef {
 }
 
 const DictTypeForm = forwardRef<DictTypeFormRef, DictTypeFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [dialogTitle, setDialogTitle] = useState('');
   const [formType, setFormType] = useState<'create' | 'update'>('create');
@@ -107,6 +109,8 @@ const DictTypeForm = forwardRef<DictTypeFormRef, DictTypeFormProps>(({ onSuccess
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={600}
       destroyOnClose
     >

+ 41 - 23
src/components/DictTypeManagement.tsx

@@ -5,7 +5,7 @@ import { dictDataApi, DictDataVO, PageParam as DictDataPageParam } from '../api/
 import { toast } from 'sonner';
 import { formatDateTimeFull } from '../utils/formatTime';
 import { getIntDictOptions, DICT_TYPE, getDictLabel } from '../utils/dict';
-import { Modal, Tag, Space, Table, Button, Input, Pagination } from 'antd';
+import { Modal, Tag, Space, Table, Button, Input } from 'antd';
 import { ExclamationCircleOutlined } from '@ant-design/icons';
 import { Button as UIButton } from './ui/button';
 import { Table as UITable, TableBody, TableCell, TableHead, TableHeader, TableRow } from './ui/table';
@@ -249,12 +249,16 @@ export default function DictTypeManagement() {
       dataIndex: 'label',
       key: 'label',
       align: 'center',
+      width: 120,
+      ellipsis: true,
     },
     {
       title: '字典键值',
       dataIndex: 'value',
       key: 'value',
       align: 'center',
+      width: 120,
+      ellipsis: true,
     },
     {
       title: '字典排序',
@@ -278,7 +282,7 @@ export default function DictTypeManagement() {
       dataIndex: 'colorType',
       key: 'colorType',
       align: 'center',
-      width: 120,
+      width: 100,
       render: (colorType: string) => getColorTypeTag(colorType),
     },
     {
@@ -286,6 +290,7 @@ export default function DictTypeManagement() {
       dataIndex: 'remark',
       key: 'remark',
       align: 'center',
+      width: 150,
       ellipsis: true,
     },
     {
@@ -322,36 +327,36 @@ export default function DictTypeManagement() {
   return (
     <div className="space-y-4">
       {/* 搜索栏 */}
-      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-5">
-        <div className="flex items-center justify-between gap-4 flex-wrap">
+      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-4 lg:p-5">
+        <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
           {/* 搜索输入框 */}
-          <div className="flex items-center gap-3 flex-wrap flex-1">
-            <div className="flex items-center gap-3">
+          <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">字典名称:</label>
               <Input
                 value={queryParams.name || ''}
                 onChange={(e) => setQueryParams(prev => ({ ...prev, name: e.target.value }))}
                 onPressEnter={handleQuery}
                 placeholder="请输入字典名称"
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 allowClear
               />
             </div>
-            <div className="flex items-center gap-3">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">字典类型:</label>
               <Input
                 value={queryParams.type || ''}
                 onChange={(e) => setQueryParams(prev => ({ ...prev, type: e.target.value }))}
                 onPressEnter={handleQuery}
                 placeholder="请输入字典类型"
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 allowClear
               />
             </div>
           </div>
 
           {/* 操作按钮组 */}
-          <Space>
+          <Space className="flex-shrink-0">
             <Button
               type="primary"
               icon={<Search className="w-4 h-4" />}
@@ -501,7 +506,7 @@ export default function DictTypeManagement() {
         open={modalVisible}
         onCancel={() => setModalVisible(false)}
         footer={null}
-        width={1200}
+        width={1400}
         destroyOnClose
       >
         <div className="space-y-4">
@@ -532,21 +537,34 @@ export default function DictTypeManagement() {
             loading={dictDataLoading}
             pagination={false}
             size="small"
-            scroll={{ x: 1200 }}
+            scroll={{ x: 1400 }}
           />
 
           {/* 分页 */}
-          {dictDataTotal > 0 && (
-            <div className="flex justify-end">
-              <Pagination
-                current={dictDataPageParams.pageNo}
-                pageSize={dictDataPageParams.pageSize}
-                total={dictDataTotal}
-                onChange={handleDictDataPageChange}
-                showSizeChanger
-                showQuickJumper
-                showTotal={(total) => `共 ${total} 条记录`}
-              />
+          {!dictDataLoading && dictDataTotal > 0 && (
+            <div className="bg-white rounded-lg border border-gray-200 px-6 py-4">
+              <div className="flex items-center justify-between">
+                <div className="text-sm text-gray-600">
+                  共 <span className="text-blue-600 font-medium">{dictDataTotal}</span> 条记录
+                </div>
+                <div className="flex gap-2">
+                  <Button
+                    onClick={() => handleDictDataPageChange(dictDataPageParams.pageNo! - 1, dictDataPageParams.pageSize!)}
+                    disabled={dictDataPageParams.pageNo! <= 1}
+                  >
+                    上一页
+                  </Button>
+                  <span className="px-4 py-2 text-sm text-gray-600 flex items-center">
+                    {dictDataPageParams.pageNo} / {Math.ceil(dictDataTotal / dictDataPageParams.pageSize!) || 1}
+                  </span>
+                  <Button
+                    onClick={() => handleDictDataPageChange(dictDataPageParams.pageNo! + 1, dictDataPageParams.pageSize!)}
+                    disabled={dictDataPageParams.pageNo! >= Math.ceil(dictDataTotal / dictDataPageParams.pageSize!)}
+                  >
+                    下一页
+                  </Button>
+                </div>
+              </div>
             </div>
           )}
         </div>

+ 11 - 9
src/components/KeyManagement.tsx

@@ -9,6 +9,7 @@ import type { ColumnsType } from 'antd/es/table';
 import { DICT_TYPE, getStrDictOptions } from '../utils/dict';
 import { dateFormatter } from '../utils/formatTime';
 import { Button as UIButton } from './ui/button';
+import { useTranslation } from 'react-i18next';
 
 interface KeyManagementProps {
   subMenu?: string;
@@ -229,25 +230,25 @@ export default function KeyManagement({ subMenu }: KeyManagementProps) {
       {/* 钥匙列表 - 搜索栏和表格放在一起 */}
       <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm overflow-hidden">
         {/* 搜索栏 */}
-        <div className="p-5 border-b border-gray-200">
-          <div className="flex items-center justify-between gap-4 flex-wrap">
+        <div className="p-4 lg:p-5 border-b border-gray-200">
+          <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
             {/* 搜索输入框 */}
-            <div className="flex items-center gap-3 flex-wrap flex-1">
-              <div className="flex items-center gap-3">
+            <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+              <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
                 <label className="text-sm font-medium text-gray-700 whitespace-nowrap">钥匙名称:</label>
                 <Input
                   value={queryParams.keyName || ''}
                   onChange={(e) => setQueryParams({ ...queryParams, keyName: e.target.value })}
                   onPressEnter={handleQuery}
                   placeholder="请输入钥匙名称"
-                  style={{ width: 192 }}
+                  className="min-w-[150px] max-w-[200px]"
                   allowClear
                 />
               </div>
             </div>
 
             {/* 操作按钮组 */}
-            <Space>
+            <Space className="flex-shrink-0">
               <Button
                 type="primary"
                 icon={<Search className="w-4 h-4" />}
@@ -284,7 +285,7 @@ export default function KeyManagement({ subMenu }: KeyManagementProps) {
         </div>
 
         {/* 表格 */}
-        <div>
+        <div className="min-w-0">
           <Table
             columns={keyColumns}
             dataSource={list}
@@ -353,6 +354,7 @@ interface KeyFormModalProps {
 }
 
 function KeyFormModal({ visible, editingKey, onCancel, onSave }: KeyFormModalProps) {
+  const { t } = useTranslation();
   const [form] = Form.useForm();
   const [formLoading, setFormLoading] = useState(false);
   const [hardwareOptions, setHardwareOptions] = useState<{ label: string; value: number }[]>([]);
@@ -435,8 +437,8 @@ function KeyFormModal({ visible, editingKey, onCancel, onSave }: KeyFormModalPro
       open={visible}
       onOk={handleSubmit}
       onCancel={onCancel}
-      okText="确定"
-      cancelText="取消"
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       confirmLoading={formLoading}
       width={600}
     >

+ 20 - 2
src/components/MenuForm.tsx

@@ -9,10 +9,11 @@ import {
   Phone, MapPin, Calendar, Clock, Star, Share2, 
   Download, Upload, RefreshCw, Eye, EyeOff, Home, 
   ShoppingBag, Package, Database, PieChart, BarChart3, 
-  Grid3x3, List, Link2, Key, Wrench, Monitor, Server
+  Grid3x3, List, Link2, Key, Wrench, Monitor, Server, Target
 } from 'lucide-react';
 import { Modal, Form, Input, Button, Radio, TreeSelect, Popover, Space, Spin } from 'antd';
 import { QuestionCircleOutlined } from '@ant-design/icons';
+import { useTranslation } from 'react-i18next';
 
 interface MenuNode extends Omit<MenuVO, 'id'>, Omit<TreeNode, 'id'> {
   id: number;
@@ -28,6 +29,7 @@ export interface MenuFormRef {
 }
 
 const MenuForm = forwardRef<MenuFormRef, MenuFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [dialogTitle, setDialogTitle] = useState('');
   const [formType, setFormType] = useState<'create' | 'update'>('create');
@@ -80,6 +82,9 @@ const MenuForm = forwardRef<MenuFormRef, MenuFormProps>(({ onSuccess }, ref) =>
     }
   }, [dialogVisible, pendingOpen]);
 
+  // 监听表单 icon 字段变化,确保 Input 能正确显示
+  const iconValue = Form.useWatch('icon', form);
+
   // 组件挂载时获取菜单树
   useEffect(() => {
     getTree();
@@ -233,6 +238,7 @@ const MenuForm = forwardRef<MenuFormRef, MenuFormProps>(({ onSuccess }, ref) =>
     { name: 'ep:monitor', label: '监控', icon: Monitor },
     { name: 'ep:server', label: '服务器', icon: Server },
     { name: 'ep:database', label: '数据库', icon: Database },
+    { name: 'ep:aim', label: '瞄准', icon: Target },
   ];
 
   // 将菜单树转换为 TreeSelect 需要的格式
@@ -256,6 +262,8 @@ const MenuForm = forwardRef<MenuFormRef, MenuFormProps>(({ onSuccess }, ref) =>
       }}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={600}
       destroyOnClose
     >
@@ -318,7 +326,13 @@ const MenuForm = forwardRef<MenuFormRef, MenuFormProps>(({ onSuccess }, ref) =>
               getFieldValue('type') !== MenuType.BUTTON ? (
                 <Form.Item label="菜单图标" name="icon">
                   <Space.Compact style={{ width: '100%' }}>
-                    <Input placeholder="请选择或输入图标名称(如:ep:document)" />
+                    <Input 
+                      placeholder="请选择或输入图标名称(如:ep:document)"
+                      value={iconValue || ''}
+                      onChange={(e) => {
+                        form.setFieldsValue({ icon: e.target.value });
+                      }}
+                    />
                     <Popover
                       content={
                         <div style={{ width: 400 }}>
@@ -340,8 +354,12 @@ const MenuForm = forwardRef<MenuFormRef, MenuFormProps>(({ onSuccess }, ref) =>
                                 <div
                                   key={iconItem.name}
                                   onClick={() => {
+                                    // 设置表单字段值,会自动更新 Input 框
                                     form.setFieldsValue({ icon: iconItem.name });
+                                    // 关闭 Popover
                                     setIconPickerOpen(false);
+                                    // 强制触发表单更新,确保 Input 框显示最新值
+                                    form.validateFields(['icon']).catch(() => {});
                                   }}
                                   style={{
                                     display: 'flex',

+ 6 - 6
src/components/MenuManagement.tsx

@@ -413,25 +413,25 @@ export default function MenuManagement() {
   return (
     <div className="space-y-4">
       {/* 搜索栏 */}
-      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-5">
-        <div className="flex items-center justify-between gap-4 flex-wrap">
+      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-4 lg:p-5">
+        <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
           {/* 搜索输入框 */}
-          <div className="flex items-center gap-3 flex-wrap flex-1">
-            <div className="flex items-center gap-3">
+          <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">菜单名称:</label>
               <Input
                 value={queryParams.name || ''}
                 onChange={(e) => setQueryParams(prev => ({ ...prev, name: e.target.value }))}
                 onPressEnter={handleQuery}
                 placeholder="请输入菜单名称"
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 allowClear
               />
             </div>
           </div>
 
           {/* 操作按钮组 */}
-          <Space>
+          <Space className="flex-shrink-0">
             <Button
               type="primary"
               icon={<Search className="w-4 h-4" />}

+ 18 - 15
src/components/PadLockManagement.tsx

@@ -12,6 +12,7 @@ import { DICT_TYPE, getStrDictOptions } from '../utils/dict';
 import { dateFormatter } from '../utils/formatTime';
 import UploadImg from './lockCabinet/UploadImg';
 import { Button as UIButton } from './ui/button';
+import { useTranslation } from 'react-i18next';
 
 interface PadLockManagementProps {
   subMenu?: string;
@@ -527,25 +528,25 @@ export default function PadLockManagement({ subMenu }: PadLockManagementProps) {
           {/* 挂锁列表 - 搜索栏和表格放在一起 */}
           <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm overflow-hidden">
             {/* 搜索栏 */}
-            <div className="p-5 border-b border-gray-200">
-              <div className="flex items-center justify-between gap-4 flex-wrap">
+            <div className="p-4 lg:p-5 border-b border-gray-200">
+              <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
               {/* 搜索输入框 */}
-              <div className="flex items-center gap-3 flex-wrap flex-1">
-                <div className="flex items-center gap-3">
+              <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+                <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
                   <label className="text-sm font-medium text-gray-700 whitespace-nowrap">挂锁名称:</label>
                   <Input
                     value={queryParams.lockName || ''}
                     onChange={(e) => setQueryParams({ ...queryParams, lockName: e.target.value })}
                     onPressEnter={handleQuery}
                     placeholder="请输入挂锁名称"
-                    style={{ width: 192 }}
+                    className="min-w-[150px] max-w-[200px]"
                     allowClear
                   />
                 </div>
               </div>
 
                 {/* 操作按钮组 */}
-                <Space>
+                <Space className="flex-shrink-0">
                   <Button
                     type="primary"
                     icon={<Search className="w-4 h-4" />}
@@ -589,7 +590,7 @@ export default function PadLockManagement({ subMenu }: PadLockManagementProps) {
             </div>
 
             {/* 表格 */}
-            <div>
+            <div className="min-w-0">
               <Table
                 columns={padLockColumns}
                 dataSource={list}
@@ -652,22 +653,22 @@ export default function PadLockManagement({ subMenu }: PadLockManagementProps) {
             <div className="p-5 border-b border-gray-200">
               <div className="flex items-center justify-between gap-4 flex-wrap">
                 {/* 搜索输入框 */}
-                <div className="flex items-center gap-3 flex-wrap flex-1">
-                  <div className="flex items-center gap-3">
+                <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+                  <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
                     <label className="text-sm font-medium text-gray-700 whitespace-nowrap">类型名称:</label>
                     <Input
                       value={typeQueryParams.lockTypeName || ''}
                       onChange={(e) => setTypeQueryParams({ ...typeQueryParams, lockTypeName: e.target.value })}
                       onPressEnter={handleTypeQuery}
                       placeholder="请输入类型名称"
-                      style={{ width: 192 }}
+                      className="min-w-[150px] max-w-[200px]"
                       allowClear
                     />
                   </div>
                 </div>
 
                 {/* 操作按钮组 */}
-                <Space>
+                <Space className="flex-shrink-0">
                   <Button
                     type="primary"
                     icon={<Search className="w-4 h-4" />}
@@ -758,6 +759,7 @@ interface TypeFormModalProps {
 }
 
 function TypeFormModal({ visible, editingType, parentTypeId, typeList, onCancel, onSave }: TypeFormModalProps) {
+  const { t } = useTranslation();
   const [form] = Form.useForm();
   const [formLoading, setFormLoading] = useState(false);
   const [typeTreeOptions, setTypeTreeOptions] = useState<any[]>([]);
@@ -842,8 +844,8 @@ function TypeFormModal({ visible, editingType, parentTypeId, typeList, onCancel,
       open={visible}
       onOk={handleSubmit}
       onCancel={onCancel}
-      okText="确定"
-      cancelText="取消"
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       confirmLoading={formLoading}
       width={600}
     >
@@ -922,6 +924,7 @@ interface PadLockFormModalProps {
 }
 
 function PadLockFormModal({ visible, editingPadLock, onCancel, onSave }: PadLockFormModalProps) {
+  const { t } = useTranslation();
   const [form] = Form.useForm();
   const [formLoading, setFormLoading] = useState(false);
   const [hardwareOptions, setHardwareOptions] = useState<{ label: string; value: number }[]>([]);
@@ -1038,8 +1041,8 @@ function PadLockFormModal({ visible, editingPadLock, onCancel, onSave }: PadLock
       open={visible}
       onOk={handleSubmit}
       onCancel={onCancel}
-      okText="确定"
-      cancelText="取消"
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       confirmLoading={formLoading}
       width={600}
     >

+ 4 - 0
src/components/PostForm.tsx

@@ -2,6 +2,7 @@ import React, { useState, useImperativeHandle, forwardRef } from 'react';
 import { postApi, PostVO, PostStatus } from '../api/Post';
 import { toast } from 'sonner';
 import { Modal, Form, Input, Button, Select, Spin } from 'antd';
+import { useTranslation } from 'react-i18next';
 
 interface PostFormProps {
   onSuccess?: () => void;
@@ -12,6 +13,7 @@ export interface PostFormRef {
 }
 
 const PostForm = forwardRef<PostFormRef, PostFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [dialogTitle, setDialogTitle] = useState('');
   const [formType, setFormType] = useState<'create' | 'update'>('create');
@@ -106,6 +108,8 @@ const PostForm = forwardRef<PostFormRef, PostFormProps>(({ onSuccess }, ref) =>
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={600}
       destroyOnClose
     >

+ 8 - 8
src/components/PostManagement.tsx

@@ -188,36 +188,36 @@ export default function PostManagement() {
   return (
     <div className="space-y-4">
       {/* 搜索栏 */}
-      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-5">
-        <div className="flex items-center justify-between gap-4 flex-wrap">
+      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-4 lg:p-5">
+        <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
           {/* 搜索输入框 */}
-          <div className="flex items-center gap-3 flex-wrap flex-1">
-            <div className="flex items-center gap-3">
+          <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">岗位名称:</label>
               <Input
                 value={queryParams.name || ''}
                 onChange={(e) => setQueryParams(prev => ({ ...prev, name: e.target.value }))}
                 onPressEnter={handleQuery}
                 placeholder="请输入岗位名称"
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 allowClear
               />
             </div>
-            <div className="flex items-center gap-3">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">岗位编码:</label>
               <Input
                 value={queryParams.code || ''}
                 onChange={(e) => setQueryParams(prev => ({ ...prev, code: e.target.value }))}
                 onPressEnter={handleQuery}
                 placeholder="请输入岗位编码"
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 allowClear
               />
             </div>
           </div>
 
           {/* 操作按钮组 */}
-          <Space>
+          <Space className="flex-shrink-0">
             <Button
               type="primary"
               icon={<Search className="w-4 h-4" />}

+ 4 - 0
src/components/RoleAssignMenuForm.tsx

@@ -5,6 +5,7 @@ import { toast } from 'sonner';
 import { Modal, Form, Tag, Card, Switch, Tree, Spin, Space } from 'antd';
 import { handleTree } from '../utils/tree';
 import type { DataNode } from 'antd/es/tree';
+import { useTranslation } from 'react-i18next';
 
 interface RoleAssignMenuFormProps {
   onSuccess?: () => void;
@@ -15,6 +16,7 @@ export interface RoleAssignMenuFormRef {
 }
 
 const RoleAssignMenuForm = forwardRef<RoleAssignMenuFormRef, RoleAssignMenuFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [formLoading, setFormLoading] = useState(false);
   const [formData, setFormData] = useState<{
@@ -190,6 +192,8 @@ const RoleAssignMenuForm = forwardRef<RoleAssignMenuFormRef, RoleAssignMenuFormP
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={800}
       destroyOnClose
     >

+ 53 - 10
src/components/RoleDataPermissionForm.tsx

@@ -1,12 +1,14 @@
 import React, { useState, useImperativeHandle, forwardRef, useEffect } from 'react';
 import { roleApi, RoleVO } from '../api/Role';
 import { deptApi, DeptVO } from '../api/dept';
+import { loginApi } from '../api/Login';
 import { toast } from 'sonner';
 import { Modal, Form, Tag, Card, Switch, Tree, Spin, Select, Space } from 'antd';
 import { handleTree } from '../utils/tree';
-import { getIntDictOptions, DICT_TYPE } from '../utils/dict';
+import { getIntDictOptions, DICT_TYPE, setDictOptions } from '../utils/dict';
 import { SystemDataScopeEnum } from '../utils/constants';
 import type { DataNode } from 'antd/es/tree';
+import { useTranslation } from 'react-i18next';
 
 interface RoleDataPermissionFormProps {
   onSuccess?: () => void;
@@ -17,6 +19,7 @@ export interface RoleDataPermissionFormRef {
 }
 
 const RoleDataPermissionForm = forwardRef<RoleDataPermissionFormRef, RoleDataPermissionFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [formLoading, setFormLoading] = useState(false);
   const [formData, setFormData] = useState<{
@@ -39,6 +42,7 @@ const RoleDataPermissionForm = forwardRef<RoleDataPermissionFormRef, RoleDataPer
   const [treeNodeAll, setTreeNodeAll] = useState(false);
   const [checkStrictly, setCheckStrictly] = useState(true);
   const [form] = Form.useForm();
+  const [dataScopeOptions, setDataScopeOptions] = useState<Array<{ label: string; value: number }>>([]);
 
   // 将部门数据转换为 Tree 组件需要的格式
   const convertDeptToTreeData = (depts: DeptVO[]): DataNode[] => {
@@ -49,12 +53,56 @@ const RoleDataPermissionForm = forwardRef<RoleDataPermissionFormRef, RoleDataPer
     }));
   };
 
+  // 加载权限范围字典数据
+  const loadDataScopeOptions = async () => {
+    try {
+      // 先从缓存获取
+      const cachedOptions = getIntDictOptions('role_scope');
+      if (cachedOptions && cachedOptions.length > 0) {
+        setDataScopeOptions(cachedOptions.map(item => ({ label: item.label, value: item.value })));
+        return;
+      }
+
+      // 如果缓存中没有,从 API 获取
+      const dictDataList = await loginApi.getDictDataSimpleList();
+      const allDictData = (dictDataList as any)?.data || dictDataList || [];
+      
+      // 过滤出 role_scope 类型的字典数据
+      const roleScopeData = allDictData.filter((item: any) => item.dictType === 'role_scope');
+      
+      if (roleScopeData.length > 0) {
+        // 转换为字典格式并缓存
+        const dictOptions = roleScopeData.map((item: any) => ({
+          dictType: 'role_scope',
+          label: item.label,
+          value: parseInt(String(item.value)),
+          colorType: item.colorType || '',
+          cssClass: item.cssClass || '',
+        }));
+        setDictOptions('role_scope', dictOptions);
+        setDataScopeOptions(dictOptions.map(item => ({ label: item.label, value: item.value })));
+      } else {
+        // 如果 API 没有数据,使用默认选项
+        const defaultOptions = getIntDictOptions(DICT_TYPE.SYSTEM_DATA_SCOPE);
+        setDataScopeOptions(defaultOptions.map(item => ({ label: item.label, value: item.value })));
+      }
+    } catch (error: any) {
+      console.error('加载权限范围字典失败:', error);
+      // 如果加载失败,使用系统默认的数据权限范围
+      const defaultOptions = getIntDictOptions(DICT_TYPE.SYSTEM_DATA_SCOPE);
+      setDataScopeOptions(defaultOptions.map(item => ({ label: item.label, value: item.value })));
+    }
+  };
+
   // 暴露方法给父组件
   useImperativeHandle(ref, () => ({
     open: async (row: RoleVO) => {
       setDialogVisible(true);
       resetForm();
       
+      // 加载权限范围字典数据
+      await loadDataScopeOptions();
+      
       // 加载部门列表
       try {
         const depts = await deptApi.getSimpleDeptList();
@@ -178,8 +226,6 @@ const RoleDataPermissionForm = forwardRef<RoleDataPermissionFormRef, RoleDataPer
     }
   };
 
-  const dataScopeOptions = getIntDictOptions(DICT_TYPE.SYSTEM_DATA_SCOPE);
-
   return (
     <Modal
       title="数据权限"
@@ -187,6 +233,8 @@ const RoleDataPermissionForm = forwardRef<RoleDataPermissionFormRef, RoleDataPer
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={800}
       destroyOnClose
     >
@@ -213,13 +261,8 @@ const RoleDataPermissionForm = forwardRef<RoleDataPermissionFormRef, RoleDataPer
             <Select
               placeholder="请选择权限范围"
               onChange={handleDataScopeChange}
-            >
-              {dataScopeOptions.map((option) => (
-                <Select.Option key={option.value} value={option.value}>
-                  {option.label}
-                </Select.Option>
-              ))}
-            </Select>
+              options={dataScopeOptions}
+            />
           </Form.Item>
 
           {formData.dataScope === SystemDataScopeEnum.DEPT_CUSTOM && (

+ 4 - 0
src/components/RoleForm.tsx

@@ -4,6 +4,7 @@ import { toast } from 'sonner';
 import { Modal, Form, Input, Button, Select, Spin } from 'antd';
 import { CommonStatusEnum } from '../utils/constants';
 import { getIntDictOptions, DICT_TYPE } from '../utils/dict';
+import { useTranslation } from 'react-i18next';
 
 interface RoleFormProps {
   onSuccess?: () => void;
@@ -14,6 +15,7 @@ export interface RoleFormRef {
 }
 
 const RoleForm = forwardRef<RoleFormRef, RoleFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [dialogTitle, setDialogTitle] = useState('');
   const [formType, setFormType] = useState<'create' | 'update'>('create');
@@ -112,6 +114,8 @@ const RoleForm = forwardRef<RoleFormRef, RoleFormProps>(({ onSuccess }, ref) =>
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={600}
       destroyOnClose
     >

+ 8 - 8
src/components/RoleManagement.tsx

@@ -178,36 +178,36 @@ export default function RoleManagement() {
   return (
     <div className="space-y-4">
       {/* 搜索栏 */}
-      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-5">
-        <div className="flex items-center justify-between gap-4 flex-wrap">
+      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-4 lg:p-5">
+        <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
           {/* 搜索输入框 */}
-          <div className="flex items-center gap-3 flex-wrap flex-1">
-            <div className="flex items-center gap-3">
+          <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">角色名称:</label>
               <Input
                 value={queryParams.name || ''}
                 onChange={(e) => setQueryParams(prev => ({ ...prev, name: e.target.value }))}
                 onPressEnter={handleQuery}
                 placeholder="请输入角色名称"
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 allowClear
               />
             </div>
-            <div className="flex items-center gap-3">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">角色标识:</label>
               <Input
                 value={queryParams.code || ''}
                 onChange={(e) => setQueryParams(prev => ({ ...prev, code: e.target.value }))}
                 onPressEnter={handleQuery}
                 placeholder="请输入角色标识"
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 allowClear
               />
             </div>
           </div>
 
           {/* 操作按钮组 */}
-          <Space>
+          <Space className="flex-shrink-0">
             <Button
               type="primary"
               icon={<Search className="w-4 h-4" />}

+ 4 - 0
src/components/SegregationPointForm.tsx

@@ -9,6 +9,7 @@ import { loginApi } from '../api/Login';
 import { handleTree } from '../utils/tree';
 import { getStrDictOptions, DICT_TYPE } from '../utils/dict';
 import { toast } from 'sonner';
+import { useTranslation } from 'react-i18next';
 
 interface SegregationPointFormProps {
   onSuccess?: () => void;
@@ -20,6 +21,7 @@ export interface SegregationPointFormRef {
 
 const SegregationPointForm = forwardRef<SegregationPointFormRef, SegregationPointFormProps>(
   ({ onSuccess }, ref) => {
+    const { t } = useTranslation();
     const [dialogVisible, setDialogVisible] = useState(false);
     const [dialogTitle, setDialogTitle] = useState('');
     const [formLoading, setFormLoading] = useState(false);
@@ -227,6 +229,8 @@ const SegregationPointForm = forwardRef<SegregationPointFormRef, SegregationPoin
         onCancel={() => setDialogVisible(false)}
         onOk={submitForm}
         confirmLoading={formLoading}
+        okText={t('common.confirm')}
+        cancelText={t('common.cancel')}
         width={960}
         destroyOnClose
       >

+ 13 - 13
src/components/SegregationPointManagement.tsx

@@ -302,21 +302,21 @@ export default function SegregationPointManagement({ subMenu }: SegregationPoint
     <div className="p-6 space-y-4">
       {/* 搜索栏 */}
       <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-5">
-        <div className="flex items-center justify-between gap-4 flex-wrap">
+        <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
           {/* 搜索输入框 */}
-          <div className="flex items-center gap-3 flex-wrap flex-1">
-            <div className="flex items-center gap-3">
+          <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">隔离点名称:</label>
               <Input
                 value={queryParams.pointName}
                 onChange={(e) => setQueryParams({ ...queryParams, pointName: e.target.value })}
                 onPressEnter={handleQuery}
                 placeholder="请输入隔离点名称"
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 allowClear
               />
             </div>
-            <div className="flex items-center gap-3">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">岗位:</label>
               <TreeSelect
                 value={queryParams.workstationId}
@@ -324,10 +324,10 @@ export default function SegregationPointManagement({ subMenu }: SegregationPoint
                 treeData={deptOptions}
                 placeholder="选择岗位"
                 allowClear
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
               />
             </div>
-            <div className="flex items-center gap-3">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">设备/工艺:</label>
               <TreeSelect
                 value={queryParams.machineryId}
@@ -335,35 +335,35 @@ export default function SegregationPointManagement({ subMenu }: SegregationPoint
                 treeData={machineryOptions}
                 placeholder="选择设备/工艺"
                 allowClear
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
               />
             </div>
-            <div className="flex items-center gap-3">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">锁定站:</label>
               <Select
                 value={queryParams.lotoId}
                 onChange={(value) => setQueryParams({ ...queryParams, lotoId: value })}
                 placeholder="请选择锁定站"
                 allowClear
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 options={lotoOptions}
               />
             </div>
-            <div className="flex items-center gap-3">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
               <label className="text-sm font-medium text-gray-700 whitespace-nowrap">能量源:</label>
               <Select
                 value={queryParams.powerType}
                 onChange={(value) => setQueryParams({ ...queryParams, powerType: value })}
                 placeholder="请选择能量源"
                 allowClear
-                style={{ width: 192 }}
+                className="min-w-[150px] max-w-[200px]"
                 options={powerTypeOptions}
               />
             </div>
           </div>
 
           {/* 操作按钮组 */}
-          <Space>
+          <Space className="flex-shrink-0">
             <Button
               type="primary"
               icon={<Search />}

+ 13 - 11
src/components/UserManagement.tsx

@@ -14,12 +14,14 @@ import UserForm, { UserFormRef } from './user/UserForm';
 import UserImportForm, { UserImportFormRef } from './user/UserImportForm';
 import UserAssignRoleForm, { UserAssignRoleFormRef } from './user/UserAssignRoleForm';
 import FaceOrFingerForm, { FaceOrFingerFormRef } from './user/FaceOrFingerForm';
+import { useTranslation } from 'react-i18next';
 
 interface UserManagementProps {
   subMenu: string;
 }
 
 export default function UserManagement({ subMenu }: UserManagementProps) {
+  const { t } = useTranslation();
   const [loading, setLoading] = useState(true);
   const [list, setList] = useState<UserVO[]>([]);
   const [total, setTotal] = useState(0);
@@ -439,36 +441,36 @@ export default function UserManagement({ subMenu }: UserManagementProps) {
       <div className="flex-1 min-w-0">
         <div className="space-y-6">
           {/* 搜索栏 */}
-          <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-5">
-            <div className="flex items-center justify-between gap-4 flex-wrap">
+          <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-4 lg:p-5">
+            <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
               {/* 搜索输入框 */}
-              <div className="flex items-center gap-3 flex-wrap flex-1">
-                <div className="flex items-center gap-3">
+              <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+                <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
                   <label className="text-sm font-medium text-gray-700 whitespace-nowrap">账号:</label>
                   <Input
                     value={queryParams.username}
                     onChange={(e) => setQueryParams({ ...queryParams, username: e.target.value })}
                     onPressEnter={handleQuery}
                     placeholder="请输入账号"
-                    style={{ width: 192 }}
+                    className="min-w-[150px] max-w-[200px]"
                     allowClear
                   />
                 </div>
-                <div className="flex items-center gap-3">
+                <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
                   <label className="text-sm font-medium text-gray-700 whitespace-nowrap">手机号码:</label>
                   <Input
                     value={queryParams.mobile}
                     onChange={(e) => setQueryParams({ ...queryParams, mobile: e.target.value })}
                     onPressEnter={handleQuery}
                     placeholder="请输入手机号码"
-                    style={{ width: 192 }}
+                    className="min-w-[150px] max-w-[200px]"
                     allowClear
                   />
                 </div>
               </div>
 
               {/* 操作按钮组 */}
-              <Space>
+              <Space className="flex-shrink-0">
                 <Button
                   type="primary"
                   icon={<Search className="w-4 h-4" />}
@@ -511,7 +513,7 @@ export default function UserManagement({ subMenu }: UserManagementProps) {
           </div>
 
           {/* 表格容器 */}
-          <div className="bg-white rounded-2xl border border-gray-200/50 shadow-sm overflow-hidden">
+          <div className="bg-white rounded-2xl border border-gray-200/50 shadow-sm overflow-hidden min-w-0">
             <Table
               columns={columns}
               dataSource={list}
@@ -569,8 +571,8 @@ export default function UserManagement({ subMenu }: UserManagementProps) {
           setResetPwdUser(null);
         }}
         confirmLoading={resetPwdLoading}
-        okText="确定"
-        cancelText="取消"
+        okText={t('common.confirm')}
+        cancelText={t('common.cancel')}
         width={500}
       >
         <div style={{ marginTop: 16 }}>

+ 4 - 0
src/components/dept/DeptForm.tsx

@@ -7,6 +7,7 @@ import { toast } from 'sonner';
 import { DICT_TYPE, getIntDictOptions } from '../../utils/dict';
 import { CommonStatusEnum } from '../../utils/constants';
 import { handleTree, TreeNode } from '../../utils/tree';
+import { useTranslation } from 'react-i18next';
 
 interface DeptFormProps {
   onSuccess?: () => void;
@@ -17,6 +18,7 @@ export interface DeptFormRef {
 }
 
 const DeptForm = forwardRef<DeptFormRef, DeptFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [dialogTitle, setDialogTitle] = useState('');
   const [formLoading, setFormLoading] = useState(false);
@@ -150,6 +152,8 @@ const DeptForm = forwardRef<DeptFormRef, DeptFormProps>(({ onSuccess }, ref) =>
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={600}
       destroyOnClose
     >

+ 54 - 49
src/components/lockCabinet/HardwareLockCabinetManagement.tsx

@@ -153,59 +153,64 @@ export default function HardwareLockCabinetManagement() {
       <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm overflow-hidden">
         {/* 搜索栏 */}
         <div className="p-5 border-b border-gray-200">
-          <Space size="middle" wrap>
-            <div className="flex items-center gap-2">
-              <span className="text-sm font-medium text-gray-700 whitespace-nowrap">锁柜名称:</span>
-              <Input
-                placeholder="请输入锁柜名称"
-                value={queryParams.cabinetName || ''}
-                onChange={(e) => setQueryParams(prev => ({ ...prev, cabinetName: e.target.value }))}
-                onPressEnter={handleQuery}
-                style={{ width: 200 }}
-                allowClear
-              />
-            </div>
+          <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
+            {/* 搜索条件 */}
+            <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+              <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
+                <label className="text-sm font-medium text-gray-700 whitespace-nowrap">锁柜名称:</label>
+                <Input
+                  placeholder="请输入锁柜名称"
+                  value={queryParams.cabinetName || ''}
+                  onChange={(e) => setQueryParams(prev => ({ ...prev, cabinetName: e.target.value }))}
+                  onPressEnter={handleQuery}
+                  className="min-w-[150px] max-w-[200px]"
+                  allowClear
+                />
+              </div>
 
-            <div className="flex items-center gap-2">
-              <span className="text-sm font-medium text-gray-700 whitespace-nowrap">是否在线:</span>
-              <Select
-                placeholder="请选择是否在线"
-                value={queryParams.isOnline || undefined}
-                onChange={(value) => setQueryParams(prev => ({ ...prev, isOnline: value }))}
-                style={{ width: 200 }}
-                allowClear
-              >
-                {isOnlineOptions && isOnlineOptions.length > 0 ? (
-                  isOnlineOptions.map(option => (
-                    <Select.Option key={option.value} value={String(option.value)}>
-                      {option.label}
-                    </Select.Option>
-                  ))
-                ) : (
-                  <>
-                    <Select.Option value="0">离线</Select.Option>
-                    <Select.Option value="1">在线</Select.Option>
-                  </>
-                )}
-              </Select>
+              <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
+                <label className="text-sm font-medium text-gray-700 whitespace-nowrap">是否在线:</label>
+                <Select
+                  placeholder="请选择是否在线"
+                  value={queryParams.isOnline || undefined}
+                  onChange={(value) => setQueryParams(prev => ({ ...prev, isOnline: value }))}
+                  className="min-w-[150px] max-w-[200px]"
+                  allowClear
+                >
+                  {isOnlineOptions && isOnlineOptions.length > 0 ? (
+                    isOnlineOptions.map(option => (
+                      <Select.Option key={option.value} value={String(option.value)}>
+                        {option.label}
+                      </Select.Option>
+                    ))
+                  ) : (
+                    <>
+                      <Select.Option value="0">离线</Select.Option>
+                      <Select.Option value="1">在线</Select.Option>
+                    </>
+                  )}
+                </Select>
+              </div>
             </div>
 
             {/* 操作按钮组 */}
-            <AntButton
-              type="primary"
-              icon={<SearchOutlined />}
-              onClick={handleQuery}
-            >
-              搜索
-            </AntButton>
-            
-            <AntButton
-              icon={<ReloadOutlined />}
-              onClick={resetQuery}
-            >
-              重置
-            </AntButton>
-          </Space>
+            <Space className="flex-shrink-0">
+              <AntButton
+                type="primary"
+                icon={<SearchOutlined />}
+                onClick={handleQuery}
+              >
+                搜索
+              </AntButton>
+              
+              <AntButton
+                icon={<ReloadOutlined />}
+                onClick={resetQuery}
+              >
+                重置
+              </AntButton>
+            </Space>
+          </div>
         </div>
 
         {/* 表格 */}

+ 4 - 0
src/components/lockCabinet/LockCabinetForm.tsx

@@ -7,6 +7,7 @@ import { toast } from 'sonner';
 import { DICT_TYPE, getStrDictOptions } from '../../utils/dict';
 import { handleTree, TreeNode } from '../../utils/tree';
 import UploadImg from './UploadImg';
+import { useTranslation } from 'react-i18next';
 
 interface LockCabinetFormProps {
   onSuccess?: () => void;
@@ -17,6 +18,7 @@ export interface LockCabinetFormRef {
 }
 
 const LockCabinetForm = forwardRef<LockCabinetFormRef, LockCabinetFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [dialogTitle, setDialogTitle] = useState('');
   const [formLoading, setFormLoading] = useState(false);
@@ -193,6 +195,8 @@ const LockCabinetForm = forwardRef<LockCabinetFormRef, LockCabinetFormProps>(({
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={650}
       destroyOnHidden
     >

+ 3 - 3
src/components/lockCabinet/SlotsList.tsx

@@ -136,10 +136,10 @@ export default function SlotsList({ cabinetId }: SlotsListProps) {
       {/* 搜索栏 */}
       <div className="bg-white p-4 rounded-lg shadow-sm">
         <Space size="middle" wrap>
-          <div className="flex items-center gap-2">
+          <div className="flex items-center gap-2 flex-shrink-0">
             <span className="text-sm font-medium">仓位类型:</span>
             <Select
-              style={{ width: 200 }}
+              className="min-w-[150px] max-w-[200px]"
               placeholder="请选择仓位类型"
               allowClear
               value={queryParams.slotType}
@@ -155,7 +155,7 @@ export default function SlotsList({ cabinetId }: SlotsListProps) {
           {/* <div className="flex items-center gap-2">
             <span className="text-sm font-medium">状态:</span>
             <Select
-              style={{ width: 200 }}
+              className="min-w-[150px] max-w-[200px]"
               placeholder="请选择状态"
               allowClear
               value={queryParams.status}

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

@@ -198,77 +198,82 @@ export default function SystemLockCabinetManagement() {
   return (
     <div className="space-y-4">
       {/* 搜索栏 */}
-      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-5">
-        <Space size="middle" wrap>
-          <div className="flex items-center gap-2">
-            <span className="text-sm font-medium text-gray-700 whitespace-nowrap">锁柜名称:</span>
-            <Input
-              placeholder="请输入锁柜名称"
-              value={queryParams.cabinetName || ''}
-              onChange={(e) => setQueryParams(prev => ({ ...prev, cabinetName: e.target.value }))}
-              onPressEnter={handleQuery}
-              style={{ width: 200 }}
-              allowClear
-            />
-          </div>
+      <div className="bg-white rounded-xl border border-gray-200/50 shadow-sm p-4 lg:p-5">
+        <div className="flex items-center justify-between gap-3 lg:gap-4 flex-wrap min-w-0">
+          {/* 搜索条件 */}
+          <div className="flex items-center gap-2 lg:gap-3 flex-wrap flex-1 min-w-0">
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
+              <label className="text-sm font-medium text-gray-700 whitespace-nowrap">锁柜名称:</label>
+              <Input
+                placeholder="请输入锁柜名称"
+                value={queryParams.cabinetName || ''}
+                onChange={(e) => setQueryParams(prev => ({ ...prev, cabinetName: e.target.value }))}
+                onPressEnter={handleQuery}
+                className="min-w-[150px] max-w-[200px]"
+                allowClear
+              />
+            </div>
 
-          <div className="flex items-center gap-2">
-            <span className="text-sm font-medium text-gray-700 whitespace-nowrap">是否在线:</span>
-            <Select
-              placeholder="请选择是否在线"
-              value={queryParams.isOnline || undefined}
-              onChange={(value) => setQueryParams(prev => ({ ...prev, isOnline: value }))}
-              style={{ width: 200 }}
-              allowClear
-            >
-              {isOnlineOptions && isOnlineOptions.length > 0 ? (
-                isOnlineOptions.map(option => (
-                  <Select.Option key={option.value} value={String(option.value)}>
-                    {option.label}
-                  </Select.Option>
-                ))
-              ) : (
-                <>
-                  <Select.Option value="0">离线</Select.Option>
-                  <Select.Option value="1">在线</Select.Option>
-                </>
-              )}
-            </Select>
+            <div className="flex items-center gap-2 lg:gap-3 flex-shrink-0">
+              <label className="text-sm font-medium text-gray-700 whitespace-nowrap">是否在线:</label>
+              <Select
+                placeholder="请选择是否在线"
+                value={queryParams.isOnline || undefined}
+                onChange={(value) => setQueryParams(prev => ({ ...prev, isOnline: value }))}
+                className="min-w-[150px] max-w-[200px]"
+                allowClear
+              >
+                {isOnlineOptions && isOnlineOptions.length > 0 ? (
+                  isOnlineOptions.map(option => (
+                    <Select.Option key={option.value} value={String(option.value)}>
+                      {option.label}
+                    </Select.Option>
+                  ))
+                ) : (
+                  <>
+                    <Select.Option value="0">离线</Select.Option>
+                    <Select.Option value="1">在线</Select.Option>
+                  </>
+                )}
+              </Select>
+            </div>
           </div>
 
           {/* 操作按钮组 */}
-          <AntButton
-            type="primary"
-            icon={<SearchOutlined />}
-            onClick={handleQuery}
-          >
-            搜索
-          </AntButton>
-          
-          <AntButton
-            icon={<ReloadOutlined />}
-            onClick={resetQuery}
-          >
-            重置
-          </AntButton>
+          <Space className="flex-shrink-0">
+            <AntButton
+              type="primary"
+              icon={<SearchOutlined />}
+              onClick={handleQuery}
+            >
+              搜索
+            </AntButton>
+            
+            <AntButton
+              icon={<ReloadOutlined />}
+              onClick={resetQuery}
+            >
+              重置
+            </AntButton>
 
-          <AntButton
-            type="primary"
-            icon={<PlusOutlined />}
-            onClick={() => openForm('create')}
-          >
-            新增
-          </AntButton>
+            <AntButton
+              type="primary"
+              icon={<PlusOutlined />}
+              onClick={() => openForm('create')}
+            >
+              新增
+            </AntButton>
 
-          <AntButton
-            danger
-            icon={<DeleteOutlined />}
-            onClick={handleDelete}
-            disabled={selectedIds.length === 0}
-          >
-            批量删除
-          </AntButton>
-        </Space>
+            <AntButton
+              danger
+              icon={<DeleteOutlined />}
+              onClick={handleDelete}
+              disabled={selectedIds.length === 0}
+            >
+              批量删除
+            </AntButton>
+          </Space>
+        </div>
       </div>
 
       {/* 表格 */}

+ 4 - 0
src/components/user/UserForm.tsx

@@ -6,6 +6,7 @@ import { postApi, PostVO } from '../../api/Post';
 import { UserVO, WorkstationNode } from '../../types';
 import { getIntDictOptions, DICT_TYPE } from '../../utils/dict';
 import { handleTree } from '../../utils/tree';
+import { useTranslation } from 'react-i18next';
 
 const { TextArea } = Input;
 
@@ -18,6 +19,7 @@ export interface UserFormRef {
 }
 
 const UserForm = forwardRef<UserFormRef, UserFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [dialogTitle, setDialogTitle] = useState('');
   const [formLoading, setFormLoading] = useState(false);
@@ -185,6 +187,8 @@ const UserForm = forwardRef<UserFormRef, UserFormProps>(({ onSuccess }, ref) =>
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={800}
       destroyOnClose
     >

+ 4 - 0
src/components/user/UserImportForm.tsx

@@ -4,6 +4,7 @@ import { InboxOutlined, DownloadOutlined } from '@ant-design/icons';
 import type { UploadFile, UploadProps } from 'antd';
 import { userImportApi } from '../../api/user/import';
 import { getAccessToken, getTenantId } from '../../utils/auth';
+import { useTranslation } from 'react-i18next';
 
 const { Dragger } = Upload;
 
@@ -16,6 +17,7 @@ export interface UserImportFormRef {
 }
 
 const UserImportForm = forwardRef<UserImportFormRef, UserImportFormProps>(({ onSuccess }, ref) => {
+  const { t } = useTranslation();
   const [dialogVisible, setDialogVisible] = useState(false);
   const [formLoading, setFormLoading] = useState(false);
   const [fileList, setFileList] = useState<UploadFile[]>([]);
@@ -130,6 +132,8 @@ const UserImportForm = forwardRef<UserImportFormRef, UserImportFormProps>(({ onS
       onCancel={() => setDialogVisible(false)}
       onOk={submitForm}
       confirmLoading={formLoading}
+      okText={t('common.confirm')}
+      cancelText={t('common.cancel')}
       width={400}
       destroyOnClose
     >