批量输入、界面优化

This commit is contained in:
wyuu 2026-05-13 17:50:49 +08:00
parent a756eafd19
commit 8b7b700017
25 changed files with 1126 additions and 649 deletions

27
src/api/batch/index.ts Normal file
View File

@ -0,0 +1,27 @@
//@ts-ignore js语法检查忽略
import request from '@/utils/request';
// 获取模版数据
export function getInputMdl(query?: Object) {
return request({
url: '/batchIn/getInputMdl',
method: 'get',
params: query,
});
}
// 获取模版明细数据
export function getInputMdlDetail(query?: Object) {
return request({
url: '/batchIn/getInputMdlDetail',
method: 'get',
params: query,
});
}
// 确认模版数据
export function confirmInputMdl(query?: Object) {
return request({
url: '/batchIn/confirmInputMdl',
method: 'post',
data: query,
});
}

145
src/utils/groupHelper.ts Normal file
View File

@ -0,0 +1,145 @@
// 定义通用类型
interface GroupOriginValues {
[key: string]: string | number | null | undefined
}
interface GroupMetaItem {
groupSeq: number
key: string
originValues: GroupOriginValues
itemCount: number
firstRowIndex: number | null
}
// @ts-ignore
interface GroupedItem<T> extends T {
rowSeq: number // 组内行序号
groupSeq?: number // 组序号(可选)
}
interface GroupData<T> {
groupSeq: number
key: string
originValues: GroupOriginValues
items: GroupedItem<T>[]
}
interface UseGroupTableDataReturn<T> {
tableData: ComputedRef<(GroupedItem<T> & { [key: string]: string | number | '' })[]>
groupMeta: ComputedRef<GroupMetaItem[]>
groupedData: ComputedRef<GroupData<T>[]>
}
/**
* 通用多字段分组函数
* @param rawList - 原始数据列表
* @param groupFields - 分组字段(单个字段传字符串,多个传数组)
* @param showFields - 每组仅第一条显示的字段
* @param sortField - 排序字段(默认按orderDate降序)
* @param originalData - 原始数据赋值字段(可选)
* @returns 表格渲染数据 + 分组元信息
*/
export function useGroupTableData<T extends Record<string, any>>(
rawList: string[],
groupFields: string,
showFields: string | string[],
sortField: string = 'orderDate',
originalData: string[]
): UseGroupTableDataReturn<T> {
// 处理参数格式:确保为数组
const groupFieldArr = Array.isArray(groupFields) ? groupFields : [groupFields]
const showFieldArr = Array.isArray(showFields) ? showFields : [showFields]
// 1. 核心分组逻辑
const groupedData = computed<GroupData<T>[]>(() => {
const groups: Record<string, {
key: string
originValues: GroupOriginValues
items: GroupedItem<T>[]
}> = {}
rawList.forEach((item: any) => {
// 生成分组key(多字段拼接,避免重复)
const groupKey = groupFieldArr.map(field => item[field] ?? '').join('_')
if (!groups[groupKey]) {
groups[groupKey] = {
key: groupKey,
originValues: groupFieldArr.reduce((obj, field) => {
obj[field] = item[field] ?? ''
return obj
}, {} as GroupOriginValues),
items: []
}
}
// 处理仅第一条显示的字段
showFieldArr.forEach((field, i) => {
originalData.forEach((v, _i) => {
if (i == _i) {
item[field] = item[v]
}
})
})
// 添加组内行序号
groups[groupKey].items.push({
...item,
rowSeq: groups[groupKey].items.length + 1
})
})
// 2. 按指定字段降序排序分组
const sortedGroupKeys = Object.keys(groups).sort((a, b) => {
const aSortValue = groups[a].originValues[sortField] ?? ''
const bSortValue = groups[b].originValues[sortField] ?? ''
// 兼容日期/字符串/数字排序
if (aSortValue && bSortValue && !isNaN(new Date(aSortValue).getTime())) {
return new Date(bSortValue).getTime() - new Date(aSortValue).getTime()
}
return String(bSortValue).localeCompare(String(aSortValue))
})
// 3. 生成带组序号的分组数据
return sortedGroupKeys.map((key, groupIndex) => ({
groupSeq: groupIndex + 1,
...groups[key]
}))
})
// 4. 构造扁平化表格数据
const tableData = computed(() => {
const result: (GroupedItem<T> & { [key: string]: string | number | '' })[] = []
groupedData.value.forEach(group => {
group.items.forEach((item, idx) => {
const processedItem = { ...item }
// 处理仅第一条显示的字段
showFieldArr.forEach(field => {
processedItem[field] = idx === 0 ? (item[field] ?? '') : ''
})
// 组序号仅每组第一条显示
processedItem.groupSeq = idx === 0 ? group.groupSeq : ''
result.push(processedItem)
})
})
return result
})
// 5. 生成分组元信息(用于合并单元格)
const groupMeta = computed<GroupMetaItem[]>(() => {
return groupedData.value.map(group => ({
groupSeq: group.groupSeq,
key: group.key,
originValues: group.originValues,
itemCount: group.items.length,
firstRowIndex: null
}))
})
return {
tableData,
groupMeta,
groupedData
}
}

View File

@ -117,9 +117,9 @@
<el-col :span="6">
<el-form-item label="标本日期:" prop="times">
<el-date-picker v-model="queryParams.st" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
@change="handletime" style="width: 47%" /> &nbsp; - &nbsp;
@change="handletime" style="width: 46%" /> &nbsp; - &nbsp;
<el-date-picker v-model="queryParams.et" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
@change="handletime" style="width: 47%" />
@change="handletime" style="width: 46%" />
</el-form-item>
</el-col>
<el-col :span="3">
@ -137,22 +137,15 @@
&nbsp;
<el-checkbox v-model="queryParams.jzbz" label="急诊" true-value="1" false-value="0" />
<el-checkbox v-model="queryParams.dcny" label="多重耐药(细菌查询用)" true-value="1" false-value="0" />
<el-col :span="3">
<el-form-item label-width="50px">
<el-button icon="search" type="primary" @click="handleQuery">
搜索
</el-button>
<!-- <el-button icon="Refresh" @click="resetQuery">重置</el-button> -->
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-row>
</div>
<div class="mb8 mt10">
<el-button icon="search" type="primary" :size="aotuSize" @click="handleQuery"> 搜索 </el-button>
<el-button type="primary" plain icon="Edit" :size="aotuSize" @click="selectStatusRows">勾选所有未打印</el-button>
<el-button type="primary" plain icon="Upload" :size="aotuSize" @click="printPdf">打印报告</el-button>
<el-button type="primary" plain icon="edit" :size="aotuSize" @click="editHandle">编辑</el-button>
<el-button type="warning" plain icon="Printer" :size="aotuSize" @click="printPdf">打印报告</el-button>
<el-button type="info" plain icon="edit" :size="aotuSize" @click="editHandle">编辑</el-button>
</div>
<el-row :gutter="15">
<el-col :span="16" class="right-table">

View File

