瀏覽代碼

feat(1.20.21.21.0): 国际化改进 - 添加宠物类型键并完善组件多语言支持

- 在 RegisterAvailableFilterBar.tsx 中添加基于产品的患者类型选择器国际化,区分人类和宠物产品
- 在 AnimalBaseInfo.tsx 中添加完整多语言支持,包括患者姓名、性别、年龄、主人类别和报告相关字段
- 在 i18n 文件中添加宠物类型和报告字段的多语言键,包括申请科室、检查号、检查方法、放射科医生、审核医师等
- 支持 VETDROS(宠物产品)和 DROS(人类产品)的动态文本切换

改动文件:
- src/pages/patient/components/RegisterAvailableFilterBar.tsx
- src/pages/patient/DiagnosticReport/components/AnimalBaseInfo.tsx
- src/assets/i18n/messages/zh.js
- src/assets/i18n/messages/en.js
- scripts/output/i18n/zh.js
- scripts/output/i18n/en.js
- CHANGELOG.md
- package.json
dengdx 3 周之前
父節點
當前提交
3b3b8a40be

+ 34 - 0
CHANGELOG.md

@@ -2,6 +2,40 @@
 
 本项目的所有重要变更都将记录在此文件中。
 
+## [1.21.0] - 2025-12-22 17:24
+
+### 新增 (Added)
+- **国际化改进 - 添加宠物类型键并完善组件多语言支持** - 实现完整的宠物产品和诊断报告界面的国际化支持
+  - 在 RegisterAvailableFilterBar.tsx 中添加基于产品的患者类型选择器国际化,区分人类和宠物产品
+  - 在 AnimalBaseInfo.tsx 中添加完整多语言支持,包括患者姓名、性别、年龄、主人类别和报告相关字段
+  - 在 i18n 文件中添加宠物类型和报告字段的多语言键,包括申请科室、检查号、检查方法、放射科医生、审核医师等
+  - 支持 VETDROS(宠物产品)和 DROS(人类产品)的动态文本切换
+
+**核心功能实现:**
+- 产品区分支持:根据 productName 动态选择不同的国际化键
+- 诊断报告国际化:AnimalBaseInfo 组件所有标签支持多语言
+- 宠物类型键:新增 "animal.register.patientType" 支持宠物产品
+- 报告字段键:新增 "report." 前缀的诊断报告相关多语言键
+
+**技术实现:**
+- 在 RegisterAvailableFilterBar 组件中添加 productName 选择器
+- 使用条件表达式根据产品名称选择患者类型标签
+- 在 AnimalBaseInfo 组件中为所有表单项添加 FormattedMessage
+- 新增多语言键到 zh.js 和 en.js 文件
+- 保持与现有 register.form.tsx 组件的一致性设计模式
+
+**改动文件:**
+- src/pages/patient/components/RegisterAvailableFilterBar.tsx
+- src/pages/patient/DiagnosticReport/components/AnimalBaseInfo.tsx
+- src/assets/i18n/messages/zh.js
+- src/assets/i18n/messages/en.js
+- scripts/output/i18n/zh.js
+- scripts/output/i18n/en.js
+- CHANGELOG.md
+- package.json (版本更新: 1.20.2 -> 1.21.0)
+
+---
+
 ## [1.20.2] - 2025-12-22 16:36
 
 ### 新增 (Added)

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "zsis",
-  "version": "1.20.2",
+  "version": "1.21.0",
   "private": true,
   "description": "医学成像系统",
   "main": "main.js",

+ 7 - 1
scripts/output/i18n/en.js

@@ -160,6 +160,7 @@
   "register.variety.placeholder": "Enter variety",
   "register.patientType": "Patient Type",
   "register.patientType.placeholder": "Enter patient type",
+  "animal.register.patientType": "Pet Type",
   "register.operatorId": "Operator ID",
   "register.operatorId.placeholder": "Enter operator ID",
   "register.modality": "Modality",
@@ -258,5 +259,10 @@
   "exam.action.toggleCamera": "Toggle Camera",
   "exam.action.reject": "Reject",
   "exam.action.restore": "Restore",
-  "exam.action.addMorePositions": "Add More Positions"
+  "exam.action.addMorePositions": "Add More Positions",
+  "report.requestingDepartment": "Requesting Department",
+  "report.inspectionNumber": "Inspection Number",
+  "report.inspectionMethod": "Inspection Method",
+  "report.radiologist": "Radiologist",
+  "report.reviewPhysician": "Review Physician"
 }

+ 7 - 1
scripts/output/i18n/zh.js

@@ -160,6 +160,7 @@
   "register.variety.placeholder": "请输入品种",
   "register.patientType": "患者类型",
   "register.patientType.placeholder": "请输入患者类型",
