Files
his/openhis-ui-vue3/src/views/medicationmanagement/priceAdjustmentFormApproval/index.vue
zhangfei 9c3e603b94 Fix Bug #443: 手术计费:点击签发耗材时异常报错
当手术计费弹窗中点击"签发"耗材时,因耗材的locationId(发放库房)为空导致后端异常。
在DoctorStationAdviceAppServiceImpl.handDevice方法中,当locationId为null时,使用登录用户的科室ID作为默认值,
与NurseBillingAppService中的处理方式保持一致。
2026-05-08 09:14:18 +08:00

550 lines
16 KiB
Vue
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="app-container">
<!-- 查询条件区域 -->
<div class="query-form">
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="审批状态">
<el-select
v-model="queryParams.statusEnum"
placeholder="请选择审批状态"
clearable
filterable
@focus="loadExamineStatusOptions"
>
<el-option
v-for="option in examineStatusOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="申请日期">
<el-date-picker
v-model="queryParams.applicantTime"
type="date"
placeholder="请选择日期"
value-format="YYYY-MM-DD"
format="YYYY-MM-DD"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="6">
<div class="query-buttons">
<el-button plain type="primary" @click="handleSearch">查询</el-button>
<el-button plain type="primary" @click="handleReset">重置</el-button>
</div>
</el-col>
</el-row>
</div>
<el-table
v-loading="loading"
:data="adjustmentList"
tooltip-effect="dark"
:show-overflow-tooltip="true"
style="width: 100%"
>
<el-table-column label="单据编号" align="center" prop="busNo" min-width="180" />
<el-table-column label="调价类型" align="center" prop="categoryEnum_enumText" min-width="120" />
<el-table-column label="审核状态" align="center" prop="statusEnum" min-width="100">
<template #default="scope">
<el-tag :type="getStatusTagType(scope.row.statusEnum)">
{{ scope.row.statusEnum_enumText || '-' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="制单人" align="center" prop="applicantId_dictText" min-width="120" />
<el-table-column label="申请日期" align="center" prop="applicantTime" min-width="180">
<template #default="scope">
{{ parseTime(scope.row.applicantTime) }}
</template>
</el-table-column>
<el-table-column label="审核人" align="center" prop="approverId_dictText" min-width="120" />
<el-table-column label="审核日期" align="center" prop="approvalTime" min-width="180">
<template #default="scope">
{{ scope.row.approvalTime ? parseTime(scope.row.approvalTime) : '-' }}
</template>
</el-table-column>
<el-table-column label="操作" align="center" min-width="180">
<template #default="scope">
<el-button size="small" type="primary" plain @click="handleDetail(scope.row)">
{{
['驳回', '同意'].includes(scope.row.statusEnum_enumText) ? '查看详情' : '查看并审核'
}}
</el-button>
</template>
</el-table-column>
</el-table>
<Pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="handlePagination"
/>
<!-- 详情弹窗组件 -->
<DetailDialog
v-model:visible="detailDialogVisible"
:detail-data="selectedRow"
:category-type="categoryType"
@close="handleDetailClose"
@approve="handleApprove"
@reject="handleReject"
/>
</div>
</template>
<script setup>
import {onMounted, reactive, ref} from 'vue';
import {ElMessage} from 'element-plus';
import {parseTime} from '@/utils/openhis';
import Pagination from '@/components/Pagination';
import request from '@/utils/request';
//import { getPriceAdjustmentPage, getPriceAdjustmentDetail, cancelPriceAdjustment } from './components/api';
import {
getExamineStatusOptions,
rejectPriceAdjustment,
searchSupplyRequestByActivity,
searchSupplyRequestByDevice,
searchSupplyRequestByHealth,
searchSupplyRequestByMed,
updateExamineByApproved,
} from './components/api';
import DetailDialog from './components/detailDialog.vue';
// 表格数据
const adjustmentList = ref([]);
const loading = ref(false);
const total = ref(0);
const activeName = ref('1'); // 当前激活的标签页
// 审核状态选项 - 初始为空数组后续会通过API加载
const examineStatusOptions = ref([]);
const optionsLoading = ref(false);
// 查询参数
const queryParams = reactive({
pageNum: 1,
pageSize: 10,
statusEnum: undefined, // 审核状态
applicantTime: undefined, // 申请日期
});
// 详情弹窗相关
const detailDialogVisible = ref(false);
const selectedRow = ref({});
const categoryType = ref('');
// 状态标签类型
const getStatusTagType = (status) => {
const typeMap = {
1: 'warning', // 待审核
2: 'primary', // 审核中
3: 'success', // 同意
4: 'danger', // 驳回
};
return typeMap[status] || 'info';
};
// 处理分页事件
const handlePagination = (params) => {
// 将分页组件的参数映射到查询参数
queryParams.pageNum = params.page;
queryParams.pageSize = params.limit;
getList();
};
// 查询数据
const getList = async () => {
loading.value = true;
try {
// 构造符合后端要求的请求参数
const requestParams = {
statusEnum: queryParams.statusEnum,
pageNo: queryParams.pageNum,
pageSize: queryParams.pageSize,
};
// 根据后端要求的格式处理日期参数
if (queryParams.applicantTime) {
const dateStr = queryParams.applicantTime;
// requestParams.applicantTime = dateStr; // 原始日期值
requestParams.applicantTimeSTime = `${dateStr} 00:00:00`; // 当天开始时间
requestParams.applicantTimeETime = `${dateStr} 23:59:59`; // 当天结束时间
console.log('applicantTime', requestParams.applicantTime);
console.log('applicantTimeSTime', requestParams.applicantTimeSTime);
console.log('applicantTimeETime', requestParams.applicantTimeETime);
}
// 调用新的后端API接口
const response = await request({
url: '/inventory-examine-page/getPageByExamine',
method: 'get',
params: requestParams,
});
// 处理返回的数据
if (response && response.code === 200) {
// 直接从records字段获取数据
adjustmentList.value = response.data?.records || [];
// 检查total字段是否正确获取增加更多调试日志
total.value = response.data?.total || response.data?.totalCount || 0;
} else {
ElMessage.error(response?.msg || '获取调价审核列表失败');
adjustmentList.value = [];
total.value = 0;
}
} catch (error) {
ElMessage.error('获取数据异常,请稍后重试');
adjustmentList.value = [];
total.value = 0;
} finally {
loading.value = false;
}
};
// 操作按钮处理函数
const handleDetail = async (row) => {
// 保存当前行的调价类型
categoryType.value = row.categoryEnum_enumText || '';
// 调用详情API获取数据
try {
// 显示加载状态
loading.value = true;
// 准备API参数
const params = {
busNo: row.busNo,
};
// 根据itemCategoryEnum选择不同的API接口
let response;
if (row.itemCategoryEnum === 49) {
// 挂号
response = await searchSupplyRequestByHealth(params);
} else if (row.itemCategoryEnum === 48) {
// 诊疗
response = await searchSupplyRequestByActivity(params);
} else if (row.itemCategoryEnum === 47) {
// 耗材
response = await searchSupplyRequestByDevice(params);
} else if (row.itemCategoryEnum === 46) {
// 药品
response = await searchSupplyRequestByMed(params);
}
if (response && response.code === 200) {
// 日志记录原始返回数据
// 准备显示数据
let items = [];
// 根据API实际返回格式处理数据
if (typeof response.data === 'object' && response.data !== null) {
// 首先尝试获取data数组根据截图API返回格式
if (Array.isArray(response.data.data)) {
items = response.data.data;
} else if (Array.isArray(response.data.items)) {
items = response.data.items;
} else if (Array.isArray(response.data)) {
items = response.data;
} else {
// 如果只是单个对象,包装成数组
items = [response.data];
}
} else if (Array.isArray(response.data)) {
items = response.data;
}
// 转换数据格式以便显示
const formattedItems = items.map((item) => {
// 基础字段映射
const baseFields = {
targetId: item.targetId || item.busNo || item.itemId || item.code || item.id || '-',
chargeName: item.chargeName || item.itemName || item.name || '-',
volume: item.totalVolume || item.spec || item.specification || '-',
price: item.price || item.newprice || item.newPrice || item.afterPrice || '-',
reason: item.reason || item.sreason || item.adjustReason || item.remark || '-',
orgName: item.orgName || item.org || '-',
// 额外字段,用于挂号调价单显示
name: item.name || item.chargeName || item.itemName || '-',
originPrice: item.originPrice || '-',
retailPrice: item.retailPrice || '-',
originBuyingPrice: item.originBuyingPrice || '-',
newBuyingPrice: item.newBuyingPrice || '-',
originRetailPrice: item.originRetailPrice || '-',
newRetailPrice: item.newRetailPrice || '-',
};
return baseFields;
});
// 设置selectedRow确保格式一致
selectedRow.value = {
items: formattedItems,
createName: row.applicantId_dictText || '-',
busNo: row.busNo, // 添加busNo字段用于后续的审核和驳回操作
statusEnum_enumText: row.statusEnum_enumText, // 添加状态字段,用于控制按钮显示
};
// 显示弹窗
detailDialogVisible.value = true;
} else {
ElMessage.error(response?.msg || '获取详情数据失败');
}
} catch (error) {
ElMessage.error('获取详情数据失败');
} finally {
loading.value = false;
}
};
// 关闭详情弹窗处理
const handleDetailClose = () => {
// 重置选中的行数据和类型
selectedRow.value = {};
categoryType.value = '';
};
// 处理审批通过事件
const handleApprove = async () => {
try {
// 获取当前选中行的业务编号
const busNo = selectedRow.value.busNo;
// 调用审核通过API
const response = await updateExamineByApproved(busNo);
if (response && response.code === 200) {
ElMessage.success('审核通过成功');
// 关闭详情弹窗
detailDialogVisible.value = false;
// 刷新页面数据
getList();
} else {
ElMessage.error(response?.msg || '审核通过失败');
}
} catch (error) {
ElMessage.error('审核通过失败');
}
};
// 处理驳回事件
const handleReject = async () => {
try {
// 获取当前选中行的业务编号
const busNo = selectedRow.value.busNo;
// 调用驳回API
const response = await rejectPriceAdjustment(busNo);
if (response && response.code === 200) {
ElMessage.success('驳回成功');
// 关闭详情弹窗
detailDialogVisible.value = false;
// 延迟一点时间再刷新,确保弹窗完全关闭
setTimeout(async () => {
await getList();
}, 300);
} else {
ElMessage.error(response?.msg || '驳回失败');
}
} catch (error) {
ElMessage.error('驳回失败');
}
};
// 处理查询
const handleSearch = () => {
queryParams.pageNum = 1; // 重置页码
getList();
};
// 加载审核状态选项
const loadExamineStatusOptions = async () => {
// 如果已经加载过,不再重复加载
if (examineStatusOptions.value.length > 0) {
return;
}
optionsLoading.value = true;
try {
const response = await getExamineStatusOptions();
// 先清空选项数组
examineStatusOptions.value = [];
if (response && response.code === 200 && response.data) {
// 1. 首先检查是否有supplyStatusOptions字段
if (response.data.supplyStatusOptions) {
if (Array.isArray(response.data.supplyStatusOptions)) {
// supplyStatusOptions是数组
examineStatusOptions.value = response.data.supplyStatusOptions.map((item) => ({
value: item.code || item.key || item.value,
label: item.name || item.label || item.value,
}));
} else if (typeof response.data.supplyStatusOptions === 'object') {
// supplyStatusOptions是对象
examineStatusOptions.value = Object.entries(response.data.supplyStatusOptions).map(
([key, value]) => ({
value: key,
label: value,
})
);
}
}
// 2. 如果没有supplyStatusOptions字段但response.data本身是数组
else if (Array.isArray(response.data)) {
examineStatusOptions.value = response.data.map((item) => {
// 处理可能的JSON字符串格式
if (typeof item === 'string') {
try {
const parsed = JSON.parse(item);
return {
value: parsed.value || parsed.code || parsed.key,
label: parsed.label || parsed.name || parsed.value,
};
} catch (e) {
return {
value: item,
label: item,
};
}
}
return {
value: item.value || item.code || item.key,
label: item.label || item.name || item.value,
};
});
}
// 3. 如果response.data是对象
else if (typeof response.data === 'object') {
examineStatusOptions.value = Object.entries(response.data).map(([key, value]) => ({
value: key,
label: value,
}));
}
// 确保选项格式正确
if (examineStatusOptions.value.length === 0) {
// 如果没有数据,添加默认的选项
examineStatusOptions.value = [
{ value: '', label: '全部' },
{ value: '1', label: '待审核' },
{ value: '2', label: '已审核' },
{ value: '3', label: '已拒绝' },
];
} else {
// 在选项开头添加"全部"选项
examineStatusOptions.value.unshift({ value: '', label: '全部' });
}
} else {
// 如果API调用失败使用默认选项
examineStatusOptions.value = [
{ value: '', label: '全部' },
{ value: '1', label: '待审核' },
{ value: '2', label: '已审核' },
{ value: '3', label: '已拒绝' },
];
}
} catch (error) {
// 错误情况下使用默认选项
examineStatusOptions.value = [
{ value: '', label: '全部' },
{ value: '1', label: '待审核' },
{ value: '2', label: '已审核' },
{ value: '3', label: '已拒绝' },
];
} finally {
optionsLoading.value = false;
}
};
// 处理重置
const handleReset = () => {
// 重置查询参数
queryParams.statusEnum = undefined;
queryParams.applicantTime = undefined;
queryParams.pageNum = 1;
getList();
};
// 生命周期 - 加载
onMounted(() => {
// 初始加载审核状态选项
loadExamineStatusOptions();
getList();
});
</script>
<style scoped>
.app-container {
padding: 20px;
}
.query-form {
background-color: #fff;
padding: 20px;
border-radius: 8px;
margin-bottom: 20px;
border: 1px solid #ebeef5;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
.query-buttons {
display: flex;
gap: 10px;
align-items: center;
height: 100%;
}
/* 确保表单元素垂直居中对齐 */
:deep(.el-form-item) {
margin-bottom: 0;
display: flex;
align-items: center;
height: 100%;
}
/* 确保标签和输入框垂直居中 */
:deep(.el-form-item__label-wrap) {
display: flex;
align-items: center;
}
:deep(.el-form-item__content) {
display: flex;
align-items: center;
}
:deep(.el-tabs__content) {
height: auto;
}
:deep(.demo-tabs > .el-tabs__content) {
color: #6b778c;
font-size: 14px;
}
:deep(.el-table) {
border: 1px solid #ebeef5;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
}
:deep(.el-table__header-wrapper) {
border-radius: 8px 8px 0 0;
overflow: hidden;
}
:deep(.el-table__body-wrapper) {
border-radius: 0 0 8px 8px;
overflow: hidden;
}
</style>