统计查询

This commit is contained in:
wyuu 2026-03-02 18:01:54 +08:00
parent 20c663592d
commit a3a75276ca
6 changed files with 559 additions and 20 deletions

View File

@ -340,6 +340,7 @@
}
.mytable-style {
.vxe-header--column {
word-break: break-word;
background-color: #1F6DD3 !important;
@ -359,7 +360,9 @@
padding: 0 !important;
}
.vxe-table--render-default .vxe-body--column {
.vxe-table--render-default .vxe-body--column,
.vxe-footer--column,
.col--ellipsis {
height: 1.875rem !important;
line-height: 1.875rem !important;
}

View File

@ -58,6 +58,7 @@ import { ElEmpty } from 'element-plus';
import { comDict } from '@/utils/dict'
import { getoptionselect } from '@/api/liswork/xtwh/localconfigApi'
import { Emits, Props } from '@/types';
import { getOptionSelect } from '@/hooks'
const props = withDefaults(defineProps<Props>(), {
placeholder: "请选择",
@ -175,6 +176,8 @@ const initData = async () => {
}));
dictRefs[props.dictType] = { value: dictList };
getOptionSelect(props.dictType, dictList);
} else {
dictRefs = await comDict(props.dictType);
}

View File

@ -39,6 +39,11 @@ export const formatDict = (v: string, dictType: string) => {
);
};
// 通用接口获取的字典数据赋值方法
export const getOptionSelect = (dictType: string, list: any[]) => {
dictData.value[dictType] = list || [];
};
//仪器格式化方法
export const formatInstr = (v: string) => {
return instrOptions.value.find((item: any) => item.yq == v.trim())?.yqmc || v;

View File

@ -0,0 +1,304 @@
<template>
<div class="labpat_box">
<el-form :model="labPat" label-width="70px" class="compact-form" label-position="right">
<el-form-item label="病人来源">
<el-col :span="14">
<SelectTable v-model:data="labPat.brly" :fields="brlyFields" dict-type="PT" placeholder="请选择" size="small"
@getDataValue="handleFieldChange" />
</el-col>
<el-col :span="10">
<el-switch v-model="labPat.jzbz" active-text="急诊" active-color="#FD0101" active-value="1" inactive-value="0"
@change="handleFieldChange"></el-switch>
</el-col>
</el-form-item>
<el-form-item label="病 历 号">
<el-input v-model="labPat.brdh" placeholder="请输入病历号" @change="handleFieldChange" size="small" />
</el-form-item>
<el-form-item label="姓 名">
<el-input v-model="labPat.brxm" placeholder="请输入姓名" @change="handleFieldChange" size="small" />
</el-form-item>
<el-form-item label="性 别">
<SelectTable v-model:data="labPat.brxb" dict-type="SX" placeholder="请选择" size="small"
@getDataValue="handleFieldChange" />
</el-form-item>
<el-form-item label="年龄">
<el-row :gutter="5">
<el-col :span="14">
<el-input v-model="labPat.nl" placeholder="年龄" @change="handleFieldChange" style="width:100%"
size="small" />
</el-col>
<el-col :span="10">
<SelectTable v-model:data="labPat.nldw" dict-type="AU" placeholder="请选择" size="small"
@getDataValue="handleFieldChange" />
</el-col>
</el-row>
</el-form-item>
<el-form-item label="送检科室">
<SelectTable v-model:data="labPat.ksdh" dict-type="DP" placeholder="请选择" size="small"
@getDataValue="handleFieldChange" />
</el-form-item>
<el-form-item label="床 号">
<el-input v-model="labPat.ch" placeholder="请输入床号" @change="handleFieldChange" size="small" />
</el-form-item>
<el-form-item label="样本类型">
<SelectTable v-model:data="labPat.yblx" dict-type="BT" placeholder="请选择" size="small"
@getDataValue="handleFieldChange" />
</el-form-item>
<el-form-item label="申请医生">
<SelectTable v-model:data="labPat.sjys" dict-type="SRD" placeholder="请选择" size="small"
@getDataValue="handleFieldChange" />
</el-form-item>
<el-form-item label="上机时间">
<el-date-picker v-model="labPat.sqsj" type="datetime" placeholder="上机时间" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" @change="handleFieldChange" size="small" style="width: 100%;" />
</el-form-item>
<el-form-item label="采样时间">
<el-date-picker v-model="labPat.cyrq" type="datetime" placeholder="采样时间" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" @change="handleFieldChange" size="small" style="width: 100%;" />
</el-form-item>
<el-form-item label="报告时间">
<el-date-picker v-model="labPat.dysj" type="datetime" placeholder="报告时间" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" @change="handleFieldChange" size="small" style="width: 100%;" />
</el-form-item>
<el-form-item label="临床诊断">
<el-input v-model="labPat.zd" placeholder="请输入临床诊断" @change="handleFieldChange" size="small" />
</el-form-item>
<el-form-item label="备 注">
<el-input v-model="labPat.bz" placeholder="请输入备注" @change="handleFieldChange" size="small" />
</el-form-item>
<el-form-item label="检验医生">
<SelectTable v-model:data="labPat.yhdh" :fields="ysFields" :tableData="userList || []" label="nickName"
value="userName" objKey="userName" :border="true" placeholder="请选择" size="small"
@getDataValue="handleFieldChange" />
</el-form-item>
<el-form-item label="审核医生">
<SelectTable v-model:data="labPat.hdys" :fields="ysFields" :tableData="userList || []" label="nickName"
value="userName" objKey="userName" :border="true" placeholder="请选择" size="small"
@getDataValue="handleFieldChange" />
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, watch, toRaw, computed, onMounted } from 'vue';
import { changepatcolumn, updateLabPat } from "@/api/liswork/work/LisWork";
import SelectTable from '@/components/SelectTable/index.vue';
// @ts-ignore
import { listUser } from '@/api/system/user.js'
const props = defineProps({
labPat: {
type: Object,
required: true
},
//结果主键
labPatKey: {
type: Object,
default: () => { }
},
dictData: {
type: Object,
default: () => { }
}
});
const lastJgbz = ref();
watch(() => props.labPat, (newVal) => {
lastValue.value = JSON.stringify(newVal);
lastJgbz.value = newVal.jgbz;
})
const emit = defineEmits(['update:labPat']);
const lastValue = ref('');
const brlyFields = ref([
{ prop: 'value', label: '代号', width: 80, enablePinyinSearch: true },
{ prop: 'label', label: '名称', width: 120, enablePinyinSearch: true },
])
const ksdhFields = ref([
{ prop: 'value', label: '代号', width: 80, enablePinyinSearch: true },
{ prop: 'label', label: '名称', width: 150, enablePinyinSearch: true },
])
const ysFields = ref([
{ prop: 'userName', label: '用户代号', width: 80, enablePinyinSearch: true },
{ prop: 'nickName', label: '用户姓名', width: 150, enablePinyinSearch: true },
])
/**
* 通用字段变化处理(失焦、回车触发)
*/
const handleFieldChange = async () => {
// 将当前labPat转为字符串用于比较
const currentValue = JSON.stringify(props.labPat);
// 对比与上一次保存的值是否有变化
if (currentValue !== lastValue.value) {
// 找出变化的字段
const oldObj = JSON.parse(lastValue.value);
const newObj = props.labPat;
const changedField = getChangedField(oldObj, newObj);
if (changedField) {
// 这里可以添加实际的更新逻辑,比如调用接口
try {
// if (props.labPat.id) {
// updateLabPat({ ...props.labPatKey, column: changedField?.field, value: changedField?.newValue }).then((res: any) => {
// if (res.code == 0) {
// }
// })
// } else {
// changepatcolumn({ ...props.labPatKey, column: changedField?.field, value: changedField?.newValue })
// }
} catch (error) {
console.error('更新失败:', error);
// 失败时可以恢复旧值
emit('update:labPat', oldObj);
lastValue.value = JSON.stringify(oldObj);
}
}
}
};
// 完善字段变化检测方法
const getChangedField = (oldObj: { [key: string]: any }, newObj: { [key: string]: any }) => {
const oldKeys = Object.keys(oldObj);
for (const key of oldKeys) {
const oldVal = oldObj[key];
const newVal = newObj[key];
if (oldVal instanceof Date && newVal instanceof Date) {
if (oldVal.getTime() !== newVal.getTime()) {
return { field: key, oldValue: oldVal, newValue: newVal };
}
} else if (oldVal !== newVal) {
return { field: key, oldValue: oldVal, newValue: newVal };
}
}
const newKeys = Object.keys(newObj);
for (const key of newKeys) {
if (!(key in oldObj)) {
return { field: key, oldValue: undefined, newValue: newObj[key] };
}
}
return null;
};
const userList = ref([]);
onMounted(() => {
const data = { status: 0, del_flag: 0, pageSize: 1000, pageNum: 1 }
listUser(data).then((res: any) => {
userList.value = res.rows;
});
})
</script>
<style scoped lang="scss">
.labpat_box {
height: calc(90vh - 20px);
display: flex;
flex-direction: column;
overflow: hidden;
.check_box {
:deep(.el-checkbox__input.is-checked+.el-checkbox__label) {
color: #f00 !important;
}
}
:deep(.el-input__wrapper) {
box-shadow: 0 0 0 1px #96B8D9 inset;
background-color: rgba(236, 244, 251, 0.5);
color: #08355E;
.is-focus {
box-shadow: 0 0 0 1px #1f6dd3 inset !important;
}
&:hover {
box-shadow: 0 0 0 1px #1f6dd3 inset !important;
}
// .el-input__placeholder {
// color: none !important;
// }
}
:deep(.el-select__wrapper) {
box-shadow: 0 0 0 1px #96B8D9 inset;
background-color: rgba(236, 244, 251, 0.5);
color: #08355E;
.is-focus {
box-shadow: 0 0 0 1px #1f6dd3 inset !important;
}
&:hover {
box-shadow: 0 0 0 1px #1f6dd3 inset !important;
}
.el-select__placeholder {
color: #08355E !important;
}
}
:deep(.el-input__inner) {
color: #08355E !important;
-webkit-text-fill-color: #08355E;
}
:deep(.el-select__input) {
color: #08355E !important;
}
.compact-form {
flex: 1;
position: relative;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
.el-form-item {
margin-bottom: 0px;
}
.el-form-item__label {
padding-bottom: 0px;
color: #08355E;
font-size: 12px;
}
:deep(.el-form-item--default .el-form-item__label) {
height: 27px !important;
line-height: 27px !important;
}
:deep(.el-form-item--default .el-form-item__content) {
line-height: 27px !important;
}
// pointer-events: none;
:deep(.el-radio__label) {
color: #08355E;
}
}
:deep(.el-switch__label) {
color: #08355E;
}
}
</style>

