667 lines
18 KiB
Vue
667 lines
18 KiB
Vue
<template>
|
||
<el-dialog
|
||
title="确认收费"
|
||
v-model="props.open"
|
||
width="700px"
|
||
append-to-body
|
||
destroy-on-close
|
||
@open="handleOpen"
|
||
@close="close"
|
||
>
|
||
<div v-loading="dialogLoading">
|
||
<el-text size="large" style="display: block; margin-bottom: 15px">
|
||
收费日期:{{ currentDate }}
|
||
</el-text>
|
||
<el-text size="large">费用性质:{{ '自费' }}</el-text>
|
||
<div class="amount-row">
|
||
<el-text size="large">应收金额:</el-text>
|
||
<el-text size="large" type="primary" class="amount">
|
||
{{ props.totalAmount.toFixed(2) + ' 元' }}
|
||
</el-text>
|
||
</div>
|
||
<div class="amount-row">
|
||
<el-text size="large">折扣金额:</el-text>
|
||
<el-text size="large" type="warning" class="amount">
|
||
{{ discountAmount.toFixed(2) + ' 元' }}
|
||
</el-text>
|
||
</div>
|
||
|
||
<!-- 自费支付 -->
|
||
<div class="payment-container">
|
||
<template v-for="(item, index) in formData.selfPay" :key="index">
|
||
<div v-show="item.payEnum != 220500" class="payment-item">
|
||
<span>支付方式:</span>
|
||
<img
|
||
v-if="item.payEnum == 220100 || item.payEnum == 220200"
|
||
:src="imgs[item.payEnum == 220100 ? 0 : 1]"
|
||
style="width: 20px; height: 20px"
|
||
/>
|
||
<el-select
|
||
v-model="item.payEnum"
|
||
placeholder="选择支付方式"
|
||
style="width: 160px"
|
||
@change="(value) => clearAmount(index, value)"
|
||
>
|
||
<el-option
|
||
v-for="payEnum in selfPayMethods"
|
||
:key="payEnum.value"
|
||
:label="payEnum.label"
|
||
:value="payEnum.value"
|
||
:disabled="isMethodDisabled(payEnum)"
|
||
/>
|
||
</el-select>
|
||
<span>支付金额:</span>
|
||
<div class="suffix-wrapper">
|
||
<el-input-number
|
||
v-model="item.amount"
|
||
:precision="2"
|
||
:min="0"
|
||
:max="getMax(index)"
|
||
:controls="false"
|
||
placeholder="金额"
|
||
class="amount-input"
|
||
@change="handleAmountChange"
|
||
/>
|
||
<span class="suffix-text">元</span>
|
||
</div>
|
||
<el-button
|
||
type="danger"
|
||
circle
|
||
:icon="Delete"
|
||
@click="removePayment(index)"
|
||
v-if="index > 0"
|
||
/>
|
||
</div>
|
||
</template>
|
||
<div class="add-payment">
|
||
<el-button
|
||
type="primary"
|
||
plain
|
||
@click="addPayment"
|
||
:disabled="formData.selfPay.length >= 4 || remainingAmount <= 0"
|
||
>
|
||
添加支付方式
|
||
</el-button>
|
||
<el-text v-if="remainingAmount <= 0" type="danger" class="tip">
|
||
金额已满足应收,不可继续添加
|
||
</el-text>
|
||
</div>
|
||
<div style="margin-top: 10px" v-if="userStore.fixmedinsCode == 'H22010200672'">
|
||
<span>折扣:</span>
|
||
<el-radio-group v-model="discountRadio" @change="handleDiscountChange">
|
||
<el-radio-button
|
||
v-for="item in charge_discount"
|
||
:key="item.value"
|
||
link
|
||
:label="item.label"
|
||
:value="item.value"
|
||
/>
|
||
</el-radio-group>
|
||
</div>
|
||
</div>
|
||
<div class="payment-item">
|
||
<span>{{ payTypeText }}支付:</span>
|
||
<el-input
|
||
ref="txtCodeRef"
|
||
v-model="txtCode"
|
||
style="width: 300px"
|
||
:placeholder="payTypePlaceholder"
|
||
/>
|
||
<el-button link type="primary" @click="handleWxPay()">扫码支付</el-button>
|
||
<el-button link type="primary" @click="getWxPayResult()">查看结果</el-button>
|
||
</div>
|
||
<div>
|
||
<el-table :data="props.details" max-height="200" border>
|
||
<el-table-column prop="payEnumText" label="支付类型" align="center" />
|
||
<el-table-column
|
||
prop="amount"
|
||
label="金额"
|
||
header-align="center"
|
||
align="right"
|
||
width="200"
|
||
>
|
||
<template #default="scope">
|
||
{{ scope.row.amount ? scope.row.amount + ' 元' : '-' }}
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
<!-- 金额汇总 -->
|
||
<div class="summary">
|
||
<el-space :size="30">
|
||
<div class="summary-item">
|
||
<el-text type="info">实收合计:</el-text>
|
||
<el-text type="success">{{ displayAmount + ' 元' }}</el-text>
|
||
</div>
|
||
<div class="summary-item">
|
||
<el-text type="info">应找零:</el-text>
|
||
<el-text type="warning">{{ returnedAmount + ' 元' }}</el-text>
|
||
</div>
|
||
</el-space>
|
||
</div>
|
||
</div>
|
||
<template #footer>
|
||
<div class="dialog-footer">
|
||
<el-button type="primary" @click="throttledGetList" :disabled="dialogLoading">
|
||
确 定
|
||
</el-button>
|
||
<!-- <el-button type="primary" @click="print()" :disabled="dialogLoading">打 印</el-button> -->
|
||
<el-button @click="close" :disabled="dialogLoading">取 消</el-button>
|
||
</div>
|
||
</template>
|
||
</el-dialog>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {dispenseMedicalConsumables, getChargeInfo, savePayment, wxPay, WxPayResult,} from './api';
|
||
import {computed, getCurrentInstance, nextTick, reactive, ref, watch} from 'vue';
|
||
import {Delete} from '@element-plus/icons-vue';
|
||
import {debounce} from 'lodash-es';
|
||
import useUserStore from '@/store/modules/user';
|
||
import printUtils, {PRINT_TEMPLATE} from '@/utils/printUtils';
|
||
import image1 from '../../../../../assets/images/weixinzhifu.png';
|
||
import image2 from '../../../../../assets/images/zhifubaozhifu.png';
|
||
|
||
const imgs = ref([image1, image2]);
|
||
const props = defineProps({
|
||
open: {
|
||
type: Boolean,
|
||
default: false,
|
||
},
|
||
totalAmount: {
|
||
type: Number,
|
||
default: 0.0,
|
||
},
|
||
category: {
|
||
type: String,
|
||
},
|
||
paymentId: {
|
||
type: String,
|
||
},
|
||
userCardInfo: {
|
||
type: Object,
|
||
},
|
||
patientInfo: {
|
||
type: Object,
|
||
default: undefined,
|
||
},
|
||
chargeItemIds: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
consumablesIdList: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
chrgBchnoList: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
details: {
|
||
type: Object,
|
||
default: undefined,
|
||
},
|
||
chargedItems: {
|
||
type: Array,
|
||
default: () => [],
|
||
},
|
||
newId: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
oldId: {
|
||
type: String,
|
||
default: '',
|
||
},
|
||
});
|
||
|
||
const { proxy } = getCurrentInstance();
|
||
|
||
const { charge_discount } = proxy.useDict('charge_discount');
|
||
|
||
const userStore = useUserStore();
|
||
const discountRadio = ref();
|
||
const discountAmount = ref(0);
|
||
const txtCode = ref('');
|
||
const formData = reactive({
|
||
totalAmount: 0,
|
||
selfPay: [{ payEnum: 220100, amount: 0.0, payLevelEnum: 2 }],
|
||
medicalInsurance: {
|
||
account: '',
|
||
poolPay: 0,
|
||
personalPay: 0,
|
||
},
|
||
});
|
||
const dialogLoading = ref(false);
|
||
|
||
watch(
|
||
() => props.totalAmount,
|
||
(newValue) => {
|
||
nextTick(() => {});
|
||
formData.totalAmount = newValue;
|
||
formData.selfPay[0].amount = newValue;
|
||
}
|
||
);
|
||
|
||
const emit = defineEmits(['close']);
|
||
let displayAmountTemp = 0;
|
||
|
||
// 打印小票
|
||
async function printReceipt(param) {
|
||
let total = 0;
|
||
props.chargedItems.forEach((item) => {
|
||
total += item.totalPrice || 0;
|
||
});
|
||
|
||
try {
|
||
// 构造打印数据
|
||
const printData = {
|
||
data: [
|
||
{
|
||
...param,
|
||
// 基础支付类型
|
||
YB_FUND_PAY:
|
||
(param.detail?.find((t) => t.payEnum === 100000)?.amount?.toFixed(2) || '0.00') + ' 元',
|
||
SELF_PAY: (param.detail?.find((t) => t.payEnum === 200000)?.amount?.toFixed(2) || '0.00') + ' 元',
|
||
OTHER_PAY: param.detail?.find((t) => t.payEnum === 300000)?.amount ?? 0, // 其他(如医院负担金额)
|
||
|
||
// 基本医保统筹基金支出
|
||
YB_TC_FUND_AMOUNT:
|
||
(param.detail?.find((t) => t.payEnum === 110000)?.amount?.toFixed(2) || '0.00') + ' 元',
|
||
YB_BC_FUND_AMOUNT:
|
||
(param.detail?.find((t) => t.payEnum === 120000)?.amount?.toFixed(2) || '0.00') + ' 元',
|
||
YB_JZ_FUND_AMOUNT:
|
||
(param.detail?.find((t) => t.payEnum === 130000)?.amount?.toFixed(2) || '0.00') + ' 元',
|
||
|
||
// 医保结算返回值
|
||
FULAMT_OWNPAY_AMT:
|
||
(param.detail?.find((t) => t.payEnum === 1)?.amount?.toFixed(2) || '0.00') + ' 元',
|
||
INSCP_SCP_AMT: (param.detail?.find((t) => t.payEnum === 5)?.amount?.toFixed(2) || '0.00') + ' 元',
|
||
|
||
// 特殊支付方式
|
||
SELF_YB_ZH_PAY:
|
||
(param.detail?.find((t) => t.payEnum === 210000)?.amount?.toFixed(2) || '0.00') + ' 元',
|
||
|
||
Mr_QR_Code: param.regNo,
|
||
sex: props.patientInfo?.genderEnum_enumText || '',
|
||
age: props.patientInfo?.age || '',
|
||
personType: '职工医保',
|
||
fixmedinsName: (param.fixmedinsName || '') + '门诊收费明细',
|
||
name: props.patientInfo?.patientName || '', // 姓名
|
||
gender: props.patientInfo?.genderEnum_enumText || '', // 性别
|
||
encounterBusNo: props.patientInfo?.encounterBusNo || '', // 病例号
|
||
currentDate: currentDate.value, // 收费日期
|
||
chargedItems: props.chargedItems, // 收费项目
|
||
totalAmount: props.totalAmount.toFixed(2) + ' 元', // 应收金额
|
||
itemTotalAmount: total.toFixed(2) + ' 元', // 应收金额
|
||
displayAmount: displayAmountTemp + ' 元', // 实收金额
|
||
returnedAmount: returnedAmount.value + ' 元', // 应找零
|
||
userName: userStore.nickName,
|
||
},
|
||
],
|
||
};
|
||
|
||
// 使用printUtils进行打印
|
||
await printUtils.print(PRINT_TEMPLATE.OUTPATIENT_CHARGE, printData.data[0]);
|
||
console.log('打印成功');
|
||
} catch (error) {
|
||
console.error('打印失败:', error);
|
||
proxy.$modal.msgError('打印失败: ' + error.message);
|
||
}
|
||
}
|
||
|
||
const throttledGetList = debounce(submit, 300);
|
||
|
||
function handleWxPay() {
|
||
wxPay({
|
||
txtCode: txtCode.value,
|
||
chargeItemIds: props.chargeItemIds,
|
||
encounterId: props.patientInfo.encounterId,
|
||
id: props.paymentId,
|
||
paymentDetails: formData.selfPay,
|
||
ybMdtrtCertType: props.userCardInfo.psnCertType,
|
||
busiCardInfo: props.userCardInfo.busiCardInfo,
|
||
});
|
||
}
|
||
|
||
function getWxPayResult() {
|
||
WxPayResult({
|
||
txtCode: txtCode.value,
|
||
chargeItemIds: props.chargeItemIds,
|
||
encounterId: props.patientInfo.encounterId,
|
||
id: props.paymentId,
|
||
paymentDetails: formData.selfPay,
|
||
ybMdtrtCertType: props.userCardInfo.psnCertType,
|
||
busiCardInfo: props.userCardInfo.busiCardInfo,
|
||
});
|
||
}
|
||
|
||
function handleOpen() {
|
||
formData.totalAmount = props.totalAmount;
|
||
formData.selfPay[0].amount = props.totalAmount;
|
||
}
|
||
|
||
async function submit() {
|
||
displayAmountTemp = displayAmount.value;
|
||
|
||
let amount = formData.selfPay
|
||
.reduce((sum, item) => {
|
||
return sum + (Number(item.amount) || 0);
|
||
}, 0)
|
||
.toFixed(2);
|
||
if (parseFloat(amount) < formData.totalAmount.toFixed(2)) {
|
||
proxy.$modal.msgError('请输入正确的结算金额');
|
||
return;
|
||
}
|
||
dialogLoading.value = true;
|
||
console.log(props.newId, props.oldId);
|
||
savePayment({
|
||
chargeItemIds: props.chargeItemIds,
|
||
encounterId: props.patientInfo.encounterId,
|
||
id: props.paymentId,
|
||
paymentDetails: formData.selfPay,
|
||
ybMdtrtCertType: props.userCardInfo.psnCertType,
|
||
busiCardInfo: props.userCardInfo.busiCardInfo,
|
||
newId: props.newId,
|
||
oldId: props.oldId,
|
||
})
|
||
.then((res) => {
|
||
if (res.code == 200) {
|
||
getChargeInfo({ paymentId: props.paymentId }).then((res) => {
|
||
// printReceipt(res.data);
|
||
});
|
||
formData.selfPay = [{ payEnum: 220100, amount: 0.0, payLevelEnum: 2 }];
|
||
emit('close', 'success', res.msg);
|
||
emit('refresh'); // 发送刷新事件给父组件
|
||
// 长春市朝阳区中医院自动发耗材
|
||
if (userStore.fixmedinsCode == 'H22010200672' && props.consumablesIdList.length > 0) {
|
||
dispenseMedicalConsumables(props.consumablesIdList).catch(err => {
|
||
console.warn('自动发耗材失败:', err);
|
||
});
|
||
}
|
||
}
|
||
})
|
||
.finally(() => {
|
||
dialogLoading.value = false;
|
||
});
|
||
}
|
||
|
||
/** 打印收费结算单 */
|
||
async function print() {
|
||
console.log('patientInfo', props.patientInfo);
|
||
let total = 0;
|
||
props.chargedItems.forEach((item) => {
|
||
total += item.totalPrice || 0;
|
||
});
|
||
|
||
try {
|
||
const printData = {
|
||
data: [
|
||
{
|
||
name: props.patientInfo.patientName, // 姓名
|
||
gender: props.patientInfo.genderEnum_enumText, // 性别
|
||
age: props.patientInfo.age, // 年龄
|
||
encounterBusNo: props.patientInfo.encounterBusNo, // 病例号
|
||
currentDate: currentDate.value, // 收费日期
|
||
chargedItems: props.chargedItems, // 收费项目
|
||
totalAmount: props.totalAmount.toFixed(2) + ' 元', // 应收金额
|
||
itemTotalAmount: total.toFixed(2) + ' 元', // 项目总金额
|
||
displayAmount: displayAmount.value + ' 元', // 实收金额
|
||
returnedAmount: returnedAmount.value + ' 元', // 应找零
|
||
userName: userStore.nickName,
|
||
},
|
||
],
|
||
};
|
||
|
||
// 使用printUtils进行打印
|
||
await printUtils.print(PRINT_TEMPLATE.OUTPATIENT_CHARGE, printData.data[0]);
|
||
console.log('打印成功');
|
||
} catch (error) {
|
||
console.error('打印失败:', error);
|
||
proxy.$modal.msgError('打印失败: ' + error.message);
|
||
}
|
||
}
|
||
|
||
const currentDate = ref(new Date().toLocaleString());
|
||
|
||
const selfPayMethods = [
|
||
{ label: '现金', value: 220400, isWebPay: false },
|
||
{ label: '微信', value: 220100, isWebPay: true },
|
||
{ label: '支付宝', value: 220200, isWebPay: true },
|
||
{ label: '银联', value: 220300, isWebPay: true },
|
||
{ label: '优惠', value: 220500, isWebPay: false },
|
||
];
|
||
|
||
// 计算剩余可输入金额
|
||
const remainingAmount = computed(() => {
|
||
return (
|
||
formData.totalAmount - formData.selfPay.reduce((sum, item) => sum + Number(item.amount), 0)
|
||
);
|
||
});
|
||
|
||
// 获取单个支付方式的最大可输入金额
|
||
const getMax = (index) => {
|
||
const otherSum = formData.selfPay.reduce(
|
||
(sum, item, i) => (i !== index ? sum + Number(item.amount) : sum),
|
||
0
|
||
);
|
||
if (formData.selfPay[index].payEnum == 220400) {
|
||
return formData.totalAmount + 100 - otherSum;
|
||
}
|
||
return formData.totalAmount - otherSum;
|
||
};
|
||
|
||
// 折扣计算
|
||
function handleDiscountChange(value) {
|
||
let amount = props.totalAmount * Number(value);
|
||
discountAmount.value = props.totalAmount - amount;
|
||
formData.selfPay = [
|
||
{ payEnum: 220100, amount: amount, payLevelEnum: 2 },
|
||
{ payEnum: 220500, amount: discountAmount.value, payLevelEnum: 2 },
|
||
];
|
||
}
|
||
|
||
// 检查支付方式是否已使用
|
||
const isMethodDisabled = (option) => {
|
||
if (formData.selfPay.length > 1) {
|
||
// 禁用已被选择的相同方式,避免重复选择
|
||
const selectedEnums = formData.selfPay.map((item) => item.payEnum);
|
||
if (selectedEnums.includes(option.value)) {
|
||
return true;
|
||
}
|
||
// 若已经选择了任一线上支付方式,则其他线上方式不可再选,仅允许现金等线下方式
|
||
const hasSelectedWebPay = selectedEnums.some((val) => {
|
||
const found = selfPayMethods.find((m) => m.value === val);
|
||
return found ? found.isWebPay === true : false;
|
||
});
|
||
if (hasSelectedWebPay && option.isWebPay) {
|
||
return true;
|
||
}
|
||
return false;
|
||
} else {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
const handleAmountChange = () => {
|
||
// 不需要在这里直接设置 returnedAmount,依赖 computed 属性
|
||
};
|
||
|
||
const addPayment = () => {
|
||
if (remainingAmount.value <= 0) {
|
||
return;
|
||
}
|
||
formData.selfPay.push({ payEnum: '', amount: remainingAmount.value });
|
||
};
|
||
|
||
const removePayment = (index) => {
|
||
formData.selfPay.splice(index, 1);
|
||
};
|
||
|
||
const payTypeText = ref('微信');
|
||
const payTypePlaceholder = computed(() => {
|
||
if (payTypeText.value === '现金') {
|
||
return '请输入现金金额';
|
||
}
|
||
return payTypeText.value + '支付二维码';
|
||
});
|
||
const clearAmount = (index, value) => {
|
||
const selectedOption = selfPayMethods.find((item) => item.value === value);
|
||
if (selectedOption) {
|
||
payTypeText.value = selectedOption.label;
|
||
}
|
||
};
|
||
|
||
// 计算属性
|
||
const displayAmount = computed(() => {
|
||
return formData.selfPay
|
||
.reduce((sum, item) => {
|
||
if (item.payEnum !== 220500) {
|
||
return sum + (Number(item.amount) || 0);
|
||
}
|
||
return sum;
|
||
}, 0)
|
||
.toFixed(2);
|
||
});
|
||
const returnedAmount = computed(() => {
|
||
const display = parseFloat(displayAmount.value);
|
||
if (isNaN(display) || display <= 0) {
|
||
return '0.00';
|
||
}
|
||
const returned = display - formData.totalAmount;
|
||
return returned >= 0 ? returned.toFixed(2) : '0.00';
|
||
});
|
||
|
||
function close() {
|
||
// unprecharge({ encounterId: props.patientInfo.encounterId }).then((res) => {
|
||
// if (res.code == 200) {
|
||
// emit('close');
|
||
// } else {
|
||
// proxy.$modal.msgError(res.message);
|
||
// }
|
||
// });
|
||
txtCode.value = '';
|
||
|
||
formData.totalAmount = 0;
|
||
formData.selfPay = [{ payEnum: 220100, amount: 0.0, payLevelEnum: 2 }];
|
||
formData.medicalInsurance = {
|
||
account: '',
|
||
poolPay: 0,
|
||
personalPay: 0,
|
||
};
|
||
|
||
// 重置折扣相关状态
|
||
discountRadio.value = undefined;
|
||
discountAmount.value = 0;
|
||
emit('close');
|
||
}
|
||
|
||
defineExpose({
|
||
printReceipt,
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
:deep(.pagination-container .el-pagination) {
|
||
right: 20px !important;
|
||
}
|
||
.charge-container {
|
||
max-width: 600px;
|
||
margin: 20px auto;
|
||
padding: 20px 30px;
|
||
}
|
||
|
||
.header {
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.amount-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15px;
|
||
margin: 15px 0;
|
||
}
|
||
|
||
.amount {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.payment-type {
|
||
margin: 15px 0;
|
||
}
|
||
|
||
.payment-container {
|
||
margin: 15px 0;
|
||
}
|
||
|
||
.payment-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.amount-input {
|
||
width: 140px;
|
||
}
|
||
|
||
.add-payment {
|
||
margin-top: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.tip {
|
||
font-size: 12px;
|
||
}
|
||
|
||
.summary {
|
||
margin: 25px 0;
|
||
padding: 15px;
|
||
background-color: #f8f9fa;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.summary-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.action-buttons {
|
||
text-align: center;
|
||
margin-top: 25px;
|
||
}
|
||
|
||
.el-text.el-text--success {
|
||
font-size: 18px !important;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.el-text.el-text--warning {
|
||
font-size: 18px !important;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.suffix-wrapper {
|
||
position: relative;
|
||
display: inline-block; /* 保持行内布局 */
|
||
}
|
||
|
||
.suffix-text {
|
||
position: absolute;
|
||
right: 10px;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
color: #999;
|
||
pointer-events: none; /* 避免点击干扰 */
|
||
}
|
||
|
||
/* 调整输入框内边距 */
|
||
.amount-input .el-input__inner {
|
||
padding-right: 30px !important;
|
||
}
|
||
</style>
|