当手术计费弹窗中点击"签发"耗材时,因耗材的locationId(发放库房)为空导致后端异常。 在DoctorStationAdviceAppServiceImpl.handDevice方法中,当locationId为null时,使用登录用户的科室ID作为默认值, 与NurseBillingAppService中的处理方式保持一致。
538 lines
16 KiB
Vue
Executable File
538 lines
16 KiB
Vue
Executable File
<template>
|
||
<div style="height: calc(100vh - 126px)">
|
||
<!-- 操作工具栏 -->
|
||
<div
|
||
style="
|
||
height: 51px;
|
||
border-bottom: 2px solid #e4e7ed;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 15px;
|
||
"
|
||
>
|
||
<div style="display: flex; align-items: center">
|
||
<!-- 日期选择tabs -->
|
||
<el-tabs
|
||
v-model="dateRange"
|
||
type="card"
|
||
class="date-tabs"
|
||
@tab-click="handleDateTabClick"
|
||
style="margin-right: 20px"
|
||
>
|
||
<el-tab-pane label="今日" name="today"></el-tab-pane>
|
||
<el-tab-pane label="昨日" name="yesterday"></el-tab-pane>
|
||
<!-- <el-tab-pane label="其他" name="other"></el-tab-pane> -->
|
||
</el-tabs>
|
||
|
||
<!-- 日期选择器 -->
|
||
<el-date-picker
|
||
v-model="dateRangeValue"
|
||
type="daterange"
|
||
format="YYYY-MM-DD"
|
||
value-format="YYYY-MM-DD"
|
||
range-separator="至"
|
||
start-placeholder="开始日期"
|
||
end-placeholder="结束日期"
|
||
@change="handleDatePickerChange"
|
||
style="width: 240px; margin-right: 20px"
|
||
/>
|
||
|
||
<!-- 费用类型选择 -->
|
||
<el-select
|
||
v-model="formParams.chargeItemEnum"
|
||
placeholder="请选择费用类型"
|
||
clearable
|
||
style="width: 150px; margin-right: 20px"
|
||
>
|
||
<el-option
|
||
v-for="type in med_chrgitm_type"
|
||
:key="type.value"
|
||
:label="type.label"
|
||
:value="type.value"
|
||
/>
|
||
</el-select>
|
||
|
||
<!-- 执行科室选择 -->
|
||
<el-select
|
||
v-model="formParams.orgId"
|
||
placeholder="请选择执行科室"
|
||
clearable
|
||
style="width: 150px; margin-right: 20px"
|
||
>
|
||
<el-option
|
||
v-for="dept in orgOptions"
|
||
:key="dept.id"
|
||
:label="dept.name"
|
||
:value="dept.id"
|
||
/>
|
||
</el-select>
|
||
|
||
<!-- 查询按钮 -->
|
||
<el-button type="primary" @click="onReset">重置</el-button>
|
||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||
</div>
|
||
|
||
<div style="display: flex; align-items: center">
|
||
<!-- 导出按钮 -->
|
||
<el-button @click="handleExport">导出</el-button>
|
||
|
||
<!-- 打印按钮 -->
|
||
<!-- <el-button @click="handlePrint" style="margin-left: 15px">打印</el-button> -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 费用明细列表区域 -->
|
||
<div
|
||
style="padding: 10px; background-color: #eef9fd; height: 100%; overflow-y: auto"
|
||
v-loading="loading"
|
||
>
|
||
<!-- 费用汇总信息 -->
|
||
<div style="background-color: white; padding: 15px; margin-bottom: 10px; border-radius: 4px">
|
||
<div style="display: flex; justify-content: space-between; align-items: center">
|
||
<div>
|
||
<h3 style="margin: 0; font-weight: normal; color: #303133">费用汇总</h3>
|
||
<p style="margin: 5px 0; color: #606266; font-size: 14px">
|
||
费用周期:{{ formatDateRange() }}
|
||
</p>
|
||
</div>
|
||
<div style="text-align: right">
|
||
<p style="margin: 0; font-size: 18px; font-weight: bold; color: #ff4d4f">
|
||
合计金额:¥{{ totalAmount.toFixed(2) }}
|
||
</p>
|
||
<p style="margin: 5px 0; color: #606266; font-size: 14px">
|
||
明细项数:{{ feeDetailList.length }}项
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<el-table
|
||
ref="tableRef"
|
||
:data="feeDetailList"
|
||
border
|
||
style="width: 100%"
|
||
max-height="400px"
|
||
:header-cell-style="{ background: '#eef9fd !important' }"
|
||
@sort-change="handleSortChange"
|
||
>
|
||
<el-table-column label="项目名称" prop="chargeName" min-width="200" />
|
||
<el-table-column
|
||
label="费用类型"
|
||
prop="chargeItemEnum_enumText"
|
||
width="120"
|
||
align="center"
|
||
/>
|
||
<el-table-column label="单价" prop="unitPrice" width="100" align="center" sortable />
|
||
<el-table-column label="数量" prop="quantityValue" width="100" align="center" sortable />
|
||
<el-table-column label="金额" prop="totalPrice" width="100" align="center" sortable>
|
||
<template #default="scope">
|
||
<span style="color: #ff4d4f">{{ scope.row.totalPrice.toFixed(2) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column :prop="orgId" label="执行科室" width="120" align="center">
|
||
<template #default="scope">
|
||
{{ selectOrg(scope.row.orgId) }}
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="执行人" prop="practitioner" width="100" align="center" />
|
||
<el-table-column label="执行日期" prop="recordedTime" width="120" align="center">
|
||
<template #default="scope">
|
||
{{ moment(scope.row?.recordedTime).format('YYYY-MM-DD HH:mm:ss') }}
|
||
</template>
|
||
</el-table-column>
|
||
|
||
<el-table-column label="医保类型" prop="chrgitmLv_enumText" width="100" align="center">
|
||
</el-table-column>
|
||
<el-table-column label="备注" prop="remark" min-width="150" />
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<div style="margin-top: 15px; display: flex; justify-content: flex-end">
|
||
<el-pagination
|
||
v-model:current-page="formParams.pageNo"
|
||
v-model:page-size="formParams.pageSize"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
:total="total"
|
||
@size-change="handleSizeChange"
|
||
@current-change="handleCurrentChange"
|
||
/>
|
||
</div>
|
||
|
||
<!-- 无数据提示 -->
|
||
<el-empty v-if="!loading && feeDetailList.length === 0" description="暂无费用明细数据" />
|
||
</div>
|
||
|
||
<!-- 打印预览弹窗 -->
|
||
<el-dialog
|
||
v-model="printDialogVisible"
|
||
title="打印预览"
|
||
width="80%"
|
||
:close-on-click-modal="false"
|
||
>
|
||
<div id="print-content">
|
||
<div style="text-align: center; margin-bottom: 20px">
|
||
<h2 style="margin: 0">费用明细清单</h2>
|
||
<p style="margin: 5px 0">患者姓名:{{ patientInfo || '未选择患者' }}</p>
|
||
<p style="margin: 5px 0">费用周期:{{ formatDateRange() }}</p>
|
||
</div>
|
||
|
||
<table style="width: 100%; border-collapse: collapse">
|
||
<thead>
|
||
<tr style="background-color: #eef9fd">
|
||
<th style="border: 1px solid #e4e7ed; padding: 8px">项目名称</th>
|
||
<th style="border: 1px solid #e4e7ed; padding: 8px">费用类型</th>
|
||
<th style="border: 1px solid #e4e7ed; padding: 8px">单价</th>
|
||
<th style="border: 1px solid #e4e7ed; padding: 8px">数量</th>
|
||
<th style="border: 1px solid #e4e7ed; padding: 8px">金额</th>
|
||
<th style="border: 1px solid #e4e7ed; padding: 8px">执行科室</th>
|
||
<th style="border: 1px solid #e4e7ed; padding: 8px">执行日期</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-for="item in feeDetailList" :key="item.id">
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px">{{ item.itemName }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px">{{ item.feeTypeName }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px">
|
||
{{ item.unitPrice.toFixed(2) }}
|
||
</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px">{{ item.quantity }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px">{{ item.amount.toFixed(2) }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px">{{ item.execDept }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px">{{ item.executeDate }}</td>
|
||
</tr>
|
||
</tbody>
|
||
<tfoot>
|
||
<tr style="background-color: #f5f7fa">
|
||
<td
|
||
colspan="4"
|
||
style="
|
||
border: 1px solid #e4e7ed;
|
||
padding: 8px;
|
||
text-align: right;
|
||
font-weight: bold;
|
||
"
|
||
>
|
||
合计:
|
||
</td>
|
||
<td
|
||
colspan="3"
|
||
style="border: 1px solid #e4e7ed; padding: 8px; color: #ff4d4f; font-weight: bold"
|
||
>
|
||
¥{{ totalAmount.toFixed(2) }}
|
||
</td>
|
||
</tr>
|
||
</tfoot>
|
||
</table>
|
||
</div>
|
||
<template #footer>
|
||
<el-button @click="printDialogVisible = false">关闭</el-button>
|
||
<el-button type="primary" @click="doPrint">打印</el-button>
|
||
</template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {computed, onMounted, reactive, ref, watch} from 'vue';
|
||
import moment from 'moment';
|
||
import {ElMessage} from 'element-plus';
|
||
import {patientInfoList} from '../../components/store/patient.js';
|
||
import {formatDateStr} from '@/utils/index';
|
||
import {getCostDetail} from './api.js';
|
||
import {getOrgList} from '../../../basicmanage/ward/components/api.js';
|
||
|
||
const { proxy } = getCurrentInstance();
|
||
const { med_chrgitm_type } = proxy.useDict('med_chrgitm_type');
|
||
|
||
// 响应式数据
|
||
const loading = ref(false);
|
||
const feeDetailList = ref([]);
|
||
const dateRange = ref('today'); // today, yesterday, other
|
||
const dateRangeValue = ref([]);
|
||
const execDepartment = ref('');
|
||
const departmentOptions = ref([]);
|
||
const feeTypeOptions = ref([]);
|
||
const tableRef = ref(null);
|
||
const patientInfo = ref('');
|
||
const orgOptions = ref([]);
|
||
const formParams = reactive({
|
||
chargeItemEnum: undefined,
|
||
orgId: undefined,
|
||
recordedTimeSTime: undefined,
|
||
recordedTimeETime: undefined,
|
||
pageSize: 10,
|
||
pageNo: 1,
|
||
});
|
||
|
||
const props = defineProps({
|
||
activeTab: {
|
||
type: String,
|
||
},
|
||
});
|
||
|
||
// 分页相关
|
||
const total = ref(0);
|
||
|
||
// 打印相关
|
||
const printDialogVisible = ref(false);
|
||
|
||
// 计算总金额
|
||
const totalAmount = computed(() => {
|
||
return feeDetailList.value.reduce((sum, item) => {
|
||
return sum + (item.totalPrice || 0);
|
||
}, 0);
|
||
});
|
||
|
||
// 初始化
|
||
onMounted(() => {
|
||
// 设置默认日期
|
||
const today = new Date();
|
||
dateRangeValue.value = [formatDateStr(today, 'YYYY-MM-DD'), formatDateStr(today, 'YYYY-MM-DD')];
|
||
});
|
||
|
||
watch(
|
||
() => patientInfoList,
|
||
(newValue) => {
|
||
if (newValue.value.length > 1) {
|
||
if (props.activeTab == 'expenseDetail') {
|
||
ElMessage({
|
||
type: 'error',
|
||
message: '一次只能查询一位患者的费用明细',
|
||
});
|
||
return;
|
||
}
|
||
}
|
||
if (newValue.value.length == 1) {
|
||
if (!(dateRangeValue.value == null || dateRangeValue.value == undefined)) {
|
||
formParams.recordedTimeSTime = dateRangeValue.value[0] + ' ' + '00:00:00';
|
||
formParams.recordedTimeETime = dateRangeValue.value[1] + ' ' + '23:59:59';
|
||
}
|
||
patientInfo.value = newValue.value[0];
|
||
formParams.encounterId = patientInfo.value.encounterId;
|
||
getTableList();
|
||
}
|
||
if (newValue.value.length <= 0) {
|
||
feeDetailList.value = [];
|
||
}
|
||
},
|
||
{ deep: true }
|
||
);
|
||
// 获取列表信息
|
||
const getTableList = async () => {
|
||
const params = formParams;
|
||
try {
|
||
const res = await getCostDetail(params);
|
||
feeDetailList.value = res.data.records;
|
||
total.value = res.data?.total;
|
||
console.log('data======>', JSON.stringify(feeDetailList.value));
|
||
} catch (error) {}
|
||
};
|
||
|
||
// 监听患者选择变化
|
||
function watchPatientSelection() {
|
||
// 定期检查患者选择状态变化
|
||
setInterval(() => {
|
||
if (patientInfoList.value && patientInfoList.value.length > 0) {
|
||
const selectedPatient = patientInfoList.value.find((patient) => patient.selected === true);
|
||
if (selectedPatient) {
|
||
patientInfo.value = selectedPatient.patientName || '';
|
||
} else {
|
||
patientInfo.value = '未选择患者';
|
||
}
|
||
} else {
|
||
patientInfo.value = '未选择患者';
|
||
}
|
||
}, 300);
|
||
}
|
||
|
||
/** 查询科室 */
|
||
const getLocationInfo = () => {
|
||
getOrgList().then((res) => {
|
||
orgOptions.value = res.data?.records[0]?.children;
|
||
console.log('orgOptions======>', JSON.stringify(orgOptions.value));
|
||
});
|
||
};
|
||
getLocationInfo();
|
||
|
||
// 映射
|
||
const selectOrg = (itemid) => {
|
||
if (!itemid) return '';
|
||
const item = orgOptions.value.find((item) => {
|
||
return item.id == itemid;
|
||
});
|
||
return item?.name || '';
|
||
};
|
||
// 重置
|
||
const onReset = () => {
|
||
const today = new Date();
|
||
dateRangeValue.value = [formatDateStr(today, 'YYYY-MM-DD'), formatDateStr(today, 'YYYY-MM-DD')];
|
||
formParams.orgId = undefined;
|
||
formParams.chargeItemEnum = undefined;
|
||
formParams.recordedTimeSTime = dateRangeValue.value[0] + ' ' + '00:00:00';
|
||
formParams.recordedTimeETime = dateRangeValue.value[1] + ' ' + '23:59:59';
|
||
getTableList();
|
||
};
|
||
|
||
// 加载费用类型选项
|
||
function loadFeeTypeOptions() {
|
||
// 模拟费用类型数据
|
||
feeTypeOptions.value = [
|
||
{ label: '检查费', value: 'examine' },
|
||
{ label: '治疗费', value: 'treatment' },
|
||
{ label: '药品费', value: 'medicine' },
|
||
{ label: '材料费', value: 'material' },
|
||
{ label: '床位费', value: 'bed' },
|
||
{ label: '其他费用', value: 'others' },
|
||
];
|
||
}
|
||
|
||
// 处理日期tabs点击
|
||
function handleDateTabClick(tab) {
|
||
const rangeType = tab.paneName;
|
||
const today = new Date();
|
||
const yesterday = new Date();
|
||
yesterday.setDate(today.getDate() - 1);
|
||
|
||
switch (rangeType) {
|
||
case 'today':
|
||
dateRangeValue.value = [
|
||
formatDateStr(today, 'YYYY-MM-DD'),
|
||
formatDateStr(today, 'YYYY-MM-DD'),
|
||
];
|
||
break;
|
||
case 'yesterday':
|
||
dateRangeValue.value = [
|
||
formatDateStr(yesterday, 'YYYY-MM-DD'),
|
||
formatDateStr(yesterday, 'YYYY-MM-DD'),
|
||
];
|
||
break;
|
||
// other 情况保持用户选择的值
|
||
}
|
||
if (!(dateRangeValue.value == null || dateRangeValue.value == undefined)) {
|
||
formParams.recordedTimeSTime = dateRangeValue.value[0] + ' ' + '00:00:00';
|
||
formParams.recordedTimeETime = dateRangeValue.value[1] + ' ' + '23:59:59';
|
||
}
|
||
}
|
||
|
||
// 处理日期选择器变化
|
||
function handleDatePickerChange() {
|
||
if (dateRangeValue.value.length > 0) {
|
||
// dateRange.value = 'other';
|
||
} else {
|
||
formParams.recordedTimeSTime = undefined;
|
||
formParams.recordedTimeETime = undefined;
|
||
}
|
||
}
|
||
|
||
// 格式化日期范围显示
|
||
function formatDateRange() {
|
||
if (dateRangeValue.value && dateRangeValue.value.length === 2) {
|
||
return `${dateRangeValue.value[0]} 至 ${dateRangeValue.value[1]}`;
|
||
}
|
||
return '';
|
||
}
|
||
|
||
// 查询按钮点击
|
||
function handleQuery() {
|
||
console.log('params=======>', formParams);
|
||
getTableList();
|
||
}
|
||
|
||
// 处理排序变化
|
||
function handleSortChange({ prop, order }) {
|
||
const sortedData = [...feeDetailList.value];
|
||
|
||
if (order === 'ascending') {
|
||
sortedData.sort((a, b) => (a[prop] > b[prop] ? 1 : -1));
|
||
} else if (order === 'descending') {
|
||
sortedData.sort((a, b) => (a[prop] < b[prop] ? 1 : -1));
|
||
}
|
||
|
||
feeDetailList.value = sortedData;
|
||
}
|
||
|
||
// 处理分页大小变化
|
||
function handleSizeChange(newSize) {
|
||
formParams.pageSize = newSize;
|
||
formParams.pageNo = 1;
|
||
getTableList();
|
||
}
|
||
|
||
// 处理当前页变化
|
||
function handleCurrentChange(newCurrent) {
|
||
formParams.pageNo = newCurrent;
|
||
getTableList();
|
||
}
|
||
|
||
// 导出
|
||
async function handleExport() {
|
||
if (feeDetailList.value.length === 0) {
|
||
ElMessage.warning('暂无数据可导出');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// 实际项目中这里应该调用导出API或使用Excel库生成文件
|
||
await proxy.$download.downloadGet(
|
||
'/inhospitalnursestation/nursebilling/excel-out',
|
||
{
|
||
...formParams,
|
||
},
|
||
`dict_${new Date().getTime()}.xlsx`
|
||
);
|
||
} catch (error) {}
|
||
}
|
||
|
||
// 打印预览
|
||
function handlePrint() {
|
||
if (feeDetailList.value.length === 0) {
|
||
ElMessage.warning('暂无数据可打印');
|
||
return;
|
||
}
|
||
printDialogVisible.value = true;
|
||
}
|
||
|
||
// 执行打印 - 使用 hiprint
|
||
function doPrint() {
|
||
try {
|
||
// 获取要打印的内容
|
||
const printContent = document.getElementById('print-content');
|
||
if (printContent) {
|
||
previewPrint(printContent);
|
||
} else {
|
||
ElMessage.warning('未找到打印内容');
|
||
}
|
||
} catch (e) {
|
||
ElMessage.error('打印失败');
|
||
console.error('Print error:', e);
|
||
}
|
||
}
|
||
|
||
// 暴露方法供父组件调用
|
||
defineExpose({
|
||
handleQuery,
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 日期tabs样式 */
|
||
.date-tabs .el-tabs__header {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.date-tabs .el-tabs__content {
|
||
display: none;
|
||
}
|
||
|
||
:deep(.el-table__header th) {
|
||
background-color: #eef9fd !important;
|
||
}
|
||
|
||
:deep(.el-table__row:hover > td) {
|
||
background-color: #eef9fd !important;
|
||
}
|
||
</style>
|