Compare commits
No commits in common. "7e876ce4993d9dbe69ec0893841a160b2f772bdc" and "2c4a3efba1c362b1603997345be90fce7cc96b54" have entirely different histories.
7e876ce499
...
2c4a3efba1
@ -26,32 +26,25 @@ export function getDate() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//增加字典数据
|
||||||
export function changeresult(data) {
|
export function addLabPatService(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/lisworkoper/changeresult',
|
url: '/liswork/add',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改病人信息
|
//修改字典数据
|
||||||
export function updateLabPat(data) {
|
export function updateLabPatService(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/lisworkoper/changepat',
|
url: '/liswork/update',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
export function changepatcolumn(query) {
|
|
||||||
return request({
|
|
||||||
url: '/lisworkoper/changepatcolumn',
|
|
||||||
method: 'get',
|
|
||||||
params:query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询结果数据列表
|
// 查询数据列表
|
||||||
export function queryLabResults(query) {
|
export function queryLabResults(query) {
|
||||||
return request({
|
return request({
|
||||||
url: '/liswork/resultinfo',
|
url: '/liswork/resultinfo',
|
||||||
@ -59,22 +52,7 @@ export function queryLabResults(query) {
|
|||||||
params: query
|
params: query
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// 查询检验项目
|
|
||||||
export function queryXmInfo(query) {
|
|
||||||
return request({
|
|
||||||
url: '/liswork/queryxminfo',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 查询常用取值
|
|
||||||
export function queryXmVal(query) {
|
|
||||||
return request({
|
|
||||||
url: '/liswork/queryxmval',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
// 批量删除结果
|
// 批量删除结果
|
||||||
export function deleteresult(data) {
|
export function deleteresult(data) {
|
||||||
return request({
|
return request({
|
||||||
@ -93,33 +71,3 @@ export function check2(query) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
//取消审核
|
|
||||||
export function uncheck2(query) {
|
|
||||||
return request({
|
|
||||||
url: '/lisworkoper/uncheck2',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
//取消审核
|
|
||||||
export function unconfirmlog(query) {
|
|
||||||
return request({
|
|
||||||
url: '/lisworkoper/unconfirmlog',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
export function checkuser(query) {
|
|
||||||
return request({
|
|
||||||
url: '/liswork/checkuserid',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
export function reglimit(query) {
|
|
||||||
return request({
|
|
||||||
url: '/lisworkoper/reglimit',
|
|
||||||
method: 'get',
|
|
||||||
params: query
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import { createVNode, render } from 'vue';
|
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
import { ElNotification , ElMessageBox, ElMessage, ElLoading } from 'element-plus'
|
||||||
import { getToken } from '@/utils/auth'
|
import { getToken } from '@/utils/auth'
|
||||||
@ -124,7 +123,7 @@ service.interceptors.response.use(res => {
|
|||||||
return Promise.reject(new Error(msg))
|
return Promise.reject(new Error(msg))
|
||||||
} else if (code === 3) {
|
} else if (code === 3) {
|
||||||
//提示并成功
|
//提示并成功
|
||||||
ElMessage({ message: msg, type: 'success' })
|
ElMessage({ message: msg, type: 'warning' })
|
||||||
return Promise.resolve(res.data)
|
return Promise.resolve(res.data)
|
||||||
} else if (code === 2) {
|
} else if (code === 2) {
|
||||||
//选择是否后续操作
|
//选择是否后续操作
|
||||||
@ -132,13 +131,6 @@ service.interceptors.response.use(res => {
|
|||||||
return Promise.resolve(res.data);
|
return Promise.resolve(res.data);
|
||||||
})
|
})
|
||||||
return Promise.reject('error');
|
return Promise.reject('error');
|
||||||
} else if (code === 1) {
|
|
||||||
//提示并失败
|
|
||||||
ElMessage({ message: msg, type: 'error' })
|
|
||||||
return Promise.reject(new Error(msg))
|
|
||||||
} else if (code === 4) {
|
|
||||||
//返回特定值,需要后续处理,表示当前操作需要处理后再调用,problemId是步骤关键参数,需要再次调用时引入
|
|
||||||
return Promise.resolve(res.data)
|
|
||||||
} else if (code === 5) {
|
} else if (code === 5) {
|
||||||
// 1. 提取后端返回的问题ID(根据实际字段名调整)
|
// 1. 提取后端返回的问题ID(根据实际字段名调整)
|
||||||
const problemId = res.data.problemId;
|
const problemId = res.data.problemId;
|
||||||
@ -188,7 +180,7 @@ service.interceptors.response.use(res => {
|
|||||||
problemId: problemId
|
problemId: problemId
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else if (code !== 200 && code !== 0) {
|
} else if (code !== 200 && code !== 0) {
|
||||||
ElNotification.error({ title: msg })
|
ElNotification.error({ title: msg })
|
||||||
return Promise.reject('error')
|
return Promise.reject('error')
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -212,6 +212,7 @@ function handleQueryDetail() {
|
|||||||
resetData()
|
resetData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//提交表单数据
|
||||||
function submitForm() {
|
function submitForm() {
|
||||||
proxy.$refs["dictRef"].validate(valid => {
|
proxy.$refs["dictRef"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
|||||||
@ -1,323 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- 遮罩层 -->
|
|
||||||
<div
|
|
||||||
v-if="visible"
|
|
||||||
class="dialog-mask"
|
|
||||||
@click="handleCancel"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<!-- 弹窗主体 -->
|
|
||||||
<div
|
|
||||||
v-if="visible"
|
|
||||||
class="dialog-container"
|
|
||||||
>
|
|
||||||
<div class="dialog-box">
|
|
||||||
<!-- 标题区域 -->
|
|
||||||
<div class="dialog-header">
|
|
||||||
<h3 class="dialog-title">{{ title }}</h3>
|
|
||||||
<button
|
|
||||||
class="dialog-close"
|
|
||||||
@click="handleCancel"
|
|
||||||
aria-label="关闭"
|
|
||||||
>
|
|
||||||
<span>×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 内容区域 -->
|
|
||||||
<div class="dialog-body">
|
|
||||||
<!-- 工号输入 -->
|
|
||||||
<div class="form-item">
|
|
||||||
<label class="form-label">用户工号</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model.trim="userId"
|
|
||||||
class="form-input"
|
|
||||||
placeholder="请输入用户工号"
|
|
||||||
@keyup.enter="handleConfirm"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 密码输入 -->
|
|
||||||
<div class="form-item">
|
|
||||||
<label class="form-label">密码</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
v-model="password"
|
|
||||||
class="form-input"
|
|
||||||
placeholder="请输入密码"
|
|
||||||
@keyup.enter="handleConfirm"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 错误提示 -->
|
|
||||||
<p v-if="errorMsg" class="error-message">{{ errorMsg }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 按钮区域 -->
|
|
||||||
<div class="dialog-footer">
|
|
||||||
<button
|
|
||||||
class="btn btn-cancel"
|
|
||||||
@click="handleCancel"
|
|
||||||
>
|
|
||||||
取消
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-confirm"
|
|
||||||
@click="handleConfirm"
|
|
||||||
:disabled="!userId || !password"
|
|
||||||
>
|
|
||||||
确认验证
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { defineProps, defineEmits, ref, watch } from 'vue';
|
|
||||||
|
|
||||||
// 组件属性
|
|
||||||
const props = defineProps({
|
|
||||||
// 控制弹窗显示/隐藏
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 弹窗标题(由外部参数控制)
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: '用户身份验证'
|
|
||||||
},
|
|
||||||
// 验证规则(可选,由外部传入)
|
|
||||||
validationRules: {
|
|
||||||
type: Object,
|
|
||||||
default: () => ({
|
|
||||||
// 工号最小长度
|
|
||||||
userIdMinLength: 3,
|
|
||||||
// 密码最小长度
|
|
||||||
passwordMinLength: 6
|
|
||||||
})
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 组件事件
|
|
||||||
const emit = defineEmits([
|
|
||||||
'update:visible', // 控制弹窗显示状态
|
|
||||||
'onConfirm', // 验证成功回调
|
|
||||||
'onCancel' // 取消验证回调
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 表单数据
|
|
||||||
const userId = ref('');
|
|
||||||
const password = ref('');
|
|
||||||
const errorMsg = ref('');
|
|
||||||
|
|
||||||
// 监听弹窗显示状态,重置表单
|
|
||||||
watch(
|
|
||||||
() => props.visible,
|
|
||||||
(newVal) => {
|
|
||||||
if (newVal) {
|
|
||||||
// 打开弹窗时重置表单
|
|
||||||
userId.value = '';
|
|
||||||
password.value = '';
|
|
||||||
errorMsg.value = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 处理确认验证
|
|
||||||
const handleConfirm = () => {
|
|
||||||
// 基础验证
|
|
||||||
if (!userId.value) {
|
|
||||||
errorMsg.value = '请输入用户工号';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!password.value) {
|
|
||||||
errorMsg.value = '请输入密码';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 应用外部传入的验证规则
|
|
||||||
if (userId.value.length < props.validationRules.userIdMinLength) {
|
|
||||||
errorMsg.value = `工号长度不能少于${props.validationRules.userIdMinLength}位`;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (password.value.length < props.validationRules.passwordMinLength) {
|
|
||||||
errorMsg.value = `密码长度不能少于${props.validationRules.passwordMinLength}位`;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证通过,返回用户工号
|
|
||||||
emit('onConfirm', {
|
|
||||||
userId: userId.value,
|
|
||||||
password: password.value
|
|
||||||
});
|
|
||||||
|
|
||||||
// 关闭弹窗
|
|
||||||
emit('update:visible', false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理取消
|
|
||||||
const handleCancel = () => {
|
|
||||||
emit('onCancel');
|
|
||||||
emit('update:visible', false);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* 遮罩层 */
|
|
||||||
.dialog-mask {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 1000;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 弹窗容器 */
|
|
||||||
.dialog-container {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1001;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 弹窗主体 */
|
|
||||||
.dialog-box {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 400px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标题区域 */
|
|
||||||
.dialog-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 16px 20px;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
background-color: #f9fafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-title {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-close {
|
|
||||||
padding: 0;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
font-size: 20px;
|
|
||||||
color: #999;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-close:hover {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 内容区域 */
|
|
||||||
.dialog-body {
|
|
||||||
padding: 24px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-item {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px 12px;
|
|
||||||
border: 1px solid #dcdfe6;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
transition: border-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #4096ff;
|
|
||||||
box-shadow: 0 0 0 2px rgba(64, 150, 255, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-message {
|
|
||||||
margin: 8px 0 0;
|
|
||||||
color: #f56c6c;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 按钮区域 */
|
|
||||||
.dialog-footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
padding: 12px 20px;
|
|
||||||
border-top: 1px solid #f0f0f0;
|
|
||||||
background-color: #f9fafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-cancel {
|
|
||||||
margin-right: 10px;
|
|
||||||
border: 1px solid #dcdfe6;
|
|
||||||
background-color: #fff;
|
|
||||||
color: #606266;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-cancel:hover {
|
|
||||||
background-color: #f5f7fa;
|
|
||||||
border-color: #c0c4cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-confirm {
|
|
||||||
border: 1px solid #4096ff;
|
|
||||||
background-color: #4096ff;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-confirm:hover {
|
|
||||||
background-color: #66b1ff;
|
|
||||||
border-color: #66b1ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-confirm:disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
cursor: not-allowed;
|
|
||||||
background-color: #4096ff;
|
|
||||||
border-color: #4096ff;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,331 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- 遮罩层 -->
|
|
||||||
<div
|
|
||||||
v-if="visible"
|
|
||||||
class="dialog-mask"
|
|
||||||
@click="handleCancel"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<!-- 弹窗主体 -->
|
|
||||||
<div
|
|
||||||
v-if="visible"
|
|
||||||
class="dialog-container"
|
|
||||||
>
|
|
||||||
<div class="dialog-box">
|
|
||||||
<!-- 标题区域 -->
|
|
||||||
<div class="dialog-header">
|
|
||||||
<h3 class="dialog-title">{{ title }}</h3>
|
|
||||||
<button
|
|
||||||
class="dialog-close"
|
|
||||||
@click="handleCancel"
|
|
||||||
aria-label="关闭"
|
|
||||||
>
|
|
||||||
<span>×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 内容区域 -->
|
|
||||||
<div class="dialog-body">
|
|
||||||
<!-- 搜索框 -->
|
|
||||||
<el-input
|
|
||||||
v-model="searchKey"
|
|
||||||
placeholder="搜索(支持名称、编码、简拼)..."
|
|
||||||
class="search-input"
|
|
||||||
clearable
|
|
||||||
@clear="filterDictData"
|
|
||||||
@input="filterDictData"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<!-- 字典列表 -->
|
|
||||||
<el-table
|
|
||||||
:data="filteredDictData"
|
|
||||||
height="300px"
|
|
||||||
border
|
|
||||||
@row-click="selectItem"
|
|
||||||
@row-dblclick="selectItem"
|
|
||||||
:loading="isDictLoading"
|
|
||||||
>
|
|
||||||
<el-table-column prop="value" label="编码" width="100" />
|
|
||||||
<el-table-column prop="label" label="名称" width="200" />
|
|
||||||
<el-table-column prop="pinyin" label="简拼" width="150" />
|
|
||||||
<el-table-column label="操作" width="100">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button size="small" type="primary" @click="selectItem(scope.row)">选择</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed, watch, onMounted } from 'vue';
|
|
||||||
import { getFirstLetter } from '@/api/pinyin.js'; // 拼音处理工具
|
|
||||||
|
|
||||||
// 组件参数
|
|
||||||
const props = defineProps({
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
type: String,
|
|
||||||
default: '选择字典项'
|
|
||||||
},
|
|
||||||
modelValue: {
|
|
||||||
type: [String, Number],
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
dictType: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: '请输入或双击选择'
|
|
||||||
},
|
|
||||||
clearable: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true
|
|
||||||
},
|
|
||||||
fetchDict: {
|
|
||||||
type: Function,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
disabled: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 组件事件
|
|
||||||
const emit = defineEmits([
|
|
||||||
'update:modelValue',
|
|
||||||
'update:labelValue',
|
|
||||||
'select',
|
|
||||||
'update:visible',
|
|
||||||
'onCancel'
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 内部状态管理
|
|
||||||
const tempValue = ref('');
|
|
||||||
const labelValue = ref('');
|
|
||||||
const dictData = ref([]); // 存储带简拼的字典数据
|
|
||||||
const filteredDictData = ref([]);
|
|
||||||
const isDictLoading = ref(true);
|
|
||||||
const searchKey = ref('');
|
|
||||||
const dialogVisible = ref(props.visible); // 内部弹窗状态
|
|
||||||
|
|
||||||
// 显示值计算属性
|
|
||||||
const displayValue = computed({
|
|
||||||
get() {
|
|
||||||
return labelValue.value || tempValue.value || props.modelValue || '';
|
|
||||||
},
|
|
||||||
set(newValue) {
|
|
||||||
tempValue.value = newValue;
|
|
||||||
if (labelValue.value && newValue !== labelValue.value) {
|
|
||||||
labelValue.value = '';
|
|
||||||
emit('update:labelValue', '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 加载字典数据并添加简拼字段
|
|
||||||
const loadDictData = async () => {
|
|
||||||
try {
|
|
||||||
isDictLoading.value = true;
|
|
||||||
const rawData = await props.fetchDict(props.dictType);
|
|
||||||
|
|
||||||
// 为每个字典项添加简拼字段
|
|
||||||
dictData.value = (rawData || []).map(item => ({
|
|
||||||
...item,
|
|
||||||
pinyin: getFirstLetter(item.label) || ''
|
|
||||||
}));
|
|
||||||
|
|
||||||
filteredDictData.value = [...dictData.value];
|
|
||||||
syncLabelWithValue();
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`加载${props.dictType}字典失败:`, error);
|
|
||||||
dictData.value = [];
|
|
||||||
filteredDictData.value = [];
|
|
||||||
} finally {
|
|
||||||
isDictLoading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 根据当前值同步显示标签
|
|
||||||
const syncLabelWithValue = () => {
|
|
||||||
if (props.modelValue) {
|
|
||||||
const matched = dictData.value.find(
|
|
||||||
item => String(item.value) === String(props.modelValue)
|
|
||||||
);
|
|
||||||
labelValue.value = matched?.label || props.modelValue;
|
|
||||||
emit('update:labelValue', labelValue.value);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 字典搜索过滤逻辑
|
|
||||||
const filterDictData = () => {
|
|
||||||
const key = searchKey.value.trim().toLowerCase();
|
|
||||||
if (!key) {
|
|
||||||
filteredDictData.value = [...dictData.value];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
filteredDictData.value = dictData.value.filter(item => {
|
|
||||||
const matchLabel = item.label?.toLowerCase().includes(key) || false;
|
|
||||||
const matchValue = String(item.value).toLowerCase().includes(key);
|
|
||||||
const matchPinyin = item.pinyin?.toLowerCase().includes(key) || false;
|
|
||||||
|
|
||||||
return matchLabel || matchValue || matchPinyin;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 打开弹窗
|
|
||||||
const openDictSelector = () => {
|
|
||||||
if (!props.disabled && !isDictLoading.value) {
|
|
||||||
dialogVisible.value = true;
|
|
||||||
searchKey.value = '';
|
|
||||||
filterDictData();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 选择字典项
|
|
||||||
const selectItem = (item) => {
|
|
||||||
if (!item) return;
|
|
||||||
|
|
||||||
emit('update:modelValue', item.value);
|
|
||||||
emit('update:labelValue', item.label);
|
|
||||||
emit('select', item);
|
|
||||||
|
|
||||||
tempValue.value = item.value;
|
|
||||||
labelValue.value = item.label;
|
|
||||||
dialogVisible.value = false;
|
|
||||||
emit('update:visible', false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理取消
|
|
||||||
const handleCancel = () => {
|
|
||||||
emit('onCancel');
|
|
||||||
dialogVisible.value = false;
|
|
||||||
emit('update:visible', false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 监听visible属性变化
|
|
||||||
watch(() => props.visible, (newVal) => {
|
|
||||||
dialogVisible.value = newVal;
|
|
||||||
if (newVal) {
|
|
||||||
searchKey.value = '';
|
|
||||||
filterDictData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 监听初始值变化
|
|
||||||
watch(() => props.modelValue, (newVal) => {
|
|
||||||
tempValue.value = newVal || '';
|
|
||||||
if (newVal && !isDictLoading.value) {
|
|
||||||
syncLabelWithValue();
|
|
||||||
}
|
|
||||||
}, { immediate: true });
|
|
||||||
|
|
||||||
// 监听字典类型变化,重新加载数据
|
|
||||||
watch(() => props.dictType, loadDictData, { immediate: false });
|
|
||||||
|
|
||||||
// 组件挂载时加载字典
|
|
||||||
onMounted(async () => {
|
|
||||||
await loadDictData();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* 遮罩层 */
|
|
||||||
.dialog-mask {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 1000;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 弹窗容器 */
|
|
||||||
.dialog-container {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1001;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 弹窗主体 */
|
|
||||||
.dialog-box {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 600px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标题区域 */
|
|
||||||
.dialog-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 16px 20px;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
background-color: #f9fafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-title {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-close {
|
|
||||||
padding: 0;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
font-size: 20px;
|
|
||||||
color: #999;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-close:hover {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 内容区域 */
|
|
||||||
.dialog-body {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-input {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 表格样式优化 */
|
|
||||||
::v-deep .el-table {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::v-deep .el-table__empty-text {
|
|
||||||
color: #909399;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 按钮样式优化 */
|
|
||||||
::v-deep .el-button--small {
|
|
||||||
padding: 4px 12px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,229 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="dict-input-wrapper">
|
|
||||||
<el-input
|
|
||||||
v-model="displayValue"
|
|
||||||
:placeholder="placeholder"
|
|
||||||
:clearable="clearable"
|
|
||||||
:disabled="isDictLoading || disabled"
|
|
||||||
@blur="handleBlur"
|
|
||||||
@clear="handleClear"
|
|
||||||
@dblclick="handleDblClick"
|
|
||||||
>
|
|
||||||
<template #prefix>
|
|
||||||
<el-icon v-if="isDictLoading" size="16"><Loading /></el-icon>
|
|
||||||
</template>
|
|
||||||
<template #suffix>
|
|
||||||
<el-icon @click="openDictSelector" size="16" class="select-icon">
|
|
||||||
<ArrowDown />
|
|
||||||
</el-icon>
|
|
||||||
</template>
|
|
||||||
</el-input>
|
|
||||||
|
|
||||||
<!-- 字典选择弹窗 -->
|
|
||||||
<el-dialog
|
|
||||||
v-model="dialogVisible"
|
|
||||||
:title="dialogTitle"
|
|
||||||
width="500px"
|
|
||||||
@close="handleDialogClose"
|
|
||||||
>
|
|
||||||
<el-input
|
|
||||||
v-model="searchKey"
|
|
||||||
placeholder="搜索(支持名称、编码、简拼)..."
|
|
||||||
class="mb-4"
|
|
||||||
clearable
|
|
||||||
@clear="filterDictData"
|
|
||||||
@input="filterDictData"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<el-table
|
|
||||||
:data="filteredDictData"
|
|
||||||
height="300px"
|
|
||||||
border
|
|
||||||
@row-click="selectItem"
|
|
||||||
@row-dblclick="selectItem"
|
|
||||||
>
|
|
||||||
<el-table-column prop="value" label="编码" width="100" />
|
|
||||||
<el-table-column prop="label" label="名称" width="200" />
|
|
||||||
<el-table-column prop="pinyin" label="简拼" width="150" /> <!-- 显示简拼便于调试 -->
|
|
||||||
<el-table-column label="操作" width="100">
|
|
||||||
<template #default="scope">
|
|
||||||
<el-button size="small" type="primary" @click="selectItem(scope.row)">选择</el-button>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
</el-table>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { ref, computed, watch, onMounted } from 'vue';
|
|
||||||
import { Loading, ArrowDown } from '@element-plus/icons-vue';
|
|
||||||
|
|
||||||
import { getFirstLetter } from '@/api/pinyin.js'; // 引入拼音处理工具
|
|
||||||
// 组件参数
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: { type: [String, Number], default: '' },
|
|
||||||
dictType: { type: String, required: true },
|
|
||||||
placeholder: { type: String, default: '请输入或双击选择' },
|
|
||||||
clearable: { type: Boolean, default: true },
|
|
||||||
disabled: {type: Boolean, default: false},
|
|
||||||
fetchDict: {type: Function, required: true},
|
|
||||||
dialogTitle: {type: String, default: '选择字典项'},
|
|
||||||
loadOnMount: { type: Boolean, default: true }
|
|
||||||
});
|
|
||||||
|
|
||||||
// 组件事件
|
|
||||||
const emit = defineEmits(['update:modelValue', 'update:labelValue', 'select']);
|
|
||||||
|
|
||||||
// 内部状态
|
|
||||||
const tempValue = ref('');
|
|
||||||
const labelValue = ref('');
|
|
||||||
const dictData = ref([]); // 存储带简拼的字典数据
|
|
||||||
const filteredDictData = ref([]);
|
|
||||||
const isDictLoading = ref(false);
|
|
||||||
const dialogVisible = ref(false);
|
|
||||||
const searchKey = ref('');
|
|
||||||
|
|
||||||
// 显示值计算
|
|
||||||
const displayValue = computed({
|
|
||||||
get() {
|
|
||||||
return labelValue.value || tempValue.value || props.modelValue || '';
|
|
||||||
},
|
|
||||||
set(newValue) {
|
|
||||||
tempValue.value = newValue;
|
|
||||||
if (labelValue.value && newValue !== labelValue.value) {
|
|
||||||
labelValue.value = '';
|
|
||||||
emit('update:labelValue', '');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 加载字典数据(并添加简拼字段)
|
|
||||||
const loadDictData = async () => {
|
|
||||||
try {
|
|
||||||
|
|
||||||
isDictLoading.value = true;
|
|
||||||
const rawData = await props.fetchDict(props.dictType);
|
|
||||||
// 为每个字典项添加简拼字段
|
|
||||||
dictData.value = (rawData || []).map(item => ({
|
|
||||||
...item,
|
|
||||||
pinyin: getFirstLetter(item.label) // 新增pinyin字段存储简拼
|
|
||||||
}));
|
|
||||||
|
|
||||||
filteredDictData.value = [...dictData.value];
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`加载${props.dictType}字典失败:`, error);
|
|
||||||
dictData.value = [];
|
|
||||||
filteredDictData.value = [];
|
|
||||||
} finally {
|
|
||||||
isDictLoading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 核心搜索逻辑(支持模糊搜索+简拼搜索)
|
|
||||||
const filterDictData = () => {
|
|
||||||
const key = searchKey.value.trim().toLowerCase();
|
|
||||||
if (!key) {
|
|
||||||
filteredDictData.value = [...dictData.value];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
filteredDictData.value = dictData.value.filter(item => {
|
|
||||||
// 1. 模糊搜索:匹配label(名称)或value(编码)
|
|
||||||
const matchLabel = item.label.toLowerCase().includes(key);
|
|
||||||
const matchValue = String(item.value).toLowerCase().includes(key);
|
|
||||||
|
|
||||||
// 2. 简拼搜索:匹配首字母简拼
|
|
||||||
const matchPinyin = item.pinyin.toLowerCase().includes(key);
|
|
||||||
|
|
||||||
// 满足任一条件即匹配
|
|
||||||
return matchLabel || matchValue || matchPinyin;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 双击事件处理
|
|
||||||
const handleDblClick = () => {
|
|
||||||
if (!props.disabled && !isDictLoading.value) {
|
|
||||||
dialogVisible.value = true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 关键修改:打开弹窗时重新加载数据
|
|
||||||
const openDictSelector = async () => {
|
|
||||||
if (props.disabled || isDictLoading.value) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 打开弹窗前先加载数据(确保每次打开都是最新的)
|
|
||||||
await loadDictData();
|
|
||||||
|
|
||||||
// 数据加载完成后再显示弹窗
|
|
||||||
dialogVisible.value = true;
|
|
||||||
searchKey.value = '';
|
|
||||||
filterDictData();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// 选择字典项
|
|
||||||
const selectItem = (item) => {
|
|
||||||
emit('update:modelValue', item.value);
|
|
||||||
emit('update:labelValue', item.label);
|
|
||||||
emit('select', item);
|
|
||||||
tempValue.value = item.value;
|
|
||||||
labelValue.value = item.label;
|
|
||||||
dialogVisible.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 其他方法(失焦、清空等)保持不变
|
|
||||||
const handleBlur = () => { /* ... */
|
|
||||||
};
|
|
||||||
const handleClear = () => { /* ... */
|
|
||||||
};
|
|
||||||
const handleDialogClose = () => {
|
|
||||||
dialogVisible.value = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 监听初始值变化
|
|
||||||
watch(() => props.modelValue, (newVal) => {
|
|
||||||
tempValue.value = newVal || '';
|
|
||||||
if (newVal && !isDictLoading.value) {
|
|
||||||
const matched = dictData.value.find(item => String(item.value) === String(newVal));
|
|
||||||
labelValue.value = matched?.label || newVal;
|
|
||||||
emit('update:labelValue', labelValue.value);
|
|
||||||
}
|
|
||||||
}, {immediate: true});
|
|
||||||
|
|
||||||
// 组件挂载时加载字典
|
|
||||||
onMounted(async () => {
|
|
||||||
if (props.loadOnMount) { // 仅当loadOnMount为true时(默认),才在挂载时加载
|
|
||||||
await loadDictData();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
defineExpose({
|
|
||||||
openDictSelector, // 暴露打开弹窗的方法
|
|
||||||
// 可选:暴露其他可能需要的方法(如刷新字典数据)
|
|
||||||
loadDictData
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* 样式保持不变 */
|
|
||||||
.dict-input-wrapper {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
color: #666;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.select-icon:hover {
|
|
||||||
color: #409eff;
|
|
||||||
}
|
|
||||||
|
|
||||||
:deep(.el-input__suffix) {
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -4,110 +4,62 @@
|
|||||||
<el-form :model="labPat" label-width="100px" class="compact-form" label-position="left">
|
<el-form :model="labPat" label-width="100px" class="compact-form" label-position="left">
|
||||||
<el-form-item label="病人来源" label-width="70px">
|
<el-form-item label="病人来源" label-width="70px">
|
||||||
<el-col :span="16">
|
<el-col :span="16">
|
||||||
<dict-input v-model="labPat.brly" :dict-type="'PT'" placeholder="请输入病人来源" :fetch-dict="fetchDict"
|
<dict-input v-model="labPat.brly" :dict-type="'PT'" placeholder="请输入病人来源" :fetch-dict="fetchDict" @update:labelValue="(label) => labPat.brlyLabel = label" dialog-title="选择病人来源"/>
|
||||||
@update:labelValue="(label) => labPat.brlyLabel = label" dialog-title="选择病人来源"
|
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
@select="handleDictSelect"
|
|
||||||
/>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<el-switch v-model="jzbzSwitch" active-text="急诊" active-color="#FD0101" @change="handleFieldChange"></el-switch>
|
<el-switch v-model="labPat.jzbz" active-text="急诊" active-color="#FD0101"></el-switch>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="病 历 号" label-width="70px">
|
<el-form-item label="病 历 号" label-width="70px">
|
||||||
<el-input v-model="labPat.brdh" placeholder="请输入病历号"
|
<el-input v-model="labPat.brdh" placeholder="请输入病历号"></el-input>
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"></el-input>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="姓 名" label-width="70px">
|
<el-form-item label="姓 名" label-width="70px">
|
||||||
<el-input v-model="labPat.brxm" placeholder="请输入姓名"
|
<el-input v-model="labPat.brxm" placeholder="请输入姓名"></el-input>
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"></el-input>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="性 别" label-width="70px">
|
<el-form-item label="性 别" label-width="70px">
|
||||||
<el-col :span="8">
|
<el-col :span="8">
|
||||||
<dict-input v-model="labPat.brxb" placeholder="性别" :dict-type="'SX'" :fetch-dict="fetchDict"
|
<dict-input v-model="labPat.brxb" placeholder="性别" :dict-type="'SX'" :fetch-dict="fetchDict" @update:labelValue="(label) => labPat.brxbLabel = label"/>
|
||||||
@update:labelValue="(label) => labPat.brxbLabel = label"
|
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
@select="handleDictSelect"
|
|
||||||
/>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4"><div>年龄</div></el-col>
|
<el-col :span="4"><div>年龄</div></el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-input v-model="labPat.nl" placeholder="年龄"
|
<el-input v-model="labPat.nl" placeholder="年龄"></el-input>
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"></el-input>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<dict-input v-model="labPat.nldw" placeholder="年月" :dict-type="'AU'" :fetch-dict="fetchDict"
|
<dict-input v-model="labPat.nldw" placeholder="年月" :dict-type="'AU'" :fetch-dict="fetchDict" @update:labelValue="(label) => labPat.nldwLabel = label"/>
|
||||||
@update:labelValue="(label) => labPat.nldwLabel = label"
|
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
@select="handleDictSelect"
|
|
||||||
/>
|
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="送检科室" label-width="70px">
|
<el-form-item label="送检科室" label-width="70px">
|
||||||
<dict-input v-model="labPat.ksdh" placeholder="请输入科室" :dict-type="'DP'" :fetch-dict="fetchDict"
|
<dict-input v-model="labPat.ksdh" placeholder="请输入科室" :dict-type="'DP'" :fetch-dict="fetchDict" @update:labelValue="(label) => labPat.ksdhLabel = label"/>
|
||||||
@update:labelValue="(label) => labPat.ksdhLabel = label"
|
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
@select="handleDictSelect"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="床 号" label-width="70px">
|
<el-form-item label="床 号" label-width="70px">
|
||||||
<el-input v-model="labPat.ch" placeholder="请输入床号"
|
<el-input v-model="labPat.ch" placeholder="请输入床号"></el-input>
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
></el-input>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="样本类型" label-width="70px">
|
<el-form-item label="样本类型" label-width="70px">
|
||||||
<dict-input v-model="labPat.yblx" placeholder="请输入样本类型" :dict-type="'BT'" :fetch-dict="fetchDict"
|
<dict-input v-model="labPat.yblx" placeholder="请输入样本类型" :dict-type="'BT'" :fetch-dict="fetchDict" @update:labelValue="(label) => labPat.yblxLabel = label"/>
|
||||||
@update:labelValue="(label) => labPat.yblxLabel = label"
|
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
@select="handleDictSelect"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="申请医生" label-width="70px">
|
<el-form-item label="申请医生" label-width="70px">
|
||||||
<dict-input v-model="labPat.sjys" placeholder="请输入申请医生" :dict-type="'SRD'" :fetch-dict="fetchDict"
|
<dict-input v-model="labPat.sjys" placeholder="请输入申请医生" :dict-type="'SRD'" :fetch-dict="fetchDict" @update:labelValue="(label) => labPat.sjysLabel = label"/>
|
||||||
@update:labelValue="(label) => labPat.sjysLabel = label"
|
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
@select="handleDictSelect"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="上机时间" label-width="70px">
|
<el-form-item label="上机时间" label-width="70px">
|
||||||
<el-date-picker v-model="labPat.sqsj" type="datetime" placeholder="上机时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
|
<el-date-picker v-model="labPat.sqsj" type="datetime" placeholder="上机时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"></el-date-picker>
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
></el-date-picker>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="采样时间" label-width="70px">
|
<el-form-item label="采样时间" label-width="70px">
|
||||||
<el-date-picker v-model="labPat.cyrq" type="datetime" placeholder="采样时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
|
<el-date-picker v-model="labPat.cyrq" type="datetime" placeholder="采样时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"></el-date-picker>
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
></el-date-picker>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="报告时间" label-width="70px">
|
<el-form-item label="报告时间" label-width="70px">
|
||||||
<el-date-picker v-model="labPat.dysj" type="datetime" placeholder="报告时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"
|
<el-date-picker v-model="labPat.dysj" type="datetime" placeholder="报告时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss"></el-date-picker>
|
||||||
@blur="handleFieldChange"
|
|
||||||
@keyup.enter="handleFieldChange"
|
|
||||||
></el-date-picker>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="临床诊断" label-width="70px">
|
<el-form-item label="临床诊断" label-width="70px">
|
||||||
<el-input v-model="labPat.zd" placeholder="请输入临床诊断" @blur="handleFieldChange" @keyup.enter="handleFieldChange"></el-input>
|
<el-input v-model="labPat.zd" placeholder="请输入临床诊断"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="备 注" label-width="70px">
|
<el-form-item label="备 注" label-width="70px">
|
||||||
<el-input v-model="labPat.bz" placeholder="请输入备注" @blur="handleFieldChange" @keyup.enter="handleFieldChange"></el-input>
|
<el-input v-model="labPat.bz" placeholder="请输入备注"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="检验医生" label-width="70px">
|
<el-form-item label="检验医生" label-width="70px">
|
||||||
<el-input v-model="labPat.yhdh" placeholder="请输入检验医生" @blur="handleFieldChange" @keyup.enter="handleFieldChange"></el-input>
|
<el-input v-model="labPat.yhdh" placeholder="请输入检验医生"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="审核医生" label-width="70px">
|
<el-form-item label="审核医生" label-width="70px">
|
||||||
<el-input v-model="labPat.hdys" placeholder="请输入审核医生" @blur="handleFieldChange" @keyup.enter="handleFieldChange"></el-input>
|
<el-input v-model="labPat.hdys" placeholder="请输入审核医生"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="审核状态" >
|
<el-form-item label="审核状态" >
|
||||||
<el-radio-group v-model="labPat.jgbz">
|
<el-radio-group v-model="labPat.jgbz">
|
||||||
@ -127,8 +79,6 @@
|
|||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import DictInput from './DictInput.vue';
|
import DictInput from './DictInput.vue';
|
||||||
import {changepatcolumn, updateLabPat} from "@/api/liswork/work/LisWork.js";
|
|
||||||
const loading = ref(true);
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
labPat: {
|
labPat: {
|
||||||
type: Object,
|
type: Object,
|
||||||
@ -140,123 +90,41 @@ const props = defineProps({
|
|||||||
default: () => []
|
default: () => []
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// 计算属性:将布尔值转换为 0/1 绑定到 labPat.jzbz
|
|
||||||
const jzbzSwitch = computed({
|
|
||||||
get() {
|
|
||||||
// 后端返回的 0/1 转换为布尔值(供开关显示)
|
|
||||||
return props.labPat.jzbz == "1";
|
|
||||||
},
|
|
||||||
set(checked) {
|
|
||||||
// 开关的 true/false 转换为 1/0 存到实体中
|
|
||||||
props.labPat.jzbz = checked ? "1" : "0";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const emit = defineEmits(['update:labPat']);
|
const emit = defineEmits(['update:labPat']);
|
||||||
// 通过inject获取全局方法
|
// 通过inject获取全局方法
|
||||||
const comDict = inject('comDict');
|
const comDict = inject('comDict');
|
||||||
const lastValue = ref(JSON.stringify(props.labPat));
|
|
||||||
const prevFieldState = ref(null); // 记录当前修改的字段及旧值 { field: '字段名', oldValue: 旧值 }
|
|
||||||
/**
|
|
||||||
* 通用字段变化处理(失焦、回车触发)
|
|
||||||
*/
|
|
||||||
const handleFieldChange = async () => {
|
|
||||||
await triggerApiUpdate();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
// 保存方法
|
||||||
* 字典选择完成处理(弹窗选择后触发)
|
const saveMain = () => {
|
||||||
*/
|
// 提交时可获取原始值(brly)和标签(brlyLabel)
|
||||||
const handleDictSelect = async () => {
|
console.log('提交数据:', {
|
||||||
// 字典选择后直接触发更新
|
rawValue: props.labPat.brly,
|
||||||
await triggerApiUpdate();
|
label: props.labPat.brlyLabel,
|
||||||
};
|
...props.labPat
|
||||||
/**
|
});
|
||||||
* 对比新旧对象,找出修改的字段及旧值
|
// 实际项目中调用接口提交数据
|
||||||
* @param oldObj 旧对象
|
|
||||||
* @param newObj 新对象
|
|
||||||
* @returns { field: string, oldValue: any } | null
|
|
||||||
*/
|
|
||||||
const getChangedField = (oldObj, newObj) => {
|
|
||||||
const oldKeys = Object.keys(oldObj);
|
|
||||||
for (const key of oldKeys) {
|
|
||||||
if (newObj[key] !== oldObj[key]) {
|
|
||||||
return { field: key, oldValue: oldObj[key], newValue: newObj[key] };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* 触发API更新的核心方法
|
|
||||||
*/
|
|
||||||
const triggerApiUpdate = async () => {
|
|
||||||
const currentLabPat = toRaw(props.labPat);
|
|
||||||
const currentValue = JSON.stringify(currentLabPat);
|
|
||||||
const oldValue = lastValue.value;
|
|
||||||
// 只有值发生变化时才调用API
|
|
||||||
if (currentValue !== lastValue.value) {
|
|
||||||
// 2. 找出修改的字段及旧值(用于回滚)
|
|
||||||
const oldObj = JSON.parse(oldValue);
|
|
||||||
const changedField = getChangedField(oldObj, currentLabPat);
|
|
||||||
prevFieldState.value = changedField; // 记录修改前的状态
|
|
||||||
console.log('prevFieldState:', prevFieldState.value)
|
|
||||||
console.log('labPatKey:', props.labPatKey)
|
|
||||||
try {
|
|
||||||
loading.value = true;
|
|
||||||
changepatcolumn({...props.labPatKey,column:changedField?.field,value:changedField?.newValue}).then(response => {
|
|
||||||
console.log('response:', response)
|
|
||||||
console.log('表单更新成功');
|
|
||||||
lastValue.value = currentValue;
|
|
||||||
loading.value = false;
|
|
||||||
}) .catch(error => {
|
|
||||||
console.error('表单更新失败', error);
|
|
||||||
loading.value = false;
|
|
||||||
if (prevFieldState.value) {
|
|
||||||
const { field, oldValue,newValue } = prevFieldState.value;
|
|
||||||
// 回滚字段值(通过emit触发父组件更新,避免直接修改props)
|
|
||||||
emit('update:labPat', {
|
|
||||||
...toRaw(props.labPat),
|
|
||||||
[field]: oldValue
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
// 若未找到具体字段,整体回滚
|
|
||||||
emit('update:labPat', JSON.parse(oldValue));
|
|
||||||
}
|
|
||||||
// 回滚后更新缓存
|
|
||||||
lastValue.value = oldValue;
|
|
||||||
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('更新接口调用失败:', error);
|
|
||||||
}finally {
|
|
||||||
loading.value = false;
|
|
||||||
prevFieldState.value = null; // 清空临时记录
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 手动保存
|
|
||||||
const saveMain = async () => {
|
|
||||||
await triggerApiUpdate();
|
|
||||||
};
|
};
|
||||||
// 重置方法
|
// 重置方法
|
||||||
const resetMain = () => {
|
const resetMain = () => {
|
||||||
const resetData = {
|
emit('update:labPat', {
|
||||||
...props.labPat,
|
|
||||||
brly: '',
|
brly: '',
|
||||||
brlyLabel: '',
|
brlyLabel: '',
|
||||||
ksdh: '',
|
ksdh: '',
|
||||||
ksdhLabel: '',
|
ksdhLabel: '',
|
||||||
|
sjys: '',
|
||||||
|
sjysLabel: '',
|
||||||
brxb: '',
|
brxb: '',
|
||||||
brxbLabel: '',
|
brxbLabel: '',
|
||||||
nldw: '',
|
nldw: '',
|
||||||
nldwLabel: '',
|
nldwLabel: '',
|
||||||
jzbz: 0,
|
yblx: '',
|
||||||
jgbz: 0
|
yblxLabel: '',
|
||||||
};
|
// 保留其他字段的默认值
|
||||||
emit('update:labPat', resetData);
|
...props.labPat,
|
||||||
lastValue.value = JSON.stringify(resetData);
|
jzbz: props.labPat.jzbz || 0,
|
||||||
};
|
jgbz: props.labPat.jgbz || 0
|
||||||
|
});
|
||||||
|
}
|
||||||
// 字典获取方法(适配子组件)
|
// 字典获取方法(适配子组件)
|
||||||
const fetchDict = async (dictType) => {
|
const fetchDict = async (dictType) => {
|
||||||
const dictRefs = await comDict(dictType);
|
const dictRefs = await comDict(dictType);
|
||||||
|
|||||||
@ -12,12 +12,8 @@
|
|||||||
:header-cell-style="{ backgroundColor: '#f5f7fa' }"
|
:header-cell-style="{ backgroundColor: '#f5f7fa' }"
|
||||||
>
|
>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
type="index"
|
type="index" prop="id" label="" width="45" :index="getRowIndex" >
|
||||||
prop="id"
|
</el-table-column>
|
||||||
label=""
|
|
||||||
width="45"
|
|
||||||
:index="getRowIndex"
|
|
||||||
></el-table-column>
|
|
||||||
<el-table-column type="selection" width="30"></el-table-column>
|
<el-table-column type="selection" width="30"></el-table-column>
|
||||||
<el-table-column prop="jyrq" label="检验日期" v-if="false"></el-table-column>
|
<el-table-column prop="jyrq" label="检验日期" v-if="false"></el-table-column>
|
||||||
<el-table-column prop="yq" label="仪器" v-if="false"></el-table-column>
|
<el-table-column prop="yq" label="仪器" v-if="false"></el-table-column>
|
||||||
@ -29,14 +25,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="csjg" label="结果" width="100" >
|
<el-table-column prop="csjg" label="结果" width="100" >
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input
|
<el-input v-model="scope.row.csjg" size="small" class="full-width-input"></el-input>
|
||||||
v-model="scope.row.csjg"
|
|
||||||
size="small"
|
|
||||||
class="full-width-input"
|
|
||||||
:disabled="readonly"
|
|
||||||
@blur="handleCsjgBlur(scope.row)"
|
|
||||||
@keyup.enter="handleCsjgEnter(scope.row)"
|
|
||||||
></el-input>
|
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="od" label="OD" width="60" v-if="false">
|
<el-table-column prop="od" label="OD" width="60" v-if="false">
|
||||||
@ -46,365 +35,197 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="cutoff" label="SCO" width="60" v-if="false">
|
<el-table-column prop="cutoff" label="SCO" width="60" v-if="false">
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-input v-model="scope.row.cutoff" size="small" class="full-width-input"></el-input>
|
<el-input v-model="scope.row.od" size="small" class="full-width-input"></el-input>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="refs" label="参考值" width="100" show-overflow-tooltip>
|
<el-table-column prop="refs" label="参考值" width="100" show-overflow-tooltip>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="dw" label="单位" width="100" show-overflow-tooltip >
|
<el-table-column prop="dw" label="单位" width="100" show-overflow-tooltip >
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, toRefs, watch, nextTick, onMounted } from "vue";
|
//import {ref, reactive, watch, toRefs, nextTick} from 'vue';
|
||||||
import { deleteresult, changeresult } from "@/api/liswork/work/LisWork.js";
|
import {deleteresult, queryLabResults} from "@/api/liswork/work/LisWork.js";
|
||||||
import { ElMessageBox, ElMessage } from "element-plus";
|
import {delType} from "@/api/system/dict/type.js";
|
||||||
|
import {ElMessageBox} from "element-plus";
|
||||||
// 组件属性定义
|
const { proxy } = getCurrentInstance();
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
tableData: { type: Array, default: () => [] },
|
// 表格数据
|
||||||
tableKey: { type: Array, default: () => [] },
|
tableData: {type: Array,default: () => []},
|
||||||
readonly: { type: Boolean, default: false },
|
//主键
|
||||||
hasChanges: { type: Boolean, default: false }
|
tableKey:{type: Array, default: () => []},
|
||||||
|
// 部门选项
|
||||||
|
// departments: {
|
||||||
|
// type: Array,
|
||||||
|
// default: () => []
|
||||||
|
// },
|
||||||
|
// 是否只读
|
||||||
|
readonly: {type: Boolean, default: false}
|
||||||
});
|
});
|
||||||
|
const { tableData, tableKey, readonly,undeleteflag,hasChanges } = toRefs(props);
|
||||||
// 事件定义
|
|
||||||
const emits = defineEmits([
|
const emits = defineEmits([
|
||||||
'add',
|
'add', // 新增行
|
||||||
'save',
|
'save', // 保存数据
|
||||||
'delete',
|
'delete', // 删除行
|
||||||
'batch-delete',
|
'batch-delete', // 批量删除
|
||||||
'fetchLabResults',
|
'fetchLabResults' //刷新数据
|
||||||
'delfalg',
|
|
||||||
'update:tableData'
|
|
||||||
]);
|
]);
|
||||||
|
// 选中的行
|
||||||
// 解构props
|
|
||||||
const { tableData, tableKey, readonly, hasChanges } = toRefs(props);
|
|
||||||
const selectedRows = ref([]);
|
const selectedRows = ref([]);
|
||||||
const filteredList = ref([]);
|
const filteredList = ref([]);
|
||||||
|
// 原始数据副本,用于检测变化
|
||||||
const originalData = ref(JSON.parse(JSON.stringify(props.tableData)));
|
const originalData = ref(JSON.parse(JSON.stringify(props.tableData)));
|
||||||
const isEnterHandled = ref(false);
|
// 处理选择变化
|
||||||
const originalCsjgMap = ref({});
|
|
||||||
const isSaving = ref({}); // 用于防止重复提交的标记
|
|
||||||
|
|
||||||
// 组件挂载时初始化缓存
|
|
||||||
onMounted(() => {
|
|
||||||
updateOriginalCsjgMap();
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新csjg原始值缓存
|
|
||||||
*/
|
|
||||||
const updateOriginalCsjgMap = () => {
|
|
||||||
const newMap = {};
|
|
||||||
props.tableData.forEach((row) => {
|
|
||||||
const uniqueKey = getRowUniqueKey(row);
|
|
||||||
let originalCsjg = row.csjg;
|
|
||||||
originalCsjg = originalCsjg == null ? "" : String(originalCsjg).trim();
|
|
||||||
newMap[uniqueKey] = originalCsjg;
|
|
||||||
});
|
|
||||||
originalCsjgMap.value = newMap;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取行的唯一标识
|
|
||||||
*/
|
|
||||||
const getRowUniqueKey = (row) => {
|
|
||||||
// 优先使用id,没有则使用xmdh确保唯一性
|
|
||||||
return row.id || row.xmdh;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* csjg输入框失焦触发保存
|
|
||||||
*/
|
|
||||||
const handleCsjgBlur = async (row) => {
|
|
||||||
if (isEnterHandled.value) return;
|
|
||||||
await saveCsjgChange(row);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* csjg输入框回车触发保存
|
|
||||||
*/
|
|
||||||
const handleCsjgEnter = async (row) => {
|
|
||||||
isEnterHandled.value = true;
|
|
||||||
await saveCsjgChange(row);
|
|
||||||
nextTick(() => {
|
|
||||||
const input = document.activeElement;
|
|
||||||
if (input.tagName === "INPUT") input.blur();
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
isEnterHandled.value = false;
|
|
||||||
}, 100);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 核心:保存csjg修改(调用API + 失败回滚)
|
|
||||||
*/
|
|
||||||
const saveCsjgChange = async (row) => {
|
|
||||||
const uniqueKey = getRowUniqueKey(row);
|
|
||||||
|
|
||||||
// 防止重复提交
|
|
||||||
if (isSaving.value[uniqueKey]) return;
|
|
||||||
|
|
||||||
const oldCsjg = originalCsjgMap.value[uniqueKey] || "";
|
|
||||||
let newCsjg = row.csjg || "";
|
|
||||||
|
|
||||||
// 标准化处理
|
|
||||||
newCsjg = String(newCsjg).trim();
|
|
||||||
|
|
||||||
// 调试日志
|
|
||||||
console.log(`
|
|
||||||
行${uniqueKey} 比较:
|
|
||||||
缓存旧值:"${oldCsjg}"(类型:${typeof oldCsjg})
|
|
||||||
当前新值:"${newCsjg}"(类型:${typeof newCsjg})
|
|
||||||
是否相等:${oldCsjg === newCsjg}
|
|
||||||
`);
|
|
||||||
|
|
||||||
// 无变化或只读状态,直接返回
|
|
||||||
if (oldCsjg === newCsjg || readonly.value) {
|
|
||||||
console.log("值未变化,无需保存");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// 设置提交中标记
|
|
||||||
isSaving.value[uniqueKey] = true;
|
|
||||||
|
|
||||||
const requestParams = {
|
|
||||||
...row,
|
|
||||||
csjg: newCsjg
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('提交参数:', requestParams);
|
|
||||||
changeresult(requestParams).then(response => {
|
|
||||||
originalCsjgMap.value[uniqueKey] = newCsjg;
|
|
||||||
emits("update:hasChanges", true);
|
|
||||||
ElMessage.success("结果保存成功");
|
|
||||||
}) .catch(error => {
|
|
||||||
ElMessage.error(error.message || "保存接口调用失败,已恢复原结果");
|
|
||||||
row.csjg = oldCsjg;
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('保存失败:', error);
|
|
||||||
ElMessage.error(error.message || "保存接口调用失败,已恢复原结果");
|
|
||||||
// 回滚值
|
|
||||||
row.csjg = oldCsjg;
|
|
||||||
} finally {
|
|
||||||
// 清除提交中标记
|
|
||||||
isSaving.value[uniqueKey] = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理选择变化
|
|
||||||
*/
|
|
||||||
const handleSelectionChange = (val) => {
|
const handleSelectionChange = (val) => {
|
||||||
selectedRows.value = val;
|
selectedRows.value = val;
|
||||||
emits('delfalg', val.length === 0);
|
if (val.length === 0) {
|
||||||
|
emits('delfalg', true);
|
||||||
|
}else{
|
||||||
|
emits('delfalg', false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
// 新增行
|
||||||
/**
|
|
||||||
* 新增行
|
|
||||||
*/
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
|
// emits('add');
|
||||||
|
// 创建新行数据
|
||||||
const newRow = {
|
const newRow = {
|
||||||
// 生成临时ID确保唯一性
|
jyrq: tableKey.jyrq,
|
||||||
id: `temp_${Date.now()}`,
|
yq: tableKey.yq,
|
||||||
jyrq: tableKey.value?.jyrq,
|
ybh: tableKey.ybh
|
||||||
yq: tableKey.value?.yq,
|
|
||||||
ybh: tableKey.value?.ybh,
|
|
||||||
csjg: ""
|
|
||||||
};
|
};
|
||||||
|
// 添加到表格数据
|
||||||
tableData.value.push(newRow);
|
tableData.value.push(newRow);
|
||||||
|
// 动画结束后移除标记
|
||||||
|
// 可选:滚动到表格底部并聚焦到第一个输入框
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const tableBody = document.querySelector('.el-table__body-wrapper');
|
const tableData = document.querySelector('.el-table__body-wrapper');
|
||||||
if (tableBody) {
|
if (tableData) {
|
||||||
tableBody.scrollTop = tableBody.scrollHeight;
|
tableData.scrollTop = tableData.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 聚焦到新行的输入框
|
// 聚焦到新行的第一个输入框
|
||||||
const inputs = document.querySelectorAll('.full-width-input .el-input__inner');
|
const inputs = document.querySelectorAll('.el-input__inner');
|
||||||
if (inputs.length > 0) {
|
if (inputs.length > 0) {
|
||||||
inputs[inputs.length - 1].focus();
|
inputs[4].focus(); // 通常最后一个是操作列的按钮,所以取倒数第二个
|
||||||
}
|
}
|
||||||
|
})
|
||||||
updateOriginalCsjgMap();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
// 新增行核心方法:接收父组件传递的项目数据
|
|
||||||
const addRowFromDict = async (rowData) => {
|
|
||||||
if (!rowData?.xmdh) {
|
|
||||||
ElMessage.error("项目编码不能为空");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 1. 校验输入数据有效性
|
|
||||||
if (!rowData || !rowData.xmdh) {
|
|
||||||
ElMessage.error("新增失败:项目编码不能为空");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 检查是否重复添加同一项目(根据xmdh判断)
|
// 保存数据
|
||||||
const isDuplicate = tableData.value.some(item => item.xmdh === rowData.xmdh);
|
|
||||||
if (isDuplicate) {
|
|
||||||
ElMessage.warning(`项目【${rowData.xmmc}】已存在`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 补全新增行的必要字段(如无则初始化)
|
|
||||||
const newRow = { ...rowData, csjg: "" };
|
|
||||||
|
|
||||||
// 4. 添加到表格数据
|
|
||||||
tableData.value.push(newRow);
|
|
||||||
console.log("子组件新增行:", newRow);
|
|
||||||
|
|
||||||
// 3. emit同步给父组件(更新父组件的labResuts)
|
|
||||||
emit('update:tableData', [...tableData.value]);
|
|
||||||
// 4. 同步缓存
|
|
||||||
await nextTick();
|
|
||||||
updateOriginalCsjgMap();
|
|
||||||
|
|
||||||
|
|
||||||
// 5. 自动聚焦
|
|
||||||
nextTick(() => {
|
|
||||||
const lastInput = document.querySelector(`.el-table__row:last-child .csjg-input .el-input__inner`);
|
|
||||||
if (lastInput) lastInput.focus();
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`成功新增项目行:`, newRow);
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* 保存数据
|
|
||||||
*/
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
if (hasChanges.value) {
|
if (hasChanges.value) {
|
||||||
emits('save', props.tableData);
|
emits('save', props.tableData);
|
||||||
updateOriginalCsjgMap();
|
// 保存后更新原始数据
|
||||||
emits("update:hasChanges", false);
|
// originalData.value = JSON.parse(JSON.stringify(props.tableData));
|
||||||
|
hasChanges.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
// 删除行
|
||||||
* 删除行
|
|
||||||
*/
|
|
||||||
const handleDelete = (row) => {
|
const handleDelete = (row) => {
|
||||||
emits("delete", row);
|
emits('delete', row);
|
||||||
tableData.value = tableData.value.filter((item) => item.id !== row.id);
|
tableData.value = tableData.value.filter(item => item.id !== row.id);
|
||||||
updateOriginalCsjgMap();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
// 批量删除(调用API)
|
||||||
* 批量删除
|
|
||||||
*/
|
|
||||||
const handleBatchDelete = async () => {
|
const handleBatchDelete = async () => {
|
||||||
if (selectedRows.value.length === 0) return;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ElMessageBox.confirm(
|
if (selectedRows.length === 0) {
|
||||||
`确定要删除选中的 ${selectedRows.value.length} 条记录吗?`,
|
return;
|
||||||
'提示',
|
|
||||||
{
|
|
||||||
confirmButtonText: '确定',
|
|
||||||
cancelButtonText: '取消',
|
|
||||||
type: 'warning'
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
await deleteresult(selectedRows.value);
|
|
||||||
emits('fetchLabResults');
|
|
||||||
ElMessage.success('删除成功');
|
|
||||||
} catch (error) {
|
|
||||||
if (error !== 'cancel') { // 排除用户取消的情况
|
|
||||||
ElMessage.error('删除失败: ' + (error.message || '未知错误'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
// 确认删除
|
||||||
|
await ElMessageBox.confirm(
|
||||||
|
`确定要删除选中的 ${selectedRows.value.length} 条记录吗?`,
|
||||||
|
'提示',
|
||||||
|
{
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
await deleteresult(selectedRows.value);
|
||||||
* 重置表格的修改状态
|
fetchLabResults();
|
||||||
*/
|
} catch (error) {
|
||||||
|
// 错误已经在拦截器中处理,这里可以不做处理或添加额外逻辑
|
||||||
|
console.error('删除失败:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// 重置表格的修改状态
|
||||||
const resetChange = () => {
|
const resetChange = () => {
|
||||||
|
// 原始数据副本,用于检测变化
|
||||||
originalData.value = JSON.parse(JSON.stringify(props.tableData));
|
originalData.value = JSON.parse(JSON.stringify(props.tableData));
|
||||||
updateOriginalCsjgMap();
|
hasChanges.value = false;
|
||||||
emits("update:hasChanges", false);
|
|
||||||
};
|
};
|
||||||
|
const fetchLabResults = () => {
|
||||||
/**
|
|
||||||
* 刷新数据
|
|
||||||
*/
|
|
||||||
const fetchLabResults = () => {
|
|
||||||
emits('fetchLabResults');
|
emits('fetchLabResults');
|
||||||
};
|
}
|
||||||
|
// 监听数据变化
|
||||||
|
watch(() => props.tableData, (newVal, oldVal) => {
|
||||||
|
// 简单比较数据是否有变化
|
||||||
|
//hasChanges.value = JSON.stringify(newVal) !== JSON.stringify(originalData.value);
|
||||||
|
}, { deep: true });
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取行号
|
// 获取行号(支持分页时显示正确行号)
|
||||||
*/
|
|
||||||
const getRowIndex = (index) => {
|
const getRowIndex = (index) => {
|
||||||
|
// 如果有分页,可以根据当前页码计算真实行号
|
||||||
|
// return (currentPage - 1) * pageSize + index + 1;
|
||||||
|
// 无分页时直接返回索引+1
|
||||||
return index + 1;
|
return index + 1;
|
||||||
};
|
};
|
||||||
// 子组件(labresult.vue):修改缓存初始化逻辑,监听tableData非空后再执行
|
|
||||||
onMounted(() => {
|
|
||||||
// 若初始tableData为空,等待父组件数据加载后再初始化缓存
|
|
||||||
if (props.tableData.length > 0) {
|
|
||||||
updateOriginalCsjgMap();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// 子组件(labresult.vue):修改watch逻辑
|
|
||||||
// 增强watch:当tableData从空变为非空时,初始化缓存
|
|
||||||
watch(
|
|
||||||
() => props.tableData.length,
|
|
||||||
(newLength, oldLength) => {
|
|
||||||
// 只有当tableData从空(0)变为有数据(>0)时,才初始化缓存
|
|
||||||
if (oldLength === 0 && newLength > 0) {
|
|
||||||
updateOriginalCsjgMap();
|
|
||||||
console.log("子组件:父组件数据加载完成,初始化缓存");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// 暴露方法给父组件
|
// 暴露方法给父组件
|
||||||
defineExpose({
|
defineExpose({
|
||||||
handleAdd,
|
handleAdd,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
handleSave,
|
handleSave,
|
||||||
handleBatchDelete,
|
handleBatchDelete
|
||||||
resetChange,
|
|
||||||
addRowFromDict,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* 移除单元格内边距 */
|
||||||
.custom-table-container /deep/ .el-table__cell {
|
.custom-table-container /deep/ .el-table__cell {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 表格行高 */
|
||||||
.custom-table-container /deep/ .el-table__row {
|
.custom-table-container /deep/ .el-table__row {
|
||||||
height: var(--table-row-height) !important;
|
height: var(--table-row-height) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 输入框占满单元格 */
|
||||||
.full-width-input /deep/ .el-input__inner {
|
.full-width-input /deep/ .el-input__inner {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(var(--table-row-height) - 2px);
|
height: calc(var(--table-row-height) - 2px); /* 减去上下边框 */
|
||||||
padding: 0 8px; /* 增加内边距提升输入体验 */
|
padding: 0 0px; /* 减小内边距 */
|
||||||
border: 0px solid #dcdfe6;
|
border: 0px solid #dcdfe6;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background-color: transparent;
|
background-color: transparent; /* 可选:透明背景 */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 输入框聚焦效果 */
|
||||||
.full-width-input /deep/ .el-input__inner:focus {
|
.full-width-input /deep/ .el-input__inner:focus {
|
||||||
border-color: #409eff;
|
border-color: #409eff;
|
||||||
box-shadow: 0 0 0 1px rgba(64, 158, 255, 0.2);
|
box-shadow: 0 0 0 0px rgba(64, 158, 255, 0.2);
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
|
/* 新增行动画 */
|
||||||
.el-table__body-wrapper {
|
.el-table__body-wrapper {
|
||||||
overflow: visible !important;
|
overflow: visible !important; /* 确保动画不被裁剪 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.new-row-enter-active {
|
.new-row-enter-active {
|
||||||
@ -415,4 +236,5 @@ defineExpose({
|
|||||||
from { opacity: 0; transform: translateY(10px); }
|
from { opacity: 0; transform: translateY(10px); }
|
||||||
to { opacity: 1; transform: translateY(0); }
|
to { opacity: 1; transform: translateY(0); }
|
||||||
}
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
@ -1,186 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- 遮罩层 -->
|
|
||||||
<div
|
|
||||||
v-if="visible"
|
|
||||||
class="dialog-mask"
|
|
||||||
@click="handleMaskClick"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<!-- 弹窗主体 -->
|
|
||||||
<div
|
|
||||||
v-if="visible"
|
|
||||||
class="dialog-wrapper"
|
|
||||||
>
|
|
||||||
<div class="dialog-container">
|
|
||||||
<!-- 标题 -->
|
|
||||||
<div class="dialog-header">
|
|
||||||
<h3>操作原因</h3>
|
|
||||||
<button class="close-btn" @click="handleCancel">×</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 内容区 -->
|
|
||||||
<div class="dialog-body">
|
|
||||||
<p class="reason-text">{{ reasonText }}</p>
|
|
||||||
<textarea
|
|
||||||
v-model="inputValue"
|
|
||||||
class="reason-input"
|
|
||||||
placeholder="请输入操作原因..."
|
|
||||||
rows="4"
|
|
||||||
></textarea>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 按钮区 -->
|
|
||||||
<div class="dialog-footer">
|
|
||||||
<button class="btn cancel" @click="handleCancel">取消</button>
|
|
||||||
<button class="btn confirm" @click="handleConfirm">确认</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { defineProps, defineEmits, ref } from 'vue';
|
|
||||||
|
|
||||||
// 组件属性
|
|
||||||
const props = defineProps({
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
reasonText: {
|
|
||||||
type: String,
|
|
||||||
default: '请填写操作原因'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 组件事件
|
|
||||||
const emit = defineEmits(['update:visible', 'onConfirm', 'onCancel']);
|
|
||||||
|
|
||||||
// 输入框内容
|
|
||||||
const inputValue = ref('');
|
|
||||||
|
|
||||||
// 确认按钮点击
|
|
||||||
const handleConfirm = () => {
|
|
||||||
emit('onConfirm', inputValue.value); // 传递输入值
|
|
||||||
emit('update:visible', false);
|
|
||||||
inputValue.value = ''; // 重置输入
|
|
||||||
};
|
|
||||||
|
|
||||||
// 取消按钮点击
|
|
||||||
const handleCancel = () => {
|
|
||||||
emit('onCancel');
|
|
||||||
emit('update:visible', false);
|
|
||||||
inputValue.value = ''; // 重置输入
|
|
||||||
};
|
|
||||||
|
|
||||||
// 遮罩层点击
|
|
||||||
const handleMaskClick = () => {
|
|
||||||
handleCancel();
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* 基础样式与之前保持一致,确保按钮边框和输入框正常 */
|
|
||||||
.dialog-mask {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background: rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-wrapper {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1001;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-container {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 500px;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
padding: 15px 20px;
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-header h3 {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-btn {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
font-size: 20px;
|
|
||||||
color: #999;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-body {
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reason-text {
|
|
||||||
margin: 0 0 15px 0;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reason-input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
border-radius: 4px;
|
|
||||||
resize: vertical;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reason-input:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #4096ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-footer {
|
|
||||||
padding: 15px 20px;
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
padding: 6px 16px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cancel {
|
|
||||||
margin-right: 10px;
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
background: #fff;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.confirm {
|
|
||||||
border: 1px solid #4096ff;
|
|
||||||
background: #4096ff;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -1,340 +0,0 @@
|
|||||||
<template>
|
|
||||||
<!-- 遮罩层 -->
|
|
||||||
<div
|
|
||||||
v-if="visible"
|
|
||||||
class="dialog-mask"
|
|
||||||
@click="handleCancel"
|
|
||||||
></div>
|
|
||||||
|
|
||||||
<!-- 弹窗主体 -->
|
|
||||||
<div
|
|
||||||
v-if="visible"
|
|
||||||
class="dialog-container"
|
|
||||||
>
|
|
||||||
<div class="dialog-box">
|
|
||||||
<!-- 标题区域 -->
|
|
||||||
<div class="dialog-header">
|
|
||||||
<h3 class="dialog-title">危急值结果上报</h3>
|
|
||||||
<button
|
|
||||||
class="dialog-close"
|
|
||||||
@click="handleCancel"
|
|
||||||
aria-label="关闭"
|
|
||||||
>
|
|
||||||
<span>×</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 内容区域 -->
|
|
||||||
<div class="dialog-body">
|
|
||||||
<div class="red-static-text">{{ msgdata }}</div>
|
|
||||||
<el-col :span="1">
|
|
||||||
<el-form-item label="上报方式" prop="uploadTp">
|
|
||||||
<el-radio-group v-model="uploadTp" size="default">
|
|
||||||
<el-radio v-for="(item, index) in uploadtypeptions" :key="index" :label="item.value"
|
|
||||||
:disabled="item.disabled">{{item.label}}</el-radio>
|
|
||||||
</el-radio-group>
|
|
||||||
</el-form-item>
|
|
||||||
</el-col>
|
|
||||||
<div class="form-item" v-if="uploadTp === 2">
|
|
||||||
<label class="form-label">电话通知人</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model.trim="userId"
|
|
||||||
class="form-input"
|
|
||||||
placeholder="请输入医生工号"
|
|
||||||
@keyup.enter="handleupload"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div class="form-item" v-if="uploadTp === 2">
|
|
||||||
<label class="form-label">联系电话</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
v-model="phone"
|
|
||||||
class="form-input"
|
|
||||||
placeholder="请输入联系电话"
|
|
||||||
@keyup.enter="handleupload"
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 错误提示 -->
|
|
||||||
<p v-if="errorMsg" class="error-message">{{ errorMsg }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 按钮区域 -->
|
|
||||||
<div class="dialog-footer">
|
|
||||||
<button
|
|
||||||
class="btn btn-cancel"
|
|
||||||
@click="handleCancel"
|
|
||||||
>
|
|
||||||
取消
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="btn btn-upload"
|
|
||||||
@click="handleupload"
|
|
||||||
:disabled="isSubmitDisabled"
|
|
||||||
>
|
|
||||||
确认上报
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { defineProps, defineEmits, ref, watch } from 'vue';
|
|
||||||
const uploadtypeptions = ref([{
|
|
||||||
"label": "系统通知",
|
|
||||||
"value": 1
|
|
||||||
}, {
|
|
||||||
"label": "电话通知",
|
|
||||||
"value": 2
|
|
||||||
}])
|
|
||||||
// 组件属性
|
|
||||||
const props = defineProps({
|
|
||||||
// 控制弹窗显示/隐藏
|
|
||||||
visible: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
},
|
|
||||||
// 弹窗内容
|
|
||||||
msgdata: {
|
|
||||||
type: String,
|
|
||||||
default: ''
|
|
||||||
},
|
|
||||||
// 显示规则
|
|
||||||
showRules: {
|
|
||||||
type: Number,
|
|
||||||
default:1
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 组件事件
|
|
||||||
const emit = defineEmits([
|
|
||||||
'update:visible', // 控制弹窗显示状态
|
|
||||||
'onupload', // 验证成功回调
|
|
||||||
'onCancel' // 取消验证回调
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 表单数据
|
|
||||||
const uploadTp = ref('1');
|
|
||||||
const userId = ref('');
|
|
||||||
const phone = ref('');
|
|
||||||
const errorMsg = ref('');
|
|
||||||
|
|
||||||
// 监听弹窗显示状态,重置表单
|
|
||||||
watch(
|
|
||||||
() => props.visible,
|
|
||||||
(newVal) => {
|
|
||||||
if (newVal) {
|
|
||||||
// 打开弹窗时重置表单
|
|
||||||
uploadTp.value = 1; // 打开弹窗时默认选中1
|
|
||||||
userId.value = '';
|
|
||||||
phone.value = '';
|
|
||||||
errorMsg.value = '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const isSubmitDisabled = computed(() => {
|
|
||||||
// 系统通知(1):无需其他字段,直接可提交
|
|
||||||
if (uploadTp.value === 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// 电话通知(2):需填写通知人和电话
|
|
||||||
return !userId.value || !phone.value;
|
|
||||||
});
|
|
||||||
// 处理确认验证
|
|
||||||
const handleupload = () => {
|
|
||||||
errorMsg.value = ''; // 清空之前的错误提示
|
|
||||||
// 基础验证
|
|
||||||
if(uploadTp.value===2) {
|
|
||||||
if (!userId.value) {
|
|
||||||
errorMsg.value = '请输入用户工号';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(props.showRules===3) {
|
|
||||||
if (!phone.value) {
|
|
||||||
errorMsg.value = '请输入电话';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 验证通过,返回用户工号
|
|
||||||
emit('onupload', {
|
|
||||||
userId: userId.value,
|
|
||||||
phone: phone.value,
|
|
||||||
uploadTp:uploadTp.value
|
|
||||||
});
|
|
||||||
|
|
||||||
// 关闭弹窗
|
|
||||||
emit('update:visible', false);
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理取消
|
|
||||||
const handleCancel = () => {
|
|
||||||
emit('onCancel');
|
|
||||||
emit('update:visible', false);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
/* 遮罩层 */
|
|
||||||
.dialog-mask {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
|
||||||
z-index: 1000;
|
|
||||||
transition: opacity 0.3s;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 弹窗容器 */
|
|
||||||
.dialog-container {
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
z-index: 1001;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 弹窗主体 */
|
|
||||||
.dialog-box {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 400px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 标题区域 */
|
|
||||||
.dialog-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 16px 20px;
|
|
||||||
border-bottom: 1px solid #f0f0f0;
|
|
||||||
background-color: #f9fafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-title {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-close {
|
|
||||||
padding: 0;
|
|
||||||
background: transparent;
|
|
||||||
border: none;
|
|
||||||
font-size: 20px;
|
|
||||||
color: #999;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog-close:hover {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 内容区域 */
|
|
||||||
.dialog-body {
|
|
||||||
padding: 24px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-item {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input {
|
|
||||||
width: 100%;
|
|
||||||
padding: 10px 12px;
|
|
||||||
border: 1px solid #dcdfe6;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
transition: border-color 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.form-input:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #4096ff;
|
|
||||||
box-shadow: 0 0 0 2px rgba(64, 150, 255, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.error-message {
|
|
||||||
margin: 8px 0 0;
|
|
||||||
color: #f56c6c;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 按钮区域 */
|
|
||||||
.dialog-footer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
padding: 12px 20px;
|
|
||||||
border-top: 1px solid #f0f0f0;
|
|
||||||
background-color: #f9fafb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 4px;
|
|
||||||
font-size: 14px;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-cancel {
|
|
||||||
margin-right: 10px;
|
|
||||||
border: 1px solid #dcdfe6;
|
|
||||||
background-color: #fff;
|
|
||||||
color: #606266;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-cancel:hover {
|
|
||||||
background-color: #f5f7fa;
|
|
||||||
border-color: #c0c4cc;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-upload {
|
|
||||||
border: 1px solid #4096ff;
|
|
||||||
background-color: #4096ff;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-upload:hover {
|
|
||||||
background-color: #66b1ff;
|
|
||||||
border-color: #66b1ff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-upload:disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
cursor: not-allowed;
|
|
||||||
background-color: #4096ff;
|
|
||||||
border-color: #4096ff;
|
|
||||||
}
|
|
||||||
.red-static-text {
|
|
||||||
color: red; /* 字体颜色设为红色 */
|
|
||||||
white-space: pre-wrap; /* 保留空格和换行(可选,配合 pre 标签或手动换行时使用) */
|
|
||||||
line-height: 1.6; /* 行高,增强多行可读性 */
|
|
||||||
/* 可选:添加其他样式 */
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 10px 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@ -11,7 +11,7 @@
|
|||||||
<el-button type="success" plain icon="Edit" :disabled="changeResultFlag" @click="handleUpdate" v-hasPermi="['system:dict:edit']">保存</el-button>
|
<el-button type="success" plain icon="Edit" :disabled="changeResultFlag" @click="handleUpdate" v-hasPermi="['system:dict:edit']">保存</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Edit" @click="handleCheck0" v-hasPermi="['system:dict:import']">初报</el-button>
|
<el-button type="success" plain icon="Edit" @click="handleCheck" v-hasPermi="['system:dict:import']">初报</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Download" @click="handleCheck" v-hasPermi="['system:dict:import']">初审</el-button>
|
<el-button type="success" plain icon="Download" @click="handleCheck" v-hasPermi="['system:dict:import']">初审</el-button>
|
||||||
@ -23,7 +23,7 @@
|
|||||||
<el-button type="success" plain icon="Download" @click="handleCheck" v-hasPermi="['system:dict:import']">审核</el-button>
|
<el-button type="success" plain icon="Download" @click="handleCheck" v-hasPermi="['system:dict:import']">审核</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="success" plain icon="Upload" @click="handleUnCheck" v-hasPermi="['system:dict:export']">取消审核</el-button>
|
<el-button type="info" plain icon="Upload" @click="handleUnCheck" v-hasPermi="['system:dict:export']">取消审核</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="1.5">
|
<el-col :span="1.5">
|
||||||
<el-button type="primary" plain icon="Edit" @click="handleUnCheck" v-hasPermi="['system:dict:export']">预览</el-button>
|
<el-button type="primary" plain icon="Edit" @click="handleUnCheck" v-hasPermi="['system:dict:export']">预览</el-button>
|
||||||
@ -77,22 +77,20 @@
|
|||||||
<el-row :gutter="5">
|
<el-row :gutter="5">
|
||||||
<el-col :span="5" :xs="24">
|
<el-col :span="5" :xs="24">
|
||||||
<div class="compact-form">
|
<div class="compact-form">
|
||||||
<LabPatForm v-model:labPat="labPat" :labPatKey="queryParams" ref="labPatRef" @save="savelabPat" @reset="resetlabPat" />
|
<LabPatForm v-model:labPat="labPat" ref="labPatRef" @save="savelabPat" @reset="resetlabPat" />
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="10" :xs="24">
|
<el-col :span="10" :xs="24">
|
||||||
<div class="compact-form">
|
<div class="compact-form">
|
||||||
<LabResultForm
|
<LabResultForm ref="labResultRef"
|
||||||
ref="labResultRef"
|
|
||||||
:tableData="labResuts"
|
:tableData="labResuts"
|
||||||
:tableKey="queryParams"
|
:tableKey="queryParams"
|
||||||
:is-data-refreshed="isDataRefreshed"
|
@add="addLabResult"
|
||||||
@add="addLabResult"
|
@delete="deleteLabResults"
|
||||||
@delete="deleteLabResults"
|
@edit="editLabResult"
|
||||||
@edit="editLabResult"
|
@delfalg="setdelResultFlag"
|
||||||
@delfalg="setdelResultFlag"
|
@changefalg="setchangeResultFlag"
|
||||||
@changefalg="setchangeResultFlag"
|
@fetchLabResults="fetchLabResults"
|
||||||
@fetchLabResults="fetchLabResults"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
@ -108,41 +106,7 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-col>
|
</el-col>
|
||||||
<ItemInput
|
|
||||||
ref="itemDictRef"
|
|
||||||
v-model="selectedItemValue"
|
|
||||||
:label-value.sync="selectedItemLabel"
|
|
||||||
:dict-type="'LAB_ITEM'"
|
|
||||||
:fetch-dict="fetchLabItemDict"
|
|
||||||
:dialog-title="'选择检验项目'"
|
|
||||||
:disabled="false"
|
|
||||||
:load-on-mount="false"
|
|
||||||
:table-data.sync="labResuts"
|
|
||||||
class="hidden-dict-input"
|
|
||||||
@select="handleItemSelect"
|
|
||||||
/>
|
|
||||||
</el-row>
|
</el-row>
|
||||||
<!-- 引入弹窗组件 -->
|
|
||||||
<unconfirmlog
|
|
||||||
v-model:visible="dialogVisible"
|
|
||||||
:reason-text="currentReason"
|
|
||||||
@onConfirm="unconfirmlogConfirm"
|
|
||||||
@onCancel="unconfirmlogCancel"
|
|
||||||
/>
|
|
||||||
<CheckUser
|
|
||||||
v-model:visible="showCheckUser"
|
|
||||||
:title="checktitle"
|
|
||||||
:validation-rules="{ userIdMinLength: 4, passwordMinLength: 6 }"
|
|
||||||
@onConfirm="handleAuthSuccess"
|
|
||||||
@onCancel="handleAuthCancel"
|
|
||||||
/>
|
|
||||||
<uploadwarning
|
|
||||||
v-model:visible="showuploadwarning"
|
|
||||||
:msgdata="warningMsgdata"
|
|
||||||
:showRules=1
|
|
||||||
@onupload="handleWarningSuccess"
|
|
||||||
@onCancel="handleWarningCancel"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -151,25 +115,17 @@ import {
|
|||||||
getDate,
|
getDate,
|
||||||
queryLabPatList,
|
queryLabPatList,
|
||||||
queryLabResults,
|
queryLabResults,
|
||||||
updateLabPat,
|
updateLabPatService,
|
||||||
queryLabPat,
|
queryLabPat,
|
||||||
check2, uncheck2, unconfirmlog, checkuser, reglimit, queryXmInfo
|
check2
|
||||||
} from "../../../api/liswork/work/LisWork.js";
|
} from "../../../api/liswork/work/LisWork.js";
|
||||||
import {querylabInstrList,querylabInstrListByLisgroup} from "../../../api/liswork/dict/LabInstr.js";
|
import {querylabInstrList,querylabInstrListByLisgroup} from "../../../api/liswork/dict/LabInstr.js";
|
||||||
import {getComDicts, queryComDictListService} from "../../../api/liswork/dict/ComDict.js";
|
import {getComDicts, queryComDictListService} from "../../../api/liswork/dict/ComDict.js";
|
||||||
import LabPatForm from './components/labpat.vue'
|
import LabPatForm from './components/labpat.vue'
|
||||||
import LabResultForm from './components/labresult.vue'
|
import LabResultForm from './components/labresult.vue'
|
||||||
import LabPatListForm from './components/labpatlist.vue'
|
import LabPatListForm from './components/labpatlist.vue'
|
||||||
import Unconfirmlog from './components/unconfirmlog.vue'
|
|
||||||
import Ddlb from './components/ddlb.vue'
|
import Ddlb from './components/ddlb.vue'
|
||||||
import CheckUser from './components/CheckUser.vue'
|
|
||||||
import uploadwarning from './components/uploadwarning.vue'
|
|
||||||
import UCKDictInput from './components/DictInput.vue';
|
|
||||||
import {ElMessage, ElMessageBox} from "element-plus";
|
|
||||||
import ItemInput from "@/views/liswork/work/components/ItemInput.vue";
|
|
||||||
|
|
||||||
|
|
||||||
const showuploadwarning = ref(false);
|
|
||||||
const single = ref(true);
|
const single = ref(true);
|
||||||
const delResultFlag = ref(true);
|
const delResultFlag = ref(true);
|
||||||
const changeResultFlag = ref(true);
|
const changeResultFlag = ref(true);
|
||||||
@ -217,10 +173,6 @@ const setInstr=ref('')
|
|||||||
const yq0=ref('')
|
const yq0=ref('')
|
||||||
const jyrq0=ref('')
|
const jyrq0=ref('')
|
||||||
const ybh0=ref('')
|
const ybh0=ref('')
|
||||||
const checktitle=ref('操作人身份验证')
|
|
||||||
const nextstepname=ref('')
|
|
||||||
const warningMsgdata=ref('')
|
|
||||||
const checkuserid=ref('')
|
|
||||||
const querydata = reactive({
|
const querydata = reactive({
|
||||||
form: {},
|
form: {},
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -230,9 +182,7 @@ const querydata = reactive({
|
|||||||
yq: '1',
|
yq: '1',
|
||||||
ybh: '1',
|
ybh: '1',
|
||||||
days: 1,
|
days: 1,
|
||||||
instrGroup:'#',
|
instrGroup:'#'
|
||||||
problemId:0,
|
|
||||||
yhdh:''
|
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
ybh: [],
|
ybh: [],
|
||||||
@ -242,119 +192,12 @@ const querydata = reactive({
|
|||||||
}
|
}
|
||||||
,
|
,
|
||||||
});
|
});
|
||||||
// 父组件:新增“数据刷新标记”,初始为false
|
|
||||||
const isDataRefreshed = ref(false);
|
|
||||||
// 新增:控制标记的重置(避免持续触发子组件缓存更新)
|
|
||||||
const resetDataRefreshFlag = () => {
|
|
||||||
// 延迟重置,确保子组件有足够时间接收标记并更新缓存
|
|
||||||
setTimeout(() => {
|
|
||||||
isDataRefreshed.value = false;
|
|
||||||
}, 100);
|
|
||||||
};
|
|
||||||
const { queryParams, form, rules } = toRefs(querydata);
|
const { queryParams, form, rules } = toRefs(querydata);
|
||||||
//子组件labResult.vue
|
//子组件labResult.vue
|
||||||
const labResultRef = ref(null);
|
const labResultRef = ref(null);
|
||||||
//子组件labPatRef.vue
|
//子组件labPatRef.vue
|
||||||
const labPatRef = ref(null);
|
const labPatRef = ref(null);
|
||||||
// 弹窗控制状态
|
|
||||||
const dialogVisible = ref(false);
|
|
||||||
const showCheckUser = ref(false);
|
|
||||||
// 弹窗显示的原因文本
|
|
||||||
const currentReason = ref('');
|
|
||||||
// 存储需要传递给API的参数
|
|
||||||
const apiParams = ref(null);
|
|
||||||
// 处理弹窗确认(获取返回值后调用API)
|
|
||||||
const unconfirmlogConfirm = async (inputValue) => {
|
|
||||||
try {
|
|
||||||
console.log('用户输入的操作原因:', inputValue);
|
|
||||||
// 调用API,携带用户输入的原因和之前保存的参数
|
|
||||||
loading.value = true;
|
|
||||||
unconfirmlog({...queryParams.value,reason: inputValue}).then(response => {
|
|
||||||
console.log('response:', response)
|
|
||||||
loading.value = false;
|
|
||||||
if(response.code=="0") {
|
|
||||||
runnextstepname();
|
|
||||||
}
|
|
||||||
}) .catch(error => {
|
|
||||||
console.error('审核失败', error);
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
// API调用成功后的处理
|
|
||||||
console.log('操作成功:', response);
|
|
||||||
// 可以添加成功提示、刷新数据等逻辑
|
|
||||||
} catch (error) {
|
|
||||||
console.error('操作失败:', error);
|
|
||||||
// 错误处理
|
|
||||||
} finally {
|
|
||||||
// 重置参数
|
|
||||||
apiParams.value = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// 处理弹窗取消
|
|
||||||
const unconfirmlogCancel = () => {
|
|
||||||
console.log('用户取消了操作');
|
|
||||||
// 重置参数
|
|
||||||
apiParams.value = null;
|
|
||||||
cancalnextstepname();
|
|
||||||
};
|
|
||||||
// 处理验证成功
|
|
||||||
const handleAuthSuccess = async (userInfo) => {
|
|
||||||
console.log('验证信息:', userInfo);
|
|
||||||
// 调用后端接口进行实际验证
|
|
||||||
loading.value = true;
|
|
||||||
checkuser({yhdh: userInfo.userId,mm: userInfo.password}).then(response => {
|
|
||||||
console.log('response:', response)
|
|
||||||
loading.value = false;
|
|
||||||
console.log('userInfo:',userInfo);
|
|
||||||
if(response.code=="0") {
|
|
||||||
checkuserid.value=userInfo.userId;
|
|
||||||
runnextstepname();
|
|
||||||
}
|
|
||||||
}) .catch(error => {
|
|
||||||
console.error('验证接口调用失败', error);
|
|
||||||
loading.value = false;
|
|
||||||
checkuserid.value='';
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理取消验证
|
|
||||||
const handleAuthCancel = () => {
|
|
||||||
console.log('用户取消了验证');
|
|
||||||
// 执行取消后的操作
|
|
||||||
cancalnextstepname();
|
|
||||||
};
|
|
||||||
// 处理危急值登记
|
|
||||||
const handleWarningSuccess = async (userInfo) => {
|
|
||||||
console.log('处理危急值登记:', userInfo);
|
|
||||||
// 调用后端接口进行实际验证
|
|
||||||
loading.value = true;
|
|
||||||
reglimit({...queryParams.value,qrr: userInfo.userId,tzfs: userInfo.uploadTp,phone:userInfo.phone}).then(response => {
|
|
||||||
console.log('危急值response:', response.code);
|
|
||||||
loading.value = false;
|
|
||||||
if(response.code=="0") {
|
|
||||||
runnextstepname();
|
|
||||||
}
|
|
||||||
if(response.code=="4") {
|
|
||||||
ElMessageBox.confirm(response.msg, '系统提示', { confirmButtonText: '是', cancelButtonText: '否', type: 'warning' }).then(() => {
|
|
||||||
queryParams.value.problemId=queryParams.value.problemId+1;
|
|
||||||
handleWarningSuccess(userInfo);
|
|
||||||
}).catch(() => {
|
|
||||||
runnextstepname();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}) .catch(error => {
|
|
||||||
console.error('处理危急值登记接口调用失败', error);
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理取消验证
|
|
||||||
const handleWarningCancel = () => {
|
|
||||||
console.log('用户取消了登记');
|
|
||||||
// 执行取消后的操作
|
|
||||||
cancalnextstepname();
|
|
||||||
};
|
|
||||||
// 页面载入时获取基本默认值参数信息,后面有扩展需要都放这里
|
// 页面载入时获取基本默认值参数信息,后面有扩展需要都放这里
|
||||||
const loadYqConfig = async () => {
|
const loadYqConfig = async () => {
|
||||||
// 使用 .value 获取响应式数据的值
|
// 使用 .value 获取响应式数据的值
|
||||||
@ -470,10 +313,6 @@ const fetchLabResults = async () => {
|
|||||||
// console.log('RESULT:', response);
|
// console.log('RESULT:', response);
|
||||||
labResuts.value = response.data;
|
labResuts.value = response.data;
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
// 关键:设置“数据刷新标记”为true(删除后数据变化,需更新子组件缓存)
|
|
||||||
isDataRefreshed.value = true;
|
|
||||||
// 数据刷新后重置标记
|
|
||||||
resetDataRefreshFlag();
|
|
||||||
}) .catch(error => {
|
}) .catch(error => {
|
||||||
console.error('列表数据加载失败', error);
|
console.error('列表数据加载失败', error);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
@ -543,14 +382,11 @@ const selectJob = async (job) => {
|
|||||||
queryParams.value.jyrq = job.jyrq;
|
queryParams.value.jyrq = job.jyrq;
|
||||||
queryParams.value.yq = job.yq;
|
queryParams.value.yq = job.yq;
|
||||||
queryParams.value.ybh = job.ybh;
|
queryParams.value.ybh = job.ybh;
|
||||||
|
|
||||||
checkQuery()
|
checkQuery()
|
||||||
isDataRefreshed.value = true;
|
|
||||||
//await nextTick();
|
//await nextTick();
|
||||||
// 获取对应的明细数据
|
// 获取对应的明细数据
|
||||||
await fetchLabPat();
|
await fetchLabPat();
|
||||||
await fetchLabResults();
|
await fetchLabResults();
|
||||||
resetDataRefreshFlag();
|
|
||||||
}
|
}
|
||||||
//样本列表检索时刷新列表信息
|
//样本列表检索时刷新列表信息
|
||||||
const searchJobs = async (text, page, size) => {
|
const searchJobs = async (text, page, size) => {
|
||||||
@ -591,8 +427,7 @@ const setchangeResultFlag = (value) =>{
|
|||||||
}
|
}
|
||||||
//新增
|
//新增
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
// labResultRef.value?.handleAdd();
|
labResultRef.value?.handleAdd();
|
||||||
openItemDictDialog();
|
|
||||||
};
|
};
|
||||||
function handleUpdate(){
|
function handleUpdate(){
|
||||||
}
|
}
|
||||||
@ -601,78 +436,21 @@ function handleDelete(){
|
|||||||
}
|
}
|
||||||
function loadingPatLabel(){
|
function loadingPatLabel(){
|
||||||
// labPatRef.value?.loadingLabel();
|
// labPatRef.value?.loadingLabel();
|
||||||
}
|
|
||||||
function handleCheck0(){
|
|
||||||
|
|
||||||
}
|
}
|
||||||
function handleCheck(){
|
function handleCheck(){
|
||||||
queryParams.value.problemId=0;
|
|
||||||
nextstepname.value='handleCheck2';
|
|
||||||
queryParams.value.yhdh=checkuserid.value
|
|
||||||
if(queryParams.value.yhdh=='') {
|
|
||||||
checktitle.value='审核人工号密码验证'
|
|
||||||
showCheckUser.value = true;
|
|
||||||
}else {
|
|
||||||
handleCheck2();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function handleCheck2(){
|
|
||||||
loading.value = true;
|
|
||||||
console.log('queryParams:', queryParams.value)
|
|
||||||
queryParams.value.yhdh=checkuserid.value
|
|
||||||
check2(queryParams.value).then(response => {
|
|
||||||
loading.value = false;
|
|
||||||
if(response.code=="4"&& response.problemId===4) {
|
|
||||||
console.log('queryParams1111:', queryParams.value)
|
|
||||||
nextstepname.value='handleCheck2';
|
|
||||||
queryParams.value.problemId = response.problemId;
|
|
||||||
// 保存需要传递给API的参数
|
|
||||||
apiParams.value = queryParams;
|
|
||||||
// 设置弹窗显示的原因文本
|
|
||||||
warningMsgdata.value = response.msg;
|
|
||||||
// 显示弹窗
|
|
||||||
showuploadwarning.value = true;
|
|
||||||
}
|
|
||||||
console.log('response:', response)
|
|
||||||
|
|
||||||
}).catch(error => {
|
|
||||||
console.error('审核失败', error);
|
|
||||||
loading.value = false;
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
function handleUnCheck(){
|
|
||||||
queryParams.value.problemId=0;
|
|
||||||
nextstepname.value='handleuncheck2';
|
|
||||||
queryParams.value.yhdh=checkuserid.value
|
|
||||||
if(queryParams.value.yhdh=='') {
|
|
||||||
checktitle.value='取消审核人工号密码验证'
|
|
||||||
showCheckUser.value = true;
|
|
||||||
}else {
|
|
||||||
handleuncheck2();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function handleuncheck2(){
|
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
queryParams.value.yhdh=checkuserid.value
|
console.log('queryParams:', queryParams.value)
|
||||||
uncheck2(queryParams.value).then(response => {
|
check2(queryParams.value).then(response => {
|
||||||
loading.value = false;
|
|
||||||
if(response.code=="4") {
|
|
||||||
nextstepname.value='handleuncheck2';
|
|
||||||
queryParams.value.problemId = response.problemId;
|
|
||||||
// 保存需要传递给API的参数
|
|
||||||
apiParams.value = queryParams;
|
|
||||||
// 设置弹窗显示的原因文本
|
|
||||||
currentReason.value = response.msg;
|
|
||||||
// 显示弹窗
|
|
||||||
dialogVisible.value = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
console.log('response:', response)
|
||||||
|
loading.value = false;
|
||||||
}) .catch(error => {
|
}) .catch(error => {
|
||||||
console.error('解除审核失败', error);
|
console.error('审核失败', error);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function handleUnCheck(){
|
||||||
|
}
|
||||||
function handlePrint(){
|
function handlePrint(){
|
||||||
}
|
}
|
||||||
function handleQueryDetail(){
|
function handleQueryDetail(){
|
||||||
@ -684,17 +462,13 @@ const handleQuery= async()=>{
|
|||||||
await loadlabPatList();
|
await loadlabPatList();
|
||||||
//暂时默认打开1号样本,后面由参数控制
|
//暂时默认打开1号样本,后面由参数控制
|
||||||
querydata.queryParams.ybh='1';
|
querydata.queryParams.ybh='1';
|
||||||
isDataRefreshed.value = true;
|
|
||||||
await handleQueryYbh();
|
await handleQueryYbh();
|
||||||
resetDataRefreshFlag();
|
|
||||||
}
|
}
|
||||||
//切换样本号时载入
|
//切换样本号时载入
|
||||||
const handleQueryYbh = async()=>{
|
const handleQueryYbh = async()=>{
|
||||||
if (checkQuery()===false) return false
|
if (checkQuery()===false) return false
|
||||||
isDataRefreshed.value = true;
|
|
||||||
await fetchLabPat();
|
await fetchLabPat();
|
||||||
await fetchLabResults();
|
await fetchLabResults();
|
||||||
resetDataRefreshFlag();
|
|
||||||
}
|
}
|
||||||
//主键空置拦截
|
//主键空置拦截
|
||||||
function checkQuery(){
|
function checkQuery(){
|
||||||
@ -714,137 +488,7 @@ function checkQuery(){
|
|||||||
yq0.value=querydata.queryParams.yq
|
yq0.value=querydata.queryParams.yq
|
||||||
ybh0.value=querydata.queryParams.ybh
|
ybh0.value=querydata.queryParams.ybh
|
||||||
}
|
}
|
||||||
function runnextstepname(){
|
|
||||||
if(nextstepname.value!=''){
|
|
||||||
switch(nextstepname.value) {
|
|
||||||
case 'handleuncheck2':
|
|
||||||
handleuncheck2();
|
|
||||||
break;
|
|
||||||
case 'handleCheck2':
|
|
||||||
handleCheck2();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// 当所有case都不匹配时执行(可选)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function cancalnextstepname(){
|
|
||||||
if(nextstepname.value!=''){
|
|
||||||
switch(nextstepname.value) {
|
|
||||||
case 'handleuncheck2':
|
|
||||||
ElMessage({ message: '取消操作,撤销审核失败!', type: 'error' })
|
|
||||||
break;
|
|
||||||
case 'handleCheck2':
|
|
||||||
ElMessage({ message: '取消操作,审核失败!', type: 'error' })
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// 当所有case都不匹配时执行(可选)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// -------------------------- 项目选择相关变量 --------------------------
|
|
||||||
const itemDictRef = ref(null); // DictInput组件引用
|
|
||||||
const selectedItemValue = ref(""); // 选择的项目编码xmdh
|
|
||||||
const selectedItemLabel = ref(""); // 选择的项目名称xmmc
|
|
||||||
|
|
||||||
// -------------------------- 1. 项目字典API调用方法(传递给DictInput) --------------------------
|
|
||||||
/**
|
|
||||||
* 项目字典加载方法:适配DictInput的fetchDict参数格式
|
|
||||||
* @param {String} dictType - 父组件传递的dict-type(无实际意义,可忽略)
|
|
||||||
* @returns {Promise<Array>} - 项目字典数据(格式需匹配DictInput要求:{value, label})
|
|
||||||
*/
|
|
||||||
// 父组件中:完善的项目字典加载方法
|
|
||||||
const fetchLabItemDict = async (dictType) => {
|
|
||||||
// 日志1:确认方法被调用
|
|
||||||
try {
|
|
||||||
// 1. 验证必要参数(如当前仪器yq)
|
|
||||||
if (!queryParams.value.yq) {
|
|
||||||
console.error("[fetchLabItemDict] 缺少必要参数:yq(仪器)");
|
|
||||||
ElMessage.error("请先选择仪器");
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 日志2:打印请求参数
|
|
||||||
const requestParams = {
|
|
||||||
pageNum: 1,
|
|
||||||
pageSize: 1000, // 加载足够多的项目
|
|
||||||
yq: queryParams.value.yq, // 当前选中的仪器
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2. 调用API(确保queryXmInfo是正确的API方法)
|
|
||||||
const response = await queryXmInfo(requestParams);
|
|
||||||
|
|
||||||
// 日志3:打印原始响应
|
|
||||||
|
|
||||||
// 3. 验证响应格式
|
|
||||||
if (!response) {
|
|
||||||
throw new Error("API返回为空");
|
|
||||||
}
|
|
||||||
if (response.code !== "0") { // 假设0为成功状态码
|
|
||||||
throw new Error(`API返回错误:${response.msg || "未知错误"}`);
|
|
||||||
}
|
|
||||||
if (!Array.isArray(response.data)) {
|
|
||||||
throw new Error(`API返回data不是数组,实际为:${typeof response.data}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 格式化数据(适配DictInput的{value, label}结构)
|
|
||||||
const formattedData = response.data.map((item, index) => {
|
|
||||||
// 验证项目数据完整性
|
|
||||||
if (!item.xmdh) {
|
|
||||||
console.warn(`[fetchLabItemDict] 第${index}条数据缺少xmdh(项目编码):`, item);
|
|
||||||
}
|
|
||||||
if (!item.xmmc) {
|
|
||||||
console.warn(`[fetchLabItemDict] 第${index}条数据缺少xmmc(项目名称):`, item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
value: item.xmdh || `未知编码_${index}`, // 确保value存在
|
|
||||||
label: item.xmmc || `未知名称_${index}`, // 确保label存在
|
|
||||||
dw: item.dw || "", // 单位(可选)
|
|
||||||
refs: item.refs || "", // 参考值(可选)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// 日志4:打印格式化后的数据量
|
|
||||||
return formattedData;
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
// 日志5:捕获并显示错误
|
|
||||||
console.error(`[fetchLabItemDict] 加载失败:`, error.message);
|
|
||||||
ElMessage.error(`项目字典加载失败:${error.message}`);
|
|
||||||
return []; // 失败时返回空数组,避免弹窗报错
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// -------------------------- 2. 打开项目选择弹窗 --------------------------
|
|
||||||
const openItemDictDialog = () => {
|
|
||||||
if (itemDictRef.value && typeof itemDictRef.value.openDictSelector === 'function') {
|
|
||||||
itemDictRef.value.openDictSelector(); // 确保方法存在再调用
|
|
||||||
} else {
|
|
||||||
console.warn("DictInput组件未加载完成或方法未暴露");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// -------------------------- 3. 处理项目选择结果:传递给labresult子组件新增行 --------------------------
|
|
||||||
const handleItemSelect = async (selectedItem) => {
|
|
||||||
// 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: queryParams.value.jyrq,
|
|
||||||
yq: queryParams.value.yq,
|
|
||||||
ybh: queryParams.value.ybh,
|
|
||||||
};
|
|
||||||
// 2. 调用子组件方法新增行(仅一次)
|
|
||||||
if (labResultRef.value && typeof labResultRef.value.addRowFromDict === 'function') {
|
|
||||||
await labResultRef.value.addRowFromDict(newRow);
|
|
||||||
ElMessage.success(`已新增项目:${newRow.xmmc}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
//打开页面需要先初始化的内容都放这里
|
//打开页面需要先初始化的内容都放这里
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
loadYqConfig();
|
loadYqConfig();
|
||||||
@ -853,7 +497,6 @@ onMounted(() => {
|
|||||||
loadlabPatList();
|
loadlabPatList();
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@ -876,15 +519,4 @@ onMounted(() => {
|
|||||||
color: blue;
|
color: blue;
|
||||||
|
|
||||||
}
|
}
|
||||||
.hidden-dict-input {
|
|
||||||
/* 定位到屏幕左侧外,视觉上不可见 */
|
|
||||||
position: absolute;
|
|
||||||
left: -9999px;
|
|
||||||
top: auto;
|
|
||||||
/* 防止占用布局空间 */
|
|
||||||
width: 1px;
|
|
||||||
height: 1px;
|
|
||||||
/* 防止意外聚焦 */
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user