血袋预警统计

This commit is contained in:
wuyy 2026-07-23 17:57:58 +08:00
parent 99e2bf5446
commit 368c6d95de
17 changed files with 1249 additions and 606 deletions

32
src/api/bloodInventory.ts Normal file
View File

@ -0,0 +1,32 @@
/**
* @file bloodInventory.ts
* @description: 血量库存
* @author: w
* @since: 2026-07-23
*/
import request from '@/utils/request'
// 查询过期血液
export function queryExpiredBlood(query?: Object) {
return request({
url: '/bus/bloodbank/stips/queryExpiredBlood',
method: 'get',
params: query
})
}
// 查询列表数据,输血科,血液品种总量类型
export function queryListByBlood(query?: Object) {
return request({
url: '/bus/bloodbank/stips/queryListByBlood',
method: 'get',
params: query
})
}
// 查询列表数据,医生站,血型总量类型
export function queryListByDoctor(query?: Object) {
return request({
url: '/bus/bloodbank/stips/queryListByDoctor',
method: 'get',
params: query
})
}

View File

@ -143,4 +143,36 @@ export function queryhistoryList(query?: Object) {
method: 'get',
params: query
})
}
// 查询大量用血审批列表
export function approvalQueryList(query?: Object) {
return request({
url: '/bus/doctor/approval/queryList',
method: 'post',
data: query
})
}
// 科主任审批
export function auditArchiater(query?: Object) {
return request({
url: '/bus/doctor/approval/auditArchiater',
method: 'get',
params: query
})
}
// 医务部审批
export function auditMedical(query?: Object) {
return request({
url: '/bus/doctor/approval/auditMedical',
method: 'get',
params: query
})
}
// 输血申请单状态闭环
export function bloodCloseLoop(query?: Object) {
return request({
url: '/bus/doctor/apply/bloodCloseLoop',
method: 'get',
params: query
})
}

View File

@ -139,9 +139,10 @@ export function updateAuthRole(data: SysUserRoles): Promise<AjaxResult> {
}
// 查询部门下拉树结构
export function deptTreeSelect(): Promise<AjaxResult<TreeSelect>> {
export function deptTreeSelect(data?: object): Promise<AjaxResult<TreeSelect>> {
return request({
url: '/system/user/deptTree',
method: 'get'
method: 'get',
params: data
})
}

View File

@ -0,0 +1,357 @@
<template>
<!-- 侧边hover悬浮容器 -->
<div class="float-wrap">
<!-- 触发窄条 + 圆形按钮 -->
<div class="float-trigger" @click="togglePanel">
<el-icon size="20">
<DishDot />
</el-icon>
</div>
</div>
<!-- 弹窗外层加transition实现动画 -->
<Transition name="stock-panel">
<div v-show="panelVisible" class="stock-notify-wrap">
<!-- 顶部蓝色标题栏 -->
<div class="panel-header">
<div class="header-title"></div>
<div class="header-btn-group">
<el-button size="small" @click="refreshStock">刷新</el-button>
<el-button size="small" @click="openSetting">设置</el-button>
<el-button size="small" @click="closePanel">关闭</el-button>
</div>
</div>
<!-- 主体区域:两种模式切换 -->
<div class="panel-main">
<!-- 输血科模式 -->
<div v-show="setting.type == '2'" class="mode-transfusion">
<el-table :data="stockTable" class="stock-table">
<el-table-column label="血液分类" prop="ClassName" align="center" width="90" />
<el-table-column label="A型(ML)" prop="AmountA" align="center">
<template #default="{ row }">
<div class="state-cell" :style="{ background: decimalToHexColor(row.TipsAColor) }">
<div>{{ row.AmountA }}</div>
<div>{{ row.TipsAText }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="B型(ML)" prop="AmountB" align="center">
<template #default="{ row }">
<div class="state-cell" :style="{ background: decimalToHexColor(row.TipsBColor) }">
<div>{{ row.AmountB }}</div>
<div>{{ row.TipsBText }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="AB型(ML)" prop="AmountAB" align="center">
<template #default="{ row }">
<div class="state-cell" :style="{ background: decimalToHexColor(row.TipsABColor) }">
<div>{{ row.AmountAB }}</div>
<div>{{ row.TipsABText }}</div>
</div>
</template>
</el-table-column>
<el-table-column label="O型(ML)" prop="AmountO" align="center">
<template #default="{ row }">
<div class="state-cell" :style="{ background: decimalToHexColor(row.TipsOColor) }">
<div>{{ row.AmountO }}</div>
<div>{{ row.TipsOText }}</div>
</div>
</template>
</el-table-column>
</el-table>
</div>
<!-- 临床医生站模式 -->
<div v-show="setting.type == '1'" class="mode-clinic">
<div class="grid-row">
<div class="color-block" v-for="item in stockBlock"
:style="{ background: decimalToHexColor(item.TipsColor) }">
<div class="block-label">{{ item.BloodAboName }}</div>
<div class="block-desc">{{ item.TipsText }}</div>
</div>
</div>
</div>
</div>
<!-- 血袋过期预警 -->
<div class="warn-title">血袋过期预警:</div>
<el-table border :data="expireList" height="140" class="expire-table" show-overflow-tooltip>
<el-table-column label="品种名称" prop="breed_name" align="center" width="120" />
<el-table-column label="剩余天数" prop="cp_moreday" align="center" width="80">
<template #default="{ row }">
<span :class="Number(row.cp_moreday) <= 0 ? 'text-red' : ''">{{ row.cp_moreday }}</span>
</template>
</el-table-column>
<el-table-column label="血液流水号" prop="blood_no" align="center" width="120" />
<el-table-column label="血型" prop="blood_type" align="center" width="60" />
<el-table-column label="容量" prop="capacity" align="center" width="60" />
<el-table-column label="产品码" prop="product_no" align="center" width="100" />
<el-table-column label="有效日期" prop="valid_date" align="center" width="150" />
<el-table-column label="采血日期" prop="pick_date" align="center" width="150" />
</el-table>
<!-- 设置弹窗 -->
<el-dialog v-model="settingVisible" title="选项" width="420" :close-on-click-modal="false" :draggable="true"
:append-to-body="true">
<el-form :model="setting" label-width="auto">
<el-form-item label="类型">
<el-select v-model="tempType">
<el-option label="临床医生站" value="1" />
<el-option label="输血科" value="2" />
</el-select>
</el-form-item>
<el-form-item label="刷新间隔">
<el-input v-model="setting.refreshMin" type="number" style="width: 60%" /> 分钟
</el-form-item>
<el-form-item label="自动关闭">
<el-input v-model="setting.autoCloseMin" type="number" style="width: 60%" /> 分钟
</el-form-item>
</el-form>
<template #footer>
<el-button @click="settingVisible = false">关闭</el-button>
<el-button type="primary" @click="saveSetting">确定</el-button>
</template>
</el-dialog>
</div>
</Transition>
</template>
<script setup lang="ts">
import { queryExpiredBlood, queryListByBlood, queryListByDoctor } from '@/api/bloodInventory'
import { decimalToHexColor } from '@/utils/classCom'
const setting = reactive({
type: '1',
refreshMin: 1000,
autoCloseMin: 1,
})
// 设置弹窗临时缓存选中值
const tempType = ref('1')
const loadConfig = () => {
const cache = localStorage.getItem('bloodStockNotify')
if (cache) Object.assign(setting, JSON.parse(cache))
}
const saveSetting = () => {
// 点击确定按钮,才覆盖真实类型,页面布局才切换
setting.type = tempType.value
localStorage.setItem('bloodStockNotify', JSON.stringify(setting))
settingVisible.value = false
refreshStock()
}
// 面板控制
const panelVisible = ref(true)
const settingVisible = ref(false)
// 切换弹窗显示
const togglePanel = () => {
panelVisible.value = !panelVisible.value
if (panelVisible.value) refreshStock()
}
const closePanel = () => {
panelVisible.value = false
}
const openSetting = () => {
settingVisible.value = true
// 打开设置弹窗,同步当前真实模式到临时下拉值
tempType.value = setting.type
}
// 输血科表格数据
const stockTable = ref([])
// 临床医生站色块数据
const stockBlock = ref([])
// 过期预警列表
const expireList = ref([])
const getList = () => {
if (setting.type == '1') {
queryListByDoctor().then(res => {
stockBlock.value = res.data
})
} else if (setting.type == '2') {
queryListByBlood().then(res => {
stockTable.value = res.data
})
}
}
// 刷新库存接口
const refreshStock = async () => {
console.log('请求库存数据')
queryExpiredBlood().then(res => {
expireList.value = res.data
})
getList()
}
onMounted(() => {
loadConfig()
refreshStock()
})
onUnmounted(() => {
})
</script>
<style scoped lang="scss">
// 侧边hover外层容器
.float-wrap {
position: fixed;
right: 0;
bottom: 86px;
z-index: 100;
width: 12px;
height: 52px;
transition: width 0.3s ease;
&:hover {
width: 52px;
.float-trigger {
transform: translateX(0);
}
}
}
// 悬浮按钮默认隐藏到右侧外面
.float-trigger {
position: absolute;
right: 0;
bottom: 0;
width: 52px;
height: 52px;
border-radius: 50% 0 0 50%;
background: #1667e8;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4px 14px rgba(22, 103, 232, 0.35);
cursor: pointer;
transform: translateX(40px);
transition: transform 0.3s ease;
&:hover {
transform: translateX(0) scale(1.07);
}
}
// 弹窗过渡动画
.stock-panel-enter-from {
opacity: 0;
transform: translateY(24px);
}
.stock-panel-enter-active {
transition: all 0.3s ease;
}
.stock-panel-leave-to {
opacity: 0;
transform: translateY(24px);
}
.stock-panel-leave-active {
transition: all 0.24s ease;
}
// 弹窗主体
.stock-notify-wrap {
position: fixed;
right: 18px;
bottom: 10px;
width: 620px;
background: #fff;
border: 1px solid #8ab4f8;
border-radius: 6px;
overflow: hidden;
box-shadow: 0 8px 30px rgba(12, 64, 160, 0.2);
z-index: 99;
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 12px;
background-color: #1667e8;
.header-btn-group {
:deep(.el-button) {
background: rgba(255, 255, 255, 0.22);
border: none;
color: #fff;
font-size: 12px;
&:hover {
background: rgba(255, 255, 255, 0.38);
}
}
}
}
.panel-main {
padding: 10px;
}
// 输血科表格样式+高饱和色块
.mode-transfusion {
.stock-table {
font-size: 12px;
:deep(.el-table__cell) {
padding: 4px 0;
}
.state-cell {
width: 100%;
padding: 6px 0;
border-radius: 4;
text-align: center;
color: #000;
}
}
}
// 临床医生站 缩小加高饱和色块
.mode-clinic {
.grid-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
margin-bottom: 8px;
}
.color-block {
height: 110px;
border-radius: 6px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 48%;
color: #000;
.block-label {
font-size: 32px;
margin-bottom: 8px;
}
.block-desc {
font-size: 32px;
}
}
}
.warn-title {
padding: 5px 12px;
font-size: 14px;
font-weight: 500;
background: #dcebff;
color: #1667e8;
}
.expire-table {
font-size: 12px;
:deep(.text-red) {
color: #e52121;
font-weight: bold;
}
}
}
</style>

View File

@ -62,7 +62,8 @@ export function useCommonDict() {
item_result: '',
item_unit: item.unit,
test_date: item.validTime,
sid: item.sid
sid: item.sid,
result_type: item.result_type
}))
return lisProject.value
}

