2026-09-11 18:00:42 +08:00

995 lines
39 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file index.vue
* @description: 交叉配血
* @author: w
* @since: 2026-06-18
*/
<template>
<div class="box-container">
<!-- 顶部操作按钮栏 -->
<div class="card-box">
<el-button type="primary" plain @click="openJsHandle">检索</el-button>
<el-button type="primary" plain @click="addMatch">新增单据</el-button>
<el-button type="danger" plain @click="cancelApply">作废整单</el-button>
<el-button type="primary" plain @click="kcOpen">血液库存</el-button>
<el-button type="primary" plain :disabled="!formData.bill_no" @click="openResultDialog">检验结果</el-button>
<el-button type="success" plain :disabled="bloodInfo.bill_status && bloodInfo.bill_status != 'A'"
@click="saveBloodApply" :loading="saveLoading">保存</el-button>
<el-button type="warning" plain>打印</el-button>
</div>
<!-- 主体左右分栏容器 -->
<div class="main-wrap">
<el-row :gutter="10" class="left-row">
<el-col :span="15" class="left-col">
<el-form :model="formData" label-width="auto" class="form_box"
:disabled="bloodInfo.bill_status && bloodInfo.bill_status != 'A'">
<div class="card-box">
<div class="section-title">
<div> 申请单信息 </div>
<div v-show="bloodInfo.bill_no">
配血单号:{{ bloodInfo.bill_no || '' }}
</div>
</div>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="申请单号">
<DropdownTableSelect v-model="formData.bill_no" :column-list="applyColumns" tableWidth="800px"
:showSearch="false" labelField="bill_no" :table-data="applyTableData" @open="loadApplyData"
@search="searchApply" @change="searchApply" :disabled="!!(bloodInfo.bill_no)">
<template #dept_id="{ row }">
{{ formatDict(row.dept_id, 'ks') }}
</template>
<template #blood_breed="{ row }">
{{bloodBreed.find(v => v.value == row.blood_breed)?.label || row.blood_breed}}
</template>
</DropdownTableSelect>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="申请日期">
<el-input v-model="formData.apply_date" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="姓 名">
<el-input v-model="formData.patient_name" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<div class="status" v-show="formData.bill_stasus"
:style="{ borderColor: getBillStatusInfo(formData.bill_stasus).color, color: getBillStatusInfo(formData.bill_stasus).color }">
{{ getBillStatusInfo(formData.bill_stasus).label }}
</div>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="性 别">
<el-input v-model="formData.patient_sex" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年 龄">
<el-input v-model="formData.age" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="住院号/ID号">
<el-input v-model="formData.beinhos_id" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="血型">
<div class="blood-type-group">
<div class="blood-type-tag ab"><span class="x_type">{{ formData.abo_type || '-' }}</span> 型</div>
</div>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="病 区">
<SelectTable v-model:data="formData.zone_id" :tableData="dictData.bq" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="科 室">
<SelectTable v-model:data="formData.dept_id" :tableData="dictData.ks" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="床位号">
<el-input v-model="formData.patient_bed" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="Rh(D)">
<!-- <el-input v-model="formData.rh_type" placeholder="" disabled /> -->
<div class="blood-type-group">
<div :class="['blood-type-tag', 'rh',]">
<span :class="[formData.rh_type == '+' ? '' : formData.rh_type == '-' ? 'red' : '']">
{{ formData.rh_type == '+' ? '阳性' : formData.rh_type == '-' ? '阴性' : '未知' }}</span> RH
</div>
</div>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="临床诊断">
<el-input v-model="formData.diagnoses" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="输血目的">
<SelectTable v-model:data="formData.intent" :tableData="dictData.sxmd" placeholder="" disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="ABO复核">
<el-input v-model="formData.affirm_abo" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="亚型">
<SelectTable v-model:data="formData.Sub_Blood" :tableData="dictData.subgroup" placeholder=""
disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="Rh(D)复核">
<el-input v-model="formData.check_rh" placeholder="" disabled />
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="抗体筛选">
<SelectTable v-model:data="formData.affirm_antibody" :tableData="dictData.ktsx" placeholder=""
disabled />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="15">
<el-form-item label=" ">
<div class="checkbox-group">
<el-checkbox :model-value="formData.reaction_history == 'Y'">输血反应史</el-checkbox>
<el-checkbox :model-value="formData.transfuse_history == 'Y'">输血史</el-checkbox>
<el-checkbox :model-value="formData.parturition_history == 'Y'">分娩史</el-checkbox>
<el-checkbox :model-value="formData.gestation_history == 'Y'">妊娠史</el-checkbox>
<el-checkbox :model-value="formData.match_history == 'Y'">配型史</el-checkbox>
</div>
</el-form-item>
</el-col>
<el-col :span="9">
<el-form-item label="预定输血日期">
<el-date-picker v-model="formData.use1_date" type="datetime" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="" disabled />
</el-form-item>
</el-col>
</el-row>
<el-table :data="bloodApplyTable" 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 || row.blood_breed}}
</template>
</el-table-column>
<el-table-column prop="blood_num" label="申请血量" align="center" />
<el-table-column prop="unit" label="单位" align="center" width="60" />
<el-table-column prop="apply_bloodtype" label="申请血型" align="center">
<template #default="{ row }">
{{ formatDict(row.apply_bloodtype, 'abotype') }}
</template>
</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 || row.replace_bloodbreed}}
</template>
</el-table-column>
<el-table-column prop="intent" label="输血目的" align="center" width="200">
<template #default="{ row }">
{{ formatDict(row.intent, 'sxmd') }}
</template>
</el-table-column>
<el-table-column prop="causalis" label="输血指征" align="center" width="200">
<template #default="{ row }">
{{ formatDict(row.causalis, 'sxzz') }}
</template>
</el-table-column>
<el-table-column label="实际用血量" prop="ops_fact_use" align="center" />
</el-table>
</div>
<div class="card-box pxBox" style="margin-bottom: 0px;">
<div class="section-title">配血记录</div>
<div class="mb10">
<el-select v-model="matchSelect" placeholder="请选择" style="width: 150px">
<el-option label="增加配血血液" value="add" />
<el-option label="取消配血血液" value="del" />
</el-select>
<el-input v-model="bloodNo" placeholder="" @keyup.enter="bloodEnter"
style="width: 250px;margin-left: 20px;" />
</div>
<div class="table-box">
<CustomTable :data="matchTable" :columns="matchColumns" :config="config">
<template #second_match_medic="{ row }">
<SelectTable v-model:data="row.second_match_medic" :tableData="userList" placeholder=""
:clearable="false" class="full-width-input"
:disabled="bloodInfo.bill_status && bloodInfo.bill_status != 'A'" />
</template>
<template #blood_breed="{ row }">
{{bloodBreed.find(v => v.value == row.blood_breed)?.label || row.blood_breed}}
</template>
<template #offer_affirm_abo="{ row }">
<el-select v-model="row.offer_affirm_abo" placeholder="" class="full-width-input">
<el-option v-for="option in dictData.abotype" :key="option.value" :label="option.label"
:value="option.value" />
</el-select>
</template>
<template #check_offer_rh="{ row }">
<el-select v-model="row.check_offer_rh" placeholder="" class="full-width-input">
<el-option v-for="option in dictData.rhtype" :key="option.value" :label="option.label"
:value="option.value" />
</el-select>
</template>
<template #match_method="{ row }">
<el-select v-model="row.match_method" placeholder="" class="full-width-input">
<el-option v-for="option in dictData.pxff" :key="option.value" :label="option.label"
:value="option.value" />
</el-select>
</template>
<template #check_method="{ row }">
<el-select v-model="row.check_method" placeholder="" class="full-width-input">
<el-option v-for="option in dictData.pxff" :key="option.value" :label="option.label"
:value="option.value" />
</el-select>
</template>
<template #first_side="{ row }">
<el-select v-model="row.first_side" placeholder="" class="full-width-input">
<el-option v-for="option in dictData.zccc" :key="option.value" :label="option.label"
:value="option.value" />
</el-select>
</template>
<template #second_side="{ row }">
<el-select v-model="row.second_side" placeholder="" class="full-width-input">
<el-option v-for="option in dictData.zccc" :key="option.value" :label="option.label"
:value="option.value" />
</el-select>
</template>
<template #result="{ row }">
<el-select v-model="row.result" placeholder="" class="full-width-input">
<el-option v-for="option in dictData.pxjg" :key="option.value" :label="option.label"
:value="option.value" />
</el-select>
</template>
<template #match_date="{ row }">
<el-date-picker v-model="row.match_date" type="datetime" format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss" placeholder="" class="full-width-input" />
</template>
<template #match_medic="{ row }">
<SelectTable v-model:data="row.match_medic" :tableData="userList" placeholder=""
class="full-width-input" :clearable="false"
:disabled="bloodInfo.bill_status && bloodInfo.bill_status != 'A'" />
</template>
<template #position_blood="{ row }">
<el-input v-model="row.position_blood" placeholder="" class="full-width-input" />
</template>
<template #position_barcode="{ row }">
<el-input v-model="row.position_barcode" placeholder="" class="full-width-input" />
</template>
<template #action="{ row, $index }">
<el-button type="primary" text @click="removeRow($index)">删除</el-button>
</template>
</CustomTable>
</div>
</div>
</el-form>
</el-col>
<!-- 右侧筛选+结果表格区域 -->
<el-col :span="9" class="right-col">
<div class="card-box pxBox" style="margin-bottom: 0px;">
<el-form :model="filterForm">
<el-row :gutter="10">
<el-col :span="8">
<el-form-item label="姓名:">
<el-input v-model="filterForm.patientName" placeholder="" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="状态:">
<el-select v-model="filterForm.status" placeholder="全部" clearable>
<el-option v-for="option in billStatus" :key="option.value" :label="option.label"
:value="option.value" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="2">
<el-form-item label="">
<el-button type="primary" plain @click="handleRefresh">刷新</el-button>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="16">
<el-form-item label="时间:">
<el-date-picker v-model="filterForm.stime" type="date" format="YYYY-MM-DD" style="width: 47%"
value-format="YYYY-MM-DD" />
<span class="timesplit">—</span>
<el-date-picker v-model="filterForm.etime" type="date" format="YYYY-MM-DD" style="width: 47%"
value-format="YYYY-MM-DD" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="table-box">
<el-table :data="resultTable" border height="100%" highlight-current-row show-overflow-tooltip
@row-click="handleRowClick">
<el-table-column label="配血日期" prop="test_date" align="center" width="150" />
<el-table-column label="患者姓名" prop="patient_name" align="center" />
<el-table-column label="单据状态" prop="bill_status" align="center">
<template #default="{ row }">
{{billStatus.find(v => v.value == row.bill_status)?.label || row.bill_status}}
</template>
</el-table-column>
<el-table-column label="配血单号" prop="bill_no" align="center" width="150" />
<el-table-column label="申请单号" prop="apply_no" align="center" width="150" />
<el-table-column label="科室" prop="dept_id" align="center">
<template #default="{ row }">
{{ formatDict(row.dept_id, 'ks') }}
</template>
</el-table-column>
<el-table-column label="ABO复核" prop="affirm_abo" align="center" />
<el-table-column label="Rh(D)复核" prop="check_rh" align="center" />
</el-table>
</div>
</div>
</el-col>
</el-row>
</div>
<el-dialog title="常规配血单检索" v-model="visible" width="1200px" :close-on-click-modal="false" @closed="handleClose">
<div class="mb10">
<el-button type="primary" @click="handleSearch">检索</el-button>
<el-button type="success" @click="handleConfirm">确认</el-button>
</div>
<!-- 检索条件区 -->
<el-form :model="searchForm" label-width="auto" class="search-form">
<el-row :gutter="10">
<el-col :span="9">
<el-form-item label="检索时间">
<div class="date-range">
<el-date-picker v-model="searchForm.stime" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
style="width: 47%" />
<span class="separator">-</span>
<el-date-picker v-model="searchForm.etime" type="date" format="YYYY-MM-DD" value-format="YYYY-MM-DD"
style="width: 47%" />
</div>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="配血单号">
<el-input v-model="searchForm.billNo" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="科室">
<SelectTable v-model:data="searchForm.dept" :tableData="dictData.ks" placeholder="" />
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="9">
<el-form-item label="申请单号">
<el-input v-model="searchForm.applyNo" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="住院号/ID号">
<el-input v-model="searchForm.beinhos_id" placeholder="" />
</el-form-item>
</el-col>
</el-row>
</el-form>
<!-- 结果表格区 -->
<el-table :data="tableData" border height="450" @row-click="jsRowclick" @row-dblclick="dblClickRow"
highlight-current-row show-overflow-tooltip>
<el-table-column prop="patient_name" label="患者姓名" align="center" />
<el-table-column prop="bill_status" label="单据状态" align="center">
<template #default="{ row }">
{{billStatus.find(v => v.value == row.bill_status)?.label || row.bill_status}}
</template>
</el-table-column>
<el-table-column prop="bill_no" label="配血单号" align="center" width="150" />
<el-table-column prop="apply_no" label="申请单号" align="center" width="150" />
<el-table-column prop="dept_id" label="科室" align="center">
<template #default="scope">
{{ formatDict(scope.row.dept_id, 'ks') }}
</template>
</el-table-column>
<el-table-column prop="test_date" label="配血日期" width="150" align="center" />
<el-table-column prop="affirm_abo" label="ABO复核" align="center" />
<el-table-column prop="check_rh" label="Rh(D)复核" align="center" />
</el-table>
</el-dialog>
<el-dialog title="查看配血相关检验结果" v-model="resultVisible" width="700px" :close-on-click-modal="false">
<div class="table-box">
<el-table :data="resultList" border height="350" show-overflow-tooltip>
<el-table-column label="检验项目名称" prop="item_name" align="center" />
<el-table-column label="检验项目结果" prop="item_result" align="center">
<template #default="{ row }">
{{ formatDict(row.item_result, 'test_result') }}
</template>
</el-table-column>
<el-table-column label="检验时间" prop="test_date" align="center" />
</el-table>
</div>
</el-dialog>
<el-dialog title="血液库存预览" v-model="kcvisible" width="1200px" :close-on-click-modal="false" @closed="">
<div class="mb10 serch-box">
<el-input v-model="kcSearchForm.blood_no" placeholder="请输入血液流水号" @keyup.enter="searchBloodStock"
style="width: 250px" clearable />
<span style="color:#f00">红色:已过期</span>
<span style="color:#ff00ff">粉红色:已配血</span>
<span style="color:#0a9292">青色:配血超过预定天数未出库</span>
</div>
<el-table :data="kcTableData" border height="500px" highlight-current-row show-overflow-tooltip
:cell-style="cellStyle">
<el-table-column label="血液流水号" prop="blood_no" align="center" />
<el-table-column label="产品码" prop="product_no" align="center" />
<el-table-column label="血型" prop="blood_type" align="center" width="60" />
<el-table-column label="Rh血型" prop="rh_blood_type" align="center" width="80" />
<el-table-column label="有效日期" prop="valid_date" align="center" width="170" />
<el-table-column label="血液状态" prop="blood_status" align="center" width="100">
<template #default="{ row }">
{{ bloddStatus[row.blood_status] || row.blood_status }}
</template>
</el-table-column>
<el-table-column label="血液品种" prop="blood_breed" align="center" width="150">
<template #default="{ row }">
{{bloodBreed.find(v => v.value == row.blood_breed)?.label || row.blood_breed}}
</template>
</el-table-column>
<el-table-column label="容量" prop="capacity" align="center" />
<el-table-column label="单位" prop="unit" align="center" width="60" />
</el-table>
<div class="f-title">
总计:{{ kcTableData.length }} 袋
</div>
</el-dialog>
<BloodMask ref="maskRef" :bloodBreed="bloodBreed" @selectRow="selectBlood" />
</div>
</template>
<script setup lang="ts" name="CrossMatching">
import DropdownTableSelect, { type TableColumnItem, type TableRowItem } from '@/components/DropdownTableSelect/index.vue'
import dayjs from 'dayjs'
import { getDictData, formatDict, dictData, useCommonDict } from '@/hooks'
import {
queryMatchBloodList, queryMatchOne, queryWaitInfo, getBloodInfoMatch, checkBloodMatched, saveBloodData, queryMatchApplyInfo, cancelBloodInfoMatch,
deleteBloodInfoMatch, queryBloodStockList, queryListResult
} from '@/api/blood'
import { queryBloodInfoByBloodNo } from '@/api/common'
import { ElMessageBox, ElMessage } from 'element-plus'
import useUserStore from '@/store/modules/user'
import BloodMask from '../component/bloodMask.vue'
const userInfo = useUserStore()
const { userList, getUserData, getServerTime, bloodBreed, getBloodList, } = useCommonDict()
const maskRef = useTemplateRef('maskRef')
const visible = ref(false)
const kcvisible = ref(false)
const kcTableData = ref([])
const bloodInfo = ref({})
const saveLoading = ref(false)
const billStatus = ref([
{ label: '未发血', value: 'A' },
{ label: '已发血', value: 'B' },
{ label: '已作废', value: 'ZF' },
])
const searchForm = ref({
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
})
const tableData = ref([])
const applyColumns = ref<TableColumnItem[]>([
{ label: '申请单号', prop: 'bill_no' },
{ label: '患者姓名', prop: 'patient_name' },
{ label: '科室', prop: 'dept_id', slotName: 'dept_id' },
{ label: '申请时间', prop: 'apply_date' },
{ label: '申请品种', prop: 'blood_breed', slotName: 'blood_breed' }
])
const applyTableData = ref<TableRowItem[]>([])
const bloddStatus = {
'1': '在库',
'4': '出库',
'2': '报废',
}
// 主表单数据
const formData = ref({})
// 右侧筛选表单
const filterForm = ref({
name: '',
status: '',
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
})
const bloodNo = ref('')
// 配血操作单选
const matchSelect = ref('add')
// 血液申请表格
const bloodApplyTable = ref([])
// 配血记录表格
const matchTable = ref([])
const matchColumns = ref([
{ label: '序号', type: 'index', width: 40, visible: true, align: 'center' },
{ label: '复核者', prop: 'second_match_medic', align: 'center', visible: true, width: 100, slot: 'second_match_medic', showOverflowTooltip: false },
{ label: '血液流水号', prop: 'blood_no', align: 'center', width: 120, visible: true, },
{ label: '产品码', prop: 'product_no', align: 'center', visible: true, },
{ label: '血液品种', prop: 'blood_breed', align: 'center', visible: true, slot: 'blood_breed', },
{ label: '血型', prop: 'blood_type', align: 'center', visible: true, },
{ label: 'Rh(D)', prop: 'rh_blood_type', align: 'center', visible: true, },
{ label: '容量', prop: 'capacity', align: 'center', visible: true, },
{ label: '供者血型复核', prop: 'offer_affirm_abo', align: 'center', visible: true, width: 120, slot: 'offer_affirm_abo', showOverflowTooltip: false },
{ label: '供者Rh(D)复核', prop: 'check_offer_rh', align: 'center', visible: true, width: 120, slot: 'check_offer_rh', showOverflowTooltip: false },
{ label: '配血方法', prop: 'match_method', align: 'center', visible: true, width: 150, slot: 'match_method', showOverflowTooltip: false },
{ label: '复核配血方法', prop: 'check_method', align: 'center', visible: true, width: 150, slot: 'check_method', showOverflowTooltip: false },
{ label: '主侧', prop: 'first_side', align: 'center', visible: true, width: 150, slot: 'first_side', showOverflowTooltip: false },
{ label: '次侧', prop: 'second_side', align: 'center', visible: true, width: 150, slot: 'second_side', showOverflowTooltip: false },
{ label: '结果', prop: 'result', align: 'center', visible: true, width: 150, slot: 'result', showOverflowTooltip: false },
{ label: '配血日期', prop: 'match_date', align: 'center', visible: true, width: 150, slot: 'match_date', showOverflowTooltip: false },
{ label: '配血者', prop: 'match_medic', align: 'center', visible: true, width: 100, slot: 'match_medic', showOverflowTooltip: false },
{ label: '血液存放位子', prop: 'position_blood', align: 'center', visible: true, width: 150, slot: 'position_blood', showOverflowTooltip: false },
{ label: '标本存放位子', prop: 'position_barcode', align: 'center', visible: true, width: 150, slot: 'position_barcode', showOverflowTooltip: false },
])
const config = {
height: '100%',
border: true,
highlightCurrentRow: true,
actionFixed: 'right',
}
// 右侧结果列表
const resultTable = ref([])
// 检验结果弹窗数据
const resultVisible = ref(false)
const resultList = ref([])
const openResultDialog = () => {
const params = { billNo: formData.value.bill_no }
queryListResult(params).then(res => {
resultList.value = res.data || []
resultVisible.value = true
})
}
const getBillStatusInfo = (code: string) => {
const statusList = dictData.value?.billApplyStatus ?? []
const target = statusList.find(item => item.value == code)
if (target) {
return { label: target.label, color: target.remark }
}
return { label: '未审核', color: '#909399' }
}
// 血液流水号获取血液信息
const bloodEnter = () => {
if (!formData.value.bill_no) return ElMessage.warning('请选择输血申请单!')
const index = matchTable.value.findIndex(item => item.blood_no == bloodNo.value)
if (matchSelect.value == 'del') {
if (index > -1) {
ElMessageBox.confirm(`确定取消血液${matchTable.value[index].blood_no}数据吗?`, '提示', { type: 'warning' }).then(() => {
cancelBloodInfoMatch({ bloodNo: matchTable.value[index].blood_no, productNo: matchTable.value[index].product_no }).then(res => {
matchTable.value.splice(index, 1)
})
})
} else {
ElMessage.warning('该血液流水号不存在,请检查!')
}
} else {
if (index > -1) return ElMessage.warning('该血液流水号已存在,请检查!')
queryBloodInfoByBloodNo({ bloodNo: bloodNo.value }).then(res => {
if (res.data.length == 1) {
const row = res.data[0]
checkBlood(row)
} else if (res.data.length > 1) {
maskRef.value.open(res.data)
}
}).finally(() => {
bloodNo.value = ''
})
}
}
const selectBlood = (row) => {
checkBlood(row)
}
// 血液校验
const checkBlood = (row) => {
checkBloodMatched({ bloodNo: row.blood_no, productNo: row.product_no, billNo: formData.value.bill_no }).then(res => {
if (res.code == 0) {
getBloodInfo(row)
}
if (res.code == 2) {
ElMessageBox.alert(`${res.msg}`, '提示', { type: 'warning' }).then(() => {
getBloodInfo(row)
})
}
})
}
const removeRow = (index) => {
ElMessageBox.confirm(`确定删除血液${matchTable.value[index].blood_no}数据吗?`, '提示', { type: 'warning' }).then(() => {
cancelBloodInfoMatch({ bloodNo: matchTable.value[index].blood_no, productNo: matchTable.value[index].product_no }).then(res => {
matchTable.value.splice(index, 1)
})
})
}
// 获取血液信息
const getBloodInfo = (row) => {
getBloodInfoMatch({ bloodNo: row.blood_no, productNo: row.product_no }).then(res => {
const row = res.data || {}
const msgArr: string[] = []
// ABO不匹配提示
if (row.blood_type != formData.value.abo_type) {
msgArr.push(`该血液流水号的血型与患者复核的血型结果不一致,请注意!`)
}
// Rh不匹配提示
if (row.rh_blood_type != formData.value.rh_type) {
msgArr.push(`患者Rh血型:Rh(D)阴性该血液的Rh血型与患者的Rh血型不符,请注意!`)
}
//血液品种不同
if (row.blood_breed != formData.value.blood_breed) {
msgArr.push(`该血液的血液品种与患者申请的血液品种不符,请注意!`)
}
// 存在任意不匹配统一弹窗
if (msgArr.length) {
ElMessageBox.alert(msgArr.join('<br/>'), '提示', { type: 'warning', dangerouslyUseHTMLString: true }).then(() => {
// 弹窗关闭后逻辑
setMatchTable(row)
})
} else {
setMatchTable(row)
}
})
}
const setMatchTable = (row) => {
matchTable.value.push({
...row,
second_match_medic: '',
offer_affirm_abo: row.blood_type,
check_offer_rh: row.rh_blood_type,
match_method: '006',
check_method: '002',
first_side: 'N',
second_side: 'N',
result: '001',
match_date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
match_medic: userInfo.name,
position_blood: '',
position_barcode: '',
})
matchTable.value.forEach((item, index) => {
item.sid = index + 1
})
bloodNo.value = ''
}
const selectRow = ref({})
const openJsHandle = () => {
visible.value = true
handleSearch()
}
const handleClose = () => {
visible.value = false
searchForm.value = {
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
}
selectRow.value = {}
}
const handleConfirm = () => {
if (!selectRow.value.bill_no) return ElMessage.warning('请选择配血单!')
getBloodMatchInfo()
visible.value = false
}
const jsRowclick = (row) => {
selectRow.value = row
}
const dblClickRow = (row) => {
selectRow.value = row
handleConfirm()
}
const handleRowClick = (row: any) => {
selectRow.value = row
getBloodMatchInfo()
}
const getBloodMatchInfo = () => {
queryMatchApplyInfo({ billNo: selectRow.value.bill_no, applyNo: selectRow.value.apply_no }).then(res => {
formData.value = res.data.matchMainInfoList[0] || {}
bloodApplyTable.value = res.data.xkTransfuseApplyBloodbreedList || []
matchTable.value = res.data.matchDetailInfoList || []
bloodInfo.value = res.data.matchDetailInfoList[0] || {}
})
}
const handleSearch = () => {
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'
queryMatchBloodList(searchForm.value).then(res => {
tableData.value = res.data || []
})
}
const saveBloodApply = () => {
if (!formData.value.bill_no) return ElMessage.warning('请选择输血申请单!')
if (matchTable.value.length == 0) return ElMessage.warning('请添加配血血液!')
const allValid = matchTable.value.every(item => item.second_match_medic?.trim())
if (!allValid) return ElMessage.warning('请填写复核者!')
saveLoading.value = true
const params = {
xkMatchMain: {
apply_no: formData.value.bill_no,
input_person: userInfo.name,
bill_status: 'A',
dept_id: formData.value.dept_id,
patient_name: formData.value.patient_name,
beinhos_id: formData.value.beinhos_id,
test_date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
input_date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
bill_no: bloodInfo.value.bill_no || '',
},
xkMatchDetailList: matchTable.value.map(item => ({
...item,
bill_no: bloodInfo.value.bill_no || '',
}))
}
saveLoading.value = true
saveBloodData(params).then(res => {
saveLoading.value = false
if (res.code == 0) {
handleRefresh()
ElMessage.success(res.msg)
}
}).catch(() => {
saveLoading.value = false
})
}
const addMatch = () => {
formData.value = {}
bloodApplyTable.value = []
matchTable.value = []
selectRow.value = {}
bloodInfo.value = {}
}
const cancelApply = () => {
if (!bloodInfo.value.bill_no) return ElMessage.warning('请选择交叉配血单!')
deleteBloodInfoMatch({ billNo: bloodInfo.value.bill_no }).then(res => {
handleRefresh()
ElMessage.success(res.msg)
})
}
const kcSearchForm = ref({
blood_no: '',
})
const kcOpen = () => {
searchBloodStock()
kcvisible.value = true
}
const searchBloodStock = () => {
queryBloodStockList({ affirmAbo: formData.value.affirm_abo, bloodNo: kcSearchForm.value.blood_no }).then(res => {
kcTableData.value = res.data || []
})
}
const cellStyle = ({ row, column, rowIndex, columnIndex }) => {
if (row.matched.trim() == 'Y') {
return {
color: '#ff00ff',
}
}
if (row.valid_date < dayjs().format('YYYY-MM-DD HH:mm:ss')) {
return {
color: '#f00',
}
}
if (row.match_delay.trim() == 'Y') {
return {
color: '#0a9292',
}
}
}
// 刷新右侧列表
const handleRefresh = () => {
filterForm.value.stime = dayjs(filterForm.value.stime).format('YYYY-MM-DD') + ' 00:00:00'
filterForm.value.etime = dayjs(filterForm.value.etime).format('YYYY-MM-DD') + ' 23:59:59'
queryMatchBloodList(filterForm.value).then(res => {
resultTable.value = res.data || []
})
}
const loadApplyData = () => {
queryWaitInfo().then(res => {
applyTableData.value = res.data || []
})
}
const searchApply = () => {
queryMatchOne({ billNo: formData.value.bill_no }).then(res => {
formData.value = res.data.matchMainInfoList[0] || {}
bloodApplyTable.value = res.data.xkTransfuseApplyBloodbreedList
if (formData.value.rh_type == '-') {
// 阴性弹出框提示
ElMessageBox.alert(`患者为Rh(D)阴性血型,请注意!`, '提示', { type: 'warning' })
}
})
}
onMounted(() => {
getDictData('ks', 'bq', 'sxmd', 'billApplyStatus', 'ktsx', 'abotype', 'subgroup', 'sxzz', 'rhtype', 'pxff', 'pxjg', 'zccc', 'test_result')
getBloodList()
getUserData()
handleRefresh()
})
</script>
<style scoped lang="scss">
.box-container {
overflow-y: auto;
display: flex;
flex-direction: column;
// 主体左右容器
.main-wrap {
flex: 1;
min-height: 0;
.timesplit {
width: 6%;
color: #999;
text-align: center;
}
.left-row {
height: 100%;
.left-col {
height: 100%;
}
.form_box {
height: 100%;
display: flex;
flex-direction: column;
}
.right-col {
height: 100%;
display: flex;
flex-direction: column;
}
.pxBox {
flex: 1;
min-height: 0;
display: flex;
flex-direction: column;
.table-box {
flex: 1;
min-height: 0;
}
}
}
}
// 通用卡片样式(对齐规范)
.card-box {
:deep(.el-form-item) {
margin-bottom: 8px;
}
.space-item {
margin-right: 10px;
}
}
}
.status {
color: #409eff;
font-size: 18px;
font-weight: 700;
text-align: center;
}
.f-title {
text-align: center;
font-size: 16px;
font-weight: 600;
margin-top: 10px;
}
.serch-box {
span {
margin-left: 20px;
font-weight: 600;
}
}
.blood-type-group {
display: flex;
// width: 100%;
.blood-type-tag {
width: 9.375rem;
border-radius: 4px;
color: #fff;
font-size: 30px;
font-weight: 600;
padding-left: 20px;
&.ab {
background: url('@/assets/images/blood_zero.png');
background-size: 100% 100%;
color: #3594c7;
.x_type {
color: #ff3b62;
}
}
&.rh {
background-color: #e8f7ff;
color: #3594c7;
}
.red {
color: #f00 !important;
}
}
}
</style>