103 增加医生个人报卡管理界面(需求)

This commit is contained in:
2026-04-14 17:23:44 +08:00
parent fe7778e6e0
commit 26e0665eeb
15 changed files with 833 additions and 507 deletions

View File

@@ -31,12 +31,12 @@
</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-input v-model="form.parentName" placeholder="≤14岁必填" :disabled="isReadOnly" />
</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-input v-model="form.idNo" placeholder="请输入身份证号" maxlength="18" :disabled="isReadOnly" @change="isReadOnly ? null : handleIdCardChange($event)" />
</el-form-item>
</el-col>
</el-row>
@@ -45,7 +45,7 @@
<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-group v-model="form.sex" :disabled="isReadOnly">
<el-radio label="男"></el-radio>
<el-radio label="女"></el-radio>
<el-radio label="未知">未知</el-radio>
@@ -55,11 +55,11 @@
<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" />
<el-input v-model="form.birthYear" placeholder="年" maxlength="4" :disabled="isReadOnly" @change="isReadOnly ? null : calculateAge()" style="width: 80px" />
<span></span>
<el-input v-model="form.birthMonth" placeholder="月" maxlength="2" @change="calculateAge" style="width: 60px" />
<el-input v-model="form.birthMonth" placeholder="月" maxlength="2" :disabled="isReadOnly" @change="isReadOnly ? null : calculateAge()" style="width: 60px" />
<span></span>
<el-input v-model="form.birthDay" placeholder="日" maxlength="2" @change="calculateAge" style="width: 60px" />
<el-input v-model="form.birthDay" placeholder="日" maxlength="2" :disabled="isReadOnly" @change="isReadOnly ? null : calculateAge()" style="width: 60px" />
<span></span>
</div>
</el-form-item>
@@ -67,8 +67,8 @@
<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-input v-model="form.age" placeholder="年龄" style="width: 100px" :disabled="isReadOnly" />
<el-select v-model="form.ageUnit" style="width: 80px" :disabled="isReadOnly">
<el-option label="岁" value="岁" />
<el-option label="月" value="月" />
<el-option label="天" value="天" />
@@ -82,7 +82,7 @@
<el-row :gutter="16" class="form-row">
<el-col :span="24">
<el-form-item label="工作单位(学校)">
<el-input v-model="form.workplace" placeholder="请输入工作单位" />
<el-input v-model="form.workplace" placeholder="请输入工作单位" :disabled="isReadOnly" />
</el-form-item>
</el-col>
</el-row>
@@ -91,12 +91,12 @@
<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-input v-model="form.phone" placeholder="请输入联系电话" maxlength="11" :disabled="isReadOnly" />
</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-input v-model="form.contactPhone" placeholder="请输入紧急联系人电话" maxlength="11" :disabled="isReadOnly" />
</el-form-item>
</el-col>
</el-row>
@@ -112,6 +112,7 @@
placeholder="请选择省/市/区县/街道"
clearable
style="width: 100%"
:disabled="isReadOnly"
@change="handleAddressChange"
/>
</el-form-item>
@@ -119,10 +120,10 @@
</el-row>
<el-row :gutter="16" class="form-row">
<el-col :span="12">
<el-input v-model="form.addressVillage" placeholder="村(居)" />
<el-input v-model="form.addressVillage" placeholder="村(居)" :disabled="isReadOnly" />
</el-col>
<el-col :span="12">
<el-input v-model="form.addressHouse" placeholder="门牌号" />
<el-input v-model="form.addressHouse" placeholder="门牌号" :disabled="isReadOnly" />
</el-col>
</el-row>
@@ -130,13 +131,13 @@
<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 v-model="form.patientBelong" :disabled="isReadOnly">
<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>
@@ -146,14 +147,14 @@
<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-select v-model="form.occupation" placeholder="请选择职业" style="width: 100%" :disabled="isReadOnly">
<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-group v-model="form.caseClass" :disabled="isReadOnly">
<el-radio label="1">疑似病例</el-radio>
<el-radio label="2">临床诊断病例</el-radio>
<el-radio label="3">确诊病例</el-radio>
@@ -175,6 +176,7 @@
style="width: 100%"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
:disabled="isReadOnly"
/>
</el-form-item>
</el-col>
@@ -187,6 +189,7 @@
style="width: 100%"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
:disabled="isReadOnly"
/>
</el-form-item>
</el-col>
@@ -199,6 +202,7 @@
style="width: 100%"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
:disabled="isReadOnly"
/>
</el-form-item>
</el-col>
@@ -215,11 +219,13 @@
<div class="disease-list">
<el-checkbox
:model-value="form.selectedClassA === '0101'"
@update:model-value="(checked) => handleClassACheckbox('0101', checked)"
:disabled="isReadOnly"
@update:model-value="(checked) => isReadOnly ? null : handleClassACheckbox('0101', checked)"
>鼠疫</el-checkbox>
<el-checkbox
:model-value="form.selectedClassA === '0102'"
@update:model-value="(checked) => handleClassACheckbox('0102', checked)"
:disabled="isReadOnly"
@update:model-value="(checked) => isReadOnly ? null : handleClassACheckbox('0102', checked)"
>霍乱</el-checkbox>
</div>
</div>
@@ -232,7 +238,8 @@
v-for="disease in classBDiseases"
:key="disease.code"
:model-value="form.selectedClassB === disease.code"
@update:model-value="(checked) => handleClassBCheckbox(disease.code, checked)"
:disabled="isReadOnly"
@update:model-value="(checked) => isReadOnly ? null : handleClassBCheckbox(disease.code, checked)"
>{{ disease.name }}</el-checkbox>
</div>
</div>
@@ -245,7 +252,8 @@
v-for="disease in classCDiseases"
:key="disease.code"
:model-value="form.selectedClassC === disease.code"
@update:model-value="(checked) => handleClassCCheckbox(disease.code, checked)"
:disabled="isReadOnly"
@update:model-value="(checked) => isReadOnly ? null : handleClassCCheckbox(disease.code, checked)"
>{{ disease.name }}</el-checkbox>
</div>
</div>
@@ -254,12 +262,12 @@
<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-input v-model="form.otherDisease" placeholder="手动输入非列表疾病" :disabled="isReadOnly" />
</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-select v-model="form.diseaseType" placeholder="请选择分型" style="width: 100%" :disabled="isReadOnly">
<el-option
v-for="option in currentSubtypeOptions"
:key="option.value"
@@ -284,7 +292,7 @@
</el-col>
<el-col :span="8">
<el-form-item label="联系电话">
<el-input v-model="form.reportOrgPhone" placeholder="请输入联系电话" />
<el-input v-model="form.reportOrgPhone" placeholder="请输入联系电话" :disabled="isReadOnly" />
</el-form-item>
</el-col>
<el-col :span="8">
@@ -304,17 +312,18 @@
style="width: 100%"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
:disabled="isReadOnly"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="订正病名">
<el-input v-model="form.correctName" placeholder="请输入订正病名" />
<el-input v-model="form.correctName" placeholder="请输入订正病名" :disabled="isReadOnly" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="退卡原因">
<el-input v-model="form.withdrawReason" placeholder="请输入退卡原因" />
<el-input v-model="form.withdrawReason" placeholder="请输入退卡原因" :disabled="isReadOnly" />
</el-form-item>
</el-col>
</el-row>
@@ -322,15 +331,15 @@
<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-input v-model="form.remark" type="textarea" :rows="2" placeholder="请输入备注" :disabled="isReadOnly" />
</el-form-item>
</el-col>
</el-row>
</el-form>
</div>
<!-- 操作按钮区 -->
<div class="action-buttons">
<!-- 操作按钮区create/edit 模式下显示) -->
<div v-if="mode !== 'view'" class="action-buttons">
<el-button type="primary" @click="handleSubmit" :loading="submitLoading">保 存</el-button>
<el-button @click="handleReset"> </el-button>
</div>
@@ -347,6 +356,9 @@ import { useDict } from '@/utils/dict';
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
// 是否只读模式
const isReadOnly = computed(() => props.mode === 'view');
// 获取职业字典数据
const { prfs: occupationList } = useDict('prfs');
@@ -418,9 +430,19 @@ const props = defineProps({
type: String,
default: '',
},
// 'create' | 'view' | 'edit'
mode: {
type: String,
default: 'create',
},
// 已有报卡数据view/edit 模式下使用)
cardData: {
type: Object,
default: null,
},
});
const emit = defineEmits(['saved']);
const emit = defineEmits(['saved', 'submit-edit']);
// 地址级联选择器配置
const addressOptions = ref(pcas);
@@ -453,7 +475,7 @@ const form = ref({
addressTown: '',
addressVillage: '',
addressHouse: '',
patientBelong: '1',
patientBelong: 1,
occupation: '',
caseClass: '',
onsetDate: '',
@@ -567,19 +589,27 @@ const isChildPatient = computed(() => {
// 监听疾病选择变化,自动清空分型选择
watch(() => [form.value.selectedClassA, form.value.selectedClassB, form.value.selectedClassC], (newVal, oldVal) => {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
// 在view/edit模式下初始化时不清空分型避免数据加载时被错误清空
if (JSON.stringify(newVal) !== JSON.stringify(oldVal) && props.mode !== 'view' && props.mode !== 'edit') {
form.value.diseaseType = '';
}
updateSelectedDiseases();
}, { deep: true });
// 监听患者信息变化,自动填充表单
// 监听患者信息变化,自动填充表单(仅 create 模式)
watch(() => props.patientInfo, (newVal) => {
if (newVal && Object.keys(newVal).length > 0) {
if (props.mode === 'create' && newVal && Object.keys(newVal).length > 0) {
initForm();
}
}, { deep: true, immediate: true });
// 监听 cardData 变化,在 view/edit 模式下初始化
watch(() => props.cardData, (newVal) => {
if ((props.mode === 'view' || props.mode === 'edit') && newVal) {
initFormFromCard(newVal);
}
}, { immediate: true });
// 监听Tab切换重新初始化
watch(() => props.activeTab, (newVal) => {
if (newVal === 'infectiousReport' && props.patientInfo && Object.keys(props.patientInfo).length > 0) {
@@ -808,7 +838,7 @@ async function initForm() {
addressTown: patientInfo.addressStreet || '',
addressVillage: '',
addressHouse: '',
patientBelong: '1',
patientBelong: 1,
occupation: '',
caseClass: '',
onsetDate: getCurrentDate(),
@@ -893,7 +923,7 @@ function buildSubmitData() {
addressTown: formData.addressTown || '',
addressVillage: formData.addressVillage || '',
addressHouse: formData.addressHouse || '',
patientBelong: parseInt(formData.patientBelong) || 1,
patientBelong: formData.patientBelong || 1,
occupation: formData.occupation || null,
diseaseCode: diseaseCode || null,
diseaseType: diseaseType || null,
@@ -1015,15 +1045,20 @@ async function handleSubmit() {
const submitData = buildSubmitData();
const res = await saveInfectiousDiseaseReport(submitData);
if (res.code === 200) {
proxy.$modal.msgSuccess('传染病报告卡保存成功');
emit('saved');
// 重新初始化表单,获取新的卡片编号
initForm();
if (props.mode === 'edit') {
// 编辑模式:通过事件通知父组件处理保存
emit('submit-edit', submitData);
} else {
proxy.$modal.msgError(res.msg || '保存失败');
// 新建模式
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);
@@ -1065,7 +1100,7 @@ function handleReset() {
form.value.contactPhone = '';
form.value.occupation = '';
form.value.caseClass = '';
form.value.patientBelong = '1';
form.value.patientBelong = 1;
form.value.otherDisease = '';
form.value.correctName = '';
form.value.withdrawReason = '';
@@ -1075,22 +1110,108 @@ function handleReset() {
updateSelectedDiseases();
}
// 从已有报卡数据初始化表单view/edit 模式)
function initFormFromCard(card) {
if (!card) return;
const ageUnitReverseMap = { '1': '岁', '2': '月', '3': '天' };
const sexMap = { '1': '男', '2': '女', '0': '未知' };
// 拆解出生日期
let birthYear = '', birthMonth = '', birthDay = '';
if (card.birthday) {
const parts = card.birthday.split('-');
birthYear = parts[0] || '';
birthMonth = parts[1] || '';
birthDay = parts[2] || '';
}
// 还原疾病分类选中状态
let selectedClassA = '', selectedClassB = '', selectedClassC = '';
if (card.diseaseCode) {
if (card.diseaseCode.startsWith('01')) selectedClassA = card.diseaseCode;
else if (card.diseaseCode.startsWith('02')) selectedClassB = card.diseaseCode;
else if (card.diseaseCode.startsWith('03')) selectedClassC = card.diseaseCode;
}
form.value = {
cardNo: card.cardNo || '',
patName: card.patName || '',
parentName: card.parentName || '',
idNo: card.idNo || '',
sex: sexMap[card.sex] || card.sex || '男',
birthYear,
birthMonth,
birthDay,
age: card.age != null ? String(card.age) : '',
ageUnit: ageUnitReverseMap[card.ageUnit] || '岁',
workplace: card.workplace || '',
phone: card.phone || '',
contactPhone: card.contactPhone || '',
addressProv: card.addressProv || '',
addressCity: card.addressCity || '',
addressCounty: card.addressCounty || '',
addressTown: card.addressTown || '',
addressVillage: card.addressVillage || '',
addressHouse: card.addressHouse || '',
patientBelong: card.patientBelong || 1,
occupation: card.occupation || '',
caseClass: card.caseClass != null ? String(card.caseClass) : '',
onsetDate: card.onsetDate || '',
diagDate: card.diagDate ? card.diagDate.substring(0, 10) : '',
deathDate: card.deathDate || '',
selectedDiseases: card.diseaseCode && card.diseaseCode !== 'OTHER' ? [card.diseaseCode] : [],
selectedClassA,
selectedClassB,
selectedClassC,
otherDisease: card.diseaseCode === 'OTHER' ? (card.otherDisease || '') : (card.otherDisease || ''),
diseaseType: card.diseaseType || '',
reportOrg: card.reportOrg || '',
reportOrgPhone: card.reportOrgPhone || '',
reportDoc: card.reportDoc || '',
reportDate: card.reportDate || '',
correctName: card.correctName || '',
withdrawReason: card.withdrawReason || '',
remark: card.remark || '',
encounterId: card.visitId || '',
patientId: card.patId || '',
diagnosisId: card.diagId || '',
};
// 设置地址级联选择器
const provName = card.addressProv || '';
const cityName = card.addressCity || '';
const countyName = card.addressCounty || '';
const townName = card.addressTown || '';
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);
}
// 组件挂载时初始化
onMounted(() => {
if (props.patientInfo && Object.keys(props.patientInfo).length > 0) {
if ((props.mode === 'view' || props.mode === 'edit') && props.cardData) {
initFormFromCard(props.cardData);
} else if (props.mode === 'create' && props.patientInfo && Object.keys(props.patientInfo).length > 0) {
initForm();
}
});
// 暴露方法供父组件调用
defineExpose({
initForm
initForm,
initFormFromCard
});
</script>
<style scoped>
.infectious-report-container {
height: 100%;
height: auto;
min-height: 100%;
display: flex;
flex-direction: column;
background: #fff;
@@ -1130,8 +1251,7 @@ defineExpose({
/* 表单区域样式 */
.report-form {
flex: 1;
overflow-y: auto;
overflow-y: visible;
padding-right: 8px;
}