View File

@ -10,6 +10,9 @@
<app-main />
<settings ref="settingRef" />
</div>
<!-- 库存预警组件 -->
<BloodStockNotify />
</div>
</template>
@ -20,6 +23,8 @@ import { AppMain, Navbar, Settings, TagsView } from './components'
import useAppStore from '@/store/modules/app'
import useSettingsStore from '@/store/modules/settings'
import { useSysParam } from '@/hooks/useSysParam'
// 异步懒加载,首屏不阻塞
const BloodStockNotify = defineAsyncComponent(() => import('@/components/BloodStockNotify/index.vue'))
const { initAllParams } = useSysParam()

View File

@ -0,0 +1,124 @@
<template>
<el-dialog v-model="visible" title="输血指征" width="1000" :close-on-click-modal="false" @close="handleClose">
<div class="tiptitle">*有如下检验结果,不符合输血指征,请填写补充说明</div>
<el-table border :data="tableData" style="width: 100%;" class="ind-table" show-overflow-tooltip>
<el-table-column label="指征名称" prop="causalis_Name" align="center">
<template #default="{ row }">
{{ row.xkTransfuseApplyCausalis.causalis_Name }}
</template>
</el-table-column>
<el-table-column label="项目名称" prop="itemName" align="center" />
<el-table-column label="结果" prop="itemResult" align="center" width='80' />
<el-table-column label="补充说明" prop="xkTransfuseApplyCausalis" align="left" width='500'>
<template #default="{ row }">
<el-input v-model="row.xkTransfuseApplyCausalis.explain" placeholder="" />
</template>
</el-table-column>
</el-table>
<div class="bottom-remark-wrap">
<div class="remark-title">其他补充说明</div>
<el-input v-model="localOtherRemark" type="textarea" :rows="4" placeholder="" />
</div>
<template #footer>
<el-button @click="handleClose">关闭</el-button>
<el-button type="primary" @click="handleConfirm">确定</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { table } from 'node:console';
// 表格行类型定义
interface IndRow {
itemName: string
itemResult: string
}
const emit = defineEmits<{
confirm: () => void
}>()
const visible = ref(false)
const tableData = ref<IndRow[]>([])
const localOtherRemark = ref('')
const billNo = ref('')
const openDialog = (data, bill_no: string) => {
visible.value = true
tableData.value = data
localOtherRemark.value = data.otherRemark
billNo.value = bill_no
}
// 仅关闭,不触发确认事件
const handleClose = () => {
visible.value = false
tableData.value = []
localOtherRemark.value = ''
billNo.value = ''
}
// 确定按钮:通知父组件已查看完成,再关闭弹窗
const handleConfirm = () => {
const arr: any = []
tableData.value.forEach(item => {
arr.push({
bill_no: billNo.value,
sid: item.xkTransfuseApplyCausalis.sid,
hos_ID: item.xkTransfuseApplyCausalis.hos_ID,
causalis_Code: item.xkTransfuseApplyCausalis.causalis_Code,
causalis_type: item.xkTransfuseApplyCausalis.causalis_type,
causalis_Name: item.xkTransfuseApplyCausalis.causalis_Name,
causalis_Result: item.xkTransfuseApplyCausalis.causalis_Result,
use_Flag: item.xkTransfuseApplyCausalis.use_Flag,
explain: item.xkTransfuseApplyCausalis.explain,
})
})
if (localOtherRemark.value) {
arr.push({
bill_no: billNo.value,
sid: tableData.value.length + 1,
hos_ID: '',
causalis_Code: 'B001',
causalis_type: 'B',
causalis_Name: localOtherRemark.value,
causalis_Result: 'W',
use_Flag: 'Y',
explain: localOtherRemark.value,
})
}
emit('confirm', arr)
visible.value = false
}
defineExpose({
openDialog
})
</script>
<style scoped lang="scss">
.ind-table {
margin-bottom: 12px;
}
.tiptitle {
color: #f00;
margin-bottom: 10px;
}
.bottom-remark-wrap {
margin-top: 8px;
.remark-title {
font-size: 14px;
font-weight: 600;
margin-bottom: 8px;
color: #000;
}
}
</style>

View File

@ -318,7 +318,7 @@
<el-table :data="bloodList" border height="143" show-overflow-tooltip>
<el-table-column prop="blood_breed" label="血液品种" align="center">
<template #default="{ row }">
{{bloodBreed.find(v => v.value == row.blood_breed).label}}
{{bloodBreed.find(v => v.value == row.blood_breed)?.label}}
</template>
</el-table-column>
<el-table-column prop="blood_num" label="申请血量" align="center" />
@ -346,7 +346,7 @@
</el-table-column>
<el-table-column prop="replace_bloodbreed" label="替代血液品种" align="center" width="120">
<template #default="{ row }">
{{bloodBreed.find(v => v.value == row.replace_bloodbreed).label}}
{{bloodBreed.find(v => v.value == row.replace_bloodbreed)?.label}}
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" align="center" />

View File

