Browse Source

为所有患者模块的页面使用多语言,添加中文翻译

dengdx 2 months ago
parent
commit
ea1c552527

+ 111 - 0
src/assets/i18n/messages/zh.js

@@ -13,4 +13,115 @@ export default {
   process:'处理',
   print:'打印',
   printlist:'打印清单',
+  worklist: '任务清单',
+  'worklist.operationPanel': '操作面板',
+  'register.basicInfoPanel': '基本信息表单区域',
+  'register.protocolListPanel': '待选择协议列表区域',
+  'register.selectedProtocolListPanel': '已选择协议列表区域',
+  'worklistTable.patientId': '患者编号22',
+  'worklistTable.name': '患者姓名',
+  'worklistTable.alias': '曾用名',
+  'worklistTable.englishName': '英文名',
+  'worklistTable.registrationId': '登记号',
+  'worklistTable.birthDate': '出生日期',
+  'worklistTable.age': '年龄',
+  'worklistTable.gender': '性别',
+  'worklistTable.bodyType': '病人体型',
+  'worklistTable.weight': '体重',
+  'worklistTable.height': '身高',
+  'worklistTable.pregnancyStatus': '怀孕状态',
+  'worklistTable.referringDoctor': '转诊医师',
+  'searchPanel.name': '按姓名查询',
+  'searchPanel.patientId': '按患者编号查询',
+  'searchPanel.registrationId': '按登记号查询',
+  'searchPanel.startDate': '开始日期',
+  'searchPanel.endDate': '结束日期',
+  'searchPanel.search': '查询',
+  // register.form
+  'register.patientId': '患者编号',
+  'register.patientId.placeholder': '请输入患者编号',
+  'register.patientName': '患者姓名',
+  'register.patientName.placeholder': '请输入患者姓名',
+  'register.previousName': '曾用名',
+  'register.previousName.placeholder': '请输入曾用名',
+  'register.englishName': '英文名',
+  'register.englishName.placeholder': '请输入英文名',
+  'register.registrationNo': '登记号',
+  'register.registrationNo.placeholder': '请输入登记号',
+  'register.dateOfBirth': '出生日期',
+  'register.age': '年龄',
+  'register.gender': '性别',
+  'register.gender.male': '男',
+  'register.gender.female': '女',
+  'register.bodyType': '病人体型',
+  'register.bodyType.slim': '瘦',
+  'register.bodyType.average': '平均',
+  'register.bodyType.fat': '重',
+  'register.weight': '体重',
+  'register.height': '身高',
+  'register.pregnancyStatus': '怀孕状态',
+  'register.pregnancyStatus.yes': '是',
+  'register.pregnancyStatus.no': '否',
+  'register.pregnancyStatus.na': '不适用',
+  'register.referringPhysician': '转诊医师',
+  'register.referringPhysician.placeholder': '请输入转诊医师姓名',
+  'register.bodyPart': '身体部位',
+  'register.bodyPart.head': '头部',
+  'register.bodyPart.chest': '胸部',
+  // 协议列表
+  'register.protocol.A': '协议A',
+  'register.protocol.B': '协议B',
+  'register.protocol.C': '协议C',
+  'register.protocol.D': '协议D',
+  'register.protocol.E': '协议E',
+  'register.protocol.F': '协议F',
+  // 已选协议
+  'register.selectedProtocol.A': '已选协议A',
+  'register.selectedProtocol.B': '已选协议B',
+  'register.selectedProtocol.C': '已选协议C',
+  'register.selectedProtocol.remove': '移除',
+  // OutputTable
+  'outputTable.name': '病人姓名',
+  'outputTable.id': '病人ID',
+  'outputTable.priority': '优先级',
+  'outputTable.status': '状态',
+  'outputTable.retryCount': '重试次数',
+  'outputTable.target': '目标',
+  // OutputActionPanel
+  'outputAction.retry': '重试',
+  'outputAction.delete': '删除',
+  // BinActionPanel
+  'bin.diskCapacity': '磁盘容量:',
+  'bin.freeSpace': '剩余空间:',
+  'bin.binCapacity': '回收站容量:',
+  'bin.delete': '删除',
+  'bin.restore': '恢复',
+  'bin.empty': '清空',
+  // DicomNodeDetailPanel
+  'dicomNodeDetail.title': 'DICOM节点详情',
+  'dicomNodeDetail.nodeList': 'DICOM节点列表',
+  'dicomNodeDetail.selectNode': '请选择DICOM节点',
+  'dicomNodeDetail.host': '主机名称',
+  'dicomNodeDetail.ip': '主机IP',
+  'dicomNodeDetail.port': '主机端口',
+  'dicomNodeDetail.calledAET': '被叫实体名',
+  'dicomNodeDetail.callingAET': '主叫实体名',
+  'dicomNodeDetail.testConnection': '测试连接状态',
+  'dicomNodeDetail.archive': '归档',
+  // ActionPanel
+  'actionPanel.deleteTask': '删除检查任务',
+  'actionPanel.editPatient': '编辑患者信息',
+  'actionPanel.lockTask': '锁定任务',
+  'actionPanel.risSync': 'RIS同步',
+  'actionPanel.reRegister': '再登记',
+  'actionPanel.saveLocal': '保存本地',
+  'actionPanel.importXLS': '从XLS导入',
+  'actionPanel.sortList': '列表排序',
+  'actionPanel.cloudShare': '云分享',
+  'actionPanel.imageExchange': '图像交换',
+  'actionPanel.qrPrint': '二维码打印',
+  'actionPanel.send': '发送',
+  'actionPanel.burn': '刻录',
+  'actionPanel.export': '导出',
+  'actionPanel.import': '导入',
 };

