CaseForm.vue 7.55 KB
<template>
  <el-dialog
    v-model="visible"
    :title="isEdit ? '编辑患者病例' : '新增患者病例'"
    width="600px"
    destroy-on-close
    :close-on-click-modal="false"
    @close="handleCancel"
  >
    <el-scrollbar max-height="60vh">
      <el-form
        ref="formRef"
        :model="form"
        :rules="rules"
        label-width="120px"
        class="case-form"
      >
        <el-form-item label="患者病例编号" prop="caseNumber">
          <el-input v-model="form.caseNumber" placeholder="请输入患者病例编号" />
        </el-form-item>

        <el-form-item label="姓名" prop="name">
          <el-input v-model="form.name" placeholder="请输入姓名" />
        </el-form-item>

        <el-form-item label="性别" prop="gender">
          <el-select v-model="form.gender" placeholder="请选择性别" style="width: 100%">
            <el-option label="男" value="男" />
            <el-option label="女" value="女" />
          </el-select>
        </el-form-item>

        <el-form-item label="出生日期" prop="birthday">
          <el-date-picker
            v-model="form.birthday"
            type="date"
            placeholder="请选择出生日期"
            style="width: 100%"
            value-format="YYYY-MM-DD"
            @change="handleBirthdayChange"
          />
        </el-form-item>

        <el-form-item label="年龄" prop="age">
          <el-input-number
            v-model="form.age"
            :min="0"
            :max="150"
            placeholder="请输入年龄"
            style="width: 100%"
          />
        </el-form-item>

        <el-form-item label="身份证号" prop="idCard">
          <el-input v-model="form.idCard" placeholder="请输入身份证号" />
        </el-form-item>

        <el-form-item label="血型" prop="bloodType">
          <el-select v-model="form.bloodType" placeholder="请选择血型" style="width: 100%">
            <el-option label="A型" value="A" />
            <el-option label="B型" value="B" />
            <el-option label="O型" value="O" />
            <el-option label="AB型" value="AB" />
          </el-select>
        </el-form-item>

        <el-form-item label="婚姻状况" prop="maritalStatus">
          <el-select v-model="form.maritalStatus" placeholder="请选择婚姻状况" style="width: 100%">
            <el-option label="未婚" value="未婚" />
            <el-option label="已婚" value="已婚" />
            <el-option label="离异" value="离异" />
            <el-option label="丧偶" value="丧偶" />
          </el-select>
        </el-form-item>

        <el-form-item label="在院状态" prop="hospitalStatus">
          <el-select v-model="form.hospitalStatus" placeholder="请选择在院状态" style="width: 100%">
            <el-option label="住院" value="住院" />
            <el-option label="出院" value="出院" />
            <el-option label="转院" value="转院" />
          </el-select>
        </el-form-item>

        <el-form-item label="医生 ID" prop="doctorId">
          <el-input v-model="form.doctorId" placeholder="请输入医生 ID" />
        </el-form-item>
      </el-form>
    </el-scrollbar>

    <template #footer>
      <div class="dialog-footer">
        <el-button @click="handleCancel">取消</el-button>
        <el-button 
          type="primary" 
          :loading="submitting" 
          :disabled="!isFormValid"
          @click="handleSubmit"
        >
          确认添加
        </el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script setup lang="ts">
import { ref, reactive, computed, watch } from 'vue';
import type { FormInstance, FormRules } from 'element-plus';
import { ElMessage } from 'element-plus';

const props = defineProps<{
  modelValue: boolean;
  initialData?: any;
}>();

const emit = defineEmits(['update:modelValue', 'submit']);

const visible = computed({
  get: () => props.modelValue,
  set: (val) => emit('update:modelValue', val)
});

const isEdit = computed(() => !!props.initialData?.id);
const formRef = ref<FormInstance>();
const submitting = ref(false);

const form = reactive({
  caseNumber: '',
  name: '',
  gender: '',
  birthday: '',
  age: undefined as number | undefined,
  idCard: '',
  bloodType: '',
  maritalStatus: '',
  hospitalStatus: '',
  doctorId: ''
});

// 必填项校验
const isFormValid = computed(() => {
  return form.caseNumber && form.name && form.gender && 
         form.birthday && form.age !== undefined && 
         form.idCard && form.hospitalStatus && 
         form.bloodType && form.maritalStatus && form.doctorId;
});

// 身份证校验逻辑
const validateIdCard = (rule: any, value: string, callback: any) => {
  const reg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
  if (value && !reg.test(value)) {
    callback(new Error('请输入正确的身份证号格式'));
  } else {
    callback();
  }
};

// 年龄与出生日期逻辑校验
const validateAgeBirthday = (rule: any, value: any, callback: any) => {
  if (form.birthday && form.age !== undefined) {
    const birthYear = new Date(form.birthday).getFullYear();
    const currentYear = new Date().getFullYear();
    const calculatedAge = currentYear - birthYear;
    if (Math.abs(calculatedAge - form.age) > 1) {
      callback(new Error('年龄与出生日期不匹配'));
    } else {
      callback();
    }
  } else {
    callback();
  }
};

const rules = reactive<FormRules>({
  caseNumber: [{ required: true, message: '请输入患者病例编号', trigger: 'blur' }],
  name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
  gender: [{ required: true, message: '请选择性别', trigger: 'change' }],
  birthday: [{ required: true, message: '请选择出生日期', trigger: 'change' }],
  age: [
    { required: true, message: '请输入年龄', trigger: 'blur' },
    { validator: validateAgeBirthday, trigger: 'blur' }
  ],
  idCard: [
    { required: true, message: '请输入身份证号', trigger: 'blur' },
    { validator: validateIdCard, trigger: 'blur' }
  ],
  bloodType: [{ required: true, message: '请选择血型', trigger: 'change' }],
  maritalStatus: [{ required: true, message: '请选择婚姻状况', trigger: 'change' }],
  hospitalStatus: [{ required: true, message: '请选择在院状态', trigger: 'change' }],
  doctorId: [{ required: true, message: '请输入医生 ID', trigger: 'blur' }]
});

// 自动计算年龄
const handleBirthdayChange = (val: string) => {
  if (val) {
    const birthDate = new Date(val);
    const today = new Date();
    let age = today.getFullYear() - birthDate.getFullYear();
    const m = today.getMonth() - birthDate.getMonth();
    if (m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) {
      age--;
    }
    form.age = age;
  }
};

const handleCancel = () => {
  visible.value = false;
  formRef.value?.resetFields();
};

const handleSubmit = async () => {
  if (!formRef.value) return;
  
  await formRef.value.validate((valid) => {
    if (valid) {
      submitting.value = true;
      // 模拟提交
      setTimeout(() => {
        submitting.value = false;
        ElMessage.success(isEdit.value ? '修改成功' : '添加成功');
        emit('submit', { ...form });
        handleCancel();
      }, 800);
    } else {
      ElMessage.warning('请完善表单信息');
    }
  });
};

watch(() => props.initialData, (newVal) => {
  if (newVal) {
    Object.assign(form, newVal);
  } else {
    formRef.value?.resetFields();
  }
}, { immediate: true });
</script>

<style scoped lang="scss">
.case-form {
  padding-right: 20px;
}

.dialog-footer {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}
</style>