490 lines
15 KiB
Vue
490 lines
15 KiB
Vue
<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="paymentMethod"
|
||
placeholder="请选择缴费方式"
|
||
clearable
|
||
style="width: 150px; margin-right: 20px"
|
||
>
|
||
<el-option
|
||
v-for="method in paymentMethodOptions"
|
||
:key="method.value"
|
||
:label="method.label"
|
||
:value="method.value"
|
||
/>
|
||
</el-select>
|
||
|
||
<!-- 查询按钮 -->
|
||
<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: flex-end; align-items: center">
|
||
<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;">缴费次数:{{ depositList.length }}次</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<el-table
|
||
ref="tableRef"
|
||
:data="depositList"
|
||
border
|
||
style="width: 100%"
|
||
:header-cell-style="{ background: '#eef9fd !important' }"
|
||
@sort-change="handleSortChange"
|
||
>
|
||
<el-table-column label="序号" type="index" width="60" align="center" />
|
||
<el-table-column label="预交金编号" prop="depositNo" min-width="180" />
|
||
<el-table-column label="金额" prop="amount" width="120" align="center" sortable>
|
||
<template #default="scope">
|
||
<span style="color: #ff4d4f">{{ scope.row.amount.toFixed(2) }}</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="缴费方式" prop="paymentMethodName" width="120" align="center" />
|
||
<el-table-column label="缴费时间" prop="paymentTime" width="150" align="center" sortable />
|
||
<el-table-column label="收费员" prop="cashier" width="100" align="center" />
|
||
</el-table>
|
||
|
||
<!-- 分页 -->
|
||
<div style="margin-top: 15px; display: flex; justify-content: flex-end;">
|
||
<el-pagination
|
||
v-model:current-page="currentPage"
|
||
v-model:page-size="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 && depositList.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>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr v-for="(item, index) in depositList" :key="item.id">
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px;">{{ index + 1 }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px;">{{ item.depositNo }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px;">{{ item.amount.toFixed(2) }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px;">{{ item.paymentMethodName }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px;">{{ item.paymentTime }}</td>
|
||
<td style="border: 1px solid #e4e7ed; padding: 8px;">{{ item.cashier }}</td>
|
||
</tr>
|
||
</tbody>
|
||
<tfoot>
|
||
<tr style="background-color: #f5f7fa;">
|
||
<td colspan="2" style="border: 1px solid #e4e7ed; padding: 8px; text-align: right; font-weight: bold;">合计:</td>
|
||
<td colspan="4" 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 } from 'vue';
|
||
import { ElMessage } from 'element-plus';
|
||
import { patientInfoList } from '../../medicalOrderExecution/store/patient.js';
|
||
import { getSinglePatient } from '../store/patient.js'; // 导入获取单选患者信息的方法
|
||
import { formatDateStr } from '@/utils/index';
|
||
|
||
// 响应式数据
|
||
const loading = ref(false);
|
||
const depositList = ref([]);
|
||
const dateRange = ref('today'); // today, yesterday, other
|
||
const dateRangeValue = ref([]);
|
||
const paymentMethod = ref('');
|
||
const paymentMethodOptions = ref([]);
|
||
const tableRef = ref(null);
|
||
const patientInfo = ref('');
|
||
|
||
// 分页相关
|
||
const currentPage = ref(1);
|
||
const pageSize = ref(20);
|
||
const total = ref(0);
|
||
|
||
// 打印相关
|
||
const printDialogVisible = ref(false);
|
||
|
||
// 计算总金额
|
||
const totalAmount = computed(() => {
|
||
return depositList.value.reduce((sum, item) => {
|
||
return sum + (item.amount || 0);
|
||
}, 0);
|
||
});
|
||
|
||
// 初始化
|
||
onMounted(() => {
|
||
// 设置默认日期
|
||
const today = new Date();
|
||
dateRangeValue.value = [formatDateStr(today, 'YYYY-MM-DD'), formatDateStr(today, 'YYYY-MM-DD')];
|
||
|
||
// 加载缴费方式选项
|
||
loadPaymentMethodOptions();
|
||
|
||
// 监听患者选择变化
|
||
watchPatientSelection();
|
||
});
|
||
|
||
// 监听患者选择变化
|
||
function watchPatientSelection() {
|
||
// 定期检查患者选择状态变化
|
||
setInterval(() => {
|
||
// 使用getSinglePatient方法获取单选患者信息
|
||
const selectedPatient = getSinglePatient();
|
||
if (selectedPatient) {
|
||
patientInfo.value = selectedPatient.patientName || '';
|
||
} else {
|
||
patientInfo.value = '未选择患者';
|
||
}
|
||
}, 300);
|
||
}
|
||
|
||
// 加载缴费方式选项
|
||
function loadPaymentMethodOptions() {
|
||
// 模拟缴费方式数据
|
||
paymentMethodOptions.value = [
|
||
{ label: '现金', value: 'cash' },
|
||
{ label: '银行卡', value: 'bankcard' },
|
||
{ label: '微信支付', value: 'wechat' },
|
||
{ label: '支付宝', value: 'alipay' },
|
||
{ 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 情况保持用户选择的值
|
||
}
|
||
}
|
||
|
||
// 处理日期选择器变化
|
||
function handleDatePickerChange() {
|
||
if (dateRangeValue.value.length > 0) {
|
||
dateRange.value = 'other';
|
||
}
|
||
}
|
||
|
||
// 格式化日期范围显示
|
||
function formatDateRange() {
|
||
if (dateRangeValue.value && dateRangeValue.value.length === 2) {
|
||
return `${dateRangeValue.value[0]} 至 ${dateRangeValue.value[1]}`;
|
||
}
|
||
return '';
|
||
}
|
||
|
||
// 生成模拟数据
|
||
function generateMockData() {
|
||
// 缴费方式映射
|
||
const paymentMethodMap = {
|
||
'cash': '现金',
|
||
'bankcard': '银行卡',
|
||
'wechat': '微信支付',
|
||
'alipay': '支付宝',
|
||
'others': '其他'
|
||
};
|
||
|
||
// 生成模拟数据
|
||
const mockData = [];
|
||
const baseDate = new Date(dateRangeValue.value[0]);
|
||
const endDate = new Date(dateRangeValue.value[1]);
|
||
const daysDiff = Math.ceil((endDate - baseDate) / (1000 * 60 * 60 * 24)) + 1;
|
||
|
||
// 收费员池
|
||
const cashiers = ['收费员A', '收费员B', '收费员C', '收费员D'];
|
||
|
||
// 生成数据
|
||
let id = 1;
|
||
for (let day = 0; day < daysDiff; day++) {
|
||
const currentDate = new Date(baseDate);
|
||
currentDate.setDate(baseDate.getDate() + day);
|
||
|
||
// 每天生成1-3条记录
|
||
const recordsCount = Math.floor(Math.random() * 3) + 1;
|
||
for (let i = 0; i < recordsCount; i++) {
|
||
// 随机选择一个缴费方式
|
||
const paymentMethods = paymentMethod.value ? [paymentMethod.value] : Object.keys(paymentMethodMap);
|
||
const randomMethod = paymentMethods[Math.floor(Math.random() * paymentMethods.length)];
|
||
|
||
// 生成随机金额 (500-5000元)
|
||
const amount = Math.floor(Math.random() * 4500) + 500;
|
||
|
||
// 生成时间
|
||
const hours = Math.floor(Math.random() * 8) + 8; // 8-16点
|
||
const minutes = Math.floor(Math.random() * 60);
|
||
const seconds = Math.floor(Math.random() * 60);
|
||
currentDate.setHours(hours, minutes, seconds);
|
||
const timeStr = formatDateStr(currentDate, 'YYYY-MM-DD HH:mm:ss');
|
||
|
||
// 生成预交金编号 (示例格式:5000120200001)
|
||
const dateCode = formatDateStr(currentDate, 'YYYYMMDD');
|
||
const serialNum = String(id).padStart(6, '0');
|
||
const depositNo = `500${dateCode.slice(2)}${serialNum}`;
|
||
|
||
mockData.push({
|
||
id: id++,
|
||
depositNo: depositNo,
|
||
amount: amount,
|
||
paymentMethod: randomMethod,
|
||
paymentMethodName: paymentMethodMap[randomMethod],
|
||
paymentTime: timeStr,
|
||
cashier: cashiers[Math.floor(Math.random() * cashiers.length)]
|
||
});
|
||
}
|
||
}
|
||
|
||
return mockData;
|
||
}
|
||
|
||
// 查询按钮点击
|
||
function handleQuery() {
|
||
// 添加调试日志,查看患者列表数据结构
|
||
console.log('患者列表数据:', patientInfoList.value);
|
||
|
||
// 使用getSinglePatient方法获取单选患者信息
|
||
const selectedPatient = getSinglePatient();
|
||
|
||
if (!selectedPatient) {
|
||
ElMessage.warning('请先选择患者');
|
||
return;
|
||
}
|
||
|
||
// 更新患者信息显示
|
||
const patientName = selectedPatient.patientName ||
|
||
selectedPatient.name ||
|
||
selectedPatient.patientInfo ||
|
||
selectedPatient.patient ||
|
||
'未命名患者';
|
||
patientInfo.value = patientName;
|
||
|
||
loading.value = true;
|
||
|
||
// 模拟API调用延迟
|
||
setTimeout(() => {
|
||
try {
|
||
// 使用模拟数据
|
||
const allData = generateMockData();
|
||
total.value = allData.length;
|
||
|
||
// 分页处理
|
||
const start = (currentPage.value - 1) * pageSize.value;
|
||
const end = start + pageSize.value;
|
||
depositList.value = allData.slice(start, end);
|
||
} catch (error) {
|
||
console.error('查询错误:', error);
|
||
ElMessage.error('查询失败,请重试');
|
||
depositList.value = [];
|
||
total.value = 0;
|
||
} finally {
|
||
loading.value = false;
|
||
}
|
||
}, 500);
|
||
}
|
||
|
||
// 处理排序变化
|
||
function handleSortChange({ prop, order }) {
|
||
const sortedData = [...depositList.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);
|
||
}
|
||
|
||
depositList.value = sortedData;
|
||
}
|
||
|
||
// 处理分页大小变化
|
||
function handleSizeChange(newSize) {
|
||
pageSize.value = newSize;
|
||
currentPage.value = 1;
|
||
handleQuery();
|
||
}
|
||
|
||
// 处理当前页变化
|
||
function handleCurrentChange(newCurrent) {
|
||
currentPage.value = newCurrent;
|
||
handleQuery();
|
||
}
|
||
|
||
// 导出
|
||
function handleExport() {
|
||
if (depositList.value.length === 0) {
|
||
ElMessage.warning('暂无数据可导出');
|
||
return;
|
||
}
|
||
|
||
// 模拟导出操作
|
||
ElMessage.success('导出成功');
|
||
// 实际项目中这里应该调用导出API或使用Excel库生成文件
|
||
}
|
||
|
||
// 打印预览
|
||
function handlePrint() {
|
||
if (depositList.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);
|
||
}
|
||
}
|
||
|
||
// 暴露方法供父组件调用
|
||
defineExpose({
|
||
handleQuery,
|
||
});
|
||
</script>
|
||
|
||
<style scoped>
|
||
/* 日期tabs样式 */
|
||
.date-tabs .el-tabs__header {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.date-tabs .el-tabs__content {
|
||
display: none;
|
||
}
|
||
</style> |