Browse Source

fix : 为年龄组件封装一个通用组件,包含数字和单位。同时添加默认年龄值和单位
fixes #18

sw 1 week ago
parent
commit
b0b69ce53a

+ 87 - 0
src/components/NumberWithUnit.tsx

@@ -0,0 +1,87 @@
+import React from 'react';
+import { InputNumber, Select, Space, SpaceProps } from 'antd';
+import type { InputNumberProps } from 'antd/es/input-number';
+import type { SelectProps } from 'antd/es/select';
+
+const { Option } = Select;
+
+export interface NumberUnitOption {
+  label: React.ReactNode;
+  value: string;
+}
+
+export interface NumberUnitValue {
+  number?: number;
+  unit?: string;
+}
+export type NumberWithUnitProps = SpaceProps & {
+  value?: NumberUnitValue;
+  onChange?: (next: NumberUnitValue) => void;
+  numberClassName?: string;
+  unitClassName?: string;
+  className?: string;
+  options: NumberUnitOption[];
+  defaultUnit?: string;
+  defaultNumber?: number;
+  numberProps?: Partial<InputNumberProps>;
+  selectProps?: Partial<SelectProps>;
+};
+
+const NumberWithUnit: React.FC<NumberWithUnitProps> = ({
+  value = {},
+  onChange,
+  numberClassName,
+  unitClassName,
+  className,
+  options,
+  defaultUnit,
+  defaultNumber,
+  numberProps,
+  selectProps,
+  onBlur,
+  ...rest // ← 这里会收到、style 等
+}) => {
+  const unit = value?.unit ?? defaultUnit ?? undefined;
+
+  const triggerChange = (changed: Partial<NumberUnitValue>) => {
+    onChange?.({ ...value, ...changed });
+  };
+
+  return (
+    <>
+      <style>{`
+            .my-space .ant-space-item:nth-child(1) {
+              width: 70%;
+            }
+            .my-space .ant-space-item:nth-child(2) {
+              width: 30%;
+            }
+        `}</style>
+      <Space {...rest} className={`${className}  my-space`}>
+        <InputNumber
+          className={numberClassName}
+          value={value?.number}
+          onChange={(n) =>
+            triggerChange({ number: typeof n === 'number' ? n : undefined })
+          }
+          {...numberProps}
+          defaultValue={defaultNumber}
+          onBlur={onBlur}
+        />
+        <Select
+          className={unitClassName}
+          value={unit}
+          onChange={(u) => triggerChange({ unit: u })}
+          {...selectProps}
+        >
+          {options.map((opt) => (
+            <Option key={opt.value} value={opt.value}>
+              {opt.label}
+            </Option>
+          ))}
+        </Select>
+      </Space>
+    </>
+  );
+};
+export default NumberWithUnit;

+ 20 - 19
src/pages/patient/components/register.form.tsx

@@ -7,10 +7,10 @@ import {
   Select,
   Radio,
   FormInstance,
-  Space,
 } from 'antd';
 import { useIntl, FormattedMessage } from 'react-intl';
 import { registerFormFields } from '@/validation/patient/registerSchema';
+import NumberWithUnit from '@/components/NumberWithUnit';
 
 const genderOptions = [
   {
@@ -68,6 +68,11 @@ interface BasicInfoFormProps {
   form?: FormInstance;
 }
 const BasicInfoForm: React.FC<BasicInfoFormProps> = ({ style, form }) => {
+  const patient_age = Form.useWatch('patient_age', form);
+  React.useEffect(() => {
+    console.log('patient_age 变化了:', patient_age); // 每次 NumberWithUnit onChange 都会触发
+  }, [patient_age]);
+
   const intl = useIntl();
   return (
     <Form form={form} layout="vertical" style={style} className="px-2">
@@ -161,25 +166,21 @@ const BasicInfoForm: React.FC<BasicInfoFormProps> = ({ style, form }) => {
         required={registerFormFields.patient_age.required}
         validateTrigger={registerFormFields.patient_age.trigger}
         rules={registerFormFields.patient_age.validation}
+        initialValue={{ number: 0, unit: 'Y' }}
       >
-        <>
-          <style>{`
-            .my-space .ant-space-item:nth-child(1) {
-              width: 70%;
-            }
-            .my-space .ant-space-item:nth-child(2) {
-              width: 30%;
-            }
-        `}</style>
-          <Space className="w-full my-space" align="baseline">
-            <InputNumber min={0} className="w-full" />
-            <Select>
-              <Select.Option value="D">天</Select.Option>
-              <Select.Option value="M">月</Select.Option>
-              <Select.Option value="Y">年</Select.Option>
-            </Select>
-          </Space>
-        </>
+        <NumberWithUnit
+          align="baseline"
+          defaultUnit="Y"
+          defaultNumber={0}
+          unitClassName="w-full"
+          numberClassName="w-full"
+          className="w-full"
+          options={[
+            { label: '天', value: 'D' },
+            { label: '月', value: 'M' },
+            { label: '年', value: 'Y' },
+          ]}
+        />
       </Form.Item>
       <Form.Item
         label={

+ 5 - 0
src/pages/patient/register.tsx

@@ -44,6 +44,10 @@ const RegisterPage: React.FC = () => {
   }> => {
     try {
       let values = form.getFieldsValue();
+      // //转换年龄
+      // console.log(`转换前的年龄值:${JSON.stringify(values.patient_age)}`)
+      // const age=`${values.patient_age.number}${values.patient_age.unit}`;
+      // console.log(`转换后的年龄和转换前的年龄:${age}---${values.patient_age}`)
       const formatDob = values.patient_dob
         ? dayjs.utc(values.patient_dob).format('YYYY-MM-DDTHH:mm:ss.SSS[Z]') //values.patient_dob.toString('YYYY-MM-DD[T00:00:00.000000Z]')
         : '';
@@ -66,6 +70,7 @@ const RegisterPage: React.FC = () => {
         patient_type: currentPatientType?.patient_type_id,
         modality: 'dx',
         study_type: 'Normal',
+        patient_age: `${values.patient_age.number}${values.patient_age.unit}`, //发送前转换为字符串
         views: selectedViews.map((view) => ({
           view_id: view.view_id,
           procedure_id: view.procedure_id,

+ 4 - 1
src/validation/patient/registerSchema.ts

@@ -18,7 +18,10 @@ const registerInfoSchema: Record<
   patient_name: z.string().nonempty(),
   patient_id: z.string().nonempty(),
   patient_size: z.string().nonempty(),
-  patient_age: z.string().nonempty(),
+  patient_age: z.object({
+    number: z.number(), // 必须是数字
+    unit: z.string(), // 必须是字符串(根据你的需求,也可以是 z.enum(...) 等)
+  }),
   patient_dob: z.string().nonempty(),
   patient_sex: z.string().optional(),
   sex_neutered: z.string().optional(),