Files
his/openhis-ui-vue3/src/views/charge/outpatientregistration/components/reprintDialog.vue
chenqi dc67c00d20 refactor(ui): 更新组件属性以符合新版本规范
- 将所有组件中的 append-to-body 属性替换为 teleported
- 为 el-radio 和 el-checkbox 组件添加正确的 value 属性
- 移除已弃用的 highlight-current-row 属性
- 为 vxe-table 添加 row-config 配置替代旧的高亮设置
- 更新 el-checkbox 的 true-value 属性值
- 修改 el-button 类型从 text 到 link 以匹配设计系统
2026-06-04 16:04:17 +08:00

797 lines
23 KiB
Vue
Executable File
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>
<el-dialog
v-model="dialogVisible"
title="补打挂号单凭证"
width="900px"
teleported
destroy-on-close
:close-on-click-modal="false"
>
<div
v-loading="loading"
style="background-color: #ffffff; padding: 20px; min-height: 400px;"
>
<!-- 标题区域 -->
<div style="text-align: center; margin-bottom: 20px;">
<h2 style="color: #ff0000; font-size: 24px; font-weight: bold; margin: 0 0 10px 0;">
挂号单重打
</h2>
<p style="color: #ff0000; font-size: 14px; margin: 0;">
补打挂号单将作废原有的挂号单据并生成新的挂号单据
</p>
</div>
<!-- 表单区域 -->
<el-form
ref="reprintFormRef"
:model="form"
label-width="120px"
style="background-color: #ffffff; padding: 20px; border-radius: 4px;"
>
<el-row :gutter="30">
<!-- 左列 -->
<el-col :span="12">
<el-form-item
label="病人姓名:"
prop="name"
>
<el-input
v-model="form.name"
placeholder="病人姓名"
:disabled="true"
/>
</el-form-item>
<el-form-item
label="医生姓名:"
prop="practitionerName"
>
<el-input
v-model="form.practitionerName"
placeholder="医生姓名"
:disabled="true"
/>
</el-form-item>
<el-form-item
label="诊疗费:"
prop="activityPrice"
>
<el-input
v-model="form.activityPrice"
placeholder="诊疗费"
:disabled="true"
/>
</el-form-item>
<el-form-item
label="流水号:"
prop="serialNo"
>
<el-input
v-model="form.serialNo"
placeholder="流水号"
:disabled="true"
/>
</el-form-item>
<el-form-item
label="合计:"
prop="totalPrice"
>
<el-input
v-model="form.totalPrice"
placeholder="合计"
:disabled="true"
/>
</el-form-item>
</el-col>
<!-- 右列 -->
<el-col :span="12">
<el-form-item
label="挂号科室:"
prop="organizationName"
>
<el-input
v-model="form.organizationName"
placeholder="挂号科室"
:disabled="true"
/>
</el-form-item>
<el-form-item
label="挂号费:"
prop="price"
>
<el-input
v-model="form.price"
placeholder="挂号费"
:disabled="true"
/>
</el-form-item>
<el-form-item
label="病历费:"
prop="medicalRecordFee"
>
<el-input
v-model="form.medicalRecordFee"
placeholder="病历费"
:disabled="true"
/>
</el-form-item>
<el-form-item
label="打印时间:"
prop="printTime"
>
<el-input
v-model="form.printTime"
placeholder="打印时间"
:disabled="true"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 跨两列的字段 -->
<el-row>
<el-col :span="24">
<el-form-item
label="预约/挂号时间:"
prop="visitTime"
>
<el-input
v-model="form.visitTime"
placeholder="预约/挂号时间"
:disabled="true"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 底部搜索和操作区域 -->
<div style="margin-top: 20px; padding: 15px; background-color: #ffffff; border-radius: 4px;">
<el-form
:inline="true"
style="margin: 0;"
>
<el-form-item
label="就诊卡号:"
style="margin-bottom: 0;"
>
<el-input
v-model="searchForm.cardNo"
placeholder="请输入就诊卡号检索条"
style="width: 300px; margin-right: 10px;"
clearable
@keyup.enter="handleSearch"
/>
<el-button
type="primary"
:loading="loading"
@click="handleSearch"
>
确认(O)
</el-button>
<el-button @click="handleCancel">
取消(C)
</el-button>
</el-form-item>
</el-form>
</div>
</div>
<!-- 挂号记录选择对话框 -->
<el-dialog
v-model="selectDialogVisible"
title="挂号记录选择"
width="800px"
teleported
:close-on-click-modal="false"
>
<vxe-table
:row-config="{ isCurrent: true }" :data="recordList"
style="width: 100%"
max-height="400"
@current-change="handleRecordSelect"
>
<vxe-column
title="序号"
type="seq"
width="60"
align="center"
/>
<vxe-column
title="挂号时间"
field="registerTime"
width="180"
align="center"
>
<template #default="scope">
{{ scope.row.registerTime ? parseTime(scope.row.registerTime, '{y}.{m}.{d} {h}时{i}分') : '-' }}
</template>
</vxe-column>
<vxe-column
title="挂号科室"
field="organizationName"
align="center"
>
<template #default="scope">
{{ scope.row.organizationName ? scope.row.organizationName.trim() || '-' : '-' }}
</template>
</vxe-column>
<vxe-column
title="医生姓名"
field="practitionerName"
align="center"
>
<template #default="scope">
{{ scope.row.practitionerName ? scope.row.practitionerName.trim() || '-' : '-' }}
</template>
</vxe-column>
<vxe-column
title="流水号"
field="encounterNo"
align="center"
>
<template #default="scope">
{{ calculateSerialNo(scope.row) }}
</template>
</vxe-column>
</vxe-table>
<template #footer>
<div class="dialog-footer">
<el-button @click="selectDialogVisible = false">
取消 (C)
</el-button>
<el-button
type="primary"
:disabled="!selectedRecord"
@click="handleConfirmSelect"
>
确认 (O)
</el-button>
</div>
</template>
</el-dialog>
</el-dialog>
</template>
<script setup>
import {getCurrentInstance, reactive, ref, watch, nextTick, onMounted} from 'vue';
import {getOutpatientRegistrationCurrent, reprintRegistration} from './outpatientregistration';
import {parseTime} from '@/utils/his';
import {formatDateStr} from '@/utils/index';
import {hiprint} from 'vue-plugin-hiprint';
import outpatientRegistrationTemplate from '@/components/Print/OutpatientRegistration.json';
import useUserStore from '@/store/modules/user';
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const props = defineProps({
open: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(['close']);
const dialogVisible = ref(false);
const loading = ref(false);
const reprintFormRef = ref(null);
const selectDialogVisible = ref(false);
const recordList = ref([]);
const selectedRecord = ref(null);
const currentRecord = ref(null); // 保存当前选择的记录,用于打印
const searchForm = reactive({
cardNo: '',
});
const form = reactive({
cardNo: '',
name: '',
idCard: '',
phone: '',
organizationName: '',
practitionerName: '',
price: '',
activityPrice: '',
medicalRecordFee: '',
serialNo: '',
totalPrice: '',
visitTime: '',
visitLocation: '',
statusText: '',
printTime: '',
encounterId: '',
});
const rules = {
cardNo: [{ required: true, message: '就诊卡号不能为空', trigger: 'blur' }],
name: [{ required: true, message: '姓名不能为空', trigger: 'blur' }],
organizationName: [{ required: true, message: '就诊科室不能为空', trigger: 'blur' }],
practitionerName: [{ required: true, message: '医生不能为空', trigger: 'blur' }],
};
// 监听open属性变化
watch(
() => props.open,
(newVal) => {
dialogVisible.value = newVal;
if (newVal) {
// 打开对话框时重置表单
resetForm();
resetSearch();
}
}
);
// 监听dialogVisible变化同步到父组件
watch(dialogVisible, (newVal) => {
if (!newVal) {
emit('close');
}
});
// 搜索挂号记录并确认补打
async function handleSearch() {
if (!searchForm.cardNo) {
proxy.$modal.msgWarning('请输入就诊卡号');
return;
}
loading.value = true;
try {
// 使用就诊卡号作为searchKey查询
const endDate = new Date();
const startDate = new Date();
startDate.setFullYear(startDate.getFullYear() - 1);
const queryParams = {
pageNo: 1,
pageSize: 100,
registerTimeSTime: formatDateStr(startDate, 'YYYY-MM-DD') + ' 00:00:00',
registerTimeETime: formatDateStr(endDate, 'YYYY-MM-DD') + ' 23:59:59',
searchKey: searchForm.cardNo
};
// 调用API查询挂号记录
const response = await getOutpatientRegistrationCurrent(queryParams);
if (response.code === 200) {
let records = response.data.records || response.data || [];
// 过滤掉挂号科室或医生姓名为空的记录
records = records.filter(record => {
const orgName = record.organizationName ? record.organizationName.trim() : '';
const pracName = record.practitionerName ? record.practitionerName.trim() : '';
// 只保留挂号科室和医生姓名都不为空的记录
return orgName && pracName;
});
if (records.length > 0) {
if (records.length === 1) {
// 只有一条记录,直接使用
const row = records[0];
currentRecord.value = row; // 保存记录用于打印
fillForm(row);
await handleSubmit();
} else {
// 多条记录,显示选择对话框
recordList.value = records;
selectedRecord.value = records[0]; // 默认选择第一条
selectDialogVisible.value = true;
loading.value = false;
}
} else {
proxy.$modal.msgWarning('未查询到相关挂号记录,请检查就诊卡号是否正确');
resetForm();
loading.value = false;
}
} else {
proxy.$modal.msgWarning('查询失败: ' + (response.msg || '接口返回异常'));
resetForm();
loading.value = false;
}
} catch (error) {
console.error('查询挂号记录异常:', error);
proxy.$modal.msgError('查询出错: ' + (error.message || '网络异常'));
resetForm();
loading.value = false;
}
}
// 填充表单
function fillForm(row) {
console.log('fillForm row:', row); // 调试日志
// 就诊卡号 - 从 identifierNo 字段获取
form.cardNo = row.identifierNo || row.cardNo || '';
// 病人姓名 - 从 patientName 字段获取
form.name = row.patientName || row.name || '';
// 身份证号 - 从 idCard 字段获取,需要脱敏处理
let idCard = row.idCard || '';
if (idCard && idCard.length >= 10) {
// 只显示前6位和后4位中间用*代替
const prefix = idCard.substring(0, 6);
const suffix = idCard.substring(idCard.length - 4);
const stars = '*'.repeat(Math.max(0, idCard.length - 10));
form.idCard = prefix + stars + suffix;
} else if (idCard) {
// 如果身份证号长度不足10位只显示部分并用*代替
if (idCard.length >= 6) {
const prefix = idCard.substring(0, 3);
const suffix = idCard.substring(idCard.length - 1);
form.idCard = prefix + '*'.repeat(idCard.length - 4) + suffix;
} else {
form.idCard = idCard;
}
} else {
form.idCard = '';
}
// 联系电话 - 从 phone 字段获取,需要脱敏处理
let phone = row.phone || '';
if (phone && phone.length >= 7) {
// 只显示前3位和后4位中间用*代替
const prefix = phone.substring(0, 3);
const suffix = phone.substring(phone.length - 4);
form.phone = prefix + '****' + suffix;
} else if (phone) {
// 如果手机号长度不足7位部分脱敏
if (phone.length >= 4) {
const prefix = phone.substring(0, 2);
const suffix = phone.substring(phone.length - 2);
form.phone = prefix + '**' + suffix;
} else {
form.phone = phone;
}
} else {
form.phone = '';
}
// 挂号科室 - 从 organizationName 字段获取
form.organizationName = row.organizationName || '';
// 医生姓名 - 从 practitionerName 字段获取
form.practitionerName = row.practitionerName || '';
// 挂号费 - 如果没有单独的 price将 totalPrice 作为挂号费
// 实际系统中,可能需要查询更详细的费用明细
form.price = row.price ? parseFloat(row.price).toFixed(2) :
(row.totalPrice ? parseFloat(row.totalPrice).toFixed(2) : '0.00');
// 诊疗费 - API 未返回,暂时设为 0.00
form.activityPrice = row.activityPrice ? parseFloat(row.activityPrice).toFixed(2) : '0.00';
// 病历费 - API 未返回,暂时设为 0.00
form.medicalRecordFee = row.medicalRecordFee ? parseFloat(row.medicalRecordFee).toFixed(2) : '0.00';
// 流水号 - 使用 calculateSerialNo 函数计算
form.serialNo = calculateSerialNo(row);
// 合计 - 优先使用 totalPrice否则计算各项费用之和
if (row.totalPrice) {
form.totalPrice = parseFloat(row.totalPrice).toFixed(2);
} else {
const total = parseFloat(form.price || 0) + parseFloat(form.activityPrice || 0) + parseFloat(form.medicalRecordFee || 0);
form.totalPrice = total.toFixed(2);
}
// 预约/挂号时间 - 从 registerTime 字段获取
if (row.registerTime) {
form.visitTime = parseTime(row.registerTime, '{y}-{m}-{d} {h}:{i}:{s}');
} else {
form.visitTime = formatDateTime(new Date());
}
// 就诊地点 - 使用科室名称作为就诊地点
form.visitLocation = row.visitLocation || row.locationName || row.organizationName || '';
// 预约状态 - 从 statusEnum_enumText 字段获取,如果没有则根据 statusEnum 判断
if (row.statusEnum_enumText) {
form.statusText = row.statusEnum_enumText;
} else if (row.statusEnum !== undefined) {
// 根据 statusEnum 判断状态
// 状态枚举可能需要根据实际情况调整
const statusMap = {
1: '已预约',
2: '已完成',
3: '已取消',
4: '进行中'
};
form.statusText = statusMap[row.statusEnum] || '已预约';
} else {
form.statusText = '已预约';
}
// 打印时间(当前时间)
form.printTime = formatDateTime(new Date());
// 保存encounterId用于提交 - 注意字段名是 encounterId
form.encounterId = row.encounterId || row.id || '';
console.log('fillForm form:', form); // 调试日志
}
// 格式化日期时间
function formatDateTime(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
// 计算流水号直接使用挂号记录表的主键IDencounterId
function calculateSerialNo(row) {
if (!row) {
return '-';
}
// 直接使用主键ID作为流水号
if (row.encounterId != null && row.encounterId !== undefined) {
return String(row.encounterId);
} else if (row.id != null && row.id !== undefined) {
// 兼容其他可能的ID字段名
return String(row.id);
} else {
return '-';
}
}
// 提交补打挂号
async function handleSubmit() {
if (!form.encounterId) {
proxy.$modal.msgWarning('请先搜索并选择挂号记录');
loading.value = false;
return;
}
try {
// 如果 reprintFormRef 不存在,跳过验证
let valid = true;
if (reprintFormRef.value) {
valid = await reprintFormRef.value.validate().catch(() => false);
}
if (!valid) {
loading.value = false;
return;
}
// 在提交前,验证表单数据是否已正确填充
console.log('handleSubmit form before submit:', form); // 调试日志
const submitData = {
encounterId: form.encounterId,
cardNo: form.cardNo,
name: form.name,
organizationName: form.organizationName,
practitionerName: form.practitionerName,
price: parseFloat(form.price) || 0,
activityPrice: parseFloat(form.activityPrice) || 0,
medicalRecordFee: parseFloat(form.medicalRecordFee || 0),
totalPrice: parseFloat(form.totalPrice) || 0,
visitTime: form.visitTime,
};
console.log('handleSubmit submitData:', submitData); // 调试日志
const res = await reprintRegistration(submitData);
if (res.code === 200) {
proxy.$modal.msgSuccess('补打挂号成功');
// 不关闭补打对话框,直接显示打印预览
// 这样可以确保 form 数据不会丢失
loading.value = false;
showPrintPreview();
} else {
proxy.$modal.msgError(res.msg || '补打挂号失败');
loading.value = false;
}
} catch (error) {
console.error('补打挂号失败:', error);
proxy.$modal.msgError('补打挂号失败: ' + (error.message || '未知错误'));
loading.value = false;
}
}
// 取消(实际执行提交操作,因为确认按钮触发搜索)
function handleCancel() {
dialogVisible.value = false;
}
// 重置表单
function resetForm() {
Object.assign(form, {
cardNo: '',
name: '',
idCard: '',
phone: '',
organizationName: '',
practitionerName: '',
price: '',
activityPrice: '',
medicalRecordFee: '',
serialNo: '',
totalPrice: '',
visitTime: '',
visitLocation: '',
statusText: '',
printTime: '',
encounterId: '',
});
if (reprintFormRef.value) {
reprintFormRef.value.clearValidate();
}
}
// 重置搜索
function resetSearch() {
searchForm.cardNo = '';
}
// 显示打印预览(使用 hiprint 打印)
function showPrintPreview() {
loading.value = false;
console.log('showPrintPreview form:', form);
console.log('showPrintPreview currentRecord:', currentRecord.value);
if (!form.name && currentRecord.value) {
console.log('重新填充表单数据...');
fillForm(currentRecord.value);
}
// 使用 hiprint 打印
printByHiprint();
}
/**
* 使用 hiprint 打印门诊挂号单(补打)
*/
function printByHiprint() {
try {
// 构建打印数据
const printData = {
patientName: form.name || '-',
sex: form.gender || '-',
age: form.age || '-',
personType: '自费',
busNo: form.cardNo || '-',
organizationName: form.organizationName || '-',
practitionerName: form.practitionerName || '-',
healthcareName: '挂号',
chargeTime: form.printTime || formatDateStr(new Date(), 'YYYY-MM-DD HH:mm:ss'),
cashier: userStore.name || '',
chargeItem: [
{
chargeItemName: '挂号费',
quantityValue: '1',
totalPrice: parseFloat(form.price || 0).toFixed(2),
dirClass: 1
},
...(parseFloat(form.activityPrice || 0) > 0 ? [{
chargeItemName: '诊疗费',
quantityValue: '1',
totalPrice: parseFloat(form.activityPrice || 0).toFixed(2),
dirClass: 1
}] : []),
...(parseFloat(form.medicalRecordFee || 0) > 0 ? [{
chargeItemName: '病历费',
quantityValue: '1',
totalPrice: parseFloat(form.medicalRecordFee || 0).toFixed(2),
dirClass: 1
}] : [])
],
displayAmount123: '¥' + parseFloat(form.totalPrice || 0).toFixed(2),
FULAMT_OWNPAY_AMT: '¥' + parseFloat(form.totalPrice || 0).toFixed(2),
SELF_CASH_VALUE: '¥' + parseFloat(form.totalPrice || 0).toFixed(2),
pictureUrl: ''
};
const result = {
data: [printData]
};
console.log('补打挂号打印数据:', printData);
// 处理模板(替换医院名称)
const printElements = JSON.parse(
JSON.stringify(outpatientRegistrationTemplate).replace(/{{HOSPITAL_NAME}}/g, userStore.hospitalName)
);
// 创建 hiprint 模板并打印
const hiprintTemplate = new hiprint.PrintTemplate({ template: printElements });
// 打印成功回调
hiprintTemplate.on('printSuccess', function (e) {
console.log('补打挂号单打印成功', e);
proxy.$modal.msgSuccess('打印成功');
dialogVisible.value = false;
});
// 打印失败回调
hiprintTemplate.on('printError', function (e) {
console.error('补打挂号单打印失败', e);
proxy.$modal.msgError('打印失败:' + (e.message || '未知错误'));
});
// 执行打印
hiprintTemplate.print2(result.data[0], {
title: '门诊挂号单(补打)',
});
} catch (error) {
console.error('hiprint 打印挂号单失败:', error);
proxy.$modal.msgError('打印失败:' + (error.message || '未知错误'));
}
}
// 选择挂号记录
function handleRecordSelect(row) {
selectedRecord.value = row;
}
// 确认选择记录
async function handleConfirmSelect() {
if (!selectedRecord.value) {
proxy.$modal.msgWarning('请选择一条挂号记录');
return;
}
loading.value = true;
selectDialogVisible.value = false;
try {
// 保存当前记录,用于打印
currentRecord.value = selectedRecord.value;
// 填充表单 - 确保数据正确填充
fillForm(selectedRecord.value);
// 等待一小段时间,确保 form 数据已更新
await new Promise(resolve => setTimeout(resolve, 50));
// 验证表单数据是否已正确填充
if (!form.encounterId) {
proxy.$modal.msgError('获取挂号记录ID失败请重试');
loading.value = false;
return;
}
// 提交补打操作handleSubmit 内部会管理 loading 状态)
await handleSubmit();
} catch (error) {
console.error('确认选择记录失败:', error);
proxy.$modal.msgError('处理失败:' + (error.message || '未知错误'));
loading.value = false;
}
}
</script>
<style scoped>
/* 确保对话框内容区域的背景色 */
:deep(.el-dialog__body) {
padding: 0;
background-color: #ffffff;
}
/* 输入框样式 */
:deep(.el-input__inner) {
background-color: #ffffff;
}
/* 标签样式 */
:deep(.el-form-item__label) {
font-weight: normal;
color: #333;
}
</style>