+ 7 - 1
src/pages/patient/ArchiveList.tsx

@@ -1,6 +1,7 @@
 import React, { useState } from 'react';
 import { Row, Col, Button, Drawer, Grid, Pagination } from 'antd';
 import { SettingOutlined } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 import WorklistTable from './components/WorklistTable';
 import ArchiveOperationPanel from './components/ArchiveOperationPanel';
 
@@ -23,7 +24,12 @@ const ArchivelistPage: React.FC = () => {
             onClick={() => setDrawerVisible(true)}
           />
           <Drawer
-            title="操作面板"
+            title={
+              <FormattedMessage
+                id="worklist.operationPanel"
+                defaultMessage="worklist.operationPanel"
+              />
+            }
             placement="left"
             onClose={() => setDrawerVisible(false)}
             open={drawerVisible}

+ 7 - 1
src/pages/patient/Bin.tsx

@@ -1,6 +1,7 @@
 import React, { useState } from 'react';
 import { Row, Col, Button, Drawer, Grid, Pagination } from 'antd';
 import { SettingOutlined } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 import WorklistTable from './components/WorklistTable';
 import BinOperationPanel from './components/BinOperationPanel';
 
@@ -23,7 +24,12 @@ const BinPage: React.FC = () => {
             onClick={() => setDrawerVisible(true)}
           />
           <Drawer
-            title="操作面板"
+            title={
+              <FormattedMessage
+                id="worklist.operationPanel"
+                defaultMessage="worklist.operationPanel"
+              />
+            }
             placement="left"
             onClose={() => setDrawerVisible(false)}
             open={drawerVisible}

+ 7 - 1
src/pages/patient/HistoryList.tsx

@@ -1,6 +1,7 @@
 import React, { useState } from 'react';
 import { Row, Col, Button, Drawer, Grid, Pagination } from 'antd';
 import { SettingOutlined } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 import WorklistTable from './components/WorklistTable';
 import OperationPanel from './components/OperationPanel';
 
@@ -23,7 +24,12 @@ const HistorylistPage: React.FC = () => {
             onClick={() => setDrawerVisible(true)}
           />
           <Drawer
-            title="操作面板"
+            title={
+              <FormattedMessage
+                id="worklist.operationPanel"
+                defaultMessage="worklist.operationPanel"
+              />
+            }
             placement="left"
             onClose={() => setDrawerVisible(false)}
             open={drawerVisible}

+ 7 - 1
src/pages/patient/OutputList.tsx

@@ -1,6 +1,7 @@
 import React, { useState } from 'react';
 import { Row, Col, Button, Drawer, Grid, Pagination } from 'antd';
 import { SettingOutlined } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 import WorklistTable from './components/WorklistTable';
 import OutputOperationPanel from './components/OutputOperationPanel';
 
@@ -23,7 +24,12 @@ const OutputlistPage: React.FC = () => {
             onClick={() => setDrawerVisible(true)}
           />
           <Drawer
-            title="操作面板"
+            title={
+              <FormattedMessage
+                id="worklist.operationPanel"
+                defaultMessage="worklist.operationPanel"
+              />
+            }
             placement="left"
             onClose={() => setDrawerVisible(false)}
             open={drawerVisible}

+ 137 - 16
src/pages/patient/components/ActionPanel.tsx

@@ -1,10 +1,11 @@
 import React from 'react';
 import { Button, Tooltip } from 'antd';
 import { DeleteOutlined } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 
 interface ActionButtonProps {
   icon: React.ReactNode;
-  tooltip: string;
+  tooltip: React.ReactNode;
 }
 
 const ActionButton: React.FC<ActionButtonProps> = ({ icon, tooltip }) => (
@@ -16,21 +17,141 @@ const ActionButton: React.FC<ActionButtonProps> = ({ icon, tooltip }) => (
 const ActionPanel: React.FC = () => {
   return (
     <div className="flex flex-wrap gap-2 w-full">
-      <ActionButton icon={<DeleteOutlined />} tooltip="删除检查任务" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="编辑患者信息" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="锁定任务" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="RIS同步" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="再登记" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="保存本地" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="从XLS导入" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="列表排序" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="云分享" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="图像交换" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="二维码打印" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="发送" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="刻录" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="导出" />
-      <ActionButton icon={<DeleteOutlined />} tooltip="导入" />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.deleteTask"
+            defaultMessage="actionPanel.deleteTask"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.editPatient"
+            defaultMessage="actionPanel.editPatient"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.lockTask"
+            defaultMessage="actionPanel.lockTask"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.risSync"
+            defaultMessage="actionPanel.risSync"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.reRegister"
+            defaultMessage="actionPanel.reRegister"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.saveLocal"
+            defaultMessage="actionPanel.saveLocal"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.importXLS"
+            defaultMessage="actionPanel.importXLS"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.sortList"
+            defaultMessage="actionPanel.sortList"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.cloudShare"
+            defaultMessage="actionPanel.cloudShare"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.imageExchange"
+            defaultMessage="actionPanel.imageExchange"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.qrPrint"
+            defaultMessage="actionPanel.qrPrint"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.send"
+            defaultMessage="actionPanel.send"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.burn"
+            defaultMessage="actionPanel.burn"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.export"
+            defaultMessage="actionPanel.export"
+          />
+        }
+      />
+      <ActionButton
+        icon={<DeleteOutlined />}
+        tooltip={
+          <FormattedMessage
+            id="actionPanel.import"
+            defaultMessage="actionPanel.import"
+          />
+        }
+      />
     </div>
   );
 };

+ 37 - 6
src/pages/patient/components/BinActionPanel.tsx

@@ -5,6 +5,7 @@ import {
   RollbackOutlined,
   RestOutlined,
 } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 
 const { Text } = Typography;
 
@@ -38,16 +39,31 @@ const BinActionPanel: React.FC<BinActionPanelProps> = ({
     >
       <Space direction="vertical" size="middle" style={{ width: '100%' }}>
         <Space direction="vertical" size={4} style={{ width: '100%' }}>
-          <Text strong>磁盘容量:</Text>
+          <Text strong>
+            <FormattedMessage
+              id="bin.diskCapacity"
+              defaultMessage="bin.diskCapacity"
+            />
+          </Text>
           <Text type="secondary">{totalCapacity} GB</Text>
           <Progress percent={usedPercent} size="small" showInfo={false} />
         </Space>
         <Space direction="vertical" size={4} style={{ width: '100%' }}>
-          <Text strong>剩余空间:</Text>
+          <Text strong>
+            <FormattedMessage
+              id="bin.freeSpace"
+              defaultMessage="bin.freeSpace"
+            />
+          </Text>
           <Text type="secondary">{freeSpace} GB</Text>
         </Space>
         <Space direction="vertical" size={4} style={{ width: '100%' }}>
-          <Text strong>回收站容量:</Text>
+          <Text strong>
+            <FormattedMessage
+              id="bin.binCapacity"
+              defaultMessage="bin.binCapacity"
+            />
+          </Text>
           <Text type="secondary">{binCapacity} GB</Text>
           <Progress
             percent={binPercent}
@@ -58,7 +74,11 @@ const BinActionPanel: React.FC<BinActionPanelProps> = ({
         </Space>
         <Row justify="center">
           <Space>
-            <Tooltip title="删除">
+            <Tooltip
+              title={
+                <FormattedMessage id="bin.delete" defaultMessage="bin.delete" />
+              }
+            >
               <Button
                 type="primary"
                 shape="circle"
@@ -67,7 +87,14 @@ const BinActionPanel: React.FC<BinActionPanelProps> = ({
                 danger
               />
             </Tooltip>
-            <Tooltip title="恢复">
+            <Tooltip
+              title={
+                <FormattedMessage
+                  id="bin.restore"
+                  defaultMessage="bin.restore"
+                />
+              }
+            >
               <Button
                 type="default"
                 shape="circle"
@@ -75,7 +102,11 @@ const BinActionPanel: React.FC<BinActionPanelProps> = ({
                 onClick={onRestore}
               />
             </Tooltip>
-            <Tooltip title="清空">
+            <Tooltip
+              title={
+                <FormattedMessage id="bin.empty" defaultMessage="bin.empty" />
+              }
+            >
               <Button
                 type="default"
                 shape="circle"

+ 80 - 10
src/pages/patient/components/DicomNodeDetailPanel.tsx

@@ -11,6 +11,7 @@ import {
   Space,
 } from 'antd';
 import { LinkOutlined, InboxOutlined } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 
 const { Option } = Select;
 
@@ -42,14 +43,34 @@ const DicomNodeDetailPanel: React.FC<Props> = ({
   const selectedNode = nodeList.find((node) => node.id === selectedNodeId);
 
   return (
-    <Card title="DICOM节点详情" bordered={false}>
+    <Card
+      title={
+        <FormattedMessage
+          id="dicomNodeDetail.title"
+          defaultMessage="dicomNodeDetail.title"
+        />
+      }
+      bordered={false}
+    >
       <Form layout="vertical">
-        <Form.Item label="DICOM节点列表">
+        <Form.Item
+          label={
+            <FormattedMessage
+              id="dicomNodeDetail.nodeList"
+              defaultMessage="dicomNodeDetail.nodeList"
+            />
+          }
+        >
           <Select
             value={selectedNodeId}
             onChange={onNodeChange}
             style={{ width: '100%' }}
-            placeholder="请选择DICOM节点"
+            placeholder={
+              <FormattedMessage
+                id="dicomNodeDetail.selectNode"
+                defaultMessage="dicomNodeDetail.selectNode"
+              />
+            }
           >
             {nodeList.map((node) => (
               <Option key={node.id} value={node.id}>
@@ -60,43 +81,92 @@ const DicomNodeDetailPanel: React.FC<Props> = ({
         </Form.Item>
         <Row gutter={16}>
           <Col span={12}>
-            <Form.Item label="主机名称">
+            <Form.Item
+              label={
+                <FormattedMessage
+                  id="dicomNodeDetail.host"
+                  defaultMessage="dicomNodeDetail.host"
+                />
+              }
+            >
               <Input value={selectedNode?.host} readOnly />
             </Form.Item>
           </Col>
           <Col span={12}>
-            <Form.Item label="主机IP">
+            <Form.Item
+              label={
+                <FormattedMessage
+                  id="dicomNodeDetail.ip"
+                  defaultMessage="dicomNodeDetail.ip"
+                />
+              }
+            >
               <Input value={selectedNode?.ip} readOnly />
             </Form.Item>
           </Col>
         </Row>
         <Row gutter={16}>
           <Col span={8}>
-            <Form.Item label="主机端口">
+            <Form.Item
+              label={
+                <FormattedMessage
+                  id="dicomNodeDetail.port"
+                  defaultMessage="dicomNodeDetail.port"
+                />
+              }
+            >
               <Input value={selectedNode?.port} readOnly />
             </Form.Item>
           </Col>
           <Col span={8}>
-            <Form.Item label="被叫实体名">
+            <Form.Item
+              label={
+                <FormattedMessage
+                  id="dicomNodeDetail.calledAET"
+                  defaultMessage="dicomNodeDetail.calledAET"
+                />
+              }
+            >
               <Input value={selectedNode?.calledAET} readOnly />
             </Form.Item>
           </Col>
           <Col span={8}>
-            <Form.Item label="主叫实体名">
+            <Form.Item
+              label={
+                <FormattedMessage
+                  id="dicomNodeDetail.callingAET"
+                  defaultMessage="dicomNodeDetail.callingAET"
+                />
+              }
+            >
               <Input value={selectedNode?.callingAET} readOnly />
             </Form.Item>
           </Col>
         </Row>
         <Form.Item>
           <Space>
-            <Tooltip title="测试连接状态">
+            <Tooltip
+              title={
+                <FormattedMessage
+                  id="dicomNodeDetail.testConnection"
+                  defaultMessage="dicomNodeDetail.testConnection"
+                />
+              }
+            >
               <Button
                 icon={<LinkOutlined />}
                 onClick={onTestConnection}
                 type="default"
               />
             </Tooltip>
-            <Tooltip title="归档">
+            <Tooltip
+              title={
+                <FormattedMessage
+                  id="dicomNodeDetail.archive"
+                  defaultMessage="dicomNodeDetail.archive"
+                />
+              }
+            >
               <Button
                 icon={<InboxOutlined />}
                 onClick={onArchive}

+ 17 - 2
src/pages/patient/components/OutputActionPanel.tsx

@@ -1,12 +1,27 @@
 import { Tooltip, Button, Space } from 'antd';
 import { ReloadOutlined, DeleteOutlined } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 
 const OutputActionPanel: React.FC = () => (
   <Space>
-    <Tooltip title="重试">
+    <Tooltip
+      title={
+        <FormattedMessage
+          id="outputAction.retry"
+          defaultMessage="outputAction.retry"
+        />
+      }
+    >
       <Button type="text" icon={<ReloadOutlined />} aria-label="重试" />
     </Tooltip>
-    <Tooltip title="删除">
+    <Tooltip
+      title={
+        <FormattedMessage
+          id="outputAction.delete"
+          defaultMessage="outputAction.delete"
+        />
+      }
+    >
       <Button type="text" icon={<DeleteOutlined />} aria-label="删除" danger />
     </Tooltip>
   </Space>

+ 34 - 6
src/pages/patient/components/OutputTable.tsx

@@ -1,5 +1,6 @@
 import React from 'react';
 import { Table } from 'antd';
+import { FormattedMessage } from 'react-intl';
 
 interface PatientData {
   key: string;
@@ -13,32 +14,59 @@ interface PatientData {
 
 const columns = [
   {
-    title: '病人姓名',
+    title: (
+      <FormattedMessage
+        id="outputTable.name"
+        defaultMessage="outputTable.name"
+      />
+    ),
     dataIndex: 'name',
     key: 'name',
   },
   {
-    title: '病人ID',
+    title: (
+      <FormattedMessage id="outputTable.id" defaultMessage="outputTable.id" />
+    ),
     dataIndex: 'id',
     key: 'id',
   },
   {
-    title: '优先级',
+    title: (
+      <FormattedMessage
+        id="outputTable.priority"
+        defaultMessage="outputTable.priority"
+      />
+    ),
     dataIndex: 'priority',
     key: 'priority',
   },
   {
-    title: '状态',
+    title: (
+      <FormattedMessage
+        id="outputTable.status"
+        defaultMessage="outputTable.status"
+      />
+    ),
     dataIndex: 'status',
     key: 'status',
   },
   {
-    title: '重试次数',
+    title: (
+      <FormattedMessage
+        id="outputTable.retryCount"
+        defaultMessage="outputTable.retryCount"
+      />
+    ),
     dataIndex: 'retryCount',
     key: 'retryCount',
   },
   {
-    title: '目标',
+    title: (
+      <FormattedMessage
+        id="outputTable.target"
+        defaultMessage="outputTable.target"
+      />
+    ),
     dataIndex: 'target',
     key: 'target',
   },

+ 29 - 5
src/pages/patient/components/SearchPanel.tsx

@@ -1,34 +1,58 @@
 import React from 'react';
 import { Input, Button, DatePicker } from 'antd';
 import { SearchOutlined } from '@ant-design/icons';
+import { useIntl, FormattedMessage } from 'react-intl';
 
 const { RangePicker } = DatePicker;
 
 const SearchPanel: React.FC = () => {
+  const intl = useIntl();
+
   return (
     <div className="flex flex-col gap-2 w-full">
       <Input
-        placeholder="按姓名查询"
+        placeholder={intl.formatMessage({
+          id: 'searchPanel.name',
+          defaultMessage: 'searchPanel.name',
+        })}
         prefix={<SearchOutlined />}
         size="small"
       />
       <Input
-        placeholder="按患者编号查询"
+        placeholder={intl.formatMessage({
+          id: 'searchPanel.patientId',
+          defaultMessage: 'searchPanel.patientId',
+        })}
         prefix={<SearchOutlined />}
         size="small"
       />
       <Input
-        placeholder="按登记号查询"
+        placeholder={intl.formatMessage({
+          id: 'searchPanel.registrationId',
+          defaultMessage: 'searchPanel.registrationId',
+        })}
         prefix={<SearchOutlined />}
         size="small"
       />
       <RangePicker
         className="w-full"
-        placeholder={['开始日期', '结束日期']}
+        placeholder={[
+          intl.formatMessage({
+            id: 'searchPanel.startDate',
+            defaultMessage: 'searchPanel.startDate',
+          }),
+          intl.formatMessage({
+            id: 'searchPanel.endDate',
+            defaultMessage: 'searchPanel.endDate',
+          }),
+        ]}
         size="small"
       />
       <Button type="primary" icon={<SearchOutlined />}>
-        查询
+        <FormattedMessage
+          id="searchPanel.search"
+          defaultMessage="searchPanel.search"
+        />
       </Button>
     </div>
   );

+ 118 - 13
src/pages/patient/components/WorklistTable.tsx

@@ -1,20 +1,125 @@
 import React from 'react';
 import { Table } from 'antd';
+import { FormattedMessage } from 'react-intl';
 
 const columns = [
-  { title: '患者编号', dataIndex: 'patientId' },
-  { title: '患者姓名', dataIndex: 'name' },
-  { title: '曾用名', dataIndex: 'alias' },
-  { title: '英文名', dataIndex: 'englishName' },
-  { title: '登记号', dataIndex: 'registrationId' },
-  { title: '出生日期', dataIndex: 'birthDate' },
-  { title: '年龄', dataIndex: 'age' },
-  { title: '性别', dataIndex: 'gender' },
-  { title: '病人体型', dataIndex: 'bodyType' },
-  { title: '体重', dataIndex: 'weight' },
-  { title: '身高', dataIndex: 'height' },
-  { title: '怀孕状态', dataIndex: 'pregnancyStatus' },
-  { title: '转诊医师', dataIndex: 'referringDoctor' },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.patientId"
+        defaultMessage="worklistTable.patientId"
+      />
+    ),
+    dataIndex: 'patientId',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.name"
+        defaultMessage="worklistTable.name"
+      />
+    ),
+    dataIndex: 'name',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.alias"
+        defaultMessage="worklistTable.alias"
+      />
+    ),
+    dataIndex: 'alias',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.englishName"
+        defaultMessage="worklistTable.englishName"
+      />
+    ),
+    dataIndex: 'englishName',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.registrationId"
+        defaultMessage="worklistTable.registrationId"
+      />
+    ),
+    dataIndex: 'registrationId',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.birthDate"
+        defaultMessage="worklistTable.birthDate"
+      />
+    ),
+    dataIndex: 'birthDate',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.age"
+        defaultMessage="worklistTable.age"
+      />
+    ),
+    dataIndex: 'age',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.gender"
+        defaultMessage="worklistTable.gender"
+      />
+    ),
+    dataIndex: 'gender',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.bodyType"
+        defaultMessage="worklistTable.bodyType"
+      />
+    ),
+    dataIndex: 'bodyType',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.weight"
+        defaultMessage="worklistTable.weight"
+      />
+    ),
+    dataIndex: 'weight',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.height"
+        defaultMessage="worklistTable.height"
+      />
+    ),
+    dataIndex: 'height',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.pregnancyStatus"
+        defaultMessage="worklistTable.pregnancyStatus"
+      />
+    ),
+    dataIndex: 'pregnancyStatus',
+  },
+  {
+    title: (
+      <FormattedMessage
+        id="worklistTable.referringDoctor"
+        defaultMessage="worklistTable.referringDoctor"
+      />
+    ),
+    dataIndex: 'referringDoctor',
+  },
 ];
 
 const WorklistTable: React.FC = () => {

+ 283 - 60
src/pages/patient/components/register.form.tsx

@@ -1,79 +1,302 @@
 import React from 'react';
 import { Form, Input, DatePicker, InputNumber, Select, Radio } from 'antd';
+import { useIntl, FormattedMessage } from 'react-intl';
 
 const genderOptions = [
-  { value: 'male', label: '男' },
-  { value: 'female', label: '女' },
+  {
+    value: 'male',
+    label: (
+      <FormattedMessage
+        id="register.gender.male"
+        defaultMessage="register.gender.male"
+      />
+    ),
+  },
+  {
+    value: 'female',
+    label: (
+      <FormattedMessage
+        id="register.gender.female"
+        defaultMessage="register.gender.female"
+      />
+    ),
+  },
 ];
 
 const bodyTypeOptions = [
-  { value: 'slim', label: '瘦' },
-  { value: 'average', label: '平均' },
-  { value: 'fat', label: '重' },
+  {
+    value: 'slim',
+    label: (
+      <FormattedMessage
+        id="register.bodyType.slim"
+        defaultMessage="register.bodyType.slim"
+      />
+    ),
+  },
+  {
+    value: 'average',
+    label: (
+      <FormattedMessage
+        id="register.bodyType.average"
+        defaultMessage="register.bodyType.average"
+      />
+    ),
+  },
+  {
+    value: 'fat',
+    label: (
+      <FormattedMessage
+        id="register.bodyType.fat"
+        defaultMessage="register.bodyType.fat"
+      />
+    ),
+  },
 ];
 
 const pregnancyStatusOptions = [
-  { value: 'yes', label: '是' },
-  { value: 'no', label: '否' },
-  { value: 'na', label: '不适用' },
+  {
+    value: 'yes',
+    label: (
+      <FormattedMessage
+        id="register.pregnancyStatus.yes"
+        defaultMessage="register.pregnancyStatus.yes"
+      />
+    ),
+  },
+  {
+    value: 'no',
+    label: (
+      <FormattedMessage
+        id="register.pregnancyStatus.no"
+        defaultMessage="register.pregnancyStatus.no"
+      />
+    ),
+  },
+  {
+    value: 'na',
+    label: (
+      <FormattedMessage
+        id="register.pregnancyStatus.na"
+        defaultMessage="register.pregnancyStatus.na"
+      />
+    ),
+  },
 ];
 
 const bodyPartOptions = [
-  { value: 'head', label: '头部' },
-  { value: 'chest', label: '胸部' },
+  {
+    value: 'head',
+    label: (
+      <FormattedMessage
+        id="register.bodyPart.head"
+        defaultMessage="register.bodyPart.head"
+      />
+    ),
+  },
+  {
+    value: 'chest',
+    label: (
+      <FormattedMessage
+        id="register.bodyPart.chest"
+        defaultMessage="register.bodyPart.chest"
+      />
+    ),
+  },
 ];
 interface BasicInfoFormProps {
   style?: React.CSSProperties;
 }
-const BasicInfoForm: React.FC<BasicInfoFormProps> = ({ style }) => (
-  <Form layout="vertical" style={style}>
-    <Form.Item label="患者编号" name="patientId">
-      <Input placeholder="请输入患者编号" />
-    </Form.Item>
-    <Form.Item label="患者姓名" name="patientName">
-      <Input placeholder="请输入患者姓名" />
-    </Form.Item>
-    <Form.Item label="曾用名" name="previousName">
-      <Input placeholder="请输入曾用名" />
-    </Form.Item>
-    <Form.Item label="英文名" name="englishName">
-      <Input placeholder="请输入英文名" />
-    </Form.Item>
-    <Form.Item label="登记号" name="registrationNo">
-      <Input placeholder="请输入登记号" />
-    </Form.Item>
-    <Form.Item label="出生日期" name="dateOfBirth">
-      <DatePicker format="YYYY-MM-DD" style={{ width: '100%' }} />
-    </Form.Item>
-    <Form.Item label="年龄" name="age">
-      <InputNumber min={0} style={{ width: '100%' }} />
-    </Form.Item>
-    <Form.Item label="性别" name="gender">
-      <Select options={genderOptions} />
-    </Form.Item>
-    <Form.Item label="病人体型" name="bodyType">
-      <Select options={bodyTypeOptions} />
-    </Form.Item>
-    <Form.Item label="体重" name="weight">
-      <InputNumber min={0} addonAfter="kg" style={{ width: '100%' }} />
-    </Form.Item>
-    <Form.Item label="身高" name="height">
-      <InputNumber min={0} addonAfter="cm" style={{ width: '100%' }} />
-    </Form.Item>
-    <Form.Item label="怀孕状态" name="pregnancyStatus">
-      <Radio.Group
-        options={pregnancyStatusOptions}
-        optionType="button"
-        buttonStyle="solid"
-      />
-    </Form.Item>
-    <Form.Item label="转诊医师" name="referringPhysician">
-      <Input placeholder="请输入转诊医师姓名" />
-    </Form.Item>
-    <Form.Item label="身体部位" name="bodyPart">
-      <Select options={bodyPartOptions} />
-    </Form.Item>
-  </Form>
-);
+const BasicInfoForm: React.FC<BasicInfoFormProps> = ({ style }) => {
+  const intl = useIntl();
+  return (
+    <Form layout="vertical" style={style}>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.patientId"
+            defaultMessage="register.patientId"
+          />
+        }
+        name="patientId"
+      >
+        <Input
+          placeholder={intl.formatMessage({
+            id: 'register.patientId.placeholder',
+            defaultMessage: 'register.patientId.placeholder',
+          })}
+        />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.patientName"
+            defaultMessage="register.patientName"
+          />
+        }
+        name="patientName"
+      >
+        <Input
+          placeholder={intl.formatMessage({
+            id: 'register.patientName.placeholder',
+            defaultMessage: 'register.patientName.placeholder',
+          })}
+        />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.previousName"
+            defaultMessage="register.previousName"
+          />
+        }
+        name="previousName"
+      >
+        <Input
+          placeholder={intl.formatMessage({
+            id: 'register.previousName.placeholder',
+            defaultMessage: 'register.previousName.placeholder',
+          })}
+        />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.englishName"
+            defaultMessage="register.englishName"
+          />
+        }
+        name="englishName"
+      >
+        <Input
+          placeholder={intl.formatMessage({
+            id: 'register.englishName.placeholder',
+            defaultMessage: 'register.englishName.placeholder',
+          })}
+        />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.registrationNo"
+            defaultMessage="register.registrationNo"
+          />
+        }
+        name="registrationNo"
+      >
+        <Input
+          placeholder={intl.formatMessage({
+            id: 'register.registrationNo.placeholder',
+            defaultMessage: 'register.registrationNo.placeholder',
+          })}
+        />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.dateOfBirth"
+            defaultMessage="register.dateOfBirth"
+          />
+        }
+        name="dateOfBirth"
+      >
+        <DatePicker format="YYYY-MM-DD" style={{ width: '100%' }} />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage id="register.age" defaultMessage="register.age" />
+        }
+        name="age"
+      >
+        <InputNumber min={0} style={{ width: '100%' }} />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.gender"
+            defaultMessage="register.gender"
+          />
+        }
+        name="gender"
+      >
+        <Select options={genderOptions} />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.bodyType"
+            defaultMessage="register.bodyType"
+          />
+        }
+        name="bodyType"
+      >
+        <Select options={bodyTypeOptions} />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.weight"
+            defaultMessage="register.weight"
+          />
+        }
+        name="weight"
+      >
+        <InputNumber min={0} addonAfter="kg" style={{ width: '100%' }} />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.height"
+            defaultMessage="register.height"
+          />
+        }
+        name="height"
+      >
+        <InputNumber min={0} addonAfter="cm" style={{ width: '100%' }} />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.pregnancyStatus"
+            defaultMessage="register.pregnancyStatus"
+          />
+        }
+        name="pregnancyStatus"
+      >
+        <Radio.Group
+          options={pregnancyStatusOptions}
+          optionType="button"
+          buttonStyle="solid"
+        />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.referringPhysician"
+            defaultMessage="register.referringPhysician"
+          />
+        }
+        name="referringPhysician"
+      >
+        <Input
+          placeholder={intl.formatMessage({
+            id: 'register.referringPhysician.placeholder',
+            defaultMessage: 'register.referringPhysician.placeholder',
+          })}
+        />
+      </Form.Item>
+      <Form.Item
+        label={
+          <FormattedMessage
+            id="register.bodyPart"
+            defaultMessage="register.bodyPart"
+          />
+        }
+        name="bodyPart"
+      >
+        <Select options={bodyPartOptions} />
+      </Form.Item>
+    </Form>
+  );
+};
 
 export default BasicInfoForm;

+ 55 - 6
src/pages/patient/components/register.protocol.list.tsx

@@ -1,16 +1,65 @@
 import React from 'react';
 import { Card, Grid } from 'antd';
+import { FormattedMessage } from 'react-intl';
 
 const { useBreakpoint } = Grid;
 
 // 示例协议数据
 const protocols = [
-  { id: 1, name: '协议A' },
-  { id: 2, name: '协议B' },
-  { id: 3, name: '协议C' },
-  { id: 4, name: '协议D' },
-  { id: 5, name: '协议E' },
-  { id: 6, name: '协议F' },
+  {
+    id: 1,
+    name: (
+      <FormattedMessage
+        id="register.protocol.A"
+        defaultMessage="register.protocol.A"
+      />
+    ),
+  },
+  {
+    id: 2,
+    name: (
+      <FormattedMessage
+        id="register.protocol.B"
+        defaultMessage="register.protocol.B"
+      />
+    ),
+  },
+  {
+    id: 3,
+    name: (
+      <FormattedMessage
+        id="register.protocol.C"
+        defaultMessage="register.protocol.C"
+      />
+    ),
+  },
+  {
+    id: 4,
+    name: (
+      <FormattedMessage
+        id="register.protocol.D"
+        defaultMessage="register.protocol.D"
+      />
+    ),
+  },
+  {
+    id: 5,
+    name: (
+      <FormattedMessage
+        id="register.protocol.E"
+        defaultMessage="register.protocol.E"
+      />
+    ),
+  },
+  {
+    id: 6,
+    name: (
+      <FormattedMessage
+        id="register.protocol.F"
+        defaultMessage="register.protocol.F"
+      />
+    ),
+  },
 ];
 
 // 卡片尺寸配置

+ 34 - 4
src/pages/patient/components/register.selected.protocol.list.tsx

@@ -1,14 +1,39 @@
 import React from 'react';
 import { Card, Grid, Button, Flex } from 'antd';
 import { CloseOutlined } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 
 const { useBreakpoint } = Grid;
 
 // 示例已选协议数据
 const selectedProtocols = [
-  { id: 1, name: '已选协议A' },
-  { id: 2, name: '已选协议B' },
-  { id: 3, name: '已选协议C' },
+  {
+    id: 1,
+    name: (
+      <FormattedMessage
+        id="register.selectedProtocol.A"
+        defaultMessage="register.selectedProtocol.A"
+      />
+    ),
+  },
+  {
+    id: 2,
+    name: (
+      <FormattedMessage
+        id="register.selectedProtocol.B"
+        defaultMessage="register.selectedProtocol.B"
+      />
+    ),
+  },
+  {
+    id: 3,
+    name: (
+      <FormattedMessage
+        id="register.selectedProtocol.C"
+        defaultMessage="register.selectedProtocol.C"
+      />
+    ),
+  },
 ];
 
 // 卡片尺寸配置
@@ -83,7 +108,12 @@ const SelectedProtocolList: React.FC<SelectedProtocolListProps> = () => {
               right: 2,
               color: '#999',
             }}
