feat(P1): 麻醉/检验/检查系统补全

V19 Flyway迁移 — 7张新表:
- anesthesia_specimen: 麻醉标本管理(采集/送检/病理报告)
- anesthesia_postop_followup: 术后随访(24H/48H/72H)
- anesthesia_quality_control: 麻醉质控(出血量/并发症/ASA分级)
- lab_internal_qc: 检验室内质控(靶值/实测值/CV%/Westgard规则)
- lab_external_eqa: 检验室间质评(偏差率/合格判定)
- radiology_urgent_report: 检查紧急报告(紧急原因/通知状态)
- radiology_statistics: 检查统计日报(总量/阳性率/出报告时间)

后端Controller:
- AnesthesiaEnhancedController: 标本管理+术后随访+麻醉质控
- LabEnhancedController: 室内质控+室间质评+统计
- RadiologyEnhancedController: 紧急报告+检查统计

前端页面:
- anesthesiaenhanced: Tab页(标本管理/术后随访/麻醉质控)
- labenhanced: Tab页(室内质控/室间质评)
- radiologyenhanced: Tab页(紧急报告/检查统计)

所有模块编译通过 (mvn clean compile -DskipTests)
This commit is contained in:
2026-06-06 16:59:18 +08:00
parent be448fe092
commit fcdfb0cb19
38 changed files with 1075 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
package com.healthlink.his.web.anesthesia.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.healthlink.his.anesthesia.domain.*;
import com.healthlink.his.anesthesia.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@RestController
@RequestMapping("/anesthesia-enhanced")
@Slf4j
@AllArgsConstructor
public class AnesthesiaEnhancedController {
private final IAnesthesiaSpecimenService specimenService;
private final IAnesthesiaPostopFollowupService followupService;
private final IAnesthesiaQualityControlService qcService;
// ==================== 标本管理 ====================
@GetMapping("/specimen/page")
public R<?> getSpecimenPage(
@RequestParam(value = "patientName", required = false) String patientName,
@RequestParam(value = "pathologyStatus", required = false) String status,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
LambdaQueryWrapper<AnesthesiaSpecimen> w = new LambdaQueryWrapper<>();
w.like(StringUtils.hasText(patientName), AnesthesiaSpecimen::getPatientName, patientName)
.eq(StringUtils.hasText(status), AnesthesiaSpecimen::getPathologyStatus, status)
.orderByDesc(AnesthesiaSpecimen::getCreateTime);
return R.ok(specimenService.page(new Page<>(pageNo, pageSize), w));
}
@PostMapping("/specimen/add")
@Transactional(rollbackFor = Exception.class)
public R<?> addSpecimen(@RequestBody AnesthesiaSpecimen s) {
s.setPathologyStatus("PENDING");
s.setCreateTime(new Date());
specimenService.save(s);
return R.ok(s);
}
@PostMapping("/specimen/report")
@Transactional(rollbackFor = Exception.class)
public R<?> reportSpecimen(@RequestBody Map<String, Object> params) {
Long id = Long.valueOf(params.get("id").toString());
AnesthesiaSpecimen s = specimenService.getById(id);
if (s == null) return R.fail("标本不存在");
s.setPathologyStatus("REPORTED");
s.setPathologyResult((String) params.get("pathologyResult"));
s.setReportTime(new Date());
s.setUpdateTime(new Date());
specimenService.updateById(s);
return R.ok();
}
// ==================== 术后随访 ====================
@GetMapping("/followup/page")
public R<?> getFollowupPage(
@RequestParam(value = "followupType", required = false) String type,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
LambdaQueryWrapper<AnesthesiaPostopFollowup> w = new LambdaQueryWrapper<>();
w.eq(StringUtils.hasText(type), AnesthesiaPostopFollowup::getFollowupType, type)
.orderByDesc(AnesthesiaPostopFollowup::getFollowupTime);
return R.ok(followupService.page(new Page<>(pageNo, pageSize), w));
}
@PostMapping("/followup/add")
@Transactional(rollbackFor = Exception.class)
public R<?> addFollowup(@RequestBody AnesthesiaPostopFollowup f) {
f.setStatus(0);
f.setCreateTime(new Date());
followupService.save(f);
return R.ok(f);
}
// ==================== 麻醉质控 ====================
@GetMapping("/qc/page")
public R<?> getQcPage(
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
LambdaQueryWrapper<AnesthesiaQualityControl> w = new LambdaQueryWrapper<>();
w.orderByDesc(AnesthesiaQualityControl::getCreateTime);
return R.ok(qcService.page(new Page<>(pageNo, pageSize), w));
}
@PostMapping("/qc/add")
@Transactional(rollbackFor = Exception.class)
public R<?> addQc(@RequestBody AnesthesiaQualityControl qc) {
qc.setStatus(0);
qc.setCreateTime(new Date());
qcService.save(qc);
return R.ok(qc);
}
@GetMapping("/qc/stats")
public R<?> getQcStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("total", qcService.count());
LambdaQueryWrapper<AnesthesiaQualityControl> w = new LambdaQueryWrapper<>();
w.isNotNull(AnesthesiaQualityControl::getComplications);
w.ne(AnesthesiaQualityControl::getComplications, "");
stats.put("withComplications", qcService.count(w));
return R.ok(stats);
}
}

View File

