|
|
<template> <!-- 历史页面--> <div id="history-container"> <div class="table-box"> <el-table ref="tableRef" style="height: 100%" v-loading="loading" v-el-table-infinite-scroll="load" :infinite-scroll-disabled="disabled" :data="tableData" show-overflow-tooltip @row-click="rowClickHandle" @selection-change="handleSelection" header-cell-class-name="table-header" row-class-name="table-row"> <el-table-column type="selection"></el-table-column> <el-table-column type="index" label="序号" width="50"></el-table-column> <el-table-column prop="creatDate" label="日期" width="170"> <template #default="scope"> {{ formatDate(scope.row.creatDate) }} </template> </el-table-column> <el-table-column prop="sampleId" label="患者ID" ></el-table-column> <el-table-column prop="sampleBloodType" label="样本类型" width="100"> <template #default="scope"> {{ settingTubeStore.bloodTypeKeyMap[scope.row.sampleBloodType].name }} </template> </el-table-column> <el-table-column prop="lotId" label="批次" ></el-table-column> <el-table-column prop="results" label="结果" width="150px"> <template #default="scope"> <div v-for="(r, idx) in scope.row.results" :key="idx" v-html="showResult(r)" class="history-result"> </div> </template> </el-table-column> </el-table> </div> <div class="history-table-footer"> <el-button type="danger" size="large" class="history-btn" :disabled="!selectedItems.length" @click="showActionConfirm('delete')">删除</el-button> <el-button type="primary" size="large" :disabled="!selectedItems.length" @click="showActionConfirm('print')">打印</el-button> <el-button type="primary" size="large" :disabled="!selectedItems.length" @click="showActionConfirm('export')">导出LIS</el-button> <el-badge :value="badgeValue" class="item"> <el-button type="primary" size="large" @click="onRefresh">刷新</el-button> </el-badge> </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"> <p>序号:{{ rowIndex }}</p> <p class="date"> 日期:{{ rowData && formatDate(rowData.creatDate) }} </p> <p class="userid">患者ID:{{ rowData && rowData.sampleId }}</p> <p class="userid">记录ID:{{ rowData && rowData.id }}</p> <p class="projName">项目名称:{{ rowData && rowData.projName }}</p>
<ul> <li> 样本类型:{{ rowData && settingTubeStore.bloodTypeKeyMap[rowData.sampleBloodType].name }} </li> <li>批次:{{ rowData && rowData.lotId }}</li> <li>有效期:{{ rowData && formatDate(rowData.expiryDate) }}</li> <li>操作人:{{ rowData && rowData.operator }}</li> <li>App版本: {{ rowData && rowData.appVersion }}</li> <li>MCU版本: {{ rowData && rowData.mcuVersion }}</li> <li>SN:{{ rowData && rowData.sn }}</li> </ul>
<div v-if="rowData" class="result-group"> <p style="font-weight: 600">结果:</p>
<div class="result-sub" v-for="(r, idx) in rowData.results" :key="idx" > <div>{{ r.subProjName + ':' }}</div> <div class="result-success" v-if="r.status === 'SUCCESS'"> <div style="display: flex"> <div>单位:</div> <div class="res-unit" v-for="res in r.resultConverters" :key="res.uint" > <div class="uint-result">{{ res.uintstr}}</div> </div> </div> <div style="display: flex; margin-top: 5px;"> <div>结果:</div> <div class="res-unit" v-for="res in r.resultConverters" :key="res.uint" > <div class="uint-result">{{ (r.result * res.A + res.B).toFixed(2) }}</div> </div> </div> </div> <div class="result-error" v-else> <div>结果:错误</div> <div>错误信息:{{ r.errorInfo }}</div> </div> </div> </div> </div>
<div class="detail-footer"> <button class="confirm-btn" @click="handleClose">确认</button> </div> </div> </HistoryMessage> <ConfirmModal v-if="confirmVisible" :confirmInfo="confirmInfo"/> </div> </template>
<script setup lang="ts"> import { ref, watchEffect } from 'vue'
import { HistoryWarn } from './components/index' import { getHistoryInfo, deleteHistoryInfo, printHistoryInfo, exportRecordsToLIS, } from '@/services' import HistoryMessage from './components/History/HistoryMessage.vue' import type { ResultItem, 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' import dayjs from 'dayjs' import { useSettingTestTubeStore } from '@/store' import type { ElTable } from 'element-plus/es/components/table/src/table'; import { useSystemStore } from '@/store/modules/useSystemStore'
defineOptions({ name: 'HistoryPage', }) const systemStore = useSystemStore() const settingTubeStore = useSettingTestTubeStore() const tableRef = ref<ElTable | null>(null) const badgeValue = ref() const showResult = (t: ResultItem) => { if (t.status !== 'SUCCESS') { return '错误' } const unit1 = t.resultConverters[0] const html = `<div style="display: flex">
<div style="width: 54px; white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">${t.subProjName}:</div> <div>${(t.result * unit1.A + unit1.B).toFixed(2)}</div> <div>${unit1.uintstr}</div> </div>`
return html }
//选中弹出框
const isVisible = ref<boolean>(false) const rowIndex = ref(0) const handleClose = () => { isVisible.value = false }
// 选中的项目
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 handleSelection = (items: TableItem[]) => { selectedItems.value = items }
const rowData = ref<TableItem>() const rowClickHandle = (row: TableItem,) => { const index = tableData.value.findIndex(item => item === row) rowIndex.value = index + 1 isVisible.value = true rowData.value = row } const formatDate = (date: string | number | Date) => { return dayjs(date).format('YYYY-MM-DD HH:mm:ss') }
// 根据操作类型显示不同的确认弹框或通知
const confirmVisible = ref(false) const confirmInfo = ref({}) const showActionConfirm = (actionType: string) => { // 如果是删除操作,确认删除的数量
if (actionType === 'delete') { confirmVisible.value = true; confirmInfo.value = { title: '确认删除', message: '请确认是否删除选中的数据?', cancelText: '取消', confirmText: '确认', onCancel:()=>{ confirmVisible.value = false }, onConfirm:async()=>{ await handleConfirmDelete() confirmVisible.value = false } } } else { currentAction.value = actions[actionType] showModal.value = true } }
const onRefresh = () => { currentPage.value = 1 pageSize.value = 25 total.value = 0 totalPage.value = 0 tableData.value = [] disabled.value = false load() systemStore.clearReactionRecordList() }
//控制骨架屏
const loading = ref(false) // 获取表格数据
const tableData = ref<TableItem[]>([]) const currentPage = ref(1) const pageSize = ref(25) const total = ref(0) const totalPage = ref(0)
const disabled = ref(false) const load = () => { if (disabled.value) return; loading.value = true
getHistoryInfo({ pageNum: currentPage.value, pageSize: pageSize.value, }).then(async (res) => { currentPage.value++; total.value = res.data.total totalPage.value = res.data.totalPage tableData.value = tableData.value.concat(res.data.list) if (currentPage.value > totalPage.value) { disabled.value = true } systemStore.clearReactionRecordList() }).catch(() => { eMessage.error("获取数据失败") }).finally(() => { loading.value = false })
}
// 确认操作时的回调函数
const handleConfirm = async () => { showModal.value = false showWarn.value = false const actionType = currentAction.value.type if (actionType === 'delete') { await handleConfirmDelete() } else if (actionType === 'print') { // 执行打印操作
await handlePrint() } else if (actionType === 'export') { // 执行导出操作
await handleExport() } } const handleWarnClose = () => { showWarn.value = false }
// 取消操作时的回调函数
const handleCancel = () => { showModal.value = false showWarn.value = false }
// 处理删除确认
const handleConfirmDelete = async () => { const deleteIds = selectedItems.value.map((item) => item.id) deleteHistoryInfo(deleteIds.join(',')).then((res) => { if (res.success && res.ecode === 'SUC') { eMessage.success('删除成功') tableData.value = tableData.value.filter( (item) => !deleteIds.includes(item.id), ) onRefresh() }else { eMessage.error('删除失败') } }) } let warnIcon: any // 打印功能
const handlePrint = async () => { try { const idsToPrint = selectedItems.value.map((item) => item.id) const res = await printHistoryInfo(idsToPrint) if (res.success && res.ecode === 'SUC') { warnMessage.value = '打印成功' warnIcon = new URL('@/assets/Index/History/success.svg', import.meta.url) .href showWarn.value = true } else { eMessage.error(res.message || '打印失败') } } catch (error) { console.error('打印失败', error) warnMessage.value = '打印失败,请重试' warnIcon = ErrorSvg showWarn.value = true } } // 导出功能
const handleExport = async () => { try { const idsToPrint = selectedItems.value.map((item) => item.id) const res = await exportRecordsToLIS(idsToPrint) if (res.success && res.ecode === 'SUC') { warnMessage.value = '导出成功' warnIcon = new URL('@/assets/Index/History/success.svg', import.meta.url) .href showWarn.value = true } else { eMessage.error(res.message || '导出失败') } } catch (error) { console.error('导出失败', error) warnMessage.value = '导出失败,请重试' warnIcon = ErrorSvg showWarn.value = true } }
watchEffect(() => { if(systemStore.reactionRecordList && systemStore.reactionRecordList.length){ badgeValue.value = systemStore.reactionRecordList.length }else{ badgeValue.value = undefined } }) </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 { > * { box-sizing: border-box; } width: 100%; height: 100%; display: flex; flex-direction: column; background-color: #fff; padding: 20px 20px 0 20px; box-sizing: border-box; .table-box { height: calc(100% - 7rem); .el-table { font-size: 18px; } } .history-table-footer { height: 7rem; display: flex; align-items: center; justify-content: space-around; .el-button { width: 150px; height: 50px; font-size: 24px; } } }
.detail-container { .detail-section { margin-bottom: 24px; font-size: 22px; .projName { font-weight: 600; } .result-group { .result-sub { margin-bottom: 12px; } .result-success, .result-error { margin-left: 20px; } .result-success { margin-left: 10px; .uint-result{ width: 8rem; background: #e9e9e9; margin-left: 5px; text-align: center; padding: 0 10px; } } .result-error { color: red; } } }
.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); } } } } .history-result{ height: 3rem; display: flex; align-items: center; } :deep(.table-header) { height: 60px; } :deep(.table-row) { height: 60px; } </style>
|