@ -1,117 +1,102 @@
<template>
<div class="labpat_box">
<el-form :model="labPat" label-width="4.3rem" class="compact-form" label-position="right">
<el-form :model="labPat" label-width="5rem" label-position="right" ref="formRef" class="left-form">
<div :class="['sh_box', getColor(newStatus)]" v-if="visbileMask">
<div class="text">{{ getLableType(newStatus) }}</div>
</div>
<el-form-item label="病人来源">
<el-col :span="16">
<SelectTable v-model:data="labPat.brly" :fields="brlyFields" :table-data="dictData.PT" size="small"
placeholder="" @getDataValue="handleFieldChange" />
</el-col>
<el-col :span="8">
<el-checkbox v-model="labPat.jzbz" true-value="1" class="check_box"> 急诊 </el-checkbox>
</el-col>
<SelectTable v-model:data="labPat.patType" :fields="brlyFields" :table-data="dictData.PT" placeholder=""
@getDataValue="handleFieldChange" @enter-press="selectEnter(1)" />
</el-form-item>
<el-form-item label="病人代号">
<el-input v-model="labPat.brdh" @keyup.enter="brdhHandle" size="small" />
<el-form-item label="病人代号" required>
<el-input v-model="labPat.patId" @change="brdhHandle" @keydown.enter="nextFocus" />
</el-form-item>
<el-form-item label="姓 名">
<el-input v-model="labPat.brxm" @change="handleFieldChange" size="small" />
<el-form-item label="姓 名" required>
<el-input v-model="labPat.patName" @change="handleFieldChange" @keydown.enter="nextFocus" />
</el-form-item>
<el-form-item label="性 别">
<SelectTable v-model:data="labPat.brxb" :table-data="dictData.SX" size="small" placeholder=""
@getDataValue="handleFieldChange" />
<el-form-item label="性 别" required>
<SelectTable v-model:data="labPat.patSex" :table-data="dictData.SX" placeholder=""
@getDataValue="handleFieldChange" @enter-press="selectEnter(4)" />
</el-form-item>
<el-form-item label="年龄">
<el-form-item label="年龄" required>
<el-col :span="14">
<el-input v-model="labPat.nl" @change="handleFieldChange" size="small" />
<el-input v-model="labPat.patAge" @change="handleFieldChange" @keydown.enter="nextFocus" />
</el-col>
<el-col :span="10">
<SelectTable v-model:data="labPat.nldw" :table-data="dictData.AU" size="small" placeholder=""
@getDataValue="handleFieldChange" />
<SelectTable v-model:data="labPat.ageUnit" :table-data="dictData.AU" placeholder="" :clearable="false"
@getDataValue="handleFieldChange" @enter-press="selectEnter(6)" />
</el-col>
</el-form-item>
<el-form-item label="样本类型">
<SelectTable v-model:data="labPat.yblx" :table-data="dictData.BT" size="small" placeholder=""
@getDataValue="handleFieldChange" />
<el-form-item label="生理周期" v-if="labPat.patSex == '2'">
<SelectTable v-model:data="labPat.slzq" :table-data="dictData.SLZQ" placeholder=""
@getDataValue="handleFieldChange" @enter-press="selectEnter(labPat.patSex == '2' ? 7 : -1)" />
</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" size="small" placeholder=""
@getDataValue="handleFieldChange" />
<SelectTable v-model:data="labPat.doctorCode" :tableData="dictData.DOCTOR" placeholder=""
@getDataValue="doctorHandle" @enter-press="selectEnter(labPat.patSex == '2' ? 8 : 7)" />
</el-form-item>
<el-form-item label="送检科室">
<SelectTable v-model:data="labPat.ksdh" :table-data="dictData.DP" size="small" placeholder=""
@getDataValue="handleFieldChange" />
<SelectTable v-model:data="labPat.departCode" :table-data="dictData.DEPT" placeholder=""
@getDataValue="deptHandle" @enter-press="selectEnter(labPat.patSex == '2' ? 9 : 8)" />
</el-form-item>
<el-form-item label="床 号">
<el-input v-model="labPat.ch" @change="handleFieldChange" size="small" />
<el-input v-model="labPat.patBed" @change="handleFieldChange" @keydown.enter="nextFocus" />
</el-form-item>
<el-form-item label="临床诊断">
<el-input v-model="labPat.zd" @change="handleFieldChange" size="small" />
<el-input v-model="labPat.diagnosisName" @change="handleFieldChange" @keydown.enter="nextFocus" />
</el-form-item>
<el-form-item label="备 注">
<el-input v-model="labPat.bz" @change="handleFieldChange" size="small" />
<el-input v-model="labPat.bz" @change="handleFieldChange" @keydown.enter="nextFocus" />
</el-form-item>
<el-form-item label="登记人员">
<SelectTable v-model:data="labPat.sjys" :table-data="dictData.SRD" size="small" placeholder=""
:disabled="true" />
<el-input v-model="labPat.userName" disabled />
</el-form-item>
<el-form-item label="登记时间">
<el-date-picker v-model="labPat.djry" type="datetime" format="YYYY-MM-DD HH:mm:ss" :disabled="true"
value-format="YYYY-MM-DD HH:mm:ss" size="small" style="width: 100%;" />
<el-date-picker v-model="labPat.orderTime" type="datetime" format="YYYY-MM-DD HH:mm:ss" disabled
value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%;" />
</el-form-item>
<el-form-item label="条 码 号">
<el-input v-model="labPat.sqh" :disabled="true" size="small" />
<el-form-item label="医疗机构">
<el-input v-model="labPat.srcHospName" disabled />
</el-form-item>
<el-form-item label="申请状态">
<SelectTable v-model:data="labPat.zt" size="small" :table-data="lisReqs" placeholder="" :disabled="true" />
</el-form-item>
<el-form-item label="证件类型">
<SelectTable v-model:data="labPat.zjlx" size="small" :table-data="dictData.ZJLX" placeholder=""
@getDataValue="handleFieldChange" />
<SelectTable v-model:data="labPat.zjlx" :table-data="dictData.ZJLX" placeholder=""
@getDataValue="handleFieldChange" @enter-press="selectEnter(labPat.patSex == '2' ? 13 : 12)" />
</el-form-item>
<el-form-item label="证件号码">
<el-input v-model="labPat.sfzh" size="small" />
<el-input v-model="labPat.patIdentity" @keydown.enter="nextFocus" />
</el-form-item>
<el-form-item label="联系电话">
<el-input v-model="labPat.phone" size="small" />
<el-input v-model="labPat.phone" @keydown.enter="nextFocus" />
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, watch, toRaw, computed, onMounted } from 'vue';
import { queryPatInfo } from '@/api/liswork/order'
import SelectTable from '@/components/SelectTable/index.vue';
import { getDictData, formatDict, dictData } from '@/hooks'
// @ts-ignore
import { listUser } from '@/api/system/user.js'
//@ts-ignore
import { getDicts } from '@/api/system/dict/data'
import { E } from 'vue-router/dist/router-CWoNjPRp.mjs';
const props = defineProps({
labPat: {
type: Object,
required: true
},
//结果主键
labPatKey: {
type: Object,
default: () => { }
//展示水印
visbileMask: {
type: Boolean,
default: false
},
});
const lastJgbz = ref();
watch(() => props.labPat, (newVal) => {
lastValue.value = JSON.stringify(newVal);
lastJgbz.value = newVal.jgbz;
const newStatus = ref('');
watch(() => props.labPat.status, (newVal: any) => {
newStatus.value = newVal;
})
const emit = defineEmits(['update:labPat']);
const lastValue = ref('');
const emit = defineEmits(['update:labPat', 'getBrdh']);
const brlyFields = ref([
{ prop: 'value', label: '代号', width: 80, enablePinyinSearch: true },
@ -122,63 +107,107 @@ 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 {
// // saveLabPat(changedField)
// } catch (error) {
// console.error('更新失败:', error);
// // 失败时可以恢复旧值
// // emit('update:labPat', oldObj);
// lastValue.value = JSON.stringify(oldObj);
// }
// }
// }
const doctorHandle = (data) => {
props.labPat.doctorName = data.label
}
const deptHandle = (data) => {
props.labPat.departName = data.label
}
const handleFieldChange = async () => {
};
const getLableType = (type: string) => {
const item = dictData.value.SQDS.find((p: any) => p.value === type);
return item && props.visbileMask ? item.label : '';
}
const getColor = (type: string) => {
switch (type) {
case '10':
return 'cs_color';
case '20':
return 'sh_color';
case '30':
return 'cb_color';
case '40':
return 'eb_color';
case '50':
return 'sd_color';
default:
return 'default';
}
}
// 病人代号查询病人信息的逻辑
const brdhHandle = () => {
queryPatInfo({ brdh: props.labPat.brdh }).then((res: any) => {
if (res.data) {
emit('update:labPat', { ...props.labPat, ...res.data })
}
})
emit('getBrdh', props.labPat.patId)
}
const formRef = useTemplateRef('formRef')
const currentTarget = ref(null);
// 回车跳转到下一个表单元素
const nextFocus = (e?: Event, idx?: number) => {
if (e) e.preventDefault() // 禁止回车提交表单
// 找到所有可聚焦的表单项:
const els = formRef.value.$el.querySelectorAll(
'input:not([type="hidden"]):not([disabled]), select:not([disabled]), textarea:not([disabled]), ' +
'.select-table__wrapper .el-select__input:not([disabled]), ' + '.el-date-editor input:not([disabled])'
);
const lisReqs = ref([]);
const userList = ref([]);
onMounted(() => {
const data = { status: 0, del_flag: 0, pageSize: 1000, pageNum: 1 }
listUser(data).then((res: any) => {
userList.value = res.rows;
const arr = Array.from(els).filter((el: any) => {
// 额外过滤:排除隐藏元素、禁用状态的父级封装组件(如 SelectTable 被 disabled 时)
const isHidden = el.offsetParent === null;
const isDisabled = el.hasAttribute('disabled') || el.parentElement?.closest('.is-disabled') !== null;
return !isHidden && !isDisabled;
});
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
}))
let index: number;
if (!idx) {
// 找到当前触发元素在列表中的位置
currentTarget.value = e?.target as HTMLElement;
// 兼容 SelectTable:如果点击的是组件外层,定位到内部输入框
if (currentTarget.value.closest('.select-table-container')) {
currentTarget.value = currentTarget.value.closest('.select-table-container').querySelector('.el-select__input');
}
index = arr.findIndex((item: any) => item === currentTarget.value || item.contains(currentTarget.value));
} else {
index = idx - 1;
}
// 跳转到下一个可聚焦元素(循环到第一个 if 最后一个)
if (index > -1) {
const nextIndex = (index + 1) % arr.length;
// 确保下一个元素存在且可聚焦
if (arr[nextIndex]) {
nextTick(() => {
(arr[nextIndex] as HTMLElement)?.focus();
});
// 针对 SelectTable 额外处理:聚焦后激活下拉框
if ((arr[nextIndex] as HTMLElement).closest('.select-table-container')) {
(arr[nextIndex] as HTMLElement).dispatchEvent(new Event('click'));
}
}
}
}
const selectEnter = (index: number) => {
const emptyEvent = new Event('keydown', { cancelable: true });
nextFocus(emptyEvent, index)
}
onMounted(() => {
})
})
</script>
@ -251,26 +280,29 @@ onMounted(() => {
}
.compact-form {
.left-form {
flex: 1;
position: relative;
height: 100%;
overflow-y: auto;
overflow-x: hidden;
padding-top: 5px;
.el-form-item {
margin-bottom: 0px;
margin-bottom: 8px;
}
.el-form-item__label {
:deep(.el-form-item__label) {
padding-bottom: 0px;
color: #08355E;
font-size: 12px;
font-size: .875rem !important;
}
:deep(.el-form-item__label:before) {
margin-right: 0 !important;
}
:deep(.el-form-item--default .el-form-item__label) {
height: 27px !important;
line-height: 27px !important;
@ -292,4 +324,51 @@ onMounted(() => {
color: #08355E;
}
}
.sh_box {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0);
z-index: 9;
display: flex;
justify-content: center;
align-items: center;
writing-mode: vertical-rl;
font-weight: 500;
font-size: 100px;
.text {
font-style: italic;
}
// pointer-events: none;
}
.cs_color {
color: rgba(40, 189, 187, 0.25);
}
.sh_color {
color: rgba(238, 8, 8, 0.25);
}
.cb_color {
color: rgba(0, 128, 0, 0.25);
}
.eb_color {
color: rgba(255, 165, 0, 0.25);
}
.sd_color {
color: rgb(233, 126, 32, .25);
}
.default {
color: rgba(40, 189, 187, 0.25);
}
</style>

View File

@ -1,192 +0,0 @@
/**
* @file setBilling.vue 开单项目设置
* @author: w
* @since: 2026-03-05
*/
<template>
<div>
<el-dialog v-model="showDialog" title="开单项目设置" width="80%" @close="handleDialogClose">
<el-row :gutter="10" class="table-toolbar">
<el-col :span="10">
<el-button type="primary" @click="cpHandle">存盘</el-button>
<el-button type="primary" @click="firstHandle">首位</el-button>
<el-button type="primary" @click="lastHadnle">末位</el-button>
</el-col>
<el-col :span="14">
项目检索: <el-input v-model="searchKey" size="small" style="width: 200px;" @clear="filterDictData"
@input="filterDictData" /> &nbsp;
<div class="tips">
说明:从右边列表中双击某个项目可以直接加入到左边的列表中,代表这个项目为分支医疗机构开单项目
</div>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="10">
<CustomTable ref="tableRef" :data="CanReqListData" :columns="leftColumns" @row-dblclick="handleLeftDblclick"
:config="{ border: true, height: '80vh', highlightCurrentRow: true, key: 'sfxmdh' }" :enableRowDrag="true"
@row-drag-end="handleRowDragEnd" @row-click="handleRowClick">
<!-- <template #dyxh="{ row }">
<el-input v-model="row.dyxh" class="full-width-input" />
</template> -->
</CustomTable>
</el-col>
<el-col :span="14" style="height:80vh">
<CustomVxeTable :table-data="filterData" :columns="columns" @cell-dblclick="handleDblclick" size="small"
:scrollYConfig="{ enabled: true, rSize: 30, height: '100%', }" class="mytable-style" ref="tableRef">
</CustomVxeTable>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<script setup>
import { queryCreateReqList, queryCanCreateReqList, saveCanCreaeReqList } from '@/api/liswork/order'
import { ElMessage } from 'element-plus'
import { getFirstLetter } from '@/utils/pinyin';
const emit = defineEmits(["update"]);
const searchKey = ref('')
const showDialog = ref(false)
const selectedRow = ref(null)
const CanReqListData = ref([])
const columns = [
{ field: 'sflbmc', title: '类别', align: 'center', resizable: true },
{ field: 'sfxmdh', title: '代号', align: 'center', resizable: true },
{ field: 'sfxmmc', title: '简称', align: 'center', width: 200, resizable: true },
{ field: 'dj', title: '单价', align: 'center', width: 80, resizable: true },
{ field: 'yblx', title: '样本', align: 'center', resizable: true },
{ field: 'bz', title: '采集说明', align: 'center', width: 200, resizable: true },
]
const leftColumns = [
{ prop: 'sfxmdh', label: '项目代号', visible: true, align: 'center' },
{ prop: 'sfxmmc', label: '医疗机构可开展的诊疗项目', visible: true, align: 'center' },
{ prop: 'xh', label: '排序', visible: true, align: 'center', },
]
const handleDblclick = ({ row }) => {
const index = CanReqListData.value.findIndex(item => item.sfxmdh === row.sfxmdh)
if (index === -1) {
CanReqListData.value.push(row)
resetSortNumber()
} else {
ElMessage.warning('已存在该项目')
}
}
const filterData = ref([])
const processedTableData = ref([])
const filterDictData = () => {
const key = searchKey.value.trim().toLowerCase();
if (!key) {
// 空搜索时显示全部预处理数据
filterData.value = [...processedTableData.value];
return;
}
filterData.value = processedTableData.value.filter((item) => {
const matchLabel = item.pinyin?.toString().toLowerCase().includes(key);
return matchLabel;
});
}
const open = () => {
queryCanCreateReqList().then(res => {
CanReqListData.value = res.data.sort((a, b) => a.xh - b.xh)
})
queryCreateReqList().then(res => {
processedTableData.value = processTableData(res.data)
filterData.value = [...processedTableData.value];
})
showDialog.value = true
}
const processTableData = (data) => {
return data.map((item) => {
const pinyinMap = {};
pinyinMap['pinyin'] = getFirstLetter(item.sfxmmc).toLowerCase();
return { ...item, ...pinyinMap };
});
};
const handleRowClick = (row) => {
selectedRow.value = row
}
const handleLeftDblclick = (row) => {
const index = CanReqListData.value.findIndex(item => item.sfxmdh == row.sfxmdh)
if (index !== -1) {
CanReqListData.value.splice(index, 1)
resetSortNumber()
}
}
//退拽属性
const handleRowDragEnd = (data) => {
// 更新行顺序
CanReqListData.value = data.list.map((item) => {
return {
...item,
xh: item.sort,
}
})
}
const cpHandle = () => {
saveCanCreaeReqList(CanReqListData.value).then((res) => {
if (res.code == 0) {
emit('update')
showDialog.value = false
ElMessage.success('保存成功')
}
})
}
const firstHandle = () => {
if (!selectedRow.value) return
const currentIndex = CanReqListData.value.findIndex(item => item.sfxmdh === selectedRow.value.sfxmdh)
if (currentIndex === 0) return
const [movedRow] = CanReqListData.value.splice(currentIndex, 1)
CanReqListData.value.unshift(movedRow)
resetSortNumber()
tableRef.value.setScrollTop(0)
}
const lastHadnle = () => {
if (!selectedRow.value) return
const currentIndex = CanReqListData.value.findIndex(item => item.sfxmdh === selectedRow.value.sfxmdh)
if (currentIndex === CanReqListData.value.length - 1) return
const [movedRow] = CanReqListData.value.splice(currentIndex, 1)
CanReqListData.value.push(movedRow)
resetSortNumber()
tableRef.value.setScrollTop(CanReqListData.value.length)
}
const resetSortNumber = () => {
CanReqListData.value.forEach((item, index) => {
item.xh = index + 1
})
}
const handleDialogClose = () => {
showDialog.value = false
}
defineExpose({
open
})
</script>
<style scoped lang="scss">
.tips {
color: #1f6dd3;
font-weight: 600;
}
/* 可拖拽表格行样式提示 */
:deep(.drag-table .el-table__row) {
cursor: move;
/* 鼠标移入行显示拖拽光标 */
transition: background-color 0.2s;
}
</style>

View File

@ -1,108 +1,112 @@
/**
* @file index.vue 科内开单
* @author: w
* @since: 2026-03-02
* @since: 2026-03-09
*/
<template>
<div class="app-container">
<el-row :gutter="10" class="row-box">
<el-col :span="13" style="height: 100%;">
<el-col :span="16" style="height: 100%;">
<div class="box-shadow">
<el-row class="top-box">
<el-col :span="7">
<el-button type="primary" size="small" @click="saveHandle">保存</el-button>
<el-button type="primary" size="small" @click="addHandle">新增</el-button>
<el-button type="danger" size="small" @click="deleteHandle">删除</el-button>
<el-col :span="8" class="col_box">
<el-button type="success" :size="aotuSize" :loading="saveLoading" @click="saveHandle">保存</el-button>
<el-button type="primary" :size="aotuSize" @click="addHandle">新增</el-button>
<el-button type="warning" :size="aotuSize" :loading="printLoading" @click="printHandle">打印</el-button>
<el-button type="danger" :size="aotuSize" @click="deleteHandle">作废</el-button>
</el-col>
<el-col :span="17">
<el-col :span="16">
<div class="tips">
项目检索: <el-input v-model="searchKey" size="small" style="width: 150px;" @clear="filterDictData"
项目检索: <el-input v-model="searchKey" style="width: 150px;" @clear="filterDictData"
@input="filterDictData" /> &nbsp;
<el-button type="primary" size="small" @click="BillingHandle">开单项目</el-button>
</div>
</el-col>
</el-row>
<el-row :gutter="5" style="height: 100%;">
<el-col :span="7">
<Info v-model:labPat="labpat" />
<Info v-model:labPat="labpat" :visbileMask="visbileMask" @getBrdh="getBrdhHandle" />
</el-col>
<el-col :span="17" style="height: 100%;">
<div class="xmBoxs">
<template v-for="item in filterData" :key="item.sflbmc">
<div class="title">{{ item.sflbmc }}</div>
<el-checkbox-group v-model="checkboxs" @change="handleChecksChange">
<el-row>
<el-col :span="12" v-for="v in item.children" :key="v.sfxmdh">
<el-checkbox :label="v.sfxmdh">
{{ v.sfxmmc }}
</el-checkbox>
</el-col>
</el-row>
</el-checkbox-group>
</template>
</div>
<div style="height: calc(40% - 30px)">
<CustomVxeTable :table-data="sqXmList" :columns="sqXmColumns" @cell-dblclick="dbRowclick"
<el-tabs v-model="activeName" type="card" class="tabs_box" @tab-click="handleTabClick">
<el-tab-pane v-for="item in xmdlList" :key="item.dictCode" :label="item.dictName" :name="item.dictCode">
</el-tab-pane>
</el-tabs>
<div style="height: calc(60% - 55px)" class="mb5">
<CustomVxeTable :table-data="filterData" :columns="xmColumns" @cell-dblclick="dbRowclick"
:cell-style="xmcellStyle" keyField='applyid'
:scrollYConfig="{ enabled: true, rSize: 30, height: '100%', }" class="mytable-style">
<template #zt="{ row }">
申请
<template #itemclass="{ row }">
{{itemclassList.find((item) => item.itemclassCode == row.itemclass)?.itemclassName}}
</template>
</CustomVxeTable>
</div>
<div style="height: calc(40% - 30px)">
<CustomVxeTable :table-data="sqxmCzList" :columns="sqXmColumns" keyField='uid' :cell-style="cellStyle"
:config="tableConfig" :scrollYConfig="{ enabled: true, rSize: 30, height: '100%', }" ref="xmRef"
@selection-change="selectionChange" class="mytable-style">
<template #newitemclass="{ row }">
{{itemclassList.find((item) => item.itemclassCode == row.newitemclass)?.itemclassName}}
</template>
<template #itemclass_yblx="{ row }">
<SelectTable v-model:data="row.itemclass_yblx" :tableData="dictData.BT" placeholder="请选择"
:clearable="false" v-if="row.status == 10 || !row.status" value="label"
@getDataValue="(data) => { getyblxData(data, row) }" class="full-width-input" />
<span v-else style="padding-left: 5px;"> {{ formatDict(row.itemclass_yblx, 'BT') }}</span>
</template>
<template #status="{ row }">
<span v-if="row.rowSeq == 1"> {{ formatDict(row.status, 'ZT') }}</span>
</template>
<template #action="{ row }">
<el-button type="danger" :text='true' v-if="row.status == 10 || !row.status" size="small"
@click="delItem(row)">删除</el-button>
</template>
</CustomVxeTable>
</div>
<div class="yblxtext">共有{{ barcodes }}个样本,合计金额:<span>{{ totalAmount }}</span></div>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="11" style="height: 100%;">
<el-col :span="8" 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;" clearable />
<el-form :model="searchForm" inline>
<el-form-item label="" prop="brxm">
<el-input v-model="searchForm.brxm" clearable style="width: 8rem;" @change="handleQuery" :size="aotuSize"
placeholder="请输入姓名" />
</el-form-item>
<el-form-item label="条码号:" prop="sqh">
<el-input v-model="queryParams.sqh" style="width: 9rem;" clearable />
<el-form-item label="" prop="status">
<div class="radio_box">
<el-radio-group v-model="searchForm.status" @change="handleQuery" :size="aotuSize">
<el-radio :value="''">所有</el-radio>
<el-radio :value="item.value" v-for="item in dictData.SQDS">{{ item.label }}</el-radio>
</el-radio-group>
</div>
</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="begdate">
<el-date-picker v-model="queryParams.begdate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
style="width: 7.5rem;" />&nbsp; -&nbsp;
<el-date-picker v-model="queryParams.enddate" 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 label="" prop="begdate">
<div class="radio_box">
<el-radio-group v-model="searchForm.days" @change="changeDays" :size="aotuSize">
<el-radio :value="3">近3天</el-radio>
<el-radio :value="7">近7天</el-radio>
<el-radio :value="0">此日
<el-icon>
<Right />
</el-icon>
</el-radio>
</el-radio-group>
<el-date-picker v-model="today" type="date" value-format="YYYY-MM-DD" style="width: 9rem;"
:size="aotuSize" @change="dateHandle" /> &nbsp;
<el-button type="primary" icon="RefreshRight" :size="aotuSize" @click="handleQuery">刷新</el-button>
</div>
</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">
<template #brxb="{ row }">
{{ formatDict(row.brxb, 'SX') }}
</template>
<template #nldw="{ row }">
{{ formatDict(row.nldw, 'AU') }}
</template>
<template #yblx="{ row }">
{{ formatDict(row.yblx, 'BT') }}
</template>
<template #ksdh="{ row }">
{{ formatDict(row.ksdh, 'DP') }}
</template>
<template #brly="{ row }">
{{ formatDict(row.brly, 'PT') }}
</template>
<template #zt="{ row }">
{{ formatDictzt(row.zt) }}
@cell-click="handleRowClick" size="small" keyField='applyid' :cell-style="sqdcellStyle"
:scrollYConfig="{ enabled: true, rSize: 30, height: '100%', }" class="mytable-style" ref="tableRef">
<template #status="{ row }">
{{ formatDict(row.status, 'SQDS') }}
</template>
</CustomVxeTable>
</div>
@ -110,118 +114,327 @@
</el-col>
</el-row>
<!-- 开单项目设置 -->
<SetBilling ref="setbilRef" @update="getXmList" />
</div>
</template>
<script setup>
<script setup name="Issueorder">
import Info from './components/info.vue'
import { getDictData, formatDict, dictData } from '@/hooks'
import { queryXmInfoList, saveReqInfo, queryPatList, queryPatDetail } from '@/api/liswork/order'
import { saveReqInfo, queryPatInfo } from '@/api/liswork/order'
import dayjs from 'dayjs'
import { ElMessage } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import { getFirstLetter } from '@/utils/pinyin';
import SetBilling from './components/setBilling.vue'
import { listregdict } from "@/api/regional/dict/regdict";
import { checkPrintService } from '@/utils/printHelper.ts';
import { listitemclass } from "@/api/regional/dict/itemclass";
import { classCom } from '@/utils/classCom';
import { useGroupTableData } from '@/utils/groupHelper'
const { proxy } = getCurrentInstance();
const { lis_req_type } = proxy.useDict("lis_req_type");
// import { initWebSocket, sendWebSocketMessage, closeWebSocket, getWebSocketState } from '@/utils/webSocket';
const aotuSize = classCom.useAutoSize();
const labpat = ref({
zt: '1'
ageUnit: '1'
})
const checkboxs = ref([])
const saveLoading = ref(false)
const searchKey = ref('')
const loading = ref(false)
const tableRef = useTemplateRef('tableRef')
const labPatList = ref([])
const queryParams = ref({})
const xmdlList = ref([])
const activeName = ref('')
const today = ref(dayjs().format('YYYY-MM-DD'))
// 记录初始数据(用于对比是否有变化)
const initialLabPat = ref({})
const initialSqxmCzList = ref([])
const searchForm = ref({
brxm: '',
status: '',
days: 3,
begdate: '',
enddate: '',
})
const tableColumns = ref([
{ field: 'brdh', title: '病历号', width: 80, align: 'center', resizable: true },
{ field: 'brxm', title: '姓名', width: 40, align: 'center', resizable: true, },
{ 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', slotName: 'zt', 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: 'sqsj', title: '登记时间', width: 80, align: 'center', resizable: true },
{ field: 'brly', title: '病人来源', width: 90, align: 'center', slotName: 'brly', resizable: true },
{ field: 'jymd', title: '项目', width: 90, align: 'center', resizable: true },
{ field: 'inputDate', title: '登记时间', width: 80, align: 'center', resizable: true },
{ field: 'rowSeq', title: 'No', width: 40, align: 'center', resizable: true },
{ field: 'patName', title: '姓名', width: 80, align: 'center', resizable: true, },
{ field: 'status', title: '状态', width: 80, align: 'center', slotName: 'status', resizable: true, },
{ field: 'userName', title: '登记人', width: 80, align: 'center', resizable: true },
{ field: 'reqDetailName', title: '项目', width: 200, align: 'center', resizable: true },
{ field: 'patId', title: '病人代号', align: 'center', width: 80, resizable: true },
])
const rowStyle = ({ row }) => {
}
const cellStyle = ({ row, column }) => {
}
const handleRowClick = (row) => {
queryPatDetail({ sqh: row.sqh }).then(res => {
labpat.value = res.data.labReqmain
labpat.value.brxb = labpat.value.brxb.trim()
labpat.value.zt = labpat.value.zt.trim()
sqXmList.value = res.data.reqInputLisWorkVOList
checkboxs.value = res.data.reqInputLisWorkVOList.map(item => item.sfxmdh)
})
}
const handleQuery = () => {
queryParams.value.begdate = dayjs(queryParams.value.begdate).format('YYYY-MM-DD') + ' 00:00:00'
queryParams.value.enddate = dayjs(queryParams.value.enddate).format('YYYY-MM-DD') + ' 23:59:59'
queryPatList(queryParams.value).then(res => {
labPatList.value = res.data
})
}
const saveHandle = () => {
if (!labpat.value.brdh) return ElMessage.warning('病人代号不能为空!')
if (!labpat.value.yblx) return ElMessage.warning('样本类型不能为空!')
if (!sqXmList.value.length) return ElMessage.warning('请选择项目!')
const data = {
labReqmain: labpat.value,
reqInputLisWorkVOList: sqXmList.value
const sqdcellStyle = ({ row, column }) => {
if (column.title == "状态") {
return {
backgroundColor: getColor(row.status),
// color: ,
}
}
}
const getColor = (type) => {
switch (type) {
case '10':
return '';
case '20':
return ' rgba(238, 8, 8, 0.25)';
case '30':
return 'rgba(0, 128, 0, 0.25)';
case '40':
return 'rgba(255, 165, 0, 0.25)';
case '50':
return 'rgba(255, 165, 0, 0.25)';
default:
return 'rgba(40, 189, 187, 0.25)';
}
}
const deepClone = (data) => {
return JSON.parse(JSON.stringify(data))
}
// 更新初始数据(在新增/加载数据时调用)
const updateInitialData = () => {
initialLabPat.value = deepClone(labpat.value)
initialSqxmCzList.value = deepClone(sqxmCzList.value)
}
// 判断数据是否有变化
const isDataChanged = () => {
const labPatChanged = JSON.stringify(labpat.value) !== JSON.stringify(initialLabPat.value)
const sqxmChanged = JSON.stringify(sqxmCzList.value) !== JSON.stringify(initialSqxmCzList.value)
return labPatChanged || sqxmChanged
}
const rowInfo = ref({})
const visbileMask = ref(false)
const handleRowClick = ({ row }) => {
rowInfo.value = row
if (!row?.applyid) return
// queryReqDetail({ applyId: row.applyid }).then(res => {
// labpat.value = res.data.regApply
// visbileMask.value = res.data.regApplyDetailList.some(item => { return item.status > 10 })
// sqXmList.value = res.data.regApplyDetailList.map(item => ({
// itemcode: item.orderItemCode,
// itemname: item.orderItemName,
// itemclass_yblx: item.sampleTypeName,
// amount: item.amount,
// applyid: item.applyid,
// uid: item.uid,
// classid: item.classid,
// barcode: item.barcode,
// itemclass: item.itemclass,
// itemclass_tips: item.itemclass_tips,
// status: item.status,
// }))
// // 异步初始化数据
// nextTick(() => {
// setTimeout(() => {
// updateInitialData()
// }, 10);
// })
// })
}
const changeDays = (val) => {
if (val == 3) {
searchForm.value.begdate = dayjs().subtract(3, 'day').format('YYYY-MM-DD') + ' 00:00:00'
searchForm.value.enddate = dayjs().format('YYYY-MM-DD') + ' 23:59:59'
} else if (val == 7) {
searchForm.value.begdate = dayjs().subtract(7, 'day').format('YYYY-MM-DD') + ' 00:00:00'
searchForm.value.enddate = dayjs().format('YYYY-MM-DD') + ' 23:59:59'
} else {
searchForm.value.begdate = dayjs(today.value).format('YYYY-MM-DD') + ' 00:00:00'
searchForm.value.enddate = dayjs(searchForm.value.begdate).format('YYYY-MM-DD') + ' 23:59:59'
}
handleQuery()
}
const dateHandle = (val) => {
searchForm.value.begdate = dayjs(val).format('YYYY-MM-DD') + ' 00:00:00'
searchForm.value.enddate = dayjs(searchForm.value.begdate).format('YYYY-MM-DD') + ' 23:59:59'
handleQuery()
}
const handleQuery = () => {
rowInfo.value = {}
// queryRegRequestInfo(searchForm.value).then(res => {
// // 数据分组
// const { tableData } = useGroupTableData(
// res.data,
// 'orderDate', // 分组字段
// ['inputDate',], // 仅第一条显示的字段
// 'orderDate', // 排序字段
// ['orderDate'],//原数据赋值对应字段
// )
// labPatList.value = tableData.value
// const item = res.data.find(item => item.patId == labpat.value.patId)
// nextTick(() => {
// tableRef.value.setCurrentRow(item)
// handleRowClick({ row: item })
// })
// })
}
// 获取病人代号查询信息
const getBrdhHandle = (val) => {
queryPatInfo({ patId: val }).then(res => {
if (res.data) {
labpat.value = res.data
}
})
}
//保存
const saveHandle = () => {
if (!labpat.value.patId) return ElMessage.warning('病人代号不能为空!')
if (!labpat.value.patName) return ElMessage.warning('病人姓名不能为空!')
if (!labpat.value.patSex) return ElMessage.warning('病人性别不能为空!')
if (!labpat.value.patAge || !labpat.value.ageUnit) return ElMessage.warning('病人年龄不能为空!')
if (!sqXmList.value.length) return ElMessage.warning('请选择项目!')
labpat.value.status = labpat.value.status ? labpat.value.status : ''
const data = {
regApply: labpat.value,
regApplyDetailList: sqxmCzList.value.map(item => ({
orderItemCode: item.itemcode,
orderItemName: item.itemname,
sampleTypeCode: item.itemclass_yblx,
sampleTypeName: item.itemclass_yblx,
amount: item.amount,
applyid: labpat.value.applyid,
uid: item.uid
}))
}
saveLoading.value = true
saveReqInfo(data).then(res => {
handleQuery()
if (res.code == 0) {
ElMessage.success('保存成功!')
handleQuery()
updateInitialData()
}
}).finally(() => {
saveLoading.value = false
})
}
const addHandle = () => {
labpat.value = {
zt: '1'
ageUnit: '1'
}
sqXmList.value = []
visbileMask.value = false
updateInitialData()
}
const deleteHandle = () => {
// if (!rowInfo.value.applyid) return ElMessage.warning('请选择要作废的申请单!')
// ElMessageBox.confirm('确定要作废此申请单吗?', '提示', {
// confirmButtonText: '确定',
// cancelButtonText: '取消',
// type: 'warning',
// }).then(() => {
// cancelReq({ applyId: rowInfo.value.applyid }).then(res => {
// if (res.code == 0) {
// ElMessage.success(res.msg)
// handleQuery()
// }
// })
// }).catch(() => { })
}
// 更新列配置
const handleColumnDragEnd = (data) => {
const printLoading = ref(false)
const printHandle = () => {
if (isDataChanged()) {
ElMessageBox.confirm('数据已修改,请先保存后再打印!', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
saveHandle()
}).catch(() => { })
return
}
const selectList = xmRef.value.allSelection()
tableColumns.value = [];
let arr = selectList.map(item => {
return {
applyId: item.applyid,
barcode: item.barcode,
}
})
const uniqueData = [];
const tempObj = {}; // 记录已出现的 barcode
nextTick(() => {
tableColumns.value = [...data.columns];
arr.forEach(item => {
// 若 tempObj 中无该 barcode,则保留并记录
if (!tempObj[item.barcode]) {
tempObj[item.barcode] = true;
uniqueData.push(item);
}
});
if (!uniqueData.length) return ElMessage.warning('请选择要打印的条码!')
checkPrintService().then((isConnected) => {
if (!isConnected) return
printLoading.value = true
// reqPrint(uniqueData).then(res => {
// if (res.code == 0) {
// sendWebSocketMessage(res.data)
// handleRowClick({ row: rowInfo.value })
// ElMessage.success('正在打印中...')
// handleQuery()
// }
// }).finally(() => {
// printLoading.value = false
// })
})
}
const filterData = ref([])
const xmColumns = ref([
{ field: 'sflbmc', title: '类别', align: 'center', resizable: true },
{ field: 'sfxmdh', title: '代号', align: 'center', resizable: true },
{ field: 'sfxmmc', title: '简称', align: 'center', width: 150, resizable: true },
{ field: 'dj', title: '单价', align: 'center', resizable: true },
{ field: 'spec', title: '规格', align: 'center', resizable: true },
{ field: 'yblx', title: '样本', align: 'center', resizable: true },
{ field: 'itemcode', title: '代号', align: 'center', resizable: true },
{ field: 'itemname', title: '项目名称', align: 'center', width: 280, resizable: true },
{ field: 'price', title: '单价', align: 'center', resizable: true },
{ field: 'itemclass', title: '类别', align: 'center', slotName: 'itemclass', resizable: true },
{ field: 'itemclass_tips', title: '采样提示', align: 'center', resizable: true },
{ field: 'itemclass_yblx', title: '样本', align: 'center', resizable: true },
])
const setbilRef = useTemplateRef('setbilRef')
const BillingHandle = () => {
setbilRef.value.open()
const xmcellStyle = ({ row, column }) => {
if (column.title == "类别") {
const bkcolor = itemclassList.value.find((item) => item.itemclassCode == row.itemclass)?.itemclassBkcolor;
const bgColor = classCom.decimalToHexColor(bkcolor);
const textColor = classCom.getContrastTextColor(bgColor);
return {
backgroundColor: `${bgColor} !important`,
color: textColor,
};
}
}
const searchList = ref([])
const handleTabClick = (tab) => {
if (tab.paneName) {
const currentTab = xmdlList.value.find(item => item.dictCode === tab.paneName)
if (currentTab) {
searchList.value = processedTableData.value.filter(item => item.classid === currentTab.dictCode)
filterData.value = [...searchList.value]
}
} else {
searchList.value = [...processedTableData.value]
filterData.value = [...searchList.value]
}
}
const processedTableData = ref([])
@ -231,21 +444,21 @@ const filterDictData = () => {
if (!key) {
// 空搜索时显示全部预处理数据
filterData.value = resultList([...processedTableData.value])
filterData.value = [...searchList.value]
return;
}
filterData.value = resultList(processedTableData.value.filter((item) => {
filterData.value = searchList.value.filter((item) => {
const matchName = item.itemname.toString().toLowerCase().includes(key);
const matchLabel = item.pinyin.toString().toLowerCase().includes(key);
return matchLabel;
return matchLabel || matchName;
})
)
}
const processTableData = (data) => {
return data.map((item) => {
const pinyinMap = {};
pinyinMap['pinyin'] = getFirstLetter(item.sfxmmc).toLowerCase();
pinyinMap['pinyin'] = getFirstLetter(item.itemname).toLowerCase();
return { ...item, ...pinyinMap };
});
};
@ -253,72 +466,177 @@ const processTableData = (data) => {
const sqXmList = ref([])
const sqXmColumns = ref([
{ field: 'sflbmc', title: '类别', align: 'center', resizable: true },
{ field: 'sfxmdh', title: '代号', align: 'center', resizable: true },
{ field: 'sfxmmc', title: '简称', align: 'center', width: 150, resizable: true },
{ field: 'dj', title: '单价', align: 'center', resizable: true },
{ field: 'spec', title: '规格', align: 'center', resizable: true },
{ field: 'yblx', title: '样本', align: 'center', resizable: true },
{ field: 'zt', title: '状态', align: 'center', resizable: true, slotName: 'zt' },
{ type: 'selection', field: '', title: '', resizable: true, align: 'center', width: 40 },
{ field: 'newitemclass', title: '类别', align: 'center', slotName: 'newitemclass', resizable: true },
{ field: 'newitemclass_tips', title: '采样提示', align: 'center', width: 60, resizable: true },
{ field: 'itemname', title: '项目名称', align: 'center', resizable: true, width: 220, },
{ field: 'newbarcode', title: '条码号', align: 'center', width: 120, resizable: true, },
{ field: 'amount', title: '单价', align: 'center', width: 60, resizable: true },
{ field: 'itemclass_yblx', title: '样本', width: 80, slotName: 'itemclass_yblx', resizable: true },
{ field: 'status', title: '状态', align: 'center', resizable: true, width: 80, slotName: 'status' },
])
const handleChecksChange = (val) => {
console.log('val==>', val);
sqXmList.value = []
val.forEach(item => {
const existingItem = processedTableData.value.find((row) => row.sfxmdh == item)
if (existingItem) {
sqXmList.value.push(existingItem)
const cellStyle = ({ row, column }) => {
if (column.title == "类别" && row.newitemclass) {
const bkcolor = itemclassList.value.find((item) => item.itemclassCode == row.itemclass)?.itemclassBkcolor;
const bgColor = classCom.decimalToHexColor(bkcolor);
const textColor = classCom.getContrastTextColor(bgColor);
return {
backgroundColor: `${bgColor} !important`,
color: textColor,
};
}
}
const getyblxData = (data, row) => {
sqXmList.value.forEach(item => {
if (row.uid == item.uid) {
item.itemclass_yblx = data.label
}
})
}
const dbRowclick = ({ row }) => {
const index = sqXmList.value.findIndex((item) => item.sfxmdh == row.sfxmdh)
if (index > -1) {
// 已申请的项目
const sqxmCzList = computed(() => {
// 数据分组
const { tableData } = useGroupTableData(
sqXmList.value,
['itemclass', 'barcode'],
['newitemclass', 'newbarcode', 'newitemclass_tips'],
'orderDate',
['itemclass', 'barcode', 'itemclass_tips'],
)
return tableData.value
})
watch(
sqxmCzList,
() => {
nextTick(() => {
// 等待 DOM 渲染完成后执行勾选
sqxmCzList.value.forEach(item => {
if (item.status < 30) {
xmRef.value.toggleRowSelection(item, true)
}
});
});
},
{ deep: true, immediate: true }
);
const barcodes = computed(() => {
return Array.from(new Set(sqxmCzList.value.map(item => item.barcode))).length
})
const totalAmount = computed(() => {
return sqxmCzList.value.reduce((total, item) => {
return total + (item.amount || 0);
}, 0)
})
const tableConfig = ref({
actionWidth: 60,
// 复选框配置
checkboxConfig: {
// 可选配置项
checkField: 'checked', // 绑定数据中的字段(默认:checked)
range: false, // 是否支持范围选择(按住 Shift 连续选择)
disabled: false, // 是否禁用全部复选框
reserve: false, // 是否保留勾选状态(分页/筛选时)
highlight: false, // 是否高亮选中行
checkMethod: ({ row }) => {
//标本送检之前状态才能勾选
return row.status < 30;
}
}
})
const xmRef = useTemplateRef('xmRef')
const selectionChange = (checked, row, selection) => {
// console.log('==>', checked, row, selection);
sqxmCzList.value.forEach(item => {
if (row.barcode === item.barcode && row.status < 30) {
xmRef.value.toggleRowSelection(item, checked)
}
});
}
const delItem = (row) => {
const index = sqXmList.value.findIndex(item => item.itemcode === row.itemcode)
if (index !== -1) {
sqXmList.value.splice(index, 1)
}
}
const dbRowclick = ({ row }) => {
if (visbileMask.value) return ElMessage.warning('申请单已审核,不能添加项目!')
const index = sqXmList.value.findIndex(item => item.itemcode == row.itemcode)
if (index > -1) {
ElMessage.warning('已存在该项目')
return
}
sqXmList.value.push({ ...row, amount: row.price })
}
const getXmList = () => {
queryXmInfoList().then(res => {
processedTableData.value = processTableData(res.data);
filterData.value = resultList([...processedTableData.value])
})
// getXmItemInfo().then(res => {
// processedTableData.value = processTableData(res.data);
// filterData.value = [...processedTableData.value]
listregdict({ dictType: 'CLASS' }).then(response => {
xmdlList.value = response.rows;
xmdlList.value.unshift({ dictCode: '', dictName: '全部' })
activeName.value = xmdlList.value.length > 0 ? xmdlList.value[0].dictCode : '';
handleTabClick({ paneName: activeName.value });
});
// })
}
//数据分类
const resultList = (arr) => {
const categoryList = Array.from(new Set(arr.map(item => item.sflbmc))).map(v => {
return {
sflbmc: v,
children: []
}
})
categoryList.forEach(item => {
arr.forEach(v => {
if (item.sflbmc == v.sflbmc) {
item.children.push(v)
}
})
})
return categoryList
}
const formatDictzt = (value) => {
const item = lis_req_type.value.find(i => i.value === value.trim());
return item ? item.label : value;
const itemclassList = ref([]) // 容器类别
const initSocket = () => {
initWebSocket({
fullUrl: `ws://localhost:9801`,
onOpen: () => {
console.log('WebSocket连接成功');
},
onMessage: (data) => {
console.log(`收到消息: `, JSON.parse(data));
},
onError: (error) => {
console.log(`连接错误: ${error.type}`);
},
onClose: () => {
console.log('WebSocket连接已关闭');
},
reconnectInterval: 3000 // 重连间隔(毫秒)
});
}
onMounted(() => {
queryParams.value.begdate = dayjs().format('YYYY-MM-DD')
queryParams.value.enddate = dayjs().format('YYYY-MM-DD')
getXmList()
getDictData('PT', 'SX', 'AU', 'BT', 'DP', 'SRD', 'ZJLX')
changeDays(3)
getDictData('PT', 'SX', 'AU', 'ZT', 'ZJLX', 'DEPT', 'DOCTOR', 'SLZQ', 'BT', 'SQDS')
listitemclass({ pageSize: 9999, pageNum: 1 }).then(response => {
itemclassList.value = response.rows;
})
// 初始化初始值
updateInitialData()
// initSocket()
})
// 页面卸载时清理
onUnmounted(() => {
// closeWebSocket();
});
</script>
<style scoped lang="scss">
@ -343,7 +661,8 @@ onMounted(() => {
}
.table-box {
height: calc(100% - 60px);
margin-top: 2px;
height: calc(100% - 85px);
}
.el-form-item {
@ -356,7 +675,6 @@ onMounted(() => {
}
.xmBoxs {
:deep(.el-checkbox__label) {}
height: 60%;
overflow-y: auto;
@ -378,9 +696,36 @@ onMounted(() => {
font-weight: 600;
}
.yblxtext {
font-style: 15px;
color: #123d64;
font-weight: 600;
text-align: center;
}
.title {
font-size: 14px;
color: #000;
font-weight: 700;
}
.radio_box {
display: flex;
align-items: center;
margin: .125rem 0;
.el-radio {
margin-right: .3125rem;
:deep(.el-radio__label) {
padding-left: .3125rem;
}
}
}
.col_box {
.el-button+.el-button {
margin-left: .5rem;
}
}
</style>

View File

@ -117,11 +117,10 @@ import { ElMessage, ElMessageBox } from 'element-plus';
import { getFirstLetter } from '@/utils/pinyin';
import { queryOldxminfo } from '@/api/liswork/xtwh/xmReqItemVsApi'
import { template } from 'lodash';
import { templateRef } from '@vueuse/core';
const queryParams = ref({
rptunitid: '46',
});
const customTableRef = templateRef('customTableRef');
const customTableRef = useTemplateRef('customTableRef');
const dialogVisible = ref(false);
const checkrulesText = ref('')
const ruledisplayText = ref('')

View File

@ -6,44 +6,39 @@
<template>
<div class="app-container">
<el-form :model="queryForm" class="query-form" label-width="6rem" inline>
<el-row>
<el-form-item label="病人代号:">
<el-input v-model="queryForm.brdh" />
</el-form-item>
<el-form-item label="病人姓名:">
<el-input v-model="queryForm.brxm" />
</el-form-item>
<el-form-item label="申请号:">
<el-input v-model="queryForm.sqh" />
</el-form-item>
<el-form-item label="科室病区:">
<SelectTable v-model:data="queryForm.ksdh" :tableData="dictData.DP" placeholder="" style="width: 12rem;" />
</el-form-item>
<el-form-item label="病人来源:">
<SelectTable v-model:data="queryForm.brly" :tableData="dictData.PT" placeholder="" @getDataValue=""
width="12rem" />
</el-form-item>
<el-form :model="queryForm" class="query-form" label-width="100px" inline>
<el-form-item label="病人代号:">
<el-input v-model="queryForm.brdh" />
</el-form-item>
<el-form-item label="病人姓名:">
<el-input v-model="queryForm.brxm" />
</el-form-item>
<el-form-item label="申请号:">
<el-input v-model="queryForm.sqh" />
</el-form-item>
<el-form-item label="科室病区:">
<SelectTable v-model:data="queryForm.ksdh" :tableData="dictData.DP" placeholder="" style="width: 12rem;" />
</el-form-item>
<el-form-item label="病人来源:">
<SelectTable v-model:data="queryForm.brly" :tableData="dictData.PT" placeholder="" @getDataValue=""
width="12rem" />
</el-form-item>
<el-form-item label="批准/联系人:" label-width="100">
<el-input v-model="queryForm.powerman" />
</el-form-item>
<el-form-item label="申请日期:">
<el-date-picker v-model="queryForm.st" type="date" placeholder="开始日期" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" style="width:9rem" /> &nbsp;- &nbsp;
<el-date-picker v-model="queryForm.et" type="date" placeholder="结束日期" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" style="width:9rem" />
</el-form-item>
<el-form-item label="批准/联系人:">
<el-input v-model="queryForm.powerman" />
</el-form-item>
<el-form-item label="申请日期:">
<el-date-picker v-model="queryForm.st" type="date" placeholder="开始日期" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" style="width:9rem" /> &nbsp;- &nbsp;
<el-date-picker v-model="queryForm.et" type="date" placeholder="结束日期" format="YYYY-MM-DD"
value-format="YYYY-MM-DD" style="width:9rem" />
</el-form-item>
<el-form-item label-width="10">
<el-button type="primary" @click="handleQuery">查询</el-button>
<el-button type="warning">导出</el-button>
</el-form-item>
</el-row>
</el-form>
<div class="mb5">
<el-button type="primary" icon="search" @click="handleQuery">查询</el-button>
<el-button type="warning" icon="Printer" plain>导出</el-button>
</div>
<div style="height: calc(100vh - 280px);" class="mt10">
<CustomTable ref="tableRefs" :data="tableData" :columns="columns" :config="tableConfig" :pagination="pagination"
@size-change="sizeChange" @page-change="currentChange">
@ -137,8 +132,6 @@ import { queryValue } from '@/api/liswork/xtwh/ComOpt'
import { ElMessage } from 'element-plus';
import { listUser } from '@/api/system/user.js'
import { checkYsUser } from '@/api/liswork/work/LisWork'
import { templateRef } from '@vueuse/core';
import { Select } from 'vxe-pc-ui';
// @ts-ignore
const { proxy } = getCurrentInstance();
const { lis_req_type } = proxy.useDict("lis_req_type");
@ -227,7 +220,7 @@ const tjConfirm = () => {
}
})
}
const formRef = templateRef('formRef')
const formRef = useTemplateRef('formRef')
const handleConfirm = async () => {
if (!formRef.value) return;

View File

@ -10,7 +10,7 @@
<!-- 顶部工具栏 -->
<div class="toolbar">
<el-button icon="EditPen" type="primary">调整</el-button>
<el-button icon="Document" type="primary">保存</el-button>
<el-button icon="Check" type="success">保存</el-button>
<el-button icon="CirclePlus" type="primary">读取</el-button>
<el-button icon="Delete" type="danger">删除</el-button>
<el-button type="danger">删除全部</el-button>

View File

@ -23,8 +23,9 @@
<SelectTable v-model:data="formData.brly" :fields="fields" width="150px" dict-type="PT" />
</el-form-item>
<el-form-item label="标本日期:" prop="jyrq">
<el-date-picker v-model="formData.jyrq1" type="date" style="width: 150px;" />&nbsp;-&nbsp;
<el-date-picker v-model="formData.jyrq2" type="date" style="width: 150px;" />
<el-date-picker v-model="formData.jyrq1" type="date" style="width: 150px;"
value-format="YYYY-MM-DD" />&nbsp;-&nbsp;
<el-date-picker v-model="formData.jyrq2" type="date" style="width: 150px;" value-format="YYYY-MM-DD" />
</el-form-item>
<el-form-item label="标本号:" prop="ybh">
<el-input placeholder="开始标本号" v-model="formData.ybh1" style="width: 120px;" /> &nbsp;-&nbsp;
@ -40,9 +41,9 @@
</el-form-item>
</el-form>
<div class="mb5">
<el-button type="primary" @click="getList">查询</el-button>
<el-button type="primary" :disabled="!multiple" @click="checkData">批量审核</el-button>
<el-button type="primary" :disabled="!multiple" @click="cancelCheck">取消审核</el-button>
<el-button type="primary" icon="Search" @click="getList">查询</el-button>
<el-button type="primary" icon="DocumentChecked" plain :disabled="!multiple" @click="checkData">批量审核</el-button>
<el-button type="primary" icon="DocumentDelete" plain :disabled="!multiple" @click="cancelCheck">取消审核</el-button>
</div>
<div class="table-container">
<el-row :gutter="10">
@ -98,9 +99,9 @@ import LabResult from './LabResult.vue';
import LabResultMed from './LabResultMed.vue';
import { getGroupInstrdList } from '@/api/liswork/work/LisWork';
import { useCommonStore } from '@/store/modules/commonStore';
import { ElMessage } from 'element-plus';
const tableRef = ref();
const msg = ref('') //审核后结果显示
const tableData = ref([])
const userStore = useUserStore()
const commonStore = useCommonStore()
@ -192,16 +193,10 @@ const checkData = async () => {
ybh: item.ybh,
}))
if (!paramList.length) {
msg.value = '请先选择要审核的行'
return
}
loading.value = true
const ret = await batchCheckService(paramList)
if (ret && ret.code === 200) {
msg.value = '批量审核成功:' + ret.msg
} else {
msg.value = '批量审核失败:' + ret.msg
ElMessage.success('批量审核成功')
}
getList()
loading.value = false
@ -221,9 +216,7 @@ const cancelCheck = async () => {
loading.value = true
const ret = await cancelBatchCheckService(paramList)
if (ret.code === 200) {
msg.value = '取消审核成功:' + ret.msg
} else {
msg.value = '取消审核失败:' + ret.msg
ElMessage.success('取消审核成功')
}
getList()
loading.value = false

View File

@ -10,7 +10,7 @@
<div class="header-toolbar">
<div class="button-group">
<el-button type="primary" icon="Plus" @click="handleAdd">新增</el-button>
<el-button type="success" icon="Document" @click="handleSave">保存</el-button>
<el-button type="success" icon="Check" @click="handleSave">保存</el-button>
</div>
</div>
@ -19,15 +19,17 @@
<div class="left-panel">
<el-form label-width="80px" :model="formData">
<el-form-item label="检验仪器">
<YQSelectTable v-model:data="formData.yq" width="100%" clearable />
<YQSelectTable v-model:data="formData.yq" width="100%" clearable @get-data-value="getYqValue" />
</el-form-item>
<el-form-item label="输入模板">
<el-select v-model="formData.template" style="width: 100%" placeholder="" />
<el-select v-model="formData.mbmc" style="width: 100%" placeholder="" @change="getDetails" clearable>
<el-option v-for="item in templateList" :key="item.mbmc" :label="item.mbmc" :value="item.mbmc" />
</el-select>
</el-form-item>
<el-form-item label="标本日期">
<el-date-picker v-model="formData.jyrq" type="date" format="YYYY/MM/DD" value-format="YYYY/MM/DD"
<el-date-picker v-model="formData.jyrq" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
style="width: 100%" />
</el-form-item>
@ -42,19 +44,19 @@
<!-- 检验项目表格 -->
<el-table :data="testItems" border height="50vh" class="test-item-table">
<el-table-column label="检验项目" prop="testItem" width="300">
<el-table-column label="检验项目" prop="xmdh" width="300">
<template #default="{ row, $index }">
<el-input v-model="row.testItem" class="full-width-input" @dblclick="dbHandle($index)" />
<el-input v-model="row.xmmczh" class="full-width-input" readonly @dblclick="dbHandle($index)" />
</template>
</el-table-column>
<el-table-column label="检验结果" prop="result">
<template #default="{ row }">
<el-input v-model="row.result" class="full-width-input" @keydown="nextResult" />
<el-input v-model="row.mrz" class="full-width-input" @keydown="nextResult" />
</template>
</el-table-column>
<el-table-column label="操作" width="80px">
<el-table-column label="操作" width="80px" align="center">
<template #default="{ row, $index }">
<el-button type="danger" text @click="handleDelete($index)">删除</el-button>
<el-button type="primary" link icon="Delete" @click="handleDelete($index)">删除</el-button>
</template>
</el-table-column>
</el-table>
@ -65,7 +67,7 @@
<!-- 说明文字 -->
<div class="description-box">
<p class="desc-title">说明:</p>
<p>标本号可以输入如:1,2,5-6等格式,结果区域最后一行回车可直接新增检验项目不输入直接回车能够存盘, 存盘后标本号自动递增,存盘后检验结果自动清除</p>
<p>标本号可以输入如:1,2,5-6等格式,结果区域最后一行回车可直接新增检验项目, 存盘后标本号自动递增,存盘后检验结果自动清除。</p>
</div>
<div class="text-area-box">
@ -81,29 +83,87 @@
</template>
<script setup lang="ts">
import { getInputMdl, getInputMdlDetail, confirmInputMdl } from '@/api/batch'
import YQSelectTable from '@/components/SelectTable/YQSelectTable/index.vue'
import dayjs from 'dayjs'
import ProjectDetails from "@/components/projectDetails/index.vue";
import { useCommonStore } from '@/store/modules/commonStore';
import { ElMessage } from 'element-plus';
const mbStore = useCommonStore();
const textresult = ref('')
// 表单数据
const formData = reactive({
yq: mbStore.defaultConfig.defaultinstr || '1',
template: '',
jyrq: dayjs().format('YYYY/MM/DD'),
mbmc: '',
jyrq: dayjs().format('YYYY-MM-DD'),
yblx: '',
ybh: '1'
})
// 检验项目表格数据
const testItems = ref<Array<{ testItem: string; result: string }>>([])
const testItems: any = ref([])
const handleAdd = () => {
testItems.value.push({ testItem: '', result: '' })
testItems.value.push({ xmmczh: '', mrz: '' })
}
const handleSave = () => {
const flag = testItems.value.every(item => item.xmmczh && item.mrz)
if (!flag) return ElMessage.error('请完整填写项目结果!')
const data = {
...formData,
jyrq: dayjs(formData.jyrq).format('YYYY-MM-DD 00:00:00'),
labInputmdlDetailList: testItems.value.map((item, i) => ({
xmmc: item.xmmc,
xmdh: item.xmdh,
mrz: item.mrz,
yq: formData.yq,
mbmc: formData.mbmc,
xh: i + 1
}))
}
confirmInputMdl(data).then((res) => {
// 存盘成功
if (res.code == 0) {
textresult.value = res.data.join('\n')
getDetails()
formData.ybh = getNextSampleNo()
}
}).catch(() => {
// 存盘失败
})
}
// 获取下一个标本号
const getNextSampleNo = () => {
const allNumbers: any = []
// 按逗号拆分每一段
const segments = formData.ybh.split(',')
// 遍历每一段
for (const seg of segments) {
const item = seg.trim()
if (!item) continue
// 判断是否是区间
if (item.includes('-')) {
const [start, end] = item.split('-').map(Number)
if (!isNaN(start)) allNumbers.push(start)
if (!isNaN(end)) allNumbers.push(end)
}
// 普通数字
else {
const num = Number(item)
if (!isNaN(num)) allNumbers.push(num)
}
}
if (allNumbers.length === 0) return ''
// 取最大值 +1
const max = Math.max(...allNumbers)
return (max + 1).toString()
}
const handleDelete = (index: number) => {
@ -123,9 +183,33 @@ const nextResult = (e: KeyboardEvent) => {
}
}
const getYqValue = (value: string) => {
formData.mbmc = ''
getMbList()
};
const templateList = ref<{ mbmc: string; }[]>([])
const getMbList = () => {
getInputMdl({ yq: formData.yq }).then((res) => {
templateList.value = res.data
})
};
const getDetails = () => {
getInputMdlDetail({ yq: formData.yq, mbmc: formData.mbmc }).then((res) => {
testItems.value = res.data.map((item) => ({
xmdh: item.xmdh,
xmmc: item.xmmc,
xmmczh: item.xmdh + ' ' + item.xmmc,
mrz: item.mrz,
xh: item.xh
}))
})
};
const handleItemSelect = (selectedItem) => {
console.log("selectedItem:", selectedItem)
testItems.value[rowIndex.value].testItem = selectedItem.label
testItems.value[rowIndex.value] = { xmdh: selectedItem.value, xmmc: selectedItem.label }
testItems.value[rowIndex.value].xmmczh = selectedItem.value + ' ' + selectedItem.label
};
</script>

View File

@ -51,6 +51,10 @@
</el-form-item>
</el-row>
</el-form>
<div>
<el-button type="primary" icon="search" @click="printHandle">查询</el-button>
<el-button type="warning" icon="Printer" plain @click="printHandle">打印</el-button>
</div>
</el-col>
<el-col :span="8" class="top-right-col">
<div class="option-panel">
@ -68,7 +72,7 @@
<div class="bottom-card mt10">
<div class="table-section">
<el-table :data="tableData" border style="width: 100%" height="50vh">
<el-table :data="tableData" border style="width: 100%" height="60vh">
<el-table-column label="样本号" prop="ybh" width="120" />
<el-table-column label="病人姓名" prop="brxm" width="120" />
<el-table-column label="病人类型" prop="brly" width="120" />
@ -78,10 +82,6 @@
</el-table>
</div>
</div>
<div class="action-buttons">
<el-button type="primary" @click="submitHandle">确定</el-button>
</div>
</div>
</template>
@ -144,7 +144,7 @@ const updateSelectedOptions = () => {
});
}
const submitHandle = () => {
const printHandle = () => {
}

View File

@ -8,17 +8,17 @@
<div class="table-toolbar mb5">
<el-row>
<el-col :span="8">
<el-button type="primary" plain @click="addHandle">新增</el-button>
<el-button type="warning" plain @click="editHandle">修改</el-button>
<el-button type="danger" plain @click="delBatch">删除</el-button>
<el-button type="primary" icon="Plus" plain @click="addHandle">新增</el-button>
<el-button type="info" icon="Edit" plain @click="editHandle">修改</el-button>
<el-button type="danger" icon="delete" plain @click="delBatch">删除</el-button>
</el-col>
<el-col :span="16">
<span class="tips">靶值列表</span> &nbsp;
<el-button type="primary" plain @click="dateClick">复制第一个开始日期到每个项目</el-button>
<el-button type="primary" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="primary" plain @click="copyBzHandle">复制靶值</el-button>
<el-button type="primary" icon="Brush" plain @click="copyBzHandle">复制靶值</el-button>
<el-button type="primary" plain @click="addBzHandle">新增靶值</el-button>
<el-button type="primary" plain @click="">计算</el-button>
<el-button type="primary" icon="Cpu" plain @click="">计算</el-button>
</el-col>
</el-row>
</div>
@ -37,7 +37,7 @@
<el-col :span="16" class="table-col">
<div style="height:59%" class="mb8">
<CustomVxeTable ref="topTableRef" class="mytable-style" :table-data="topTableData" :columns="topColumns"
:cell-render-delay="10" :loading="loading" @current-change="rowClick"
:cell-render-delay="0" :loading="loading" @current-change="rowClick" keyField='xmdh'
:scrollYConfig="{ enabled: true, rSize: 30, height: '100%', }">
<template #xmdh="{ row }">
{{ row.xmdh }} {{ row.xmmc }}
@ -63,13 +63,16 @@
style="width:100%" />
</template>
<template #ff="{ row }">
<SelectTable v-if="row.show" v-model:data="row.ff" :tableData="dictData.MD" placeholder=""
class="full-width-input" />
<template v-if="row.show">
<SelectTable v-model:data="row.ff" :tableData="dictData.MD" placeholder="" class="full-width-input" />
</template>
<span class="text_show" v-else @click="row.show = true">{{ formatDict(row.ff, 'MD') }}</span>
</template>
<template #sjph="{ row }">
<SelectTable v-if="row.show" v-model:data="row.sjph" :tableData="dictData.LOT" value="label"
objKey="label" placeholder="" class="full-width-input" />
<template v-if="row.show">
<SelectTable v-model:data="row.sjph" :tableData="dictData.LOT" value="label" objKey="label"
placeholder="" class="full-width-input" />
</template>
<span class="text_show" v-else @click="row.show = true">{{ row.sjph }}</span>
</template>
<template #qccv="{ row }">
@ -102,12 +105,11 @@
@close="handleDialogClose">
<el-form :model="formData" ref="queryRef" :rules="rules" label-position="right" label-width="auto">
<el-form-item label="仪器" prop="yq">
<span class="mr20"> {{ formData.yq }}</span>
<span class="mr20"> {{ yqmc }}</span>
<el-radio-group v-model="formData.useflag">
<el-radio value="1">在用</el-radio>
<el-radio value="0">停用</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="质控批号" prop="zkpph">
<el-input v-model="formData.zkpph" />
@ -194,17 +196,21 @@
<script setup lang="ts">
import { queryBatch, queryValXmdh, queryBatchXm, delBatchno, addBatchno, updateBatchno, saveBtQcSample, copyQcSample, delQcSample } from '@/api/liswork/qualityControl'
import { templateRef } from '@vueuse/core'
import { formatDict, getDictData, dictData } from '@/hooks';
import { ElMessage, ElMessageBox } from 'element-plus'
import YQSelectTable from '@/components/SelectTable/YQSelectTable/index.vue';
import dayjs from 'dayjs';
const props = defineProps({
yqmc: {
type: String,
default: ''
}
})
const yq = defineModel<string>()
const title = ref('新增批号')
const visible = ref(false)
const selectedRow: any = ref(null)
const queryRef = templateRef('queryRef')
const queryRef = useTemplateRef('queryRef')
const copyVisible = ref(false)
const copyFormData = ref({
yq: '',
@ -408,7 +414,7 @@ const handleCvEnter = (row: any) => {
row.sd = row.cv * row.zkbz / 100
}
const leftTableRef = templateRef('leftTableRef')
const leftTableRef = useTemplateRef('leftTableRef')
const getBatchList = () => {
batchInfo.value = null
loading.value = true
@ -426,7 +432,7 @@ const getBatchList = () => {
})
}
const topTableRef = templateRef('topTableRef')
const topTableRef = useTemplateRef('topTableRef')
const getXmList = (row: any) => {
topTableRef.value.setCurrentRow(row)
queryBatchXm({ yq: yq.value, zkpph: row.zkpph, zkph: row.zkph }).then((res: any) => {
@ -434,6 +440,8 @@ const getXmList = (row: any) => {
topTableData.value = res.data
if (topTableData.value.length) {
rowClick(topTableData.value[0])
} else {
bottomTableData.value = []
}
})
}

View File

@ -8,10 +8,10 @@
<div class="sys_box">
<el-row :gutter="10" class="table-toolbar">
<el-col :span="1.5">
<el-button type="primary" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="success" plain icon="Check" @click="handleSave">保存</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="Edit" @click="handleCancelEdit">取消修改</el-button>
<el-button type="info" plain icon="Edit" @click="handleCancelEdit">取消修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="RefreshRight" @click="handleRestoreDefault">还原默认</el-button>

View File

@ -6,7 +6,7 @@
<template>
<div class="app-container">
<div class="table-toolbar">
<el-button type="primary" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="success" plain icon="Check" @click="handleSave">保存</el-button>
</div>
<div class="tips">提示:左边的列表已经列出所有检验项目,请在质控项目前面打勾,右边是当前项目的质控规则</div>
<el-row :gutter="20" class="table-row">

View File

@ -6,7 +6,7 @@
<template>
<div class="app-container">
<div class="table-toolbar">
<el-button type="primary" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="success" plain icon="Check" @click="handleSave">保存</el-button>
</div>
<div class="tips">说明:1_2S作为一个警告规则,如果选中这个规则,则表示所有其他失控规则必须先满足说明:25,则视为在控。</div>
<div class="table-row" style="margin-top: 10px;">

View File

@ -6,9 +6,9 @@
<template>
<div class="app-container">
<div class="table-toolbar mb5">
<el-button type="primary" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="primary" @click="addItem">新增</el-button>
<el-button type="danger" @click="delItem">删除</el-button>
<el-button type="success" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="primary" icon="Plus" plain @click="addItem">新增</el-button>
</div>
<div class="table-row">
@ -17,10 +17,13 @@
<el-input v-model="row.ybh" class="full-width-input" />
</template>
<template #zkph="{ row }">
<el-input-number v-model="row.zkph" min="1" max="6" class="full-width-input" />
<el-input-number v-model="row.zkph" :min="1" :max="6" class="full-width-input" />
</template>
<template #cs="{ row }">
<el-input-number v-model="row.cs" min="1" max="7" class="full-width-input" />
<el-input-number v-model="row.cs" :min="1" :max="7" class="full-width-input" />
</template>
<template #action="{ row, $index }">
<el-button type="primary" link icon="Delete" @click="delItem(row, $index)">删除</el-button>
</template>
</CustomTable>
</div>
@ -35,21 +38,23 @@ const yq = defineModel<string>()
interface ybhItem {
ybh: string
zkph: string
cs: string,
zkph: string | number
cs: string | number,
yq?: string
}
const tableData = ref<ybhItem[]>([])
const columns = [
{ label: '普通标准号', prop: 'ybh', visible: true, align: 'center', slot: 'ybh' },
{ label: '对应质控品号', prop: 'zkph', visible: true, align: 'center', slot: 'zkph' },
{ label: '次数', prop: 'cs', visible: true, align: 'center', slot: 'cs' },
{ label: '普通标准号', prop: 'ybh', visible: true, align: 'center', slot: 'ybh', showOverflowTooltip: false },
{ label: '对应质控品号', prop: 'zkph', visible: true, align: 'center', slot: 'zkph', showOverflowTooltip: false },
{ label: '次数', prop: 'cs', visible: true, align: 'center', slot: 'cs', showOverflowTooltip: false },
]
const tableConfig = {
border: true,
highlightCurrentRow: true,
height: '100%'
height: '100%',
actionWidth: 120,
actionAlign: 'center',
}
const tableRef = ref()
const ybhInfo: any = ref(null)
@ -59,8 +64,8 @@ const rowYbhClick = (row: ybhItem) => {
const addItem = () => {
tableData.value.push({
ybh: '',
zkph: '1',
cs: '1',
zkph: 1,
cs: 1,
yq: yq.value,
})
nextTick(() => {
@ -68,9 +73,8 @@ const addItem = () => {
})
}
const delItem = () => {
if (!ybhInfo.value) return ElMessage.warning('请选择要删除的行')
deleteQcSample(ybhInfo.value).then((res: any) => {
const delItem = (row, index: number) => {
deleteQcSample(row).then((res: any) => {
if (res.code == 0) {
ElMessage.success('删除成功')
const index = tableData.value.findIndex(item => item == ybhInfo.value)

View File

@ -39,7 +39,8 @@
<el-tab-pane v-for="tab in tabList" :key="tab.key" :label="tab.label" :name="tab.key" />
</el-tabs>
<!-- 动态组件渲染 -->
<component :is="currentComponent" :key="activeName" v-model="queryParams.yq" @updateTree="getDeptTree" />
<component :is="currentComponent" :key="activeName" v-model="queryParams.yq" :yqmc="yqmc"
@updateTree="getDeptTree" />
</el-col>
</el-row>
</div>
@ -116,7 +117,7 @@ const tabList = [
{ key: 'SetSample', label: '质控品样本号对应', component: SetSample },
{ key: 'SetBatch', label: '质控品批号管理', component: SetBatch },
]
const activeName = ref('SetBatch')
const activeName = ref('SetRule')
// 计算当前要渲染的组件
const currentComponent = computed(() => {

View File

@ -23,7 +23,7 @@
</el-form-item>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="success" plain icon="Check" @click="handleSave">保存</el-button>
</el-col>
<el-col :span="5">
<span class="tips ml10">颜色说明:</span> <span class="color-red">大于3SD</span> <span

View File

@ -16,7 +16,7 @@
</el-form-item>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="success" plain icon="Check" @click="handleSave">保存</el-button>
</el-col>
<el-col :span="5">
<span class="tips ml10">颜色说明:</span> <span class="color-red">大于3SD</span> <span

View File

@ -34,8 +34,8 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button type="warning">打印</el-button>
<el-button type="primary" icon="Search" @click="handleSearch">查询</el-button>
<el-button type="warning" icon="Printer">打印</el-button>
</el-form-item>
</el-form>
</div>

View File

@ -11,19 +11,19 @@
@clear="sqdQuery" />
</el-col>
<el-col :span="1.5">
<el-button type="primary" @click="sqdQuery" plain>读取</el-button>
<el-button type="primary" icon="Memo" @click="sqdQuery" plain>读取</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain :disabled="RCV_AUTOSAVE == '1'" @click="saveHandle">保存</el-button>
<el-button type="success" plain icon="Check" :disabled="RCV_AUTOSAVE == '1'" @click="saveHandle">保存</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" @click="setHandle" plain>设置</el-button>
<el-button type="info" icon="Setting" @click="setHandle" plain>设置</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" @click="clearHandle" plain>清除</el-button>
<el-button type="danger" plain icon="Delete" @click="clearHandle">清除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain>打印</el-button>
<el-button type="warning" icon="Printer" plain>打印</el-button>
</el-col>
</el-row>

View File

@ -11,16 +11,16 @@
@clear="sqdQuery" />
</el-col>
<el-col :span="1.5">
<el-button type="primary" @click="sqdQuery" plain>读取</el-button>
<el-button type="primary" icon="Memo" @click="sqdQuery" plain>读取</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain @click="saveData">保存</el-button>
<el-button type="success" icon="Check" plain @click="saveData">保存</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain @click="clearData">清除</el-button>
<el-button type="danger" icon="Delete" plain @click="clearData">清除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="primary" plain>打印</el-button>
<el-button type="warning" icon="Printer" plain>打印</el-button>
</el-col>
</el-row>

View File

@ -2,7 +2,7 @@
<template>
<div class="app-container">
<div class="mb5">
<el-button type="primary" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="success" plain icon="Check" @click="handleSave">保存</el-button>
<el-button type="info" plain icon="Edit" @click="handleCancelEdit">取消修改</el-button>
<el-button type="danger" plain icon="RefreshRight" @click="handleRestoreDefault">还原默认</el-button>
</div>

View File

@ -106,8 +106,6 @@
import { ref, onMounted, onUnmounted } from 'vue'
import CountTo from '@/components/countTo/index.vue'
import dayjs from 'dayjs'
import { templateRef } from '@vueuse/core'
import { set } from 'lodash'
// 填充模拟数据(保持原有逻辑)
const list1 = ref([
{ dept: '1111', name: '张三', item: '血常规', time: '2024-05-20 08:15:30' },
@ -178,10 +176,10 @@ const tableRowStyle = ({ rowIndex }: { rowIndex: number }) => {
hover: 'rgba(0, 153, 255, 0.2)' // 悬浮行浅蓝高亮
}
}
const table1Ref = templateRef('table1Ref')
const table2Ref = templateRef('table2Ref')
const table3Ref = templateRef('table3Ref')
const table4Ref = templateRef('table4Ref')
const table1Ref = useTemplateRef('table1Ref')
const table2Ref = useTemplateRef('table2Ref')
const table3Ref = useTemplateRef('table3Ref')
const table4Ref = useTemplateRef('table4Ref')
// 封装滚动函数,接收表格ref和数据列表(用于判断是否需要刷新)
const createTableScroll = (tableRef: Ref, dataList: Ref) => {