Files
his/openhis-ui-vue3/src/views/doctorstation/components/infectiousReport/index.vue
chenqi 0b361df0a4 fix(doctorstation): 统一儿童患者家长姓名输入框提示文本
- 将诊断组件中家长姓名输入框占位符从"≤14 岁必填"改为"≤14岁必填"
- 将传染病报告组件中家长姓名输入框占位符统一为"≤14岁必填"
- 移除多余的条件判断逻辑,简化占位符显示逻辑
2026-03-27 11:56:39 +08:00

1225 lines
38 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="infectious-report-container">
<!-- 标题区 -->
<div class="report-header">
<h1 class="report-title">中华人民共和国传染病报告卡</h1>
<div class="card-number-row">
<span class="card-number-label">卡片编号</span>
<el-input
v-model="form.cardNo"
class="card-number-input"
placeholder="系统自动生成"
disabled
/>
</div>
</div>
<!-- 表单区域 -->
<div class="report-form" v-loading="loading">
<el-form ref="formRef" :model="form" :rules="rules" label-position="top">
<!-- 患者基本信息 -->
<div class="section-title">
<span class="title-text">患者基本信息</span>
</div>
<!-- 患者姓名家长姓名身份证号 -->
<el-row :gutter="16" class="form-row">
<el-col :span="8">
<el-form-item label="患者姓名" prop="patName" required>
<el-input v-model="form.patName" placeholder="请输入患者姓名" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item :label="'家长姓名' + (isChildPatient ? '' : '')" :prop="isChildPatient ? 'parentName' : ''" :required="isChildPatient">
<el-input v-model="form.parentName" placeholder="≤14岁必填" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="身份证号" prop="idNo" required>
<el-input v-model="form.idNo" placeholder="请输入身份证号" maxlength="18" @change="handleIdCardChange" />
</el-form-item>
</el-col>
</el-row>
<!-- 性别出生日期实足年龄 -->
<el-row :gutter="16" class="form-row">
<el-col :span="6">
<el-form-item label="性别" prop="sex" required>
<el-radio-group v-model="form.sex">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
<el-radio label="未知">未知</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="10">
<el-form-item label="出生日期" required>
<div class="date-inputs">
<el-input v-model="form.birthYear" placeholder="年" maxlength="4" @change="calculateAge" style="width: 80px" />
<span></span>
<el-input v-model="form.birthMonth" placeholder="月" maxlength="2" @change="calculateAge" style="width: 60px" />
<span></span>
<el-input v-model="form.birthDay" placeholder="日" maxlength="2" @change="calculateAge" style="width: 60px" />
<span></span>
</div>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="或 实足年龄">
<div class="age-inputs">
<el-input v-model="form.age" placeholder="年龄" style="width: 100px" />
<el-select v-model="form.ageUnit" style="width: 80px">
<el-option label="岁" value="岁" />
<el-option label="月" value="月" />
<el-option label="天" value="天" />
</el-select>
</div>
</el-form-item>
</el-col>
</el-row>
<!-- 工作单位 -->
<el-row :gutter="16" class="form-row">
<el-col :span="24">
<el-form-item label="工作单位(学校)">
<el-input v-model="form.workplace" placeholder="请输入工作单位" />
</el-form-item>
</el-col>
</el-row>
<!-- 联系电话紧急联系人电话 -->
<el-row :gutter="16" class="form-row">
<el-col :span="12">
<el-form-item label="联系电话" prop="phone" required>
<el-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="紧急联系人电话" prop="contactPhone" required>
<el-input v-model="form.contactPhone" placeholder="请输入紧急联系人电话" maxlength="11" />
</el-form-item>
</el-col>
</el-row>
<!-- 现住地址 -->
<el-row :gutter="16" class="form-row">
<el-col :span="24">
<el-form-item label="现住地址" required>
<el-cascader
v-model="addressCodes"
:options="addressOptions"
:props="addressCascaderProps"
placeholder="请选择省/市/区县/街道"
clearable
style="width: 100%"
@change="handleAddressChange"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16" class="form-row">
<el-col :span="12">
<el-input v-model="form.addressVillage" placeholder="村(居)" />
</el-col>
<el-col :span="12">
<el-input v-model="form.addressHouse" placeholder="门牌号" />
</el-col>
</el-row>
<!-- 病人属于 -->
<el-row :gutter="16" class="form-row">
<el-col :span="24">
<el-form-item label="病人属于" prop="patientBelong" required>
<el-radio-group v-model="form.patientBelong">
<el-radio label="1">本县区</el-radio>
<el-radio label="2">本市其他县区</el-radio>
<el-radio label="3">本省其他地市</el-radio>
<el-radio label="4">外省</el-radio>
<el-radio label="5">港澳台</el-radio>
<el-radio label="6">外籍</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<!-- 职业 -->
<el-row :gutter="16" class="form-row">
<el-col :span="12">
<el-form-item label="职业" prop="occupation" required>
<el-select v-model="form.occupation" placeholder="请选择职业" style="width: 100%">
<el-option v-for="item in occupationList" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="病例分类" prop="caseClass" required>
<el-radio-group v-model="form.caseClass">
<el-radio label="1">疑似病例</el-radio>
<el-radio label="2">临床诊断病例</el-radio>
<el-radio label="3">确诊病例</el-radio>
<el-radio label="4">病原携带者</el-radio>
<el-radio label="5">阳性检测结果</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<!-- 发病日期诊断日期死亡日期 -->
<el-row :gutter="16" class="form-row">
<el-col :span="8">
<el-form-item label="发病日期" prop="onsetDate" required>
<el-date-picker
v-model="form.onsetDate"
type="date"
placeholder="选择日期"
style="width: 100%"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="诊断日期" prop="diagDate" required>
<el-date-picker
v-model="form.diagDate"
type="date"
placeholder="选择日期"
style="width: 100%"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="死亡日期">
<el-date-picker
v-model="form.deathDate"
type="date"
placeholder="选择日期"
style="width: 100%"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 疾病名称选择区 -->
<div class="section-title">
<span class="title-text">疾病名称勾选或补填</span>
</div>
<!-- 甲类传染病 -->
<div class="disease-section">
<div class="disease-title">甲类传染病</div>
<div class="disease-list">
<el-checkbox
:model-value="form.selectedClassA === '0101'"
@update:model-value="(checked) => handleClassACheckbox('0101', checked)"
>鼠疫</el-checkbox>
<el-checkbox
:model-value="form.selectedClassA === '0102'"
@update:model-value="(checked) => handleClassACheckbox('0102', checked)"
>霍乱</el-checkbox>
</div>
</div>
<!-- 乙类传染病 -->
<div class="disease-section">
<div class="disease-title">乙类传染病</div>
<div class="disease-list four-columns">
<el-checkbox
v-for="disease in classBDiseases"
:key="disease.code"
:model-value="form.selectedClassB === disease.code"
@update:model-value="(checked) => handleClassBCheckbox(disease.code, checked)"
>{{ disease.name }}</el-checkbox>
</div>
</div>
<!-- 丙类传染病 -->
<div class="disease-section">
<div class="disease-title">丙类传染病</div>
<div class="disease-list four-columns">
<el-checkbox
v-for="disease in classCDiseases"
:key="disease.code"
:model-value="form.selectedClassC === disease.code"
@update:model-value="(checked) => handleClassCCheckbox(disease.code, checked)"
>{{ disease.name }}</el-checkbox>
</div>
</div>
<!-- 其他法定管理传染病 + 分型选择 -->
<el-row :gutter="16" class="form-row">
<el-col :span="showSubtypeSelect ? 16 : 24">
<el-form-item label="其他法定管理以及重点监测传染病">
<el-input v-model="form.otherDisease" placeholder="手动输入非列表疾病" />
</el-form-item>
</el-col>
<el-col v-if="showSubtypeSelect" :span="8">
<el-form-item label="分型" prop="diseaseType" :required="showSubtypeSelect">
<el-select v-model="form.diseaseType" placeholder="请选择分型" style="width: 100%">
<el-option
v-for="option in currentSubtypeOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<!-- 报告信息区 -->
<div class="section-title">
<span class="title-text">报告信息</span>
</div>
<el-row :gutter="16" class="form-row">
<el-col :span="8">
<el-form-item label="报告单位">
<el-input v-model="form.reportOrg" disabled />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系电话">
<el-input v-model="form.reportOrgPhone" placeholder="请输入联系电话" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="报告医生" required>
<el-input v-model="form.reportDoc" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16" class="form-row">
<el-col :span="8">
<el-form-item label="填卡日期" prop="reportDate" required>
<el-date-picker
v-model="form.reportDate"
type="date"
placeholder="选择日期"
style="width: 100%"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="订正病名">
<el-input v-model="form.correctName" placeholder="请输入订正病名" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="退卡原因">
<el-input v-model="form.withdrawReason" placeholder="请输入退卡原因" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16" class="form-row">
<el-col :span="24">
<el-form-item label="备注">
<el-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<!-- 操作按钮区 -->
<div class="action-buttons">
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">保 存</el-button>
<el-button @click="handleReset"> </el-button>
</div>
</div>
</template>
<script setup>
import { ref, computed, watch, getCurrentInstance, onMounted } from 'vue';
import pcas from 'china-division/dist/pcas-code.json';
import { saveInfectiousDiseaseReport, getNextCardNo, listInfectiousCards } from '../api';
import useUserStore from '@/store/modules/user';
import { useDict } from '@/utils/dict';
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
// 获取职业字典数据
const { prfs: occupationList } = useDict('prfs');
// 公共常量
const PHONE_REGEX = /^1[3-9]\d{9}$|^0\d{2,3}-?\d{7,8}$/;
const DISEASE_NAMES = {
'0203': '病毒性肝炎',
'0211': '炭疽',
'0213': '肺结核',
'0222': '梅毒',
'0224': '血吸虫病',
'0225': '疟疾'
};
// 乙类传染病列表
const classBDiseases = [
{ code: '0201', name: '传染性非典型肺炎' },
{ code: '0202', name: '艾滋病' },
{ code: '0203', name: '病毒性肝炎' },
{ code: '0204', name: '脊髓灰质炎' },
{ code: '0205', name: '人感染高致病性禽流感' },
{ code: '0206', name: '麻疹' },
{ code: '0207', name: '流行性出血热' },
{ code: '0208', name: '狂犬病' },
{ code: '0209', name: '流行性乙型脑炎' },
{ code: '0210', name: '登革热' },
{ code: '0211', name: '炭疽' },
{ code: '0212', name: '细菌性和阿米巴性痢疾' },
{ code: '0213', name: '肺结核' },
{ code: '0214', name: '伤寒和副伤寒' },
{ code: '0215', name: '流行性脑脊髓膜炎' },
{ code: '0216', name: '百日咳' },
{ code: '0217', name: '白喉' },
{ code: '0218', name: '新生儿破伤风' },
{ code: '0219', name: '猩红热' },
{ code: '0220', name: '布鲁氏菌病' },
{ code: '0221', name: '淋病' },
{ code: '0222', name: '梅毒' },
{ code: '0223', name: '钩端螺旋体病' },
{ code: '0224', name: '血吸虫病' },
{ code: '0225', name: '疟疾' },
];
// 丙类传染病列表
const classCDiseases = [
{ code: '0301', name: '流行性感冒' },
{ code: '0302', name: '流行性腮腺炎' },
{ code: '0303', name: '风疹' },
{ code: '0304', name: '急性出血性结膜炎' },
{ code: '0305', name: '麻风病' },
{ code: '0306', name: '流行性和地方性斑疹伤寒' },
{ code: '0307', name: '黑热病' },
{ code: '0308', name: '包虫病' },
{ code: '0309', name: '丝虫病' },
{ code: '0310', name: '其它感染性腹泻病' },
{ code: '0311', name: '手足口病' },
];
const formRef = ref(null);
const loading = ref(false);
const submitLoading = ref(false);
const props = defineProps({
patientInfo: {
type: Object,
default: () => ({}),
},
activeTab: {
type: String,
default: '',
},
});
const emit = defineEmits(['saved']);
// 地址级联选择器配置
const addressOptions = ref(pcas);
const addressCodes = ref([]);
const municipalities = ['北京市', '天津市', '上海市', '重庆市'];
const addressCascaderProps = {
checkStrictly: true,
value: 'code',
label: 'name',
children: 'children'
};
const form = ref({
cardNo: '',
patName: '',
parentName: '',
idNo: '',
sex: '男',
birthYear: '',
birthMonth: '',
birthDay: '',
age: '',
ageUnit: '岁',
workplace: '',
phone: '',
contactPhone: '',
addressProv: '',
addressCity: '',
addressCounty: '',
addressTown: '',
addressVillage: '',
addressHouse: '',
patientBelong: '1',
occupation: '',
caseClass: '',
onsetDate: '',
diagDate: '',
deathDate: '',
selectedDiseases: [],
selectedClassA: '',
selectedClassB: '',
selectedClassC: '',
otherDisease: '',
diseaseType: '',
reportOrg: '',
reportOrgPhone: '',
reportDoc: '',
reportDate: '',
correctName: '',
withdrawReason: '',
remark: '',
encounterId: '',
patientId: '',
diagnosisId: '',
});
// 表单验证规则
const rules = {
patName: [{ required: true, message: '请输入患者姓名', trigger: 'blur' }],
idNo: [
{ required: true, message: '请输入身份证号', trigger: 'blur' },
{ pattern: /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/, message: '请输入有效的身份证号码', trigger: 'blur' }
],
phone: [
{ required: true, message: '请输入联系电话', trigger: 'blur' },
{ pattern: PHONE_REGEX, message: '请输入有效的联系电话', trigger: 'blur' }
],
contactPhone: [
{ required: true, message: '请输入紧急联系人电话', trigger: 'blur' },
{ pattern: PHONE_REGEX, message: '请输入有效的紧急联系人电话', trigger: 'blur' }
],
occupation: [{ required: true, message: '请选择职业', trigger: 'change' }],
caseClass: [{ required: true, message: '请选择病例分类', trigger: 'change' }],
patientBelong: [{ required: true, message: '请选择病人属于', trigger: 'change' }],
onsetDate: [{ required: true, message: '请选择发病日期', trigger: 'change' }],
diagDate: [{ required: true, message: '请选择诊断日期', trigger: 'change' }],
reportDate: [{ required: true, message: '请选择填卡日期', trigger: 'change' }],
};
// 疾病类型与分型选项映射
const diseaseSubtypeMap = {
'0213': [
{ label: '涂阳', value: '涂阳' },
{ label: '仅培阳', value: '仅培阳' },
{ label: '菌阴', value: '菌阴' },
{ label: '未痰检', value: '未痰检' }
],
'0222': [
{ label: 'Ⅰ期', value: 'Ⅰ期' },
{ label: 'Ⅱ期', value: 'Ⅱ期' },
{ label: 'Ⅲ期', value: 'Ⅲ期' },
{ label: '胎传', value: '胎传' },
{ label: '隐性', value: '隐性' }
],
'0211': [
{ label: '肺炭疽', value: '肺炭疽' },
{ label: '皮肤炭疽', value: '皮肤炭疽' },
{ label: '胃肠炭疽', value: '胃肠炭疽' },
{ label: '未分型', value: '未分型' }
],
'0203': [
{ label: '甲型', value: '甲型' },
{ label: '乙型', value: '乙型' },
{ label: '丙型', value: '丙型' },
{ label: '戊型', value: '戊型' }
],
'0225': [
{ label: '间日疟', value: '间日疟' },
{ label: '恶性疟', value: '恶性疟' },
{ label: '三日疟', value: '三日疟' },
{ label: '卵形疟', value: '卵形疟' },
{ label: '未分型', value: '未分型' }
],
'0224': [
{ label: '急性', value: '急性' },
{ label: '慢性', value: '慢性' },
{ label: '晚期', value: '晚期' },
{ label: '未分型', value: '未分型' }
]
};
// 需要分型的疾病编码列表
const diseasesRequiringSubtype = ['0203', '0211', '0213', '0222', '0224', '0225'];
// 计算当前选中的疾病对应的分型选项
const currentSubtypeOptions = computed(() => {
if (!form.value.selectedClassA && !form.value.selectedClassB && !form.value.selectedClassC) {
return [];
}
const selectedDisease = form.value.selectedClassA || form.value.selectedClassB || form.value.selectedClassC;
return diseaseSubtypeMap[selectedDisease] || [];
});
// 计算是否显示分型选择
const showSubtypeSelect = computed(() => {
return (form.value.selectedClassA || form.value.selectedClassB || form.value.selectedClassC) && currentSubtypeOptions.value.length > 0;
});
// 计算是否为14岁以下儿童
const isChildPatient = computed(() => {
const age = parseInt(form.value.age);
return !isNaN(age) && form.value.ageUnit === '岁' && age <= 14;
});
// 监听疾病选择变化,自动清空分型选择
watch(() => [form.value.selectedClassA, form.value.selectedClassB, form.value.selectedClassC], (newVal, oldVal) => {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
form.value.diseaseType = '';
}
updateSelectedDiseases();
}, { deep: true });
// 监听患者信息变化,自动填充表单
watch(() => props.patientInfo, (newVal) => {
if (newVal && Object.keys(newVal).length > 0) {
initForm();
}
}, { deep: true, immediate: true });
// 监听Tab切换重新初始化
watch(() => props.activeTab, (newVal) => {
if (newVal === 'infectiousReport' && props.patientInfo && Object.keys(props.patientInfo).length > 0) {
initForm();
}
});
// 获取当前日期
function getCurrentDate() {
const date = new Date();
const year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
month = month < 10 ? '0' + month : month;
day = day < 10 ? '0' + day : day;
return `${year}-${month}-${day}`;
}
// 解析出生日期
function parseBirthDate(birthDate) {
if (!birthDate) return { year: '', month: '', day: '' };
const date = new Date(birthDate);
if (Number.isNaN(date.getTime())) return { year: '', month: '', day: '' };
return {
year: date.getFullYear().toString(),
month: (date.getMonth() + 1).toString().padStart(2, '0'),
day: date.getDate().toString().padStart(2, '0'),
};
}
// 从身份证号解析出生日期和性别
function parseIdCardInfo(idNo) {
if (!idNo) return null;
idNo = idNo.trim().toUpperCase();
if (idNo.length === 18) {
const birthYear = idNo.substring(6, 10);
const birthMonth = idNo.substring(10, 12);
const birthDay = idNo.substring(12, 14);
const genderCode = idNo.substring(16, 17);
const birthDate = new Date(parseInt(birthYear), parseInt(birthMonth) - 1, parseInt(birthDay));
if (isNaN(birthDate.getTime())) return null;
return {
birthYear,
birthMonth,
birthDay,
sex: parseInt(genderCode, 10) % 2 === 1 ? '男' : '女',
birthDate: `${birthYear}-${birthMonth}-${birthDay}`
};
}
if (idNo.length === 15) {
const birthYear = '19' + idNo.substring(6, 8);
const birthMonth = idNo.substring(8, 10);
const birthDay = idNo.substring(10, 12);
const genderCode = idNo.substring(13, 14);
const birthDate = new Date(parseInt(birthYear), parseInt(birthMonth) - 1, parseInt(birthDay));
if (isNaN(birthDate.getTime())) return null;
return {
birthYear,
birthMonth,
birthDay,
sex: parseInt(genderCode, 10) % 2 === 1 ? '男' : '女',
birthDate: `${birthYear}-${birthMonth}-${birthDay}`
};
}
return null;
}
// 身份证号变化时自动填充
function handleIdCardChange(value) {
if (!value) return;
const info = parseIdCardInfo(value);
if (info) {
form.value.birthYear = info.birthYear;
form.value.birthMonth = info.birthMonth;
form.value.birthDay = info.birthDay;
form.value.sex = info.sex;
calculateAge();
}
}
// 计算年龄
function calculateAge() {
const { birthYear, birthMonth, birthDay } = form.value;
if (!birthYear || !birthMonth || !birthDay) return;
const birthDate = new Date(parseInt(birthYear), parseInt(birthMonth) - 1, parseInt(birthDay));
const today = new Date();
let age = today.getFullYear() - birthDate.getFullYear();
const monthDiff = today.getMonth() - birthDate.getMonth();
if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
age--;
}
if (age < 0) age = 0;
form.value.age = age.toString();
form.value.ageUnit = '岁';
}
// 地址选择变化处理
function handleAddressChange(values) {
if (!values || values.length === 0) {
form.value.addressProv = '';
form.value.addressCity = '';
form.value.addressCounty = '';
form.value.addressTown = '';
return;
}
const names = [];
let currentNodes = addressOptions.value;
for (const code of values) {
const node = currentNodes?.find(n => n.code === code);
if (node) {
names.push(node.name);
currentNodes = node.children;
}
}
const provName = names[0] || '';
let cityName = names[1] || '';
const countyName = names[2] || '';
const townName = names[3] || '';
if (municipalities.includes(provName)) {
form.value.addressProv = provName;
form.value.addressCity = provName;
form.value.addressCounty = cityName;
form.value.addressTown = countyName;
} else {
form.value.addressProv = provName;
form.value.addressCity = cityName;
form.value.addressCounty = countyName;
form.value.addressTown = townName;
}
}
// 根据地址名称数组查找对应的代码数组
function findCodesByNames(names) {
const codes = [];
let currentNodes = addressOptions.value;
for (const name of names) {
if (!name) break;
const node = currentNodes?.find(n => n.name === name);
if (node) {
codes.push(node.code);
currentNodes = node.children;
} else {
break;
}
}
return codes;
}
// 疾病选择处理
const handleDiseaseCheckbox = (category, value, checked) => {
if (checked) {
form.value[category] = value;
} else {
form.value[category] = '';
}
updateSelectedDiseases();
};
const handleClassACheckbox = (value, checked) => {
handleDiseaseCheckbox('selectedClassA', value, checked);
};
const handleClassBCheckbox = (value, checked) => {
handleDiseaseCheckbox('selectedClassB', value, checked);
};
const handleClassCCheckbox = (value, checked) => {
handleDiseaseCheckbox('selectedClassC', value, checked);
};
const updateSelectedDiseases = () => {
const diseases = [];
if (form.value.selectedClassA) diseases.push(form.value.selectedClassA);
if (form.value.selectedClassB) diseases.push(form.value.selectedClassB);
if (form.value.selectedClassC) diseases.push(form.value.selectedClassC);
form.value.selectedDiseases = diseases;
};
// 初始化表单
async function initForm() {
const patientInfo = props.patientInfo || {};
const birthInfo = parseBirthDate(patientInfo.birthDate || patientInfo.birthday);
// 生成默认卡片编号
const orgCode = userStore.fixmedinsCode || '0000';
let cardNo = '';
try {
const res = await getNextCardNo(orgCode);
if (res.code === 200 && res.data) {
cardNo = res.data;
}
} catch (err) {
console.error('获取卡片编号失败:', err);
}
form.value = {
cardNo: cardNo,
patName: patientInfo.patientName || patientInfo.name || '',
parentName: '',
idNo: patientInfo.idCard || '',
sex: patientInfo.genderName || (patientInfo.genderEnum === 1 ? '男' : patientInfo.genderEnum === 2 ? '女' : '未知'),
birthYear: birthInfo.year,
birthMonth: birthInfo.month,
birthDay: birthInfo.day,
age: patientInfo.age || '',
ageUnit: '岁',
workplace: patientInfo.workCompany || '',
phone: patientInfo.phone || '',
contactPhone: '',
addressProv: patientInfo.addressProvince || '',
addressCity: patientInfo.addressCity || '',
addressCounty: patientInfo.addressDistrict || '',
addressTown: patientInfo.addressStreet || '',
addressVillage: '',
addressHouse: '',
patientBelong: '1',
occupation: '',
caseClass: '',
onsetDate: getCurrentDate(),
diagDate: getCurrentDate(),
deathDate: '',
selectedDiseases: [],
selectedClassA: '',
selectedClassB: '',
selectedClassC: '',
otherDisease: '',
diseaseType: '',
reportOrg: userStore.orgName || '',
reportOrgPhone: '',
reportDoc: userStore.nickName || userStore.name || '',
reportDate: getCurrentDate(),
correctName: '',
withdrawReason: '',
remark: '',
encounterId: patientInfo.encounterId || '',
patientId: patientInfo.patientId || '',
diagnosisId: '',
};
// 设置地址选择器初始值
const provName = patientInfo.addressProvince || '';
const cityName = patientInfo.addressCity || '';
const countyName = patientInfo.addressDistrict || '';
const townName = patientInfo.addressStreet || '';
let names = [];
if (municipalities.includes(provName)) {
names = [provName, countyName, townName].filter(n => n);
} else {
names = [provName, cityName, countyName, townName].filter(n => n);
}
addressCodes.value = findCodesByNames(names);
if (birthInfo.year) {
calculateAge();
}
}
// 构建提交数据
function buildSubmitData() {
const formData = form.value;
let diseaseCode = '';
let diseaseType = null;
if (formData.selectedClassA || formData.selectedClassB || formData.selectedClassC) {
diseaseCode = formData.selectedClassA || formData.selectedClassB || formData.selectedClassC;
if (formData.diseaseType) {
diseaseType = formData.diseaseType;
}
} else if (formData.otherDisease) {
diseaseCode = 'OTHER';
}
const ageUnitMap = { '岁': '1', '月': '2', '天': '3' };
const submitData = {
cardNo: formData.cardNo,
visitId: props.patientInfo?.encounterId || formData.encounterId || null,
diagId: formData.diagnosisId || null,
patId: formData.patientId || null,
idType: 1,
idNo: formData.idNo,
patName: formData.patName || '',
parentName: formData.parentName || null,
sex: formData.sex === '男' ? '1' : formData.sex === '女' ? '2' : '0',
birthday: formData.birthYear && formData.birthMonth && formData.birthDay
? `${formData.birthYear}-${formData.birthMonth}-${formData.birthDay}`
: null,
age: formData.age ? parseInt(formData.age) : null,
ageUnit: ageUnitMap[formData.ageUnit] || '1',
workplace: formData.workplace || null,
phone: formData.phone || null,
contactPhone: formData.contactPhone || null,
addressProv: formData.addressProv || '',
addressCity: formData.addressCity || '',
addressCounty: formData.addressCounty || '',
addressTown: formData.addressTown || '',
addressVillage: formData.addressVillage || '',
addressHouse: formData.addressHouse || '',
patientBelong: parseInt(formData.patientBelong) || 1,
occupation: formData.occupation || null,
diseaseCode: diseaseCode || null,
diseaseType: diseaseType || null,
otherDisease: formData.otherDisease || null,
caseClass: formData.caseClass ? parseInt(formData.caseClass) : null,
onsetDate: formData.onsetDate || null,
diagDate: formData.diagDate ? `${formData.diagDate}T00:00:00` : null,
deathDate: formData.deathDate || null,
correctName: formData.correctName || null,
withdrawReason: formData.withdrawReason || null,
reportOrg: formData.reportOrg || '',
reportOrgPhone: formData.reportOrgPhone || null,
reportDoc: formData.reportDoc || '',
reportDate: formData.reportDate || null,
cardNameCode: 1,
registrationSource: 1,
status: 0,
deptId: props.patientInfo?.deptId || null,
doctorId: userStore.userId || null,
};
return submitData;
}
// 手动验证表单
function validateFormManually() {
const errors = [];
if (!form.value.idNo) {
errors.push('请输入身份证号');
} else {
const idCardReg = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
if (!idCardReg.test(form.value.idNo)) {
errors.push('请输入有效的身份证号码');
}
}
if (!form.value.phone) {
errors.push('请输入联系电话');
} else if (!PHONE_REGEX.test(form.value.phone)) {
errors.push('请输入有效的联系电话');
}
if (!form.value.contactPhone) {
errors.push('请输入紧急联系人电话');
} else if (!PHONE_REGEX.test(form.value.contactPhone)) {
errors.push('请输入有效的紧急联系人电话');
}
if (isChildPatient.value && !form.value.parentName) {
errors.push('14岁以下患者必须填写家长姓名');
}
if (!form.value.onsetDate) {
errors.push('请选择发病日期');
} else if (form.value.diagDate && new Date(form.value.onsetDate) > new Date(form.value.diagDate)) {
errors.push('发病日期不能晚于诊断日期');
}
if (!form.value.diagDate) {
errors.push('请选择诊断日期');
}
if (!form.value.reportDate) {
errors.push('请选择填卡日期');
}
if (!form.value.caseClass) {
errors.push('请选择病例分类');
}
if (!form.value.occupation) {
errors.push('请选择职业');
}
if (!form.value.patientBelong) {
errors.push('请选择病人属于');
}
if (!form.value.addressProv || !form.value.addressCity) {
errors.push('请至少选择省和市');
}
if (form.value.deathDate) {
if (form.value.diagDate && new Date(form.value.deathDate) < new Date(form.value.diagDate)) {
errors.push('死亡日期不能早于诊断日期');
}
if (new Date(form.value.deathDate) > new Date()) {
errors.push('死亡日期不能晚于当前日期');
}
}
const selectedDisease = form.value.selectedClassA || form.value.selectedClassB || form.value.selectedClassC;
if (diseasesRequiringSubtype.includes(selectedDisease) && !form.value.diseaseType) {
errors.push(`${DISEASE_NAMES[selectedDisease]}必须选择分型`);
}
if (errors.length > 0) {
proxy.$modal.msgError(errors[0]);
return false;
}
return true;
}
// 提交表单
async function handleSubmit() {
try {
if (!validateFormManually()) {
return;
}
if (form.value.selectedDiseases.length === 0 && !form.value.otherDisease) {
proxy.$modal.msgError('请至少选择一种疾病或填写其他传染病');
return;
}
submitLoading.value = true;
const submitData = buildSubmitData();
const res = await saveInfectiousDiseaseReport(submitData);
if (res.code === 200) {
proxy.$modal.msgSuccess('传染病报告卡保存成功');
emit('saved');
// 重新初始化表单,获取新的卡片编号
initForm();
} else {
proxy.$modal.msgError(res.msg || '保存失败');
}
} catch (err) {
console.error('传染病报告卡保存失败:', err);
proxy.$modal.msgError(err.message || '保存失败,请检查网络连接');
} finally {
submitLoading.value = false;
}
}
// 重置表单
function handleReset() {
const { patName, idNo, sex, birthYear, birthMonth, birthDay, age, ageUnit, phone, reportOrg, reportDoc, encounterId, patientId } = form.value;
formRef.value?.resetFields();
// 保留患者基本信息
form.value.patName = patName;
form.value.idNo = idNo;
form.value.sex = sex;
form.value.birthYear = birthYear;
form.value.birthMonth = birthMonth;
form.value.birthDay = birthDay;
form.value.age = age;
form.value.ageUnit = ageUnit;
form.value.phone = phone;
form.value.reportOrg = reportOrg;
form.value.reportDoc = reportDoc;
form.value.encounterId = encounterId;
form.value.patientId = patientId;
// 重置其他字段
form.value.reportDate = getCurrentDate();
form.value.onsetDate = getCurrentDate();
form.value.diagDate = getCurrentDate();
form.value.selectedClassA = '';
form.value.selectedClassB = '';
form.value.selectedClassC = '';
form.value.diseaseType = '';
form.value.parentName = '';
form.value.contactPhone = '';
form.value.occupation = '';
form.value.caseClass = '';
form.value.patientBelong = '1';
form.value.otherDisease = '';
form.value.correctName = '';
form.value.withdrawReason = '';
form.value.remark = '';
form.value.deathDate = '';
updateSelectedDiseases();
}
// 组件挂载时初始化
onMounted(() => {
if (props.patientInfo && Object.keys(props.patientInfo).length > 0) {
initForm();
}
});
// 暴露方法供父组件调用
defineExpose({
initForm
});
</script>
<style scoped>
.infectious-report-container {
height: 100%;
display: flex;
flex-direction: column;
background: #fff;
padding: 16px;
}
/* 标题区样式 */
.report-header {
text-align: center;
padding-bottom: 16px;
border-bottom: 2px solid #3498db;
margin-bottom: 16px;
}
.report-title {
color: #2c3e50;
font-size: 20px;
font-weight: bold;
margin: 0 0 12px 0;
}
.card-number-row {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
.card-number-label {
color: #666;
font-size: 12px;
}
.card-number-input {
width: 240px;
}
/* 表单区域样式 */
.report-form {
flex: 1;
overflow-y: auto;
padding-right: 8px;
}
.section-title {
margin: 16px 0 12px 0;
padding-bottom: 8px;
border-bottom: 2px solid #3498db;
}
.title-text {
color: #2c3e50;
font-size: 16px;
font-weight: bold;
}
.form-row {
margin-bottom: 8px;
}
.date-inputs {
display: flex;
align-items: center;
gap: 4px;
}
.date-inputs span {
color: #606266;
font-size: 14px;
}
.age-inputs {
display: flex;
align-items: center;
gap: 4px;
}
/* 疾病选择区样式 */
.disease-section {
margin-bottom: 12px;
padding: 12px;
border: 1px solid #e4e7ed;
border-radius: 4px;
background: #fafafa;
}
.disease-title {
color: #2c3e50;
font-size: 14px;
font-weight: bold;
margin-bottom: 10px;
padding-bottom: 6px;
border-bottom: 1px solid #e4e7ed;
}
.disease-list {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.disease-list :deep(.el-checkbox) {
width: calc(50% - 8px);
margin-right: 0;
}
.disease-list.four-columns :deep(.el-checkbox) {
width: calc(25% - 8px);
}
/* 操作按钮区样式 */
.action-buttons {
padding: 16px 0 0;
border-top: 1px solid #e4e7ed;
display: flex;
justify-content: center;
gap: 16px;
}
/* 响应式调整 */
@media (max-width: 1200px) {
.disease-list.four-columns :deep(.el-checkbox) {
width: calc(33.33% - 8px);
}
}
@media (max-width: 900px) {
.disease-list.four-columns :deep(.el-checkbox) {
width: calc(50% - 8px);
}
}
</style>