Compare commits
3 Commits
2c4a3efba1
...
7e876ce499
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e876ce499 | ||
|
|
9244000fb0 | ||
|
|
02451a912f |
@ -26,25 +26,32 @@ export function getDate() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//增加字典数据
|
//
|
||||||
export function addLabPatService(data) {
|
export function changeresult(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/liswork/add',
|
url: '/lisworkoper/changeresult',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//修改字典数据
|
//修改病人信息
|
||||||
export function updateLabPatService(data) {
|
export function updateLabPat(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/liswork/update',
|
url: '/lisworkoper/changepat',
|
||||||
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',
|
||||||
@ -52,7 +59,22 @@ 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({
|
||||||
@ -71,3 +93,33 @@ 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,3 +1,4 @@
|
|||||||
|
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'
|
||||||
@ -123,7 +124,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: 'warning' })
|
ElMessage({ message: msg, type: 'success' })
|
||||||
return Promise.resolve(res.data)
|
return Promise.resolve(res.data)
|
||||||
} else if (code === 2) {
|
} else if (code === 2) {
|
||||||
//选择是否后续操作
|
//选择是否后续操作
|
||||||
@ -131,6 +132,13 @@ 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;
|
||||||
|
|||||||
@ -212,7 +212,6 @@ function handleQueryDetail() {
|
|||||||
resetData()
|
resetData()
|
||||||
}
|
}
|
||||||
|
|
||||||
//提交表单数据
|
|
||||||
function submitForm() {
|
function submitForm() {
|
||||||
proxy.$refs["dictRef"].validate(valid => {
|
proxy.$refs["dictRef"].validate(valid => {
|
||||||
if (valid) {
|
if (valid) {
|
||||||
|
|||||||
323
src/views/liswork/work/components/CheckUser.vue
Normal file
323
src/views/liswork/work/components/CheckUser.vue
Normal file
@ -0,0 +1,323 @@
|
|||||||
|
<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>
|
||||||
331
src/views/liswork/work/components/DictInputany.vue
Normal file
331
src/views/liswork/work/components/DictInputany.vue
Normal file
@ -0,0 +1,331 @@
|
|||||||
|
<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>
|
||||||
229
src/views/liswork/work/components/ItemInput.vue
Normal file
229
src/views/liswork/work/components/ItemInput.vue
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
<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,62 +4,110 @@
|
|||||||
<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" @update:labelValue="(label) => labPat.brlyLabel = label" dialog-title="选择病人来源"/>
|
<dict-input v-model="labPat.brly" :dict-type="'PT'" placeholder="请输入病人来源" :fetch-dict="fetchDict"
|
||||||
|
@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="labPat.jzbz" active-text="急诊" active-color="#FD0101"></el-switch>
|
<el-switch v-model="jzbzSwitch" active-text="急诊" active-color="#FD0101" @change="handleFieldChange"></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>
|
<el-input v-model="labPat.brdh" placeholder="请输入病历号"
|
||||||
|
@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>
|
<el-input v-model="labPat.brxm" placeholder="请输入姓名"
|
||||||
|
@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" @update:labelValue="(label) => labPat.brxbLabel = label"/>
|
<dict-input v-model="labPat.brxb" placeholder="性别" :dict-type="'SX'" :fetch-dict="fetchDict"
|
||||||
|
@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>
|
<el-input v-model="labPat.nl" placeholder="年龄"
|
||||||
|
@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" @update:labelValue="(label) => labPat.nldwLabel = label"/>
|
<dict-input v-model="labPat.nldw" placeholder="年月" :dict-type="'AU'" :fetch-dict="fetchDict"
|
||||||
|
@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" @update:labelValue="(label) => labPat.ksdhLabel = label"/>
|
<dict-input v-model="labPat.ksdh" placeholder="请输入科室" :dict-type="'DP'" :fetch-dict="fetchDict"
|
||||||
|
@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>
|
<el-input v-model="labPat.ch" placeholder="请输入床号"
|
||||||
|
@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" @update:labelValue="(label) => labPat.yblxLabel = label"/>
|
<dict-input v-model="labPat.yblx" placeholder="请输入样本类型" :dict-type="'BT'" :fetch-dict="fetchDict"
|
||||||
|
@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" @update:labelValue="(label) => labPat.sjysLabel = label"/>
|
<dict-input v-model="labPat.sjys" placeholder="请输入申请医生" :dict-type="'SRD'" :fetch-dict="fetchDict"
|
||||||
|
@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>
|
<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"
|
||||||
|
@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>
|
<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"
|
||||||
|
@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>
|
<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"
|
||||||
|
@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="请输入临床诊断"></el-input>
|
<el-input v-model="labPat.zd" placeholder="请输入临床诊断" @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.bz" placeholder="请输入备注"></el-input>
|
<el-input v-model="labPat.bz" placeholder="请输入备注" @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.yhdh" placeholder="请输入检验医生"></el-input>
|
<el-input v-model="labPat.yhdh" placeholder="请输入检验医生" @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.hdys" placeholder="请输入审核医生"></el-input>
|
<el-input v-model="labPat.hdys" placeholder="请输入审核医生" @blur="handleFieldChange" @keyup.enter="handleFieldChange"></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">
|
||||||
@ -79,6 +127,8 @@
|
|||||||
|
|
||||||
<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,
|
||||||
@ -90,41 +140,123 @@ 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)
|
*/
|
||||||
console.log('提交数据:', {
|
const handleDictSelect = async () => {
|
||||||
rawValue: props.labPat.brly,
|
// 字典选择后直接触发更新
|
||||||
label: props.labPat.brlyLabel,
|
await triggerApiUpdate();
|
||||||
...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 = () => {
|
||||||
emit('update:labPat', {
|
const resetData = {
|
||||||
|
...props.labPat,
|
||||||
brly: '',
|
brly: '',
|
||||||
brlyLabel: '',
|
brlyLabel: '',
|
||||||
ksdh: '',
|
ksdh: '',
|
||||||
ksdhLabel: '',
|
ksdhLabel: '',
|
||||||
sjys: '',
|
|
||||||
sjysLabel: '',
|
|
||||||
brxb: '',
|
brxb: '',
|
||||||
brxbLabel: '',
|
brxbLabel: '',
|
||||||
nldw: '',
|
nldw: '',
|
||||||
nldwLabel: '',
|
nldwLabel: '',
|
||||||
yblx: '',
|
jzbz: 0,
|
||||||
yblxLabel: '',
|
jgbz: 0
|
||||||
// 保留其他字段的默认值
|
};
|
||||||
...props.labPat,
|
emit('update:labPat', resetData);
|
||||||
jzbz: props.labPat.jzbz || 0,
|
lastValue.value = JSON.stringify(resetData);
|
||||||
jgbz: props.labPat.jgbz || 0
|
};
|
||||||
});
|
|
||||||
}
|
|
||||||
// 字典获取方法(适配子组件)
|
// 字典获取方法(适配子组件)
|
||||||
const fetchDict = async (dictType) => {
|
const fetchDict = async (dictType) => {
|
||||||
const dictRefs = await comDict(dictType);
|
const dictRefs = await comDict(dictType);
|
||||||
|
|||||||
@ -12,8 +12,12 @@
|
|||||||
:header-cell-style="{ backgroundColor: '#f5f7fa' }"
|
:header-cell-style="{ backgroundColor: '#f5f7fa' }"
|
||||||
>
|
>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
type="index" prop="id" label="" width="45" :index="getRowIndex" >
|
type="index"
|
||||||
</el-table-column>
|
prop="id"
|
||||||
|
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>
|
||||||
@ -25,7 +29,14 @@
|
|||||||
</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 v-model="scope.row.csjg" size="small" class="full-width-input"></el-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">
|
||||||
@ -35,114 +46,265 @@
|
|||||||
</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.od" size="small" class="full-width-input"></el-input>
|
<el-input v-model="scope.row.cutoff" 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, reactive, watch, toRefs, nextTick} from 'vue';
|
import { ref, toRefs, watch, nextTick, onMounted } from "vue";
|
||||||
import {deleteresult, queryLabResults} from "@/api/liswork/work/LisWork.js";
|
import { deleteresult, changeresult } from "@/api/liswork/work/LisWork.js";
|
||||||
import {delType} from "@/api/system/dict/type.js";
|
import { ElMessageBox, ElMessage } from "element-plus";
|
||||||
import {ElMessageBox} from "element-plus";
|
|
||||||
const { proxy } = getCurrentInstance();
|
// 组件属性定义
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
// 表格数据
|
|
||||||
tableData: { type: Array, default: () => [] },
|
tableData: { type: Array, default: () => [] },
|
||||||
//主键
|
|
||||||
tableKey: { type: Array, default: () => [] },
|
tableKey: { type: Array, default: () => [] },
|
||||||
// 部门选项
|
readonly: { type: Boolean, default: false },
|
||||||
// departments: {
|
hasChanges: { type: Boolean, default: false }
|
||||||
// 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;
|
||||||
if (val.length === 0) {
|
emits('delfalg', val.length === 0);
|
||||||
emits('delfalg', true);
|
|
||||||
}else{
|
|
||||||
emits('delfalg', false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
// 新增行
|
|
||||||
|
/**
|
||||||
|
* 新增行
|
||||||
|
*/
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
// emits('add');
|
|
||||||
// 创建新行数据
|
|
||||||
const newRow = {
|
const newRow = {
|
||||||
jyrq: tableKey.jyrq,
|
// 生成临时ID确保唯一性
|
||||||
yq: tableKey.yq,
|
id: `temp_${Date.now()}`,
|
||||||
ybh: tableKey.ybh
|
jyrq: tableKey.value?.jyrq,
|
||||||
|
yq: tableKey.value?.yq,
|
||||||
|
ybh: tableKey.value?.ybh,
|
||||||
|
csjg: ""
|
||||||
};
|
};
|
||||||
// 添加到表格数据
|
|
||||||
tableData.value.push(newRow);
|
tableData.value.push(newRow);
|
||||||
// 动画结束后移除标记
|
|
||||||
// 可选:滚动到表格底部并聚焦到第一个输入框
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const tableData = document.querySelector('.el-table__body-wrapper');
|
const tableBody = document.querySelector('.el-table__body-wrapper');
|
||||||
if (tableData) {
|
if (tableBody) {
|
||||||
tableData.scrollTop = tableData.scrollHeight;
|
tableBody.scrollTop = tableBody.scrollHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 聚焦到新行的第一个输入框
|
// 聚焦到新行的输入框
|
||||||
const inputs = document.querySelectorAll('.el-input__inner');
|
const inputs = document.querySelectorAll('.full-width-input .el-input__inner');
|
||||||
if (inputs.length > 0) {
|
if (inputs.length > 0) {
|
||||||
inputs[4].focus(); // 通常最后一个是操作列的按钮,所以取倒数第二个
|
inputs[inputs.length - 1].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();
|
||||||
// originalData.value = JSON.parse(JSON.stringify(props.tableData));
|
emits("update:hasChanges", false);
|
||||||
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 {
|
||||||
if (selectedRows.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 确认删除
|
|
||||||
await ElMessageBox.confirm(
|
await ElMessageBox.confirm(
|
||||||
`确定要删除选中的 ${selectedRows.value.length} 条记录吗?`,
|
`确定要删除选中的 ${selectedRows.value.length} 条记录吗?`,
|
||||||
'提示',
|
'提示',
|
||||||
@ -154,78 +316,95 @@ const handleBatchDelete = async () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
await deleteresult(selectedRows.value);
|
await deleteresult(selectedRows.value);
|
||||||
fetchLabResults();
|
emits('fetchLabResults');
|
||||||
|
ElMessage.success('删除成功');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// 错误已经在拦截器中处理,这里可以不做处理或添加额外逻辑
|
if (error !== 'cancel') { // 排除用户取消的情况
|
||||||
console.error('删除失败:', error);
|
ElMessage.error('删除失败: ' + (error.message || '未知错误'));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// 重置表格的修改状态
|
|
||||||
const resetChange = () => {
|
|
||||||
// 原始数据副本,用于检测变化
|
|
||||||
originalData.value = JSON.parse(JSON.stringify(props.tableData));
|
|
||||||
hasChanges.value = false;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重置表格的修改状态
|
||||||
|
*/
|
||||||
|
const resetChange = () => {
|
||||||
|
originalData.value = JSON.parse(JSON.stringify(props.tableData));
|
||||||
|
updateOriginalCsjgMap();
|
||||||
|
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 0px; /* 减小内边距 */
|
padding: 0 8px; /* 增加内边距提升输入体验 */
|
||||||
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 0px rgba(64, 158, 255, 0.2);
|
box-shadow: 0 0 0 1px 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 {
|
||||||
@ -236,5 +415,4 @@ 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>
|
||||||
186
src/views/liswork/work/components/unconfirmlog.vue
Normal file
186
src/views/liswork/work/components/unconfirmlog.vue
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
<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>
|
||||||
340
src/views/liswork/work/components/uploadwarning.vue
Normal file
340
src/views/liswork/work/components/uploadwarning.vue
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
<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="handleCheck" v-hasPermi="['system:dict:import']">初报</el-button>
|
<el-button type="success" plain icon="Edit" @click="handleCheck0" 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="info" plain icon="Upload" @click="handleUnCheck" v-hasPermi="['system:dict:export']">取消审核</el-button>
|
<el-button type="success" 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,14 +77,16 @@
|
|||||||
<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" ref="labPatRef" @save="savelabPat" @reset="resetlabPat" />
|
<LabPatForm v-model:labPat="labPat" :labPatKey="queryParams" 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 ref="labResultRef"
|
<LabResultForm
|
||||||
|
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"
|
||||||
@ -106,7 +108,41 @@
|
|||||||
/>
|
/>
|
||||||
</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>
|
||||||
|
|
||||||
@ -115,17 +151,25 @@ import {
|
|||||||
getDate,
|
getDate,
|
||||||
queryLabPatList,
|
queryLabPatList,
|
||||||
queryLabResults,
|
queryLabResults,
|
||||||
updateLabPatService,
|
updateLabPat,
|
||||||
queryLabPat,
|
queryLabPat,
|
||||||
check2
|
check2, uncheck2, unconfirmlog, checkuser, reglimit, queryXmInfo
|
||||||
} 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);
|
||||||
@ -173,6 +217,10 @@ 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: {
|
||||||
@ -182,7 +230,9 @@ const querydata = reactive({
|
|||||||
yq: '1',
|
yq: '1',
|
||||||
ybh: '1',
|
ybh: '1',
|
||||||
days: 1,
|
days: 1,
|
||||||
instrGroup:'#'
|
instrGroup:'#',
|
||||||
|
problemId:0,
|
||||||
|
yhdh:''
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
ybh: [],
|
ybh: [],
|
||||||
@ -192,12 +242,119 @@ 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 获取响应式数据的值
|
||||||
@ -313,6 +470,10 @@ 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;
|
||||||
@ -382,11 +543,14 @@ 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) => {
|
||||||
@ -427,7 +591,8 @@ const setchangeResultFlag = (value) =>{
|
|||||||
}
|
}
|
||||||
//新增
|
//新增
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
labResultRef.value?.handleAdd();
|
// labResultRef.value?.handleAdd();
|
||||||
|
openItemDictDialog();
|
||||||
};
|
};
|
||||||
function handleUpdate(){
|
function handleUpdate(){
|
||||||
}
|
}
|
||||||
@ -436,20 +601,77 @@ 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;
|
loading.value = true;
|
||||||
console.log('queryParams:', queryParams.value)
|
console.log('queryParams:', queryParams.value)
|
||||||
|
queryParams.value.yhdh=checkuserid.value
|
||||||
check2(queryParams.value).then(response => {
|
check2(queryParams.value).then(response => {
|
||||||
|
|
||||||
console.log('response:', response)
|
|
||||||
loading.value = false;
|
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 => {
|
}).catch(error => {
|
||||||
console.error('审核失败', error);
|
console.error('审核失败', error);
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
function handleUnCheck(){
|
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;
|
||||||
|
queryParams.value.yhdh=checkuserid.value
|
||||||
|
uncheck2(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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}) .catch(error => {
|
||||||
|
console.error('解除审核失败', error);
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
function handlePrint(){
|
function handlePrint(){
|
||||||
}
|
}
|
||||||
@ -462,13 +684,17 @@ 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(){
|
||||||
@ -488,7 +714,137 @@ 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();
|
||||||
@ -497,6 +853,7 @@ onMounted(() => {
|
|||||||
loadlabPatList();
|
loadlabPatList();
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
@ -519,4 +876,15 @@ 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