Files
his/openhis-ui-vue3/src/views/charge/outpatientregistration/index.vue
zhangfei 9c3e603b94 Fix Bug #443: 手术计费:点击签发耗材时异常报错
当手术计费弹窗中点击"签发"耗材时,因耗材的locationId(发放库房)为空导致后端异常。
在DoctorStationAdviceAppServiceImpl.handDevice方法中,当locationId为null时,使用登录用户的科室ID作为默认值,
与NurseBillingAppService中的处理方式保持一致。
2026-05-08 09:14:18 +08:00

2040 lines
72 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>
<div class="app-container" v-loading="readCardLoading" :element-loading-text="loadingText">
<el-row>
<el-col :span="24" class="card-box">
<el-card>
<template #header>
<div style="display: flex; align-items: center; width: 100%">
<span style="font-size: 16px; font-weight: bold; margin-right: 20px;">门诊挂号</span>
<div style="flex: 1; display: flex; justify-content: center; align-items: center;">
<el-button type="success" icon="Check" @click="handleCheckIn" size="small">预约签到</el-button>
<el-button type="primary" icon="Document" @click="goToPatientRecord" size="small">档案</el-button>
<el-button type="primary" icon="Plus" @click="handleAddPatient" size="small">新建</el-button>
<el-button type="primary" plain icon="Search" @click="handleSearch" size="small">查询</el-button>
<el-button type="primary" plain @click="handleReadCard('01')" size="small">电子凭证</el-button>
<el-button type="primary" plain @click="handleReadCard('02')" size="small" :disabled="true">身份证</el-button>
<el-button type="primary" plain @click="handleReadCard('03')" size="small">医保卡</el-button>
<el-button type="warning" plain icon="CircleClose" @click="handleClear" size="small">清空</el-button>
<el-button type="primary" icon="Plus" @click="handleAdd" size="small">保存挂号</el-button>
<el-button type="info" icon="Printer" @click="handleReprint" size="small">补打挂号</el-button>
</div>
</div>
</template>
<el-form :model="form" :rules="rules" ref="outpatientRegistrationRef" label-width="110px">
<el-row :gutter="24">
<el-col :span="5">
<el-form-item label="患者身份信息:" prop="searchKey">
<el-popover
:popper-style="{ padding: '0' }"
placement="bottom-start"
:visible="showPopover"
trigger="manual"
:width="1200"
>
<patientList :searchkey="patientSearchKey" @selsectPatient="selsectPatient" />
<template #reference>
<el-input
@focus="handleFocus"
@blur="handleBlur"
@input="handleSearchPatient"
v-model="form.searchKey"
placeholder="请输入姓名/身份证/就诊卡号"
/>
</template>
</el-popover>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="姓名:" prop="name">
<el-input v-model="form.name" placeholder="姓名" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item
label="性别:"
prop="genderEnum_enumText"
class="custom-label-spacing"
>
<el-input v-model="form.genderEnum_enumText" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="年龄:" prop="age" class="custom-label-spacing">
<el-input v-model="form.age" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="5">
<el-form-item label="就诊卡号:" prop="card">
<el-input v-model="form.identifierNo" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="证件号:" prop="idCard">
<el-input v-model="form.idCard" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item
label="初复诊:"
prop="firstEnum_enumText"
class="custom-label-spacing"
>
<el-input v-model="form.firstEnum_enumText" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="医保余额:" prop="balanceAmount" class="custom-label-spacing">
<el-input v-model="form.balanceAmount" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="参保类型:" prop="cb" class="custom-label-spacing">
<el-input v-model="form.pyStr" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="5">
<el-form-item label="医保名称:" prop="ybName" class="custom-label-spacing">
<el-input v-model="form.ybName" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="医保区域:" prop="ybAreaNo">
<el-select
v-model="form.ybAreaNo"
placeholder="医保区域"
clearable
style="width: 240px"
:disabled="true"
>
<el-option
v-for="dict in med_chrgitm_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item
label="欠费限制额度:"
prop="limitAccount"
class="custom-label-spacing"
>
<el-input v-model="form.limitAccount" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="5">
<el-form-item label="费用性质:" prop="contractNo" class="custom-label-spacing">
<el-select
v-model="form.contractNo"
placeholder="费用性质"
clearable
style="width: 240px"
ref="contractNameRef"
>
<el-option
v-for="dict in medfee_paymtd_code"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="就诊原因:" prop="jzyy">
<el-select
v-model="form.jzyy"
placeholder="就诊原因"
clearable
style="width: 240px"
ref="jzyyRef"
>
<el-option
v-for="dict in jzyyList"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="电话:" prop="phone" class="custom-label-spacing">
<el-input v-model="form.phone" placeholder="" ref="phoneRef" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="优先级:" prop="priorityEnum" class="custom-label-spacing">
<el-select
v-model="form.priorityEnum"
placeholder="优先级"
clearable
style="width: 240px"
ref="prioritySelectRef"
>
<el-option
v-for="item in priorityLevelOptionOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<!-- <el-col :span="4">
<el-form-item
label=""
prop="pyStr"
class="custom-label-spacing"
>
<el-checkbox
v-model="form.allergenFlag"
label="减免"
></el-checkbox>
</el-form-item>
</el-col> -->
</el-row>
<el-row :gutter="24">
<!-- <el-col :span="5">
<el-form-item label="科室:" prop="name">
<el-select
v-model="form.ybType"
placeholder="就诊原因"
clearable
style="width: 240px"
>
<el-option
v-for="dict in med_chrgitm_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col> -->
<el-col :span="5">
<el-form-item label="就诊科室:" prop="orgId" class="custom-label-spacing">
<el-tree-select
v-model="form.orgId"
:data="orgOptions"
:props="{
value: 'id',
label: 'name',
children: 'children',
}"
value-key="id"
placeholder="请选择就诊科室"
check-strictly
:expand-on-click-node="false"
:filter-node-method="filterNode"
ref="locationTreeRef"
node-key="value"
highlight-current
default-expand-all
@node-click="handleNodeClick"
@change="
() => {
form.serviceTypeId = undefined;
setchargeItem();
}
"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="挂号类型" prop="serviceTypeId" class="custom-label-spacing">
<el-select
v-model="form.serviceTypeId"
placeholder="挂号类型"
clearable
style="width: 240px"
@change="handleServiceTypeChange"
ref="serviceTypeRef"
>
<el-option
v-for="healthcare in healthcareList"
:key="healthcare.id"
:label="healthcare.name"
:value="healthcare.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="医生:" prop="practitionerId">
<el-select
v-model="form.practitionerId"
placeholder="医生"
clearable
style="width: 240px"
@change="setInfo"
ref="doctorRef"
>
<el-option
v-for="doctor in doctorList"
:key="doctor.id"
:label="getTypeCodeLabel(doctor)"
:value="doctor.id"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="特病病种:" prop="pyStr" class="custom-label-spacing">
<el-select
v-model="form.ybType"
placeholder="特病病种"
clearable
style="width: 240px"
ref="ybTypeRef"
disabled
>
<el-option
v-for="dict in med_chrgitm_type"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24">
<el-col :span="4">
<el-form-item label="挂号科室:" prop="locationId_dictText">
<el-input v-model="form.locationId_dictText" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="医生:" prop="doctorName">
<el-input v-model="form.doctorName" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="挂号费:" prop="price" class="custom-label-spacing">
<el-input v-model="form.price" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="诊疗费:" prop="activityPrice" class="custom-label-spacing">
<el-input v-model="form.activityPrice" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="总金额:" prop="totalPrice" class="custom-label-spacing">
<el-input v-model="form.totalPrice" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="24" justify="end">
<el-col :span="5" style="text-align: right">
<!-- 功能按钮已移至标题区域 -->
</el-col>
</el-row>
</el-form>
</el-card>
</el-col>
</el-row>
<el-row>
<el-col :span="24" class="card-box">
<el-card>
<template #header>
<div style="display: flex; align-items: center; justify-content: space-between;">
<span style="vertical-align: middle">当日已挂号</span>
<el-radio-group v-model="queryType" @change="handleQueryTypeChange" size="small">
<el-radio-button label="all">全部</el-radio-button>
<el-radio-button label="normal">正常挂号</el-radio-button>
<el-radio-button label="returned">退号记录</el-radio-button>
</el-radio-group>
</div>
</template>
<el-input
v-model="queryParams.searchKey"
style="width: 200px; margin-bottom: 10px"
placeholder="请输入患者姓名"
@keyup.enter="handleQuery"
>
<template #append>
<el-button icon="Search" @click="handleQuery" />
</template>
</el-input>
<el-date-picker
v-model="dateRange"
type="daterange"
start-placeholder="开始日期"
end-placeholder="结束日期"
style="width: 300px; margin-bottom: 10px; margin-left: 20px"
value-format="YYYY-MM-DD"
:clearable="false"
@change="handleQuery"
/>
<el-table v-loading="loading" :data="outpatientRegistrationList" max-height="250">
<!-- <el-table-column
label="租户ID"
align="center"
key="tenantId"
prop="tenantId"
/>
<el-table-column
label="就诊ID"
align="center"
key="encounterId"
prop="encounterId"
/>
<el-table-column
label="科室ID"
align="center"
key="organizationId"
prop="organizationId"
:show-overflow-tooltip="true"
/> -->
<el-table-column label="" align="center" width="50">
<template #default="scope">
{{ scope.$index + 1 }}
</template>
</el-table-column>
<el-table-column
label="患者姓名"
align="center"
key="patientName"
prop="patientName"
width="120"
/>
<el-table-column label="年龄" align="center" key="age" prop="age" width="120">
<template #default="scope">
{{ scope.row.age ? `${scope.row.age}` : '-' }}
</template>
</el-table-column>
<el-table-column
label="患者性别"
align="center"
key="genderEnum_enumText"
prop="genderEnum_enumText"
/>
<el-table-column label="联系电话" align="center" key="phone" prop="phone" />
<el-table-column
label="就诊卡号"
align="center"
key="identifierNo"
width="150"
>
<template #default="scope">
{{ scope.row.identifierNo || scope.row.cardNo || scope.row.card || scope.row.patientCardNo || scope.row.patient?.identifierNo || '-' }}
</template>
</el-table-column>
<el-table-column
label="科室名称"
align="center"
key="organizationName"
prop="organizationName"
:show-overflow-tooltip="true"
/>
<el-table-column
label="*挂号类型 "
align="center"
key="healthcareName"
prop="healthcareName"
:show-overflow-tooltip="true"
width="200"
>
<template #default="scope">
<span>
{{ (scope.row.healthcareName || '').replace('挂号', '') }}{{ scope.row.isFromAppointment ? '预约' : '挂号' }}
</span>
</template>
</el-table-column>
<!-- <el-table-column
label="专家账号"
align="center"
key="practitionerUserId"
prop="practitionerUserId"
/> -->
<el-table-column
label="专家"
align="center"
key="practitionerName"
prop="practitionerName"
/>
<el-table-column
label="费用性质"
align="center"
key="contractName"
prop="contractName"
>
</el-table-column>
<el-table-column label="挂号金额" align="center" key="totalPrice" prop="totalPrice">
<template #default="scope">
<span>
{{ scope.row.totalPrice ? scope.row.totalPrice.toFixed(2) + ' 元' : '0.00 元' }}
</span>
</template>
</el-table-column>
<el-table-column label="收款人" align="center" key="entererName" prop="entererName" />
<!-- <el-table-column
label="收款方式"
align="center"
key="contractName"
prop="contractName"
/> -->
<!-- <el-table-column
label="患者id"
align="center"
key="patientId"
prop="patientId"
/> -->
<!-- <el-table-column label="证件号" align="center" key="idCard" prop="idCard" width="180" /> -->
<el-table-column
label="就诊状态"
align="center"
key="statusEnum_enumText"
prop="statusEnum_enumText"
>
<template #default="scope">
<el-tag
:type="
handleColor(
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[
'info',
'success',
'info',
'info',
'success',
'info',
'warning',
'danger',
'info',
],
scope.row.statusEnum
)
"
>{{ scope.row.statusEnum_enumText || '未知' }}</el-tag
>
</template>
</el-table-column>
<el-table-column
label="挂号日期/时间"
align="center"
key="registerTime"
prop="registerTime"
width="180"
>
<template #default="scope">
<span>{{ parseTime(scope.row.registerTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" key="registerTime" prop="registerTime" do>
<template #default="scope">
<!-- <el-tooltip
:content="
scope.row.statusEnum == 6
? '已退号'
: scope.row.statusEnum == 2
? '已接诊,不允许退号'
: ''
"
placement="top"
:disabled="scope.row.statusEnum != 6"
> -->
<div style="display: flex">
<el-button
link
type="primary"
@click="handleReturn(scope.row, 1)"
:disabled="scope.row.statusEnum == 6"
>
退号
</el-button>
<el-button link type="primary" @click="handleReturn(scope.row, 0)">
详情
</el-button>
</div>
<!-- </el-tooltip> -->
</template>
</el-table-column>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-card>
</el-col>
</el-row>
<patient-info-dialog
ref="patientInfoRef"
:patientInfoData="patientInfoList"
:searchInfo="form.searchKey"
@submit="setForm"
/>
<patient-add-dialog ref="patientAddRef" @submit="setForm" :guardian-age="guardianAgeConfig" />
<ChargeDialog
:open="openDialog"
@close="handleClose"
:category="patientInfo.categoryEnum"
:totalAmount="totalAmount"
:patientInfo="patientInfo"
:chargeItemIds="chargeItemIdList"
:chrgBchnoList="chrgBchnoList"
:transformedData="transformedData"
:chrgBchno="chrgBchno"
:registerBusNo="registerBusNo"
:feeType="(patientInfo && patientInfo.medfeePaymtdCode) || (form && form.value && form.value.contractNo) || ''"
:medfee_paymtd_code="medfee_paymtd_code"
/>
<RefundDialog
:open="openRefundDialog"
@close="
(value) => {
if (value == 'success') {
proxy.$modal.msgSuccess('操作成功');
getList();
}
openRefundDialog = false;
}
"
:totalAmount="totalAmount"
:patientInfo="patientInfo"
:paymentId="paymentId"
:chargeItemIds="chargeItemIdList"
:eventType="eventType"
/>
<ReprintDialog
:open="openReprintDialog"
@close="
(value) => {
if (value == 'success') {
proxy.$modal.msgSuccess('操作成功');
getList();
}
openReprintDialog = false;
}
"
/>
<!-- 预约签到患者选择弹窗 -->
<el-dialog
v-model="showCheckInPatientModal"
title="请选择预约的患者"
width="1200px"
:close-on-click-modal="false"
>
<div style="margin-bottom: 20px; display: flex; gap: 10px;">
<el-input
v-model="checkInSearchKey"
placeholder="输入患者姓名回车查询"
style="width: 400px"
@keyup.enter="loadCheckInPatientList"
/>
<el-button type="primary" @click="loadCheckInPatientList">查询</el-button>
</div>
<el-table
v-loading="checkInLoading"
:data="checkInPatientList"
border
style="width: 100%"
@row-click="selectRow"
highlight-current-row
>
<el-table-column type="index" label="序号" width="60" align="center" />
<el-table-column prop="patientId" label="就诊卡号" width="120" align="center" />
<el-table-column prop="patientName" label="姓名" width="120" align="center">
<template #default="scope">
<span style="color: #ff4d4f">{{ scope.row.patientName }}</span>
</template>
</el-table-column>
<el-table-column prop="gender" label="性别" width="80" align="center" />
<el-table-column label="证件类型" width="150" align="center">
<template #default>居民身份证</template>
</el-table-column>
<el-table-column prop="idCard" label="证件号码" width="200" align="center" />
<el-table-column prop="phone" label="手机号码" width="150" align="center" />
<el-table-column label="号源类型" width="100" align="center">
<template #default="scope">
<el-tag :type="scope.row.ticketType === 'expert' ? 'danger' : 'success'">
{{ scope.row.ticketType === 'expert' ? '专家号' : '普通号' }}
</el-tag>
</template>
</el-table-column>
<el-table-column prop="fee" label="预约金额" width="100" align="center">
<template #default="scope">
<span style="font-weight: bold; color: #f5222d">{{ scope.row.fee }}</span>
</template>
</el-table-column>
<el-table-column prop="dateTime" label="就诊时间" width="180" align="center" />
</el-table>
<div style="margin-top: 20px; display: flex; justify-content: space-between; align-items: center;">
<el-pagination
v-model:current-page="checkInPage"
v-model:page-size="checkInLimit"
:total="checkInTotal"
layout="prev, pager, next"
@current-change="loadCheckInPatientList"
/>
<div class="dialog-footer">
<el-button @click="showCheckInPatientModal = false">取消</el-button>
<el-button type="primary" @click="confirmCheckIn" :disabled="!selectedCheckInPatient">确定</el-button>
</div>
</div>
</el-dialog>
</div>
</template>
<script setup name="OutpatientRegistration">
import {
addOutpatientRegistration,
gerPreInfo,
getContractList,
getHealthcareMetadata,
getInit,
getLocationTree,
getOutpatientRegistrationCurrent,
getOutpatientRegistrationList,
getPractitionerMetadata,
returnRegister,
updatePatientPhone,
} from './components/outpatientregistration';
import { listTicket, checkInTicket } from '@/api/appoinmentmanage/ticket';
import { invokeYbPlugin5000, invokeYbPlugin5001 } from '@/api/public';
import patientInfoDialog from './components/patientInfoDialog';
import PatientAddDialog from './components/patientAddDialog';
import patientList from './components/patientList';
import {nextTick, onMounted, onUnmounted, ref} from 'vue';
import ChargeDialog from './components/chargeDialog.vue';
import RefundDialog from './components/refundDialog.vue';
import ReprintDialog from './components/reprintDialog.vue';
import {handleColor} from '@/utils/his';
import useUserStore from '@/store/modules/user';
import {formatDateStr} from '@/utils/index';
import {isValidCNPhoneNumber} from '../../../utils/validate';
import {ElMessage, ElMessageBox} from 'element-plus';
import {hiprint} from 'vue-plugin-hiprint';
import outpatientRegistrationTemplate from '@/components/Print/OutpatientRegistration.json';
const patientInfo = ref({});
const eventType = ref(0);
const router = useRouter();
const { proxy } = getCurrentInstance();
const { sys_normal_disable, sys_user_sex, med_chrgitm_type,medfee_paymtd_code } = proxy.useDict(
'sys_normal_disable',
'sys_user_sex',
'med_chrgitm_type',
'medfee_paymtd_code'
);
const outpatientRegistrationList = ref([]);
const open = ref(false);
const loading = ref(true);
const showSearch = ref(true);
const selectedData = ref([]); // 存储选择的行数据
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref('');
const BusiCardInfo = ref(''); // miyao
const priorityLevelOptionOptions = ref(undefined); // 优先级
const jzyyList = ref([{ value: '1', label: '其他' }]);
const showPopover = ref(false);
const patientSearchKey = ref();
const chrgBchno = ref('');
const registerBusNo = ref('');
// 键盘事件用
const contractNameRef = ref(null);
const jzyyRef = ref(null);
const phoneRef = ref(null);
const prioritySelectRef = ref(null);
const locationTreeRef = ref(null);
const serviceTypeRef = ref(null);
const doctorRef = ref(null);
const ybTypeRef = ref(null);
const openDialog = ref(false);
const openRefundDialog = ref(false);
const openReprintDialog = ref(false);
// 预约签到相关变量
const showCheckInPatientModal = ref(false);
const checkInPatientList = ref([]);
const selectedCheckInPatient = ref(null);
const totalAmount = ref(0);
const chargeItemIdList = ref([]);
const chrgBchnoList = ref([]);
const paymentId = ref('');
const loadingText = ref('');
const checkInSearchKey = ref('');
const checkInPage = ref(1);
const checkInLimit = ref(10);
const checkInTotal = ref(0);
const checkInLoading = ref(false);
const registerInfo = ref({}); // 原挂号记录信息
const queryType = ref('all'); // 查询类型all-全部, normal-正常挂号, returned-退号记录
const guardianAgeConfig = ref(''); // 监护人规定年龄配置
const currentSlotId = ref(null); // 当前预约签到的号源ID
// 使用 ref 定义查询所得用户信息数据
const patientInfoList = ref(undefined);
// 费用性质
const contractList = ref(undefined);
// const locationOptions = ref(undefined); // 地点树选项
const doctorList = ref(undefined); // 医生选项
const allDoctorList = ref(undefined); // 所有医生选项(用于过滤)
const healthcareList = ref([]); // 挂号项目选项
const orgOptions = ref(undefined); // 科室选项
const readCardLoading = ref(false);
const transformedData = ref({});
const dateRange = ref([
formatDateStr(new Date(), 'YYYY-MM-DD'),
formatDateStr(new Date(), 'YYYY-MM-DD'),
]);
// const initPassword = ref(undefined);
// const postOptions = ref([]);
// const roleOptions = ref([]);
const userStore = useUserStore();
const data = reactive({
form: {
priorityEnum: 3,
},
queryParams: {
pageNo: 1,
pageSize: 10,
registerTimeSTime: dateRange.value[0] + ' 00:00:00',
registerTimeETime: dateRange.value[1] + ' 23:59:59',
// searchKey: undefined, // 品名/商品名/英文品名/编码/拼音
// statusEnum: undefined, // 状态(包括 1预置2启用3停用
// ybMatchFlag: undefined, // 是否医保匹配(包括 10
// status: undefined, // 状态(包括 1预置2启用3停用
},
rules: {
contractNo: [{ required: true, message: '费用性质', trigger: 'blur' }],
patientId: [{ required: true, message: '病人不能为空', trigger: 'blur' }],
priorityEnum: [{ required: true, message: '优先级不能为空', trigger: 'blur' }],
organizationId: [{ required: true, message: '优先级不能为空', trigger: 'blur' }],
orgId: [{ required: true, message: '就诊科室不能为空', trigger: 'blur' }],
serviceTypeId: [{ required: true, message: '挂号类型不能为空', trigger: 'blur' }],
practitionerId: [{ required: true, message: '医生不能为空', trigger: 'blur' }],
typeCode: [{ required: true, message: '账户类型不能为空', trigger: 'blur' }],
definitionId: [{ required: true, message: '费用定价不能为空', trigger: 'blur' }],
phone: [{ required: true, message: '联系电话不能为空', trigger: 'blur' }],
// totalPrice: [{ required: true, message: "总价不能为空", trigger: "blur" }],
},
});
// 其他输入框和选择框的 ref
const inputs = [
contractNameRef,
jzyyRef,
phoneRef,
prioritySelectRef,
locationTreeRef,
serviceTypeRef,
doctorRef,
ybTypeRef,
];
// 键盘事件处理函数
const handleKeyDown = (event) => {
const { key } = event;
// 获取当前焦点的元素
const currentIndex = inputs.findIndex((input) => {
if (input.value && input.value.$el) {
return input.value.$el.contains(document.activeElement);
}
return input.value === document.activeElement;
});
if (key === 'ArrowDown' || key === 'ArrowRight' || key === 'Tab') {
event.preventDefault();
const nextIndex = (currentIndex + 1) % inputs.length;
const nextInput = inputs[nextIndex].value;
if (nextInput && nextInput.focus) {
nextInput.focus();
} else if (nextInput && nextInput.$el) {
nextInput.$el.querySelector('input').focus();
}
} else if (key === 'ArrowUp' || key === 'ArrowLeft') {
event.preventDefault();
const prevIndex = (currentIndex - 1 + inputs.length) % inputs.length;
const prevInput = inputs[prevIndex].value;
if (prevInput && prevInput.focus) {
prevInput.focus();
} else if (prevInput && prevInput.$el) {
prevInput.$el.querySelector('input').focus();
}
}
};
// 添加事件监听器
onMounted(() => {
window.addEventListener('keydown', handleKeyDown);
});
// 移除事件监听器
onUnmounted(() => {
window.removeEventListener('keydown', handleKeyDown);
});
const { queryParams, form, rules } = toRefs(data);
/** 根据contractNo获取费用性质名称 */
function getFeeTypeName(contractNo) {
if (!contractNo || !medfee_paymtd_code?.value || !Array.isArray(medfee_paymtd_code.value)) {
return '';
}
const dictItem = medfee_paymtd_code.value.find(item => item.value === contractNo);
return dictItem ? dictItem.label : '';
}
/** 初期所用数据查询 */
function getInitData() {
getInit().then((response) => {
console.log(response, 'response');
priorityLevelOptionOptions.value = response.data.priorityLevelOptionOptions; // 优先级
});
}
/** 打开用户信息弹窗 */
function handleSearch() {
console.log(form.value.searchKey, 'form.value.searchKey');
if (!form.value.searchKey) {
proxy.$modal.msgError('请输入查询内容');
return;
}
const param = {
searchKey: form.value.searchKey,
};
getOutpatientRegistrationList(param).then((res) => {
loading.value = false;
console.log(param, 'param');
if (res.data.records.length > 0) {
patientInfoList.value = res.data;
console.log(patientInfoList.value, 'patientInfoList.value');
nextTick(() => {
proxy.$refs['patientInfoRef'].show(); // 确保子组件更新后再调用 show 方法
});
}
});
}
let userCardInfo = ref({});
async function handleReadCard(value) {
// if (window.CefSharp === undefined) {
// alert('请在医保版本中调用读卡功能!');
// } else {
try {
// await CefSharp.BindObjectAsync('boundAsync');
// string url,
// string fixmedins_code,
// string businessType,
// string operatorCode,
// string operatorName,
// string officeId,
// string officeName
// readCardLoading.value = true;
let jsonResult;
let cardInfo;
let userMessage = undefined;
switch (value) {
case '01': // 电子凭证
// readCardLoading.value = true;
// await boundAsync
// .getInfoByQrCodeAsync(
// )
await invokeYbPlugin5000({
FunctionId: 3,
url: 'http://10.47.0.67:8089/localcfc/api/hsecfc/localQrCodeQuery',
orgId: 'H22010402403',
businessType: '01101',
operatorId: userStore.id.toString(),
operatorName: userStore.name,
officeId: 'D83',
officeName: '财务科',
})
.then((res) => {
readCardLoading.value = true;
loadingText.value = '正在读取...';
console.log(res);
jsonResult = res.data;
})
.catch(() => {
readCardLoading.value = false;
});
cardInfo = JSON.parse(JSON.stringify(jsonResult));
let message = JSON.parse(cardInfo.data);
userMessage = {
certType: '02', // 证件类型
certNo: message.data.idNo, // 身份证号
psnCertType: '02', // 居民身份证
};
userCardInfo = {
certType: '01', // 证件类型
certNo: message.data.idNo, // 身份证号
psnCertType: '01', // 居民身份证
busiCardInfo: message.data.ecToken, // 令牌
};
BusiCardInfo.value = message.data.ecToken;
console.log(BusiCardInfo.value);
break;
case '02':
break;
case '03': // 社保卡
readCardLoading.value = true;
loadingText.value = '正在读取...';
await invokeYbPlugin5001(
JSON.stringify({
FunctionId: 1,
IP: 'ddjk.jlhs.gov.cn',
PORT: 20215,
TIMEOUT: 60,
SFZ_DRIVER_TYPE: 1,
})
)
.then((res) => {
jsonResult = JSON.stringify(res.data);
})
.finally(() => {
readCardLoading.value = false;
});
// console.log(
// 'jsonResult',
// JSON.parse({
// IssuingAreaCode: '310000',
// SocialSecurityNumber: '371324198810224515',
// CardNumber: 'M501A1A78',
// CardIdentificationCode: '310000D15600000535925154E880AB97',
// Name: '\u5218\u5CF0',
// CardResetInfo: '00814A444686603100333E4FA9',
// SpecificationVersion: '3.00',
// IssuingDate: '20190313',
// ExpirationDate: '20290313',
// TerminalNumber: '000000000000',
// TerminalDeviceNumber: '00041161201901000005',
// Code: 0,
// ErrorMessage: null,
// })
// );
let message1 = JSON.parse(jsonResult);
userMessage = {
certType: '02', // 证件类型
certNo: message1.SocialSecurityNumber, // 身份证号
psnCertType: '02', // 居民身份证
};
userCardInfo = {
certType: '02', // 证件类型
certNo: message1.SocialSecurityNumber, // 身份证号
psnCertType: '02', // 居民身份证
busiCardInfo: message1.BusiCardInfo, //卡号
};
BusiCardInfo.value = message1.BusiCardInfo;
console.log(message1.BusiCardInfo);
break;
case '99':
break;
}
readCardLoading.value = true;
if (userMessage.certNo) {
gerPreInfo(userMessage)
.then((res) => {
if (res.code == 200) {
form.value.patientId = res.data.id;
form.value.name = res.data.name;
form.value.age = res.data.age;
form.value.idCard = res.data.idCard;
form.value.card = res.data.id;
form.value.contractNo = res.data.contractBusNo;
form.value.genderEnum = res.data.genderEnum;
form.value.ybAreaNo = res.data.contractName;
}
})
.finally(() => {
readCardLoading.value = false;
});
}
} catch (error) {
console.error('调用失败:', error);
readCardLoading.value = false;
}
// }
}
/** 跳转到患者档案页面 */
function goToPatientRecord() {
// 如果已选择患者,则跳转到档案页面并定位到该患者
if (form.value.patientId) {
// 使用患者ID作为查询参数传递到档案页面
router.push({
path: '/patient/patientmgr',
query: {
patientId: form.value.patientId,
patientName: form.value.name
}
});
} else {
// 未选择患者时,直接跳转到档案页面
router.push('/patient/patientmgr');
}
}
/** 新增用户信息弹窗 */
function handleAddPatient() {
proxy.$refs['patientAddRef'].show(); // 确保子组件更新后再调用 show 方法
}
// 设定表单
function setForm(formData) {
console.log(formData, 'formData');
form.value = { ...form.value, ...formData };
form.value.patientId = formData.id;
// 使用 nextTick 确保 DOM 更新完成后设置焦点
nextTick(() => {
const prioritySelect = prioritySelectRef.value?.$el?.querySelector('input');
if (prioritySelect) {
prioritySelect.focus();
}
});
}
// 设定表单
function setInfo() {
const doctorData = doctorList.value.filter((doctor) => doctor.id === form.value.practitionerId);
form.value.doctorName = doctorData.length > 0 ? doctorData[0].name : '';
}
// 挂号类型选择变化处理
function handleServiceTypeChange() {
setchargeItem();
// 如果已选择科室和医生,重新过滤医生列表
if (form.value.orgId && allDoctorList.value) {
filterDoctorsByHealthcare();
}
}
// 设定费用项管理表单
function setchargeItem() {
if (healthcareList.value.length > 0) {
const healthcareData = healthcareList.value.filter(
(healthcare) => healthcare.id === form.value.serviceTypeId
);
form.value.locationId_dictText = healthcareData.length > 0 ? healthcareData[0].name : '';
form.value.price = healthcareData.length > 0 ? healthcareData[0].price : '';
form.value.activityPrice = healthcareData.length > 0 ? healthcareData[0].activityPrice : '';
form.value.totalPrice =
healthcareData.length > 0 ? healthcareData[0].price + healthcareData[0].activityPrice : '';
form.value.definitionId = healthcareData.length > 0 ? healthcareData[0].definitionId : '';
} else {
// 如果没有挂号类型数据,清空相关字段
form.value.locationId_dictText = '';
form.value.price = '';
form.value.activityPrice = '';
form.value.totalPrice = '';
form.value.definitionId = '';
}
}
/** 查询患者信息 */
function getList() {
loading.value = true;
getOutpatientRegistrationCurrent(queryParams.value).then((res) => {
loading.value = false;
outpatientRegistrationList.value = res.data.records;
total.value = res.data.total;
// 调试:查看返回的数据结构,查找就诊卡号字段
if (res.data.records && res.data.records.length > 0) {
console.log('当日已挂号数据结构:', res.data.records[0]);
console.log('所有字段:', Object.keys(res.data.records[0]));
// 查找可能的就诊卡号字段
const firstRecord = res.data.records[0];
const possibleCardFields = ['identifierNo', 'cardNo', 'card', 'patientCardNo', 'identifier', 'medicalCardNo'];
possibleCardFields.forEach(field => {
if (firstRecord[field] !== undefined) {
console.log(`找到可能的就诊卡号字段 ${field}:`, firstRecord[field]);
}
});
}
});
}
/** 查询费用性质 */
function getContract() {
form.value.jzyy = jzyyList.value[0]; // 设置默认值为第一项
getContractList().then((response) => {
contractList.value = response.data;
console.log('getContractList', 'response', response.data);
// form.value.contractNo = response.data.length > 0 ? response.data[0].busNo : '0000';
});
}
function handleCharge() {}
// /** 查询诊断信息 */
// function getConditionDefinition() {
// getConditionDefinitionMetadata().then((response) => {
// console.log("getConditionDefinitionMetadata", "response", response.data);
// });
// }
// /** 查询就诊科室 */
// function getLocationInfo() {
// getLocationTree().then((response) => {
// locationOptions.value = response.data.records;
// });
// }
/** 查询就诊位置 */
function getLocationInfo() {
getLocationTree().then((response) => {
console.log('getLocationTree', 'response', response.data);
orgOptions.value = response.data;
});
}
/** 通过条件过滤节点 */
const filterNode = (value, data) => {
if (!value) return true;
return data.label.indexOf(value) !== -1;
};
/** 节点单击事件 */
function handleNodeClick(data) {
// queryParams.value.sourceEnum = data.value;
// handleQuery();
console.log('handleNodeClick', 'data', data);
form.value.organ = data.id;
// 先获取医生和服务项目,然后在回调中过滤
getPractitioner(data);
getHealthcare(data);
}
/** 根据位置id筛选医生 */
function getPractitioner(data) {
const param = {
orgId: data.id,
};
console.log('getPractitioner', 'param', param);
getPractitionerMetadata(param).then((response) => {
console.log('getPractitioner', 'response', response.data);
// 保存所有医生列表用于后续过滤
allDoctorList.value = response.data.records;
// 如果已选择挂号类型,则根据科室和挂号类型过滤医生
if (form.value.serviceTypeId) {
filterDoctorsByHealthcare();
} else {
// 如果未选择挂号类型,显示所有医生
doctorList.value = allDoctorList.value;
}
});
}
/** 根据机构id筛选服务项目 */
function getHealthcare(data) {
const param = {
organizationId: data.id,
};
// 设定表单中的机构ID
form.value.organizationId = data.organizationId;
getHealthcareMetadata(param).then((response) => {
console.log('返回的结果,response.data:',response.data)
// 对数据进行去重处理name去重
const uniqueRecords = removeDuplicateHealthcareItems(response.data.records);
healthcareList.value = uniqueRecords;
console.log('去重后的数据列表,healthcareList', healthcareList.value)
console.log('getHealthcareMetadata', 'response', response.data);
// 使用 nextTick 确保数据更新后再过滤
nextTick(() => {
// 如果已选择挂号类型,则根据科室和挂号类型过滤医生
if (form.value.serviceTypeId && allDoctorList.value) {
filterDoctorsByHealthcare();
}
});
});
}
/** 根据name和typeCode对挂号类型数据进行去重同时保留所有相关医生信息 */
function removeDuplicateHealthcareItems(records) {
// 创建一个Map以name和typeCode的组合作为键
const groupedRecords = new Map();
for (const item of records) {
const key = item.name && item.typeCode !== undefined ? `${item.name}_${item.typeCode}` : item.name;
if (groupedRecords.has(key)) {
// 如果已存在相同的组合,将当前项的医生信息合并到现有项中
const existingItem = groupedRecords.get(key);
// 确保relatedPractitioners数组存在
if (!existingItem.relatedPractitioners) {
existingItem.relatedPractitioners = [existingItem.practitionerId].filter(id => id);
}
// 添加当前项的医生ID如果存在且不重复
if (item.practitionerId && !existingItem.relatedPractitioners.includes(item.practitionerId)) {
existingItem.relatedPractitioners.push(item.practitionerId);
}
} else {
// 如果是新的组合添加到Map中
const newItem = { ...item };
// 初始化相关医生数组
newItem.relatedPractitioners = item.practitionerId ? [item.practitionerId] : [];
groupedRecords.set(key, newItem);
}
}
console.log('去重后的数组groupedRecords:', groupedRecords.values())
// 返回去重后的数组
return Array.from(groupedRecords.values());
}
/** 根据就诊科室和挂号类型过滤医生列表 */
function filterDoctorsByHealthcare() {
// 如果没有医生列表,直接返回
if (!allDoctorList.value) {
return;
}
// 如果未选择科室或挂号类型,显示所有医生
if (!form.value.orgId || !form.value.serviceTypeId || !healthcareList.value) {
doctorList.value = allDoctorList.value;
// 如果当前选中的医生不在列表中,清空选择
if (form.value.practitionerId && !doctorList.value.some((d) => d.id === form.value.practitionerId)) {
form.value.practitionerId = undefined;
form.value.doctorName = '';
}
return;
}
// 获取选中的挂号类型信息
const selectedHealthcare = healthcareList.value?.find(
(healthcare) => healthcare.id === form.value.serviceTypeId
);
if (!selectedHealthcare) {
// 如果找不到选中的挂号类型,显示所有医生
doctorList.value = allDoctorList.value;
return;
}
// 如果selectedHealthcare有relatedPractitioners数组直接使用
let practitionerIds = [];
if (selectedHealthcare.relatedPractitioners && selectedHealthcare.relatedPractitioners.length > 0) {
// 使用合并后的医生ID列表
practitionerIds = [...new Set(selectedHealthcare.relatedPractitioners.filter(id => id != null))];
} else {
// 否则,按原来的方式查找
const orgIdStr = String(form.value.orgId);
const selectedTypeCode = selectedHealthcare.typeCode;
const matchedHealthcares = healthcareList.value.filter((healthcare) => {
const healthcareOrgIdStr = healthcare.offeredOrgId != null ? String(healthcare.offeredOrgId) : null;
const healthcareTypeCode = healthcare.typeCode;
return (
healthcareOrgIdStr === orgIdStr &&
healthcareTypeCode === selectedTypeCode
);
});
practitionerIds = [...new Set(matchedHealthcares.map((h) => h.practitionerId).filter((id) => id != null))];
}
// 从所有医生列表中筛选出匹配的医生
let filteredDoctors = [];
if (practitionerIds.length > 0) {
filteredDoctors = allDoctorList.value.filter((doctor) => practitionerIds.includes(doctor.id));
}
// 根据typeCode对医生进行分组并添加相关信息
doctorList.value = groupDoctorsByTypeCode(filteredDoctors, []);
// 如果当前选中的医生不在过滤后的列表中,清空选择
if (form.value.practitionerId && !doctorList.value.some((d) => d.id === form.value.practitionerId)) {
form.value.practitionerId = undefined;
form.value.doctorName = '';
}
// console.log('filterDoctorsByHealthcare', {
// orgId: form.value.orgId,
// orgIdStr: orgIdStr,
// serviceTypeId: form.value.serviceTypeId,
// selectedTypeCode: selectedTypeCode,
// selectedHealthcare: selectedHealthcare,
// healthcareListSample: healthcareList.value.slice(0, 3).map(h => ({
// id: h.id,
// offeredOrgId: h.offeredOrgId,
// typeCode: h.typeCode,
// typeCode_dictText: h.typeCode_dictText,
// practitionerId: h.practitionerId
// })),
// matchedHealthcares: matchedHealthcares.length,
// matchedHealthcaresDetail: matchedHealthcares.map(h => ({
// id: h.id,
// offeredOrgId: h.offeredOrgId,
// typeCode: h.typeCode,
// practitionerId: h.practitionerId
// })),
// practitionerIds: practitionerIds,
// filteredDoctors: doctorList.value.length,
// });
}
/** 根据typeCode对医生列表进行分组用于下拉框显示 */
function groupDoctorsByTypeCode(doctors, healthcareListForTypeCode) {
// 直接返回医生列表因为我们已经在filterDoctorsByHealthcare中处理了医生的选择
return doctors;
}
/** 生成带有typeCode信息的医生标签 */
function getTypeCodeLabel(doctor) {
if (doctor.typeCodes && doctor.typeCodes.length > 0) {
// 如果有typeCode信息将它们显示在医生名字旁边
return `${doctor.name} (${doctor.typeCodes.join(', ')})`;
}
return doctor.name; // 否则只显示医生名字
}
/** 清空条件按钮操作 */
function handleClear() {
reset();
}
/** 查询类型切换 */
function handleQueryTypeChange() {
queryParams.value.pageNo = 1;
// 根据查询类型设置状态筛选
if (queryType.value === 'returned') {
// 查询退号记录状态为6
queryParams.value.statusEnum = 6;
} else if (queryType.value === 'normal') {
// 查询正常挂号(排除退号状态)
queryParams.value.statusEnum = -1; // 使用特殊值表示排除退号记录
} else {
// 查询全部
queryParams.value.statusEnum = undefined;
}
handleQuery();
}
/** 搜索按钮操作 */
function handleQuery() {
queryParams.value.pageNo = 1;
queryParams.value.registerTimeSTime = dateRange.value[0] + ' 00:00:00';
queryParams.value.registerTimeETime = dateRange.value[1] + ' 23:59:59';
// 根据查询类型设置状态筛选
if (queryType.value === 'returned') {
queryParams.value.statusEnum = 6; // 退号状态
} else if (queryType.value === 'normal') {
// 正常挂号,排除退号记录
queryParams.value.statusEnum = -1; // 使用特殊值表示排除退号记录
} else {
// 全部
queryParams.value.statusEnum = undefined;
}
getList();
}
/** 重置操作表单 */
function reset() {
form.value = {
id: undefined,
searchKey: undefined,
type: undefined,
allergenFlag: undefined,
name: undefined,
genderEnum_enumText: undefined,
age: undefined,
idCard: undefined,
pyStr: undefined,
busNo: undefined,
ybType: undefined,
phone: undefined,
orgId: undefined,
serviceTypeId: undefined,
practitionerId: undefined,
locationId_dictText: undefined,
doctorName: undefined,
price: undefined,
activityPrice: undefined,
priorityEnum: 3,
patientId: undefined,
organizationId: undefined,
contractNo: undefined,
typeCode: 1, // 个人现金账户 目前固定传1
ybName: undefined,
ybAreaNo: undefined,
limitAccount: undefined,
definitionId: undefined,
serviceId: undefined,
totalPrice: undefined,
jzyy: 1,
};
proxy.resetForm('outpatientRegistrationRef');
}
/** 新增按钮操作 */
function handleAdd() {
console.log('isValidCNPhoneNumber=======>', isValidCNPhoneNumber(form.value.phone));
transformedData.value = transformFormData(form.value);
console.log(transformedData, 'transformedData 门诊挂号');
chargeItemIdList.value = [];
// patientInfo.value.patientId = form.value.patientId;
patientInfo.value = {
patientId: form.value.patientId,
patientName: form.value.name,
genderEnum_enumText: form.value.genderEnum_enumText,
age: form.value.age,
contractName: form.value.contractNo
? contractList.value?.find((item) => item.busNo === form.value.contractNo)?.contractName ||
'自费'
: '自费',
idCard: form.value.idCard,
phone: form.value.phone,
categoryEnum: form.value.categoryEnum || '门诊',
organizationName: form.value.locationId_dictText || '',
practitionerName: form.value.doctorName || '',
healthcareName: '', // 可根据实际情况补充
};
proxy.$refs['outpatientRegistrationRef'].validate((valid) => {
if (valid) {
if (!isValidCNPhoneNumber(patientInfo.value.phone)) {
ElMessage({
type: 'error',
message: '手机号格式不正确,请重新输入!',
});
return;
}
readCardLoading.value = true;
transformedData.value.busiCardInfo = userCardInfo.busiCardInfo;
transformedData.value.certType = userCardInfo.certType;
transformedData.value.certNo = userCardInfo.certNo;
transformedData.value.ybMdtrtCertType = userCardInfo.psnCertType;
addOutpatientRegistration(transformedData.value)
.then((res) => {
if (res.code == 200) {
console.log('78989798', 'res', res);
// proxy.$modal.msgSuccess('挂号成功');
chrgBchno.value = res.data.chrgBchno;
registerBusNo.value = res.data.busNo;
totalAmount.value = res.data.psnCashPay;
patientInfo.value.encounterId = res.data.encounterId || '';
patientInfo.value.busNo = res.data.busNo || '';
readCardLoading.value = false;
openDialog.value = true;
// 保存成功后使用 hiprint 打印挂号单
printRegistrationByHiprint(res.data);
// chargeItemIdList.value = res.data;
// patientInfo.value.encounterId = res.data.encounterId[0];
// precharge({
// patientId: patientInfo.value.patientId,
// encounterId: patientInfo.value.encounterId,
// chargeItemIds: chargeItemIdList.value,
// }).then((res) => {
// if (res.code == 200) {
// // proxy.$modal.msgSuccess('操作成功');
// // totalAmount.value = res.data.psnCashPay;
// chrgBchnoList.value = res.data.chrgBchnoList;
// openDialog.value = true;
// } else {
// proxy.$modal.msgError(res.msg);
// }
// });
// getList();
} else {
readCardLoading.value = false;
proxy.$modal.msgError(res.msg);
}
})
.finally(() => {
readCardLoading.value = false;
});
}
});
}
/**
* 使用 hiprint 打印门诊挂号单
* @param {Object} data 挂号返回的数据
*/
function printRegistrationByHiprint(data) {
try {
// 构建打印数据
const printData = {
patientName: patientInfo.value.patientName || form.value.name || '-',
sex: patientInfo.value.genderEnum_enumText || form.value.genderEnum_enumText || '-',
age: patientInfo.value.age || form.value.age || '-',
personType: patientInfo.value.contractName || '自费',
busNo: data.busNo || registerBusNo.value || '-',
organizationName: patientInfo.value.organizationName || '-',
practitionerName: patientInfo.value.practitionerName || '-',
healthcareName: healthcareList.value.find(h => h.id === form.value.serviceTypeId)?.name || '-',
chargeTime: formatDateStr(new Date(), 'YYYY-MM-DD HH:mm:ss'),
cashier: userStore.name || '',
chargeItem: data.chargeItemList ? data.chargeItemList.map(item => ({
chargeItemName: item.itemName || item.name || '-',
quantityValue: item.quantity || '1',
totalPrice: item.price || item.totalPrice || '0',
dirClass: item.dirClass || 1
})) : [],
displayAmount123: '¥' + (data.psnCashPay || 0).toFixed(2),
FULAMT_OWNPAY_AMT: '¥' + (data.psnCashPay || 0).toFixed(2),
SELF_CASH_VALUE: '¥' + (data.psnCashPay || 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);
});
// 打印失败回调
hiprintTemplate.on('printError', function (e) {
console.error('挂号单打印失败', e);
});
// 执行打印
hiprintTemplate.print2(result.data[0], {
title: '门诊挂号单',
});
} catch (error) {
console.error('hiprint 打印挂号单失败:', error);
}
}
/**
* 姓名表单获取焦点打开列表
*/
function handleFocus() {
showPopover.value = true;
}
/**
* 姓名表单失去焦点关闭列表
*/
function handleBlur() {
showPopover.value = false;
}
/**
* 搜索患者
*/
function handleSearchPatient(value) {
patientSearchKey.value = value;
}
function handleReturn(row, type = 1) {
openRefundDialog.value = true;
patientInfo.value.patientId = row.patientId;
patientInfo.value.encounterId = row.encounterId;
totalAmount.value = row.totalPrice;
chargeItemIdList.value = row.chargeItemIds.split(',');
paymentId.value = row.paymentId;
eventType.value = type;
console.log(paymentId.value);
}
function handleReturnRegister() {
returnRegister(patientInfo.value.encounterId).then((res) => {
if (res.code == 200) {
proxy.$modal.msgSuccess('操作成功');
getList();
}
});
}
/** 打开补打挂号对话框 */
function handleReprint() {
openReprintDialog.value = true;
}
/** 预约签到 - 打开患者选择弹窗 */
function handleCheckIn() {
// 打开患者选择弹窗,显示已预约但未签到的患者列表
showCheckInPatientModal.value = true;
// 加载已预约未签到的患者列表
loadCheckInPatientList();
}
/** 加载预约签到患者列表 */
function loadCheckInPatientList() {
checkInLoading.value = true;
const today = formatDateStr(new Date(), 'YYYY-MM-DD');
listTicket({
date: today,
status: 'booked',
name: checkInSearchKey.value, // 支持姓名等模糊查询,后端需适配
page: checkInPage.value,
limit: checkInLimit.value
}).then(res => {
const data = res.data?.list || res.list || res.data || [];
const total = res.data?.total || res.total || data.length;
checkInPatientList.value = data.map(item => ({
...item,
appointmentDate: item.scheduleDate + ' ' + (item.expectTime || '')
}));
checkInTotal.value = total;
}).catch(err => {
console.error('加载预约导出失败:', err);
ElMessage.error('获取预约列表失败');
}).finally(() => {
checkInLoading.value = false;
});
}
/** 弹窗行点击处理 */
function selectRow(row) {
selectedCheckInPatient.value = row;
}
/** 确认签到(一键签到:直接构建挂号参数 → 预结算 → 弹收费窗口) */
async function confirmCheckIn() {
if (!selectedCheckInPatient.value) {
ElMessage.warning('请先选择患者');
return;
}
const patient = selectedCheckInPatient.value;
// 每次开始新的签到流程先清理残留 slotId避免历史脏值串单
currentSlotId.value = null;
// 弹出确认提示
try {
await ElMessageBox.confirm(
`确认为患者【${patient.patientName}】办理签到挂号?\n` +
`科室:${patient.department || '-'}\n` +
`医生:${patient.doctor || '-'}\n` +
`费用:¥${patient.fee || '0.00'}`,
'签到确认',
{
confirmButtonText: '确认签到',
cancelButtonText: '取消',
type: 'info',
}
);
} catch {
// 用户点了取消
return;
}
showCheckInPatientModal.value = false;
readCardLoading.value = true;
loadingText.value = '正在处理签到挂号...';
try {
// 1. 用科室ID加载该科室的挂号类型列表获取 serviceTypeId 和 definitionId
const healthcareRes = await getHealthcareMetadata({ organizationId: patient.departmentId });
const healthcareRecords = healthcareRes.data?.records || [];
if (healthcareRecords.length === 0) {
ElMessage.error('该科室未配置挂号类型,无法自动签到');
readCardLoading.value = false;
return;
}
// 2. 按号源类型(专家/普通)模糊匹配挂号类型
const matchTypeName = (patient.ticketType === 'expert') ? '专家' : '普通';
const matchedService = healthcareRecords.find(h => h.name && h.name.includes(matchTypeName));
if (!matchedService) {
// 匹配不到就取第一个作为兜底
ElMessage.warning('未精确匹配到挂号类型,已使用默认类型');
}
const service = matchedService || healthcareRecords[0];
const realPatientId = patient.realPatientId; // 后端新增的真实患者数据库ID
if (!realPatientId) {
ElMessage.error('患者ID缺失请联系管理员检查预约数据');
readCardLoading.value = false;
return;
}
// 3. 构建挂号参数(与 transformFormData 结构一致)
const registrationParam = {
encounterFormData: {
patientId: realPatientId,
priorityEnum: 3, // 默认优先级
serviceTypeId: service.id,
organizationId: patient.departmentId,
orderId: patient.orderId, // 预约订单ID预约签到时需要传递
},
encounterLocationFormData: {
locationId: null,
},
encounterParticipantFormData: {
practitionerId: patient.doctorId,
},
accountFormData: {
patientId: realPatientId,
typeCode: 1, // 个人现金账户
contractNo: '0000', // 默认自费
},
chargeItemFormData: {
patientId: realPatientId,
definitionId: service.definitionId,
serviceId: service.id,
totalPrice: parseFloat(patient.fee) || ((service.price || 0) + (service.activityPrice || 0)),
},
};
// 4. 设置 patientInfoChargeDialog 需要展示)
patientInfo.value = {
patientId: realPatientId,
patientName: patient.patientName,
genderEnum_enumText: patient.gender || '-',
age: '',
contractName: '自费',
idCard: patient.idCard,
phone: patient.phone,
categoryEnum: '门诊',
organizationName: patient.department || '',
practitionerName: patient.doctor || '',
healthcareName: service.name || '',
};
// 同步设置 form 的 contractNoChargeDialog 的 feeType 会读取它
form.value.contractNo = '0000';
// 5. 调用预结算接口reg-pre-pay
const res = await addOutpatientRegistration(registrationParam);
if (res.code == 200) {
// 仅在预结算成功后记录待签到的号源,避免失败路径残留脏数据
currentSlotId.value = patient.slot_id;
// 6. 设置收费弹窗所需的数据
chrgBchno.value = res.data.chrgBchno;
registerBusNo.value = res.data.busNo;
totalAmount.value = res.data.psnCashPay;
patientInfo.value.encounterId = res.data.encounterId || '';
patientInfo.value.busNo = res.data.busNo || '';
transformedData.value = registrationParam;
chargeItemIdList.value = [];
// 7. 打开收费弹窗
openDialog.value = true;
// 打印挂号单
printRegistrationByHiprint(res.data);
} else {
currentSlotId.value = null;
ElMessage.error(res.msg || '预结算失败');
}
} catch (err) {
currentSlotId.value = null;
console.error('预约签到失败:', err);
ElMessage.error('签到处理失败: ' + (err.message || '未知错误'));
} finally {
readCardLoading.value = false;
}
}
/**
* 点击患者列表给表单赋值
*/
function selsectPatient(row) {
form.value = { ...form.value, ...row };
form.value.patientId = row.id;
form.value.searchKey = row.name;
form.value.name = row.name;
form.value.idCard = row.idCard;
form.value.genderEnum_enumText = row.genderEnum_enumText;
form.value.phone = row.phone;
form.value.firstEnum_enumText = row.firstEnum_enumText;
form.value.age = row.age;
form.value.identifierNo = row.identifierNo;
}
// 设置新增参数
function transformFormData(form) {
console.log(form, 'transformFormData*****************');
return {
encounterFormData: {
patientId: form.patientId,
priorityEnum: form.priorityEnum,
serviceTypeId: form.serviceTypeId,
organizationId: form.orgId,
},
encounterLocationFormData: {
locationId: form.locationId,
},
encounterParticipantFormData: {
practitionerId: form.practitionerId,
},
accountFormData: {
patientId: form.patientId,
typeCode: 1, // 默认值为 "1"
name: form.ybName,
balanceAmount: form.balanceAmount,
ybAreaNo: form.ybAreaNo,
contractNo: form.contractNo,
limitAccount: form.limitAccount,
},
chargeItemFormData: {
patientId: form.patientId,
definitionId: form.definitionId,
serviceId: form.serviceTypeId,
totalPrice: form.totalPrice, // 使用正确的总价字段
},
};
}
// 更新患者手机号
async function updatePhone() {
const params = {
id: patientInfo.value.patientId,
phone: patientInfo.value.phone,
};
console.log('params========>', JSON.stringify(params));
try {
await updatePatientPhone(params);
getList();
reset();
} catch (error) {
console.log(error);
}
}
function handleClose(value) {
openDialog.value = false;
if (value == 'success') {
proxy.$modal.msgSuccess('操作成功');
// 更新患者手机号
updatePhone();
// 先取出并清空,避免接口失败/取消等路径导致 slotId 残留污染下一单
const pendingSlotId = currentSlotId.value;
currentSlotId.value = null;
// 如果是预约签到的挂号,执行签到状态更新
if (pendingSlotId) {
checkInTicket(pendingSlotId).then(() => {
console.log('预约状态已更新为已取号');
}).catch(err => {
console.error('更新预约状态失败:', err);
ElMessage.error('预约状态更新失败,请手动签到');
});
}
} else if (value == 'cancel') {
currentSlotId.value = null;
// cancelRegister(patientInfo.value.encounterId).then((res) => {
// if (res.code == 200) {
// getList();
// }
// });
} else {
currentSlotId.value = null;
openRefundDialog.value = false;
}
}
getInitData();
getList();
getContract();
// getConditionDefinition();
getLocationInfo();
// 获取监护人规定年龄配置
async function loadGuardianAgeConfig() {
try {
const response = await getConfigKey('guardianAge');
console.log('获取监护人年龄配置完整响应:', JSON.stringify(response, null, 2));
console.log('响应 code:', response.code);
console.log('响应 data:', response.data);
console.log('响应 data 类型:', typeof response.data);
console.log('响应 data === null:', response.data === null);
console.log('响应 data === undefined:', response.data === undefined);
console.log('响应 data === "":', response.data === '');
if (response && response.code === 200) {
// response.data 可能是字符串、数字或对象
let configValue = response.data;
// 如果是对象,尝试获取 configValue 字段
if (typeof configValue === 'object' && configValue !== null) {
configValue = configValue.configValue || configValue.value || '';
console.log('从对象中提取的 configValue:', configValue);
}
// 处理数字类型(可能是数字 18
if (typeof configValue === 'number') {
configValue = String(configValue);
console.log('将数字转换为字符串:', configValue);
}
// 转换为字符串并去除空白
const trimmedValue = configValue !== null && configValue !== undefined ? String(configValue).trim() : '';
console.log('trimmedValue:', trimmedValue, '长度:', trimmedValue.length);
if (trimmedValue) {
guardianAgeConfig.value = trimmedValue;
console.log('✅ 监护人年龄配置值已设置为:', guardianAgeConfig.value, '类型:', typeof guardianAgeConfig.value);
} else {
console.warn('⚠️ 配置值为空trimmedValue:', trimmedValue);
guardianAgeConfig.value = '';
}
} else {
console.warn('⚠️ 获取监护人年龄配置失败,响应码:', response?.code, '响应:', response);
guardianAgeConfig.value = '';
}
} catch (error) {
console.error('❌ 获取监护人规定年龄配置失败:', error);
console.error('错误详情:', error.response || error);
guardianAgeConfig.value = '';
}
}
// 组件加载时获取配置
loadGuardianAgeConfig();
</script>
<style scoped>
.el-form--inline .el-form-item {
display: inline-flex;
vertical-align: middle;
margin-right: 10px !important;
}
/* 让图标和下拉选在同一行显示 */
.icon-select-container {
display: flex; /* 使用 Flexbox 布局 */
align-items: center; /* 垂直居中 */
padding-left: 0px;
}
/* 调整 el-form-item 的样式 */
.icon-select-container .el-form-item {
margin-bottom: 0; /* 去掉默认的 margin-bottom */
margin-left: 8px; /* 图标和下拉选之间的间距 */
}
/* 标题区域按钮样式 */
.header-buttons {
display: flex;
gap: 8px;
}
</style>