+  "animal.register.patientType": "宠物类型",
   "register.operatorId": "操作员ID",
   "register.operatorId.placeholder": "请输入操作员ID",
   "register.modality": "物理疗法",
@@ -258,5 +259,10 @@
   "exam.action.toggleCamera": "打开/关闭摄像头",
   "exam.action.reject": "拒绝",
   "exam.action.restore": "恢复",
-  "exam.action.addMorePositions": "添加更多体位"
+  "exam.action.addMorePositions": "添加更多体位",
+  "report.requestingDepartment": "申请科室",
+  "report.inspectionNumber": "检查号",
+  "report.inspectionMethod": "检查方法",
+  "report.radiologist": "放射科医生",
+  "report.reviewPhysician": "审核医师"
 }

+ 7 - 1
src/assets/i18n/messages/en.js

@@ -162,6 +162,7 @@ export default {
   "register.variety.placeholder": "Enter variety",
   "register.patientType": "Patient Type",
   "register.patientType.placeholder": "Enter patient type",
+  "animal.register.patientType": "Pet Type",
   "register.operatorId": "Operator ID",
   "register.operatorId.placeholder": "Enter operator ID",
   "register.modality": "Modality",
@@ -260,5 +261,10 @@ export default {
   "exam.action.toggleCamera": "Toggle Camera",
   "exam.action.reject": "Reject",
   "exam.action.restore": "Restore",
-  "exam.action.addMorePositions": "Add More Positions"
+  "exam.action.addMorePositions": "Add More Positions",
+  "report.requestingDepartment": "Requesting Department",
+  "report.inspectionNumber": "Inspection Number",
+  "report.inspectionMethod": "Inspection Method",
+  "report.radiologist": "Radiologist",
+  "report.reviewPhysician": "Review Physician"
 };

+ 7 - 1
src/assets/i18n/messages/zh.js

@@ -162,6 +162,7 @@ export default {
   "register.variety.placeholder": "请输入品种",
   "register.patientType": "患者类型",
   "register.patientType.placeholder": "请输入患者类型",
+  "animal.register.patientType": "宠物类型",
   "register.operatorId": "操作员ID",
   "register.operatorId.placeholder": "请输入操作员ID",
   "register.modality": "物理疗法",
@@ -260,5 +261,10 @@ export default {
   "exam.action.toggleCamera": "打开/关闭摄像头",
   "exam.action.reject": "拒绝",
   "exam.action.restore": "恢复",
-  "exam.action.addMorePositions": "添加更多体位"
+  "exam.action.addMorePositions": "添加更多体位",
+  "report.requestingDepartment": "申请科室",
+  "report.inspectionNumber": "检查号",
+  "report.inspectionMethod": "检查方法",
+  "report.radiologist": "放射科医生",
+  "report.reviewPhysician": "审核医师"
 };

+ 77 - 9
src/pages/patient/DiagnosticReport/components/AnimalBaseInfo.tsx

@@ -9,6 +9,7 @@ import {
 import { useSelector } from 'react-redux';
 import { useEffect } from 'react';
 import { Task, TaskAnimal } from '@/domain/work';
+import { useIntl, FormattedMessage } from 'react-intl';
 
 const { Option } = Select;
 
@@ -19,6 +20,10 @@ export const AnimalBaseInfo: React.FC = () => {
     (s: RootState) => s.workSelection.selectedIds
   );
   const workEntities = useSelector((s: RootState) => s.workEntities.data);
+  const productName = useSelector(
+    (s: RootState) => s.product.productName
+  );
+  const intl = useIntl();
   console.log(`【诊断报告】:选中的study id :${selectedIds[0]}`);
   const selectedStudy: Task | TaskAnimal | null =
     selectedIds.length > 0
@@ -73,7 +78,14 @@ export const AnimalBaseInfo: React.FC = () => {
     <Form layout="vertical">
       <Row gutter={12}>
         <Col span={6}>
-          <Form.Item label="患者姓名">
+          <Form.Item
+            label={
+              <FormattedMessage
+                id={productName === 'VETDROS' ? 'animal.register.patientName' : 'register.patientName'}
+                defaultMessage={productName === 'VETDROS' ? 'animal.register.patientName' : 'register.patientName'}
+              />
+            }
+          >
             <Input
               value={data.patientName}
               onChange={(e) => onChange('patientName', e.target.value)}
@@ -81,7 +93,14 @@ export const AnimalBaseInfo: React.FC = () => {
           </Form.Item>
         </Col>
         <Col span={6}>
-          <Form.Item label="性别">
+          <Form.Item
+            label={
+              <FormattedMessage
+                id="register.gender"
+                defaultMessage="register.gender"
+              />
+            }
+          >
             <Select
               value={data.sex}
               onChange={(v) => onDropdownChange('sex', v)}
@@ -92,7 +111,14 @@ export const AnimalBaseInfo: React.FC = () => {
           </Form.Item>
         </Col>
         <Col span={6}>
-          <Form.Item label="年龄">
+          <Form.Item
+            label={
+              <FormattedMessage
+                id="register.age"
+                defaultMessage="register.age"
+              />
+            }
+          >
             <Input
               value={data.age}
               onChange={(e) => onChange('age', e.target.value)}
@@ -100,7 +126,14 @@ export const AnimalBaseInfo: React.FC = () => {
           </Form.Item>
         </Col>
         <Col span={6}>
-          <Form.Item label="主人姓名">
+          <Form.Item
+            label={
+              <FormattedMessage
+                id="register.owner_name"
+                defaultMessage="register.owner_name"
+              />
+            }
+          >
             <Input
               value={data.ownerName}
               onChange={(e) => onChange('ownerName', e.target.value)}
@@ -108,7 +141,14 @@ export const AnimalBaseInfo: React.FC = () => {
           </Form.Item>
         </Col>
         <Col span={6}>
-          <Form.Item label="申请科室">
+          <Form.Item
+            label={
+              <FormattedMessage
+                id="report.requestingDepartment"
+                defaultMessage="report.requestingDepartment"
+              />
+            }
+          >
             <Input
               value={data.requestingDepartment}
               onChange={(e) => onChange('requestingDepartment', e.target.value)}
@@ -116,7 +156,14 @@ export const AnimalBaseInfo: React.FC = () => {
           </Form.Item>
         </Col>
         <Col span={6}>
-          <Form.Item label="检查号">
+          <Form.Item
+            label={
+              <FormattedMessage
+                id="report.inspectionNumber"
+                defaultMessage="report.inspectionNumber"
+              />
+            }
+          >
             <Input
               value={data.inspectionNumber}
               onChange={(e) => onChange('inspectionNumber', e.target.value)}
@@ -124,7 +171,14 @@ export const AnimalBaseInfo: React.FC = () => {
           </Form.Item>
         </Col>
         <Col span={6}>
-          <Form.Item label="检查方法">
+          <Form.Item
+            label={
+              <FormattedMessage
+                id="report.inspectionMethod"
+                defaultMessage="report.inspectionMethod"
+              />
+            }
+          >
             <Input
               value={data.inspectionMethod}
               onChange={(e) => onChange('inspectionMethod', e.target.value)}
@@ -132,7 +186,14 @@ export const AnimalBaseInfo: React.FC = () => {
           </Form.Item>
         </Col>
         <Col span={6}>
-          <Form.Item label="放射科医生">
+          <Form.Item
+            label={
+              <FormattedMessage
+                id="report.radiologist"
+                defaultMessage="report.radiologist"
+              />
+            }
+          >
             <Input
               value={data.radiologist}
               onChange={(e) => onChange('radiologist', e.target.value)}
@@ -140,7 +201,14 @@ export const AnimalBaseInfo: React.FC = () => {
           </Form.Item>
         </Col>
         <Col span={6}>
-          <Form.Item label="审核医师">
+          <Form.Item
+            label={
+              <FormattedMessage
+                id="report.reviewPhysician"
+                defaultMessage="report.reviewPhysician"
+              />
+            }
+          >
             <Input
               value={data.reviewPhysician}
               onChange={(e) => onChange('reviewPhysician', e.target.value)}

+ 8 - 1
src/pages/patient/components/RegisterAvailableFilterBar.tsx

@@ -40,6 +40,9 @@ const RegisterAvailableFilterBar: React.FC<Props> = ({
   const patientTypes = useSelector(
     (state: RootState) => state.patientType.items
   ); // [{ label, value }]
+  const productName = useSelector(
+    (state: RootState) => state.product.productName
+  );
   // const enabledOptions = [
   //   { label: '全部', value: undefined },
   //   { label: '启用', value: 'enabled' },
@@ -54,6 +57,10 @@ const RegisterAvailableFilterBar: React.FC<Props> = ({
     id: 'register.filter.protocol',
     defaultMessage: 'register.filter.protocol',
   });
+  const patientTypePlaceholder = intl.formatMessage({
+    id: productName === 'VETDROS' ? 'animal.register.patientType' : 'register.patientType',
+    defaultMessage: productName === 'VETDROS' ? '宠物类型' : '患者类型',
+  });
   return (
     <div
       className="absolute top-0 left-0 right-0 z-10"
@@ -84,7 +91,7 @@ const RegisterAvailableFilterBar: React.FC<Props> = ({
           <Select
             allowClear
             style={{ width: '100%' }}
-            placeholder="患者类型"
+            placeholder={patientTypePlaceholder}
             options={patientTypes.map((item: PatientType) => ({
               label: intl.formatMessage({
                 id: `register.${item.patient_type_name.toLowerCase()}`,