2026-06-05 17:37:24 +08:00

1178 lines
35 KiB
Vue
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="tips">报告查询打印:{{ formatDict(queryParams.ksdh, 'DP') }}</div>
<div ref="compactForm">
<el-row :gutter="5" class="compact-form" v-show="showSearch">
<el-form :model="queryParams" ref="queryRef" label-width="100px" :rules="queryRules" style="width: 100%;">
<el-row>
<el-col :span="4">
<el-form-item label="开始时间:" prop="st">
<el-date-picker v-model="queryParams.st" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
@change="handletime" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="结束时间:" prop="et">
<el-date-picker v-model="queryParams.et" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
@change="handletime" style="width: 100%" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="打印状态:" prop="dybz">
<el-select v-model="queryParams.dybz" placeholder="请选择" clearable @change="handleQuery">
<el-option label="已打印" value="1" />
<el-option label="未打印" value="0" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="科室:" prop="ksdh">
<SelectTable v-model:data="queryParams.ksdh" :fields="ksdhFields" :tableData="dictData.DP || []"
label="label" value="value" objKey="value" placeholder="请选择科室" @getDataValue="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="病人类型:" prop="brlyname">
<SelectTable v-model:data="queryParams.brlyname" :fields="brlxFields" :tableData="dictData.PT || []"
label="label" value="label" objKey="label" placeholder="请选择" @getDataValue="handleQuery" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="4">
<el-form-item label="姓名:" prop="brxm">
<el-input v-model="queryParams.brxm" clearable placeholder="请输入姓名" @keyup.enter="handleQuery"
@clear="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="病人号:" prop="brdh">
<el-input v-model="queryParams.brdh" clearable placeholder="请输入病人号" @keyup.enter="handleQuery"
@clear="handleQuery" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="床号:" prop="ch">
<el-input v-model="queryParams.ch" clearable placeholder="请输入床号" @keyup.enter="handleQuery"
@clear="handleQuery" />
</el-form-item>
</el-col>
<el-form-item label-width="50px">
<el-checkbox v-model="queryParams.alarmflag" label="仅危急值" @change="alarmHandle" />
<el-checkbox v-model="queryParams.jzbz" label="仅急诊" @change="jzbzHandle" />
</el-form-item>
</el-row>
</el-form>
</el-row>
</div>
<el-row :gutter="10" class="mb8 mt10">
<el-col :span="1.5">
<el-button icon="search" type="primary" :size="aotuSize" @click="handleQuery">搜索</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Edit" :size="aotuSize" @click="selectStatusRows">勾选所有未打印</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="Upload" :size="aotuSize" @click="printPdf">打印报告</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" :size="aotuSize" plain @click="openDB">对比历史</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" :size="aotuSize" plain @click="getCDSS">CDSS</el-button>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="16" class="right-table sqd-box">
<CustomVxeTable :table-data="tableData" :loading="loading" :columns="columns" @current-change="rowHandle"
size="small" :scrollYConfig="{ enabled: true, rSize: 30, height: '100%', }" class="mytable-style"
ref="tableRefs" :row-style="rowClassNameHd" :cell-style="cellStyleHd" @selection-change="selectionChange"
:config="tableConfig" :enable-column-drag="true" @column-drag-end="handleColumnDragEnd">
<template #dybz="{ row }">
<svg-icon v-if="row.dybz == 1" icon-class="lvgou" />
</template>
<template #alarmflag="{ row }">
{{ row.alarmflag == 1 ? '危' : '' }}
</template>
<template #jzbz="{ row }">
{{ row.jzbz == 1 ? '急' : '' }}
</template>
</CustomVxeTable>
<div class="mask" :style="{ top: `${pageY}px` }">
<el-popover placement="left" :width="400" trigger="click">
<template #reference>
<div class="text">医嘱明细</div>
</template>
<el-table :data="sqlisReqs" style="width: 100%" border @row-click="sqxmClick" highlight-current-row
show-overflow-tooltip max-height="300px">
<el-table-column prop="sqh" label="申请单号" />
<el-table-column prop="bz1" label="医嘱号" />
<el-table-column prop="sqxmdh" label="项目代号" />
<el-table-column prop="sqxmmc" label="项目名称" />
</el-table>
</el-popover>
</div>
<div class="mt10">
<el-pagination background @size-change="handleSizeChange" @current-change="handleCurrentChange"
:size="aotuSize" :current-page="queryParams.pageNum" :page-sizes="[10, 20, 50, 100]"
:page-size="queryParams.pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total">
</el-pagination>
</div>
</el-col>
<el-col :span="8" class="right-table">
<div>
<ContextMenu :items="contextMenuItems" @select="handleMenuSelect" menu-width="120">
<CustomTable :data="rightTableData" :columns="rightColumns" :config="rightTableConfig"
@row-click="xmrowHandle" ref="rightTableRef">
<template #jgbz="{ row }">
{{ formatJgbz(row.jgbz) }}
</template>
<template #xmmc="{ row }">
<el-tooltip class="box-item" effect="dark" :content="row.clinicref" placement="top"
:popper-style="{ width: '320px', maxWidth: '320px' }" :disabled="!row.clinicref">
<span>{{ row.xmmc }}</span>
</el-tooltip>
</template>
</CustomTable>
</ContextMenu>
<div class="mt10" v-if="bottomTableData.length > 0"></div>
<div>
<CustomTable v-if="bottomTableData.length > 0" :data="bottomTableData" :columns="bottomColumns"
:config="bottomTableConfig">
</CustomTable>
</div>
<div v-if="bottomTableData.length > 0" class="expert-comment" :title="expertComment">
专家评语:{{ expertComment }}
</div>
</div>
</el-col>
</el-row>
<!-- 样本流程 -->
<div class="time-line-box">
<div v-for="(item, i) in timelineItems" :key="i" class="time-line-item">
<div v-if="i != 0" class="timeline-connector">
<img class="timg" src="@/assets/images/yjt.png" alt="">
</div>
<div :class="['timeline-content', i > lastTimeIndex ? 'no_active' : '']">
<div :class="['index', lastTimeIndex == i ? 'active' : '']">{{ i + 1 }}</div>
<div class="timeline-title">{{ item.title }}</div>
<div class="timeline-time">{{ item.time }}</div>
</div>
</div>
</div>
<!-- 结果对比 -->
<el-dialog v-model="dialogVisible" title="结果对比" draggable :close-on-click-modal="false">
<div class="flex-between">
</div>
<el-table ref="diaTableRef" :data="compareTableData" style="width: 100%" @row-click="handleRowClick"
highlight-current-row border height="350px">
<el-table-column prop="xmdh" label="项目编号" fixed align="center" width="150px" />
<el-table-column prop="xmmc" label="项目名称" fixed align="center" />
<template v-for="(period) in periods" :key="period">
<el-table-column :label="period" :prop="period" :width="150" align="center" />
</template>
</el-table>
<div ref="myEcharts" style="width:100%;height: 350px" />
</el-dialog>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, toRaw, computed, watch, nextTick, onMounted } from 'vue';
import CustomTable from '@/components/elTable/index.vue'
import CustomVxeTable from '@/components/vxeTable/index.vue'
import { useRouter } from 'vue-router'
import ContextMenu from "@/components/contextMenu/index.vue";
import { reportList, reportPrintPdf, reportResult, reportMedList, reportFsresult, getSQDDetailList, getCdssUrl } from '@/api/checkCode/index'
import dayjs from 'dayjs';
import SelectTable from '@/components/SelectTable/index.vue';
import { ElMessage, ElMessageBox } from 'element-plus'
import { classCom } from '@/utils/classCom'
import { ContextMenuItem } from '@/types/index'
import * as echarts from 'echarts';
import { comDict } from '@/utils/dict'
import { getDicts } from '@/api/system/dict/data'
import { usePrintStore } from '@/store/modules/printStore'
import useUserStore from '@/store/modules/user'
import { useRoute } from 'vue-router'
const route = useRoute()
const aotuSize = classCom.useAutoSize();
const userStore = useUserStore()
const compactForm = ref<HTMLElement | null>(null);
const lisReqs: any = ref([])
const dialogVisible = ref(false)
const tableRefs = ref()
const diaTableRef = ref()
const myEcharts = ref()
const options = ref([
{ label: '复制全部数据', value: 'All' },
{ label: '复制异常数据', value: 'N' },
{ label: '复制正常数据', value: 'Y' },
])
interface QueryParams {
st: string,
et: string,
alarmflag: boolean,
jzbz: boolean,
ksdh: string,
brlyname: string,
brxm: string,
brdh: string,
ch: string,
dybz: string,
sqh: string,
userid: string,
yljg: string,
pageNum: number,
pageSize: number,
}
// 提交表单数据
const queryParams = reactive<QueryParams>({
// times: ['2025-08-19', '2025-08-19'],
// ksdh: '0203',
st: '',
et: '',
ksdh: '0210',
brlyname: '',
sqh: '25080109476',
alarmflag: false,
jzbz: false,
brxm: '',
brdh: '',
ch: '',
dybz: '',
userid: '',
yljg: '',
pageNum: 1,
pageSize: 20,
});
const single = ref(true);
const multiple = ref(true);
const alarmflag = ref()
const jzbz = ref()
const showSearch = ref(true);
const queryRef = ref()
// 项目点击数据
const Info = ref<any>({})
// 定义校验规则
const queryRules = ref({
})
const handletime = (val: Array<string>) => {
// 校验日期格式
const dayDiff = getDayDiff(queryParams.st, queryParams.et);
if (dayDiff === -1 || dayDiff === -2) return ElMessage.warning('请选择有效的日期范围');
}
// 时间线数据
const timelineItems = ref(
[
{ title: '检验申请', time: '' },
{ title: '标本采集', time: '' },
{ title: '标本送检', time: '' },
{ title: '标本签收', time: '' },
{ title: '上机检验', time: '' },
{ title: '结果审核', time: '' },
]
);
// 计算最后一个有时间的节点索引
const lastTimeIndex = computed(() => {
const lastIndex = timelineItems.value.findLastIndex(item => item.time);
if (lastIndex === -1) {
return -1
} else {
return lastIndex;
}
});
const total = ref(0)
const handleQuery = async () => {
const valid = await queryRef.value.validate().catch(() => { });
if (!valid) return false;
getList()
}
// 重置
const resetQuery = () => {
queryRef.value?.resetFields();
getList()
}
const loading = ref(false);
// 勾选框数据
const rows = ref<any[]>([])
// 数据源
const tableData = ref([])
// 配置项
const columns = ref([
{ type: 'selection', field: '', title: '', resizable: true, align: 'center', width: 40 },
{ field: 'dybz', title: '印', align: 'center', resizable: true, slotName: 'dybz', width: 40 },
{ field: 'jzbz', title: '急', align: 'center', resizable: true, slotName: 'jzbz', width: 40 },
{ field: 'alarmflag', title: '危', align: 'center', resizable: true, slotName: 'alarmflag', width: 40 },
{ field: 'brdh', title: '病人代号', align: 'center', resizable: true, sortable: true, width: 100 },
{ field: 'brxm', title: '病人姓名', align: 'center', resizable: true, width: 60 },
{ field: 'brxbname', title: '性别', align: 'center', resizable: true, width: 40 },
{ field: 'ch', title: '床号', align: 'center', resizable: true, width: 50 },
{ field: 'sqh', title: '申请单号', align: 'center', resizable: true, width: 100 },
{ field: 'jymd', title: '检验目的', align: 'center', resizable: true, width: 200 },
{ field: 'yblxname', title: '样本类型', align: 'center', resizable: true, width: 60 },
{ field: 'sqsj', title: '送检时间', align: 'center', resizable: true, width: 150 },
{ field: 'confirmtime', title: '报告时间', align: 'center', resizable: true, sortable: true, width: 150 },
{ field: 'sjysname', title: '送检医生', align: 'center', resizable: true, width: 80 },
{ field: 'brlyname', title: '病人类型', align: 'center', resizable: true, width: 80 },
{ field: 'yljg', title: '医疗机构', align: 'center', resizable: true, width: 150 },
{ field: 'jyrqname', title: '检验日期', align: 'center', resizable: true, width: 100 },
{ field: 'ybh', title: '样本号', align: 'center', resizable: true, width: 60 },
{ field: 'yqmc', title: '仪器名称', align: 'center', resizable: true, width: 150 },
{ field: 'yqdl', title: '仪器', align: 'center', resizable: true, width: 100 },
])
const selectionChange = (selection: any) => {
rows.value = selection
single.value = selection.length != 1;
multiple.value = !selection.length;
}
const pageY = ref(0)
const sqlisReqs = ref([])
const rightTableRef = ref()
const rowHandle = (row, $rowIndex, column, $columnIndex, cell, $event) => {
pageY.value = $event?.pageY - 200 || 0
if (row.yqdl == '细菌仪') {
rightColumns.value[1].visible = false
rightColumns.value[2].visible = true
rightColumns.value[4].visible = false
rightColumns.value[5].visible = false
rightColumns.value[6].visible = true
} else {
rightColumns.value[1].visible = true
rightColumns.value[2].visible = false
rightColumns.value[4].visible = true
rightColumns.value[5].visible = true
rightColumns.value[6].visible = false
}
timelineItems.value =
[
{ title: '检验申请', time: row.sqsj },
{ title: '标本采集', time: row.cysj },
{ title: '标本送检', time: row.bbsjsj },
{ title: '标本签收', time: row.jssj },
{ title: '上机检验', time: row.sjsj },
{ title: '结果审核', time: row.confirmtime },
]
Info.value = row
getxmmxList(row)
getSQDDetailList({ sqh: row.sqh }).then((res: any) => {
if (res.code == 0) {
sqlisReqs.value = res.data
}
})
}
const getxmmxList = (row) => {
const data = {
jyrq: row.jyrq,
yq: row.yq,
ybh: row.ybh,
sqxmdh: row.sqxmdh
}
reportResult(data).then((res: any) => {
if (res.code == 0) {
rightTableData.value = res.data
if (res.data.length) {
nextTick(() => {
rightTableRef.value.setCurrentRow(res.data[0])
})
xmrowHandle(res.data[0])
} else {
bottomTableData.value = []
}
}
})
}
const sqxmClick = (row) => {
getxmmxList({ ...Info.value, ...row })
}
const handleColumnDragEnd = (newColumns: any) => {
columns.value = [];
// 使用nextTick确保DOM更新后再设置新值
nextTick(() => {
columns.value = [...newColumns.columns];
});
}
// 打印单张Pdf
const printPdf = () => {
const printStore = usePrintStore();
const selections = tableRefs.value.allSelection()
if (selections.length <= 0) return ElMessage.warning('请选择要打印的数据!')
const arr = [...new Set(selections.map((item: any) => { return item.brdh }))]
if (arr.length > 1) return ElMessage.warning('只能选中一个病人的报告单打印!')
const merge = selections.map((item: any) => { return `${item.jyrqname.replace(/-/g, '')}_${item.yq.trim()}_${item.ybh}` })
reportPrintPdf(merge).then((res: any) => {
if (res.code == 0) {
if (!res.data) return ElMessage.warning('未找到打印文件')
classCom.printBase64PDF(res.data)
// if (printStore.isConnected) {
// HiprintPrinter.silentPrint([res.data])
// } else {
// classCom.printBase64PDF(res.data)
// }
} else {
ElMessage.warning(res.msg)
}
})
}
// 单元格样式
const cellStyleHd = ({ row, column, rowIndex, columnIndex }: {
row: any;
column: any;
rowIndex: number;
columnIndex: number;
}) => {
// // console.log(row, column, rowIndex, columnIndex);
// if (column.title == "急" && row.jzbz == "1") {
// return { color: '#f00' };
// }
// if (column.title == "危" && row.alarmflag == "1") {
// return { color: '#f00' };
// }
};
const rowClassNameHd = ({ row, rowIndex }: {
row: any;
rowIndex: number;
}) => {
// 最高优先级:警告/异常
if (row.jzbz == "1" || row.alarmflag == "1") {
return {
backgroundColor: '#f00 !important',
color: '#000 !important',
};
}
if (row.jgbz == '2') {
return { background: '#C0FFC0 !important' };
}
if (row.dybz == '1') {
return { background: '#C0C0C0 !important' };
}
return 'custom-row-class'; // 返回自定义类名
};
// 表格配置
const tableConfig = ref({
height: '71vh', // 高度
// 复选框配置
checkboxConfig: {
// 可选配置项
checkField: 'checked', // 绑定数据中的字段(默认:checked)
range: false, // 是否支持范围选择(按住 Shift 连续选择)
disabled: false, // 是否禁用全部复选框
reserve: false, // 是否保留勾选状态(分页/筛选时)
highlight: false // 是否高亮选中行
}
})
// 勾选未打印
const selectStatusRows = () => {
tableData.value.forEach((item: any) => {
if (item.dybz != 1) {
tableRefs.value.toggleRowSelection(item, true)
} else {
tableRefs.value.toggleRowSelection(item, false)
}
})
}
const alarmHandle = (val: boolean) => {
if (val) {
queryParams.jzbz = false
alarmflag.value = '1'
jzbz.value = null
} else {
alarmflag.value = null
}
getList()
}
const jzbzHandle = (val: boolean) => {
if (val) {
queryParams.alarmflag = false
alarmflag.value = null
jzbz.value = '1'
} else {
jzbz.value = null
}
getList()
}
interface ColumnItem {
prop: string;
label: string;
visible: boolean;
key: number;
align?: string;
slot?: string;
width?: string | number;
sortable?: boolean;
type?: string;
}
// 更新列
const updateColumns = (arr: any[]) => {
columns.value = arr
};
const ksdhFields = ref([
{ prop: 'value', label: '代号', width: 80, enablePinyinSearch: true },
{ prop: 'label', label: '名称', enablePinyinSearch: true },
])
const brlxFields = ref([
{ prop: 'value', label: '代号', width: 80, enablePinyinSearch: true },
{ prop: 'label', label: '名称', enablePinyinSearch: true },
])
// 右侧数据源
const rightTableData = ref([])
// 配置项
const rightColumns = ref([
{ prop: 'xmdh', label: '项目代号', align: 'center', visible: true, },
{ prop: 'xmmc', label: '项目名称', align: 'center', visible: true, slot: 'xmmc' },
{ prop: 'xmmc', label: '培养结果', align: 'center', visible: true, width: 150 },
{ prop: 'csjg', label: '检验结果', align: 'center', visible: true, },
{ prop: 'refs', label: '参考值', align: 'center', visible: true, },
{ prop: 'dw', label: '单位', align: 'center', visible: true, },
{ prop: 'od', label: '菌落计数', align: 'center', visible: true, },
// { prop: 'jgbz', label: '结果标志', align: 'center', visible: true, slot: 'jgbz' },
])
const rightCellStyleHd = ({ row, column, rowIndex, columnIndex }: {
row: any;
column: any;
rowIndex: number;
columnIndex: number;
}) => {
if (column.label == "检验结果" && (row.alarm_flag ?? "").trim().length > 0) {
return { background: '#f00 !important', color: '#FFF' };
}
if (column.label == "检验结果" && row.jgbz == "H") {
return { background: '#ffc0c0 !important', color: '#606266' };
}
if (column.label == "检验结果" && row.jgbz == "L") {
return { background: '#8080ff !important', color: '#fff' };
}
if (column.label == "检验结果" && row.jgbz == "P") {
return { background: '#ffc0c0 !important', color: '#606266' };
}
if (column.label == "检验结果" && row.jgbz == "Q") {
return { background: '#ffff80 !important', color: '#606266' };
}
};
// 表格配置
const rightTableConfig = ref(
{
// stripe: true, // 斑马纹
border: true, // 边框
height: '68vh', // 高度
highlightCurrentRow: true, // 高亮当前行
cellStyle: rightCellStyleHd
}
)
const contextMenuItems = computed<ContextMenuItem[]>(() => [
{ label: '复制全部数据', action: 'All' },
{ label: '复制异常数据', action: 'N' },
{ label: '复制正常数据', action: 'Y' },
]);
const handleMenuSelect = ((item: ContextMenuItem) => {
copyData(item.action)
})
const formatJgbz = (v: string) => {
const jgbzMap = {
'H': '高',
'L': '低',
'N': '阴性',
'P': '阳性',
'Q': '弱阳性',
'M': '正常'
};
return jgbzMap[v as keyof typeof jgbzMap] ?? '';
}
const expertComment = ref('')
const xmRow = ref<any>({})
// 查询抗生素
const xmrowHandle = (row: any) => {
xmRow.value = row
expertComment.value = row?.textresult || ''
const data = {
jyrq: Info.value.jyrq,
yq: Info.value.yq,
ybh: Info.value.ybh,
xmdh: row.xmdh
}
reportMedList(data).then((res: any) => {
if (res.code == 200) {
bottomTableData.value = res.rows
if (res.rows.length > 0) {
nextTick(() => {
rightTableConfig.value.height = `25vh`
rightTableRef.value?.doLayout && rightTableRef.value.doLayout();
});
} else {
nextTick(() => {
rightTableConfig.value.height = `68vh`
rightTableRef.value?.doLayout && rightTableRef.value.doLayout();
});
}
}
})
}
const periods = ref<string[]>([])
const compareTableData = ref([])
// 历史数据对比
const openDB = () => {
// 00507620
compareTableData.value = []
if (!xmRow.value.xmdh) return ElMessage.error('至少选择一条数据进行对比')
const data = {
brdh: Info.value.brdh,
xmdh: xmRow.value.xmdh
}
reportFsresult(data).then((res: any) => {
periods.value = []
if (res.code == 0) {
const arr: string[] = res.data.map((item: any) => item.confirmdt);
periods.value = [...new Set(arr)];
res.data.forEach((v: any) => {
arr.forEach((item: any) => {
if (item == v.confirmdt) {
v[item] = v.csjg
}
})
});
// @ts-ignore 忽略重组数据动态时间key
compareTableData.value = formatGroupedData(res.data)
dialogVisible.value = true
nextTick(() => {
diaTableRef.value.setCurrentRow(compareTableData.value[0])
handleRowClick(compareTableData.value[0])
})
}
})
}
const getCDSS = () => {
const data = {
msg: Info.value.sqh,
userId: queryParams.userid,
yljg: queryParams.yljg
}
getCdssUrl(data).then((res) => {
if (res.data) {
window.open(res.data)
}
})
}
interface copyItem {
xmdh: string;
xmmc: string;
csjg: string | number;
refs: string | number;
dw: string;
jgbz: string;
od: string;
}
// 复制函数
const copyData = (type: string | undefined) => {
let str = '';
// 处理空值的工具函数:null/undefined/空字符串都返回空白
const getFieldValue = (value: any) => {
if (value === null || value === undefined || value === '') {
return '';
}
// 转换为字符串,避免数字等类型直接拼接
return String(value);
};
// 根据设备类型定义不同的字段拼接逻辑
const getCommonRow = Info.value.yqdl === '细菌仪'
? (item: copyItem) => `${getFieldValue(item.xmdh)}\t${getFieldValue(item.xmmc)}\t${getFieldValue(item.csjg)}\t${getFieldValue(item.od)}\t\r\n`
: (item: copyItem) => `${getFieldValue(item.xmdh)}\t${getFieldValue(item.xmmc)}\t${getFieldValue(item.csjg)}\t${getFieldValue(item.refs)}\t${getFieldValue(item.dw)}\t\r\n`;
// 遍历数据拼接内容
rightTableData.value.forEach((v: any) => {
// 根据类型过滤数据
if (type === 'All' ||
(type === 'N' && v.jgbz !== 'M' && v.jgbz !== '') ||
(type === 'Y' && v.jgbz === 'M')) {
str += getCommonRow(v);
}
});
// 执行复制操作
const input = document.createElement('textarea');
if (!str) {
ElMessage.error('没有数据可复制');
return;
}
input.value = str;
document.body.appendChild(input);
input.select();
const copyResult = document.execCommand('copy');
copyResult ? ElMessage.success('复制成功') : ElMessage.error('复制失败');
document.body.removeChild(input);
};
// 数据重组
const formatGroupedData = (data: any[]) => {
if (!data || data.length === 0) return [];
const groupMap: any = {};
data.forEach(item => {
const key = item.xmdh;
if (!groupMap[key]) {
groupMap[key] = {
xmdh: item.xmdh,
xmmc: item.xmmc,
// confirmdt: item.confirmdt
};
}
const dateKeys = Object.keys(item).filter(key =>
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(key) // 匹配 YYYY-MM-DD HH:mm:ss 时间格式
);
// 将日期键值对添加到分组对象
dateKeys.forEach(dateKey => {
groupMap[key][dateKey] = item[dateKey];
});
});
// 将 Map 转为数组
return Object.values(groupMap);
};
const handleRowClick = (row: any) => {
getEcharts(row)
}
const getEcharts = (data: any) => {
const dateKeys = Object.keys(data).filter(key =>
/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(key)
);
const Intance = echarts.init(myEcharts.value);
const xData = dateKeys;
let seriesData = []
seriesData = dateKeys.map(item => data[item]);
const option = {
title: {
text: data.xmmc,
top: '5',
right: '5%',
left: '20',
// bottom: '20%'
// subtext: 'Feature Sample: Gradient Color, Shadow, Click Zoom'
},
tooltip: {
trigger: 'axis'
},
grid: {
top: '20%',
left: '3%',
right: '4%',
// bottom: '3%',
height: '80%',
containLabel: true
},
xAxis: {
type: 'category',
data: xData,
axisTick: {
show: false
},
axisLine: {
lineStyle: {
// color: 'rgba(193, 207, 220, 1)',
}
},
axisLabel: {
rotate: 30,
textStyle: {
color: "#8D949B "
}
},
},
yAxis: [{
// name: '单位(mm)',
type: 'value',
axisLabel: {
textStyle: {
color: "#8D949B"
},
// formatter: '{value}%'
},
axisLine: {
show: false,
lineStyle: {
color: '#24abf2'
}
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed'
},
},
}
],
series: [{
name: data.xmmc,
type: 'line',
data: seriesData,
symbol: 'circle',
symbolSize: 5, //标记的大小
lineStyle: {
normal: {
width: 2,
color: '#24abf2',
}
},
itemStyle: {
normal: {
color: '#24abf2',
}
},
smooth: true
}
]
};
Intance.setOption(option);
}
// 右侧数据源
const bottomTableData = ref([])
// 配置项
const bottomColumns = ref([
{ prop: 'ywdh', label: '抗生素代码', align: 'center', visible: true, },
{ prop: 'ywmc', label: '抗生素名称', align: 'center', width: 200, visible: true, },
{ prop: 'mic', label: 'MIC', align: 'center', visible: true },
{ prop: 'rad', label: 'KB', align: 'center', visible: true },
{ prop: 'csjg', label: '药敏结果', align: 'center', visible: true },
])
const botCellStyleHd = ({ row, column, rowIndex, columnIndex }: {
row: any;
column: any;
rowIndex: number;
columnIndex: number;
}) => {
if (column.label == '药敏结果' && row.jgbz == 'R') {
return { background: '#ffc0c0 !important', color: '#606266' };
}
if (column.label == '药敏结果' && row.jgbz.trim() == "") {
return { background: '#ffff80 !important', color: '#606266' };
}
}
// 表格配置
const bottomTableConfig = ref(
{
// stripe: true, // 斑马纹
border: true, // 边框
height: '37vh', // 高度
highlightCurrentRow: true, // 高亮当前行
cellStyle: botCellStyleHd
}
)
interface DictData {
DP?: Array<any>;
PT?: Array<any>;
[key: string]: any[] | undefined; // 添加索引签名以支持动态访问
}
// 字典数据存储
const dictData = ref<DictData>({});
onMounted(async () => {
// 获取当前日期(当天)
const today = dayjs();
// 计算前6天的日期(当天 + 前6天 = 7天)
const startOfWeek = today.subtract(6, 'day');
queryParams.st = route.query.startdate ? String(route.query.startdate) : startOfWeek.format('YYYY-MM-DD');
queryParams.et = route.query.endate ? String(route.query.endate) : today.format('YYYY-MM-DD');
// queryParams.st = '2025-08-07'
// queryParams.et = '2025-08-14'
queryParams.ksdh = (route.query.deptcode as string) ? (route.query.deptcode as string) : '';
queryParams.userid = (route.query.userid as string) ? (route.query.userid as string) : '';
queryParams.brdh = (route.query.brdh as string) ? (route.query.brdh as string) : '';
queryParams.yljg = (route.query.yljg as string) ? (route.query.yljg as string) : '1';
// 进入页面单点登录
const result = await userStore.loginAnonymous({ name: queryParams.userid, yljg: queryParams.yljg })
if (result) {
// 获取状态字典
getDicts('lis_req_type').then((resp: any) => {
lisReqs.value = resp.data.map((p: any) => ({
label: p.dictLabel,
value: p.dictValue,
elTagType: p.listClass,
elTagClass: p.cssClass
}))
})
getList()
}
// 加载病人来源字典
const dictRefs = await comDict('PT', 'DP');
// 从 ref 中获取实际数据
dictData.value = {
PT: toRaw(dictRefs.PT.value) || [],
DP: toRaw(dictRefs.DP.value) || [],
};
});
const formatDict = (v: string, dictType: string) => {
return dictData.value[dictType]?.find((item: any) => item.value == v)?.label || v;
};
// 计算两个日期的天数差(支持带时分秒)
const getDayDiff = (start: string, end: string): number => {
const startTime = new Date(start).getTime();
const endTime = new Date(end).getTime();
if (isNaN(startTime) || isNaN(endTime)) {
return -2; // -2 表示日期无效
}
const dayDiff = Math.ceil((endTime - startTime) / (24 * 60 * 60 * 1000));
return dayDiff < 0 ? -1 : dayDiff; // -1 表示结束时间早于开始时间,>=0 为正常天数
};
const handleSizeChange = (size: number) => {
pageY.value = 0
queryParams.pageSize = size
getList()
}
const handleCurrentChange = (val: number) => {
pageY.value = 0
queryParams.pageNum = val
getList()
};
const getList = () => {
const data = {
alarmflag: alarmflag.value,
jzbz: jzbz.value,
dybz: queryParams.dybz,
ksdh: queryParams.ksdh,
brlyname: queryParams.brlyname,
brxm: queryParams.brxm,
brdh: queryParams.brdh,
ch: queryParams.ch,
userid: queryParams.userid,
st: queryParams.st,
et: queryParams.et,
yljg: queryParams.yljg,
pageNum: queryParams.pageNum,
pageSize: queryParams.pageSize
}
if (!data.ksdh) return ElMessage.error('科室代号不能为空');
if (!data.yljg) return ElMessage.error('医疗机构yljg不能为空');
if (!data.userid) return ElMessage.error('用户userid不能为空');
// 校验日期格式
const dayDiff = getDayDiff(queryParams.st, queryParams.et);
if (dayDiff === -1 || dayDiff === -2) return ElMessage.warning('请选择有效的日期范围');
loading.value = true
reportList(data).then((res: any) => {
if (res.code == 200) {
loading.value = false
tableData.value = res.rows
total.value = res.total
if (res.rows.length > 0) {
tableRefs.value.setCurrentRow(res.rows[0])
rowHandle(res.rows[0])
} else {
rightTableData.value = []
bottomTableData.value = []
}
}
})
}
</script>
<style scoped lang="scss">
.mytable-style {
height: 64vh;
}
.tips {
font-family: SourceHanSansCN, SourceHanSansCN;
font-size: 1rem;
color: #409eff;
font-weight: 600;
margin-bottom: 5px;
}
.compact-form {
border-bottom: 1px solid #E1E9F7;
.el-form-item {
margin-bottom: .625rem;
}
}
.title {
border-bottom: 1px solid #E1E9F7;
margin-bottom: .625rem;
padding: .625rem;
font-weight: 700;
}
.time-line-box {
display: flex;
justify-content: space-around;
align-items: center;
margin-top: .625rem;
background-color: #f0f3f8;
padding: .3rem 2.5rem;
}
.time-line-item {
display: flex;
align-items: center;
justify-content: space-around;
width: 16.6%;
// padding: 0 30px;
.timeline-content {
display: flex;
flex-direction: column;
align-items: center;
.index {
width: 1.875rem;
height: 1.875rem;
line-height: 1.875rem;
background: #E1E9F7;
border-radius: 50%;
text-align: center;
font-family: SourceHanSansCN, SourceHanSansCN;
font-weight: 500;
font-size: 1.125rem;
color: #4767A3;
}
.active {
background-color: #4096ff;
box-shadow: 0 0 0 .25rem rgba(64, 150, 255, 0.2);
color: #FFF;
}
.timeline-title {
font-family: SourceHanSansCN, SourceHanSansCN;
font-weight: 500;
font-size: 1rem;
color: #4767A3;
}
.timeline-time {
font-family: SourceHanSansCN, SourceHanSansCN;
font-weight: 400;
font-size: .875rem;
color: #4767A3;
}
}
.timg {
width: 3.125rem;
}
}
:deep(.el-form-item--default) {
margin-bottom: 1.125rem;
}
.expert-comment {
/* 限制最大显示行数为2行 */
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
/* 超出部分隐藏 */
overflow: hidden;
/* 可选:设置行高和最大宽度,优化显示效果 */
line-height: 1.3;
/* 行高,根据字体大小调整 */
max-width: 100%;
pointer-events: auto;
/* 允许鼠标交互 */
cursor: default;
font-size: .875rem;
margin-top: .3125rem;
}
.sqd-box {
position: relative;
.mask {
position: absolute;
right: -5px;
top: 40%;
cursor: pointer;
.text {
width: 18px;
padding: 8px 2px;
text-align: center;
color: #FFF;
font-size: 12px;
background-color: #4096ff;
border-radius: 0 4px 4px 0;
}
}
}
</style>