当手术计费弹窗中点击"签发"耗材时,因耗材的locationId(发放库房)为空导致后端异常。 在DoctorStationAdviceAppServiceImpl.handDevice方法中,当locationId为null时,使用登录用户的科室ID作为默认值, 与NurseBillingAppService中的处理方式保持一致。
815 lines
24 KiB
Vue
Executable File
815 lines
24 KiB
Vue
Executable File
<template>
|
||
<div class="package-management">
|
||
<!-- 顶部筛选栏 -->
|
||
<div class="filter-section">
|
||
<el-form :model="queryParams" :inline="true" label-width="80px">
|
||
<el-form-item label="日期">
|
||
<el-date-picker
|
||
v-model="dateRange"
|
||
type="daterange"
|
||
range-separator="-"
|
||
start-placeholder="开始日期"
|
||
end-placeholder="结束日期"
|
||
format="YYYY-MM-DD"
|
||
value-format="YYYY-MM-DD"
|
||
style="width: 240px"
|
||
/>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="卫生机构">
|
||
<el-select v-model="queryParams.organization" placeholder="请选择机构" style="width: 150px" clearable filterable>
|
||
<el-option
|
||
v-for="org in organizationOptions"
|
||
:key="org.value"
|
||
:label="org.label"
|
||
:value="org.value"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="套餐名称">
|
||
<el-input
|
||
v-model="queryParams.packageName"
|
||
placeholder="请输入套餐名称"
|
||
style="width: 200px"
|
||
clearable
|
||
/>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="套餐级别">
|
||
<el-select v-model="queryParams.packageLevel" placeholder="请选择套餐级别" style="width: 150px" clearable>
|
||
<el-option
|
||
v-for="item in packageLevelOptions"
|
||
:key="item.dictValue"
|
||
:label="item.dictLabel"
|
||
:value="item.dictValue"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="套餐类别">
|
||
<el-select v-model="queryParams.packageType" placeholder="请选择套餐类别" style="width: 150px" clearable>
|
||
<el-option label="检查套餐" value="检查套餐" />
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="科室">
|
||
<el-select v-model="queryParams.department" placeholder="请选择科室" style="width: 150px" clearable filterable>
|
||
<el-option
|
||
v-for="dept in departments"
|
||
:key="dept.dictValue"
|
||
:label="dept.dictLabel"
|
||
:value="dept.deptCode || dept.busNoPrefix || dept.rawOrg?.busNo || dept.dictLabel"
|
||
/>
|
||
</el-select>
|
||
</el-form-item>
|
||
|
||
<el-form-item label="用户">
|
||
<el-input
|
||
v-model="queryParams.user"
|
||
placeholder="请输入用户名称"
|
||
style="width: 150px"
|
||
clearable
|
||
/>
|
||
</el-form-item>
|
||
|
||
<el-form-item>
|
||
<el-button type="primary" @click="handleQuery" icon="Search">查询</el-button>
|
||
<el-button @click="handleReset" icon="Refresh">重置</el-button>
|
||
<el-button type="success" @click="handleAdd" icon="Plus">新增</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
|
||
<!-- 表格展示区 -->
|
||
<div class="table-section">
|
||
<div class="table-wrapper">
|
||
<el-table
|
||
:data="tableData"
|
||
border
|
||
style="width: 100%"
|
||
v-loading="loading"
|
||
:max-height="600"
|
||
>
|
||
<el-table-column prop="id" label="ID" width="80" align="center" />
|
||
<el-table-column prop="organization" label="卫生机构" width="120" align="center" />
|
||
<el-table-column prop="maintainDate" label="日期" width="120" align="center" />
|
||
<el-table-column prop="packageName" label="套餐名称" min-width="150" show-overflow-tooltip />
|
||
<el-table-column prop="packageType" label="套餐类别" width="100" align="center" />
|
||
<el-table-column prop="packageLevel" label="套餐级别" width="100" align="center">
|
||
<template #default="{ row }">
|
||
{{ getLevelLabel(row.packageLevel) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="department" label="科室" width="150" align="center">
|
||
<template #default="{ row }">
|
||
<span :title="row.department && /^[A-Z]\d{2}$/.test(row.department.trim()) ? '旧编码格式,建议编辑套餐重新选择科室' : ''">
|
||
{{ getDeptName(row.department) }}
|
||
</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="user" label="用户" width="100" align="center" />
|
||
<el-table-column prop="packagePrice" label="金额" width="100" align="center">
|
||
<template #default="{ row }">
|
||
{{ (row.packagePrice || 0).toFixed(2) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="serviceFee" label="服务费" width="100" align="center">
|
||
<template #default="{ row }">
|
||
{{ (row.serviceFee || 0).toFixed(2) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="总金额" width="100" align="center">
|
||
<template #default="{ row }">
|
||
{{ ((row.packagePrice || 0) + (row.serviceFee || 0)).toFixed(2) }}
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="组合套餐" width="100" align="center">
|
||
<template #default="{ row }">
|
||
<el-tag :type="row.packagePriceEnabled === 1 ? 'success' : 'danger'">
|
||
{{ row.packagePriceEnabled === 1 ? '是' : '否' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="显示套餐名" width="110" align="center">
|
||
<template #default="{ row }">
|
||
<el-tag :type="row.showPackageName === 1 ? 'success' : 'info'">
|
||
{{ row.showPackageName === 1 ? '是' : '否' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="启用标志" width="100" align="center">
|
||
<template #default="{ row }">
|
||
<el-tag :type="row.isDisabled === 0 ? 'success' : 'danger'">
|
||
{{ row.isDisabled === 0 ? '是' : '否' }}
|
||
</el-tag>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="creator" label="操作人" width="100" align="center" />
|
||
<el-table-column label="操作" width="180" align="center" fixed="right">
|
||
<template #default="{ row }">
|
||
<div class="actions">
|
||
<el-button
|
||
class="btn btn-edit"
|
||
size="small"
|
||
circle
|
||
@click="handleEdit(row)"
|
||
title="编辑"
|
||
>
|
||
✏️
|
||
</el-button>
|
||
<el-button
|
||
class="btn btn-view"
|
||
size="small"
|
||
circle
|
||
@click="handleView(row)"
|
||
title="查看"
|
||
>
|
||
👁️
|
||
</el-button>
|
||
<el-button
|
||
class="btn btn-delete"
|
||
size="small"
|
||
circle
|
||
@click="handleDelete(row)"
|
||
title="删除"
|
||
>
|
||
✕
|
||
</el-button>
|
||
</div>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 底部分页 -->
|
||
<div class="pagination-section">
|
||
<el-pagination
|
||
v-model:current-page="queryParams.pageNo"
|
||
v-model:page-size="queryParams.pageSize"
|
||
:page-sizes="[10, 20, 50, 100]"
|
||
:total="total"
|
||
layout="total, sizes, prev, pager, next, jumper"
|
||
@size-change="handleQuery"
|
||
@current-change="handleQuery"
|
||
/>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import {onMounted, reactive, ref} from 'vue'
|
||
import {ElMessage, ElMessageBox} from 'element-plus'
|
||
import {getDicts} from '@/api/system/dict/data'
|
||
import {listDept} from '@/api/system/dept'
|
||
import {delCheckPackage, getCheckPackage, listCheckPackage} from '@/api/system/checkType'
|
||
import {getTenantPage} from '@/api/system/tenant'
|
||
import request from '@/utils/request'
|
||
import useUserStore from '@/store/modules/user'
|
||
|
||
// 定义emit事件
|
||
const emit = defineEmits(['switch-to-settings'])
|
||
|
||
const userStore = useUserStore()
|
||
|
||
//删除
|
||
function handleDelete(row) {
|
||
const currentUser = userStore.name
|
||
console.log('当前用户:', currentUser, '套餐创建者:', row.creator)
|
||
//只有创建者本人才能删除(creator为空时不能删除)
|
||
if(!row.creator){
|
||
ElMessage.warning('该套餐创建者未知,无法删除')
|
||
return
|
||
}
|
||
if(row.creator !== currentUser){
|
||
ElMessage.warning(`该套餐由"${row.creator}"创建,您没有权限删除`)
|
||
return
|
||
}
|
||
|
||
ElMessageBox.confirm(
|
||
`确认删除套餐ID:${row.id} - ${row.packageName} 吗?删除后将无法恢复`,
|
||
'确认删除',
|
||
{
|
||
confirmButtonText:'确定删除',
|
||
cancelButtonText:'取消',
|
||
type: 'warning',
|
||
buttonSize:'default'
|
||
}
|
||
).then(async () => {
|
||
try{const response = await delCheckPackage(row.id)
|
||
|
||
if(response && response.code === 200 || response.code === 0){
|
||
ElMessage.success('删除成功')
|
||
handleQuery()
|
||
}else{
|
||
ElMessage.error(response?.msg || response?.message || '删除失败')
|
||
}
|
||
}catch(error){
|
||
console.error('删除失败:',error)
|
||
const errorMsg = error?.response?.data?.msg || error?.message || ''
|
||
if(errorMsg.includes('foreign key') || errorMsg.includes('violates foreign key')){
|
||
ElMessage.warning('该套餐已被使用,无法删除')
|
||
}else{
|
||
ElMessage.error('删除失败:'+(error.message || '未知错误'))
|
||
}
|
||
}
|
||
}).catch(() => {})
|
||
}
|
||
|
||
// 查询参数
|
||
const queryParams = reactive({
|
||
pageNo: 1,
|
||
pageSize: 10,
|
||
organization: '',
|
||
packageName: '',
|
||
packageLevel: '',
|
||
packageType: '',
|
||
department: '',
|
||
user: ''
|
||
})
|
||
|
||
// 日期范围
|
||
const dateRange = ref([])
|
||
|
||
// 表格数据
|
||
const tableData = ref([])
|
||
const total = ref(0)
|
||
const loading = ref(false)
|
||
|
||
// 套餐级别选项
|
||
const packageLevelOptions = ref([])
|
||
// 科室选项
|
||
const departments = ref([])
|
||
// 卫生机构选项
|
||
const organizationOptions = ref([])
|
||
|
||
// 初始化数据
|
||
onMounted(async () => {
|
||
// 获取套餐级别字典
|
||
try {
|
||
const levelResponse = await getDicts('examination_item_package_level')
|
||
if (levelResponse && levelResponse.data) {
|
||
packageLevelOptions.value = levelResponse.data
|
||
}
|
||
} catch (error) {
|
||
console.error('获取套餐级别字典失败:', error)
|
||
}
|
||
|
||
// 获取科室列表 - 使用Organization完整API(包含编码和名称)
|
||
try {
|
||
// 使用Organization完整API获取科室列表(包含busNo编码)
|
||
const orgResponse = await request({
|
||
url: '/base-data-manage/organization/organization',
|
||
method: 'get',
|
||
params: {
|
||
pageNo: 1,
|
||
pageSize: 1000 // 获取足够多的数据
|
||
}
|
||
})
|
||
let orgList = []
|
||
if (orgResponse) {
|
||
if (orgResponse.data) {
|
||
if (orgResponse.data.records && Array.isArray(orgResponse.data.records)) {
|
||
orgList = orgResponse.data.records
|
||
} else if (Array.isArray(orgResponse.data)) {
|
||
orgList = orgResponse.data
|
||
}
|
||
} else if (Array.isArray(orgResponse)) {
|
||
orgList = orgResponse
|
||
}
|
||
}
|
||
|
||
// 展开树结构,过滤出科室类型(typeEnum=2)
|
||
if (orgList && orgList.length > 0) {
|
||
const flattenList = []
|
||
function flatten(nodes) {
|
||
nodes.forEach(node => {
|
||
if (node.typeEnum === 2 && node.busNo && node.name) {
|
||
flattenList.push(node)
|
||
}
|
||
if (node.children && node.children.length > 0) {
|
||
flatten(node.children)
|
||
}
|
||
})
|
||
}
|
||
flatten(orgList)
|
||
orgList = flattenList
|
||
}
|
||
|
||
if (orgList && orgList.length > 0) {
|
||
departments.value = orgList.map(org => {
|
||
const busNo = (org.busNo || org.code || '').trim()
|
||
const name = (org.name || org.deptName || '').trim()
|
||
const busNoPrefix = busNo ? busNo.split('.')[0] : ''
|
||
return {
|
||
dictValue: name,
|
||
dictLabel: name,
|
||
deptId: org.id || org.deptId,
|
||
deptCode: busNo || name,
|
||
busNoPrefix: busNoPrefix,
|
||
rawOrg: org
|
||
}
|
||
})
|
||
} else {
|
||
// 如果Organization API没有数据,使用系统部门API
|
||
const deptResponse = await listDept()
|
||
|
||
let deptList = []
|
||
if (deptResponse) {
|
||
if (Array.isArray(deptResponse)) {
|
||
deptList = deptResponse
|
||
} else if (deptResponse.data) {
|
||
if (Array.isArray(deptResponse.data)) {
|
||
deptList = deptResponse.data
|
||
} else if (deptResponse.data.data && Array.isArray(deptResponse.data.data)) {
|
||
deptList = deptResponse.data.data
|
||
}
|
||
} else if (deptResponse.code === 200 && deptResponse.data) {
|
||
deptList = Array.isArray(deptResponse.data) ? deptResponse.data : []
|
||
}
|
||
}
|
||
|
||
if (deptList && deptList.length > 0) {
|
||
departments.value = deptList.map(dept => ({
|
||
dictValue: dept.deptName || dept.name,
|
||
dictLabel: dept.deptName || dept.name,
|
||
deptId: dept.deptId || dept.id,
|
||
deptCode: dept.deptName || dept.name
|
||
}))
|
||
} else {
|
||
// 如果获取失败,尝试使用字典方式
|
||
try {
|
||
const dictResponse = await getDicts('dept')
|
||
if (dictResponse && dictResponse.data) {
|
||
departments.value = dictResponse.data
|
||
}
|
||
} catch (dictError) {
|
||
console.error('获取科室字典失败:', dictError)
|
||
}
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('获取科室列表失败:', error)
|
||
// 如果获取失败,尝试使用字典方式
|
||
try {
|
||
const dictResponse = await getDicts('dept')
|
||
if (dictResponse && dictResponse.data) {
|
||
departments.value = dictResponse.data
|
||
}
|
||
} catch (dictError) {
|
||
console.error('获取科室字典也失败:', dictError)
|
||
}
|
||
}
|
||
|
||
// 获取卫生机构列表
|
||
try {
|
||
const tenantResponse = await getTenantPage({ pageNum: 1, pageSize: 100 })
|
||
if (tenantResponse && tenantResponse.code === 200) {
|
||
const tenantData = tenantResponse.data || {}
|
||
let tenantList = []
|
||
if (Array.isArray(tenantData)) {
|
||
tenantList = tenantData
|
||
} else if (tenantData.records) {
|
||
tenantList = tenantData.records
|
||
} else if (tenantData.rows) {
|
||
tenantList = tenantData.rows
|
||
} else if (tenantData.list) {
|
||
tenantList = tenantData.list
|
||
}
|
||
// 过滤启用的机构
|
||
organizationOptions.value = tenantList
|
||
.filter(item => item && item.status === '0')
|
||
.map(item => ({
|
||
value: item.tenantName || item.name || item.orgName || String(item.id),
|
||
label: item.tenantName || item.name || item.orgName || String(item.id)
|
||
}))
|
||
}
|
||
} catch (error) {
|
||
console.error('获取卫生机构列表失败:', error)
|
||
}
|
||
|
||
// 加载列表数据
|
||
handleQuery()
|
||
})
|
||
|
||
// 获取级别标签
|
||
function getLevelLabel(value) {
|
||
const item = packageLevelOptions.value.find(i => i.dictValue === value)
|
||
return item ? item.dictLabel : value
|
||
}
|
||
|
||
// 获取科室名称(根据编码或名称查找)
|
||
function getDeptName(deptValue) {
|
||
if (!deptValue) return ''
|
||
|
||
// 去除前后空格
|
||
const trimmedValue = String(deptValue).trim()
|
||
if (!trimmedValue) return ''
|
||
|
||
// 如果科室列表为空,直接返回原值
|
||
if (!departments.value || departments.value.length === 0) {
|
||
return trimmedValue
|
||
}
|
||
|
||
// 先尝试精确匹配编码(去除所有空格,转大写)
|
||
let dept = departments.value.find(d => {
|
||
const code = String(d.deptCode || '').trim().replace(/\s+/g, '').toUpperCase()
|
||
const searchValue = trimmedValue.replace(/\s+/g, '').toUpperCase()
|
||
return code && code === searchValue
|
||
})
|
||
|
||
// 如果找不到,尝试通过busNo前缀匹配(优先使用存储的前缀)
|
||
if (!dept) {
|
||
dept = departments.value.find(d => {
|
||
const busNoPrefix = String(d.busNoPrefix || '').trim().replace(/\s+/g, '').toUpperCase()
|
||
const searchValue = trimmedValue.replace(/\s+/g, '').toUpperCase()
|
||
return busNoPrefix && busNoPrefix === searchValue
|
||
})
|
||
}
|
||
|
||
// 如果找不到,尝试通过原始busNo精确匹配
|
||
if (!dept) {
|
||
dept = departments.value.find(d => {
|
||
const rawBusNo = String(d.rawOrg?.busNo || '').trim().replace(/\s+/g, '').toUpperCase()
|
||
const searchValue = trimmedValue.replace(/\s+/g, '').toUpperCase()
|
||
return rawBusNo && rawBusNo === searchValue
|
||
})
|
||
}
|
||
|
||
// 如果找不到,尝试层级编码匹配(busNo可能是 "A01.001",搜索值是 "A01")
|
||
if (!dept) {
|
||
dept = departments.value.find(d => {
|
||
const rawBusNo = String(d.rawOrg?.busNo || '').trim().replace(/\s+/g, '').toUpperCase()
|
||
const searchValue = trimmedValue.replace(/\s+/g, '').toUpperCase()
|
||
if (!rawBusNo) return false
|
||
// 如果busNo包含点号,取点号前的部分进行匹配
|
||
const busNoPrefix = rawBusNo.split('.')[0]
|
||
// 匹配方式:前缀匹配、完全匹配、或者搜索值作为前缀
|
||
return busNoPrefix === searchValue ||
|
||
rawBusNo.startsWith(searchValue + '.') ||
|
||
rawBusNo === searchValue
|
||
})
|
||
}
|
||
|
||
// 如果找不到,尝试匹配名称
|
||
if (!dept) {
|
||
dept = departments.value.find(d => {
|
||
const label = String(d.dictLabel || '').trim()
|
||
const value = String(d.dictValue || '').trim()
|
||
return label === trimmedValue || value === trimmedValue
|
||
})
|
||
}
|
||
|
||
// 如果还是找不到,尝试部分匹配(编码可能不完整,或者编码格式不同)
|
||
if (!dept) {
|
||
dept = departments.value.find(d => {
|
||
const code = String(d.deptCode || '').trim().replace(/\s+/g, '').toUpperCase()
|
||
const rawBusNo = String(d.rawOrg?.busNo || '').trim().replace(/\s+/g, '').toUpperCase()
|
||
const searchValue = trimmedValue.replace(/\s+/g, '').toUpperCase()
|
||
if (!code && !rawBusNo) return false
|
||
|
||
// 尝试多种匹配方式
|
||
return (code && code.includes(searchValue)) ||
|
||
(code && searchValue.includes(code)) ||
|
||
(rawBusNo && rawBusNo.includes(searchValue)) ||
|
||
(rawBusNo && searchValue.includes(rawBusNo)) ||
|
||
(rawBusNo && rawBusNo.startsWith(searchValue)) ||
|
||
(code && code.length >= 3 && searchValue.length >= 3 && code.substring(0, 3) === searchValue.substring(0, 3))
|
||
})
|
||
}
|
||
|
||
if (dept && dept.dictLabel) {
|
||
return dept.dictLabel
|
||
}
|
||
|
||
// 无法匹配时,返回原始编码值
|
||
const isOldFormat = /^[A-Z]\d{2}$/.test(trimmedValue)
|
||
if (isOldFormat) {
|
||
return trimmedValue + ' (旧格式)'
|
||
}
|
||
|
||
return trimmedValue
|
||
}
|
||
|
||
// 查询
|
||
async function handleQuery() {
|
||
try {
|
||
loading.value = true
|
||
|
||
// 构建查询参数
|
||
const params = {
|
||
...queryParams
|
||
}
|
||
|
||
// 处理日期范围
|
||
if (dateRange.value && dateRange.value.length === 2) {
|
||
params.startDate = dateRange.value[0]
|
||
params.endDate = dateRange.value[1]
|
||
}
|
||
|
||
const response = await listCheckPackage(params)
|
||
|
||
if (response && response.data) {
|
||
// 处理不同的响应格式
|
||
if (Array.isArray(response.data)) {
|
||
tableData.value = response.data
|
||
total.value = response.data.length
|
||
} else if (response.data.records) {
|
||
tableData.value = response.data.records
|
||
total.value = response.data.total || 0
|
||
} else {
|
||
tableData.value = []
|
||
total.value = 0
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('查询失败:', error)
|
||
ElMessage.error('查询失败: ' + (error.message || '未知错误'))
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
// 重置
|
||
function handleReset() {
|
||
queryParams.pageNo = 1
|
||
queryParams.pageSize = 10
|
||
queryParams.organization = ''
|
||
queryParams.packageName = ''
|
||
queryParams.packageLevel = ''
|
||
queryParams.packageType = ''
|
||
queryParams.department = ''
|
||
queryParams.user = ''
|
||
dateRange.value = []
|
||
|
||
handleQuery()
|
||
}
|
||
|
||
// 新增
|
||
function handleAdd() {
|
||
emit('switch-to-settings', { mode: 'add', data: null })
|
||
}
|
||
|
||
// 编辑
|
||
async function handleEdit(row) {
|
||
try {
|
||
const response = await getCheckPackage(row.id)
|
||
|
||
if (response && (response.code === 200 || response.code === 0) && response.data) {
|
||
emit('switch-to-settings', { mode: 'edit', data: response.data })
|
||
} else {
|
||
ElMessage.error('加载套餐数据失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('加载套餐数据失败:', error)
|
||
ElMessage.error('数据加载失败,请重试')
|
||
}
|
||
}
|
||
|
||
// 查看
|
||
async function handleView(row) {
|
||
try {
|
||
const response = await getCheckPackage(row.id)
|
||
|
||
if (response && (response.code === 200 || response.code === 0) && response.data) {
|
||
emit('switch-to-settings', { mode: 'view', data: response.data })
|
||
} else {
|
||
ElMessage.error('加载套餐数据失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('加载套餐数据失败:', error)
|
||
ElMessage.error('数据加载失败,请重试')
|
||
}
|
||
}
|
||
|
||
// 查询参数
|
||
</script>
|
||
|
||
<style scoped>
|
||
.package-management {
|
||
padding: 24px;
|
||
background-color: #f5f7fa;
|
||
min-height: 100vh;
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: auto;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.filter-section {
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
margin-bottom: 16px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.filter-section :deep(.el-form-item) {
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.table-section {
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 20px;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.03);
|
||
width: 100%;
|
||
box-sizing: border-box;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.table-wrapper {
|
||
width: 100%;
|
||
overflow-x: auto;
|
||
overflow-y: auto;
|
||
max-height: calc(100vh - 400px);
|
||
min-height: 400px;
|
||
}
|
||
|
||
.pagination-section {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
padding: 16px 20px;
|
||
}
|
||
|
||
/* 统一的操作按钮样式 */
|
||
.actions {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
position: relative;
|
||
z-index: 10;
|
||
}
|
||
|
||
.btn {
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
cursor: pointer;
|
||
border: none;
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
position: relative;
|
||
z-index: 10;
|
||
color: white;
|
||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
|
||
}
|
||
|
||
.btn:hover {
|
||
transform: translateY(-2px) scale(1.1);
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
|
||
}
|
||
|
||
.btn:active {
|
||
transform: translateY(0) scale(0.95);
|
||
}
|
||
|
||
.btn-confirm {
|
||
background: linear-gradient(135deg, #52C41A 0%, #73d13d 100%);
|
||
}
|
||
|
||
.btn-confirm:hover {
|
||
background: linear-gradient(135deg, #389E0D 0%, #52C41A 100%);
|
||
}
|
||
|
||
.btn-edit {
|
||
background: linear-gradient(135deg, #1890FF 0%, #40a9ff 100%);
|
||
}
|
||
|
||
.btn-edit:hover {
|
||
background: linear-gradient(135deg, #096DD9 0%, #1890FF 100%);
|
||
}
|
||
|
||
.btn-add {
|
||
background: linear-gradient(135deg, #1890FF 0%, #40a9ff 100%);
|
||
}
|
||
|
||
.btn-add:hover {
|
||
background: linear-gradient(135deg, #096DD9 0%, #1890FF 100%);
|
||
}
|
||
|
||
.btn-view {
|
||
background: linear-gradient(135deg, #722ED1 0%, #9254DE 100%);
|
||
}
|
||
|
||
.btn-view:hover {
|
||
background: linear-gradient(135deg, #531DAE 0%, #722ED1 100%);
|
||
}
|
||
|
||
.btn-delete {
|
||
background: linear-gradient(135deg, #FF4D4F 0%, #ff7875 100%);
|
||
z-index: 20;
|
||
pointer-events: auto;
|
||
}
|
||
|
||
.btn-delete:hover {
|
||
background: linear-gradient(135deg, #CF1322 0%, #FF4D4F 100%);
|
||
}
|
||
|
||
/* 优化滚动条样式 - 支持水平和垂直滚动 */
|
||
.table-wrapper {
|
||
scrollbar-width: thin;
|
||
scrollbar-color: #c1c1c1 #f1f1f1;
|
||
}
|
||
|
||
.table-wrapper::-webkit-scrollbar {
|
||
width: 8px;
|
||
height: 8px;
|
||
}
|
||
|
||
.table-wrapper::-webkit-scrollbar-track {
|
||
background: #f1f1f1;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.table-wrapper::-webkit-scrollbar-thumb {
|
||
background: #c1c1c1;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.table-wrapper::-webkit-scrollbar-thumb:hover {
|
||
background: #a8a8a8;
|
||
}
|
||
|
||
/* 确保表格可以水平滚动 */
|
||
.table-wrapper :deep(.el-table) {
|
||
min-width: 100%;
|
||
}
|
||
|
||
.table-wrapper :deep(.el-table__body-wrapper) {
|
||
overflow-x: auto;
|
||
}
|
||
|
||
/* 响应式设计 */
|
||
@media (max-width: 1200px) {
|
||
.filter-section :deep(.el-form) {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.package-management {
|
||
padding: 16px;
|
||
}
|
||
|
||
.filter-section,
|
||
.table-section,
|
||
.pagination-section {
|
||
padding: 16px;
|
||
}
|
||
|
||
.table-wrapper {
|
||
max-height: calc(100vh - 350px);
|
||
}
|
||
}
|
||
</style>
|
||
|