输血申请

This commit is contained in:
wuyy 2026-07-10 17:40:50 +08:00
parent 476c5ea082
commit e35a900f36
19 changed files with 2257 additions and 491 deletions

View File

@ -23,4 +23,61 @@ export function queryLisProject(query?: Object) {
method: 'post',
data: query
})
}
// 获取员工数据
export function queryUserInfo(query?: Object) {
return request({
url: '/bus/common/queryUserInfo',
method: 'get',
params: query
})
}
// 获取当前服务器时间
export function currentDateTime(query?: Object) {
return request({
url: '/bus/common/currentDateTime',
method: 'get',
params: query
})
}
// 获取有效的血液品种
export function getBloodBreed(query?: Object) {
return request({
url: '/bus/common/getBloodBreed',
method: 'get',
params: query
})
}
// 查询单病种信息列表
export function queryIllDiagnoseList(query?: Object) {
return request({
url: '/bus/doctor/apply/queryIllDiagnoseList',
method: 'get',
params: query
})
}
// 校验用户名和密码是否成功
export function checkLoginAffirm(query?: Object) {
return request({
url: '/bus/common/checkLoginAffirm',
method: 'get',
params: query
})
}
// 获取员工的部门类型
export function getDeptType(query?: Object) {
return request({
url: '/bus/common/getDeptType',
method: 'get',
params: query
})
}
// 查询手术字典
export function queryOperation(query?: Object) {
return request({
url: '/bus/common/queryOperation',
method: 'get',
params: query
})
}

View File

@ -0,0 +1,130 @@
/**
* @file application.ts
* @description: 输血申请模块接口
* @author: w
* @since: 2026-07-06
*/
import request from '@/utils/request'
// 查询申请单列表
export function querysqList(query?: Object) {
return request({
url: '/bus/doctor/apply/queryList',
method: 'get',
params: query
})
}
// 获取病人信息
export function getPatInfo(query?: Object) {
return request({
url: '/bus/doctor/apply/getPatInfo',
method: 'get',
params: query
})
}
// 自体血校验
export function checkSelfBlood(query?: Object) {
return request({
url: '/bus/doctor/apply/checkSelfBlood',
method: 'get',
params: query
})
}
// 校验是否符合输血指征的规则
export function checkCausalis(query?: Object) {
return request({
url: '/bus/doctor/apply/checkCausalis',
method: 'post',
data: query
})
}
// 保存前校验
export function savePreApplyInfo(query?: Object) {
return request({
url: '/bus/doctor/apply/savePreApplyInfo',
method: 'post',
data: query
})
}
// 保存申请单
export function saveApplyInfo(query?: Object) {
return request({
url: '/bus/doctor/apply/saveApplyInfo',
method: 'post',
data: query
})
}
// 查询单条申请单
export function queryApplyOne(query?: Object) {
return request({
url: '/bus/doctor/apply/queryApplyOne',
method: 'get',
params: query
})
}
// 查询输血前评估信息列表
export function queryApplyBeforeList(query?: Object) {
return request({
url: '/bus/doctor/apply/queryApplyBeforeList',
method: 'get',
params: query
})
}
// 申请单审核前校验
export function applyCheck(query?: Object) {
return request({
url: '/bus/doctor/apply/applyCheck',
method: 'post',
data: query
})
}
// 取消申请单审核
export function cancelApplyCheck(query?: Object) {
return request({
url: '/bus/doctor/apply/cancelApplyCheck',
method: 'get',
params: query
})
}
// 上级医生审核
export function applyMedicCheck(query?: Object) {
return request({
url: '/bus/doctor/apply/applyMedicCheck',
method: 'post',
data: query
})
}
// 取消上级医生审核
export function cancelApplyMedicCheck(query?: Object) {
return request({
url: '/bus/doctor/apply/cancelApplyMedicCheck',
method: 'post',
data: query
})
}
// 审核意见
export function checkExplain(query?: Object) {
return request({
url: '/bus/doctor/checkExplain/checkExplain',
method: 'post',
data: query
})
}
// 获取输血指征数据
export function queryCausailsList(query?: Object) {
return request({
url: '/bus/doctor/checkExplain/queryCausailsList',
method: 'get',
params: query
})
}
// 作废申请单
export function cancelApply(query?: Object) {
return request({
url: '/bus/doctor/apply/cancelApply',
method: 'get',
params: query
})
}

View File

@ -1,3 +1,11 @@
/**
* @file assessment.ts
* @description: 输血评估模块接口
* @author: w
* @since: 2026-07-06
*/
import request from '@/utils/request'
// 根据住院号获取病人信息

View File

