Files
his/openhis-ui-vue3/src/views/charge/surgerycharge/index.vue
2026-05-27 08:59:07 +08:00

503 lines
16 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 style="display: flex; justify-content: space-between" class="app-container" v-loading="loading"
:element-loading-text="loadingText">
<!-- 左侧患者基本信息区 -->
<el-card style="width: 30%">
<template #header>
<span style="vertical-align: middle">患者基本信息</span>
</template>
<el-descriptions :column="1" border>
<el-descriptions-item label="病历号">{{ patientInfo.encounterBusNo }}</el-descriptions-item>
<el-descriptions-item label="姓名">{{ patientInfo.patientName }}</el-descriptions-item>
<el-descriptions-item label="性别">{{ patientInfo.genderEnum_enumText }}</el-descriptions-item>
<el-descriptions-item label="年龄">{{ patientInfo.age }}</el-descriptions-item>
<el-descriptions-item label="科室">{{ patientInfo.organizationName }}</el-descriptions-item>
<el-descriptions-item label="就诊时间">
{{ formatDateStr(patientInfo.receptionTime, 'YYYY-MM-DD HH:mm:ss') }}
</el-descriptions-item>
<el-descriptions-item label="手术单号">{{ surgeryInfo.surgeryNo }}</el-descriptions-item>
<el-descriptions-item label="手术名称">{{ surgeryInfo.surgeryName }}</el-descriptions-item>
</el-descriptions>
</el-card>
<!-- 右侧收费项目区 -->
<div style="width: 69%">
<el-card style="min-width: 1100px">
<template #header>
<span style="vertical-align: middle">收费项目</span>
</template>
<div style="margin-bottom: 10px">
<el-button type="primary" @click="confirmCharge()" :disabled="buttonDisabled">
确认收费
</el-button>
<el-button type="primary" plain @click="handleReadCard('01')" style="width: 65px">
电子凭证
</el-button>
<el-button type="primary" plain @click="handleReadCard('03')" style="width: 65px">
医保卡
</el-button>
<span style="float: right">
合计金额{{ totalAmounts ? totalAmounts.toFixed(2) : 0 }}
</span>
</div>
<el-table
ref="chargeListRef"
height="530"
:data="chargeList"
row-key="id"
@selection-change="handleSelectionChange"
v-loading="chargeLoading"
:span-method="objectSpanMethod"
border
>
<el-table-column type="selection" :selectable="checkSelectable" width="55" />
<el-table-column label="单据号" align="center" prop="busNo" width="180" />
<el-table-column label="收费项目" align="center" prop="itemName" width="200" />
<el-table-column label="数量" align="center" prop="quantityValue" width="80" />
<el-table-column label="医疗类型" align="center" prop="medTypeCode_dictText" />
<el-table-column label="医保编码" align="center" prop="ybNo" />
<el-table-column label="费用性质" align="center" prop="contractName" />
<el-table-column label="收费状态" align="center" prop="statusEnum_enumText" width="150">
<template #default="scope">
<el-tag v-if="scope.row.statusEnum === 1" disable-transitions>
{{ scope.row.statusEnum_enumText }}
</el-tag>
<el-tag v-else-if="scope.row.statusEnum === 5" type="success" disable-transitions>
{{ scope.row.statusEnum_enumText }}
</el-tag>
<el-tag v-else-if="scope.row.statusEnum === 8" type="danger" disable-transitions>
{{ scope.row.statusEnum_enumText }}
</el-tag>
<el-tag v-else type="warning" disable-transitions>
{{ scope.row.statusEnum_enumText }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="金额" align="right" prop="totalPrice" header-align="center">
<template #default="scope">
{{ scope.row.totalPrice.toFixed(2) + ' 元' || '0.00' + ' 元' }}
</template>
</el-table-column>
<el-table-column label="收款人" align="center" prop="entererId_dictText" />
<el-table-column
label="操作"
align="center"
fixed="right"
header-align="center"
class-name="no-hover-column"
>
<template #default="scope">
<el-button
:disabled="!scope.row.paymentId"
link
type="primary"
@click="printCharge(scope.row)"
>
打印
</el-button>
</template>
</el-table-column>
</el-table>
</el-card>
</div>
<!-- 收费对话框 -->
<ChargeDialog
ref="chargeDialogRef"
:open="openDialog"
@close="handleClose"
:category="patientInfo.categoryEnum"
:totalAmount="totalAmount"
:patientInfo="patientInfo"
:chargeItemIds="chargeItemIdList"
:consumablesIdList="consumablesIdList"
:chrgBchnoList="chrgBchnoList"
:userCardInfo="userCardInfo"
:paymentId="paymentId"
:details="details"
:chargedItems="chargedItems"
:feeType="patientInfo.medfeePaymtdCode"
:medfee_paymtd_code="medfee_paymtd_code"
@refresh="getChargeList"
/>
</div>
</template>
<script setup name="SurgeryCharge">
import {
getChargeList,
precharge,
getChargeInfo,
} from '../cliniccharge/components/api';
import {invokeYbPlugin5000, invokeYbPlugin5001} from '@/api/public';
import ChargeDialog from '../cliniccharge/components/chargeDialog.vue';
import {formatDateStr} from '@/utils';
import useUserStore from '@/store/modules/user';
import Decimal from 'decimal.js';
const { proxy } = getCurrentInstance();
const userStore = useUserStore();
const { medfee_paymtd_code } = proxy.useDict('medfee_paymtd_code');
// Props: 从手术安排界面传入的患者信息和手术信息
const props = defineProps({
patientInfo: {
type: Object,
required: true,
default: () => ({})
},
surgeryInfo: {
type: Object,
required: true,
default: () => ({})
}
});
// 数据定义
const totalAmounts = ref(0);
const selectedRows = ref([]);
const chargeList = ref([]);
const chargeItemIdList = ref([]);
const chrgBchnoList = ref([]);
const chargeLoading = ref(false);
const encounterId = ref('');
const paymentId = ref('');
const openDialog = ref(false);
const totalAmount = ref(0);
const chargeListRef = ref();
const details = ref({});
const buttonDisabled = computed(() => {
return Object.keys(props.patientInfo).length === 0;
});
const chargedItems = ref([]);
const consumablesIdList = ref([]);
const userCardInfo = ref({});
const readCardLoading = ref(false);
const loadingText = ref('');
const loading = ref(false);
// Watch
watch(
() => selectedRows.value,
(newVlaue) => {
if (newVlaue && newVlaue.length > 0) {
handleTotalAmount();
} else {
totalAmounts.value = 0;
}
},
{ immediate: true }
);
watch(
() => chargeList.value,
(newVlaue) => {
if (newVlaue && newVlaue.length > 0) {
handleTotalAmount();
} else {
totalAmounts.value = 0;
}
},
{ immediate: true }
);
// 初始化
onMounted(() => {
if (props.patientInfo && props.patientInfo.encounterId) {
encounterId.value = props.patientInfo.encounterId;
fetchChargeList();
}
});
// 方法
function handleSelectionChange(selection) {
selectedRows.value = selection;
}
function handleTotalAmount() {
if (selectedRows.value.length == 0) {
totalAmounts.value = chargeList.value.reduce((accumulator, currentRow) => {
return new Decimal(accumulator).add(currentRow.totalPrice.toFixed(2) || 0);
}, new Decimal(0));
} else {
totalAmounts.value = selectedRows.value.reduce((accumulator, currentRow) => {
return new Decimal(accumulator).add(currentRow.totalPrice.toFixed(2) || 0);
}, 0);
}
}
// 获取收费项目列表(只显示该手术已计费的项目)
function fetchChargeList() {
if (!props.patientInfo.encounterId) {
return;
}
chargeLoading.value = true;
// 调用门诊划价的getChargeList接口传入encounterId
// 只显示generateSourceEnum=2手术计费且sourceBillNo=手术单号的费用项
getChargeList(props.patientInfo.encounterId).then((res) => {
// 过滤出手术计费的收费项目
chargeList.value = (res.data || []).filter(item =>
item.generateSourceEnum === 2 && item.sourceBillNo === props.surgeryInfo.surgeryNo
);
setTimeout(() => {
chargeLoading.value = false;
// 默认选中所有未收费的项目
if (chargeListRef.value) {
chargeListRef.value.toggleAllSelection();
}
}, 100);
}).catch(() => {
chargeLoading.value = false;
});
}
function checkSelectable(row, index) {
// 已结算时禁用选择框
return row.statusEnum === 1;
}
function handleClose(value, msg) {
openDialog.value = false;
if (value == 'success') {
proxy.$modal.msgSuccess(msg);
fetchChargeList();
}
}
// 确认收费
function confirmCharge() {
let selectRows = chargeListRef.value.getSelectionRows();
if (selectRows.length == 0) {
proxy.$modal.msgWarning('请选择一条收费项目');
return;
}
chargeItemIdList.value = selectRows.map((item) => {
return item.id;
});
consumablesIdList.value = selectRows
.filter((item) => {
return item.serviceTable == 'wor_device_request';
})
.map((item) => {
return item.id;
});
chargedItems.value = selectRows;
precharge({
patientId: props.patientInfo.patientId,
encounterId: props.patientInfo.encounterId,
chargeItemIds: chargeItemIdList.value,
// 传递手术计费标识
generateSourceEnum: 2,
sourceBillNo: props.surgeryInfo.surgeryNo,
}).then((res) => {
if (res.code == 200 && res.data) {
paymentId.value = res.data.paymentId;
chrgBchnoList.value = res.data.chrgBchnoList;
totalAmount.value = res.data.details?.find((item) => item.payEnum == 220000)?.amount ?? 0;
details.value = res.data.details?.filter((item) => {
return item.amount > 0;
}) || [];
openDialog.value = true;
} else {
proxy.$modal.msgError(res?.msg || '预结算失败');
}
});
}
// 读卡功能
async function handleReadCard(value) {
try {
let jsonResult;
let cardInfo;
let userMessage = undefined;
switch (value) {
case '01': // 电子凭证
await invokeYbPlugin5000({
FunctionId: 3,
url: 'http://10.47.0.67:8089/localcfc/api/hsecfc/localQrCodeQuery',
orgId: 'H22010200672',
businessType: '01101',
operatorId: userStore.id.toString(),
operatorName: userStore.name,
officeId: 'D83',
officeName: '财务科',
})
.then((res) => {
readCardLoading.value = true;
loadingText.value = '正在读取...';
jsonResult = res.data;
})
.catch(() => {
readCardLoading.value = false;
})
.finally(() => {
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.value = {
certType: '01',
certNo: message.data.idNo,
psnCertType: '01',
busiCardInfo: message.data.ecToken,
};
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;
});
let message1 = JSON.parse(jsonResult);
userMessage = {
certType: '02',
certNo: message1.SocialSecurityNumber,
psnCertType: '02',
};
userCardInfo.value = {
certType: '02',
certNo: message1.SocialSecurityNumber,
psnCertType: '02',
busiCardInfo: message1.BusiCardInfo,
};
break;
}
readCardLoading.value = false;
if (userMessage.certNo) {
let selectRows = chargeListRef.value.getSelectionRows();
if (selectRows.length == 0) {
proxy.$modal.msgWarning('请选择一条收费项目');
return;
}
chargeItemIdList.value = selectRows.map((item) => {
return item.id;
});
totalAmount.value = selectRows.reduce((accumulator, currentRow) => {
return accumulator + (currentRow.totalPrice || 0);
}, 0);
precharge({
patientId: props.patientInfo.patientId,
encounterId: props.patientInfo.encounterId,
chargeItemIds: chargeItemIdList.value,
ybMdtrtCertType: userCardInfo.value.psnCertType,
busiCardInfo: userCardInfo.value.busiCardInfo,
generateSourceEnum: 2,
sourceBillNo: props.surgeryInfo.surgeryNo,
}).then((res) => {
if (res.code == 200 && res.data) {
paymentId.value = res.data.paymentId;
totalAmount.value = res.data.details?.find((item) => item.payEnum == 220000)?.amount ?? 0;
details.value = res.data.details || [];
chargeItemIdList.value = selectRows.map((item) => {
return item.id;
});
chargedItems.value = selectRows;
consumablesIdList.value = selectRows
.filter((item) => {
return item.serviceTable == 'wor_device_request';
})
.map((item) => {
return item.id;
});
openDialog.value = true;
} else {
proxy.$modal.msgError(res?.msg || '预结算失败');
}
});
}
} catch (error) {
console.error('调用失败:', error);
readCardLoading.value = false;
}
}
// 行合并方法
function objectSpanMethod({ row, column, rowIndex, columnIndex }) {
if (columnIndex === 10) {
if (!row.paymentId) {
return [1,1];
}
let spanCount = 1;
if (rowIndex === 0 || chargeList.value[rowIndex - 1].paymentId !== row.paymentId) {
for (let i = rowIndex + 1; i < chargeList.value.length; i++) {
if (chargeList.value[i].paymentId === row.paymentId) {
spanCount++;
} else {
break;
}
}
return [spanCount, 1];
} else {
return [0, 0];
}
}
return [1, 1];
}
// 打印功能
function printCharge(row) {
let rows = [];
chargeList.value.forEach((item, index) => {
if (item.paymentId === row.paymentId) {
rows.push(item);
}
});
chargedItems.value = rows;
getChargeInfo({ paymentId: row.paymentId }).then((res) => {
if (res.data && res.data.detail) {
const amountDetail = res.data.detail?.find((item) => item.payEnum == 220000);
if (amountDetail) {
totalAmount.value = amountDetail.amount || 0;
rows.forEach((item) => {
if (item.actualPrice === undefined || item.actualPrice === null) {
item.actualPrice = 0;
}
if (item.discountAmount === undefined || item.discountAmount === null) {
item.discountAmount = 0;
}
if (item.discountRate === undefined || item.discountRate === null) {
item.discountRate = 100;
}
});
}
const enhancedPrintData = {
...res.data,
selectedRow: row,
chargedItems: rows,
};
nextTick(() => {
proxy.$refs['chargeDialogRef'].printReceipt(enhancedPrintData);
});
}
});
}
</script>
<style scoped>
:deep(.no-hover-column) .cell:hover {
background-color: transparent !important;
}
:deep(.el-table__body) tr:hover td.no-hover-column {
background-color: inherit !important;
}
</style>