700 lines
23 KiB
Vue
Raw Normal View History

2025-11-21 18:01:14 +08:00
<template>
<div>
<div>
<el-button class="btn_green btns_box" :size="aotuSize" v-if="labPat.jgbz != 2"
@click="handleCheck(2)">审核</el-button>
<el-button class="btns_box" :size="aotuSize" v-if="labPat.jgbz == 2" @click="handleCheck(3)">取消审核</el-button>
<el-button class="btns_box" type="primary" :size="aotuSize" plain
:disabled="labPat.jgbz != null && labPat.jgbz != 0" @click="openItemDictDialog">新增</el-button>
<el-button class="btns_box" type="danger" :size="aotuSize" :disabled="labPat.jgbz != null && labPat.jgbz != 0"
plain @click="handleBatchDelete">删除</el-button>
<el-button class="btn_green btns_box" :size="aotuSize" @click="zhHandel">组合项目</el-button>
</div>
<CustomTable ref="tableRef" :data="tableData" :columns="columns" :config="tableConfig" :enable-column-drag="true"
@column-drag-end="handleColumnDragEnd" @row-click="rowHandle">
<template #xmdh="{ column }">
细菌/结果({{ tableData.length }})项
</template>
<template #od="{ row }">
<el-input v-model="row.od" v-if="labPat.jgbz == 0 || labPat.jgbz == null" size="small"
class="full-width-input foucs-input" @change="handleCsjgEnter(row)" />
<span v-else>{{ row.od }}</span>
</template>
<template #csjg="{ row }">
<el-input v-model="row.csjg" v-if="labPat.jgbz == 0 || labPat.jgbz == null" size="small"
class="full-width-input" @change="handleCsjgEnter(row)" @dblclick="handleInputFocus(row)" />
<span v-else>{{ row.csjg }}</span>
</template>
<template #jgbz="{ row }">
<el-select v-model="row.jgbz" class="full-width-input" v-if="labPat.jgbz == 0 || labPat.jgbz == null"
@change="handleCsjgEnter(row)">
<el-option label="阳性" value="P" />
<el-option label="阴性" value="N" />
</el-select>
<span v-else> {{ formatJgbz(row.jgbz) }}</span>
</template>
<template #cutoff="{ row }">
<el-input v-model="row.cutoff" v-if="labPat.jgbz == 0 || labPat.jgbz == null" size="small"
class="full-width-input" @change="handleCsjgEnter(row)" />
<span v-else>{{ row.cutoff }}</span>
</template>
<template #alarm_flag="{ row }">
<el-select v-model="row.alarm_flag" class="full-width-input" v-if="labPat.jgbz == 0 || labPat.jgbz == null"
placeholder="" @change="handleCsjgEnter(row)">
<el-option label="危急值" value="H" />
<el-option label="无" value="" />
</el-select>
<span v-else> {{ row.alarm_flag == 'H' ? '危急值' : '' }}</span>
</template>
<template #germclass="{ row }">
{{ formatDict(row.germclass, 'germclass') }}
</template>
</CustomTable>
<div class="tabs_btns">
<el-tabs v-model="activeName2" type="card" class="demo-tabs" :size="aotuSize">
<el-tab-pane label="药敏结果" name="first">
<CustomTable :data="ymTableData" :columns="ymColumns" :config="ymTableConfig" :enable-column-drag="true"
@column-drag-end="ymHandleColumnDragEnd">
<template #ywdhHead="{ column }">
抗生素({{ ymTableData.length }})项
</template>
<template #jgbz="{ row }">
<el-radio-group v-model="row.jgbz">
<el-radio value="R">R</el-radio>
<el-radio value="I">I</el-radio>
<el-radio value="S">S</el-radio>
<el-radio value="N">N</el-radio>
<el-radio value="SDD">SDD</el-radio>
</el-radio-group>
</template>
</CustomTable>
</el-tab-pane>
<el-tab-pane label="专家评语" name="second">
<el-input v-model="textarea" style="width: 100%" :rows="20" type="textarea" />
</el-tab-pane>
</el-tabs>
<div class="btns anchor">
<template v-if="activeName2 == 'first'">
<el-button class="btns_box" type="primary" :size="aotuSize" plain
:disabled="labPat.jgbz != null && labPat.jgbz != 0">新增</el-button>
<el-button class="btns_box" type="danger" :size="aotuSize" :disabled="labPat.jgbz != null && labPat.jgbz != 0"
plain>删除</el-button>
<el-button type="primary" class="btns_box" plain :size="autoSize">更换抗生素组</el-button>
<el-button type="primary" class="btns_box" plain :size="autoSize">添加抗生素组</el-button>
</template>
<template v-if="activeName2 == 'second'">
<el-button type="primary" class="btns_box" plain :size="autoSize" @click="handleTextareaEnter">确定</el-button>
<el-button type="primary" class="btns_box" plain :size="autoSize" @click="textarea = ''">清除</el-button>
</template>
</div>
</div>
<!-- 新增明细 -->
<ProjectDetails ref="itemDictRef" :dialog-title="'选择检验项目'" :tableKey="labPatKey" @select="handleItemSelect" />
<!-- 测试结果项目常用结果选择 -->
<projectsJg ref="csjgRef" :tableData='csjgTableData' :dialog-title="'项目常用结果选择'" @selectItem="selectItem"
label="qz" />
<!-- 组合项目 -->
<Combined ref="combinedRef" :queryParams="labPatKey" @dbMbHandle="combinedHandel" />
<!-- 操作原因 -->
<el-dialog v-model="unCheckshow" title="操作原因" width="500" :close-on-click-modal="false" :draggable="true"
@close="unconfirmlogCancel">
<div class="dialog-body mb10">
<p class="reason-text mb5">{{ reasonText }} </p>
<el-form ref="uncheckFormRef" style="max-width: 600px" :model="uncheckForm" :rules="rules" label-width="auto">
<template v-if="labPatKey.problemId == 4">
<el-input type="textarea" v-model="uncheckForm.reason" class="reason-input" placeholder="请输入操作原因..."
:rows="4"></el-input>
</template>
<template v-if="labPatKey.problemId == 6">
<el-form-item label="用户工号:" prop="yhdh">
<el-input v-model.trim="uncheckForm.yhdh" placeholder="请输入用户工号" maxlength="20"
@keyup.enter="submitForm" />
</el-form-item>
<el-form-item label="密码:" prop="mm">
<el-input v-model.trim="uncheckForm.mm" placeholder="请输入密码" type="mm" maxlength="20" show-password
@keyup.enter="submitForm" />
</el-form-item>
</template>
</el-form>
</div>
<div style="text-align: center; width: 100%;">
<el-button type="primary" @click="unconfirmlogConfirm()"> 确认 </el-button>
<el-button @click="unconfirmlogCancel">取消</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup lang="ts">
import CustomTable from "@/components/elTable/index.vue";
import { classCom } from "@/utils/classCom";
import { getresultmedList, savetestResult, changeresult, saveresult, newresult, } from '@/api/liswork/micro/index';
import {
check1, check2, uncheck2, unconfirmlog, checkuser, reglimit, deleteresult, allPatquery, emrquery, datalink, changeLinkList,
viewBackup, queryXmVal, printListwork, getresultchangelog, setinputmdl, lockSample, unLockSample, clearnotComplete, clearPrintflag,
noiteMresult, queryXmInfo, setitemInter
} from "@/api/liswork/work/LisWork";
import { useCommonStore } from "@/store/modules/commonStore";
// @ts-ignore
import ProjectDetails from "@/components/projectDetails/index.vue";
import projectsJg from "@/components/projectsjg/index.vue"
import Combined from "./components/combinedDialog.vue";
import { ElMessage, ElMessageBox } from "element-plus";
import emitter from "@/utils/mitt";
const aotuSize = classCom.useAutoSize();
interface LabResultItem {
xmdh: string;
xmmc: string;
csjg: string;
qz: string;
[key: string]: any;
}
const props = defineProps({
labPat: {
type: Object,
required: true
},
//结果主键
labPatKey: {
type: Object,
default: () => { }
},
labResutsData: {
type: Array as PropType<LabResultItem[]>,
default: () => []
},
dictData: {
type: Object,
default: () => { }
}
});
const { labPat, labPatKey, labResutsData, dictData } = toRefs(props);
// 事件定义
const emits = defineEmits([
'fetchLabResults',
'changeStatus',
'previewHandle'
]);
const autoSize = classCom.useAutoSize();
const activeName2 = ref('first')
const textarea = ref('')
const columns = ref([
{ label: "细菌/结果", prop: "zhxmdh", align: 'center', visible: true, headerSlot: 'xmdh', width: 150 },
{ label: "菌落计数", prop: "od", align: 'center', visible: true, slot: 'od' },
{ label: "检验结果", prop: "csjg", align: 'center', visible: true, slot: 'csjg' },
{ label: "阴阳性", prop: "jgbz", align: 'center', visible: true, slot: 'jgbz', showOverflowTooltip: false },
{ label: "危急值", prop: "alarm_flag", align: 'center', visible: true, slot: 'alarm_flag', showOverflowTooltip: false },
{ label: "菌属", prop: "germclass", align: 'center', visible: true, slot: 'germclass' },
{ label: "鉴定率", prop: "cutoff", align: 'center', visible: true, slot: 'cutoff' },
{ label: "抗生素组", prop: "bz1", align: 'center', visible: true, width: 120 },
])
const CellStyleHd = ({ row, column, rowIndex, columnIndex }: {
row: any;
column: any;
rowIndex: number;
columnIndex: number;
}) => {
if (column.label == "细菌/结果" && (row.alarm_flag ?? "").trim().length > 0) {
return { background: '#f00 !important', color: '#FFF' };
}
if (column.label == "危急值" && (row.alarm_flag ?? "").trim().length > 0) {
return { background: '#f00 !important', color: '#FFF' };
}
if (column.label == "检验结果" && row.jgbz == "H") {
return { background: '#ffc0c0 !important', color: '#606266' };
}
if (column.label == "检验结果" && row.jgbz == "L") {
return { background: '#8080ff !important', color: '#fff' };
}
if (column.label == "检验结果" && row.jgbz == "P") {
return { background: '#ffc0c0 !important', color: '#606266' };
}
if (column.label == "检验结果" && row.jgbz == "Q") {
return { background: '#ffff80 !important', color: '#606266' };
}
if (column.label == "阴阳性" && row.jgbz == "H") {
return { background: '#ffc0c0 !important', color: '#606266' };
}
if (column.label == "阴阳性" && row.jgbz == "L") {
return { background: '#8080ff !important', color: '#fff' };
}
if (column.label == "阴阳性" && row.jgbz == "P") {
return { background: '#ffc0c0 !important', color: '#606266' };
}
if (column.label == "阴阳性" && row.jgbz == "Q") {
return { background: '#ffff80 !important', color: '#606266' };
}
};
const tableConfig = ref({
height: '24vh',
border: true,
highlightCurrentRow: true,
cellStyle: CellStyleHd
});
const handleColumnDragEnd = (data: any) => {
columns.value = data.columns;
}
const unCheckshow = ref(false);
const reasonText = ref('');
const warningMsgdata = ref('');
const showuploadwarning = ref(false);
const handleCheck = (checkType: number) => {
// yhdh = checkuserid.value
switch (checkType) {
// case 1: // 初审
// check1({ ...labPatKey.value, jyrq: labPat.value.jyrq, yhdh: props.labPat.yhdh }).then((res: any) => {
// emits("changeStatus", props.labPat);
// })
// break;
case 2: // 审核
labPatKey.value.problemId = 0
shHandleCheck()
break;
case 3: // 取消审核
labPatKey.value.problemId = 0
unShHandle()
break;
default:
break;
}
};
const shHandleCheck = () => {
check2({ ...labPatKey.value, jyrq: labPat.value.jyrq, yhdh: props.labPat.yhdh }).then((res: any) => {
emits("changeStatus", props.labPat);
if (res.code == "4" && res.problemId === 4) {
labPatKey.value.problemId = res.problemId;
warningMsgdata.value = res.msg;
showuploadwarning.value = true;
}
})
};
const unShHandle = () => {
uncheck2({ ...labPatKey.value, jyrq: labPat.value.jyrq, yhdh: props.labPat.yhdh }).then((res: any) => {
if (res.code == "4") {
labPatKey.value.problemId = res.problemId;
reasonText.value = res.msg;
unCheckshow.value = true;
}
emits("changeStatus", props.labPat);
})
};
const uncheckFormRef = ref();
const uncheckForm = ref({
reason: '',
yhdh: '',
mm: '',
})
// 取消审核原因
const unconfirmlogConfirm = async () => {
if (labPatKey.value.problemId == 4) {
// if (!uncheckForm.value.inputValue) return ElMessage.warning("请输入操作原因")
} else if (labPatKey.value.problemId == 6) {
const valid = await uncheckFormRef.value.validate().catch(() => { });
if (!valid) return false;
}
unconfirmlog({ ...labPatKey.value, jyrq: labPat.value.jyrq, ...uncheckForm.value }).then((response: any) => {
if (response.code == "0") {
unCheckshow.value = false;
unShHandle();
}
})
};
const checkuserid = ref()
const checkShow = ref(false);
const ruleForm = ref({
yhdh: '',
mm: ''
});
const rules = ref(
{
yhdh: [{ required: true, message: "请输入用户工号", trigger: "blur" },
{ min: 3, max: 20, message: "长度在 3 到 20 个字符", trigger: "blur" }
],
mm: [{ required: true, message: "请输入密码", trigger: "blur" },
{ min: 6, max: 20, message: "长度在 6 到 20 个字符", trigger: "blur" }
]
}
);
const unconfirmlogCancel = () => {
unCheckshow.value = false;
uncheckForm.value.reason = '';
uncheckForm.value.yhdh = '';
uncheckForm.value.mm = '';
uncheckFormRef.value.resetFields();
}
const ruleFormRef = ref();
const submitForm = () => {
ruleFormRef.value.validate((valid: boolean) => {
if (valid) {
checkuser(ruleForm.value).then((res: any) => {
if (res.code == 0) {
checkuserid.value = ruleForm.value.yhdh
checkShow.value = false;
ElMessage.success("验证成功");
}
})
} else {
return false;
}
});
}
const itemDictRef = ref();
const openItemDictDialog = () => {
itemDictRef.value.openDictSelector();
};
const handleItemSelect = async (selectedItem: any) => {
// 1. 构造新增行数据
const newRow = {
id: `temp_${Date.now()}_${Math.random().toString(36).substr(2, 8)}`,
xmdh: selectedItem.value,
xmmc: selectedItem.label,
dw: selectedItem.dw || "",
refs: selectedItem.refs || "",
jyrq: labPatKey.value.jyrq,
yq: labPatKey.value.yq,
ybh: labPatKey.value.ybh,
};
addRowFromDict(newRow);
// ElMessage.success(`已新增项目:${newRow.xmmc}`);
};
const selectedRows: any = ref([])
const tableRef = ref()
// 新增行核心方法:接收父组件传递的项目数据
const addRowFromDict = async (rowData: any) => {
if (!rowData.xmdh) return ElMessage.error("新增失败:项目编码不能为空");
const isDuplicate = tableData.value.some((item: any) => item.xmdh === rowData.xmdh);
if (isDuplicate) return ElMessage.warning(`项目【${rowData.xmmc}】已存在`);
const newRow = {
...rowData,
od: '',
csjg: "",
jgbz: "",
alarm_flag: '',
cutoff: '',
};
tableData.value.push(newRow);
// 5. 自动聚焦
nextTick(() => {
selectedRows.value = [newRow];
tableRef.value.setCurrentRow(newRow);
tableRef.value.setScrollTo(tableData.value.length - 1)
// 聚焦到新行的输入框
const inputs = Array.from(document.querySelectorAll('.foucs-input .el-input__inner'))
.filter(el => el instanceof HTMLElement) as HTMLElement[];
if (inputs.length > 0) {
inputs[inputs.length - 1].focus();
}
});
};
const handleBatchDelete = () => {
if (selectedRows.value.length === 0) return ElMessage.warning("请先选择要删除的记录");
const arr = selectedRows.value.filter((row: any) => !row.id);
ElMessageBox.confirm(
`确定要删除选中的 ${selectedRows.value.length} 条记录吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
if (arr.length == 0) {
const index = tableData.value.findIndex((item: any) => item.xmdh === selectedRows.value[0].xmdh);
if (index > -1) tableData.value.splice(index, 1);
selectedRows.value = [];
} else {
deleteresult(arr).then((res: any) => {
if (res.code == 0) {
ElMessage.success('删除成功');
emits('fetchLabResults');
}
})
}
}).catch(() => {
});
};
const mbStore = useCommonStore();
const tableData: any = ref([])
watch(labResutsData, (newVal: any) => {
if (newVal.length) {
tableData.value = newVal.map((item: any) => {
return {
...item,
zhxmdh: item.xmdh + ' ' + item.xmmc,
}
})
rowHandle(newVal[0])
textarea.value = newVal[0]?.textresult
} else {
textarea.value = ''
rowInfo.value = {}
tableData.value = []
}
if (props.labPat.jgbz != null && props.labPat.jgbz != 0 && props.labPat.jgbz != 'C') return;
// console.log('mbStore==>', mbStore.lxsrs);
if (mbStore.lxsrs.length > 0) {
mbStore.lxsrs.forEach((mbmc) => {
const data = {
...labPatKey.value,
mbmc: mbmc,
}
setinputmdl(data).then((res: any) => {
if (res.code == 0) {
const existingNames = new Set(tableData.value.map((item: any) => item.xmdh))
res.data?.forEach((item: any) => {
if (!existingNames.has(item.xmdh)) {
tableData.value.push({ ...item, jyrq: labPat.value.jyrq, zhxmdh: item.xmdh + ' ' + item.xmmc })
existingNames.add(item.xmdh)
}
})
emitter.emit('clearLxsrList')
}
});
});
}
})
const handleTextareaEnter = () => {
if (!rowInfo.value.xmdh) return
savetestResult({ ...rowInfo.value, textresult: textarea.value }).then((res: any) => {
if (res.code == 0) {
ElMessage.success('保存成功');
}
});
};
const rowInfo: any = ref({})
const rowHandle = (row: any) => {
selectedRows.value = [row];
emitter.emitWithCache('refreshClinical', row);
rowInfo.value = row
const data = {
ybh: labPat.value.ybh,
yq: labPat.value.yq,
jyrq: labPat.value.jyrq,
xmdh: row.xmdh
}
getresultmedList(data).then((res: any) => {
if (res.code == 0) {
ymTableData.value = res.data.map((item: any) => {
return {
...item,
zhywdh: item.ywdh + ' ' + item.ywmc
}
})
}
})
}
const ymTableData = ref([]);
const ymColumns = ref([
{ label: "抗生素", prop: "zhywdh", visible: true, width: 120, headerSlot: 'ywdhHead' },
{ label: "Mic", prop: "mic", align: 'center', visible: true, width: 60 },
{ label: "KB", prop: "rad", align: 'center', visible: true, width: 40 },
{ label: "结果", prop: "csjg", align: 'center', visible: true, width: 50 },
{ label: "结果标志", prop: "jgbz", align: 'center', visible: true, slot: 'jgbz', width: 180, showOverflowTooltip: false },
{ label: "折点", prop: "ckz", align: 'center', visible: true },
{ label: "分组", prop: "bz", align: 'center', visible: true },
{ label: "专家值", prop: "txtresult", align: 'center', visible: true },
{ label: "引用说明", prop: "cp_bz", align: 'center', visible: true },
])
const ymTableConfig = ref({
height: '48vh',
border: true,
highlightCurrentRow: true,
});
const ymHandleColumnDragEnd = (data: any) => {
ymColumns.value = data.columns;
}
const handleCsjgEnter = async (row: any) => {
// 判断数据中包含模板新增的数据 flag
if (tableData.value.length == 0) return
const flag = tableData.value.some((item: any) => item.changeflag == 2)
if (flag) {
saveresult(tableData.value).then((res: any) => {
if (res.code == 0) {
emitter.emit('wswSaveResult');
}
})
} else {
if (!row) return
if (row && row.id) {
emitter.emit('wswSaveResult');
newresult({ ...row, ybh: labPat.value.ybh, jyrq: labPat.value.jyrq, yq: labPat.value.yq }).then((response: any) => {
ElMessage.success("结果保存成功");
emits('fetchLabResults');
}).catch((error: any) => {
emits('fetchLabResults');
});
} else {
changeresult(row).then((response: any) => {
ElMessage.success("结果保存成功");
emits('fetchLabResults');
}).catch((error: any) => {
emits('fetchLabResults');
});
}
// nextTick(() => {
// const input = document.activeElement;
// if (input?.tagName === "INPUT") input?.blur();
// });
}
};
const csjgRef = ref()
const csjgTableData = ref([])
const handleInputFocus = (row: any) => {
// dbRow.value = row
queryXmVal({ yq: labPatKey.value.yq, xmdh: row.xmdh }).then((res: any) => {
if (res.code == 0) {
csjgTableData.value = res.data
}
nextTick(() => {
csjgRef.value.open()
})
})
};
const selectItem = (row: any) => {
// 查找修改行
const index = tableData.value.findIndex((item: any) => item.xmdh == row.xmdh)
tableData.value[index].csjg = row.qz
handleCsjgEnter(tableData.value[index])
};
// 组合项目
const combinedRef = ref()
const zhHandel = () => {
combinedRef.value.open()
};
const combinedHandel = (row: any) => {
console.log('data==>', row);
if (props.labPat.jgbz != null && props.labPat.jgbz != 0 && props.labPat.jgbz != 'C') return ElMessage.warning('已审核结果不可添加模板项目');
const data = {
...labPatKey.value,
mbmc: row.mbmc,
}
setinputmdl(data).then((res: any) => {
if (res.code == 0) {
const existingNames = new Set(tableData.value.map((item: any) => item.xmdh))
res.data?.forEach((item: any) => {
if (!existingNames.has(item.xmdh)) {
tableData.value.push({ ...item, jyrq: labPat.value.jyrq, zhxmdh: item.xmdh + ' ' + item.xmmc })
existingNames.add(item.xmdh)
}
})
handleCsjgEnter(null)
emitter.emit('clearLxsrList')
}
});
};
onMounted(() => {
// 获取模板项目
emitter.on('dbMbHandle', (info: any) => {
combinedHandel(info)
})
});
const formatDict = (v: string, dictType: string) => {
return props.dictData[dictType]?.find((item: any) => item.value == v)?.label || v;
}
const formatJgbz = (v: string) => {
return v == 'H' ? '高' : v == 'L' ? '低' : v == 'N' ? '阴性' : v == 'P' ? '阳性' : v == 'Q' ? '弱阳性' : v == 'M' ? '正常' : ''
}
</script>
<style scoped lang="scss">
.btns {
display: flex;
align-items: center;
span {
color: #1f6dd3;
margin-left: 15px;
}
}
.el-radio {
margin-right: .3125rem;
:deep(.el-radio__label) {
padding-left: 2px !important;
}
}
.btns_box {
padding: .3125rem .625rem !important;
font-size: .875rem;
height: 1.25rem !important;
margin: 5px 0;
margin-left: .625rem !important;
border-radius: 0 !important;
}
.tabs_btns {
position: relative;
.anchor {
position: absolute;
top: 0;
right: 0;
}
}
</style>