@@ -0,0 +1,85 @@
package com.healthlink.his.web.check.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.healthlink.his.check.domain.*;
import com.healthlink.his.check.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@RestController
@RequestMapping("/radiology-enhanced")
@Slf4j
@AllArgsConstructor
public class RadiologyEnhancedController {
private final IRadiologyUrgentReportService urgentReportService;
private final IRadiologyStatisticsService statisticsService;
// ==================== 紧急报告 ====================
@GetMapping("/urgent-report/page")
public R<?> getUrgentReportPage(
@RequestParam(value = "patientName", required = false) String patientName,
@RequestParam(value = "notifyStatus", required = false) Integer status,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
LambdaQueryWrapper<RadiologyUrgentReport> w = new LambdaQueryWrapper<>();
w.like(StringUtils.hasText(patientName), RadiologyUrgentReport::getPatientName, patientName)
.eq(status != null, RadiologyUrgentReport::getNotifyStatus, status)
.orderByDesc(RadiologyUrgentReport::getReportTime);
return R.ok(urgentReportService.page(new Page<>(pageNo, pageSize), w));
}
@PostMapping("/urgent-report/add")
@Transactional(rollbackFor = Exception.class)
public R<?> addUrgentReport(@RequestBody RadiologyUrgentReport r) {
r.setNotifyStatus(0);
r.setReportTime(new Date());
r.setCreateTime(new Date());
urgentReportService.save(r);
return R.ok(r);
}
@PostMapping("/urgent-report/notify")
@Transactional(rollbackFor = Exception.class)
public R<?> notifyReport(@RequestParam Long id) {
RadiologyUrgentReport r = urgentReportService.getById(id);
if (r == null) return R.fail("报告不存在");
r.setNotifyStatus(1);
r.setNotifyTime(new Date());
r.setUpdateTime(new Date());
urgentReportService.updateById(r);
return R.ok();
}
// ==================== 检查统计 ====================
@GetMapping("/statistics/page")
public R<?> getStatisticsPage(
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
LambdaQueryWrapper<RadiologyStatistics> w = new LambdaQueryWrapper<>();
w.orderByDesc(RadiologyStatistics::getStatDate);
return R.ok(statisticsService.page(new Page<>(pageNo, pageSize), w));
}
@PostMapping("/statistics/add")
@Transactional(rollbackFor = Exception.class)
public R<?> addStatistics(@RequestBody RadiologyStatistics s) {
s.setCreateTime(new Date());
statisticsService.save(s);
return R.ok(s);
}
@GetMapping("/statistics/summary")
public R<?> getStatisticsSummary() {
Map<String, Object> summary = new HashMap<>();
summary.put("totalRecords", statisticsService.count());
return R.ok(summary);
}
}

View File

@@ -0,0 +1,78 @@
package com.healthlink.his.web.lab.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.core.common.core.domain.R;
import com.healthlink.his.lab.domain.*;
import com.healthlink.his.lab.service.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import java.util.*;
@RestController
@RequestMapping("/lab-enhanced")
@Slf4j
@AllArgsConstructor
public class LabEnhancedController {
private final ILabInternalQcService internalQcService;
private final ILabExternalEqaService externalEqaService;
// ==================== 室内质控 ====================
@GetMapping("/internal-qc/page")
public R<?> getInternalQcPage(
@RequestParam(value = "qcItem", required = false) String qcItem,
@RequestParam(value = "isPass", required = false) Boolean isPass,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
LambdaQueryWrapper<LabInternalQc> w = new LambdaQueryWrapper<>();
w.like(StringUtils.hasText(qcItem), LabInternalQc::getQcItem, qcItem)
.eq(isPass != null, LabInternalQc::getIsPass, isPass)
.orderByDesc(LabInternalQc::getQcDate);
return R.ok(internalQcService.page(new Page<>(pageNo, pageSize), w));
}
@PostMapping("/internal-qc/add")
@Transactional(rollbackFor = Exception.class)
public R<?> addInternalQc(@RequestBody LabInternalQc qc) {
qc.setCreateTime(new Date());
internalQcService.save(qc);
return R.ok(qc);
}
@GetMapping("/internal-qc/stats")
public R<?> getQcStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("total", internalQcService.count());
LambdaQueryWrapper<LabInternalQc> w = new LambdaQueryWrapper<>();
w.eq(LabInternalQc::getIsPass, true);
stats.put("passed", internalQcService.count(w));
w.eq(LabInternalQc::getIsPass, false);
stats.put("failed", internalQcService.count(w));
return R.ok(stats);
}
// ==================== 室间质评 ====================
@GetMapping("/external-eqa/page")
public R<?> getExternalEqaPage(
@RequestParam(value = "assessmentName", required = false) String name,
@RequestParam(value = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(value = "pageSize", defaultValue = "20") Integer pageSize) {
LambdaQueryWrapper<LabExternalEqa> w = new LambdaQueryWrapper<>();
w.like(StringUtils.hasText(name), LabExternalEqa::getAssessmentName, name)
.orderByDesc(LabExternalEqa::getCreateTime);
return R.ok(externalEqaService.page(new Page<>(pageNo, pageSize), w));
}
@PostMapping("/external-eqa/add")
@Transactional(rollbackFor = Exception.class)
public R<?> addExternalEqa(@RequestBody LabExternalEqa eqa) {
eqa.setCreateTime(new Date());
externalEqaService.save(eqa);
return R.ok(eqa);
}
}

View File