@ -656,50 +656,91 @@ aside {
.vxe-table {
border: 1px solid #96B8D9 !important;
// border-top: none !important;
/* 蓝色外边框 */
border-radius: .5rem;
// border: 1px solid #ccc !important;
/* 可选:添加边框圆角 */
overflow: hidden;
}
.mytable-style {
.vxe-table.border--full {
border: 1px solid #ccc !important;
.vxe-header--column {
word-break: break-word;
background-color: #f6fafc !important;
color: #3c526f;
height: 1.875rem !important;
line-height: 1.875rem !important;
padding: 0 !important;
font-size: 16px;
border-color: #f6fafc !important;
.vxe-header--column,
.vxe-body--column,
.vxe-footer--column {
border-right: 1px solid #ccc !important;
border-bottom: 1px solid #ccc !important;
height: 30px;
line-height: 30px;
padding: 0 !important;
background-image: none !important;
&:last-child {
// border-right: none !important;
}
}
.vxe-footer--column {
border-bottom: none !important;
}
/* 表头最下方单元格强制底红线 */
.vxe-header--row:last-of-type .vxe-header--column {
border-bottom: 1px solid #ccc !important;
}
.vxe-body--row {
border-bottom: 1px solid #ccc !important;
}
.vxe-footer--row.vxe-footer--row {
border-top: 1px solid #ccc !important;
}
.vxe-header--row th {
height: 30px !important;
line-height: 30px;
padding: 0 !important;
}
.vxe-body--row td {
height: 30px !important;
line-height: 30px;
padding: 0 !important;
}
.vxe-footer--row td {
height: 30px !important;
line-height: 30px;
font-size: 13px;
font-weight: 700;
padding: 0 !important;
}
/* 清除最后一列重复竖线,避免双线重叠 */
.vxe-header--col:last-child .vxe-header--column,
.vxe-body--col:last-child .vxe-body--column,
.vxe-footer--col:last-child .vxe-footer--column {
border-right: none !important;
}
}
.vxe-table--render-default.is--padding .vxe-body--column .vxe-cell {
padding: 0 !important;
.vxe-table--render-default .vxe-table--footer-wrapper {
border-top: 1px solid #ccc !important;
}
.vxe-table--render-default .vxe-header--column .vxe-cell {
padding: 0 !important;
}
.vxe-table--render-default .vxe-body--column,
.vxe-footer--column,
.col--ellipsis {
height: 1.875rem !important;
line-height: 1.875rem !important;
}
.el-checkbox {
height: 1.875rem !important;
.vxe-table--header-wrapper {
border-bottom: 1px solid #ccc !important;
background-color: #eff6fa !important;
}
}
// 高亮
.vxe-table--render-default .vxe-body--row.row--current {
background-color: #a4beef !important;
@ -765,4 +806,41 @@ aside {
box-shadow: none !important;
}
}
}
.el-input.is-disabled .el-input__wrapper {
background-color: #f5f7fa !important;
}
.el-select__wrapper.is-disabled {
background-color: #f5f7fa !important;
}
.el-select__wrapper.is-disabled .el-select__selected-item {
color: #606266 !important;
}
.el-date-editor.is-disabled,
.el-date-editor.is-disabled .el-input__wrapper {
background-color: #f5f7fa !important;
}
.el-radio__input.is-disabled+span.el-radio__label,
.el-checkbox.is-disabled {
color: #606266 !important;
}
.el-radio__input.is-disabled.is-checked .el-radio__inner {
background: #00a5ff;
border-color: #00a5ff;
&::after {
background: #f5f7fa;
}
}
.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner {
background: #00a5ff;
}

View File

@ -0,0 +1,113 @@
<template>
<div>
<el-dialog v-model="checkShow" :title="title" width="500" :close-on-click-modal="false" :draggable="true"
@close="close">
<el-form ref="ruleFormRef" style="max-width: 600px" :model="ruleForm" :rules="rules" label-width="auto">
<el-form-item label="用户工号:" prop="yhdh">
<el-input ref="yhdhRef" v-model.trim="ruleForm.yhdh" placeholder="请输入用户工号" maxlength="20"
@keyup.enter="handleConfirm" />
</el-form-item>
<el-form-item label="密码:" prop="mm">
<el-input v-model.trim="ruleForm.mm" placeholder="请输入密码" type="mm" maxlength="20" show-password
@keyup.enter="handleConfirm" />
</el-form-item>
<el-form-item>
<div style="text-align: center; width: 100%;">
<el-button type="primary" @click="handleConfirm()"> 确认 </el-button>
<el-button @click="handleCancel">取消</el-button>
</div>
</el-form-item>
</el-form>
</el-dialog>
</div>
</template>
<script setup lang="ts">
// 组件属性
const props = defineProps({
// 弹窗标题(由外部参数控制)
title: {
type: String,
default: '用户身份验证'
},
// 验证规则(可选,由外部传入)
validationRules: {
type: Object,
default: () => ({
// 工号最小长度
userIdMinLength: 3,
// 密码最小长度
passwordMinLength: 6
})
}
});
// 组件事件
const emit = defineEmits([
'onConfirm', // 验证成功回调
'onCancel'
]);
// 表单数据
const ruleForm = ref({
yhdh: '',
mm: '',
});
const rules = ref(
{
yhdh: [{ required: true, message: "请输入用户工号", trigger: "blur" },],
mm: [{ required: true, message: "请输入密码", trigger: "blur" },]
}
);
const yhdhRef = ref();
const open = () => {
checkShow.value = true;
flag.value = true;
nextTick(() => {
setTimeout(() => {
yhdhRef.value.focus();
}, 100);
});
};
const checkShow = ref(false);
const ruleFormRef = ref();
const flag = ref(true);
// 处理确认验证
const handleConfirm = () => {
ruleFormRef.value.validate((valid: boolean) => {
if (valid) {
emit('onConfirm', { yhdh: ruleForm.value.yhdh, mm: ruleForm.value.mm });
flag.value = false;
checkShow.value = false;
} else {
return false;
}
});
};
const handleCancel = () => {
checkShow.value = false;
ruleForm.value.yhdh = '';
ruleForm.value.mm = '';
ruleFormRef.value.resetFields();
emit('onCancel');
};
const close = () => {
ruleForm.value.yhdh = '';
ruleForm.value.mm = '';
ruleFormRef.value.resetFields();
if (flag.value) {
emit('onCancel');
}
};
defineExpose({
open,
});
</script>
<style scoped lang="scss"></style>

View File

@ -1,12 +1,7 @@
/**
* @file index.vue
* @description: 下拉表格选择
* @author: w
* @since: 2026-06-18
*/
<template>
<div class="dropdown-table-select" :style="{ width: inputWidth }">
<el-dropdown ref="dropdownRef" trigger="manual" placement="bottom-start" style="width:100%">
<el-dropdown ref="dropdownRef" trigger="manual" placement="bottom-start" style="width:100%" :teleported="false"
:popper-style="{ width: realtableWidth }">
<div class="input-wrap" style="width:100%">
<el-input v-model="inputText" :placeholder="placeholder" @keydown.enter.prevent="handleInputEnter" />
<span class="arrow-icon" @click.stop="toggleDropdown">
@ -16,17 +11,35 @@
</span>
</div>
<template #dropdown>
<div class="table-panel" :style="{ width: panelWidth }">
<el-table :data="tableData" border :height="tableHeight" @row-click="handleRowClick" v-loading="tableLoading">
<el-table-column v-for="col in columnList" :key="col.prop" :label="col.label" :prop="col.prop"
:width="col.width" :align="col.align || 'center'" />
</el-table>
<div class="table-panel mytable-style" style="width:100%">
<!-- 搜索框-->
<div style="text-align: left;" v-if="props.showSearch">
<el-input v-model="searchKey" ref="searchInput" size="small" placeholder="快速搜索(支持简拼)" class="mb10" clearable
@clear="filterDataHandle" @input="filterDataHandle" @keydown="handleInputKeydown" />
</div>
<!-- 空数据提示 -->
<el-empty v-if="filterData.length === 0" description="没有匹配的数据" :image-size="100" />
<!-- 表格容器增加键盘监听 -->
<div v-else @keydown="handleTableKeydown" tabindex="0" style="outline: none;">
<vxe-table ref="tableRef" border resizable max-height="350px" v-loading="tableLoading"
:row-config="{ isHover: true, keyField: labelField, height: 30, isCurrent: true }" :data="filterData"
:current-row="currentRow" @cell-click="handleRowClick"
:tooltip-config="{ appendToBody: true, zIndex: 3000 }" :show-overflow="true"
:scroll-y="{ enabled: true, rSize: 30, height: '100%', oSize: 20, gt: 30, }">
<vxe-table-column v-for="field in props.columnList" :key="field.prop" :field="field.prop"
:title="field.label" align="center" :width="field.width" min-width="100" />
</vxe-table>
</div>
</div>
</template>
</el-dropdown>
</div>
</template>
<script setup lang="ts">
import { ArrowDown } from '@element-plus/icons-vue'
// 引入拼音首字母工具
import { getFirstLetter } from '@/utils/pinyin';
export interface TableColumnItem {
label: string
@ -35,6 +48,7 @@ export interface TableColumnItem {
align?: 'left' | 'center' | 'right'
}
export type TableRowItem = Record<string, any>
const props = defineProps({
// 绑定值
modelValue: {
@ -46,48 +60,174 @@ const props = defineProps({
type: String,
default: ''
},
// 绑定值字段
// 绑定值字段
labelField: {
type: String,
default: 'billNo'
},
// 输入框宽度
// 输入框宽度
inputWidth: {
type: String,
default: '100%'
},
// 下拉面板宽度
panelWidth: {
// 表格宽度
tableWidth: {
type: String,
default: '700px'
default: '100%'
},
//表格高度
// 表格高度
tableHeight: {
type: String,
default: '150px'
},
// 表格列 父必传,无默认值
// 是否显示表头
showHeader: {
type: Boolean,
default: true
},
// 表格列配置
columnList: {
type: Array as () => TableColumnItem[],
required: true
},
// 表格数据 父必传
// 表格原始数据
tableData: {
type: Array as () => TableRowItem[],
required: true
},
//是否展示搜索框
showSearch: {
type: Boolean,
default: true
}
})
const emit = defineEmits<{
'update:modelValue': [val: string]
change: [row: TableRowItem]
open: []
search: [val: string]
}>()
const bindField = props.labelField ?? 'billNo'
const dropdownRef = useTemplateRef('dropdownRef')
const showPanel = ref(false)
const inputText = ref('')
const tableLoading = ref(false)
const currentRow = ref<any>(null)
const tableRef = useTemplateRef('tableRef')
// 搜索相关变量
const searchKey = ref('');
const searchInput = ref();
// 预处理带拼音的完整原始数据
const processedTableData = ref<{ [key: string]: any; pinyinMap: Record<string, string> }[]>([]);
// 过滤后渲染表格的数据
const filterData = ref<{ [key: string]: any; pinyinMap: Record<string, string> }[]>([]);
const currentIndex = ref(-1);
const realtableWidth = computed(() => {
if (props.tableWidth === '100%') {
return props.inputWidth
}
return props.tableWidth
})
// 数据预处理生成拼音简拼
const processTableData = (data: TableRowItem[]) => {
const list = Array.isArray(data) ? data : [];
return list.map((item: any) => {
const pinyinMap: Record<string, string> = {};
// 所有列都生成拼音用于检索
props.columnList.forEach((field) => {
if (item[field.prop]) {
pinyinMap[field.prop] = getFirstLetter(item[field.prop]).toLowerCase();
}
});
return { ...item, pinyinMap };
});
};
//搜索过滤逻辑
const filterDataHandle = () => {
const key = searchKey.value.trim().toLowerCase();
if (!key) {
filterData.value = [...processedTableData.value];
currentIndex.value = -1;
return;
}
currentIndex.value = 0;
filterData.value = processedTableData.value.filter((item) => {
let match = false;
// 遍历所有列:文本匹配 + 拼音简拼匹配
props.columnList.forEach((field) => {
const text = item[field.prop]?.toString().toLowerCase() || '';
const pinyin = item.pinyinMap[field.prop] || '';
if (text.includes(key) || pinyin.includes(key)) {
match = true;
}
});
return match;
});
// 过滤完成自动选中第一行
if (filterData.value.length > 0) {
nextTick(() => {
tableRef.value?.setCurrentRow(filterData.value[0]);
tableRef.value?.scrollToRow(filterData.value[0]);
});
} else {
tableRef.value?.clearCurrentRow();
}
};
//搜索框上下回车键盘事件 ==========
const handleInputKeydown = (e: KeyboardEvent) => {
if (!['ArrowUp', 'ArrowDown', 'Enter'].includes(e.key)) return;
e.stopPropagation();
if (filterData.value.length > 0) {
nextTick(() => {
const tableBox = searchInput.value.$el.closest('.table-panel').querySelector('div[tabindex="0"]') as HTMLElement;
if (tableBox) {
tableBox.focus();
tableBox.dispatchEvent(new KeyboardEvent('keydown', { key: e.key }));
}
});
if (e.key === 'Enter') {
const targetRow = filterData.value[currentIndex.value];
targetRow && handleRowClick({ row: targetRow });
}
}
};
//表格容器上下键导航 ==========
const handleTableKeydown = (e: KeyboardEvent) => {
if (!['ArrowUp', 'ArrowDown', 'Enter'].includes(e.key)) return;
e.preventDefault();
const maxIdx = filterData.value.length - 1;
if (e.key === 'ArrowUp') {
currentIndex.value = Math.max(0, currentIndex.value - 1);
} else if (e.key === 'ArrowDown') {
currentIndex.value = Math.min(maxIdx, currentIndex.value + 1);
}
tableRef.value.setCurrentRow(filterData.value[currentIndex.value]);
tableRef.value.scrollToRow(filterData.value[currentIndex.value]);
if (e.key === 'Enter') {
const targetRow = filterData.value[currentIndex.value];
targetRow && handleRowClick({ row: targetRow });
}
};
// ========== 监听原始表格数据变化,重新生成拼音数据 ==========
watch(
() => props.tableData,
(newVal) => {
if (!Array.isArray(newVal)) return;
processedTableData.value = processTableData(newVal);
filterDataHandle();
},
{ deep: true, immediate: true }
)
// 原有监听逻辑不变
watch(
() => props.modelValue,
(val) => {
@ -99,13 +239,13 @@ watch(inputText, (val) => {
emit('update:modelValue', val)
})
// 回车处理
// 输入框回车(原有逻辑)
const handleInputEnter = (e: KeyboardEvent) => {
e.stopPropagation();
e.stopPropagation()
emit('search', inputText.value)
}
// 仅点击箭头才切换下拉
// 切换下拉框(修改:打开时聚焦搜索框、刷新过滤)
const toggleDropdown = () => {
if (!dropdownRef.value) return
showPanel.value = !showPanel.value
@ -113,24 +253,32 @@ const toggleDropdown = () => {
dropdownRef.value.handleOpen()
tableLoading.value = true
emit('open')
searchKey.value = '';
filterDataHandle();
setTimeout(() => {
tableLoading.value = false
// 只有开启搜索框才聚焦
if (props.showSearch && searchInput.value) {
searchInput.value?.focus();
}
}, 300)
} else {
dropdownRef.value.handleClose()
}
}
// 行点击选中
const handleRowClick = (row: TableRowItem) => {
const text = row[bindField] ?? ''
// 表格行点击(原有逻辑完全不变)
const handleRowClick = (params: { row: TableRowItem }) => {
const text = params.row[bindField] ?? ''
inputText.value = text
emit('update:modelValue', text)
emit('change', row)
emit('change', params.row)
currentRow.value = params.row
dropdownRef.value?.handleClose()
showPanel.value = false
}
</script>
<style scoped lang="scss">
.dropdown-table-select {
.input-wrap {
@ -152,6 +300,18 @@ const handleRowClick = (row: TableRowItem) => {
.table-panel {
padding: 12px;
width: 100%;
}
}
/* 只清除最小宽度限制,删除强制 width:100% 代码 */
:deep(.el-popper) {
min-width: 0 !important;
max-width: none !important;
}
/* 修复vxe-table滚动空白样式 */
:deep(.vxe-table--body) {
overflow-anchor: none;
}
</style>

View File

@ -29,18 +29,18 @@
</div>
<!-- 数据为空时显示空状态提示 -->
<el-empty v-if="filterData.length === 0" description="没有匹配的数据" :image-size="100" />
<div @keydown="handleKeydown" v-else tabindex="0" style="outline: none;">
<div @keydown="handleKeydown" v-else tabindex="0" style="outline: none;" class="mytable-style">
<!-- 数据存在时显示表格 -->
<!-- <el-table ref="tableRef" :data="filterData" :highlight-current-row="props.isHighlight" style="width: 100%"
:border="props.border" @row-click="handleRowChange" max-height="350px" :row-style="{ height: '25px' }">
<el-table-column v-for="field in props.fields" :prop="field.prop" :label="field.label"
:width="field.width" show-overflow-tooltip align="center" />
</el-table> -->
<vxe-table class="mytable-style" ref="tableRef" border resizable max-height="350px"
<vxe-table ref="tableRef" border resizable max-height="350px"
:row-config="{ isHover: true, keyField: 'value', height: 30, isCurrent: true }" :data="filterData"
:current-row="currentRow" @cell-click="currentChange"
:tooltip-config="{ appendToBody: true, zIndex: 3000 }" :show-overflow="true"
:scroll-y="{ enabled: true, rSize: 30, height: '100%' }">
:scroll-y="{ enabled: true, rSize: 30, height: '100%', oSize: 20, gt: 30, }">
<vxe-table-column v-for="field in props.fields" :field="field.prop" :title="field.label" align="center"
:width="field.width" min-width="150" />
</vxe-table>
@ -359,23 +359,6 @@ const clearHandle = () => {
width: 100%;
}
:deep(.vxe-header--row th) {
border-color: #00a5ff;
// background-color: #e6edf9;
font-size: 14px;
}
:deep(.vxe-body--row td) {
border-color: #00a5ff;
}
:deep(.vxe-table--row-hover) {
background-color: #00a5ff;
}
:deep(.vxe-table--current-row) {
background-color: #00a5ff;
}
:deep(.el-table-header-cell) {
cursor: move;
@ -383,20 +366,16 @@ const clearHandle = () => {
}
// 表格边框
:deep(.vxe-table--render-default.border--full .vxe-body--column) {
background-image: linear-gradient(#96B8D9, #96B8D9), linear-gradient(#96B8D9, #96B8D9) !important;
}
// :deep(.vxe-table--render-default.border--full .vxe-body--column) {
// background-image: linear-gradient(#ccc, #ccc), linear-gradient(#ccc, #ccc) !important;
// }
// 表头边框
:deep(.vxe-table--render-default.border--full .vxe-header--column) {
background-image: linear-gradient(#e6edf9, #e6edf9), linear-gradient(#e6edf9, #e6edf9) !important;
}
// // 表头边框
// :deep(.vxe-table--render-default.border--full .vxe-header--column) {
// background-image: linear-gradient(#ccc, #ccc), linear-gradient(#ccc, #ccc) !important;
// }
.select-table-dropdown {
padding: 8px;
}
:deep(.el-table .el-table__cell) {
padding: 0;
}
</style>

View File

@ -1 +1,4 @@
export * from './lisData/dictData';
export * from './lisData/dictData';
export * from './useSysParam'
export * from './messageBox'
export * from './useCommonDict'

102
src/hooks/useCommonDict.ts Normal file
View File

@ -0,0 +1,102 @@
import { queryLisProject, queryUserInfo, currentDateTime, getBloodBreed, queryIllDiagnoseList } from '@/api/common'
import dayjs from 'dayjs'
// 员工下拉类型
type option = {
label: string
value: string
}
// 血液品种下拉类型
type BreedOption = {
label: string
value: string
unit: string
}
// 检验项目表格初始行结构
type LisProjectRow = {
bill_no: string
item_name: string
item_result: string
item_unit: string
test_date: string
sid: string | number
}
export function useCommonDict() {
const getServerTime = async () => {
const res = await currentDateTime()
return res.data
}
// 员工下拉列表
const userList = ref<option[]>([])
const getUserData = async () => {
const res = await queryUserInfo()
userList.value = res.rows.map(item => ({
label: item.nickName,
value: item.userName
}))
}
// 血液品种下拉
const bloodBreed = ref<BreedOption[]>([])
const getBloodList = async () => {
const res = await getBloodBreed()
bloodBreed.value = res.data.map(item => ({
label: item.breed_name,
value: item.breed_code,
unit: item.unit
}))
}
// 检验项目LIS项目
const lisProject = ref<LisProjectRow[]>([])
const getLisProject = async () => {
const res = await queryLisProject({ need: 'Y' })
lisProject.value = res.data.map(item => ({
bill_no: '',
item_name: item.pro_name,
item_result: '',
item_unit: item.unit,
test_date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
sid: item.sid
}))
return lisProject.value
}
// 单病种列表
const diaList = ref<option[]>([])
const getDiaList = async () => {
const res = await queryIllDiagnoseList({ pageSize: 9999, pageNum: 1 })
diaList.value = res.rows.map(item => ({
label: item.dia_Name,
value: item.dia_Code
}))
}
// 一次性加载
const loadAllDict = async () => {
await Promise.all([
getUserData(),
getBloodList(),
getLisProject(),
getDiaList()
])
}
return {
getServerTime,
userList,
getUserData,
bloodBreed,
getBloodList,
loadAllDict,
lisProject,
getLisProject,
diaList,
getDiaList
}
}

View File

@ -25,8 +25,9 @@ const { initAllParams } = useSysParam()
// ========== 在这里统一维护【所有需要全局获取的参数 key】 ==========
const GLOBAL_PARAM_KEYS = [
'YBZFXMTSXX', // YBZFXMTSXX
'YBZFXMTSXX', // 输血报销
'HZBQGY', // 患者病情概要是否必填
'SQDSFKRLXGXX',//输血申请时是否可从HIS系统中调出患者信息,是否可以录入修改患者血型?以"/"分隔,"/"前指可以调出患者信息时是否可以修改患者血型(Y可以修改N不可以修改),"/"后指不可以调出患者信息时是否可以录入全部和只能录入"未知"患者血型(Y可以录入全部N只能录入"未知")
]
const settingsStore = useSettingsStore()

View File

@ -81,6 +81,7 @@ export function comDict(...args: string[]): Promise<DictResult> {
const dictList = resp.data.map((p: any) => ({
label: p.wordbook_name,
value: p.wordbook_code,
remark: p.remark,
}));
res.value[dictType] = dictList;

View File

@ -131,6 +131,8 @@ service.interceptors.response.use((res: any) => {
duration: 0,
})
return Promise.resolve(res.data)
} else if (code === 2) {
return Promise.resolve(res.data)
} else if (code === 3) {
ElMessage({
message: msg,

View File

@ -0,0 +1,142 @@
<template>
<el-dialog v-model="dialogVisible" title="审核意见" width="900px" :close-on-click-modal="false" @close="resetForm">
<!-- 上方指征表格 -->
<el-table ref="tableRef" :data="tableData" border style="margin-bottom: 16px" max-height="320"
@selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="指征名称" prop="indicateName" min-width="280" />
<el-table-column label="补充说明" prop="remark" min-width="320" />
</el-table>
<!-- 下方表单区域 -->
<el-form label-width="130px" :model="indicationForm" :rules="rules">
<el-form-item label="审核意见" prop="checkResult">
<SelectTable v-model:data="indicationForm.checkResult" dict-type="sqdshyj" placeholder="" />
</el-form-item>
<el-form-item label="审核备注">
<el-input v-model="indicationForm.checkExplain" type="textarea" :rows="4" placeholder="" />
</el-form-item>
<el-form-item label="上次血型复核">
<span>{{ indicationForm.checkDateText }}</span>
</el-form-item>
<div class="row-flex">
<el-form-item label="是否需要血型复核">
<el-checkbox v-model="indicationForm.needCheck" true-value="Y" false-value="N" />
</el-form-item>
<el-form-item label="输血合理性">
<el-select v-model="indicationForm.validFlag" placeholder="" style="width:150px">
<el-option label="合理" value="Y"></el-option>
<el-option label="不合理" value="N"></el-option>
<el-option label="待定" value="W"></el-option>
</el-select>
</el-form-item>
</div>
</el-form>
<template #footer>
<el-button type="primary" @click="handleSubmit">确定</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import type { ElTable } from 'element-plus'
import { checkExplain, queryCausailsList } from '@/api/doctor/application'
import { ElMessage } from 'element-plus'
import { ElMessageBox } from 'element-plus'
// 弹窗显隐
const dialogVisible = defineModel<boolean>()
const tableRef = ref<InstanceType<typeof ElTable>>()
// 存储表格勾选选中行
const selectedRows = ref<any[]>([])
const rules = {
checkResult: [{ required: true, message: '请选择审核意见', trigger: 'change' }]
}
// 表格数据源
const tableData = ref<{ indicateName: string; remark: string }[]>([])
// 表单变量
const indicationForm = ref({
checkExplain: '',
auditRemark: '',
checkResult: '',
validFlag: '',
needCheck: 'N'
})
const emit = defineEmits<{
(e: 'success'): void
}>()
// 表格勾选事件
const handleSelectionChange = (val: any[]) => {
selectedRows.value = val
}
// 提交逻辑
const handleSubmit = async () => {
if (!indicationForm.value.checkResult) return ElMessage.error('请选择审核意见')
if (indicationForm.value.checkResult == '001' && indicationForm.value.validFlag == 'N') {
ElMessageBox.confirm(
`审核意见:【同意】,输血合理性为【不合理】确定继续吗?`,
'提示',
{ type: 'warning', }
).then(() => {
comfirm()
})
} else {
comfirm()
}
}
const comfirm = () => {
checkExplain(indicationForm.value).then(res => {
if (res.code == 0) {
ElMessage.success(res.msg)
emit('success')
dialogVisible.value = false
}
})
}
// 弹窗关闭重置表单、清空表格勾选
const resetForm = () => {
indicationForm.value = {
checkExplain: '',
auditRemark: '',
checkResult: '',
validFlag: '',
needCheck: 'N'
}
selectedRows.value = []
// 清空表格勾选
tableRef.value?.clearSelection()
}
const open = (data) => {
indicationForm.value = data
dialogVisible.value = true
queryCausailsList({ billNo: data.applyNo }).then(res => {
tableData.value = res.data
})
}
defineExpose({
open
})
</script>
<style scoped lang="scss">
.row-flex {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@
</div>
<!-- 基础信息 -->
<div class="section">
<div class="title">基础信息</div>
<div class="title">患者信息</div>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="住院号/ID号">
@ -228,10 +228,10 @@
</el-form>
<!-- 结果表格区 -->
<el-table :data="tableData" border style="width: 100%; margin-top: 10px" height="350" @row-click="handleRowClick"
highlight-current-row>
<el-table-column prop="bill_no" label="评估单号" align="center" width="180" />
<el-table-column prop="dept_id" label="科室" align="center">
<el-table :data="tableData" border style="width: 100%; margin-top: 10px" show-overflow-tooltip height="350"
@row-click="handleRowClick" highlight-current-row>
<el-table-column prop="bill_no" label="评估单号" align="center" width="150" />
<el-table-column prop="dept_id" label="科室" align="center" width="160">
<template #default="scope">
{{ formatDict(scope.row.dept_id, 'ks') }}
</template>
@ -304,11 +304,11 @@ const handleSearch = () => {
getList()
}
const handleConfirm = () => {
if (!seelctRow.value.bill_no) return ElMessage.warning('请选择评估单')
evaluationInfo.value.billNo = seelctRow.value.bill_no
if (!selectRow.value.bill_no) return ElMessage.warning('请选择评估单')
evaluationInfo.value.billNo = selectRow.value.bill_no
getBillInfo()
visible.value = false
seelctRow.value = {}
selectRow.value = {}
}
const handleClose = () => {
@ -320,7 +320,7 @@ const handleClose = () => {
bill_no: '',
beinhos_id: ''
}
seelctRow.value = {}
selectRow.value = {}
}
//获取评估单信息
@ -333,7 +333,7 @@ const getBillInfo = () => {
lisProject.value = res.data.xkTransfuseApplyTestitemList.map(item => {
return {
bill_no: item.bill_no,
item_name: item.pro_name,
item_name: item.item_name,
item_result: item.item_result,
item_unit: item.item_unit,
test_date: item.test_date,
@ -361,9 +361,9 @@ const splitAge = (ageStr: string) => {
baseInfo.value.nldw = unit
}
const seelctRow = ref({})
const selectRow = ref({})
const handleRowClick = (row) => {
seelctRow.value = row
selectRow.value = row
}
//查询单据信息
const getList = () => {
@ -441,14 +441,14 @@ const handleSubmit = () => {
}
if (bloodInfo.value.bill_status && bloodInfo.value.bill_status == '1') {
updatePat(data).then((res) => {
saveLoading.value = false
if (res.code == 0) {
ElMessage.success('保存成功')
}
}).finally(() => {
saveLoading.value = false
})
} else {
savePat(data).then((res) => {
saveLoading.value = false
if (res.code == 0) {
ElMessage.success('保存成功')
evaluationInfo.value.billNo = res.data
@ -456,6 +456,8 @@ const handleSubmit = () => {
//获取到评估单号后请求最新评估单信息
getBillInfo()
}
}).finally(() => {
saveLoading.value = false
})
}
@ -463,7 +465,12 @@ const handleSubmit = () => {
}
const goSxPath = () => {
router.push({ path: `/doctor/application` })
const billNo = evaluationInfo.value.billNo.trim()
// 额外添加标识 isJump 区分是主动跳转携带的参数
router.push({
name: 'Application',
state: { billNo, isJump: true }
})
}
const getProject = () => {
@ -513,7 +520,7 @@ onMounted(() => {
background: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
padding: 12px;
padding: 10px;
margin-bottom: 10px;
.title {

View File

@ -0,0 +1,17 @@
/**
* @file index.vue
* @description: 储存室自体血登记
* @author: w
* @since: 2026-07-08
*/
<template>
<div>
储存室自体血登记
</div>
</template>
<script setup lang="ts">
</script>
<style scoped></style>

View File

@ -0,0 +1,313 @@
/**
* @file index.vue
* @description: 输血治疗登记
* @author: w
* @since: 2026-07-08
*/
<template>
<div class="box-container">
<div class="toolbar">
<el-button type="primary" plain>检索</el-button>
<el-button type="primary" plain>新增单据</el-button>
<el-button type="danger" plain>删除单据</el-button>
<el-button type="success" plain>保存</el-button>
<el-button type="warning" plain>审核</el-button>
<el-button type="warning" plain>打印</el-button>
<el-button type="info" plain>标签重打</el-button>
</div>
<el-form label-width="auto">
<div class="section">
<div class="section-title">申请信息</div>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="申请单号">
<DropdownTableSelect v-model="form.beinhos_id" :columnList="sqcolumnList" :tableData="sqList"
tableWidth="300px" labelField="beinhos_id" :showSearch="false" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="住院号/ID号">
<el-input v-model="form.patientId" readonly />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="姓 名">
<el-input v-model="form.patientName" readonly />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="性 别">
<el-select v-model="form.sex" placeholder="" readonly>
<el-option label="男" value="男" />
<el-option label="女" value="女" />
<el-option label="未知" value="未知" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="血 型">
<el-input v-model="form.bloodType" readonly />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="科 室">
<SelectTable v-model:data="form.deptId" :tableData="dictData.ks" placeholder="" readonly />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="申请日期">
<el-date-picker v-model="form.applyDate" type="datetime" style="width: 100%"
value-format="YYYY-MM-DD HH:mm:ss" readonly />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="治疗日期">
<el-date-picker v-model="form.treatDate" type="datetime" style="width: 100%"
value-format="YYYY-MM-DD HH:mm:ss" readonly />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="年 龄">
<div>
<el-input v-model="form.age" readonly />
<!-- <el-select v-model="form.nldw" placeholder="" style="width: 45%">
<el-option v-for="v in dictData.nldw" :label="v.label" :value="v.value" />
</el-select> -->
</div>
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="Rh(D)">
<el-input v-model="form.rh" readonly />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="是否采血">
<el-checkbox v-model="form.collectBlood" true-value="Y" false-value="N" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="输血史">
<el-checkbox v-model="form.transfusionHistory" true-value="Y" false-value="N" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="输血反应史">
<el-checkbox v-model="form.transfusionReactionHistory" true-value="Y" false-value="N" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="妊娠史">
<el-checkbox v-model="form.pregnancyHistory" true-value="Y" false-value="N" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="分娩史">
<el-checkbox v-model="form.deliveryHistory" true-value="Y" false-value="N" />
</el-form-item>
</el-col>
</el-row>
</div>
</el-form>
<el-row :gutter="10">
<el-col :span="12">
<div class="box-item">
<div class="box-title">治疗项目</div>
<div class="table-box">
<el-table :data="treatmentItems" border height="150" style="width: 100%" show-overflow-tooltip
highlight-current-row>
<el-table-column prop="project" label="治疗项目" align="center" />
<el-table-column prop="quantity" label="数量" align="center" />
<el-table-column prop="unit" label="单位" align="center" />
<el-table-column prop="remark" label="备注" align="center" />
</el-table>
</div>
</div>
</el-col>
<el-col :span="12">
<div class="box-item">
<div class="box-title">采血血液</div>
<div class="table-box">
<el-table :data="bloodItems" border height="150" style="width: 100%" show-overflow-tooltip
highlight-current-row>
<el-table-column prop="bloodBreed" label="血液品种" align="center" />
<el-table-column prop="volume" label="容量" align="center" />
<el-table-column prop="unit" label="单位" align="center" />
<el-table-column prop="remark" label="备注" align="center" />
</el-table>
</div>
</div>
</el-col>
</el-row>
<div class="section">
<div class="section-title">登记信息</div>
<el-row :gutter="20">
<el-col :span="4">
<el-form-item label="治 疗 人">
<SelectTable v-model:data="registerInfo.apply_medic" :tableData="userList" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item label="治疗日期">
<el-date-picker v-model="registerInfo.treatDate" type="datetime" style="width: 100%"
value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="治疗不良反应">
<el-input v-model="registerInfo.adverseReaction" placeholder="双击选择" />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="不良反应处理">
<el-input v-model="registerInfo.adverseHandle" placeholder="双击选择" />
</el-form-item>
</el-col>
</el-row>
</div>
<div class="section">
<div class="section-title">采血信息</div>
<div class="table-box">
<el-button type="primary" plain class="mb10">新增血液</el-button>
<el-table :data="bloodRecords" border height="220" style="width: 100%">
<el-table-column prop="bloodBreed" label="血液品种" align="center" />
<el-table-column prop="bloodType" label="血型" align="center" />
<el-table-column prop="rh" label="Rh(D)" align="center" />
<el-table-column prop="volume" label="容量" align="center" />
<el-table-column prop="unit" label="单位" align="center" />
<el-table-column label="操作" align="center">
<template #default="{ row }">
<el-button type="primary" text plain>删除</el-button>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import DropdownTableSelect from '@/components/DropdownTableSelect/index.vue'
import { getDictData, formatDict, dictData, useCommonDict, useSysParam } from '@/hooks'
const { userList, getUserData } = useCommonDict()
const form = reactive({})
const sqcolumnList = ref([
{ label: '申请单编号', prop: 'sqbh' },
{ label: '姓名', prop: 'name' },
])
const sqList = ref([])
const treatmentItems = ref([])
const bloodItems = ref([])
const registerInfo = reactive({
treatPerson: '',
treatDate: '',
adverseReaction: '',
adverseHandle: ''
})
const bloodRecords = ref([])
onMounted(() => {
getUserData()
getDictData('ks', 'nldw')
})
</script>
<style scoped lang="scss">
.box-container {
display: flex;
flex-direction: column;
box-sizing: border-box;
gap: 10px;
overflow-y: auto;
}
.toolbar {
padding: 8px;
background: #fff;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
border-radius: 4px;
}
.section {
background: #fff;
border-radius: 4px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
padding: 10px;
}
.el-form-item {
margin-bottom: 6px;
:deep(.el-form-item__label) {
font-weight: 700;
}
}
.section-title {
font-size: 15px;
font-weight: 700;
position: relative;
padding-left: 14px;
padding-bottom: 6px;
}
.section-title::before {
content: '';
position: absolute;
left: 0;
top: 4px;
width: 4px;
height: 16px;
border-radius: 0 4px 4px 0;
background-color: #409eff;
}
.box-item {
background: #fff;
border-radius: 4px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
padding: 12px;
}
.box-title {
font-size: 15px;
font-weight: 700;
margin-bottom: 12px;
position: relative;
padding-left: 14px;
}
.box-title::before {
content: '';
position: absolute;
left: 0;
top: 4px;
width: 4px;
height: 16px;
border-radius: 0 4px 4px 0;
background-color: #409eff;
}
.age-input {
display: flex;
align-items: center;
gap: 8px;
}
.text-danger {
color: #f00 !important;
}
</style>

View File

@ -0,0 +1,11 @@
<template>
<div>
输血治疗登记
</div>
</template>
<script setup lang="ts">
</script>
<style scoped></style>

View File

@ -238,6 +238,7 @@ function reset() {
form.value = {
wordbook_sign: '',
wordbook_name: '',
wordbook_code_old: '',
wordbook_code: '',
use_sign: "Y",
remark: undefined
@ -268,6 +269,7 @@ function handleAdd() {
function handleUpdate(row) {
reset()
form.value = row.wordbook_sign ? JSON.parse(JSON.stringify(row)) : info.value
form.value.wordbook_code_old = row.wordbook_code
open.value = true;
title.value = '编辑字典';
}