版本更新

This commit is contained in:
Zhang.WH
2025-09-03 15:54:41 +08:00
parent 0b93d16b64
commit 8f82322d10
3290 changed files with 154339 additions and 23829 deletions

View File

@@ -0,0 +1,466 @@
<template>
<el-dialog title="确认收费" v-model="props.open" width="700px" append-to-body destroy-on-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="payment-container">
<div v-for="(item, index) in formData.selfPay" :key="index" class="payment-item">
<span>支付方式</span>
<el-select
v-model="item.payEnum"
placeholder="选择支付方式"
style="width: 160px"
@change="clearAmount(index)"
>
<el-option
v-for="payEnum in selfPayMethods"
:key="payEnum.value"
:label="payEnum.label"
:value="payEnum.value"
:disabled="isMethodDisabled(payEnum.value)"
/>
</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>
<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>
<!-- 金额汇总 -->
<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 @click="close" :disabled="dialogLoading"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { savePayment } from './outpatientregistration';
import { computed, watch, reactive, ref, getCurrentInstance, nextTick } from 'vue';
import { Delete } from '@element-plus/icons-vue';
import { debounce } from 'lodash-es';
const props = defineProps({
open: {
type: Boolean,
default: false,
},
totalAmount: {
type: Number,
default: 0.0,
},
patientInfo: {
type: Object,
default: undefined,
},
chargeItemIds: {
type: [],
default: [],
},
chrgBchnoList: {
type: [],
default: [],
},
chrgBchno: {
type: String,
default: '',
},
registerBusNo: {
type: String,
default: '',
},
transformedData: {
type: Object,
default: undefined,
},
});
const { proxy } = getCurrentInstance();
const dialogLoading = ref(false);
const throttledGetList = debounce(submit, 300);
const formData = reactive({
totalAmount: 0,
selfPay: [{ payEnum: 220100, amount: 0.0, payLevelEnum: 2 }],
medicalInsurance: {
account: '',
poolPay: 0,
personalPay: 0,
},
});
watch(
() => props.totalAmount,
(newValue) => {
nextTick(() => {
formData.totalAmount = newValue;
formData.selfPay[0].amount = newValue;
});
}
);
const emit = defineEmits(['close']);
async function printReceipt(param) {
console.log(param, 'param');
console.log(props.patientInfo, 'props.patientInfo');
// 构造一个新的对象,添加头 "data"
const result = {
data: [
{
...param,
// 基础支付类型
YB_FUND_PAY: param.detail.find((t) => t.payEnum === 100000)?.amount ?? 0, // 基金支付总额
SELF_PAY: param.detail.find((t) => t.payEnum === 200000)?.amount ?? 0, // 个人负担总金额
OTHER_PAY: param.detail.find((t) => t.payEnum === 300000)?.amount ?? 0, // 其他(如医院负担金额)
// 基本医保统筹基金支出
YB_TC_FUND_AMOUNT: param.detail.find((t) => t.payEnum === 110000)?.amount ?? 0, // 基本医保统筹基金支出
YB_BC_FUND_AMOUNT: param.detail.find((t) => t.payEnum === 120000)?.amount ?? 0, // 补充医疗保险基金支出
YB_JZ_FUND_AMOUNT: param.detail.find((t) => t.payEnum === 130000)?.amount ?? 0, // 医疗救助基金支出
YB_OTHER_AMOUNT: param.detail.find((t) => t.payEnum === 140000)?.amount ?? 0, // 其他支出
// 职工基本医疗保险
YB_TC_ZG_FUND_VALUE: param.detail.find((t) => t.payEnum === 110100)?.amount ?? 0, // 职工基本医疗保险
YB_TC_JM_FUND_VALUE: param.detail.find((t) => t.payEnum === 110200)?.amount ?? 0, // 居民基本医疗保险(修正原错误注释)
// 补充医疗保险基金支出细分
YB_BC_JM_DB_VALUE: param.detail.find((t) => t.payEnum === 120100)?.amount ?? 0, // 全体参保人的居民大病保险
YB_BC_DE_BZ_VALUE: param.detail.find((t) => t.payEnum === 120200)?.amount ?? 0, // 大额医疗费用补助
YB_BC_ZG_DE_BZ_VALUE: param.detail.find((t) => t.payEnum === 120300)?.amount ?? 0, // 企业职工大额医疗费用补助
YB_BC_GWY_BZ_VALUE: param.detail.find((t) => t.payEnum === 120400)?.amount ?? 0, // 公务员医疗补助
// 其他支出细分
OTHER_PAY_DD_FUND_VALUE: param.detail.find((t) => t.payEnum === 300001)?.amount ?? 0, // 兜底基金支出
OTHER_PAY_YW_SH_FUND_VALUE: param.detail.find((t) => t.payEnum === 300002)?.amount ?? 0, // 意外伤害基金支出
OTHER_PAY_LX_YL_FUND_VALUE: param.detail.find((t) => t.payEnum === 300003)?.amount ?? 0, // 离休人员医疗保障金支出
OTHER_PAY_LX_YH_FUND_VALUE: param.detail.find((t) => t.payEnum === 300004)?.amount ?? 0, // 离休人员优惠金支出
OTHER_PAY_CZ_FUND_VALUE: param.detail.find((t) => t.payEnum === 300005)?.amount ?? 0, // 财政基金支出
OTHER_PAY_CZ_YZ_FUND_VALUE: param.detail.find((t) => t.payEnum === 300006)?.amount ?? 0, // 财政预支支出
OTHER_PAY_ZG_DB_FUND_VALUE: param.detail.find((t) => t.payEnum === 300007)?.amount ?? 0, // 职工大病基金支出
OTHER_PAY_EY_FUND_VALUE: param.detail.find((t) => t.payEnum === 300008)?.amount ?? 0, // 二乙基金支出
OTHER_PAY_QX_JZ_FUND_VALUE: param.detail.find((t) => t.payEnum === 300009)?.amount ?? 0, // 倾斜救助支出
OTHER_PAY_YL_JZ_FUND_VALUE: param.detail.find((t) => t.payEnum === 300010)?.amount ?? 0, // 医疗救助再救助基金
HOSP_PART_AMT: param.detail.find((t) => t.payEnum === 300011)?.amount ?? 0, // 医院负担金额
// 医保结算返回值
FULAMT_OWNPAY_AMT: param.detail.find((t) => t.payEnum === 1)?.amount ?? 0, // 全自费金额
OVERLMT_SELFPAY: param.detail.find((t) => t.payEnum === 3)?.amount ?? 0, // 超限价自费费用
PRESELFPAY_AMT: param.detail.find((t) => t.payEnum === 4)?.amount ?? 0, // 先行自付金额
INSCP_SCP_AMT: param.detail.find((t) => t.payEnum === 5)?.amount ?? 0, // 符合政策范围金额
ACT_PAY_DEDC: param.detail.find((t) => t.payEnum === 6)?.amount ?? 0, // 实际支付起付线
POOL_PROP_SELFPAY: param.detail.find((t) => t.payEnum === 7)?.amount ?? 0, // 基本医疗保险统筹基金支付比例
BALC: param.detail.find((t) => t.payEnum === 8)?.amount ?? 0, // 余额
// 特殊支付方式
SELF_YB_ZH_PAY: param.detail.find((t) => t.payEnum === 210000)?.amount ?? 0, // 个人医保账户支付
SELF_YB_ZH_GJ_VALUE: param.detail.find((t) => t.payEnum === 210100)?.amount ?? 0, // 账户共济支付金额
SELF_CASH_PAY: param.detail.find((t) => t.payEnum === 220000)?.amount ?? 0, // 个人现金支付金额
SELF_VX_PAY: param.detail.find((t) => t.payEnum === 230000)?.amount ?? 0, // 微信支付金额
SELF_ALI_PAY: param.detail.find((t) => t.payEnum === 240000)?.amount ?? 0, // 阿里支付金额
// 现金支付细分
SELF_CASH_VALUE: param.detail.find((t) => t.payEnum === 220400)?.amount ?? 0, // 个人现金支付金额(现金)
SELF_CASH_VX_VALUE: param.detail.find((t) => t.payEnum === 220100)?.amount ?? 0, // 个人现金支付金额(微信)
SELF_CASH_ALI_VALUE: param.detail.find((t) => t.payEnum === 220200)?.amount ?? 0, // 个人现金支付金额(支付宝)
SELF_CASH_UNION_VALUE: param.detail.find((t) => t.payEnum === 220300)?.amount ?? 0, // 个人现金支付金额(银联)
// 基金类型(扩展)
BIRTH_FUND: param.detail.find((t) => t.payEnum === 510100)?.amount ?? 0, // 生育基金
RETIREE_MEDICAL: param.detail.find((t) => t.payEnum === 340100)?.amount ?? 0, // 离休人员医疗保障基金
URBAN_BASIC_MEDICAL: param.detail.find((t) => t.payEnum === 390100)?.amount ?? 0, // 城乡居民基本医疗保险基金
URBAN_SERIOUS_ILLNESS: param.detail.find((t) => t.payEnum === 390200)?.amount ?? 0, // 城乡居民大病医疗保险基金
MEDICAL_ASSISTANCE: param.detail.find((t) => t.payEnum === 610100)?.amount ?? 0, // 医疗救助基金
GOVERNMENT_SUBSIDY: param.detail.find((t) => t.payEnum === 640100)?.amount ?? 0, // 政府兜底基金
ACCIDENT_INSURANCE: param.detail.find((t) => t.payEnum === 390400)?.amount ?? 0, // 意外伤害基金
CARE_INSURANCE: param.detail.find((t) => t.payEnum === 620100)?.amount ?? 0, // 照护保险基金
FINANCIAL_FUND: param.detail.find((t) => t.payEnum === 360100)?.amount ?? 0, // 财政基金
HOSPITAL_ADVANCE: param.detail.find((t) => t.payEnum === 999900)?.amount ?? 0, // 医院垫付
SUPPLEMENTARY_INSURANCE: param.detail.find((t) => t.payEnum === 390300)?.amount ?? 0, // 城乡居民大病补充保险基金
HEALTHCARE_PREPAYMENT: param.detail.find((t) => t.payEnum === 360300)?.amount ?? 0, // 保健预支基金
Mr_QR_Code: param.regNo,
sex: props.patientInfo.genderEnum_enumText,
age: props.patientInfo.age,
personType: '职工医保',
fixmedinsName: param.fixmedinsName + '门诊收费明细',
},
],
// feeDetial: param.detail, //收费项目,后端还未返回
};
// 将对象转换为 JSON 字符串
let jsonString = JSON.stringify(result, null, 2);
console.log(jsonString, 'jsonString');
await CefSharp.BindObjectAsync('boundAsync');
await boundAsync.printReport(
'门诊收费明细单.grf',
jsonString
)
.then((response) => {
//返回结果是jsonString可判断其调用是否成功
console.log(response, 'response');
var res = JSON.parse(response);
if (!res.IsSuccess) {
proxy.$modal.msgError('调用打印插件失败:' + res.ErrorMessage);
}
})
.catch((error) => {
proxy.$modal.msgError('调用打印插件失败:' + error);
});
}
function submit() {
if (parseFloat(displayAmount.value) < formData.totalAmount) {
proxy.$modal.msgError('请输入正确的结算金额');
return;
}
dialogLoading.value = true;
savePayment({
// paymentEnum: 0,
// kindEnum: 1,
// patientId: props.patientInfo.patientId,
// encounterId: props.patientInfo.encounterId,
// chargeItemIds: props.chargeItemIds,
outpatientRegistrationAddParam: props.transformedData,
chrgBchno: props.chrgBchno,
busNo: props.registerBusNo,
paymentDetails: formData.selfPay,
// ybFlag: '0',
// eleFlag: '0',
// returnedAmount: parseFloat(returnedAmount.value),
})
.then((res) => {
if (res.code == 200) {
printReceipt(res.data);
(formData.selfPay = [{ payEnum: 220100, amount: 0.0, payLevelEnum: 2 }]),
emit('close', 'success');
}
})
.finally(() => {
dialogLoading.value = false;
});
}
const currentDate = ref(new Date().toLocaleString());
const selfPayMethods = [
{ label: '现金', value: 220400 },
{ label: '微信', value: 220100 },
{ label: '支付宝', value: 220200 },
{ label: '银联', value: 220300 },
];
// 计算剩余可输入金额
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;
};
// 检查支付方式是否已使用
const isMethodDisabled = (payEnum) => {
return formData.selfPay.some((item) => item.payEnum === payEnum);
};
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 clearAmount = (index) => {
// formData.selfPay[index].amount = 0;
};
// 计算属性
const displayAmount = computed(() => {
return formData.selfPay.reduce((sum, item) => sum + (Number(item.amount) || 0), 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() {
emit('close', 'cancel');
}
</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; /* 避免点击干扰 */
}
</style>

View File

@@ -0,0 +1,216 @@
import request from '@/utils/request'
import { parseStrEmpty } from "@/utils/openhis";
// 查询初期所需数据
export function getInit() {
return request({
url: '/charge-manage/register/init',
method: 'get'
})
}
// 查询患者信息
export function getOutpatientRegistrationList(query) {
return request({
url: '/charge-manage/register/patient-metadata',
method: 'get',
params: query
})
}
// 查询费用性质
export function getContractList() {
return request({
url: '/app-common/contract-list',
method: 'get'
})
}
// 查询诊断信息
export function getConditionDefinitionMetadata(query) {
return request({
url: '/charge-manage/register/condition-definition-metadata',
method: 'get',
params: query
})
}
// // 查询就诊位置
// export function getLocationTree(query) {
// return request({
// url: '/charge-manage/register/location-tree',
// method: 'get',
// params: query
// })
// }
// 查询就诊科室
export function getLocationTree(query) {
return request({
url: '/charge-manage/register/org-list',
method: 'get',
params: query
})
}
// 根据位置id筛选医生
export function getPractitionerMetadata(query) {
return request({
url: '/charge-manage/register/practitioner-metadata',
method: 'get',
params: query
})
}
// 根据机构id筛选服务项目
export function getHealthcareMetadata(query) {
return request({
url: '/charge-manage/register/healthcare-metadata',
method: 'get',
params: query
})
}
// 门诊挂号查询
export function getOutpatientRegistrationCurrent(query) {
return request({
url: '/charge-manage/register/current-day-encounter',
method: 'get',
params: query
})
}
// 新增门诊挂号信息
export function addOutpatientRegistration(data) {
return request({
url: '/payment/payment/reg-pre-pay',
method: 'post',
data: data
})
}
// 新增病人信息
export function addPatient(data) {
return request({
url: '/patient-manage/information/patient-information',
method: 'post',
data: data
})
}
export function listmaritalstatus() {
return request({
url: '/patientmanage/information/list-maritalstatus',
method: 'get',
})
}
export function listoccupationtype() {
return request({
url: '/patientmanage/information/list-occupationtype',
method: 'get',
})
}
export function lisadministrativegender() {
return request({
url: '/patientmanage/information/list-administrativegender',
method: 'get',
})
}
export function listbloodtypeabo() {
return request({
url: '/patientmanage/information/list-bloodtypeabo',
method: 'get',
})
}
export function listbloodtypearh() {
return request({
url: '/patientmanage/information/list-bloodtypearh',
method: 'get',
})
}
export function listfamilyrelationshiptype() {
return request({
url: '/patientmanage/information/list-familyrelationshiptype',
method: 'get',
})
}
// 查询患者相关
export function patientlLists() {
return request({
url: '/patient-manage/information/init',
method: 'get'
})
}
// 患者退号
export function returnRegister(encounterId) {
return request({
url: '/charge-manage/register/return?encounterId=' + encounterId,
method: 'put'
})
}
/**
* 收费
*/
export function savePayment(data) {
return request({
url: '/payment/payment/reg-pay',
method: 'post',
data: data
})
}
/**
* 收费预结算
*/
export function precharge(data) {
return request({
url: '/payment/payment/precharge',
method: 'post',
data: data
})
}
/**
* 退费
*/
export function refund(data) {
return request({
url: '/payment/payment/uncharge',
method: 'post',
data: data
})
}
/**
* 取消挂号
*/
export function cancelRegister(data) {
return request({
url: '/charge-manage/register/return',
method: 'put',
data: data
})
}
/**
* 获取用户信息
*/
export function gerPreInfo(userMaessage) {
return request({
url: '/yb-request/per-info',
method: 'post',
params: userMaessage
})
}

View File

@@ -0,0 +1,493 @@
<template>
<!-- <div class="app-container"> -->
<!-- 添加或修改对话框 -->
<el-dialog :title="title" v-model="visible" width="980px" append-to-body>
<el-form ref="patientRef" :model="form" :rules="rules" label-width="100px">
<el-row>
<el-col :span="8">
<el-form-item label="姓名" prop="name">
<el-input v-model="form.name" clearable :disabled="isViewMode" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="性别" prop="genderEnum">
<el-radio-group v-model="form.genderEnum" :disabled="isViewMode">
<el-radio
v-for="item in administrativegenderList"
:key="item.value"
:label="item.value"
>
{{ item.info }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<!-- <el-col :span="8">
<el-form-item label="活动标识" prop="tempFlag">
<el-radio-group v-model="form.tempFlag" :disabled="isViewMode">
<el-radio v-for="dict in patient_temp_flag" :key="dict.value" :label="dict.value">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col> -->
<el-col :span="8">
<el-form-item label="联系方式" prop="phone">
<el-input v-model="form.phone" clearable :disabled="isViewMode" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="证件号码" prop="idCard">
<el-input v-model="form.idCard" clearable :disabled="isViewMode" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="民族" prop="nationalityCode">
<el-select v-model="form.nationalityCode" clearable filterable :disabled="isViewMode">
<el-option
v-for="item in nationality_code"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="卡类别" prop="typeCode">
<el-select
v-model="form.typeCode"
placeholder="卡类别"
clearable
:disabled="isViewMode"
>
<el-option
v-for="dict in sys_idtype"
:key="dict.value"
:label="dict.label"
:value="dict.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="就诊卡号" prop="identifierNo">
<el-input v-model="form.identifierNo" clearable :disabled="isViewMode" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="国家编码" prop="countryCode">
<el-input v-model="form.countryCode" clearable :disabled="isViewMode" />
</el-form-item>
</el-col>
</el-row>
<!-- <el-col :span="6">
<el-form-item label="年龄" prop="age">
<el-input v-model="form.age" clearable :disabled="isViewMode"/>
</el-form-item>
</el-col> -->
<el-row>
<el-col :span="8">
<el-form-item label="职业" prop="prfsEnum">
<el-select v-model="form.prfsEnum" placeholder="职业" clearable :disabled="isViewMode">
<el-option
v-for="item in occupationtypeList"
:key="item.value"
:label="item.info"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="工作单位" prop="workCompany">
<el-input v-model="form.workCompany" clearable :disabled="isViewMode" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="年龄" prop="age">
<el-input
v-model="form.age"
:disabled="isViewMode"
@input="(value) => (form.age = value.replace(/[^0-9]/g, ''))"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="联系人" prop="linkName">
<el-input v-model="form.linkName" clearable :disabled="isViewMode" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系人关系" prop="linkRelationCode">
<el-select
v-model="form.linkRelationCode"
placeholder="联系人关系"
clearable
:disabled="isViewMode"
>
<el-option
v-for="item in familyrelationshiptypeList"
:key="item.value"
:label="item.info"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="联系人电话" prop="linkRelationCode">
<el-input v-model="form.linkTelcom" clearable :disabled="isViewMode" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="地址选择" prop="addressSelect">
<el-cascader
:options="options"
:props="{ checkStrictly: true, value: 'code', label: 'name' }"
v-model="selectedOptions"
@change="handleChange"
:disabled="isViewMode"
>
<template #default="{ node, data }">
<span>{{ data.name }}</span>
<span v-if="!node.isLeaf"> ({{ data.children.length }}) </span>
</template>
</el-cascader>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="详细地址" prop="address">
<el-input v-model="form.address" clearable :disabled="isViewMode" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="血型ABO" prop="bloodAbo">
<el-select
v-model="form.bloodAbo"
placeholder="血型ABO"
clearable
:disabled="isViewMode"
>
<el-option
v-for="item in bloodtypeaboList"
:key="item.value"
:label="item.info"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="血型RH" prop="bloodRh">
<el-select v-model="form.bloodRh" placeholder="血型RH" clearable :disabled="isViewMode">
<el-option
v-for="item in bloodtypearhList"
:key="item.value"
:label="item.info"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<el-form-item label="婚姻状态" prop="maritalStatusEnum">
<el-select
v-model="form.maritalStatusEnum"
placeholder="婚姻状态"
clearable
:disabled="isViewMode"
>
<el-option
v-for="item in maritalstatusList"
:key="item.value"
:label="item.info"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="死亡时间" prop="deceasedDate">
<el-date-picker
v-model="form.deceasedDate"
type="datetime"
placeholder="请选择时间"
format="YYYY/MM/DD HH:mm:ss"
:disabled="isViewMode"
value-format="YYYY/MM/DD HH:mm:ss"
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- </div> -->
</template>
<script setup name="PatientAddDialog">
import { watch } from "vue";
import pcas from 'china-division/dist/pcas-code.json';
import { addPatient, patientlLists, getOutpatientRegistrationList } from './outpatientregistration';
import { fromPairs } from 'lodash';
const router = useRouter();
const { proxy } = getCurrentInstance();
const {
patient_gender_enum,
sys_idtype,
prfs_enum,
blood_rh,
blood_abo,
marital_status_enum,
patient_temp_flag,
link_relation_code,
nationality_code,
} = proxy.useDict(
'patient_gender_enum',
'sys_idtype',
'prfs_enum',
'blood_rh',
'blood_abo',
'marital_status_enum',
'patient_temp_flag',
'link_relation_code',
'nationality_code'
);
const selectedOptions = ref([]); // v-model 绑定的选中值
const maritalstatusList = ref([]); //婚姻
const occupationtypeList = ref([]); //职业
const administrativegenderList = ref([]); //性别
const bloodtypeaboList = ref([]); //血型abo
const bloodtypearhList = ref([]); //血型RH
const familyrelationshiptypeList = ref([]); //家庭关系
// 使用 ref 定义查询所得用户信息数据
const patientInfo = ref(undefined);
const addressCom = ref(''); //地址
const options = ref(pcas); // 地区数据
const title = ref('新增患者');
const visible = ref(false);
const emits = defineEmits(['submit']); // 声明自定义事件
const data = reactive({
isViewMode: false,
form: {
typeCode: '08',
},
rules: {
name: [{ required: true, message: '姓名不能为空', trigger: 'change' }],
genderEnum: [{ required: true, message: '请选择性别', trigger: 'change' }],
age: [{ required: true, message: '年龄不能为空', trigger: 'change' }],
phone: [{ required: true, message: '联系方式不能为空', trigger: 'change' }],
},
});
const { queryParams, form, rules, isViewMode } = toRefs(data);
const props = defineProps({
item: {
type: Object,
required: false,
},
});
watch(
() => form.value.idCard,
(newIdCard) => {
if (newIdCard && newIdCard.length === 18) {
const birthYear = parseInt(newIdCard.substring(6, 10));
const birthMonth = parseInt(newIdCard.substring(10, 12));
const birthDay = parseInt(newIdCard.substring(12, 14));
const today = new Date();
const currentYear = today.getFullYear();
const currentMonth = today.getMonth() + 1;
const currentDay = today.getDate();
let age = currentYear - birthYear;
// 如果当前月份小于出生月份或者月份相同但当前日期小于出生日期则年龄减1
if (
currentMonth < birthMonth ||
(currentMonth === birthMonth && currentDay < birthDay)
) {
age--;
}
form.value.age = age;
}
}
);
/** 查询菜单列表 */
function getList() {
patientlLists().then((response) => {
console.log(response);
occupationtypeList.value = response.data.occupationType;
administrativegenderList.value = response.data.sex;
bloodtypeaboList.value = response.data.bloodTypeABO;
bloodtypearhList.value = response.data.bloodTypeRH;
familyrelationshiptypeList.value = response.data.familyRelationshipType;
maritalstatusList.value = response.data.maritalStatus;
});
}
/** 打开用户信息弹窗 */
function getPatientInfo(idCard) {
const param = {
searchKey: idCard,
};
getOutpatientRegistrationList(param).then((res) => {
console.log(param, 'param');
if (res.data.records.length > 0) {
patientInfo.value = res.data.records[0];
console.log(patientInfo.value, 'patientInfo.value');
// 将表单数据发送给父组件
emits('submit', patientInfo.value);
}
});
}
//地址选择
const handleChange = () => {
const checkedNodes = selectedOptions.value.map((code) => {
const node = findNodeByCode(options.value, code);
return node ? node.name : null;
});
form.value.addressProvince = checkedNodes[0] || '';
form.value.addressCity = checkedNodes[1] || '';
form.value.addressDistrict = checkedNodes[2] || '';
form.value.addressStreet = checkedNodes[3] || '';
form.value.address = '';
};
// 递归查找节点
const findNodeByCode = (data, code) => {
for (const item of data) {
if (item.code === code) return item;
if (item.children) {
const result = findNodeByCode(item.children, code);
if (result) return result;
}
}
return null;
};
// 显示弹框
function show() {
// queryParams.roleId = props.roleId;
getList();
visible.value = true;
}
/** 表单重置 */
function reset() {
form.value = {
name: undefined,
nameJson: undefined,
menuName: undefined,
age: undefined,
genderEnum: undefined,
typeCode: '08',
idCard: undefined,
phone: undefined,
prfsEnum: undefined,
address: undefined,
tempFlag: undefined,
countryCode: undefined,
bloodRh: undefined,
bloodAbo: undefined,
nationalityCode: undefined,
deceasedDate: undefined,
linkName: undefined,
linkRelationCode: undefined,
linkTelcom: undefined,
workCompany: undefined,
addressCity: undefined,
addressDistrict: undefined,
addressStreet: undefined,
addressProvince: undefined,
maritalStatusEnum: undefined,
busNo: undefined,
organizationId: undefined,
};
proxy.resetForm('patientRef');
}
/** 提交按钮 */
function submitForm() {
if (form.value.idCard) {
form.value.birthDate =
form.value.idCard.toString().substring(6, 10) +
'-' +
form.value.idCard.toString().substring(10, 12) +
'-' +
form.value.idCard.toString().substring(12, 14);
console.log(form.value.birthDate, 123);
}
proxy.$refs['patientRef'].validate((valid) => {
if (valid) {
// 使用
if (!form.value.identifierNo) {
form.value.typeCode = undefined;
}
form.value.address = getAddress(form);
addPatient(form.value).then((response) => {
proxy.$modal.msgSuccess('新增成功');
getPatientInfo(response.data.idCard);
visible.value = false;
reset();
});
}
});
}
// 获取完整地址字符串
function getAddress(form) {
const addressParts = [
form.value.addressProvince,
form.value.addressCity,
form.value.addressDistrict,
form.value.addressStreet,
form.value.address,
];
// 使用 reduce 方法拼接地址
return addressParts.reduce((acc, part) => {
return part ? acc + part : acc;
}, '');
}
/** 取消按钮 */
function cancel() {
visible.value = false;
reset();
}
defineExpose({
show,
});
</script>
<style scoped>
.el-form--inline .el-form-item {
display: inline-flex;
vertical-align: middle;
margin-right: 10px !important;
}
/* 使用深度选择器 */
.custom-label-spacing :deep(.el-form-item__label) {
line-height: 1.2; /* 调整行间距 */
margin-bottom: 4px; /* 调整 label 和输入框之间的间距 */
}
</style>

View File

@@ -0,0 +1,182 @@
<template>
<!-- <div class="app-container"> -->
<el-dialog :title="title" v-model="visible" width="800px" append-to-body>
<el-table
:data="patientInfoList"
@selection-change="handleSelectionChange"
width="90%"
@cell-dblclick="handleCellDblClick"
>
<el-table-column type="selection" width="50" align="center" />
<el-table-column
label="患者姓名"
align="center"
key="name"
prop="name"
:show-overflow-tooltip="true"
/>
<el-table-column
label="性别"
align="center"
key="genderEnum_enumText"
prop="genderEnum_enumText"
:show-overflow-tooltip="true"
/>
<el-table-column
label="身份证号"
align="center"
key="idCard"
prop="idCard"
:show-overflow-tooltip="true"
/>
<el-table-column
label="电话"
align="center"
key="phone"
prop="phone"
:show-overflow-tooltip="true"
width="100"
/>
<el-table-column
label="生日"
align="center"
key="birthDate"
prop="birthDate"
:show-overflow-tooltip="true"
width="50"
/>
<el-table-column
label="年龄"
align="center"
key="age"
prop="age"
:show-overflow-tooltip="true"
/>
</el-table>
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
<template #footer>
<div class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button>
<el-button @click="cancel"> </el-button>
</div>
</template>
</el-dialog>
<!-- </div> -->
</template>
<script setup name="PatientInfoDialog">
import {
getOutpatientRegistrationList,
} from "./outpatientregistration";
const { proxy } = getCurrentInstance();
const patientInfoList = ref([]);
const selectedData = ref([]); // 存储选择的行数据
const single = ref(true);
const multiple = ref(true);
const total = ref(0);
const title = ref("病人信息");
const visible = ref(false);
const emits = defineEmits(['submit']); // 声明自定义事件
const data = reactive({
form: {},
queryParams: {
pageNo: 1,
pageSize: 10,
searchKey: undefined, // 品名/商品名/英文品名/编码/拼音
},
rules: {},
});
const { queryParams, form, rules } = toRefs(data);
const props = defineProps({
patientInfoData: {
type: Object,
required: false,
default: () => ({}), // 提供默认值
},
searchInfo: {
type: String,
required: true,
default: "",
},
});
// 显示弹框
function show() {
patientInfoList.value = props.patientInfoData.records;
total.value = props.patientInfoData.total;
console.log(props.patientInfoData, "props.patientInfoData");
visible.value = true;
}
/** 查询病种目录列表 */
function getList() {
const query = {
searchKey: props.searchInfo,
pageNo: queryParams.value.pageNo,
pageSize: queryParams.value.pageSize,
};
getOutpatientRegistrationList(query).then((res) => {
if (res.data.records.length > 0) {
patientInfoList.value = res.data.records;
total.value = res.data.total;
console.log(patientInfoList.value, "patientInfoList.value");
}
});
}
/** 选择条数 */
function handleSelectionChange(selection) {
console.log(selection, "selection");
selectedData.value = selection.map((item) => ({ ...item })); // 存储选择的行数据
single.value = selection.length != 1;
multiple.value = !selection.length;
}
/** 取消按钮 */
function cancel() {
visible.value = false;
patientInfoList.value = [];
}
/** 提交按钮 */
function submitForm() {
if (selectedData.value.length > 1) {
proxy.$modal.msgSuccess("只能选中一条数据操作!");
} else if (selectedData.value.length === 1) {
console.log(selectedData.value[0], "selectedData.value");
const data = selectedData.value[0];
// 将表单数据发送给父组件
emits("submit", data);
}
visible.value = false;
}
// 双击数据时触发的方法
function handleCellDblClick(row, column, cell, event) {
emits("submit", row);
visible.value = false;
// 获取整条数据
console.log('双击的行数据:', row);
// 根据需求进行进一步操作
}
defineExpose({
show,
});
</script>
<style scoped>
.el-form--inline .el-form-item {
display: inline-flex;
vertical-align: middle;
margin-right: 10px !important;
}
</style>

View File

@@ -0,0 +1,58 @@
<template>
<div>
<el-table
height="400"
:data="patientList"
row-key="id"
@cell-click="clickRow"
>
<el-table-column label="姓名" align="center" prop="name" />
<el-table-column label="性别" align="center" prop="genderEnum_enumText" />
<el-table-column label="证件号" align="center" prop="idCard" />
<el-table-column label="联系电话" align="center" prop="phone" />
<el-table-column label="年龄" align="center" prop="age" />
</el-table>
</div>
</template>
<script setup>
import { getOutpatientRegistrationList } from "./outpatientregistration";
const props = defineProps({
searchkey: {
type: String,
default: "",
},
});
const emit = defineEmits(["selsectPatient"]);
const total = ref(0);
const queryParams = ref({
pageNum: 1,
pageSize: 50,
});
const patientList = ref([]);
watch(
() => props.searchkey,
(newValue) => {
queryParams.value.searchKey = newValue;
getList();
},
{ immdiate: true }
);
getList();
function getList() {
getOutpatientRegistrationList(queryParams.value).then((res) => {
patientList.value = res.data.records;
total.value = res.data.total;
});
}
function clickRow(row) {
emit("selsectPatient", row);
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,364 @@
<template>
<el-dialog
title="确认退费"
v-model="props.open"
width="700px"
append-to-body
destroy-on-close
@close="close"
>
<div>
<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="payment-container">
<div v-for="(item, index) in formData.selfPay" :key="index" class="payment-item">
<span>退费方式</span>
<el-select
v-model="item.payEnum"
placeholder="选择退费方式"
style="width: 160px"
@change="clearAmount(index)"
>
<el-option
v-for="payEnum in selfPayMethods"
:key="payEnum.value"
:label="payEnum.label"
:value="payEnum.value"
:disabled="isMethodDisabled(payEnum.value)"
/>
</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>
<div class="payment-container" style="position: relative">
<span style="position: absolute; top: 5px">退费原因</span>
<el-input
type="textarea"
:rows="2"
v-model="reason"
placeholder="退费原因"
class="reason-textarea"
@change="handleAmountChange"
/>
</div>
<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>
<!-- 金额汇总 -->
<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="submit"> </el-button>
<el-button @click="close"> </el-button>
</div>
</template>
</el-dialog>
</template>
<script setup>
import { cancelRegister } from './outpatientregistration';
import { computed, watch, reactive, ref, getCurrentInstance } from 'vue';
import { Delete } from '@element-plus/icons-vue';
const props = defineProps({
open: {
type: Boolean,
default: false,
},
totalAmount: {
type: Number,
default: 0.0,
},
category: {
type: String,
},
paymentId: {
type: String,
},
patientInfo: {
type: Object,
default: undefined,
},
chargeItemIds: {
type: [],
default: [],
},
});
const { proxy } = getCurrentInstance();
const reason = ref('');
const formData = reactive({
totalAmount: 0,
selfPay: [{ payEnum: 220100, amount: 0.0, payLevelEnum: 2 }],
medicalInsurance: {
account: '',
poolPay: 0,
personalPay: 0,
},
});
watch(
() => props.totalAmount,
(newValue) => {
formData.totalAmount = newValue;
formData.selfPay[0].amount = newValue;
}
);
const emit = defineEmits(['close']);
function submit() {
console.log(props.chargeItemIds);
if (parseFloat(displayAmount.value) < formData.totalAmount) {
proxy.$modal.msgError('请输入正确的金额');
return;
}
cancelRegister({
paymentEnum: 0,
kindEnum: 1,
patientId: props.patientInfo.patientId,
id: props.paymentId,
encounterId: props.patientInfo.encounterId,
chargeItemIds: [],
paymentDetails: formData.selfPay,
reason: reason.value,
ybFlag: '1',
eleFlag: '0',
// returnedAmount: parseFloat(returnedAmount.value),
}).then((res) => {
if (res.code == 200) {
emit('close', 'success');
}
});
}
const currentDate = ref(new Date().toLocaleString());
const selfPayMethods = [
{ label: '现金', value: 220400 },
{ label: '微信', value: 220100 },
{ label: '支付宝', value: 220200 },
{ label: '银联', value: 220300 },
];
// 计算剩余可输入金额
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;
};
// 检查支付方式是否已使用
const isMethodDisabled = (payEnum) => {
return formData.selfPay.some((item) => item.payEnum === payEnum);
};
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 clearAmount = (index) => {
// formData.selfPay[index].amount = 0;
};
// 计算属性
const displayAmount = computed(() => {
return formData.selfPay.reduce((sum, item) => sum + (Number(item.amount) || 0), 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() {
emit('close');
}
</script>
<style lang="scss" 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;
}
.reason-textarea {
margin-left: 80px;
width: 59%;
}
.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>