View File

@ -0,0 +1,144 @@
/**
* @file index.vue 科内开单
* @author: w
* @since: 2026-03-02
*/
<template>
<div class="app-container">
<el-row :gutter="10" class="row-box">
<el-col :span="13" style="height: 100%;">
<div class="box-shadow">
<el-row :gutter="5">
<el-col :span="8">
<Info :lab-pat="labpat" :dict-data="dictData" />
</el-col>
<el-col :span="16">
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="11" style="height: 100%;">
<div class="box-shadow">
<el-form :model="queryParams" inline size="small" label-width="5.5rem">
<el-form-item label="姓名:" prop="brxm">
<el-input v-model="queryParams.brxm" style="width: 9rem;" />
</el-form-item>
<el-form-item label="条码号:" prop="sqh">
<el-input v-model="queryParams.sqh" style="width: 9rem;" />
</el-form-item>
<el-form-item label="状态:" prop="zt">
<el-select v-model="queryParams.zt" placeholder="请选择" style="width: 9rem;" clearable>
<el-option label="已申请未打印" value="1" />
<el-option label="显示所有" value="0" />
</el-select>
</el-form-item>
<el-form-item label="登记时间:" prop="st">
<el-date-picker v-model="queryParams.st" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
style="width: 7.5rem;" />&nbsp; -&nbsp;
<el-date-picker v-model="queryParams.et" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
style="width: 7.5rem;" />
</el-form-item>
<el-form-item label="">
<el-button type="primary" @click="handleQuery"> 查询 </el-button>
</el-form-item>
</el-form>
<div class="table-box">
<CustomVxeTable :table-data="labPatList" :loading="loading" :columns="tableColumns"
@current-change="handleRowClick" size="small"
:scrollYConfig="{ enabled: true, rSize: 30, height: '100%', }" :row-style="rowStyle"
:cell-style="cellStyle" class="mytable-style" ref="tableRef" :enable-column-drag="true"
@column-drag-end="handleColumnDragEnd">
</CustomVxeTable>
</div>
</div>
</el-col>
</el-row>
</div>
</template>
<script setup>
import { templateRef } from '@vueuse/core'
import Info from './components/info.vue'
import { getDictData, formatDict, dictData } from '@/hooks'
import dayjs from 'dayjs'
const labpat = ref({})
const loading = ref(false)
const tableRef = templateRef('tableRef')
const labPatList = ref([])
const queryParams = ref({})
const tableColumns = ref([
{ field: 'brdh', title: '病历号', width: 80, align: 'center', resizable: true },
{ field: 'brxm', title: '姓名', width: 40, align: 'center', resizable: true, slotName: 'brxm' },
{ field: 'brxb', title: '性别', width: 30, align: 'center', slotName: 'brxb', resizable: true },
{ field: 'sqh', title: '条码号', width: 100, align: 'center', resizable: true, },
{ field: 'zt', title: '状态', width: 40, align: 'center', resizable: true, },
{ field: 'nl', title: '年', width: 30, align: 'center', resizable: true },
{ field: 'nldw', title: '龄', width: 20, align: 'center', slotName: 'nldw', resizable: true },
{ field: 'yblx', title: '标本', width: 50, align: 'center', resizable: true, slotName: 'yblx' },
{ field: 'yhdh', title: '检验医生', width: 60, align: 'center', resizable: true, slotName: 'yhdh' },
{ field: 'ksdh', title: '科室', width: 80, align: 'center', slotName: 'ksdh', resizable: true },
{ field: 'time', title: '登记时间', width: 80, align: 'center', resizable: true },
{ field: 'brly', title: '病人来源', width: 90, align: 'center', slotName: 'brly', resizable: true },
{ field: 'xmdh', title: '项目', width: 90, align: 'center', resizable: true },
])
const rowStyle = ({ row }) => {
}
const cellStyle = ({ row, column }) => {
}
const handleRowClick = (row) => {
labpat.value = row
}
// 更新列配置
const handleColumnDragEnd = (data) => {
tableColumns.value = [];
nextTick(() => {
tableColumns.value = [...data.columns];
});
}
onMounted(() => {
queryParams.value.st = dayjs().format('YYYY-MM-DD')
queryParams.value.et = dayjs().format('YYYY-MM-DD')
})
</script>
<style scoped lang="scss">
.app-container {
background: #F0F3F8;
}
.box-shadow {
height: 100%;
box-shadow: 2px 2px 4px 0px rgba(206, 217, 234, 0.7);
border-radius: .75rem;
padding: .5rem;
background-color: #fff;
.flex-between {
margin-bottom: .5rem;
}
}
.row-box {
height: 100%;
}
.table-box {
height: calc(100% - 60px);
}
.el-form-item {
margin-bottom: 5px;
}
</style>

