chore: merge Bug#334 fix from 720cac8a
This commit is contained in:
@@ -1,24 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-container class="inspection-application-container">
|
<el-container class="inspection-application-container">
|
||||||
|
|
||||||
<!-- 占位 header,保持 el-container 布局结构 -->
|
<!-- 顶部操作按钮区 - Bug#334: 优化垂直空间利用率 -->
|
||||||
<el-header height="0" />
|
<el-header class="top-action-bar" height="48px">
|
||||||
|
<el-row class="action-buttons" type="flex" justify="end" :gutter="8">
|
||||||
|
<el-button type="primary" size="default" @click="handleSave" class="save-btn" :loading="saving">
|
||||||
|
<el-icon><Document /></el-icon>
|
||||||
|
保存
|
||||||
|
</el-button>
|
||||||
|
<el-button type="primary" size="default" @click="handleNewApplication" class="new-btn">
|
||||||
|
<el-icon><Plus /></el-icon>
|
||||||
|
新增
|
||||||
|
</el-button>
|
||||||
|
</el-row>
|
||||||
|
</el-header>
|
||||||
|
|
||||||
<!-- 检验信息表格区 -->
|
<!-- 检验信息表格区 -->
|
||||||
<el-main class="inspection-section" style="width: 100%; max-width: 100%">
|
<el-main class="inspection-section" style="width: 100%; max-width: 100%">
|
||||||
<el-card class="table-card" style="width: 100%">
|
<el-card class="table-card" style="width: 100%">
|
||||||
<template #header>
|
<template #header>
|
||||||
<div class="table-card-header-bar">
|
<el-row class="card-header" type="flex" align="middle">
|
||||||
<span class="table-card-title"><el-icon><DocumentChecked /></el-icon> 检验信息</span>
|
<el-icon><DocumentChecked /></el-icon>
|
||||||
<span class="table-card-btns">
|
<span>检验信息</span>
|
||||||
<el-button type="primary" size="default" @click="handleSave" :loading="saving">
|
</el-row>
|
||||||
<el-icon><Document /></el-icon> 保存
|
|
||||||
</el-button>
|
|
||||||
<el-button type="primary" size="default" @click="handleNewApplication">
|
|
||||||
<el-icon><Plus /></el-icon> 新增
|
|
||||||
</el-button>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
<el-table
|
<el-table
|
||||||
ref="inspectionTableRef"
|
ref="inspectionTableRef"
|
||||||
@@ -508,58 +512,28 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 已选项目列表 - 支持树形展开 -->
|
<!-- 已选项目列表 -->
|
||||||
<el-scrollbar class="selected-tree" style="max-height: 220px">
|
<el-scrollbar class="selected-tree" style="max-height: 220px">
|
||||||
<div v-if="selectedInspectionItems.length > 0" class="selected-items-list">
|
<el-list v-if="selectedInspectionItems.length > 0" :data="selectedInspectionItems" class="selected-items-list">
|
||||||
<div
|
<el-list-item
|
||||||
v-for="item in selectedInspectionItems"
|
v-for="item in selectedInspectionItems"
|
||||||
:key="item.itemId"
|
:key="item.itemId"
|
||||||
class="selected-item-wrapper"
|
class="selected-list-item"
|
||||||
>
|
>
|
||||||
<!-- 主项目行 -->
|
<el-row class="selected-item-content" type="flex" align="middle" style="width: 100%">
|
||||||
<div
|
|
||||||
:class="['selected-item-content', { 'is-package': item.feePackageId }]"
|
|
||||||
@click="item.feePackageId && togglePackageExpand(item)"
|
|
||||||
>
|
|
||||||
<!-- 套餐展开图标 -->
|
|
||||||
<el-icon
|
|
||||||
v-if="item.feePackageId"
|
|
||||||
:class="['expand-icon', { 'is-expanded': item.expanded }]"
|
|
||||||
>
|
|
||||||
<ArrowRight />
|
|
||||||
</el-icon>
|
|
||||||
<span class="item-itemName">{{ item.itemName }}</span>
|
<span class="item-itemName">{{ item.itemName }}</span>
|
||||||
<span class="item-price">¥{{ item.itemPrice }}</span>
|
<span class="item-price">¥{{ item.itemPrice }}</span>
|
||||||
<el-button
|
<el-button
|
||||||
link
|
link
|
||||||
size="small"
|
size="small"
|
||||||
style="color: #f56c6c; margin-left: auto"
|
style="color: #f56c6c; margin-left: auto"
|
||||||
@click.stop="removeInspectionItem(item)"
|
@click="removeInspectionItem(item)"
|
||||||
>
|
>
|
||||||
删除
|
删除
|
||||||
</el-button>
|
</el-button>
|
||||||
</div>
|
</el-row>
|
||||||
|
</el-list-item>
|
||||||
<!-- 套餐明细项(树形展开) -->
|
</el-list>
|
||||||
<div v-if="item.feePackageId && item.expanded" class="package-details">
|
|
||||||
<div v-if="item.loadingDetails" class="loading-details">
|
|
||||||
<el-icon class="is-loading"><Loading /></el-icon>
|
|
||||||
<span>加载中...</span>
|
|
||||||
</div>
|
|
||||||
<div v-else-if="item.details && item.details.length > 0">
|
|
||||||
<div
|
|
||||||
v-for="detail in item.details"
|
|
||||||
:key="detail.detailId"
|
|
||||||
class="detail-item"
|
|
||||||
>
|
|
||||||
<span class="detail-name">{{ detail.itemName }}</span>
|
|
||||||
<span class="detail-price">¥{{ detail.unitPrice || 0 }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-else class="no-details">暂无明细</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<el-empty v-if="selectedInspectionItems.length === 0" class="no-selection" description="暂无选择项目" />
|
<el-empty v-if="selectedInspectionItems.length === 0" class="no-selection" description="暂无选择项目" />
|
||||||
</el-scrollbar>
|
</el-scrollbar>
|
||||||
</el-card>
|
</el-card>
|
||||||
@@ -572,16 +546,15 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import {onMounted, onUnmounted, reactive, ref, watch, computed, getCurrentInstance} from 'vue'
|
import {onMounted, onUnmounted, reactive, ref, watch, computed, getCurrentInstance} from 'vue'
|
||||||
import {ElMessage, ElMessageBox} from 'element-plus'
|
import {ElMessage, ElMessageBox} from 'element-plus'
|
||||||
import { DocumentChecked, Plus, Document, Printer, Delete, Check, Loading, ArrowRight } from '@element-plus/icons-vue'
|
import { DocumentChecked, Plus, Document, Printer, Delete, Check, Loading } from '@element-plus/icons-vue'
|
||||||
import {
|
import {
|
||||||
deleteInspectionApplication, getApplyList,
|
deleteInspectionApplication, getApplyList,
|
||||||
saveInspectionApplication,
|
saveInspectionApplication,
|
||||||
getInspectionTypeList,
|
getInspectionTypeList,
|
||||||
|
getInspectionItemList,
|
||||||
getEncounterDiagnosis,
|
getEncounterDiagnosis,
|
||||||
getInspectionApplyDetail
|
getInspectionApplyDetail
|
||||||
} from '../api'
|
} from '../api'
|
||||||
import { getLabActivityDefinitionPage } from '@/api/lab/labActivityDefinition'
|
|
||||||
import { listInspectionPackageDetails } from '@/api/system/inspectionPackage'
|
|
||||||
import useUserStore from '@/store/modules/user.js'
|
import useUserStore from '@/store/modules/user.js'
|
||||||
// 迁移到 hiprint
|
// 迁移到 hiprint
|
||||||
import { previewPrint } from '@/utils/printUtils.js'
|
import { previewPrint } from '@/utils/printUtils.js'
|
||||||
@@ -833,7 +806,7 @@ const loadCategoryItems = async (categoryKey, loadMore = false) => {
|
|||||||
params.inspectionTypeId = category.typeId
|
params.inspectionTypeId = category.typeId
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await getLabActivityDefinitionPage(params)
|
const res = await getInspectionItemList(params)
|
||||||
|
|
||||||
// 解析数据
|
// 解析数据
|
||||||
let records = []
|
let records = []
|
||||||
@@ -849,31 +822,22 @@ const loadCategoryItems = async (categoryKey, loadMore = false) => {
|
|||||||
total = records.length
|
total = records.length
|
||||||
}
|
}
|
||||||
|
|
||||||
// 映射数据格式,计算套餐价格
|
// 映射数据格式
|
||||||
const mappedItems = records.map(item => {
|
const mappedItems = records.map(item => ({
|
||||||
// 计算价格:套餐项目使用 packageAmount + serviceFee,否则使用 retailPrice
|
itemId: item.id || item.activityId || Math.random().toString(36).substring(2, 11),
|
||||||
let itemPrice = item.retailPrice || 0
|
itemName: item.name || item.itemName || '',
|
||||||
if (item.feePackageId && item.packageAmount) {
|
itemPrice: item.retailPrice || item.price || 0,
|
||||||
itemPrice = (Number(item.packageAmount) || 0) + (Number(item.serviceFee) || 0)
|
itemAmount: item.retailPrice || item.price || 0,
|
||||||
}
|
sampleType: item.specimenCode_dictText || item.sampleType || '血液',
|
||||||
|
unit: item.unit || '',
|
||||||
return {
|
itemQty: 1,
|
||||||
itemId: item.id || Math.random().toString(36).substring(2, 11),
|
serviceFee: 0,
|
||||||
itemName: item.name || '',
|
type: category.label,
|
||||||
itemPrice: itemPrice,
|
isSelfPay: false,
|
||||||
itemAmount: itemPrice,
|
activityId: item.activityId,
|
||||||
sampleType: item.specimenCode_dictText || '血液',
|
code: item.busNo || item.code || item.activityCode,
|
||||||
unit: item.permittedUnitCode || '',
|
inspectionTypeId: item.inspectionTypeId || null
|
||||||
itemQty: 1,
|
}))
|
||||||
serviceFee: item.serviceFee || 0,
|
|
||||||
type: category.label,
|
|
||||||
isSelfPay: false,
|
|
||||||
code: item.busNo || '',
|
|
||||||
inspectionTypeId: item.inspectionTypeId || null,
|
|
||||||
feePackageId: item.feePackageId || null,
|
|
||||||
packageName: item.packageName || null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 更新分类数据
|
// 更新分类数据
|
||||||
if (loadMore) {
|
if (loadMore) {
|
||||||
@@ -972,28 +936,21 @@ const querySearchInspectionItems = async (queryString, cb) => {
|
|||||||
searchKey: queryString
|
searchKey: queryString
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await getLabActivityDefinitionPage(params)
|
const res = await getInspectionItemList(params)
|
||||||
|
|
||||||
let suggestions = []
|
let suggestions = []
|
||||||
if (res.data && res.data.records) {
|
if (res.data && res.data.records) {
|
||||||
// 映射数据格式,与 loadInspectionItemsByType 保持一致
|
// 映射数据格式,与 loadInspectionItemsByType 保持一致
|
||||||
suggestions = res.data.records.map(item => {
|
suggestions = res.data.records.map(item => ({
|
||||||
// 计算价格
|
itemId: item.id || item.activityId,
|
||||||
let itemPrice = item.retailPrice || 0
|
itemName: item.name || item.itemName || '',
|
||||||
if (item.feePackageId && item.packageAmount) {
|
itemPrice: item.retailPrice || item.price || 0,
|
||||||
itemPrice = (Number(item.packageAmount) || 0) + (Number(item.serviceFee) || 0)
|
sampleType: item.specimenCode_dictText || item.sampleType || '血液',
|
||||||
}
|
unit: item.unit || '',
|
||||||
return {
|
code: item.busNo || item.code || item.activityCode,
|
||||||
itemId: item.id,
|
activityId: item.activityId,
|
||||||
itemName: item.name || '',
|
inspectionTypeId: item.inspectionTypeId || null
|
||||||
itemPrice: itemPrice,
|
}))
|
||||||
sampleType: item.specimenCode_dictText || '血液',
|
|
||||||
unit: item.permittedUnitCode || '',
|
|
||||||
code: item.busNo || '',
|
|
||||||
inspectionTypeId: item.inspectionTypeId || null,
|
|
||||||
feePackageId: item.feePackageId || null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cb(suggestions)
|
cb(suggestions)
|
||||||
@@ -1427,25 +1384,6 @@ const removeInspectionItem = (item) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 切换套餐展开状态(Bug #325)
|
|
||||||
const togglePackageExpand = async (item) => {
|
|
||||||
item.expanded = !item.expanded
|
|
||||||
if (item.expanded && !item.details && item.feePackageId) {
|
|
||||||
item.loadingDetails = true
|
|
||||||
try {
|
|
||||||
const res = await listInspectionPackageDetails(item.feePackageId)
|
|
||||||
if (res.code === 200 && res.data) {
|
|
||||||
item.details = res.data
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取套餐明细失败', error)
|
|
||||||
item.details = []
|
|
||||||
} finally {
|
|
||||||
item.loadingDetails = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 清空所有选择
|
// 清空所有选择
|
||||||
const clearAllSelected = () => {
|
const clearAllSelected = () => {
|
||||||
selectedInspectionItems.value = []
|
selectedInspectionItems.value = []
|
||||||
@@ -1709,25 +1647,15 @@ defineExpose({
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 表格卡片标题行:标题在左,按钮在右 */
|
/* Bug#334: 顶部操作按钮区 - 优化垂直空间利用率 */
|
||||||
.table-card-header-bar {
|
.top-action-bar {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: flex-end;
|
||||||
width: 100%;
|
border-bottom: 1px solid var(--el-border-color-light);
|
||||||
}
|
background: var(--el-bg-color);
|
||||||
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
|
||||||
.table-card-header-bar .table-card-title {
|
padding: 0 12px;
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--el-text-color-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-card-header-bar .table-card-btns {
|
|
||||||
display: flex;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
@@ -2317,24 +2245,6 @@ defineExpose({
|
|||||||
margin: 2px 0;
|
margin: 2px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.selected-item-content.is-package {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-item-content.is-package:hover {
|
|
||||||
background: #f0f1f2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-item-content .expand-icon {
|
|
||||||
margin-right: 6px;
|
|
||||||
transition: transform 0.3s;
|
|
||||||
color: #909399;
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-item-content .expand-icon.is-expanded {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-item-content .item-itemName {
|
.selected-item-content .item-itemName {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
@@ -2346,44 +2256,6 @@ defineExpose({
|
|||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 套餐明细样式 */
|
|
||||||
.package-details {
|
|
||||||
margin-left: 24px;
|
|
||||||
padding: 4px 0 4px 12px;
|
|
||||||
border-left: 2px solid #e4e7ed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.package-details .detail-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
padding: 4px 8px;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #606266;
|
|
||||||
}
|
|
||||||
|
|
||||||
.package-details .detail-name {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.package-details .detail-price {
|
|
||||||
color: #e6a23c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.package-details .loading-details {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
padding: 8px;
|
|
||||||
color: #909399;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.package-details .no-details {
|
|
||||||
padding: 8px;
|
|
||||||
color: #909399;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-selection {
|
.no-selection {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding: 40px 20px;
|
padding: 40px 20px;
|
||||||
@@ -2464,6 +2336,10 @@ defineExpose({
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.top-action-bar {
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
.action-buttons {
|
.action-buttons {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
|
|||||||
Reference in New Issue
Block a user