```
docs(release-notes): 添加住院护士站划价功能说明和发版记录 - 新增住院护士站划价服务流程说明文档,详细描述了从参数预处理到结果响应的五大阶段流程 - 包含耗材类医嘱和诊疗活动类医嘱的差异化处理逻辑 - 添加完整的发版内容记录,涵盖新增菜单功能和各模块优化点 - 记录了住院相关功能的新增和门诊业务流程的修复 ```
This commit is contained in:
@@ -0,0 +1,874 @@
|
||||
<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"
|
||||
@clear="onClear"
|
||||
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">
|
||||
合计金额:¥{{ formatNumber(totalAmount, 4) }}
|
||||
</p>
|
||||
<p style="margin: 5px 0; color: #606266; font-size: 14px">
|
||||
明细项数:{{ groupedPrescriptionList.length }}项
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 列表内容容器 -->
|
||||
<div
|
||||
v-if="groupedPrescriptionList.length > 0"
|
||||
style="
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
background-color: white;
|
||||
border-radius: 4px;
|
||||
"
|
||||
>
|
||||
<!-- 患者医嘱折叠面板 -->
|
||||
<div class="prescription-collapse-container">
|
||||
<el-collapse
|
||||
v-model="activeCollapseNames"
|
||||
accordion
|
||||
border
|
||||
style="--el-collapse-border-color: #e4e7ed"
|
||||
@change="onCollapasChange"
|
||||
>
|
||||
<!-- 按encounterId分组渲染患者折叠项 -->
|
||||
<el-collapse-item
|
||||
v-for="(patientGroup, index) in groupedPrescriptionList"
|
||||
:key="`patient-${index}-${safeGet(patientGroup[0], 'encounterId', index)}`"
|
||||
:name="`patient-${index}`"
|
||||
class="patient-collapse-item"
|
||||
>
|
||||
<!-- 折叠面板头部 - 患者信息 -->
|
||||
<template #title>
|
||||
<div class="patient-header">
|
||||
<div class="patient-basic-info">
|
||||
<el-avatar :icon="User" size="small" style="margin-right: 10px"></el-avatar>
|
||||
<div>
|
||||
<span class="patient-name">{{
|
||||
safeGet(patientGroup[0], 'patientName', '未知患者')
|
||||
}}</span>
|
||||
<span class="patient-info-tag"
|
||||
>{{ safeGet(patientGroup[0], 'genderEnum_enumText', '未知') }} /
|
||||
{{ safeGet(patientGroup[0], 'age', '未知') }}</span
|
||||
>
|
||||
<span class="patient-info-tag"
|
||||
>{{ safeGet(patientGroup[0], 'bedName', '无床位') }}【{{
|
||||
safeGet(patientGroup[0], 'busNo', '未知编号')
|
||||
}}】</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="patient-ext-info">
|
||||
<div class="ext-item">
|
||||
<span class="label">住院医生:</span>
|
||||
<span class="value">{{
|
||||
safeGet(patientGroup[0], 'admittingDoctorName', '未知')
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="ext-item">
|
||||
<span class="label">预交金余额:</span>
|
||||
<span class="value amount">{{
|
||||
formatNumber(safeGet(patientGroup[0], 'balanceAmount', 0), 4)
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="ext-item">
|
||||
<span class="label">诊断:</span>
|
||||
<span class="value" :title="safeGet(patientGroup[0], 'conditionNames', '无')">
|
||||
{{ truncateText(safeGet(patientGroup[0], 'conditionNames', '无'), 20) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="ext-item">
|
||||
<el-tag size="small">{{
|
||||
safeGet(patientGroup[0], 'contractName', '未知')
|
||||
}}</el-tag>
|
||||
</div>
|
||||
<div class="patient-amount-preview">
|
||||
小计:<span class="amount">{{ calculatePatientTotal(patientGroup) }}</span> 元
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- 折叠面板内容 - 医嘱表格 -->
|
||||
<div class="prescription-table-container">
|
||||
<el-table
|
||||
:data="safeArray(patientGroup)"
|
||||
border
|
||||
size="small"
|
||||
style="width: 100%; margin-top: 10px"
|
||||
@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
|
||||
>
|
||||
<template #default="scope">
|
||||
{{ formatNumber(scope.row.unitPrice, 4) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<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">{{
|
||||
formatNumber(scope.row.totalPrice, 4)
|
||||
}}</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>
|
||||
</el-collapse-item>
|
||||
</el-collapse>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 无数据提示 -->
|
||||
<el-empty
|
||||
v-if="!loading && groupedPrescriptionList.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 { ref, computed, onMounted, watch, reactive } 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';
|
||||
import { User } from '@element-plus/icons-vue';
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { med_chrgitm_type } = proxy.useDict('med_chrgitm_type');
|
||||
|
||||
const groupedPrescriptionList = ref([]); // 按encounterId分组后的数据
|
||||
const activeCollapseNames = ref(['patient-0']); // Collapse激活状态
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false);
|
||||
const feeDetailList = ref([]);
|
||||
const dateRange = ref('today'); // today, yesterday, other
|
||||
const dateRangeValue = ref([]);
|
||||
const execDepartment = ref('');
|
||||
const feeTypeOptions = ref([]);
|
||||
const patientInfo = ref('');
|
||||
const orgOptions = ref([]);
|
||||
const selectIndex = ref(0);
|
||||
const formParams = reactive({
|
||||
chargeItemEnum: undefined,
|
||||
orgId: undefined,
|
||||
recordedTimeSTime: undefined,
|
||||
recordedTimeETime: undefined,
|
||||
pageSize: 10,
|
||||
encounterIds: '',
|
||||
pageNo: 1,
|
||||
});
|
||||
|
||||
const props = defineProps({
|
||||
activeTab: {
|
||||
type: String,
|
||||
},
|
||||
});
|
||||
|
||||
// 分页相关
|
||||
const total = ref(0);
|
||||
|
||||
// 打印相关
|
||||
const printDialogVisible = ref(false);
|
||||
|
||||
// 计算总金额
|
||||
const totalAmount = computed(() => {
|
||||
console.log('feeDetailList========>', feeDetailList.value);
|
||||
|
||||
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 > 0) {
|
||||
if (!(dateRangeValue.value == null || dateRangeValue.value == undefined)) {
|
||||
formParams.recordedTimeSTime = dateRangeValue.value[0] + ' ' + '00:00:00';
|
||||
formParams.recordedTimeETime = dateRangeValue.value[1] + ' ' + '23:59:59';
|
||||
}
|
||||
const encounterIds = newValue.value
|
||||
.map((item) => {
|
||||
return item.encounterId;
|
||||
})
|
||||
.join(',');
|
||||
formParams.encounterIds = encounterIds;
|
||||
if (props.activeTab === 'expenseDetail') {
|
||||
getTableList();
|
||||
}
|
||||
}
|
||||
if (newValue.value.length <= 0) {
|
||||
feeDetailList.value = [];
|
||||
groupedPrescriptionList.value = [];
|
||||
}
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
// 获取列表信息
|
||||
const getTableList = async () => {
|
||||
const params = formParams;
|
||||
try {
|
||||
const res = await getCostDetail(params);
|
||||
feeDetailList.value = res.data;
|
||||
total.value = res.data?.total;
|
||||
// 核心:按encounterId分组数据
|
||||
groupedPrescriptionList.value = groupByEncounterId(res.data);
|
||||
// 默认展开第一个患者面板
|
||||
if (groupedPrescriptionList.value.length > 0 && activeCollapseNames.value.length === 0) {
|
||||
activeCollapseNames.value = ['patient-0'];
|
||||
}
|
||||
} 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;
|
||||
});
|
||||
};
|
||||
getLocationInfo();
|
||||
|
||||
// 映射
|
||||
const selectOrg = (itemid) => {
|
||||
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';
|
||||
dateRange.value = 'today';
|
||||
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';
|
||||
}
|
||||
getTableList();
|
||||
}
|
||||
|
||||
// 处理日期选择器变化
|
||||
function handleDatePickerChange() {
|
||||
if (dateRangeValue?.value?.length > 0) {
|
||||
// dateRange.value = 'other';
|
||||
formParams.recordedTimeSTime = dateRangeValue.value[0] + ' ' + '00:00:00';
|
||||
formParams.recordedTimeETime = dateRangeValue.value[1] + ' ' + '23:59:59';
|
||||
} else {
|
||||
formParams.recordedTimeSTime = undefined;
|
||||
formParams.recordedTimeETime = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// 清空
|
||||
const onClear = () => {
|
||||
console.log('1111111111');
|
||||
|
||||
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';
|
||||
dateRange.value = 'today';
|
||||
getTableList();
|
||||
};
|
||||
|
||||
// 格式化日期范围显示
|
||||
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];
|
||||
const selectData = groupedPrescriptionList.value[selectIndex.value];
|
||||
const sortedData = [...selectData];
|
||||
|
||||
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));
|
||||
}
|
||||
groupedPrescriptionList.value[selectIndex.value] = sortedData;
|
||||
// feeDetailList.value = sortedData;
|
||||
}
|
||||
|
||||
// 处理分页大小变化
|
||||
function handleSizeChange(newSize) {
|
||||
formParams.pageSize = newSize;
|
||||
formParams.pageNo = 1;
|
||||
getTableList();
|
||||
}
|
||||
|
||||
// 处理当前页变化
|
||||
function handleCurrentChange(newCurrent) {
|
||||
formParams.pageNo = newCurrent;
|
||||
getTableList();
|
||||
}
|
||||
|
||||
// 导出
|
||||
async function handleExport() {
|
||||
if (groupedPrescriptionList.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;
|
||||
}
|
||||
|
||||
// 执行打印
|
||||
function doPrint() {
|
||||
try {
|
||||
// 获取要打印的内容
|
||||
const printContent = document.getElementById('print-content').innerHTML;
|
||||
|
||||
// 创建临时窗口
|
||||
const printWindow = window.open('', '_blank');
|
||||
|
||||
// 写入内容
|
||||
printWindow.document.write(`
|
||||
<html>
|
||||
<head>
|
||||
<title>费用明细清单</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
table { width: 100%; border-collapse: collapse; }
|
||||
th, td { border: 1px solid #ccc; padding: 8px; }
|
||||
th { background-color: #f2f2f2; }
|
||||
tfoot { font-weight: bold; }
|
||||
.total-row { background-color: #f5f5f5; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
${printContent}
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
// 打印
|
||||
printWindow.document.close();
|
||||
printWindow.focus();
|
||||
printWindow.print();
|
||||
} catch (e) {
|
||||
ElMessage.error('打印失败');
|
||||
console.error('Print error:', e);
|
||||
}
|
||||
}
|
||||
// 获取当前展开折叠板索引
|
||||
function onCollapasChange(select) {
|
||||
if (select) {
|
||||
const selectArr = select.split('-');
|
||||
if (selectArr && selectArr.length > 1) {
|
||||
const idx = selectArr[1];
|
||||
selectIndex.value = Number(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ========== 核心工具函数 ==========
|
||||
/**
|
||||
* 安全获取对象属性,避免空值报错
|
||||
* @param {Object} obj - 源对象
|
||||
* @param {String} path - 属性路径
|
||||
* @param {Any} defaultValue - 默认值
|
||||
* @returns {Any}
|
||||
*/
|
||||
const safeGet = (obj, path, defaultValue = '') => {
|
||||
// 1. 前置校验:如果源对象不是对象类型,直接返回默认值
|
||||
if (!obj || typeof obj !== 'object') return defaultValue;
|
||||
|
||||
// 2. 拆分路径:把 "info.basic.name" 拆成 ["info", "basic", "name"]
|
||||
const paths = path.split('.');
|
||||
|
||||
// 3. 初始化结果为源对象
|
||||
let result = obj;
|
||||
|
||||
// 4. 循环遍历路径数组,逐层访问属性
|
||||
for (const p of paths) {
|
||||
// 5. 关键:如果当前层属性不存在(undefined/null),直接返回默认值
|
||||
if (result[p] === undefined || result[p] === null) return defaultValue;
|
||||
// 6. 存在则继续访问下一层
|
||||
result = result[p];
|
||||
}
|
||||
|
||||
// 7. 所有层级都存在,返回最终属性值
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 安全转换为数组
|
||||
* @param {Any} data - 待转换数据
|
||||
* @returns {Array}
|
||||
*/
|
||||
const safeArray = (data) => {
|
||||
return Array.isArray(data) ? data : [];
|
||||
};
|
||||
|
||||
/**
|
||||
* 格式化数字(保留4位小数,金额专用)
|
||||
* @param {Number} num - 数字
|
||||
* @param {Number} decimal - 小数位数(默认4位)
|
||||
* @returns {String}
|
||||
*/
|
||||
const formatNumber = (num, decimal = 4) => {
|
||||
if (isNaN(Number(num))) return '0.0000';
|
||||
// 保留指定小数位,不足补0
|
||||
return Number(num).toFixed(decimal);
|
||||
};
|
||||
|
||||
/**
|
||||
* 文本截断(超出长度显示省略号)
|
||||
* @param {String} text - 待处理文本
|
||||
* @param {Number} length - 最大长度
|
||||
* @returns {String}
|
||||
*/
|
||||
const truncateText = (text, length = 20) => {
|
||||
if (!text || text.length <= length) return text;
|
||||
return `${text.slice(0, length)}...`;
|
||||
};
|
||||
|
||||
/**
|
||||
* 按encounterId分组数据
|
||||
* @param {Array} data - 原始数据
|
||||
* @returns {Array} 分组后的数据(二维数组)
|
||||
*/
|
||||
const groupByEncounterId = (data) => {
|
||||
const grouped = {};
|
||||
safeArray(data).forEach((item) => {
|
||||
const encounterId = safeGet(item, 'encounterId', 'unknown');
|
||||
if (!grouped[encounterId]) {
|
||||
grouped[encounterId] = [];
|
||||
}
|
||||
grouped[encounterId].push({
|
||||
...item,
|
||||
});
|
||||
});
|
||||
// 转换为数组格式
|
||||
return Object.values(grouped);
|
||||
};
|
||||
|
||||
/**
|
||||
* 计算单个患者的总金额(保留4位小数)
|
||||
* @param {Array} patientGroup - 患者医嘱列表
|
||||
* @returns {String} 格式化后的金额字符串
|
||||
*/
|
||||
const calculatePatientTotal = (patientGroup) => {
|
||||
const total = safeArray(patientGroup).reduce((sum, item) => {
|
||||
return Math.round((sum + Number(safeGet(item, 'totalPrice', 0))) * 10000) / 10000;
|
||||
}, 0);
|
||||
return formatNumber(total, 4);
|
||||
};
|
||||
|
||||
// 暴露方法供父组件调用
|
||||
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;
|
||||
}
|
||||
|
||||
/* 折叠面板容器 */
|
||||
.prescription-collapse-container {
|
||||
--el-collapse-item-border-radius: 8px;
|
||||
}
|
||||
/* 患者折叠项 */
|
||||
.patient-collapse-item {
|
||||
margin-bottom: 12px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
/* 患者头部 */
|
||||
.patient-header {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 4px 0;
|
||||
padding-left: 10px;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
.patient-basic-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.patient-name {
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.patient-info-tag {
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.patient-ext-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.ext-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 13px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.ext-item .label {
|
||||
color: #999;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.ext-item .amount {
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.patient-amount-preview {
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.patient-amount-preview .amount {
|
||||
color: #e6a23c;
|
||||
font-weight: 600;
|
||||
}
|
||||
.prescription-table-container {
|
||||
padding: 10px 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user