forked from gzt/A8000
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
690 lines
17 KiB
690 lines
17 KiB
<template>
|
|
<!-- 历史页面-->
|
|
<div id="history-container">
|
|
<!-- 筛选 -->
|
|
<!-- <div class="history-filter">
|
|
<div class="filter-input">
|
|
<el-input v-model="inputValue" placeholder="输入信息">
|
|
<template #prefix>
|
|
<el-icon class="el-input__icon">
|
|
<search />
|
|
</el-icon>
|
|
</template>
|
|
</el-input>
|
|
</div>
|
|
<div class="filter-button">
|
|
<el-button type="primary" class="search-button" @click="handleSearch" disabled>搜索</el-button>
|
|
<el-button class="reload-button" @click="handleReset">重置</el-button>
|
|
</div>
|
|
</div> -->
|
|
|
|
<!-- 表格 -->
|
|
<div class="history-table" @scroll="onScroll" ref="tableContainer">
|
|
<HistoryTable ref="historyTableRef" @selectItems="handleSelection" @selectIds="handleSelectIds"
|
|
@select-row="handleSelectRow" :tableData="tableData" :loading="loading" :key="tableKey"
|
|
:loadingText="loadingText" />
|
|
</div>
|
|
|
|
<!-- 功能 -->
|
|
<div class="history-function">
|
|
<el-button type="primary" plain @click="showActionConfirm('delete')">删除</el-button>
|
|
<el-button type="primary" plain @click="showActionConfirm('print')">打印</el-button>
|
|
<el-button type="primary" plain @click="showActionConfirm('export')">导出</el-button>
|
|
</div>
|
|
|
|
<!-- 确认操作弹框 -->
|
|
<HistoryWarn v-if="showModal" :icon="currentAction.icon" :message="currentAction.message"
|
|
:confirmText="currentAction.confirmText" :cancelText="currentAction.cancelText" @confirm="handleConfirm"
|
|
@cancel="handleCancel" />
|
|
|
|
<!-- 通知提示框 -->
|
|
<HistoryWarn v-if="showWarn" :message="warnMessage" :icon="warnIcon" @close="showWarn = false" />
|
|
<!-- 通用通知组件 -->
|
|
<HistoryWarn v-if="showWarn" :message="warnMessage" :icon="warnIcon" :confirmText="'关闭'" :showButtons="false"
|
|
@confirm="handleWarnClose" />
|
|
|
|
<HistoryMessage :isVisible="isVisible" @update:isVisible="isVisible = $event">
|
|
<div class="detail-container">
|
|
<div class="detail-section">
|
|
<div class="detail-item">
|
|
<span class="label">日期:</span>
|
|
<span class="value">{{ rowData && formatDate(rowData.creatDate) }}</span>
|
|
</div>
|
|
<div class="divider"></div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">样本id:</span>
|
|
<span class="value">{{ rowData && rowData.id }}</span>
|
|
</div>
|
|
<div class="divider"></div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">项目名称:</span>
|
|
<span class="value">{{ rowData && rowData.id }}</span>
|
|
</div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">Result:</span>
|
|
<span class="value">{{ rowData && JSON.stringify(rowData.results) }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="detail-section">
|
|
<div class="detail-item">
|
|
<span class="label">样本种类:</span>
|
|
<span class="value">{{ rowData && rowData.sampleBloodType }}</span>
|
|
|
|
</div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">操次:</span>
|
|
<span class="value">{{ rowData && rowData.lotId }}</span>
|
|
|
|
</div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">Rec:</span>
|
|
<span class="value">Record 1</span>
|
|
</div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">有效期:</span>
|
|
<span class="value">2024-12-31</span>
|
|
</div>
|
|
<div class="divider"></div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">操作人:</span>
|
|
<span class="value">John Doe</span>
|
|
</div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">序列号:</span>
|
|
<span class="value">SN12345</span>
|
|
</div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">App Ver:</span>
|
|
<span class="value">1.0.0</span>
|
|
</div>
|
|
|
|
<div class="detail-item">
|
|
<span class="label">F/W Ver:</span>
|
|
<span class="value">2.0.0</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="detail-footer">
|
|
<button class="confirm-btn" @click="handleClose">确认</button>
|
|
</div>
|
|
</div>
|
|
</HistoryMessage>
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { onMounted, ref } from 'vue'
|
|
import dayjs from 'dayjs'
|
|
import { HistoryTable, HistoryWarn } from './components/index'
|
|
import {
|
|
getHistoryInfo,
|
|
deleteHistoryInfo,
|
|
printHistoryInfo,
|
|
} from '../../services/Index/index'
|
|
import HistoryMessage from './components/History/HistoryMessage.vue'
|
|
import type { TableItem } from '../../types/Index'
|
|
import WarnSvg from '@/assets/Index/History/warn.svg'
|
|
import PrintSvg from '@/assets/Index/History/print.svg'
|
|
import ErrorSvg from '@/assets/Warn.svg'
|
|
import { eMessage } from './utils'
|
|
// 添加表格引用
|
|
const historyTableRef = ref()
|
|
|
|
//选中弹出框
|
|
const isVisible = ref<boolean>(false)
|
|
|
|
const handleClose = () => {
|
|
isVisible.value = false
|
|
}
|
|
// 绑定输入框的值
|
|
// const inputValue = ref<string>('')
|
|
|
|
// 选中的项目
|
|
const selectedItems = ref<TableItem[]>([])
|
|
|
|
// 控制弹框和通知的显示
|
|
const showModal = ref<boolean>(false)
|
|
const showWarn = ref<boolean>(false)
|
|
|
|
// 当前操作的图标和提示信息
|
|
const currentAction = ref<{
|
|
type: string
|
|
icon: string
|
|
message: string
|
|
confirmText: string
|
|
cancelText: string
|
|
}>({
|
|
type: '',
|
|
icon: '',
|
|
message: '',
|
|
confirmText: '',
|
|
cancelText: '',
|
|
})
|
|
|
|
// 通知消息
|
|
const warnMessage = ref<string>('')
|
|
// 未选择项目通知的图标
|
|
|
|
// 定义不同操作的图标和提示信息
|
|
const actions: Record<
|
|
string,
|
|
{
|
|
type: string
|
|
icon: string
|
|
message: string
|
|
confirmText: string
|
|
cancelText: string
|
|
}
|
|
> = {
|
|
delete: {
|
|
type: 'delete',
|
|
icon: WarnSvg,
|
|
message: '请确认是否删除所选项目',
|
|
confirmText: '确认删除',
|
|
cancelText: '取消',
|
|
},
|
|
print: {
|
|
type: 'print',
|
|
icon: PrintSvg,
|
|
message: '请确认是否打印所选项目',
|
|
confirmText: '确认打印',
|
|
cancelText: '取消',
|
|
},
|
|
export: {
|
|
type: 'export',
|
|
icon: WarnSvg,
|
|
message: '请确认是否导出所选项目',
|
|
confirmText: '确认导出',
|
|
cancelText: '取消',
|
|
},
|
|
}
|
|
const selectedIds = ref<number[]>([])
|
|
// 处理表格选中的项目
|
|
const handleSelection = (items: TableItem[]) => {
|
|
console.log(items)
|
|
selectedItems.value = items
|
|
}
|
|
const handleSelectIds = (ids: number[]) => {
|
|
selectedIds.value = ids
|
|
}
|
|
const rowData = ref<TableItem>()
|
|
const handleSelectRow = (item: TableItem) => {
|
|
isVisible.value = true
|
|
rowData.value = item
|
|
}
|
|
const formatDate = (date: string | number | Date) => {
|
|
return dayjs(date).format('YYYY-MM-DD')
|
|
}
|
|
|
|
// 根据操作类型显示不同的确认弹框或通知
|
|
const showActionConfirm = (actionType: string) => {
|
|
// 判断是否有选中的项目
|
|
if (selectedItems.value.length === 0) {
|
|
// 如果没有选中项目,弹出通知框
|
|
warnMessage.value = '请先选择项目'
|
|
showWarn.value = true
|
|
return
|
|
}
|
|
|
|
// 如果是删除操作,确认删除的数量
|
|
if (actionType === 'delete') {
|
|
currentAction.value = {
|
|
...actions[actionType],
|
|
message: `是否删除选中的 ${selectedItems.value.length} 条记录?`
|
|
}
|
|
} else {
|
|
currentAction.value = actions[actionType]
|
|
}
|
|
|
|
showModal.value = true
|
|
}
|
|
//控制骨架屏
|
|
const loading = ref(false)
|
|
// 获取表格数据
|
|
const tableData = ref<TableItem[]>([])
|
|
const currentPage = ref(1)
|
|
const pageSize = ref(20)
|
|
const total = ref(0)
|
|
const totalPage = ref(0)
|
|
const tableKey = ref(0)//控制重新渲染
|
|
const tableContainer = ref(null as HTMLElement | null)
|
|
const hasMore = ref(true)
|
|
const loadingText = ref("加载中...")
|
|
const getTableData = async (isReset: boolean = false) => {
|
|
if (isReset) {
|
|
// 重置数据和页码
|
|
tableData.value = []
|
|
currentPage.value = 1
|
|
hasMore.value = true
|
|
}
|
|
|
|
if (loading.value || !hasMore.value) return
|
|
loading.value = true
|
|
|
|
try {
|
|
const res = await getHistoryInfoApi()
|
|
if (currentPage.value > totalPage.value) {
|
|
hasMore.value = false
|
|
loadingText.value = "没有更多数据了"
|
|
} else {
|
|
tableData.value = [...tableData.value, ...res.data.list]
|
|
currentPage.value++;
|
|
loadingText.value = "加载中..."
|
|
}
|
|
} catch (error) {
|
|
console.error('获取数据失败', error)
|
|
loadingText.value = "加载失败,请重试"
|
|
} finally {
|
|
setTimeout(() => {
|
|
loading.value = false
|
|
}, 1000)
|
|
}
|
|
}
|
|
const getHistoryInfoApi = async () => {
|
|
const params = {
|
|
pageNum: currentPage.value,
|
|
pageSize: pageSize.value,
|
|
}
|
|
try {
|
|
const res = await getHistoryInfo(params)
|
|
total.value = res.data.total
|
|
totalPage.value = res.data.totalPage
|
|
return res
|
|
} catch (error) {
|
|
console.log("获取数据失败", error)
|
|
}
|
|
}
|
|
const onScroll = (event: any) => {
|
|
const container = event.target;
|
|
const isNearBottom = container.scrollHeight - container.scrollTop <= container.clientHeight + 100;
|
|
if (isNearBottom && !loading.value) {
|
|
getTableData()
|
|
}
|
|
}
|
|
|
|
|
|
// 搜索功能 暂时注释
|
|
// const handleSearch = async () => {
|
|
// console.log('搜索内容:', inputValue.value)
|
|
// try {
|
|
// const res = await searchHistoryInfo(inputValue.value)
|
|
// console.log(res.data.list)
|
|
// // 直接替换数据,不进行累加
|
|
// tableData.value = res.data.list as TableItem[]
|
|
// // 重置分页相关状态
|
|
// currentPage.value = 1
|
|
// hasMore.value = false
|
|
// } catch (error) {
|
|
// console.error('搜索失败', error)
|
|
// }
|
|
// }
|
|
|
|
// 确认操作时的回调函数
|
|
const handleConfirm = async () => {
|
|
showModal.value = false
|
|
showWarn.value = false
|
|
const actionType = currentAction.value.type
|
|
if (actionType === 'delete') {
|
|
await handleConfirmDelete()
|
|
} else if (actionType === 'print') {
|
|
// 执行打印操作
|
|
handlePrint()
|
|
} else if (actionType === 'export') {
|
|
// 执行导出操作
|
|
handleExport()
|
|
}
|
|
}
|
|
const handleWarnClose = () => {
|
|
getTableData()
|
|
showWarn.value = false
|
|
}
|
|
|
|
// 取消操作时的回调函数
|
|
const handleCancel = () => {
|
|
showModal.value = false
|
|
showWarn.value = false
|
|
}
|
|
|
|
// 处理删除确认
|
|
const handleConfirmDelete = async () => {
|
|
try {
|
|
// 一次删除一条记录
|
|
for (const item of selectedItems.value) {
|
|
const res = await deleteHistoryInfo(item.id)
|
|
if (!res.success) {
|
|
throw new Error('删除失败')
|
|
}
|
|
}
|
|
|
|
// 从表格数据中移除被删除的项目
|
|
const deleteIds = selectedItems.value.map(item => item.id)
|
|
tableData.value = tableData.value.filter(item => !deleteIds.includes(item.id))
|
|
|
|
// 通过表格组件清空选择状态
|
|
if (historyTableRef.value) {
|
|
historyTableRef.value.clearSelection()
|
|
}
|
|
|
|
eMessage.success('删除成功')
|
|
} catch (error) {
|
|
eMessage.error('删除失败')
|
|
} finally {
|
|
showModal.value = false
|
|
}
|
|
}
|
|
let warnIcon: any
|
|
// 打印功能
|
|
const handlePrint = async () => {
|
|
try {
|
|
if (selectedItems.value.length > 10) {
|
|
warnMessage.value = '一次最多只能打印 10 条记录'
|
|
warnIcon = new URL('@/assets/Index/History/warn.svg', import.meta.url).href
|
|
showWarn.value = true
|
|
return
|
|
}
|
|
|
|
const idsToPrint = selectedItems.value.map((item) => item.id)
|
|
for (const item of idsToPrint) {
|
|
const res = await printHistoryInfo(item)
|
|
if (res.success && res.ecode === "SUC") {
|
|
warnMessage.value = '打印成功'
|
|
warnIcon = new URL('@/assets/Index/History/success.svg', import.meta.url).href
|
|
showWarn.value = true
|
|
|
|
// 清空选中状态
|
|
selectedItems.value = []
|
|
selectedIds.value = []
|
|
// 手动清除表格的选中状态
|
|
if (historyTableRef.value?.clearSelection) {
|
|
historyTableRef.value.clearSelection()
|
|
}
|
|
} else {
|
|
throw new Error(res.message || '打印失败')
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('打印失败', error)
|
|
warnMessage.value = '打印失败,请重试'
|
|
warnIcon = ErrorSvg
|
|
showWarn.value = true
|
|
}
|
|
}
|
|
// 导出功能
|
|
const handleExport = () => {
|
|
// 执行导出操作
|
|
// 根据实际需求实现导出功能
|
|
console.log('导出项目:', selectedItems.value)
|
|
warnMessage.value = '导出成功'
|
|
showWarn.value = true
|
|
}
|
|
|
|
onMounted(() => {
|
|
getTableData()
|
|
})
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
:global(.custom-message) {
|
|
min-width: 380px !important;
|
|
padding: 16px 24px !important;
|
|
|
|
.el-message__content {
|
|
font-size: 24px !important;
|
|
line-height: 1.5 !important;
|
|
}
|
|
|
|
.el-message__icon {
|
|
font-size: 24px !important;
|
|
margin-right: 12px !important;
|
|
}
|
|
}
|
|
|
|
#history-container {
|
|
width: 100%;
|
|
height: 90vh;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background-color: #f5f7fa;
|
|
box-sizing: border-box;
|
|
|
|
.history-filter {
|
|
width: 100%;
|
|
height: 70px;
|
|
margin-bottom: 20px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
background-color: #fff;
|
|
border-radius: 10px;
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
|
|
.filter-input {
|
|
flex: 1;
|
|
max-width: 800px;
|
|
|
|
.el-input {
|
|
height: 50px;
|
|
font-size: 26px;
|
|
|
|
.el-input__wrapper {
|
|
border-radius: 25px;
|
|
padding: 0 20px;
|
|
box-shadow: 0 0 0 1px #dcdfe6;
|
|
|
|
&:hover {
|
|
box-shadow: 0 0 0 1px #409eff;
|
|
}
|
|
|
|
&.is-focus {
|
|
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);
|
|
}
|
|
}
|
|
|
|
.el-input__icon {
|
|
font-size: 26px;
|
|
color: #909399;
|
|
}
|
|
}
|
|
}
|
|
|
|
.filter-button {
|
|
display: flex;
|
|
|
|
.search-button,
|
|
.reload-button {
|
|
height: 50px;
|
|
border-radius: 25px;
|
|
font-size: 26px;
|
|
font-weight: 500;
|
|
transition: all 0.3s;
|
|
|
|
&:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
}
|
|
}
|
|
|
|
.search-button {
|
|
width: 200px;
|
|
|
|
&:disabled {
|
|
background-color: #a0cfff;
|
|
border-color: #a0cfff;
|
|
|
|
&:hover {
|
|
transform: none;
|
|
box-shadow: none;
|
|
}
|
|
}
|
|
}
|
|
|
|
.reload-button {
|
|
width: 90px;
|
|
color: #606266;
|
|
border: 1px solid #dcdfe6;
|
|
|
|
&:hover {
|
|
color: #409eff;
|
|
border-color: #c6e2ff;
|
|
background-color: #ecf5ff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.history-table {
|
|
flex: 1;
|
|
overflow-y: auto; // 只允许垂直滚动
|
|
overflow-x: hidden; // 禁止水平滚动
|
|
background-color: #fff;
|
|
border-radius: 10px;
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
margin: 0 20px;
|
|
padding: 20px;
|
|
position: relative;
|
|
|
|
// 优化滚动条样式
|
|
&::-webkit-scrollbar {
|
|
width: 6px;
|
|
height: 6px;
|
|
}
|
|
|
|
&::-webkit-scrollbar-thumb {
|
|
background: #c0c4cc;
|
|
border-radius: 3px;
|
|
|
|
&:hover {
|
|
background: #909399;
|
|
}
|
|
}
|
|
|
|
&::-webkit-scrollbar-track {
|
|
background: #f5f7fa;
|
|
}
|
|
|
|
// 添加表格容器阴影效果
|
|
&::after {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
height: 30px;
|
|
background: linear-gradient(to top, rgba(255, 255, 255, 0.9), transparent);
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
|
|
.history-function {
|
|
width: 100%;
|
|
height: 84px;
|
|
margin-top: 20px;
|
|
background-color: #fff;
|
|
box-shadow: 0 -2px 12px 0 rgba(0, 0, 0, 0.05);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: 20px;
|
|
|
|
.el-button {
|
|
height: 50px;
|
|
border-radius: 25px;
|
|
font-size: 26px;
|
|
font-weight: 500;
|
|
transition: all 0.3s;
|
|
|
|
&:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
&:nth-child(1) {
|
|
width: 215px;
|
|
}
|
|
|
|
&:nth-child(2),
|
|
&:nth-child(3) {
|
|
width: 392px;
|
|
}
|
|
|
|
&.is-plain {
|
|
background-color: #fff;
|
|
|
|
&:hover {
|
|
background-color: #ecf5ff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.detail-container {
|
|
.detail-section {
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.detail-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 16px 0;
|
|
font-size: 28px;
|
|
|
|
.label {
|
|
color: #606266;
|
|
min-width: 200px;
|
|
font-weight: 500;
|
|
}
|
|
|
|
.value {
|
|
color: #303133;
|
|
flex: 1;
|
|
word-break: break-all;
|
|
}
|
|
}
|
|
|
|
.divider {
|
|
height: 1px;
|
|
background-color: #ebeef5;
|
|
margin: 16px 0;
|
|
}
|
|
|
|
.detail-footer {
|
|
margin-top: 40px;
|
|
text-align: center;
|
|
|
|
.confirm-btn {
|
|
width: 90%;
|
|
height: 88px;
|
|
background-color: #409eff;
|
|
border: none;
|
|
border-radius: 44px;
|
|
color: white;
|
|
font-size: 32px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.3s;
|
|
|
|
&:hover {
|
|
background-color: #66b1ff;
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 4px 12px rgba(64, 158, 255, 0.4);
|
|
}
|
|
|
|
&:active {
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|