@ -16,10 +16,12 @@
<el-button :loading="shLoading" @click="reviewHandle">审核</el-button>
<el-button type="danger" plain @click="cancelreviewHandle">取消审核</el-button>
<el-button type="info" plain @click="invalidateHandle">作废</el-button>
<el-button type="warning" plain>打印输血申请单</el-button>
<el-button type="warning" :disabled="!xkTransfuseApply.bill_no" plain @click="">打印输血申请单</el-button>
<el-button @click="goHistoryBlood">患者输血历史</el-button>
<el-button type="warning" plain>打印大量输血审批单</el-button>
<el-button type="warning" plain>打印输血知情同意书</el-button>
<el-button type="warning" :disabled="!xkTransfuseApply.bill_no" plain :loading="printLoading"
@click="printPg('LARGE_APPLY')">打印大量输血审批单</el-button>
<el-button type="warning" :disabled="!xkTransfuseApply.assess_bill_no" plain :loading="printLoading"
@click="printPg('INFORMED_CONSENT')">打印输血知情同意书</el-button>
</div>
<!-- 主体区域 左2 : 右1 -->
@ -38,7 +40,7 @@
<div class="info-row">
<div class="info-item">
<span class="label">住院号:</span>
<span class="value">{{ xkTransfuseApply.beinhos_id }}</span>
<span class="value">{{ xkPatientInfo.beinhos_id }}</span>
</div>
<div class="info-item">
<span class="label">姓名:</span>
@ -79,8 +81,8 @@
<div class="blood-type-group">
<div class="blood-type-tag ab"><span class="x_type">{{ xkPatientInfo.abo || '-' }}</span> 型</div>
<div :class="['blood-type-tag', 'rh',]">
<span :class="[xkPatientInfo.rh ? (xkPatientInfo.rh == '+' ? '' : 'red') : '']">
{{ xkPatientInfo.rh ? (xkPatientInfo.rh == '+' ? '阳性' : '阴性') : '-' }}</span> RH
<span :class="[xkPatientInfo.rh == '+' ? '' : xkPatientInfo.rh == '-' ? 'red' : '']">
{{ xkPatientInfo.rh == '+' ? '阳性' : xkPatientInfo.rh == '-' ? '阴性' : '未知' }}</span> RH
</div>
</div>
</div>
@ -236,15 +238,20 @@
<div class="line"></div>
<div class="flow-wrap">
<div class="flow-item" v-for="(item, index) in processList" :key="index">
<el-tooltip effect="dark" placement="top"
:content="item.operateTime ? `操作时间:${item.operateTime}` : '暂未操作'">
<el-tooltip effect="dark" placement="top">
<template #content>
<div v-if="item.occurDate">
操作时间:{{ item.occurDate }}<br>
操作人:{{userList.find(v => v.value == item.occurName)?.label || ''}}
</div>
<div v-else>暂未操作</div>
</template>
<div class="circle-node" :class="[getNodeStatusClass(item, index)]">
{{ item.label }}
{{ item.statusName }}
</div>
</el-tooltip>
<!-- 箭头:index对应的节点是当前圆圈,有时间=箭头绿色 -->
<div v-if="Number(index) < Number(processList.length) - 1" class="arrow-line"
:class="{ arrow_finish: !!processList[index].operateTime }"></div>
:class="{ arrow_finish: item.visible == 'Y' }"></div>
</div>
</div>
@ -265,7 +272,7 @@
<el-table :data="bloodList" border height="120" show-overflow-tooltip>
<el-table-column prop="blood_breed" label="血液品种" align="center" width="150">
<template #default="{ row }">
{{bloodBreed.find(v => v.value == row.blood_breed).label}}
{{bloodBreed.find(v => v.value == row.blood_breed)?.label}}
</template>
</el-table-column>
<el-table-column prop="blood_num" label="申请血量" align="center" />
@ -553,6 +560,8 @@
@success="() => { getQueryOneInfo(xkTransfuseApply.bill_no); getSqdList() }" />
<!-- 校验用户身份 -->
<CheckUser ref="checkUserRef" @onConfirm="handleCheckUserConfirm" />
<!-- 输血指征校验 -->
<Indication ref="indicationRef" @confirm="indicationComfirm" />
</div>
</template>
@ -564,18 +573,19 @@ import DropdownTableSelect from '@/components/DropdownTableSelect/index.vue'
import dayjs from 'dayjs'
import {
querysqList, getPatInfo, checkSelfBlood, checkCausalis, savePreApplyInfo, saveApplyInfo, queryApplyOne, queryApplyBeforeList, applyCheck, applyMedicCheck,
cancelApplyMedicCheck, cancelApplyCheck, cancelApply, invokeEMR
cancelApplyMedicCheck, cancelApplyCheck, cancelApply, invokeEMR, bloodCloseLoop
} from '@/api/doctor/application'
import { printPat } from '@/api/doctor/assessment'
import { queryOperation, getDeptType, checkLoginAffirm } from '@/api/common'
import ReviewComments from './component/reviewComments.vue'
import Indication from './component/indication.vue'
import PatientLisTable from '../components/PatientLisTable.vue'
import CheckUser from '@/components/CheckUser/index.vue'
import useUserStore from '@/store/modules/user'
import router from '@/router/index.js'
import { printBase64PDF } from '@/utils/classCom.js'
const userInfo = useUserStore()
// 解构全部公共变量与方法
const { getParam } = useSysParam()
const {
getServerTime,
@ -592,19 +602,18 @@ const {
const route = useRoute()
const aboFlag = ref('')
const saveLoading = ref(false)
const bloodFormRef = ref<InstanceType<typeof ElForm>>()
const queryForm = reactive({
day: 7,
bill_status: '',
dept_code: userInfo.deptParam.deptId,
dept_code: '',
doctor_code: userInfo.name,
beinhos_id: ''
})
const listScope = ref('3')
const indicationRef = useTemplateRef('indicationRef')
const radioChange = (val: string) => {
switch (val) {
case '1':
@ -718,29 +727,29 @@ const bloodFormRules = reactive({
//流程节点
const processList = ref([
{ label: '开单', operateTime: '2026-06-01 10:10:10' },
{ label: '上级医生审核', operateTime: '2026-06-02 13:10:10' },
{ label: '科主任审核', operateTime: '2026-06-01 15:10:10' },
{ label: '医务部审核', operateTime: '' },
{ label: '输血科审核', operateTime: '' },
{ label: '血型复核', operateTime: '' },
{ label: '交叉配血', operateTime: '' },
{ label: '临床发血', operateTime: '' },
{ statusName: '开单', occurDate: '' },
{ statusName: '上级医生审核', occurDate: '' },
{ statusName: '输血科审核', occurDate: '' },
// { statusName: '医务部审核', occurDate: '' },
// { statusName: '输血科审核', occurDate: '' },
{ statusName: '血型复核', occurDate: '' },
{ statusName: '交叉配血', occurDate: '' },
{ statusName: '临床发血', occurDate: '' },
])
// 当前激活步骤下标
const currentStepIndex = computed(() => {
const list = processList.value
for (let i = 0; i < list.length; i++) {
if (!list[i].operateTime) return i
if (!list[i].occurDate) return i
}
return list.length - 1
})
// 节点状态类名
const getNodeStatusClass = (item: { operateTime: string }, index: number) => {
const getNodeStatusClass = (item, index: number) => {
const currIdx = currentStepIndex.value
// 已完成:有时间
if (item.operateTime) return 'finish'
if (item.visible == 'Y') return 'finish'
// 当前待办节点
if (index === currIdx) return 'active'
// 未开始
@ -805,8 +814,8 @@ const getSqdList = () => {
querysqList(queryForm).then((res) => {
orderList.value = res.data
if (res.data.length) {
const row = res.data.find(item => item.bill_no == xkTransfuseApply.value.bill_no)
nextTick(() => {
const row = res.data.find(item => item.bill_no == xkTransfuseApply.value.bill_no)
if (row) {
orderRef.value.setCurrentRow(row)
}
@ -836,6 +845,14 @@ const addHandle = () => {
formRef.value?.clearValidate()
})
})
processList.value = [
{ statusName: '开单', occurDate: '' },
{ statusName: '上级医生审核', occurDate: '' },
{ statusName: '输血科审核', occurDate: '' },
{ statusName: '血型复核', occurDate: '' },
{ statusName: '交叉配血', occurDate: '' },
{ statusName: '临床发血', occurDate: '' },
]
getLisProject()
}
const checkUserRef = useTemplateRef('checkUserRef')
@ -962,8 +979,25 @@ const shClose = () => {
agreement_ink: 'Y'
}
}
const printLoading = ref(false)
//打印输血评估单
const printPg = (name: string) => {
printLoading.value = true
let billno = ''
if (name == 'INFORMED_CONSENT') {
billno = xkTransfuseApply.value.assess_bill_no
} else if (name == 'LARGE_APPLY') {
billno = xkTransfuseApply.value.bill_no
}
printPat({ billNo: billno, templateName: name }).then((res) => {
if (res.data) {
printBase64PDF(res.data)
}
}).finally(() => {
printLoading.value = false
})
}
//患者历史
const goHistoryBlood = () => {
router.push({
@ -1068,16 +1102,23 @@ const handleSubmit = async () => {
xkTransfuseApplyTestitemList: lisProject.value,
}
// 自体血校验
checkSelfBlood({ beinhos_id: xkTransfuseApply.value.beinhos_id }).then((res) => {
if (res.code == 0) {
// 校验是否符合输血指征的规则
checkCausalis(data).then((res1) => {
if (res1.code == 0) {
// 保存前校验
savePreApplyInfo(data).then((res2) => {
if (res2.code == 0) {
// 保存申请单
saveApplyInfo(data).then((res3) => {
if (res3.data) {
getQueryOneInfo(res3.data)
getSqdList()
}
if (res3.code == 0) {
ElMessage.success('保存成功')
getSqdList()
}
})
} else if (res2.code == 1) {
@ -1097,15 +1138,21 @@ const handleSubmit = async () => {
).then(() => {
getQueryOneInfo(res2.data)
}).catch(() => {
// 保存申请单
saveApplyInfo(data).then((res3) => {
if (res3.code == 0) {
if (res3.data) {
getQueryOneInfo(res3.data)
getSqdList()
}
if (res3.code == 0) {
ElMessage.success('保存成功')
}
})
})
}
})
} else if (res1.code == 1) {
indicationRef.value.openDialog(res1.data, xkTransfuseApply.value.bill_no)
}
})
}
@ -1117,42 +1164,107 @@ const handleSubmit = async () => {
}
})
}
//输血指征校验弹窗确定
const indicationComfirm = (arr) => {
const tempPatient = { ...xkPatientInfo.value, beinhos_id: xkTransfuseApply.value.beinhos_id }
const data = {
transfuseApplyInfoOne: {
xkPatientInfo: tempPatient,
xkTransfuseApply: xkTransfuseApply.value
},
xkTransfuseApplyBloodbreedList: bloodList.value,
xkTransfuseApplyTestitemList: lisProject.value,
xkTransfuseApplyCausalisList: arr
}
saveApplyInfo(data).then((res) => {
if (res.data) {
getQueryOneInfo(res.data)
getSqdList()
}
if (res.code == 0) {
ElMessage.success('保存成功')
}
})
}
//获取申请单信息
const getQueryOneInfo = (bill_no: string) => {
queryApplyOne({ billNo: bill_no }).then((res) => {
xkPatientInfo.value = res.data.transfuseApplyInfoOne.xkPatientInfo
xkTransfuseApply.value = res.data.transfuseApplyInfoOne.xkTransfuseApply
bloodList.value = res.data.xkTransfuseApplyBloodbreedList
lisProject.value = res.data.xkTransfuseApplyTestitemList.map(item => {
return {
bill_no: item.bill_no,
item_name: item.item_name,
item_result: item.item_result,
item_unit: item.item_unit,
test_date: item.test_date,
sid: item.sid
}
})
lisProject.value = mergeLisTestItem(lisProject.value, res.data.xkTransfuseApplyTestitemList)
})
//获取申请单状态
bloodCloseLoop({ billNo: bill_no }).then(res => {
if (res.code == 0) {
processList.value = res.data
}
})
}
//获取患者信息
const getInfo = (billNo) => {
const getInfo = (billNo: string) => {
//PJD2026061623
getPatInfo({ bill_no: billNo }).then((res) => {
xkPatientInfo.value = res.data.transfuseApplyInfoOne.xkPatientInfo
xkTransfuseApply.value = res.data.transfuseApplyInfoOne.xkTransfuseApply
bloodList.value = res.data.xkTransfuseApplyBloodbreedList || []
lisProject.value = res.data.xkTransfuseApplyTestitemList.map(item => {
lisProject.value = mergeLisTestItem(lisProject.value, res.data.xkTransfuseApplyTestitemList)
})
}
//合并检查结果
const mergeLisTestItem = (oldList: Array<any>, apiList: Array<any>) => {
const currentBillNo = xkTransfuseApply.value?.bill_no ?? ''
if (apiList.length === 0) {
// 过滤脏数据
return oldList.filter(item => item?.item_name).map(item => {
return {
bill_no: item.bill_no,
item_name: item.item_name,
item_result: item.item_result,
item_unit: item.item_unit,
test_date: item.test_date,
sid: item.sid
...item,
item_result: '',
bill_no: currentBillNo
}
})
}
const oldMap = new Map<string, any>()
oldList.forEach(item => {
if (item?.item_name) oldMap.set(item.item_name, item)
})
return apiList.map(apiItem => {
if (!apiItem || !apiItem.item_name) {
return {
bill_no: currentBillNo,
item_name: '',
item_result: '',
item_unit: '',
test_date: '',
sid: '',
result_type: ''
}
}
const apiData = {
bill_no: apiItem.bill_no ?? currentBillNo,
item_name: apiItem.item_name ?? '',
item_result: apiItem.item_result ?? '',
item_unit: apiItem.item_unit ?? '',
test_date: apiItem.test_date ?? '',
sid: apiItem.sid ?? ''
}
const localItem = oldMap.get(apiItem.item_name)
if (localItem) {
// 接口所有字段覆盖,仅复用旧result_type
return {
...apiData,
result_type: localItem.result_type ?? ''
}
}
return {
...apiData,
result_type: ''
}
})
}
@ -1189,6 +1301,7 @@ const loadBillInfo = () => {
// 只有主动跳转带过来的参数才执行查询
if (state?.isJump && state.billNo) {
getInfo(state.billNo)
addHandle()
needClearState = true // 标记本次有跳转参数,页面销毁时清空
}
}
@ -1244,16 +1357,6 @@ onMounted(() => {
getDictData('sqdzfyy', 'rhtype', 'abotype', 'nldw', 'billApplyStatus', 'sd', 'ks', 'depttype', 'bq', 'sxmd', 'sxzz', 'test_result', 'sqlx', 'lczd', 'xylx', 'operatype', 'nooperatype')
getSqdList()
loadBillInfo()
// SQDSFKRLXGXX 参数说明如下:
// 输血申请时是否可从HIS系统中调出患者信息,是否可以录入修改患者血型?
// 以"/"分隔,"/"前指可以调出患者信息时是否可以修改患者血型(Y可以修改N不可以修改),
// "/"后指不可以调出患者信息时是否可以录入全部和只能录入"未知"患者血型(Y可以录入全部N只能录入"未知")
if (getParam('SQDSFKRLXGXX')) {
const [a, b] = getParam('SQDSFKRLXGXX').split('/')
aboFlag.value = b
}
})
// 监听路由变化
@ -1441,10 +1544,11 @@ onBeforeUnmount(() => {
width: 20%;
display: flex;
font-size: 14px;
// font-weight: 600;
.label {
color: #000;
font-weight: 600;
font-size: 14px;
color: #333;
min-width: 70px;
text-align: right;
margin-right: 8px;

View File

@ -57,7 +57,9 @@
</el-col>
<el-col :span="4">
<el-form-item label="血 型">
<el-input v-model="baseInfo.abo" disabled :value="baseInfo.abo" />
<el-select v-model="baseInfo.abo" placeholder="" :disabled="aboFlag == 'N'" clearable>
<el-option v-for="v in dictData.abotype" :label="v.label" :value="v.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
@ -81,7 +83,9 @@
<el-col :span="4">
<el-form-item label="Rh(D)">
<el-input v-model="baseInfo.rh" disabled :value="baseInfo.rh" />
<el-select v-model="baseInfo.rh" placeholder="" :disabled="aboFlag == 'N'" clearable>
<el-option v-for="v in dictData.rhtype" :label="v.label" :value="v.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
@ -263,6 +267,9 @@ const searchForm = ref({
beinhos_id: ''
})
const aboFlag = ref('')
const printLoading = ref(false)
const saveLoading = ref(false)
@ -324,21 +331,67 @@ const getBillInfo = () => {
evaluationInfo.value.assessmentDate = res.data.xkTransfuseApplyBeforeList[0].assess_data
baseInfo.value = res.data.xkPatientInfo
bloodInfo.value = res.data.xkTransfuseApplyBeforeList[0]
lisProject.value = res.data.xkTransfuseApplyTestitemList.map(item => {
return {
bill_no: item.bill_no,
item_name: item.item_name,
item_result: item.item_result,
item_unit: item.item_unit,
test_date: item.test_date,
sid: item.sid
}
})
lisProject.value = mergeLisTestItem(lisProject.value, res.data.xkTransfuseApplyTestitemList)
splitAge(baseInfo.value.age)
}
})
}
//合并检查结果
const mergeLisTestItem = (oldList: Array<any>, apiList: Array<any>) => {
const currentBillNo = evaluationInfo.value?.billNo ?? ''
if (apiList.length === 0) {
// 过滤脏数据
return oldList.filter(item => item?.item_name).map(item => {
return {
...item,
item_result: '',
bill_no: currentBillNo
}
})
}
const oldMap = new Map<string, any>()
oldList.forEach(item => {
if (item?.item_name) oldMap.set(item.item_name, item)
})
return apiList.map(apiItem => {
if (!apiItem || !apiItem.item_name) {
return {
bill_no: currentBillNo,
item_name: '',
item_result: '',
item_unit: '',
test_date: '',
sid: '',
result_type: ''
}
}
const apiData = {
bill_no: apiItem.bill_no ?? currentBillNo,
item_name: apiItem.item_name ?? '',
item_result: apiItem.item_result ?? '',
item_unit: apiItem.item_unit ?? '',
test_date: apiItem.test_date ?? '',
sid: apiItem.sid ?? ''
}
const localItem = oldMap.get(apiItem.item_name)
if (localItem) {
// 接口所有字段覆盖,仅复用旧result_type
return {
...apiData,
result_type: localItem.result_type ?? ''
}
}
return {
...apiData,
result_type: ''
}
})
}
// 回显时拆分 年龄 + 单位
const splitAge = (ageStr: string) => {
const unitList = dictData.value.nldw.map(item => item.value)
@ -477,18 +530,29 @@ const getProject = () => {
item_name: item.pro_name,
item_result: '',
item_unit: item.unit,
test_date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
sid: item.sid
test_date: '',
sid: item.sid,
result_type: item.result_type
}
})
})
}
onMounted(() => {
getDictData('ks', 'test_result', 'nldw', 'anemia')
getDictData('ks', 'test_result', 'nldw', 'anemia', 'rhtype', 'abotype',)
getProject()
// SQDSFKRLXGXX 参数说明如下:
// 输血申请时是否可从HIS系统中调出患者信息,是否可以录入修改患者血型?
// 以"/"分隔,"/"前指可以调出患者信息时是否可以修改患者血型(Y可以修改N不可以修改),
// "/"后指不可以调出患者信息时是否可以录入全部和只能录入"未知"患者血型(Y可以录入全部N只能录入"未知")
if (getParam('SQDSFKRLXGXX')) {
const [a, b] = getParam('SQDSFKRLXGXX').split('/')
aboFlag.value = b
}
const tipText = `<strong>输血报销适用限制范围如下:</strong><br />
诊疗少白细胞红细胞限特殊适应症与急救、抢救请根据限制范围,结合当前病人情况,判断是否适用医保如为自费患者。<br />
请到HIS-医保管理菜单-医保费用审核里`

View File

@ -1,373 +0,0 @@
/**
* @file index.vue
* @description: 储存室自体血登记
* @author: w
* @since: 2026-07-08
*/
<template>
<div class="box-container">
<div class="card-box">
<el-button type="primary" plain>检索</el-button>
<el-button type="primary" plain>新增单据</el-button>
<el-button type="danger" plain>删除单据</el-button>
<el-button 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 plain>反审核</el-button>
</div>
<el-form label-width="auto" class="form-container">
<div class="card-box">
<el-row :gutter="20" class="top-row">
<el-col :span="4">
<el-form-item class="compact-item" label="申请单号">
<el-input v-model="formData.applyNo" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item class="compact-item" label="申请日期">
<el-date-picker v-model="formData.applyDate" type="datetime" placeholder="选择日期" style="width:100%"
value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item class="compact-item" label="申请医师">
<el-input v-model="formData.applyDoctor" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item class="compact-item" label="主治医师">
<el-input v-model="formData.attendingDoctor" />
</el-form-item>
</el-col>
</el-row>
</div>
<div class="section form-body">
<el-row :gutter="20">
<el-col :span="16">
<div class="section-title">患者信息</div>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="住院号/ID号">
<el-input v-model="formData.patientId" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="姓 名">
<el-input v-model="formData.patientName" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="血 型">
<el-input v-model="formData.abo" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="Rh(D)">
<el-input v-model="formData.rh" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="性 别">
<el-select v-model="formData.patientSex" placeholder="">
<el-option label="男" value="男" />
<el-option label="女" value="女" />
<el-option label="未知" value="未知" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年 龄">
<div class="age-group">
<el-input v-model="formData.age" />
<el-input v-model="formData.ageUnit" class="age-unit" disabled />
</div>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="属 地">
<el-input v-model="formData.apanage" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="病 区">
<el-input v-model="formData.zone" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="科 室">
<el-input v-model="formData.dept" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="床 号">
<el-input v-model="formData.bedNo" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="禁 忌 症">
<el-input v-model="formData.contraindications" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="临床诊断">
<el-input v-model="formData.diagnoses" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="治 疗 目 的">
<el-input v-model="formData.treatmentPurpose" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20" class="checkbox-row">
<el-col :span="6">
<el-checkbox v-model="formData.transfusionHistory" true-value="Y" false-value="N">输血史</el-checkbox>
</el-col>
<el-col :span="6">
<el-checkbox v-model="formData.matchHistory" true-value="Y" false-value="N">配型史</el-checkbox>
</el-col>
<el-col :span="6">
<el-checkbox v-model="formData.pregnancyHistory" true-value="Y" false-value="N">妊娠史</el-checkbox>
</el-col>
<el-col :span="6">
<el-checkbox v-model="formData.deliveryHistory" true-value="Y" false-value="N">分娩史</el-checkbox>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-form-item label="备 注">
<el-input v-model="formData.remark" />
</el-form-item>
</el-col>
</el-row>
</el-col>
<el-col :span="8">
<div class="treatment-card">
<div class="section-title treatment-title">
<span>治疗项目</span>
<span class="status-oval">未审核</span>
</div>
<el-form-item label="治 疗 项 目">
<el-input v-model="formData.treatmentProject" />
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="采 血 量">
<div class="input-with-unit">
<el-input v-model="formData.collectVolume" type="number" />
<span class="unit">ml</span>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="治 疗 量">
<div class="input-with-unit">
<el-input v-model="formData.treatVolume" type="number" />
<span class="unit">ml</span>
</div>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="制 备 方 法">
<el-input v-model="formData.prepareMode" />
</el-form-item>
<el-form-item label="预约治疗时间">
<el-date-picker v-model="formData.appointmentTime" type="datetime" placeholder="选择日期" style="width:100%"
value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
</div>
</el-col>
</el-row>
</div>
<div class="section">
<div class="section-title">病人最近检查结果</div>
<div class="check-table">
<PatientLisTable v-model:lis-list="lisProject" />
</div>
</div>
</el-form>
</div>
</template>
<script setup lang="ts">
import PatientLisTable from '../components/PatientLisTable.vue'
const formData = reactive({
applyNo: '',
applyDate: '',
applyDoctor: '',
attendingDoctor: '',
patientId: '',
patientName: '',
abo: '',
patientSex: '',
age: '',
ageUnit: '岁',
apanage: '',
dept: '',
zone: '',
bedNo: '',
rh: '',
diagnoses: '',
contraindications: '无',
treatmentPurpose: '',
remark: '',
transfusionHistory: 'N',
matchHistory: 'N',
pregnancyHistory: 'N',
deliveryHistory: 'N',
treatmentProject: '',
collectVolume: '',
treatVolume: '',
prepareMode: '',
appointmentTime: ''
})
const lisProject = ref<any[]>([])
onMounted(() => {
lisProject.value = [
{ item_name: 'HGB', item_result: '', item_unit: 'g/L', validTime: '' },
{ item_name: 'ALT', item_result: '', item_unit: 'U/L', validTime: '' },
{ item_name: 'Anti-HCV', item_result: '', item_unit: '', validTime: '' },
{ item_name: 'APTT', item_result: '', item_unit: '秒', validTime: '' },
{ item_name: 'HCT', item_result: '', item_unit: '%', validTime: '' },
{ item_name: 'HBsAg', item_result: '', item_unit: '', validTime: '' },
{ item_name: 'Anti-HIV', item_result: '', item_unit: '', validTime: '' },
{ item_name: 'FIB', item_result: '', item_unit: 'g/L', validTime: '' },
{ item_name: 'PLT', item_result: '', item_unit: '×10⁹/L', validTime: '' },
{ item_name: 'TR', item_result: '', item_unit: '', validTime: '' },
{ item_name: 'PT', item_result: '', item_unit: '秒', validTime: '' },
{ item_name: 'INR', item_result: '', item_unit: '', validTime: '' }
]
})
</script>
<style scoped lang="scss">
.box-container {
display: flex;
flex-direction: column;
}
.form-container {
display: flex;
flex-direction: column;
gap: 10px;
.el-form-item {
margin-bottom: 6px;
}
}
.section {
width: 100%;
}
.section {
background: #fff;
border-radius: 4px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08);
padding: 14px 18px;
}
.top-row {
.el-form-item {
margin-bottom: 0;
}
}
.treatment-card {
border: 1px solid #dfe6ec;
border-radius: 4px;
padding: 12px;
background: #f9fbff;
}
.treatment-title {
display: flex;
justify-content: space-between;
align-items: center;
}
.status-oval {
display: inline-flex;
align-items: center;
justify-content: center;
width: 90px;
height: 40px;
border: 2px solid #999;
border-radius: 50px;
color: #333;
background: #f9fafb;
font-size: 12px;
}
.age-group {
display: flex;
align-items: center;
gap: 8px;
}
.age-unit {
width: 70px;
}
.checkbox-row {
padding-top: 8px;
}
.checkbox-row .el-checkbox {
line-height: 32px;
}
.input-with-unit {
position: relative;
}
.input-with-unit .el-input {
width: 100%;
}
.input-with-unit .unit {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
color: #909399;
font-size: 12px;
pointer-events: none;
}
.check-table {
min-height: 260px;
}
.el-form-item {
margin-bottom: 10px;
}
.el-form-item__label {
font-weight: 600;
}
</style>

View File

@ -5,13 +5,305 @@
* @since: 2026-07-08
*/
<template>
<div>
储存室自体血登记
<div class="box-container">
<div class="card-box">
<el-button type="primary" plain>检索</el-button>
<el-button type="primary" plain>新增单据</el-button>
<el-button type="danger" plain>删除单据</el-button>
<el-button 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 plain>反审核</el-button>
</div>
<el-form label-width="auto" class="form-container">
<div class="card-box">
<el-row :gutter="20" class="top-row">
<el-col :span="4">
<el-form-item class="compact-item" label="申请单号">
<el-input v-model="formData.applyNo" disabled />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item class="compact-item" label="申请日期">
<el-date-picker v-model="formData.applyDate" type="datetime" placeholder="选择日期" style="width:100%"
value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item class="compact-item" label="申请医师">
<SelectTable v-model:data="formData.applyDoctor" :tableData="userList" />
</el-form-item>
</el-col>
<el-col :span="4">
<el-form-item class="compact-item" label="主治医师">
<SelectTable v-model:data="formData.attendingDoctor" :tableData="userList" />
</el-form-item>
</el-col>
</el-row>
</div>
<div class="card-box form-body">
<el-row :gutter="20">
<el-col :span="16">
<div class="section-title">患者信息</div>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="住院号/ID号">
<el-input v-model="formData.patientId" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="姓 名">
<el-input v-model="formData.patientName" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="血 型">
<el-select v-model="formData.abo" placeholder="">
<el-option v-for="v in dictData.abotype" :label="v.label" :value="v.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="Rh(D)">
<el-select v-model="formData.rh" placeholder="">
<el-option v-for="v in dictData.rhtype" :label="v.label" :value="v.value" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="性 别">
<el-select v-model="formData.patientSex" placeholder="">
<el-option label="男" value="男" />
<el-option label="女" value="女" />
<el-option label="未知" value="未知" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年 龄">
<div class="age-group">
<el-input v-model="formData.age" style="width:60%" />
<el-select v-model="formData.nldw" placeholder="" style="width:40%">
<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="6">
<el-form-item label="属 地">
<SelectTable v-model:data="formData.apanage" :tableData="dictData.sd" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="病 区">
<SelectTable v-model:data="formData.apanage" :tableData="dictData.bq" placeholder="" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="6">
<el-form-item label="科 室">
<SelectTable v-model:data="formData.dept" :tableData="dictData.ks" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="床 号">
<el-input v-model="formData.bedNo" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="禁 忌 症">
<el-input v-model="formData.contraindications" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="临床诊断">
<el-input v-model="formData.diagnoses" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="治 疗 目 的">
<el-input v-model="formData.treatmentPurpose" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="备 注">
<el-input v-model="formData.remark" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-checkbox v-model="formData.transfusionHistory" true-value="Y" false-value="N">输血史</el-checkbox>
<el-checkbox v-model="formData.matchHistory" true-value="Y" false-value="N">配型史</el-checkbox>
<el-checkbox v-model="formData.pregnancyHistory" true-value="Y" false-value="N">妊娠史</el-checkbox>
<el-checkbox v-model="formData.deliveryHistory" true-value="Y" false-value="N">分娩史</el-checkbox>
</el-col>
</el-row>
</el-col>
<el-col :span="8">
<div class="treatment-card">
<div class="section-title">
<div> 治疗项目 </div>
<div class="status-oval"> 未审核 </div>
</div>
<el-form-item label="治 疗 项 目">
<el-input v-model="formData.treatmentProject" />
</el-form-item>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="采 血 量">
<el-input v-model="formData.collectVolume" type="number">
<template #suffix>
ml
</template>
</el-input>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="治 疗 量">
<el-input v-model="formData.treatVolume" type="number">
<template #suffix>
ml
</template>
</el-input>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="制 备 方 法">
<el-input v-model="formData.prepareMode" />
</el-form-item>
<el-form-item label="预约治疗时间">
<el-date-picker v-model="formData.appointmentTime" type="datetime" placeholder="选择日期" style="width:100%"
value-format="YYYY-MM-DD HH:mm:ss" />
</el-form-item>
</div>
</el-col>
</el-row>
</div>
<div class="card-box">
<div class="section-title">病人最近检查结果</div>
<div class="check-table">
<PatientLisTable v-model:lis-list="lisProject" />
</div>
</div>
</el-form>
</div>
</template>
<script setup lang="ts">
import PatientLisTable from '../components/PatientLisTable.vue'
import { getDictData, formatDict, dictData, useCommonDict } from '@/hooks/index.js'
const formData = ref({})
const {
userList,
getUserData,
lisProject,
getLisProject,
getServerTime
} = useCommonDict()
onMounted(() => {
})
onMounted(() => {
getDictData('nldw', 'abotype', 'rhtype', 'sd', 'bq', 'ks')
getUserData()
getLisProject()
getServerTime().then(time => {
formData.value.applyDate = time
})
})
</script>
<style scoped></style>
<style scoped lang="scss">
.box-container {
display: flex;
flex-direction: column;
}
.form-container {
.el-form-item {
margin-bottom: 6px;
}
}
.top-row {
.el-form-item {
margin-bottom: 0;
}
}
.treatment-card {
border: 1px solid #dfe6ec;
border-radius: 4px;
padding: 12px;
background: #f9fbff;
}
.status-oval {
display: inline-flex;
align-items: center;
justify-content: center;
width: 90px;
height: 40px;
border: 2px solid #999;
border-radius: 50px;
color: #333;
background: #f9fafb;
font-size: 12px;
}
.age-group {
display: flex;
align-items: center;
gap: 8px;
}
.age-unit {
width: 70px;
}
.checkbox-row {
padding-top: 8px;
}
.checkbox-row .el-checkbox {
line-height: 32px;
}
.check-table {
min-height: 260px;
}
.el-form-item {
margin-bottom: 10px;
}
.el-form-item__label {
font-weight: 600;
}
</style>

View File

@ -1,37 +1,40 @@
<template>
<div class="table-content">
<el-table :data="firstGroup" border height="100%">
<el-table :data="firstGroupList" border height="100%" show-overflow-tooltip>
<el-table-column label="项目名" prop="item_name" align="center" />
<el-table-column label="结果" prop="item_result" align="center">
<template #default="{ row }">
<el-input v-model="row.item_result" placeholder="" type="number" class="full-width-input"
v-if="row.result_type == 'A'" @input="syncParent" />
<el-select v-model="row.item_result" placeholder="" class="full-width-input" allow-create filterable
default-first-option clearable @change="handleChange">
v-else-if="row.result_type == 'B'" default-first-option clearable @change="syncParent">
<el-option v-for="item in dictData.test_result" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="单位" prop="item_unit" align="center" width="80" />
<el-table-column label="检验时间" prop="validTime" align="center" width="150" />
<el-table-column label="检验时间" prop="test_date" align="center" />
</el-table>
<el-table :data="secondGroup" border height="100%">
<el-table :data="secondGroupList" border height="100%" show-overflow-tooltip>
<el-table-column label="项目名" prop="item_name" align="center" />
<el-table-column label="结果" prop="item_result" align="center">
<template #default="{ row }">
<el-input v-model="row.item_result" placeholder="" type="number" class="full-width-input"
v-if="row.result_type == 'A'" @input="syncParent" />
<el-select v-model="row.item_result" placeholder="" class="full-width-input" allow-create filterable
default-first-option clearable @change="handleChange">
v-else-if="row.result_type == 'B'" default-first-option clearable @change="syncParent">
<el-option v-for="item in dictData.test_result" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</template>
</el-table-column>
<el-table-column label="单位" prop="item_unit" align="center" width="80" />
<el-table-column label="检验时间" prop="validTime" align="center" width="150" />
<el-table-column label="检验时间" prop="test_date" />
</el-table>
</div>
</template>
<script setup lang="ts">
import { dictData } from '@/hooks'
const props = defineProps<{
lisList: any[]
}>()
@ -41,29 +44,25 @@ const { lisList } = toRefs(props)
// 本地副本
const localList = ref<any[]>([])
// 父数据更新同步本地,仅初始化/切换单据时执行
watch(
lisList,
(val) => {
localList.value = JSON.parse(JSON.stringify(val || []))
},
{ immediate: true }
)
// 监听父数据
watch(lisList, (val) => {
localList.value = val ? JSON.parse(JSON.stringify(val)) : []
}, { immediate: true })
// 平分两组数据
const splitList = computed(() => {
const list = localList.value
const midIndex = Math.ceil(list.length / 2)
return {
firstGroup: list.slice(0, midIndex),
secondGroup: list.slice(midIndex)
}
// 拆分两组 分开computed
const firstGroupList = computed(() => {
const list = localList.value || []
const mid = Math.ceil(list.length / 2)
return list.slice(0, mid)
})
const secondGroupList = computed(() => {
const list = localList.value || []
const mid = Math.ceil(list.length / 2)
return list.slice(mid)
})
const firstGroup = computed(() => splitList.value.firstGroup)
const secondGroup = computed(() => splitList.value.secondGroup)
// 下拉修改时同步给父,不使用deep watch避免递归
const handleChange = () => {
// 同步父组件
const syncParent = () => {
const copy = JSON.parse(JSON.stringify(localList.value))
emit('update:lisList', copy)
}
@ -76,4 +75,8 @@ const handleChange = () => {
gap: 10px;
overflow: auto;
}
:deep(.full-width-input) {
width: 100%;
}
</style>

View File

@ -45,7 +45,7 @@
</el-table-column>
<el-table-column prop="blood_breed" label="血液品种" align="center">
<template #default="{ row }">
{{bloodBreed.find(v => v.value == row.blood_breed).label}}
{{bloodBreed.find(v => v.value == row.blood_breed)?.label}}
</template>
</el-table-column>
<el-table-column prop="ds" label="袋数" align="center" />

View File

@ -11,92 +11,119 @@
<div class="top-search-card">
<el-form inline :model="searchForm">
<el-form-item label="开单日期:">
<el-date-picker v-model="searchForm.startDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
<el-date-picker v-model="searchForm.stime" type="date" format="YYYY-MM-DD " value-format="YYYY-MM-DD"
placeholder="选择日期" style="width: 150px" />
<span class="divider"> — </span>
<el-date-picker v-model="searchForm.endDate" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
<el-date-picker v-model="searchForm.etime" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
placeholder="选择日期" style="width: 150px" />
</el-form-item>
<el-form-item label="申请单号:">
<el-input v-model="searchForm.patientName" placeholder="请输入" style="width:150px" />
<el-input v-model="searchForm.billNo" placeholder="请输入" style="width:150px" clearable />
</el-form-item>
<el-form-item label="住院号:">
<el-input v-model="searchForm.inNo" placeholder="请输入" style="width:150px" />
<el-input v-model="searchForm.beinhos_id" placeholder="请输入" style="width:150px" clearable />
</el-form-item>
<el-form-item label="科室:">
<el-select v-model="searchForm.dept" placeholder="" style="width:120px">
<!-- <el-option label="未提交" value="0" /> -->
</el-select>
<SelectTable v-model:data="searchForm.dept" :tableData="dictData.ks" placeholder="" width="150px" clearable />
</el-form-item>
<el-form-item label="是否提交:">
<el-select v-model="searchForm.status" placeholder="" style="width:120px">
<el-option label="未提交" value="0" />
<el-option label="已提交" value="1" />
<el-form-item label="状态:">
<el-select v-model="searchForm.flag" placeholder="" style="width:150px" clearable>
<el-option label="未审核" value="N" />
<el-option label="已审核" value="Y" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSearch">确定</el-button>
</el-form-item>
</el-form>
</div>
<!-- 表格卡片 -->
<div class="table-card">
<div class="mb10">
<el-button type="primary">检索</el-button>
<el-button type="primary">科主任核准</el-button>
<el-button type="primary">医务部审批</el-button>
<el-button type="warning">打印</el-button>
<el-button type="primary" plain @click="onSearch">检索</el-button>
<el-button type="primary" plain @click="approvalHandle">科主任核准</el-button>
<el-button type="primary" plain @click="spHandle">医务部审批</el-button>
<el-button type="warning" plain>打印</el-button>
</div>
<CustomTable :data="tableData" :columns="columns" :config="config" @selection-change="selectionChange"
@column-drag-end="ColumnDragEnd" :enableColumnDrag="true" />
<CustomTable :data="tableData" :columns="columns" :config="config" @row-click="rowClick"
@column-drag-end="ColumnDragEnd" :enableColumnDrag="true">
<template #dept_id="{ row }">
{{ formatDict(row.dept_id, 'ks') }}
</template>
<template #blood_breed="{ row }">
{{bloodBreed.find(item => item.value == row.blood_breed)?.label}}
</template>
<template #Archiater="{ row }">
{{userList.find(item => item.value == row.Archiater)?.label}}
</template>
<template #Medical_Dept="{ row }">
{{userList.find(item => item.value == row.Medical_Dept)?.label}}
</template>
<template #apply_medic="{ row }">
{{userList.find(item => item.value == row.apply_medic)?.label}}
</template>
<template #attending_medic="{ row }">
{{userList.find(item => item.value == row.attending_medic)?.label}}
</template>
<template #treat_medic="{ row }">
{{userList.find(item => item.value == row.treat_medic)?.label}}
</template>
<template #flag="{ row }">
{{ row.flag == 'Y' ? '已审核' : '未审核' }}
</template>
</CustomTable>
</div>
</div>
</template>
<script setup lang="ts">
import dayjs from 'dayjs'
import { approvalQueryList, auditArchiater, auditMedical } from '@/api/doctor/application'
import { getDictData, formatDict, dictData, useCommonDict } from '@/hooks'
import { ElMessage } from 'element-plus'
const {
getServerTime,
userList,
getUserData,
bloodBreed,
getBloodList,
} = useCommonDict()
// 搜索表单
const searchForm = ref({
patientName: '',
inNo: '',
startDate: dayjs().format('YYYY-MM-DD'),
endDate: dayjs().format('YYYY-MM-DD'),
status: '0',
billNo: '',
beinhos_id: '',
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
flag: '',
dept: '',
})
// 选中行
const selectedRows = ref<any[]>([])
const selectedRow = ref({})
// 模拟表格数据
const tableData = ref([
{ id: '1', name: '张三', sex: '男', nl: '18', xx: 'A', RH: '+', xypz: 'B', sl: '1', dw: '瓶', ks: '张三', shsj: '2023-06-04 10:00:00', ywb: '张三', spsj: '2023-06' },
])
// 表格数据
const tableData = ref([])
const columns = ref([
{ type: 'selection', width: 60, align: 'center', visible: true, },
{ label: '申请科室', prop: 'dept', align: 'center', visible: true, },
{ label: '申请单号', prop: 'applyNo', align: 'center', visible: true, width: 120 },
{ label: '住院号/ID号', prop: 'id', align: 'center', visible: true, width: 120 },
{ label: '患者姓名', prop: 'name', align: 'center', visible: true, },
{ label: '性别', prop: 'sex', align: 'center', visible: true, },
{ label: '年龄', prop: 'nl', align: 'center', visible: true, },
{ label: '血型', prop: 'xx', align: 'center', visible: true, },
{ label: 'Rh(D)', prop: 'RH', align: 'center', visible: true, },
{ label: '血液品种', prop: 'xypz', align: 'center', visible: true, },
{ label: '申请数量', prop: 'sl', align: 'center', visible: true, },
{ label: '单位', prop: 'dw', align: 'center', visible: true, },
{ label: '科室主任', prop: 'ks', align: 'center', visible: true, },
{ label: '审核时间', prop: 'shsj', align: 'center', visible: true, },
{ label: '医务部', prop: 'ywb', align: 'center', visible: true, },
{ label: '审批时间', prop: 'spsj', align: 'center', visible: true, },
{ label: '申请医生', prop: 'doctor', align: 'center', visible: true, },
{ label: '主治医师', prop: 'zz', align: 'center', visible: true, },
{ label: '上级医师', prop: 'sj', align: 'center', visible: true, },
{ label: '申请科室', prop: 'dept_id', align: 'center', visible: true, slot: 'dept_id' },
{ label: '申请单号', prop: 'bill_no', align: 'center', visible: true, width: 120 },
{ label: '住院号/ID号', prop: 'beinhos_id', align: 'center', visible: true, width: 120 },
{ label: '患者姓名', prop: 'patient_name', align: 'center', visible: true, },
{ label: '性别', prop: 'patient_sex', align: 'center', visible: true, },
{ label: '年龄', prop: 'age', align: 'center', visible: true, width: 50 },
{ label: '血型', prop: 'abo_type', align: 'center', visible: true, width: 50 },
{ label: 'Rh(D)', prop: 'rh_type', align: 'center', visible: true, width: 50 },
{ label: '血液品种', prop: 'blood_breed', align: 'center', visible: true, slot: 'blood_breed' },
{ label: '申请数量', prop: 'blood_num', align: 'center', visible: true, },
{ label: '单位', prop: 'unit', align: 'center', visible: true, width: 50 },
{ label: '科室主任', prop: 'Archiater', align: 'center', visible: true, slot: 'Archiater' },
{ label: '审核时间', prop: 'Archiater_CheckTime', align: 'center', visible: true, width: 150 },
{ label: '医务部', prop: 'Medical_Dept', align: 'center', visible: true, slot: 'Medical_Dept' },
{ label: '审批时间', prop: 'Medical_CheckTime', align: 'center', visible: true, width: 150 },
{ label: '申请医生', prop: 'apply_medic', align: 'center', visible: true, slot: 'apply_medic' },
{ label: '主治医师', prop: 'attending_medic', align: 'center', visible: true, slot: 'attending_medic' },
{ label: '上级医师', prop: 'treat_medic', align: 'center', visible: true, slot: 'treat_medic' },
{ label: '状态', prop: 'flag', align: 'center', visible: true, slot: 'flag' },
])
const config = {
@ -109,19 +136,47 @@ const ColumnDragEnd = (newColumns) => {
columns.value = newColumns.columns
}
const selectionChange = (arr) => {
console.log('选中行', arr)
const rowClick = (row) => {
selectedRow.value = row
}
// 事件
const onSearch = () => {
searchForm.value.stime = dayjs(searchForm.value.stime).format('YYYY-MM-DD') + ' 00:00:00'
searchForm.value.etime = dayjs(searchForm.value.etime).format('YYYY-MM-DD') + ' 23:59:59'
console.log('查询参数', searchForm.value)
approvalQueryList(searchForm.value).then((res) => {
tableData.value = res.data
})
}
const onCancel = () => {
console.log('作废', selectedRows.value)
// 科主任核准
const approvalHandle = () => {
if (!selectedRow.value.bill_no) return ElMessage.warning('请选择申请单')
auditArchiater({ billNo: selectedRow.value.bill_no }).then((res) => {
if (res.code == 0) {
ElMessage.success(res.msg)
selectedRow.value = {}
onSearch()
}
})
}
const onAudit = () => {
console.log('审核', selectedRows.value)
// 审批
const spHandle = () => {
if (!selectedRow.value.bill_no) return ElMessage.warning('请选择申请单')
auditMedical({ billNo: selectedRow.value.bill_no }).then((res) => {
if (res.code == 0) {
ElMessage.success(res.msg)
selectedRow.value = {}
onSearch()
}
})
}
onMounted(() => {
getDictData('ks')
getUserData()
getBloodList()
onSearch()
})
</script>
<style scoped lang="scss">
@ -154,7 +209,7 @@ const onAudit = () => {
background: #fff;
border-radius: 6px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.07);
padding: 16px;
padding: 12px;
height: calc(100% - 60px);
// 右上角按钮栏

View File

@ -16,7 +16,7 @@
<el-button type="info" plain>标签重打</el-button>
</div>
<el-form label-width="auto">
<div class="section">
<div class="card-box">
<div class="section-title">申请信息</div>
<el-row :gutter="20">
<el-col :span="4">
@ -117,8 +117,8 @@
</el-form>
<el-row :gutter="10">
<el-col :span="12">
<div class="box-item">
<div class="box-title">治疗项目</div>
<div class="card-box">
<div class="section-title">治疗项目</div>
<div class="table-box">
<el-table :data="treatmentItems" border height="150" style="width: 100%" show-overflow-tooltip
highlight-current-row>
@ -131,8 +131,8 @@
</div>
</el-col>
<el-col :span="12">
<div class="box-item">
<div class="box-title">采血血液</div>
<div class="card-box">
<div class="section-title">采血血液</div>
<div class="table-box">
<el-table :data="bloodItems" border height="150" style="width: 100%" show-overflow-tooltip
highlight-current-row>
@ -146,7 +146,7 @@
</el-col>
</el-row>
<div class="section">
<div class="card-box" style="margin-bottom: 0;">
<div class="section-title">登记信息</div>
<el-row :gutter="20">
<el-col :span="4">
@ -173,7 +173,7 @@
</el-row>
</div>
<div class="card-box" style="margin-bottom: 0;">
<div class="card-box">
<div class="section-title">
<div> 采血信息 </div>
<el-button type="primary" plain class="mb10">新增血液</el-button>
@ -230,7 +230,6 @@ onMounted(() => {
.box-container {
display: flex;
flex-direction: column;
box-sizing: border-box;
gap: 10px;
overflow-y: auto;
}
@ -242,65 +241,12 @@ onMounted(() => {
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 {

View File

@ -383,7 +383,7 @@ function getList() {
/** 查询部门下拉树结构 */
function getDeptTree() {
deptTreeSelect().then(response => {
deptTreeSelect({ status: 0 }).then(response => {
deptOptions.value = response.data
enabledDeptOptions.value = filterDisabledDept(JSON.parse(JSON.stringify(response.data)))
})