952 lines
38 KiB
Vue
Raw Normal View History

2026-06-26 17:55:13 +08:00
/**
* @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>
2026-08-12 18:04:04 +08:00
<el-button type="primary" plain @click="addMatch">新增单据</el-button>
<el-button type="danger" plain @click="cancelApply">作废整单</el-button>
2026-08-14 17:57:50 +08:00
<el-button type="primary" plain @click="kcOpen">血液库存</el-button>
<el-button type="primary" plain :disabled="!formData.bill_no" @click="openResultDialog">检验结果</el-button>
2026-08-12 18:04:04 +08:00
<el-button type="success" plain :disabled="bloodInfo.bill_status && bloodInfo.bill_status != 'A'"
@click="saveBloodApply" :loading="saveLoading">保存</el-button>
2026-06-26 17:55:13 +08:00
<el-button type="warning" plain>打印</el-button>
</div>
<!-- 主体左右分栏容器 -->
<div class="main-wrap">
2026-08-12 18:04:04 +08:00
<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>
2026-06-26 17:55:13 +08:00
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="申请单号">
2026-08-12 18:04:04 +08:00
<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>
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="申请日期">
2026-08-12 18:04:04 +08:00
<el-input v-model="formData.apply_date" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="姓 名">
2026-08-12 18:04:04 +08:00
<el-input v-model="formData.patient_name" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="6">
2026-08-12 18:04:04 +08:00
<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>
2026-06-26 17:55:13 +08:00
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="性 别">
2026-08-12 18:04:04 +08:00
<el-input v-model="formData.patient_sex" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="年 龄">
2026-08-12 18:04:04 +08:00
<el-input v-model="formData.age" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="住院号/ID号">
2026-08-12 18:04:04 +08:00
<el-input v-model="formData.beinhos_id" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="6">
2026-08-12 18:04:04 +08:00
<el-form-item label="血型">
<el-input v-model="formData.abo_type" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="病 区">
2026-08-12 18:04:04 +08:00
<SelectTable v-model:data="formData.zone_id" :tableData="dictData.bq" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="科 室">
2026-08-12 18:04:04 +08:00
<SelectTable v-model:data="formData.dept_id" :tableData="dictData.ks" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="床位号">
2026-08-12 18:04:04 +08:00
<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 />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="临床诊断">
2026-08-12 18:04:04 +08:00
<el-input v-model="formData.diagnoses" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="输血目的">
2026-08-12 18:04:04 +08:00
<SelectTable v-model:data="formData.intent" :tableData="dictData.sxmd" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
2026-08-14 17:57:50 +08:00
<el-col :span="6">
2026-06-26 17:55:13 +08:00
<el-form-item label="ABO复核">
2026-08-12 18:04:04 +08:00
<el-input v-model="formData.affirm_abo" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
2026-08-14 17:57:50 +08:00
<el-col :span="6">
2026-06-26 17:55:13 +08:00
<el-form-item label="亚型">
2026-08-12 18:04:04 +08:00
<SelectTable v-model:data="formData.Sub_Blood" :tableData="dictData.subgroup" placeholder=""
disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
2026-08-14 17:57:50 +08:00
<el-col :span="6">
2026-06-26 17:55:13 +08:00
<el-form-item label="Rh(D)复核">
2026-08-12 18:04:04 +08:00
<el-input v-model="formData.check_rh" placeholder="" disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
2026-08-14 17:57:50 +08:00
<el-col :span="6">
2026-06-26 17:55:13 +08:00
<el-form-item label="抗体筛选">
2026-08-12 18:04:04 +08:00
<SelectTable v-model:data="formData.affirm_antibody" :tableData="dictData.ktsx" placeholder=""
disabled />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="15">
<el-form-item label=" ">
<div class="checkbox-group">
2026-08-12 18:04:04 +08:00
<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>
2026-06-26 17:55:13 +08:00
</div>
</el-form-item>
</el-col>
2026-08-12 18:04:04 +08:00
<el-col :span="9">
2026-06-26 17:55:13 +08:00
<el-form-item label="预定输血日期">
2026-08-12 18:04:04 +08:00
<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 />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
</el-row>
2026-08-27 09:37:45 +08:00
<el-table :data="bloodApplyTable" border height="120" show-overflow-tooltip>
2026-08-12 18:04:04 +08:00
<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>
2026-06-26 17:55:13 +08:00
2026-08-12 18:04:04 +08:00
<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">
2026-08-14 17:57:50 +08:00
<template #second_match_medic="{ row }">
2026-08-12 18:04:04 +08:00
<SelectTable v-model:data="row.second_match_medic" :tableData="userList" placeholder=""
2026-08-14 17:57:50 +08:00
:clearable="false" class="full-width-input"
:disabled="bloodInfo.bill_status && bloodInfo.bill_status != 'A'" />
2026-08-12 18:04:04 +08:00
</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 #second_match_method="{ row }">
<el-select v-model="row.second_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 #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=""
2026-08-14 17:57:50 +08:00
class="full-width-input" :clearable="false"
:disabled="bloodInfo.bill_status && bloodInfo.bill_status != 'A'" />
2026-08-12 18:04:04 +08:00
</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>
2026-06-26 17:55:13 +08:00
</div>
2026-08-12 18:04:04 +08:00
</el-form>
2026-06-26 17:55:13 +08:00
</el-col>
<!-- 右侧筛选+结果表格区域 -->
2026-08-12 18:04:04 +08:00
<el-col :span="9" class="right-col">
<div class="card-box pxBox" style="margin-bottom: 0px;">
2026-08-14 17:57:50 +08:00
<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>
2026-06-26 17:55:13 +08:00
</el-form>
2026-08-12 18:04:04 +08:00
<div class="table-box">
2026-08-27 09:37:45 +08:00
<el-table :data="resultTable" border height="100%" highlight-current-row show-overflow-tooltip
@row-click="handleRowClick">
2026-08-12 18:04:04 +08:00
<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" />
2026-06-26 17:55:13 +08:00
</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">
2026-09-04 09:18:22 +08:00
<el-col :span="9">
2026-06-26 17:55:13 +08:00
<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="配血单号">
2026-08-12 18:04:04 +08:00
<el-input v-model="searchForm.billNo" placeholder="" />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item label="科室">
2026-08-12 18:04:04 +08:00
<SelectTable v-model:data="searchForm.dept" :tableData="dictData.ks" placeholder="" />
2026-06-26 17:55:13 +08:00
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="10">
2026-09-04 09:18:22 +08:00
<el-col :span="9">
2026-06-26 17:55:13 +08:00
<el-form-item label="申请单号">
2026-08-12 18:04:04 +08:00
<el-input v-model="searchForm.applyNo" placeholder="" />
2026-06-26 17:55:13 +08:00
</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>
<!-- 结果表格区 -->
2026-09-04 09:18:22 +08:00
<el-table :data="tableData" border height="450" @row-click="jsRowclick" @row-dblclick="dblClickRow"
highlight-current-row show-overflow-tooltip>
2026-06-26 17:55:13 +08:00
<el-table-column prop="patient_name" label="患者姓名" align="center" />
2026-08-12 18:04:04 +08:00
<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>
2026-06-26 17:55:13 +08:00
<el-table-column prop="bill_no" label="配血单号" align="center" width="150" />
2026-08-12 18:04:04 +08:00
<el-table-column prop="apply_no" label="申请单号" align="center" width="150" />
<el-table-column prop="beinhos_id" label="住院号/ID号" align="center" width="150" />
2026-06-26 17:55:13 +08:00
<el-table-column prop="dept_id" label="科室" align="center">
<template #default="scope">
{{ formatDict(scope.row.dept_id, 'ks') }}
</template>
</el-table-column>
2026-08-12 18:04:04 +08:00
<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" />
2026-06-26 17:55:13 +08:00
</el-table>
</el-dialog>
2026-08-14 17:57:50 +08:00
<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>
2026-08-12 18:04:04 +08:00
<el-dialog title="血液库存预览" v-model="kcvisible" width="1200px" :close-on-click-modal="false" @closed="">
2026-08-14 17:57:50 +08:00
<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" />
2026-08-12 18:04:04 +08:00
</el-table>
2026-08-14 17:57:50 +08:00
<div class="f-title">
总计:{{ kcTableData.length }} 袋
</div>
2026-08-12 18:04:04 +08:00
</el-dialog>
2026-08-27 09:37:45 +08:00
<BloodMask ref="maskRef" :bloodBreed="bloodBreed" @selectRow="selectBlood" />
2026-06-26 17:55:13 +08:00
</div>
</template>
2026-08-27 09:37:45 +08:00
<script setup lang="ts" name="CrossMatching">
2026-06-26 17:55:13 +08:00
import DropdownTableSelect, { type TableColumnItem, type TableRowItem } from '@/components/DropdownTableSelect/index.vue'
import dayjs from 'dayjs'
2026-08-12 18:04:04 +08:00
import { getDictData, formatDict, dictData, useCommonDict } from '@/hooks'
2026-08-14 17:57:50 +08:00
import {
queryMatchBloodList, queryMatchOne, queryWaitInfo, getBloodInfoMatch, checkBloodMatched, saveBloodData, queryMatchApplyInfo, cancelBloodInfoMatch,
deleteBloodInfoMatch, queryBloodStockList, queryListResult
} from '@/api/blood'
2026-08-12 18:04:04 +08:00
import { queryBloodInfoByBloodNo } from '@/api/common'
import { ElMessageBox, ElMessage } from 'element-plus'
import useUserStore from '@/store/modules/user'
2026-08-27 09:37:45 +08:00
import BloodMask from '../component/bloodMask.vue'
2026-06-26 17:55:13 +08:00
2026-08-12 18:04:04 +08:00
const userInfo = useUserStore()
const { userList, getUserData, getServerTime, bloodBreed, getBloodList, } = useCommonDict()
2026-06-26 17:55:13 +08:00
2026-08-27 09:37:45 +08:00
const maskRef = useTemplateRef('maskRef')
2026-08-12 18:04:04 +08:00
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' },
])
2026-06-26 17:55:13 +08:00
const searchForm = ref({
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
})
const tableData = ref([])
const applyColumns = ref<TableColumnItem[]>([
2026-08-12 18:04:04 +08:00
{ 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' }
2026-06-26 17:55:13 +08:00
])
const applyTableData = ref<TableRowItem[]>([])
2026-08-14 17:57:50 +08:00
const bloddStatus = {
'1': '在库',
'4': '出库',
'2': '报废',
}
2026-06-26 17:55:13 +08:00
// 主表单数据
const formData = ref({})
// 右侧筛选表单
2026-08-12 18:04:04 +08:00
const filterForm = ref({
2026-06-26 17:55:13 +08:00
name: '',
status: '',
2026-08-12 18:04:04 +08:00
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
2026-06-26 17:55:13 +08:00
})
2026-08-14 17:57:50 +08:00
const bloodNo = ref('')
2026-06-26 17:55:13 +08:00
// 配血操作单选
2026-08-12 18:04:04 +08:00
const matchSelect = ref('add')
2026-06-26 17:55:13 +08:00
// 血液申请表格
const bloodApplyTable = ref([])
// 配血记录表格
const matchTable = ref([])
2026-08-12 18:04:04 +08:00
const matchColumns = ref([
{ label: '序号', type: 'index', width: 40, visible: true, align: 'center' },
2026-08-14 17:57:50 +08:00
{ label: '复核者', prop: 'second_match_medic', align: 'center', visible: true, width: 100, slot: 'second_match_medic', showOverflowTooltip: false },
2026-08-12 18:04:04 +08:00
{ 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: 'second_match_method', align: 'center', visible: true, width: 150, slot: 'second_match_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',
}
2026-06-26 17:55:13 +08:00
// 右侧结果列表
const resultTable = ref([])
2026-08-14 17:57:50 +08:00
// 检验结果弹窗数据
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
})
}
2026-08-12 18:04:04 +08:00
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]
2026-08-27 09:37:45 +08:00
checkBlood(row)
} else if (res.data.length > 1) {
maskRef.value.open(res.data)
2026-08-12 18:04:04 +08:00
}
})
}
}
2026-08-27 09:37:45 +08:00
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)
})
}
})
}
2026-08-12 18:04:04 +08:00
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',
second_match_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
})
2026-08-14 17:57:50 +08:00
bloodNo.value = ''
2026-08-12 18:04:04 +08:00
}
const selectRow = ref({})
2026-06-26 17:55:13 +08:00
const openJsHandle = () => {
visible.value = true
2026-08-12 18:04:04 +08:00
handleSearch()
2026-06-26 17:55:13 +08:00
}
const handleClose = () => {
visible.value = false
searchForm.value = {
stime: dayjs().format('YYYY-MM-DD'),
etime: dayjs().format('YYYY-MM-DD'),
}
2026-08-12 18:04:04 +08:00
selectRow.value = {}
2026-06-26 17:55:13 +08:00
}
const handleConfirm = () => {
2026-08-12 18:04:04 +08:00
if (!selectRow.value.bill_no) return ElMessage.warning('请选择配血单!')
getBloodMatchInfo()
visible.value = false
2026-06-26 17:55:13 +08:00
}
2026-08-12 18:04:04 +08:00
const jsRowclick = (row) => {
selectRow.value = row
}
2026-09-04 09:18:22 +08:00
const dblClickRow = (row) => {
selectRow.value = row
handleConfirm()
}
2026-06-26 17:55:13 +08:00
const handleRowClick = (row: any) => {
2026-08-12 18:04:04 +08:00
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)
})
2026-06-26 17:55:13 +08:00
}
2026-08-14 17:57:50 +08:00
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',
}
}
}
2026-06-26 17:55:13 +08:00
// 刷新右侧列表
const handleRefresh = () => {
2026-08-14 17:57:50 +08:00
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'
2026-08-12 18:04:04 +08:00
queryMatchBloodList(filterForm.value).then(res => {
resultTable.value = res.data || []
})
2026-06-26 17:55:13 +08:00
}
const loadApplyData = () => {
2026-08-12 18:04:04 +08:00
queryWaitInfo().then(res => {
applyTableData.value = res.data || []
})
2026-06-26 17:55:13 +08:00
}
2026-08-12 18:04:04 +08:00
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' })
}
})
2026-06-26 17:55:13 +08:00
}
2026-08-12 18:04:04 +08:00
2026-06-26 17:55:13 +08:00
onMounted(() => {
2026-08-14 17:57:50 +08:00
getDictData('ks', 'bq', 'sxmd', 'billApplyStatus', 'ktsx', 'abotype', 'subgroup', 'sxzz', 'rhtype', 'pxff', 'pxjg', 'zccc', 'test_result')
2026-08-12 18:04:04 +08:00
getBloodList()
getUserData()
handleRefresh()
2026-06-26 17:55:13 +08:00
})
</script>
<style scoped lang="scss">
.box-container {
overflow-y: auto;
2026-08-12 18:04:04 +08:00
display: flex;
flex-direction: column;
2026-06-26 17:55:13 +08:00
// 主体左右容器
.main-wrap {
2026-08-12 18:04:04 +08:00
flex: 1;
min-height: 0;
2026-06-26 17:55:13 +08:00
.timesplit {
2026-08-14 17:57:50 +08:00
width: 6%;
2026-06-26 17:55:13 +08:00
color: #999;
2026-08-14 17:57:50 +08:00
text-align: center;
2026-06-26 17:55:13 +08:00
}
2026-08-12 18:04:04 +08:00
.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;
}
}
}
2026-06-26 17:55:13 +08:00
}
// 通用卡片样式(对齐规范)
.card-box {
:deep(.el-form-item) {
margin-bottom: 8px;
}
.space-item {
margin-right: 10px;
}
}
}
2026-08-12 18:04:04 +08:00
.status {
color: #409eff;
font-size: 18px;
font-weight: 700;
text-align: center;
}
2026-08-14 17:57:50 +08:00
.f-title {
text-align: center;
font-size: 16px;
font-weight: 600;
margin-top: 10px;
}
.serch-box {
span {
margin-left: 20px;
font-weight: 600;
}
}
2026-06-26 17:55:13 +08:00
</style>