View File

@ -46,20 +46,22 @@
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="print_box">
<div class="title">{{ formatDict(userStore.sysLoginParam.loginYLJG, 'HOS') }}</div>
<div class="content">{{ statsTitle }}</div>
<div class="table-container">
<el-table :data="tableData" height="100%" border highlight-current-row v-loading="loading">
<el-table-column v-for="col in tableColumns" :key="col.prop" :label="col.label" :prop="col.prop"
width="100" />
</el-table>
<vxe-table :data="tableData" border v-loading="loading" height="100%" class="mytable-style"
:tooltip-config="{ appendToBody: true, zIndex: 3000 }" show-footer :footer-method="getSummaries"
:scroll-y="{ enabled: true, rSize: 30, height: '100%', }">
<vxe-column v-for="col in tableColumns" :key="col.prop" :title="col.label" :field="col.prop" width="100"
show-overflow align="center">
<template #default="scope">
{{ col.dictType ? formatDict(scope.row[col.prop], col.dictType) : scope.row[col.prop] }}
</template>
</vxe-column>
</vxe-table>
</div>
</div>
</div>
@ -118,9 +120,33 @@ const handletime = () => {
// if (dayDiff === -1 || dayDiff === -2) return ElMessage.warning('请选择有效的日期范围');
}
const getSummaries = ({ columns, data }) => {
const sumSamplecnt = tableData.value.reduce((sum, item) => sum + item.cp_samplecnt, 0)
const sumCnt = tableData.value.reduce((sum, item) => sum + item.cp_cnt, 0)
const sumAmt = tableData.value.reduce((sum, item) => sum + item.cp_amt, 0).toFixed(2)
// 2. 定义合计行每一列的内容
const footerData = columns.map((column, index) => {
switch (column.field) {
case tableColumns.value[0].prop: // 第一列显示“合计”
return '合计'
case 'cp_samplecnt':
return sumSamplecnt
case 'cp_cnt':
return sumCnt
case 'cp_amt':
return sumAmt
default:
return '' // 其他列空值
}
})
return [footerData]
};
const search = () => {
const checkedCols = [...coloums.value, ...checkBoxs.value];
console.log('checkedCols==>', checkedCols);
const arr = [];
tableColumns.value.forEach((tableItem, tableIndex) => {
@ -130,7 +156,7 @@ const search = () => {
if (matchItem) {
arr.push({
...matchItem,
paramSort: tableIndex,
paramSequence: matchItem.paramSequence ? matchItem.paramSequence : tableIndex + 1,
});
}
});
@ -140,10 +166,7 @@ const search = () => {
);
unmatchedItems.forEach((item, unmatchIndex) => {
arr.push({
...item,
paramSort: tableColumns.value.length + unmatchIndex,
});
arr.push({ ...item, });
});
const data = {
@ -151,9 +174,11 @@ const search = () => {
Column: arr,
Template: Template.value
};
console.log('data==>', data);
loading.value = true;
getstatsQuery(data).then(res => {
tableData.value = res.data
}).finally(() => {
loading.value = false;
})
};
@ -164,16 +189,15 @@ const handleCheckBoxChange = (val) => {
const checkedCols = val.map(paramCode => {
const matchItem = checkBoxs.value.find(item => item.paramCode === paramCode);
return matchItem ? { label: matchItem.paramName, prop: matchItem.paramCode } : null;
return matchItem ? { label: matchItem.paramName, prop: matchItem.paramCode, dictType: matchItem.remark } : null;
}).filter(Boolean); // 过滤null
const fixedCols = coloums.value.map(item => ({
label: item.paramName,
prop: item.paramCode,
dictType: item.remark,
}));
tableColumns.value = [...checkedCols, ...fixedCols];
}
@ -186,6 +210,7 @@ const getParams = () => {
key: item.paramCode,
label: item.paramName,
prop: item.paramCode,
dictType: item.remark,
}
})
@ -229,7 +254,7 @@ onMounted(() => {
.table-container {
margin-top: 10px;
height: calc(100% - 80px);
height: calc(100% - 100px);
}
.tips {
@ -237,4 +262,59 @@ onMounted(() => {
color: #3282F6;
margin-bottom: 5px;
}
:deep(.el-table__footer-wrapper tfoot td.el-table__cell) {
color: #1f6dd3 !important;
font-weight: 700;
/* 可替换为任意颜色值 */
}
:deep(.vxe-header--row th) {
border-color: #1F6DD3;
background-color: #1F6DD3;
color: #fff;
}
:deep(.vxe-body--row td) {
border-color: #1F6DD3;
}
:deep(.vxe-table--row-hover) {
background-color: #1F6DD3;
}
:deep(.vxe-table--current-row) {
background-color: #1F6DD3;
}
:deep(.el-table-header-cell) {
cursor: move;
user-select: none;
}
// 表格边框
:deep(.vxe-table--render-default.border--full .vxe-body--column) {
background-image: linear-gradient(#96B8D9, #96B8D9), linear-gradient(#96B8D9, #96B8D9) !important;
}
// 表头边框
:deep(.vxe-table--render-default.border--full .vxe-header--column) {
background-image: linear-gradient(#1F6DD3, #1F6DD3), linear-gradient(#1F6DD3, #1F6DD3) !important;
}
:deep(.vxe-table--render-default.is--padding .vxe-body--column:not(.col--ellipsis)) {
padding: 0 !important;
}
:deep(.vxe-table--render-default .vxe-footer--column:not(.col--ellipsis)) {
padding: 0 !important;
color: #1f6dd3 !important;
font-weight: 700;
}
:deep(.vxe-header--gutter),
:deep(.col--gutter) {
display: none !important;
}
</style>