Преглед на файлове

把语言设置放到配置模块中;修改配置模块的二级模块的id信息,不使用短线,这样可以把首选项中的页面可以通过点击左侧导航按钮显示出来

dengdx преди 1 седмица
родител
ревизия
e18980951a

+ 2 - 2
src/pages/system/SettingsModal/SettingsContent.tsx

@@ -38,8 +38,8 @@ const SettingsContent: React.FC<SettingsContentProps> = ({
     navigation.activeSection
   );
 
-  // 移动端:显示二级分区列表
-  if (isMobile && currentCategory) {
+  // 移动端:仅在未选择section时显示二级分区列表
+  if (isMobile && currentCategory && !navigation.activeSection) {
     return (
       <div
         style={{

+ 3 - 3
src/pages/system/SettingsModal/SettingsModal.tsx

@@ -84,10 +84,10 @@ const SettingsModal: React.FC<SettingsModalProps> = ({
 
   // 分类切换处理(移动端专用)
   const handleCategoryChange = (categoryId: string) => {
-    setNavigation((prev) => ({
+    setNavigation({
       activeCategory: categoryId,
-      activeSection: prev.activeSection,
-    }));
+      activeSection: '', // 清空activeSection,切换回列表选择
+    });
   };
 
   // 关闭处理

+ 36 - 31
src/pages/system/SettingsModal/config.tsx

@@ -42,42 +42,42 @@ export const settingsConfig: SettingsCategory[] = [
     icon: <HomeOutlined />,
     sections: [
       {
-        id: 'site-info',
+        id: 'site_info',
         title: '站点信息',
         component: SystemHome.SiteInfo,
       },
       {
-        id: 'user-account',
+        id: 'user_account',
         title: '用户账户',
         component: SystemHome.UserAccount,
       },
       {
-        id: 'disk-space-management',
+        id: 'disk_space_management',
         title: '磁盘空间管理',
         component: SystemHome.DiskSpaceManagement,
       },
       {
-        id: 'doctor-technician',
+        id: 'doctor_technician',
         title: '医生和技师',
         component: SystemHome.DoctorTechnician,
       },
       {
-        id: 'backup-restore',
+        id: 'backup_restore',
         title: '备份与恢复',
         component: SystemHome.BackupRestore,
       },
       {
-        id: 'log-cleanup',
+        id: 'log_cleanup',
         title: '日志清理',
         component: SystemHome.LogCleanup,
       },
       {
-        id: 'info-security',
+        id: 'info_security',
         title: '信息安全',
         component: SystemHome.InfoSecurity,
       },
       {
-        id: 'software-license',
+        id: 'software_license',
         title: '软件许可',
         component: SystemHome.SoftwareLicense,
       },
@@ -89,12 +89,17 @@ export const settingsConfig: SettingsCategory[] = [
     icon: <SettingOutlined />,
     sections: [
       {
-        id: 'general-settings',
+        id: 'general_settings',
         title: '通用设置',
         component: Preferences.GeneralSettings,
       },
       {
-        id: 'workflow-inspection',
+        id: 'language_settings',
+        title: '语言设置',
+        component: Preferences.LanguageSettingsComponent,
+      },
+      {
+        id: 'workflow_inspection',
         title: '流程检査',
         component: Preferences.WorkflowInspection,
       },
@@ -104,17 +109,17 @@ export const settingsConfig: SettingsCategory[] = [
         component: Preferences.Workflow,
       },
       {
-        id: 'user-info',
+        id: 'user_info',
         title: '用户信息',
         component: Preferences.UserInfo,
       },
       {
-        id: 'add-remarks',
+        id: 'add_remarks',
         title: '添加备注',
         component: Preferences.AddRemarks,
       },
       {
-        id: 'view-and-process',
+        id: 'view_and_process',
         title: '查看和处理',
         component: Preferences.ViewAndProcess,
       },
@@ -131,22 +136,22 @@ export const settingsConfig: SettingsCategory[] = [
     icon: <ToolOutlined />,
     sections: [
       {
-        id: 'flat-panel-detector',
+        id: 'flat_panel_detector',
         title: '平板探测',
         component: Hardware.FlatPanelDetector,
       },
       {
-        id: 'high-voltage-generator',
+        id: 'high_voltage_generator',
         title: '高压发生器',
         component: Hardware.HighVoltageGenerator,
       },
       {
-        id: 'sync-box',
+        id: 'sync_box',
         title: '同步盒',
         component: Hardware.SyncBox,
       },
       {
-        id: 'workstation-sync',
+        id: 'workstation_sync',
         title: '工作位与同步',
         component: Hardware.WorkstationSync,
       },
@@ -188,17 +193,17 @@ export const settingsConfig: SettingsCategory[] = [
         component: Network.Connection,
       },
       {
-        id: 'network-preferences',
+        id: 'network_preferences',
         title: '首选项',
         component: Network.NetworkPreferences,
       },
       {
-        id: 'tag-mapping',
+        id: 'tag_mapping',
         title: '标记映射',
         component: Network.TagMapping,
       },
       {
-        id: 'network-test',
+        id: 'network_test',
         title: '测试',
         component: Network.NetworkTest,
       },
@@ -210,32 +215,32 @@ export const settingsConfig: SettingsCategory[] = [
     icon: <FileTextOutlined />,
     sections: [
       {
-        id: 'exam-protocol',
+        id: 'exam_protocol',
         title: '检查协议',
         component: Protocol.ExamProtocol,
       },
       {
-        id: 'imaging-position',
+        id: 'imaging_position',
         title: '摄影体位',
         component: Protocol.ImagingPosition,
       },
       {
-        id: 'exposure-parameters',
+        id: 'exposure_parameters',
         title: '曝光参数',
         component: Protocol.ExposureParameters,
       },
       {
-        id: 'processing-parameters',
+        id: 'processing_parameters',
         title: '处理参数',
         component: Protocol.ProcessingParameters,
       },
       {
-        id: 'import-export',
+        id: 'import_export',
         title: '导入导出',
         component: Protocol.ImportExport,
       },
       {
-        id: 'parameter-set',
+        id: 'parameter_set',
         title: '参数集',
         component: Protocol.ParameterSet,
       },
@@ -252,27 +257,27 @@ export const settingsConfig: SettingsCategory[] = [
         component: Statistics.Workload,
       },
       {
-        id: 'body-part',
+        id: 'body_part',
         title: '身体部位',
         component: Statistics.BodyPart,
       },
       {
-        id: 'rejection-reason',
+        id: 'rejection_reason',
         title: '拒绝原因',
         component: Statistics.RejectionReason,
       },
       {
-        id: 'dose-statistics',
+        id: 'dose_statistics',
         title: '剂量统计',
         component: Statistics.DoseStatistics,
       },
       {
-        id: 'print-statistics',
+        id: 'print_statistics',
         title: '打印统计',
         component: Statistics.PrintStatistics,
       },
       {
-        id: 'hardware-status',
+        id: 'hardware_status',
         title: '硬件状态统计',
         component: Statistics.HardwareStatus,
       },

+ 135 - 0
src/pages/system/SettingsModal/sections/Preferences/LanguageSettings.tsx

@@ -0,0 +1,135 @@
+import React, { useEffect } from 'react';
+import { Space, Typography, message, Spin, Select, Button } from 'antd';
+import { GlobalOutlined } from '@ant-design/icons';
+import { useAppDispatch, useAppSelector } from '../../../../../states/store';
+import {
+  loadAvailableLanguages,
+  updateSystemLanguage,
+  setSelectedLanguage,
+} from '../../../../../states/i18nSlice';
+
+const { Text } = Typography;
+
+const LanguageSettings: React.FC = () => {
+  const dispatch = useAppDispatch();
+
+  // 从 Redux 获取状态
+  const {
+    availableLanguages,
+    selectedLanguage,
+    currentSystemLocale,
+    languagesLoading,
+    savingLanguage,
+    languageError,
+  } = useAppSelector((state) => state.i18n);
+
+  // 加载语言列表
+  useEffect(() => {
+    if (availableLanguages.length === 0) {
+      dispatch(loadAvailableLanguages());
+    }
+  }, [dispatch, availableLanguages.length]);
+
+  // 显示错误消息
+  useEffect(() => {
+    if (languageError) {
+      message.error({
+        content: languageError,
+        duration: 3,
+      });
+    }
+  }, [languageError]);
+
+  const handleSave = async (): Promise<void> => {
+    if (!selectedLanguage) {
+      message.warning('请选择一个语言');
+      return;
+    }
+
+    try {
+      await dispatch(updateSystemLanguage(selectedLanguage)).unwrap();
+      message.success({
+        content: '语言设置已保存',
+        duration: 2,
+      });
+      message.info({
+        content: '请重启电脑以应用新的语言设置',
+        duration: 3,
+      });
+    } catch (error) {
+      // 错误已经在 Redux slice 中处理并通过 languageError 显示
+      console.error('修改语言失败:', error);
+    }
+  };
+
+  const handleLanguageChange = (value: string): void => {
+    dispatch(setSelectedLanguage(value));
+  };
+
+  return (
+    <div style={{ padding: '24px', minHeight: 400 }}>
+      <Space direction="horizontal" align="start" style={{ width: '100%', marginBottom: 24 }}>
+        <GlobalOutlined style={{ fontSize: 20, color: '#1890ff' }} />
+        <div>
+          <Text strong style={{ fontSize: 16, display: 'block', marginBottom: 8 }}>
+            语言设置
+          </Text>
+          <Text type="secondary">选择系统显示语言,保存后需要重启软件才能生效</Text>
+        </div>
+      </Space>
+
+      {languagesLoading ? (
+        <div style={{ textAlign: 'center', padding: '40px 0' }}>
+          <Spin size="large" tip="加载中..." />
+        </div>
+      ) : (
+        <Space direction="vertical" size="large" style={{ width: '100%', maxWidth: 600 }}>
+          {currentSystemLocale && (
+            <div>
+              <Text style={{ fontSize: 14, display: 'block', marginBottom: 8 }}>
+                当前系统语言:<Text strong>{currentSystemLocale}</Text>
+              </Text>
+            </div>
+          )}
+
+          <div>
+            <Text
+              strong
+              style={{ display: 'block', marginBottom: 12, fontSize: 14 }}
+            >
+              选择语言:
+            </Text>
+            <Select
+              style={{ width: '100%', maxWidth: 300 }}
+              size="large"
+              value={selectedLanguage || undefined}
+              onChange={handleLanguageChange}
+              disabled={savingLanguage}
+              placeholder="请选择语言"
+            >
+              {availableLanguages.map((lang) => (
+                <Select.Option key={lang.language} value={lang.language}>
+                  {lang.display}
+                </Select.Option>
+              ))}
+            </Select>
+          </div>
+
+          <div>
+            <Button
+              type="primary"
+              size="large"
+              onClick={handleSave}
+              loading={savingLanguage}
+              disabled={!selectedLanguage}
+            >
+              保存设置
+            </Button>
+          </div>
+        </Space>
+      )}
+    </div>
+  );
+};
+
+export default LanguageSettings;

+ 4 - 0
src/pages/system/SettingsModal/sections/Preferences/index.tsx

@@ -5,6 +5,7 @@ import React from 'react';
 import PlaceholderSection from '../PlaceholderSection';
 import NewInspection from './NewInspection';
 import WorkflowComponent from './Workflow';
+import LanguageSettings from './LanguageSettings';
 
 // 通用设置
 export const GeneralSettings: React.FC = () => (
@@ -36,3 +37,6 @@ export const ViewAndProcess: React.FC = () => (
 export const Report: React.FC = () => (
   <PlaceholderSection title="报告" />
 );
+
+// 语言设置
+export const LanguageSettingsComponent: React.FC = () => <LanguageSettings />;