-            aria-label="移除"
+            aria-label={String(
+              <FormattedMessage
+                id="register.selectedProtocol.remove"
+                defaultMessage="register.selectedProtocol.remove"
+              />
+            )}
           />
         </Card>
       ))}

+ 28 - 3
src/pages/patient/register.tsx

@@ -1,5 +1,6 @@
 import React from 'react';
 import { Row, Col, Collapse, Grid, Divider } from 'antd';
+import { FormattedMessage } from 'react-intl';
 import BasicInfoForm from './components/register.form';
 import ProtocolList from './components/register.protocol.list';
 import SelectedProtocolList from './components/register.selected.protocol.list';
@@ -80,13 +81,37 @@ const RegisterPage: React.FC = () => {
         defaultActiveKey={['1']}
         style={{ margin: 16, overflow: 'auto', height: '100%' }}
       >
-        <Panel header="基本信息表单区域" key="1">
+        <Panel
+          header={
+            <FormattedMessage
+              id="register.basicInfoPanel"
+              defaultMessage="register.basicInfoPanel"
+            />
+          }
+          key="1"
+        >
           <BasicInfoForm />
         </Panel>
-        <Panel header="待选择协议列表区域" key="2">
+        <Panel
+          header={
+            <FormattedMessage
+              id="register.protocolListPanel"
+              defaultMessage="register.protocolListPanel"
+            />
+          }
+          key="2"
+        >
           <ProtocolList />
         </Panel>
-        <Panel header="已选择协议列表区域" key="3">
+        <Panel
+          header={
+            <FormattedMessage
+              id="register.selectedProtocolListPanel"
+              defaultMessage="register.selectedProtocolListPanel"
+            />
+          }
+          key="3"
+        >
           <SelectedProtocolList />
         </Panel>
       </Collapse>

+ 7 - 1
src/pages/patient/worklist.tsx

@@ -1,6 +1,7 @@
 import React, { useState } from 'react';
 import { Row, Col, Button, Drawer, Grid } from 'antd';
 import { SettingOutlined } from '@ant-design/icons';
+import { FormattedMessage } from 'react-intl';
 import WorklistTable from './components/WorklistTable';
 import OperationPanel from './components/OperationPanel';
 
@@ -23,7 +24,12 @@ const WorklistPage: React.FC = () => {
             onClick={() => setDrawerVisible(true)}
           />
           <Drawer
-            title="操作面板"
+            title={
+              <FormattedMessage
+                id="worklist.operationPanel"
+                defaultMessage="worklist.operationPanel"
+              />
+            }
             placement="left"
             onClose={() => setDrawerVisible(false)}
             open={drawerVisible}