feat(blood-transfusion): 输血管理全流程
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package com.healthlink.his.web.bloodtransfusion.appservice;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionRecord;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionObservation;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import java.util.Map;
|
||||
public interface IBloodTransfusionAppService {
|
||||
void apply(BloodTransfusionRecord record);
|
||||
IPage<BloodTransfusionRecord> page(String patientName, String approvalStatus, String bloodComponent, Integer pageNum, Integer pageSize);
|
||||
void approve(Long id, String approvalStatus, String approverName, String remark);
|
||||
void observe(BloodTransfusionObservation observation);
|
||||
Map<String, Object> getRecordDetail(Long id);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
package com.healthlink.his.web.bloodtransfusion.appservice.impl;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionRecord;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionObservation;
|
||||
import com.healthlink.his.bloodtransfusion.service.IBloodTransfusionRecordService;
|
||||
import com.healthlink.his.bloodtransfusion.service.IBloodTransfusionObservationService;
|
||||
import com.healthlink.his.web.bloodtransfusion.appservice.IBloodTransfusionAppService;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import java.util.*;
|
||||
@Service
|
||||
public class BloodTransfusionAppServiceImpl implements IBloodTransfusionAppService {
|
||||
@Autowired
|
||||
private IBloodTransfusionRecordService recordService;
|
||||
@Autowired
|
||||
private IBloodTransfusionObservationService observationService;
|
||||
@Override
|
||||
public void apply(BloodTransfusionRecord record) {
|
||||
record.setStatus("SUBMITTED");
|
||||
record.setApprovalStatus("PENDING");
|
||||
record.setCreateTime(new Date());
|
||||
recordService.save(record);
|
||||
}
|
||||
@Override
|
||||
public IPage<BloodTransfusionRecord> page(String patientName, String approvalStatus, String bloodComponent, Integer pageNum, Integer pageSize) {
|
||||
LambdaQueryWrapper<BloodTransfusionRecord> w = new LambdaQueryWrapper<>();
|
||||
if (patientName != null && !patientName.isEmpty()) {
|
||||
w.like(BloodTransfusionRecord::getDoctorName, patientName);
|
||||
}
|
||||
if (approvalStatus != null && !approvalStatus.isEmpty()) {
|
||||
w.eq(BloodTransfusionRecord::getApprovalStatus, approvalStatus);
|
||||
}
|
||||
if (bloodComponent != null && !bloodComponent.isEmpty()) {
|
||||
w.eq(BloodTransfusionRecord::getBloodComponent, bloodComponent);
|
||||
}
|
||||
w.orderByDesc(BloodTransfusionRecord::getCreateTime);
|
||||
return recordService.page(new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNum, pageSize), w);
|
||||
}
|
||||
@Override
|
||||
public void approve(Long id, String approvalStatus, String approverName, String remark) {
|
||||
BloodTransfusionRecord record = recordService.getById(id);
|
||||
if (record == null) {
|
||||
throw new RuntimeException("输血记录不存在");
|
||||
}
|
||||
record.setApprovalStatus(approvalStatus);
|
||||
record.setApproverName(approverName);
|
||||
record.setApproveTime(new Date());
|
||||
if ("APPROVED".equals(approvalStatus)) {
|
||||
record.setStatus("APPROVED");
|
||||
} else if ("REJECTED".equals(approvalStatus)) {
|
||||
record.setStatus("REJECTED");
|
||||
}
|
||||
recordService.updateById(record);
|
||||
}
|
||||
@Override
|
||||
public void observe(BloodTransfusionObservation observation) {
|
||||
observation.setCreateTime(new Date());
|
||||
observationService.save(observation);
|
||||
}
|
||||
@Override
|
||||
public Map<String, Object> getRecordDetail(Long id) {
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
BloodTransfusionRecord record = recordService.getById(id);
|
||||
if (record == null) {
|
||||
result.put("error", "记录不存在");
|
||||
return result;
|
||||
}
|
||||
result.put("record", record);
|
||||
List<BloodTransfusionObservation> observations = observationService.list(
|
||||
new LambdaQueryWrapper<BloodTransfusionObservation>()
|
||||
.eq(BloodTransfusionObservation::getRecordId, id)
|
||||
.orderByAsc(BloodTransfusionObservation::getObservationTime)
|
||||
);
|
||||
result.put("observations", observations);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.healthlink.his.web.bloodtransfusion.controller;
|
||||
import com.core.common.core.domain.AjaxResult;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionRecord;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionObservation;
|
||||
import com.healthlink.his.web.bloodtransfusion.appservice.IBloodTransfusionAppService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@Tag(name = "输血管理") @RestController @RequestMapping("/api/v1/blood-transfusion")
|
||||
public class BloodTransfusionController {
|
||||
@Autowired
|
||||
private IBloodTransfusionAppService appService;
|
||||
@Operation(summary = "申请输血")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:edit')")
|
||||
@PostMapping("/apply")
|
||||
public AjaxResult apply(@RequestBody BloodTransfusionRecord record) {
|
||||
appService.apply(record);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "输血申请分页")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:list')")
|
||||
@GetMapping("/page")
|
||||
public AjaxResult page(@RequestParam(required = false) String patientName,
|
||||
@RequestParam(required = false) String approvalStatus,
|
||||
@RequestParam(required = false) String bloodComponent,
|
||||
@RequestParam(defaultValue = "1") Integer pageNum,
|
||||
@RequestParam(defaultValue = "10") Integer pageSize) {
|
||||
return AjaxResult.success(appService.page(patientName, approvalStatus, bloodComponent, pageNum, pageSize));
|
||||
}
|
||||
@Operation(summary = "审批输血")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:edit')")
|
||||
@PutMapping("/approve/{id}")
|
||||
public AjaxResult approve(@PathVariable Long id,
|
||||
@RequestParam String approvalStatus,
|
||||
@RequestParam(required = false) String approverName,
|
||||
@RequestParam(required = false) String remark) {
|
||||
appService.approve(id, approvalStatus, approverName, remark);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "输血观察记录")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:edit')")
|
||||
@PostMapping("/observe")
|
||||
public AjaxResult observe(@RequestBody BloodTransfusionObservation observation) {
|
||||
appService.observe(observation);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
@Operation(summary = "输血记录详情")
|
||||
@PreAuthorize("@ss.hasPermi('inpatient:bloodtransfusion:list')")
|
||||
@GetMapping("/record/{id}")
|
||||
public AjaxResult recordDetail(@PathVariable Long id) {
|
||||
return AjaxResult.success(appService.getRecordDetail(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
CREATE TABLE blood_transfusion_record (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
encounter_id BIGINT NOT NULL,
|
||||
patient_id BIGINT NOT NULL,
|
||||
advice_id BIGINT,
|
||||
blood_type VARCHAR(10),
|
||||
blood_component VARCHAR(50) NOT NULL,
|
||||
blood_volume DECIMAL(10,2),
|
||||
blood_unit VARCHAR(50),
|
||||
cross_match_result VARCHAR(20),
|
||||
indication TEXT,
|
||||
doctor_id BIGINT NOT NULL,
|
||||
doctor_name VARCHAR(50),
|
||||
approval_status VARCHAR(20) DEFAULT 'PENDING',
|
||||
approver_id BIGINT,
|
||||
approver_name VARCHAR(50),
|
||||
approve_time TIMESTAMP,
|
||||
transfusion_start_time TIMESTAMP,
|
||||
transfusion_end_time TIMESTAMP,
|
||||
transfusion_nurse_id BIGINT,
|
||||
transfusion_nurse_name VARCHAR(50),
|
||||
pre_vital_signs TEXT,
|
||||
during_vital_signs TEXT,
|
||||
post_vital_signs TEXT,
|
||||
adverse_reaction TEXT,
|
||||
adverse_reaction_type VARCHAR(50),
|
||||
status VARCHAR(20) DEFAULT 'DRAFT',
|
||||
del_flag CHAR(1) DEFAULT '0',
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
create_by VARCHAR(64),
|
||||
update_time TIMESTAMP,
|
||||
update_by VARCHAR(64)
|
||||
);
|
||||
|
||||
CREATE TABLE blood_transfusion_observation (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
record_id BIGINT NOT NULL,
|
||||
observation_time TIMESTAMP NOT NULL,
|
||||
observation_phase VARCHAR(20),
|
||||
temperature DECIMAL(4,1),
|
||||
pulse INTEGER,
|
||||
respiration INTEGER,
|
||||
blood_pressure_high INTEGER,
|
||||
blood_pressure_low INTEGER,
|
||||
symptoms TEXT,
|
||||
nurse_id BIGINT,
|
||||
nurse_name VARCHAR(50),
|
||||
del_flag CHAR(1) DEFAULT '0',
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
create_by VARCHAR(64)
|
||||
);
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.healthlink.his.bloodtransfusion.domain;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.core.common.core.domain.HisBaseEntity;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
@Data
|
||||
@TableName("blood_transfusion_observation")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class BloodTransfusionObservation extends HisBaseEntity {
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
private Long recordId;
|
||||
private Date observationTime;
|
||||
private String observationPhase;
|
||||
private BigDecimal temperature;
|
||||
private Integer pulse;
|
||||
private Integer respiration;
|
||||
private Integer bloodPressureHigh;
|
||||
private Integer bloodPressureLow;
|
||||
private String symptoms;
|
||||
private Long nurseId;
|
||||
private String nurseName;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.healthlink.his.bloodtransfusion.domain;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.core.common.core.domain.HisBaseEntity;
|
||||
import tools.jackson.databind.annotation.JsonSerialize;
|
||||
import tools.jackson.databind.ser.std.ToStringSerializer;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
@Data
|
||||
@TableName("blood_transfusion_record")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class BloodTransfusionRecord extends HisBaseEntity {
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
private Long encounterId;
|
||||
private Long patientId;
|
||||
private Long adviceId;
|
||||
private String bloodType;
|
||||
private String bloodComponent;
|
||||
private BigDecimal bloodVolume;
|
||||
private String bloodUnit;
|
||||
private String crossMatchResult;
|
||||
private String indication;
|
||||
private Long doctorId;
|
||||
private String doctorName;
|
||||
private String approvalStatus;
|
||||
private Long approverId;
|
||||
private String approverName;
|
||||
private Date approveTime;
|
||||
private Date transfusionStartTime;
|
||||
private Date transfusionEndTime;
|
||||
private Long transfusionNurseId;
|
||||
private String transfusionNurseName;
|
||||
private String preVitalSigns;
|
||||
private String duringVitalSigns;
|
||||
private String postVitalSigns;
|
||||
private String adverseReaction;
|
||||
private String adverseReactionType;
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.healthlink.his.bloodtransfusion.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionObservation;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@Mapper
|
||||
public interface BloodTransfusionObservationMapper extends BaseMapper<BloodTransfusionObservation> {
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.healthlink.his.bloodtransfusion.mapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionRecord;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
@Mapper
|
||||
public interface BloodTransfusionRecordMapper extends BaseMapper<BloodTransfusionRecord> {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.healthlink.his.bloodtransfusion.service;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionObservation;
|
||||
public interface IBloodTransfusionObservationService extends IService<BloodTransfusionObservation> {
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package com.healthlink.his.bloodtransfusion.service;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionRecord;
|
||||
public interface IBloodTransfusionRecordService extends IService<BloodTransfusionRecord> {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.bloodtransfusion.service.impl;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionObservation;
|
||||
import com.healthlink.his.bloodtransfusion.mapper.BloodTransfusionObservationMapper;
|
||||
import com.healthlink.his.bloodtransfusion.service.IBloodTransfusionObservationService;
|
||||
import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class BloodTransfusionObservationServiceImpl extends ServiceImpl<BloodTransfusionObservationMapper, BloodTransfusionObservation> implements IBloodTransfusionObservationService {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.healthlink.his.bloodtransfusion.service.impl;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.healthlink.his.bloodtransfusion.domain.BloodTransfusionRecord;
|
||||
import com.healthlink.his.bloodtransfusion.mapper.BloodTransfusionRecordMapper;
|
||||
import com.healthlink.his.bloodtransfusion.service.IBloodTransfusionRecordService;
|
||||
import org.springframework.stereotype.Service;
|
||||
@Service
|
||||
public class BloodTransfusionRecordServiceImpl extends ServiceImpl<BloodTransfusionRecordMapper, BloodTransfusionRecord> implements IBloodTransfusionRecordService {
|
||||
}
|
||||
40
healthlink-his-ui/src/api/bloodtransfusion/index.js
Normal file
40
healthlink-his-ui/src/api/bloodtransfusion/index.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function applyBloodTransfusion(data) {
|
||||
return request({
|
||||
url: '/api/v1/blood-transfusion/apply',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function getBloodTransfusionPage(params) {
|
||||
return request({
|
||||
url: '/api/v1/blood-transfusion/page',
|
||||
method: 'get',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function approveBloodTransfusion(id, params) {
|
||||
return request({
|
||||
url: '/api/v1/blood-transfusion/approve/' + id,
|
||||
method: 'put',
|
||||
params: params
|
||||
})
|
||||
}
|
||||
|
||||
export function addObservation(data) {
|
||||
return request({
|
||||
url: '/api/v1/blood-transfusion/observe',
|
||||
method: 'post',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
|
||||
export function getRecordDetail(id) {
|
||||
return request({
|
||||
url: '/api/v1/blood-transfusion/record/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
464
healthlink-his-ui/src/views/inpatientDoctor/BloodTransfusion.vue
Normal file
464
healthlink-his-ui/src/views/inpatientDoctor/BloodTransfusion.vue
Normal file
@@ -0,0 +1,464 @@
|
||||
<template>
|
||||
<div class="blood-transfusion-container">
|
||||
<el-card v-loading="loading">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>输血管理</span>
|
||||
<el-button type="primary" size="small" @click="handleApply">新建申请</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<el-form :inline="true" :model="queryParams" class="query-form">
|
||||
<el-form-item label="血液成分">
|
||||
<el-select v-model="queryParams.bloodComponent" clearable placeholder="请选择" style="width: 160px">
|
||||
<el-option label="全血" value="全血" />
|
||||
<el-option label="红细胞悬液" value="红细胞悬液" />
|
||||
<el-option label="血浆" value="血浆" />
|
||||
<el-option label="血小板" value="血小板" />
|
||||
<el-option label="冷沉淀" value="冷沉淀" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item label="审批状态">
|
||||
<el-select v-model="queryParams.approvalStatus" clearable placeholder="请选择" style="width: 140px">
|
||||
<el-option label="待审批" value="PENDING" />
|
||||
<el-option label="已通过" value="APPROVED" />
|
||||
<el-option label="已驳回" value="REJECTED" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||
<el-button @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="tableData" border style="width: 100%">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="bloodComponent" label="血液成分" width="140" />
|
||||
<el-table-column prop="bloodVolume" label="血量" width="100" align="center" />
|
||||
<el-table-column prop="bloodUnit" label="单位" width="80" align="center" />
|
||||
<el-table-column prop="doctorName" label="申请医生" width="120" />
|
||||
<el-table-column prop="indication" label="输血指征" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column prop="approvalStatus" label="审批状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.approvalStatus === 'PENDING'" type="warning">待审批</el-tag>
|
||||
<el-tag v-else-if="scope.row.approvalStatus === 'APPROVED'" type="success">已通过</el-tag>
|
||||
<el-tag v-else-if="scope.row.approvalStatus === 'REJECTED'" type="danger">已驳回</el-tag>
|
||||
<el-tag v-else type="info">{{ scope.row.approvalStatus }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="status" label="状态" width="100" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.status === 'SUBMITTED'" type="info">已提交</el-tag>
|
||||
<el-tag v-else-if="scope.row.status === 'APPROVED'" type="success">已审批</el-tag>
|
||||
<el-tag v-else-if="scope.row.status === 'REJECTED'" type="danger">已驳回</el-tag>
|
||||
<el-tag v-else type="info">{{ scope.row.status }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="createTime" label="申请时间" width="170" />
|
||||
<el-table-column label="操作" width="200" align="center" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button link type="primary" @click="handleDetail(scope.row)">详情</el-button>
|
||||
<el-button v-if="scope.row.approvalStatus === 'PENDING'" link type="success" @click="handleApprove(scope.row)">审批</el-button>
|
||||
<el-button v-if="scope.row.status === 'APPROVED'" link type="primary" @click="handleObserve(scope.row)">观察记录</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-pagination
|
||||
v-model:current-page="queryParams.pageNum"
|
||||
v-model:page-size="queryParams.pageSize"
|
||||
:page-sizes="[10, 20, 50]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="total"
|
||||
style="margin-top: 12px; justify-content: flex-end"
|
||||
@size-change="handleQuery"
|
||||
@current-change="handleQuery"
|
||||
/>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="applyDialogVisible" title="输血申请" width="700px" destroy-on-close :close-on-click-modal="false">
|
||||
<el-form ref="applyFormRef" :model="applyForm" :rules="applyRules" label-width="110px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="血液成分" prop="bloodComponent">
|
||||
<el-select v-model="applyForm.bloodComponent" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="全血" value="全血" />
|
||||
<el-option label="红细胞悬液" value="红细胞悬液" />
|
||||
<el-option label="血浆" value="血浆" />
|
||||
<el-option label="血小板" value="血小板" />
|
||||
<el-option label="冷沉淀" value="冷沉淀" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="血型" prop="bloodType">
|
||||
<el-select v-model="applyForm.bloodType" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="A型" value="A" />
|
||||
<el-option label="B型" value="B" />
|
||||
<el-option label="AB型" value="AB" />
|
||||
<el-option label="O型" value="O" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="血量" prop="bloodVolume">
|
||||
<el-input-number v-model="applyForm.bloodVolume" :min="0" :precision="2" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="单位" prop="bloodUnit">
|
||||
<el-select v-model="applyForm.bloodUnit" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="ml" value="ml" />
|
||||
<el-option label="U" value="U" />
|
||||
<el-option label="袋" value="袋" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="交叉配血" prop="crossMatchResult">
|
||||
<el-select v-model="applyForm.crossMatchResult" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="待检测" value="PENDING" />
|
||||
<el-option label="相合" value="COMPATIBLE" />
|
||||
<el-option label="不合" value="INCOMPATIBLE" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="申请医生" prop="doctorName">
|
||||
<el-input v-model="applyForm.doctorName" placeholder="请输入" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="输血指征" prop="indication">
|
||||
<el-input v-model="applyForm.indication" type="textarea" :rows="3" placeholder="请输入输血指征" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="applyDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitLoading" @click="submitApply">提交申请</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="approveDialogVisible" title="输血审批" width="500px" destroy-on-close :close-on-click-modal="false">
|
||||
<el-form ref="approveFormRef" :model="approveForm" label-width="90px">
|
||||
<el-form-item label="审批结果">
|
||||
<el-radio-group v-model="approveForm.approvalStatus">
|
||||
<el-radio value="APPROVED">通过</el-radio>
|
||||
<el-radio value="REJECTED">驳回</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<el-form-item label="审批人">
|
||||
<el-input v-model="approveForm.approverName" placeholder="请输入审批人" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="approveDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitLoading" @click="submitApprove">确认</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="observeDialogVisible" title="输血观察记录" width="700px" destroy-on-close :close-on-click-modal="false">
|
||||
<el-form ref="observeFormRef" :model="observeForm" :rules="observeRules" label-width="100px">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="观察时间" prop="observationTime">
|
||||
<el-date-picker v-model="observeForm.observationTime" type="datetime" placeholder="选择时间" value-format="YYYY-MM-DD HH:mm:ss" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="观察阶段" prop="observationPhase">
|
||||
<el-select v-model="observeForm.observationPhase" placeholder="请选择" style="width: 100%">
|
||||
<el-option label="输血前" value="PRE" />
|
||||
<el-option label="输血中" value="DURING" />
|
||||
<el-option label="输血后" value="POST" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="体温(℃)">
|
||||
<el-input-number v-model="observeForm.temperature" :min="35" :max="42" :step="0.1" :precision="1" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="脉搏(次/分)">
|
||||
<el-input-number v-model="observeForm.pulse" :min="40" :max="200" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="呼吸(次/分)">
|
||||
<el-input-number v-model="observeForm.respiration" :min="10" :max="50" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="收缩压(mmHg)">
|
||||
<el-input-number v-model="observeForm.bloodPressureHigh" :min="60" :max="250" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="舒张压(mmHg)">
|
||||
<el-input-number v-model="observeForm.bloodPressureLow" :min="30" :max="150" style="width: 100%" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="护士">
|
||||
<el-input v-model="observeForm.nurseName" placeholder="请输入护士姓名" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="24">
|
||||
<el-form-item label="症状描述">
|
||||
<el-input v-model="observeForm.symptoms" type="textarea" :rows="3" placeholder="请输入症状描述" />
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button @click="observeDialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" :loading="submitLoading" @click="submitObserve">保存</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog v-model="detailDialogVisible" title="输血记录详情" width="800px" destroy-on-close top="5vh" :close-on-click-modal="false">
|
||||
<div v-if="detailData.record" class="detail-content">
|
||||
<el-descriptions title="申请信息" :column="2" border size="small">
|
||||
<el-descriptions-item label="血液成分">{{ detailData.record.bloodComponent }}</el-descriptions-item>
|
||||
<el-descriptions-item label="血型">{{ detailData.record.bloodType }}</el-descriptions-item>
|
||||
<el-descriptions-item label="血量">{{ detailData.record.bloodVolume }} {{ detailData.record.bloodUnit }}</el-descriptions-item>
|
||||
<el-descriptions-item label="交叉配血">{{ detailData.record.crossMatchResult }}</el-descriptions-item>
|
||||
<el-descriptions-item label="申请医生">{{ detailData.record.doctorName }}</el-descriptions-item>
|
||||
<el-descriptions-item label="审批状态">
|
||||
<el-tag v-if="detailData.record.approvalStatus === 'PENDING'" type="warning">待审批</el-tag>
|
||||
<el-tag v-else-if="detailData.record.approvalStatus === 'APPROVED'" type="success">已通过</el-tag>
|
||||
<el-tag v-else-if="detailData.record.approvalStatus === 'REJECTED'" type="danger">已驳回</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="审批人">{{ detailData.record.approverName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="审批时间">{{ detailData.record.approveTime || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="输血指征" :span="2">{{ detailData.record.indication }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<el-descriptions v-if="detailData.record.transfusionStartTime" title="执行信息" :column="2" border size="small" style="margin-top: 16px">
|
||||
<el-descriptions-item label="开始时间">{{ detailData.record.transfusionStartTime }}</el-descriptions-item>
|
||||
<el-descriptions-item label="结束时间">{{ detailData.record.transfusionEndTime || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="输血护士">{{ detailData.record.transfusionNurseName || '-' }}</el-descriptions-item>
|
||||
<el-descriptions-item label="不良反应">{{ detailData.record.adverseReaction || '无' }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
<div v-if="detailData.observations && detailData.observations.length > 0" style="margin-top: 16px">
|
||||
<el-table :data="detailData.observations" border size="small">
|
||||
<el-table-column type="index" label="序号" width="60" align="center" />
|
||||
<el-table-column prop="observationTime" label="观察时间" width="170" />
|
||||
<el-table-column prop="observationPhase" label="阶段" width="80" align="center">
|
||||
<template #default="scope">
|
||||
<el-tag v-if="scope.row.observationPhase === 'PRE'" type="info">前</el-tag>
|
||||
<el-tag v-else-if="scope.row.observationPhase === 'DURING'" type="warning">中</el-tag>
|
||||
<el-tag v-else-if="scope.row.observationPhase === 'POST'" type="success">后</el-tag>
|
||||
<el-tag v-else>{{ scope.row.observationPhase }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="temperature" label="体温" width="80" align="center" />
|
||||
<el-table-column prop="pulse" label="脉搏" width="80" align="center" />
|
||||
<el-table-column prop="respiration" label="呼吸" width="80" align="center" />
|
||||
<el-table-column label="血压" width="110" align="center">
|
||||
<template #default="scope">{{ scope.row.bloodPressureHigh }}/{{ scope.row.bloodPressureLow }}</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="nurseName" label="护士" width="100" />
|
||||
<el-table-column prop="symptoms" label="症状" min-width="150" show-overflow-tooltip />
|
||||
</el-table>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<el-button @click="detailDialogVisible = false">关闭</el-button>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { applyBloodTransfusion, getBloodTransfusionPage, approveBloodTransfusion, addObservation, getRecordDetail } from '@/api/bloodtransfusion'
|
||||
|
||||
const loading = ref(false)
|
||||
const submitLoading = ref(false)
|
||||
const tableData = ref([])
|
||||
const total = ref(0)
|
||||
const queryParams = reactive({ pageNum: 1, pageSize: 10, bloodComponent: '', approvalStatus: '' })
|
||||
|
||||
const applyDialogVisible = ref(false)
|
||||
const approveDialogVisible = ref(false)
|
||||
const observeDialogVisible = ref(false)
|
||||
const detailDialogVisible = ref(false)
|
||||
|
||||
const applyFormRef = ref(null)
|
||||
const approveFormRef = ref(null)
|
||||
const observeFormRef = ref(null)
|
||||
|
||||
const applyForm = reactive({
|
||||
bloodComponent: '', bloodType: '', bloodVolume: null, bloodUnit: 'ml',
|
||||
crossMatchResult: 'PENDING', doctorName: '', indication: '',
|
||||
encounterId: null, patientId: null
|
||||
})
|
||||
const applyRules = {
|
||||
bloodComponent: [{ required: true, message: '请选择血液成分', trigger: 'change' }],
|
||||
bloodType: [{ required: true, message: '请选择血型', trigger: 'change' }],
|
||||
bloodVolume: [{ required: true, message: '请输入血量', trigger: 'blur' }],
|
||||
bloodUnit: [{ required: true, message: '请选择单位', trigger: 'change' }],
|
||||
doctorName: [{ required: true, message: '请输入申请医生', trigger: 'blur' }],
|
||||
indication: [{ required: true, message: '请输入输血指征', trigger: 'blur' }]
|
||||
}
|
||||
|
||||
const approveForm = reactive({ approvalStatus: 'APPROVED', approverName: '' })
|
||||
const observeForm = reactive({
|
||||
recordId: null, observationTime: '', observationPhase: '',
|
||||
temperature: null, pulse: null, respiration: null,
|
||||
bloodPressureHigh: null, bloodPressureLow: null, symptoms: '', nurseName: ''
|
||||
})
|
||||
const observeRules = {
|
||||
observationTime: [{ required: true, message: '请选择观察时间', trigger: 'change' }],
|
||||
observationPhase: [{ required: true, message: '请选择观察阶段', trigger: 'change' }]
|
||||
}
|
||||
|
||||
const detailData = ref({ record: null, observations: [] })
|
||||
let currentRecordId = null
|
||||
|
||||
function handleQuery() {
|
||||
loading.value = true
|
||||
getBloodTransfusionPage(queryParams).then(res => {
|
||||
tableData.value = res.data?.records || []
|
||||
total.value = res.data?.total || 0
|
||||
}).catch(() => {
|
||||
ElMessage.error('查询失败')
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function resetQuery() {
|
||||
queryParams.bloodComponent = ''
|
||||
queryParams.approvalStatus = ''
|
||||
queryParams.pageNum = 1
|
||||
handleQuery()
|
||||
}
|
||||
|
||||
function handleApply() {
|
||||
applyForm.bloodComponent = ''
|
||||
applyForm.bloodType = ''
|
||||
applyForm.bloodVolume = null
|
||||
applyForm.bloodUnit = 'ml'
|
||||
applyForm.crossMatchResult = 'PENDING'
|
||||
applyForm.doctorName = ''
|
||||
applyForm.indication = ''
|
||||
applyDialogVisible.value = true
|
||||
}
|
||||
|
||||
function submitApply() {
|
||||
applyFormRef.value?.validate(valid => {
|
||||
if (!valid) return
|
||||
submitLoading.value = true
|
||||
applyBloodTransfusion({ ...applyForm }).then(res => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('申请提交成功')
|
||||
applyDialogVisible.value = false
|
||||
handleQuery()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '提交失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
ElMessage.error('提交失败')
|
||||
}).finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function handleApprove(row) {
|
||||
currentRecordId = row.id
|
||||
approveForm.approvalStatus = 'APPROVED'
|
||||
approveForm.approverName = ''
|
||||
approveDialogVisible.value = true
|
||||
}
|
||||
|
||||
function submitApprove() {
|
||||
submitLoading.value = true
|
||||
approveBloodTransfusion(currentRecordId, {
|
||||
approvalStatus: approveForm.approvalStatus,
|
||||
approverName: approveForm.approverName
|
||||
}).then(res => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('审批完成')
|
||||
approveDialogVisible.value = false
|
||||
handleQuery()
|
||||
} else {
|
||||
ElMessage.error(res.msg || '审批失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
ElMessage.error('审批失败')
|
||||
}).finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function handleObserve(row) {
|
||||
currentRecordId = row.id
|
||||
observeForm.recordId = row.id
|
||||
observeForm.observationTime = ''
|
||||
observeForm.observationPhase = ''
|
||||
observeForm.temperature = null
|
||||
observeForm.pulse = null
|
||||
observeForm.respiration = null
|
||||
observeForm.bloodPressureHigh = null
|
||||
observeForm.bloodPressureLow = null
|
||||
observeForm.symptoms = ''
|
||||
observeForm.nurseName = ''
|
||||
observeDialogVisible.value = true
|
||||
}
|
||||
|
||||
function submitObserve() {
|
||||
observeFormRef.value?.validate(valid => {
|
||||
if (!valid) return
|
||||
submitLoading.value = true
|
||||
addObservation({ ...observeForm }).then(res => {
|
||||
if (res.code === 200) {
|
||||
ElMessage.success('观察记录已保存')
|
||||
observeDialogVisible.value = false
|
||||
} else {
|
||||
ElMessage.error(res.msg || '保存失败')
|
||||
}
|
||||
}).catch(() => {
|
||||
ElMessage.error('保存失败')
|
||||
}).finally(() => {
|
||||
submitLoading.value = false
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function handleDetail(row) {
|
||||
loading.value = true
|
||||
getRecordDetail(row.id).then(res => {
|
||||
detailData.value = res.data || { record: null, observations: [] }
|
||||
detailDialogVisible.value = true
|
||||
}).catch(() => {
|
||||
ElMessage.error('查询详情失败')
|
||||
}).finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
handleQuery()
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.blood-transfusion-container {
|
||||
padding: 12px;
|
||||
}
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.query-form {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.detail-content {
|
||||
max-height: 70vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user