@@ -0,0 +1,169 @@
-- V19: P1模块补全 — 麻醉+检验+检查
-- 1. 麻醉标本管理
CREATE TABLE IF NOT EXISTS anesthesia_specimen (
id BIGSERIAL PRIMARY KEY,
encounter_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
patient_name VARCHAR(50),
surgery_id BIGINT,
specimen_type VARCHAR(50) NOT NULL,
specimen_name VARCHAR(200),
collection_time TIMESTAMP,
collector_name VARCHAR(50),
destination VARCHAR(100),
pathology_status VARCHAR(20) DEFAULT 'PENDING',
pathology_result TEXT,
report_time TIMESTAMP,
tenant_id BIGINT DEFAULT 0,
is_deleted INT NOT NULL DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE anesthesia_specimen IS '麻醉标本管理';
COMMENT ON COLUMN anesthesia_specimen.pathology_status IS '病理状态(PENDING送检中/REPORTED已出报告)';
CREATE INDEX idx_spec_encounter ON anesthesia_specimen(encounter_id);
-- 2. 术后随访
CREATE TABLE IF NOT EXISTS anesthesia_postop_followup (
id BIGSERIAL PRIMARY KEY,
encounter_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
patient_name VARCHAR(50),
surgery_id BIGINT,
followup_type VARCHAR(20) NOT NULL,
followup_time TIMESTAMP NOT NULL,
pain_score INT,
nausea_vomiting BOOLEAN DEFAULT FALSE,
consciousness_status VARCHAR(50),
vital_signs TEXT,
complications TEXT,
treatment TEXT,
followup_doctor_id BIGINT,
followup_doctor_name VARCHAR(50),
status INT NOT NULL DEFAULT 0,
tenant_id BIGINT DEFAULT 0,
is_deleted INT NOT NULL DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE anesthesia_postop_followup IS '术后随访记录';
COMMENT ON COLUMN anesthesia_postop_followup.followup_type IS '随访类型(24H/48H/72H)';
CREATE INDEX idx_fu_encounter ON anesthesia_postop_followup(encounter_id);
-- 3. 麻醉质控
CREATE TABLE IF NOT EXISTS anesthesia_quality_control (
id BIGSERIAL PRIMARY KEY,
encounter_id BIGINT NOT NULL,
patient_name VARCHAR(50),
anesthesia_type VARCHAR(50),
anesthesia_start TIMESTAMP,
anesthesia_end TIMESTAMP,
total_duration_min INT,
blood_loss_ml INT DEFAULT 0,
fluid_input_ml INT DEFAULT 0,
urine_output_ml INT DEFAULT 0,
complications TEXT,
adverse_event TEXT,
asa_grade INT,
risk_level VARCHAR(20),
status INT NOT NULL DEFAULT 0,
tenant_id BIGINT DEFAULT 0,
is_deleted INT NOT NULL DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
update_by VARCHAR(64),
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE anesthesia_quality_control IS '麻醉质控记录';
CREATE INDEX idx_aqc_encounter ON anesthesia_quality_control(encounter_id);
-- 4. 检验室内质控
CREATE TABLE IF NOT EXISTS lab_internal_qc (
id BIGSERIAL PRIMARY KEY,
department_id BIGINT NOT NULL,
department_name VARCHAR(100),
instrument_name VARCHAR(100),
qc_item VARCHAR(100) NOT NULL,
qc_date DATE NOT NULL,
target_value DECIMAL(10,4),
actual_value DECIMAL(10,4),
sd_value DECIMAL(10,4),
cv_rate DECIMAL(5,2),
westgard_rule VARCHAR(20),
is_pass BOOLEAN NOT NULL DEFAULT TRUE,
operator_name VARCHAR(50),
remarks TEXT,
tenant_id BIGINT DEFAULT 0,
is_deleted INT NOT NULL DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE lab_internal_qc IS '检验室内质控';
COMMENT ON COLUMN lab_internal_qc.westgard_rule IS 'Westgard规则(1-2s/1-3s/2-2s/R-4s/4-1s/10x)';
-- 5. 检验室间质评
CREATE TABLE IF NOT EXISTS lab_external_eqa (
id BIGSERIAL PRIMARY KEY,
assessment_name VARCHAR(200) NOT NULL,
assessment_org VARCHAR(200),
assessment_year INT,
assessment_quarter INT,
sample_code VARCHAR(100),
test_item VARCHAR(100),
target_value VARCHAR(100),
actual_value VARCHAR(100),
deviation_rate DECIMAL(5,2),
result VARCHAR(20),
operator_name VARCHAR(50),
tenant_id BIGINT DEFAULT 0,
is_deleted INT NOT NULL DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE lab_external_eqa IS '检验室间质评';
-- 6. 检查紧急报告
CREATE TABLE IF NOT EXISTS radiology_urgent_report (
id BIGSERIAL PRIMARY KEY,
encounter_id BIGINT NOT NULL,
patient_id BIGINT NOT NULL,
patient_name VARCHAR(50),
examination_type VARCHAR(50),
examination_name VARCHAR(200),
urgency_reason TEXT NOT NULL,
report_content TEXT NOT NULL,
reporter_id BIGINT,
reporter_name VARCHAR(50),
report_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
notify_status INT NOT NULL DEFAULT 0,
notify_time TIMESTAMP,
tenant_id BIGINT DEFAULT 0,
is_deleted INT NOT NULL DEFAULT 0,
create_by VARCHAR(64),
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE radiology_urgent_report IS '检查紧急报告';
COMMENT ON COLUMN radiology_urgent_report.notify_status IS '通知状态(0待通知 1已通知 2通知失败)';
CREATE INDEX idx_ur_encounter ON radiology_urgent_report(encounter_id);
-- 7. 检查统计
CREATE TABLE IF NOT EXISTS radiology_statistics (
id BIGSERIAL PRIMARY KEY,
stat_date DATE NOT NULL,
department_id BIGINT,
department_name VARCHAR(100),
examination_type VARCHAR(50),
total_count INT DEFAULT 0,
positive_count INT DEFAULT 0,
urgent_count INT DEFAULT 0,
avg_report_hours DECIMAL(5,2) DEFAULT 0,
tenant_id BIGINT DEFAULT 0,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE radiology_statistics IS '检查统计日报';
CREATE INDEX idx_rs_date ON radiology_statistics(stat_date);

View File

@@ -0,0 +1,31 @@
package com.healthlink.his.anesthesia.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.core.common.core.domain.HisBaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("anesthesia_postop_followup")
public class AnesthesiaPostopFollowup extends HisBaseEntity {
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
@TableField("encounter_id") private Long encounterId;
@TableField("patient_id") private Long patientId;
@TableField("patient_name") private String patientName;
@TableField("surgery_id") private Long surgeryId;
@TableField("followup_type") private String followupType;
@TableField("followup_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date followupTime;
@TableField("pain_score") private Integer painScore;
@TableField("nausea_vomiting") private Boolean nauseaVomiting;
@TableField("consciousness_status") private String consciousnessStatus;
@TableField("vital_signs") private String vitalSigns;
@TableField("complications") private String complications;
@TableField("treatment") private String treatment;
@TableField("followup_doctor_id") private Long followupDoctorId;
@TableField("followup_doctor_name") private String followupDoctorName;
@TableField("status") private Integer status;
}

View File

@@ -0,0 +1,30 @@
package com.healthlink.his.anesthesia.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.core.common.core.domain.HisBaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("anesthesia_quality_control")
public class AnesthesiaQualityControl extends HisBaseEntity {
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
@TableField("encounter_id") private Long encounterId;
@TableField("patient_name") private String patientName;
@TableField("anesthesia_type") private String anesthesiaType;
@TableField("anesthesia_start") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date anesthesiaStart;
@TableField("anesthesia_end") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date anesthesiaEnd;
@TableField("total_duration_min") private Integer totalDurationMin;
@TableField("blood_loss_ml") private Integer bloodLossMl;
@TableField("fluid_input_ml") private Integer fluidInputMl;
@TableField("urine_output_ml") private Integer urineOutputMl;
@TableField("complications") private String complications;
@TableField("adverse_event") private String adverseEvent;
@TableField("asa_grade") private Integer asaGrade;
@TableField("risk_level") private String riskLevel;
@TableField("status") private Integer status;
}

View File

@@ -0,0 +1,28 @@
package com.healthlink.his.anesthesia.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.core.common.core.domain.HisBaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("anesthesia_specimen")
public class AnesthesiaSpecimen extends HisBaseEntity {
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
@TableField("encounter_id") private Long encounterId;
@TableField("patient_id") private Long patientId;
@TableField("patient_name") private String patientName;
@TableField("surgery_id") private Long surgeryId;
@TableField("specimen_type") private String specimenType;
@TableField("specimen_name") private String specimenName;
@TableField("collection_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date collectionTime;
@TableField("collector_name") private String collectorName;
@TableField("destination") private String destination;
@TableField("pathology_status") private String pathologyStatus;
@TableField("pathology_result") private String pathologyResult;
@TableField("report_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date reportTime;
}

View File

@@ -0,0 +1,9 @@
package com.healthlink.his.anesthesia.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.healthlink.his.anesthesia.domain.AnesthesiaPostopFollowup;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AnesthesiaPostopFollowupMapper extends BaseMapper<AnesthesiaPostopFollowup> {
}

View File

@@ -0,0 +1,9 @@
package com.healthlink.his.anesthesia.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.healthlink.his.anesthesia.domain.AnesthesiaQualityControl;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AnesthesiaQualityControlMapper extends BaseMapper<AnesthesiaQualityControl> {
}

View File

@@ -0,0 +1,9 @@
package com.healthlink.his.anesthesia.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.healthlink.his.anesthesia.domain.AnesthesiaSpecimen;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface AnesthesiaSpecimenMapper extends BaseMapper<AnesthesiaSpecimen> {
}

View File

@@ -0,0 +1,7 @@
package com.healthlink.his.anesthesia.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.healthlink.his.anesthesia.domain.AnesthesiaPostopFollowup;
public interface IAnesthesiaPostopFollowupService extends IService<AnesthesiaPostopFollowup> {
}

View File

@@ -0,0 +1,7 @@
package com.healthlink.his.anesthesia.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.healthlink.his.anesthesia.domain.AnesthesiaQualityControl;
public interface IAnesthesiaQualityControlService extends IService<AnesthesiaQualityControl> {
}

View File

@@ -0,0 +1,7 @@
package com.healthlink.his.anesthesia.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.healthlink.his.anesthesia.domain.AnesthesiaSpecimen;
public interface IAnesthesiaSpecimenService extends IService<AnesthesiaSpecimen> {
}

View File

@@ -0,0 +1,11 @@
package com.healthlink.his.anesthesia.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.healthlink.his.anesthesia.domain.AnesthesiaPostopFollowup;
import com.healthlink.his.anesthesia.mapper.AnesthesiaPostopFollowupMapper;
import com.healthlink.his.anesthesia.service.IAnesthesiaPostopFollowupService;
import org.springframework.stereotype.Service;
@Service
public class AnesthesiaPostopFollowupServiceImpl extends ServiceImpl<AnesthesiaPostopFollowupMapper, AnesthesiaPostopFollowup> implements IAnesthesiaPostopFollowupService {
}

View File

@@ -0,0 +1,11 @@
package com.healthlink.his.anesthesia.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.healthlink.his.anesthesia.domain.AnesthesiaQualityControl;
import com.healthlink.his.anesthesia.mapper.AnesthesiaQualityControlMapper;
import com.healthlink.his.anesthesia.service.IAnesthesiaQualityControlService;
import org.springframework.stereotype.Service;
@Service
public class AnesthesiaQualityControlServiceImpl extends ServiceImpl<AnesthesiaQualityControlMapper, AnesthesiaQualityControl> implements IAnesthesiaQualityControlService {
}

View File

@@ -0,0 +1,11 @@
package com.healthlink.his.anesthesia.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.healthlink.his.anesthesia.domain.AnesthesiaSpecimen;
import com.healthlink.his.anesthesia.mapper.AnesthesiaSpecimenMapper;
import com.healthlink.his.anesthesia.service.IAnesthesiaSpecimenService;
import org.springframework.stereotype.Service;
@Service
public class AnesthesiaSpecimenServiceImpl extends ServiceImpl<AnesthesiaSpecimenMapper, AnesthesiaSpecimen> implements IAnesthesiaSpecimenService {
}

View File

@@ -0,0 +1,23 @@
package com.healthlink.his.check.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.core.common.core.domain.HisBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("radiology_statistics")
public class RadiologyStatistics extends HisBaseEntity {
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
@TableField("stat_date") private String statDate;
@TableField("department_id") private Long departmentId;
@TableField("department_name") private String departmentName;
@TableField("examination_type") private String examinationType;
@TableField("total_count") private Integer totalCount;
@TableField("positive_count") private Integer positiveCount;
@TableField("urgent_count") private Integer urgentCount;
@TableField("avg_report_hours") private BigDecimal avgReportHours;
}

View File

@@ -0,0 +1,28 @@
package com.healthlink.his.check.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.core.common.core.domain.HisBaseEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("radiology_urgent_report")
public class RadiologyUrgentReport extends HisBaseEntity {
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
@TableField("encounter_id") private Long encounterId;
@TableField("patient_id") private Long patientId;
@TableField("patient_name") private String patientName;
@TableField("examination_type") private String examinationType;
@TableField("examination_name") private String examinationName;
@TableField("urgency_reason") private String urgencyReason;
@TableField("report_content") private String reportContent;
@TableField("reporter_id") private Long reporterId;
@TableField("reporter_name") private String reporterName;
@TableField("report_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date reportTime;
@TableField("notify_status") private Integer notifyStatus;
@TableField("notify_time") @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date notifyTime;
}

View File

@@ -0,0 +1,9 @@
package com.healthlink.his.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.healthlink.his.check.domain.RadiologyStatistics;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RadiologyStatisticsMapper extends BaseMapper<RadiologyStatistics> {
}

View File

@@ -0,0 +1,9 @@
package com.healthlink.his.check.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.healthlink.his.check.domain.RadiologyUrgentReport;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface RadiologyUrgentReportMapper extends BaseMapper<RadiologyUrgentReport> {
}

View File

@@ -0,0 +1,7 @@
package com.healthlink.his.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.healthlink.his.check.domain.RadiologyStatistics;
public interface IRadiologyStatisticsService extends IService<RadiologyStatistics> {
}

View File

@@ -0,0 +1,7 @@
package com.healthlink.his.check.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.healthlink.his.check.domain.RadiologyUrgentReport;
public interface IRadiologyUrgentReportService extends IService<RadiologyUrgentReport> {
}

View File

@@ -0,0 +1,11 @@
package com.healthlink.his.check.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.healthlink.his.check.domain.RadiologyStatistics;
import com.healthlink.his.check.mapper.RadiologyStatisticsMapper;
import com.healthlink.his.check.service.IRadiologyStatisticsService;
import org.springframework.stereotype.Service;
@Service
public class RadiologyStatisticsServiceImpl extends ServiceImpl<RadiologyStatisticsMapper, RadiologyStatistics> implements IRadiologyStatisticsService {
}

View File

@@ -0,0 +1,11 @@
package com.healthlink.his.check.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.healthlink.his.check.domain.RadiologyUrgentReport;
import com.healthlink.his.check.mapper.RadiologyUrgentReportMapper;
import com.healthlink.his.check.service.IRadiologyUrgentReportService;
import org.springframework.stereotype.Service;
@Service
public class RadiologyUrgentReportServiceImpl extends ServiceImpl<RadiologyUrgentReportMapper, RadiologyUrgentReport> implements IRadiologyUrgentReportService {
}

View File

@@ -0,0 +1,37 @@
package com.healthlink.his.lab.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.core.common.core.domain.HisBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("lab_external_eqa")
public class LabExternalEqa extends HisBaseEntity {
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
@TableField("assessment_name")
private String assessmentName;
@TableField("assessment_org")
private String assessmentOrg;
@TableField("assessment_year")
private Integer assessmentYear;
@TableField("assessment_quarter")
private Integer assessmentQuarter;
@TableField("sample_code")
private String sampleCode;
@TableField("test_item")
private String testItem;
@TableField("target_value")
private String targetValue;
@TableField("actual_value")
private String actualValue;
@TableField("deviation_rate")
private BigDecimal deviationRate;
@TableField("result")
private String result;
@TableField("operator_name")
private String operatorName;
}

View File

@@ -0,0 +1,41 @@
package com.healthlink.his.lab.domain;
import com.baomidou.mybatisplus.annotation.*;
import com.core.common.core.domain.HisBaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("lab_internal_qc")
public class LabInternalQc extends HisBaseEntity {
@TableId(value = "id", type = IdType.ASSIGN_ID)
private Long id;
@TableField("department_id")
private Long departmentId;
@TableField("department_name")
private String departmentName;
@TableField("instrument_name")
private String instrumentName;
@TableField("qc_item")
private String qcItem;
@TableField("qc_date")
private String qcDate;
@TableField("target_value")
private BigDecimal targetValue;
@TableField("actual_value")
private BigDecimal actualValue;
@TableField("sd_value")
private BigDecimal sdValue;
@TableField("cv_rate")
private BigDecimal cvRate;
@TableField("westgard_rule")
private String westgardRule;
@TableField("is_pass")
private Boolean isPass;
@TableField("operator_name")
private String operatorName;
@TableField("remarks")
private String remarks;
}

View File

@@ -0,0 +1,9 @@
package com.healthlink.his.lab.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.healthlink.his.lab.domain.LabExternalEqa;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface LabExternalEqaMapper extends BaseMapper<LabExternalEqa> {
}

View File

@@ -0,0 +1,9 @@
package com.healthlink.his.lab.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.healthlink.his.lab.domain.LabInternalQc;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface LabInternalQcMapper extends BaseMapper<LabInternalQc> {
}

View File

@@ -0,0 +1,7 @@
package com.healthlink.his.lab.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.healthlink.his.lab.domain.LabExternalEqa;
public interface ILabExternalEqaService extends IService<LabExternalEqa> {
}

View File

@@ -0,0 +1,7 @@
package com.healthlink.his.lab.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.healthlink.his.lab.domain.LabInternalQc;
public interface ILabInternalQcService extends IService<LabInternalQc> {
}

View File

@@ -0,0 +1,11 @@
package com.healthlink.his.lab.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.healthlink.his.lab.domain.LabExternalEqa;
import com.healthlink.his.lab.mapper.LabExternalEqaMapper;
import com.healthlink.his.lab.service.ILabExternalEqaService;
import org.springframework.stereotype.Service;
@Service
public class LabExternalEqaServiceImpl extends ServiceImpl<LabExternalEqaMapper, LabExternalEqa> implements ILabExternalEqaService {
}

View File

@@ -0,0 +1,11 @@
package com.healthlink.his.lab.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.healthlink.his.lab.domain.LabInternalQc;
import com.healthlink.his.lab.mapper.LabInternalQcMapper;
import com.healthlink.his.lab.service.ILabInternalQcService;
import org.springframework.stereotype.Service;
@Service
public class LabInternalQcServiceImpl extends ServiceImpl<LabInternalQcMapper, LabInternalQc> implements ILabInternalQcService {
}

View File

@@ -0,0 +1,9 @@
import request from '@/utils/request'
export function getSpecimenPage(p){return request({url:'/anesthesia-enhanced/specimen/page',method:'get',params:p})}
export function addSpecimen(d){return request({url:'/anesthesia-enhanced/specimen/add',method:'post',data:d})}
export function reportSpecimen(d){return request({url:'/anesthesia-enhanced/specimen/report',method:'post',data:d})}
export function getFollowupPage(p){return request({url:'/anesthesia-enhanced/followup/page',method:'get',params:p})}
export function addFollowup(d){return request({url:'/anesthesia-enhanced/followup/add',method:'post',data:d})}
export function getQcPage(p){return request({url:'/anesthesia-enhanced/qc/page',method:'get',params:p})}
export function addQc(d){return request({url:'/anesthesia-enhanced/qc/add',method:'post',data:d})}
export function getQcStats(){return request({url:'/anesthesia-enhanced/qc/stats',method:'get'})}

View File

@@ -0,0 +1,85 @@
<template>
<div style="padding:16px">
<div style="margin-bottom:16px"><span style="font-size:18px;font-weight:bold">麻醉系统增强</span></div>
<el-tabs v-model="tab" type="border-card">
<el-tab-pane label="标本管理" name="specimen">
<div style="margin-bottom:12px"><el-button type="success" @click="showSpec=true">新增标本</el-button></div>
<el-table :data="specData" border stripe>
<el-table-column prop="patientName" label="患者" width="90"/>
<el-table-column prop="specimenType" label="标本类型" width="100"/>
<el-table-column prop="specimenName" label="标本名称" width="150"/>
<el-table-column prop="collectorName" label="采集人" width="90"/>
<el-table-column prop="pathologyStatus" label="病理状态" width="100">
<template #default="{row}"><el-tag :type="row.pathologyStatus==='REPORTED'?'success':'warning'" size="small">{{ row.pathologyStatus==='PENDING'?'送检中':'已出报告' }}</el-tag></template>
</el-table-column>
<el-table-column label="操作" width="120">
<template #default="{row}">
<el-button v-if="row.pathologyStatus==='PENDING'" type="primary" link size="small" @click="reportAction(row)">出报告</el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="术后随访" name="followup">
<div style="margin-bottom:12px"><el-button type="success" @click="showFu=true">新增随访</el-button></div>
<el-table :data="fuData" border stripe>
<el-table-column prop="patientName" label="患者" width="90"/>
<el-table-column prop="followupType" label="随访类型" width="90"/>
<el-table-column prop="painScore" label="疼痛评分" width="90" align="center"/>
<el-table-column prop="nauseaVomiting" label="恶心呕吐" width="90">
<template #default="{row}"><el-tag :type="row.nauseaVomiting?'danger':'success'" size="small">{{ row.nauseaVomiting?'是':'否' }}</el-tag></template>
</el-table-column>
<el-table-column prop="complications" label="并发症" min-width="150" show-overflow-tooltip/>
<el-table-column prop="followupDoctorName" label="随访医生" width="100"/>
</el-table>
</el-tab-pane>
<el-tab-pane label="麻醉质控" name="qc">
<el-card shadow="never" style="margin-bottom:12px">
<div style="display:flex;gap:40px;text-align:center">
<div><div style="font-size:28px;font-weight:bold;color:#409eff">{{ qcStats.total||0 }}</div><div>总记录</div></div>
<div><div style="font-size:28px;font-weight:bold;color:#f56c6c">{{ qcStats.withComplications||0 }}</div><div>有并发症</div></div>
</div>
</el-card>
<div style="margin-bottom:12px"><el-button type="success" @click="showQc=true">新增记录</el-button></div>
<el-table :data="qcData" border stripe>
<el-table-column prop="patientName" label="患者" width="90"/>
<el-table-column prop="anesthesiaType" label="麻醉方式" width="100"/>
<el-table-column prop="totalDurationMin" label="时长(分)" width="80" align="center"/>
<el-table-column prop="bloodLossMl" label="出血量(ml)" width="90" align="center"/>
<el-table-column prop="complications" label="并发症" min-width="150" show-overflow-tooltip/>
<el-table-column prop="asaGrade" label="ASA分级" width="80" align="center"/>
</el-table>
</el-tab-pane>
</el-tabs>
<el-dialog v-model="showSpec" title="新增标本" width="500px">
<el-form :model="specForm" label-width="100px">
<el-form-item label="患者"><el-input v-model="specForm.patientName"/></el-form-item>
<el-form-item label="标本类型"><el-input v-model="specForm.specimenType"/></el-form-item>
<el-form-item label="标本名称"><el-input v-model="specForm.specimenName"/></el-form-item>
<el-form-item label="采集人"><el-input v-model="specForm.collectorName"/></el-form-item>
</el-form>
<template #footer><el-button @click="showSpec=false">取消</el-button><el-button type="primary" @click="submitSpec">保存</el-button></template>
</el-dialog>
</div>
</template>
<script setup>
import {ref,reactive,onMounted} from 'vue'
import {ElMessage,ElMessageBox} from 'element-plus'
import {getSpecimenPage,addSpecimen,reportSpecimen,getFollowupPage,addFollowup,getQcPage,addQc,getQcStats} from './api'
const tab=ref('specimen')
const specData=ref([]),fuData=ref([]),qcData=ref([])
const qcStats=ref({})
const showSpec=ref(false),showFu=ref(false),showQc=ref(false)
const specForm=reactive({patientName:'',specimenType:'',specimenName:'',collectorName:''})
const loadData=async()=>{
const [s,f,q,qs]=await Promise.all([getSpecimenPage({pageNo:1,pageSize:50}),getFollowupPage({pageNo:1,pageSize:50}),getQcPage({pageNo:1,pageSize:50}),getQcStats()])
specData.value=s.data?.records||[];fuData.value=f.data?.records||[];qcData.value=q.data?.records||[];qcStats.value=qs.data||{}
}
const reportAction=async(row)=>{
const{value}=await ElMessageBox.prompt('请输入病理结果','出报告',{inputType:'textarea'})
await reportSpecimen({id:row.id,pathologyResult:value});ElMessage.success('已出报告');loadData()
}
const submitSpec=async()=>{await addSpecimen(specForm);ElMessage.success('新增成功');showSpec.value=false;loadData()}
onMounted(()=>loadData())
</script>

View File

@@ -0,0 +1,6 @@
import request from '@/utils/request'
export function getInternalQcPage(p){return request({url:'/lab-enhanced/internal-qc/page',method:'get',params:p})}
export function addInternalQc(d){return request({url:'/lab-enhanced/internal-qc/add',method:'post',data:d})}
export function getQcStats(){return request({url:'/lab-enhanced/internal-qc/stats',method:'get'})}
export function getExternalEqaPage(p){return request({url:'/lab-enhanced/external-eqa/page',method:'get',params:p})}
export function addExternalEqa(d){return request({url:'/lab-enhanced/external-eqa/add',method:'post',data:d})}

View File

@@ -0,0 +1,62 @@
<template>
<div style="padding:16px">
<div style="margin-bottom:16px"><span style="font-size:18px;font-weight:bold">检验系统增强</span></div>
<el-tabs v-model="tab" type="border-card">
<el-tab-pane label="室内质控" name="iqc">
<el-card shadow="never" style="margin-bottom:12px">
<div style="display:flex;gap:40px;text-align:center">
<div><div style="font-size:28px;font-weight:bold;color:#409eff">{{ iqcStats.total||0 }}</div><div>总检测</div></div>
<div><div style="font-size:28px;font-weight:bold;color:#67c23a">{{ iqcStats.passed||0 }}</div><div>合格</div></div>
<div><div style="font-size:28px;font-weight:bold;color:#f56c6c">{{ iqcStats.failed||0 }}</div><div>失控</div></div>
</div>
</el-card>
<div style="margin-bottom:12px"><el-button type="success" @click="showIqc=true">新增记录</el-button></div>
<el-table :data="iqcData" border stripe>
<el-table-column prop="instrumentName" label="仪器" width="120"/>
<el-table-column prop="qcItem" label="质控项目" width="120"/>
<el-table-column prop="qcDate" label="质控日期" width="120"/>
<el-table-column prop="targetValue" label="靶值" width="80" align="center"/>
<el-table-column prop="actualValue" label="实测值" width="80" align="center"/>
<el-table-column prop="cvRate" label="CV%" width="70" align="center"/>
<el-table-column prop="westgardRule" label="规则" width="80"/>
<el-table-column prop="isPass" label="结果" width="70">
<template #default="{row}"><el-tag :type="row.isPass?'success':'danger'" size="small">{{ row.isPass?'合格':'失控' }}</el-tag></template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="室间质评" name="eqa">
<div style="margin-bottom:12px"><el-button type="success" @click="showEqa=true">新增记录</el-button></div>
<el-table :data="eqaData" border stripe>
<el-table-column prop="assessmentName" label="质评项目" width="150"/>
<el-table-column prop="assessmentOrg" label="组织机构" width="150"/>
<el-table-column prop="testItem" label="检测项目" width="120"/>
<el-table-column prop="targetValue" label="靶值" width="100"/>
<el-table-column prop="actualValue" label="实测值" width="100"/>
<el-table-column prop="deviationRate" label="偏差率%" width="80" align="center"/>
<el-table-column prop="result" label="结果" width="80">
<template #default="{row}"><el-tag :type="row.result==='合格'?'success':'danger'" size="small">{{ row.result }}</el-tag></template>
</el-table-column>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup>
import {ref,reactive,onMounted} from 'vue'
import {ElMessage} from 'element-plus'
import {getInternalQcPage,addInternalQc,getQcStats,getExternalEqaPage,addExternalEqa} from './api'
const tab=ref('iqc')
const iqcData=ref([]),eqaData=ref([])
const iqcStats=ref({})
const showIqc=ref(false),showEqa=ref(false)
const iqcForm=reactive({instrumentName:'',qcItem:'',qcDate:'',targetValue:null,actualValue:null,cvRate:null,westgardRule:'',isPass:true,operatorName:''})
const eqaForm=reactive({assessmentName:'',assessmentOrg:'',testItem:'',targetValue:'',actualValue:'',deviationRate:null,result:'合格'})
const loadData=async()=>{
const [i,q,e]=await Promise.all([getInternalQcPage({pageNo:1,pageSize:50}),getQcStats(),getExternalEqaPage({pageNo:1,pageSize:50})])
iqcData.value=i.data?.records||[];iqcStats.value=q.data||[];eqaData.value=e.data?.records||[]
}
const submitIqc=async()=>{await addInternalQc(iqcForm);ElMessage.success('新增成功');showIqc.value=false;loadData()}
const submitEqa=async()=>{await addExternalEqa(eqaForm);ElMessage.success('新增成功');showEqa.value=false;loadData()}
onMounted(()=>loadData())
</script>

View File

@@ -0,0 +1,6 @@
import request from '@/utils/request'
export function getUrgentReportPage(p){return request({url:'/radiology-enhanced/urgent-report/page',method:'get',params:p})}
export function addUrgentReport(d){return request({url:'/radiology-enhanced/urgent-report/add',method:'post',data:d})}
export function notifyReport(id){return request({url:'/radiology-enhanced/urgent-report/notify',method:'post',params:{id}})}
export function getStatisticsPage(p){return request({url:'/radiology-enhanced/statistics/page',method:'get',params:p})}
export function addStatistics(d){return request({url:'/radiology-enhanced/statistics/add',method:'post',data:d})}

View File

@@ -0,0 +1,55 @@
<template>
<div style="padding:16px">
<div style="margin-bottom:16px"><span style="font-size:18px;font-weight:bold">检查系统增强</span></div>
<el-tabs v-model="tab" type="border-card">
<el-tab-pane label="紧急报告" name="urgent">
<div style="margin-bottom:12px"><el-button type="danger" @click="showUrgent=true">新增紧急报告</el-button></div>
<el-table :data="urgentData" border stripe>
<el-table-column prop="patientName" label="患者" width="90"/>
<el-table-column prop="examinationType" label="检查类型" width="100"/>
<el-table-column prop="examinationName" label="检查名称" width="150"/>
<el-table-column prop="urgencyReason" label="紧急原因" min-width="150" show-overflow-tooltip/>
<el-table-column prop="reporterName" label="报告人" width="90"/>
<el-table-column prop="reportTime" label="报告时间" width="170"/>
<el-table-column prop="notifyStatus" label="通知状态" width="90">
<template #default="{row}"><el-tag :type="['warning','success','danger'][row.notifyStatus]" size="small">{{ ['待通知','已通知','通知失败'][row.notifyStatus] }}</el-tag></template>
</el-table-column>
<el-table-column label="操作" width="100">
<template #default="{row}"><el-button v-if="row.notifyStatus===0" type="primary" link size="small" @click="notifyAction(row)">通知</el-button></template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="检查统计" name="stats">
<div style="margin-bottom:12px"><el-button type="success" @click="showStats=true">新增统计</el-button></div>
<el-table :data="statsData" border stripe>
<el-table-column prop="statDate" label="日期" width="120"/>
<el-table-column prop="departmentName" label="科室" width="120"/>
<el-table-column prop="examinationType" label="检查类型" width="100"/>
<el-table-column prop="totalCount" label="总例数" width="80" align="center"/>
<el-table-column prop="positiveCount" label="阳性数" width="80" align="center"/>
<el-table-column prop="urgentCount" label="急诊数" width="80" align="center"/>
<el-table-column prop="avgReportHours" label="平均出报告(h)" width="120" align="center"/>
</el-table>
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup>
import {ref,reactive,onMounted} from 'vue'
import {ElMessage} from 'element-plus'
import {getUrgentReportPage,addUrgentReport,notifyReport,getStatisticsPage,addStatistics} from './api'
const tab=ref('urgent')
const urgentData=ref([]),statsData=ref([])
const showUrgent=ref(false),showStats=ref(false)
const urgentForm=reactive({patientName:'',examinationType:'',examinationName:'',urgencyReason:'',reportContent:'',reporterName:''})
const statsForm=reactive({statDate:'',departmentName:'',examinationType:'',totalCount:0,positiveCount:0,urgentCount:0,avgReportHours:0})
const loadData=async()=>{
const [u,s]=await Promise.all([getUrgentReportPage({pageNo:1,pageSize:50}),getStatisticsPage({pageNo:1,pageSize:50})])
urgentData.value=u.data?.records||[];statsData.value=s.data?.records||[]
}
const notifyAction=async(row)=>{await notifyReport(row.id);ElMessage.success('已通知');loadData()}
const submitUrgent=async()=>{await addUrgentReport(urgentForm);ElMessage.success('新增成功');showUrgent.value=false;loadData()}
const submitStats=async()=>{await addStatistics(statsForm);ElMessage.success('新增成功');showStats.value=false;loadData()}
onMounted(()=>loadData())
</script>