初始化

master
linjj 3 months ago
parent d1f42eff87
commit 8ca06f01b7

@ -9,7 +9,7 @@
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>collector_czry</artifactId>
<artifactId>fushu</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootDemo</name>
<description>springbootDemo</description>
@ -60,6 +60,39 @@
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatisPlus.version}</version>
</dependency>
<!-- OFD 核心支持 -->
<dependency>
<groupId>org.ofdrw</groupId>
<artifactId>ofdrw-layout</artifactId>
<version>1.20.2</version>
</dependency>
<!-- PDF 渲染 -->
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox</artifactId>
<version>2.0.27</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>jbig2-imageio</artifactId>
<version>3.0.3</version>
</dependency>
<!-- OCR -->
<dependency>
<groupId>net.sourceforge.tess4j</groupId>
<artifactId>tess4j</artifactId>
<version>5.10.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.14</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
@ -81,6 +114,15 @@
<version>2.0.27</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.14</version>
</dependency>
<!-- swaggerui相关依赖 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>

@ -1,27 +0,0 @@
package com.example.aother.annotation.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MybatisPlusConfig{
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
paginationInnerInterceptor.setDbType(DbType.MYSQL);
paginationInnerInterceptor.setOverflow(true);
interceptor.addInnerInterceptor(paginationInnerInterceptor);
OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);
return interceptor;
}
}

@ -1,42 +0,0 @@
package com.example.aother.annotation.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
//Json序列化器
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(om);
//String序列化器
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key采用String序列化器
template.setKeySerializer(stringRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
//value采用Json序列化器
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}

@ -1,11 +1,6 @@
package com.example.duplicate.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.example.duplicate.controller.param.UploadBatchFileParam;
import com.example.duplicate.controller.param.updateTaskDto;
import com.example.duplicate.controller.param.FileUpload;
import com.example.duplicate.service.TaskService;
import com.example.duplicate.service.MedicalAdviceService;
import com.example.utils.CommonResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -14,218 +9,34 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* @ClassName TaskController
* @Description
* @Description OFD
* @Author linjj
* @Date 2024/8/5 14:21
* @Version 1.0
*/
@RestController
@RequestMapping("/task")
@Api(value = "任务接口", tags = "任务对外接口")
@RequestMapping("/emr")
@Api(value = "佐医佑康OFD外部接口", tags = "佐医佑康OFD外部接口")
@Slf4j
public class TaskController {
@Autowired
private TaskService taskService;
/**
* @description:
* @params: collectid
* @return: data
* @author linjj
* @date: 2024/8/5 14:46
*/
@PostMapping("/getTask")
@ApiOperation("获取任务接口")
@ResponseBody
public CommonResult<?> GetTask(@RequestParam @ApiParam(required = false, name = "collectId", value = "采集器id") String collectId) {
return taskService.GetTask(collectId);
}
/**
* @description:
* @params: masterId
* @return: data
* @author linjj
* @date: 2024/8/5 15:31
*/
//补偿接口
@PostMapping(value = "repairTask")
@ApiOperation("补偿患者所有采集任务接口")
@ResponseBody
public CommonResult<?> repairTask(@RequestParam @ApiParam(required = false, name = "masterId", value = "患者masterId") String masterId) {
if (StringUtils.isBlank(masterId)) {
return CommonResult.failed("masterId不能为空");
}
return taskService.repairTask(masterId);
}
/**
* @description:
* @params: masterId
* @params: collectId
* @return: CommonResult
* @author linjj
* @date: 2024/8/6 9:15
*/
@PostMapping(value = "repairTaskByCollectId")
@ApiOperation("补偿患者单个采集任务接口")
@ResponseBody
public CommonResult<?> repairTask(@RequestParam @ApiParam(required = false, name = "masterId", value = "患者masterId") String masterId,
@RequestParam @ApiParam(required = false, name = "collectId", value = "采集器id") String collectId) {
if (StringUtils.isBlank(masterId)) {
return CommonResult.failed("masterId不能为空");
}
if (StringUtils.isBlank(collectId)) {
return CommonResult.failed("collectId不能为空");
}
return taskService.repairTaskByCollectId(masterId, collectId);
}
/**
* @description: idid
* @params: masterId
* @params: collectId
* @author linjj
* @date: 2024/12/26 14:30
*/
@PostMapping(value = "delFileBySource")
@ApiOperation("根据采集器id患者id删除单据")
@ResponseBody
public CommonResult<?> delFileBySource(@RequestParam @ApiParam(required = false, name = "masterId", value = "患者masterId") String masterId,
@RequestParam @ApiParam(required = false, name = "collectId", value = "采集器id") String collectId) {
if (StringUtils.isBlank(masterId)) {
return CommonResult.failed("masterId不能为空");
}
if (StringUtils.isBlank(collectId)) {
return CommonResult.failed("collectId不能为空");
}
return taskService.delFileBySource(masterId,collectId);
}
/**
* @description:
* @params: updateTaskDto
* @return: CommonResult
* @author linjj
* @date: 2024/8/6 9:17
*/
@PostMapping(value = "updateTask")
@ApiOperation("维护任务表接口")
@ResponseBody
public CommonResult<?> updateTask(updateTaskDto dto) {
return taskService.updateTask(dto);
}
/**
* @description:
* @params: files
* @params: uploadBatchFileParam
* @return: CommonResult
* @author linjj
* @date: 2024/8/6 14:13
*/
@PostMapping(value = "fileUpload")
@ApiOperation("文件上传接口")
private MedicalAdviceService medicalAdviceService;
@PostMapping("/patientInfoSync")
@ApiOperation("根据出院时间范围上传患者")
@ResponseBody
public CommonResult<?> fileUpload(@RequestPart("files") MultipartFile[] files, UploadBatchFileParam uploadBatchFileParam) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = dateFormat.format(new Date());
//成功流水号id
List<String> serialNumberIds = new ArrayList<>();
//失败流水号id
List<String> failIds = new ArrayList<>();
if (Objects.isNull(uploadBatchFileParam) || Objects.isNull(uploadBatchFileParam.getUploadFileParams())) {
log.info(format + "文件上传参数为空!");
return CommonResult.failed("文件上传参数为空!");
}
log.info(format + "本次文件上传传输参数为:" + JSONObject.toJSONString(uploadBatchFileParam));
List<FileUpload> fileUpload = JSONArray.parseArray(uploadBatchFileParam.getUploadFileParams(), FileUpload.class);
for (FileUpload dto : fileUpload) {
if (StringUtils.isBlank(dto.getMasterid())) {
log.info(format + "病案主键不能为空!");
return CommonResult.failed("病案主键不能为空");
}
if (StringUtils.isBlank(dto.getAssortid())) {
log.info(format + "文件分段id不能为空");
return CommonResult.failed("文件分段id不能为空");
}
if (StringUtils.isBlank(dto.getSource())) {
log.info(format + "文件来源不能为空!");
return CommonResult.failed("文件来源不能为空");
}
if (StringUtils.isBlank(dto.getSubassort())) {
log.info(format + "文件MD5码不能为空不能为空");
return CommonResult.failed("文件MD5码不能为空不能为空");
}
if (StringUtils.isBlank(dto.getTitle())) {
log.info(format + "保存数据库文件名不能为空!");
return CommonResult.failed("保存数据库文件名不能为空");
}
if (StringUtils.isBlank(dto.getFileName())) {
log.info(format + "真实文件名不能为空!");
return CommonResult.failed("真实文件名不能为空");
}
if (StringUtils.isBlank(dto.getSerialNumber())) {
log.info(format + "文件MD5码不能为空不能为空");
return CommonResult.failed("文件MD5码不能为空不能为空");
public CommonResult<?> patientInfoSync(@RequestParam @ApiParam(required = false, name = "startTime", value = "出院时间范围开始" ) String startTime,
@RequestParam @ApiParam(required = false, name = "endTime", value = "出院时间范围结束" ) String endTime) throws Exception {
if (StringUtils.isBlank(startTime)){
return CommonResult.failed("开始时间不能为空");
}
if (StringUtils.isBlank(dto.getSoleKey())) {
log.info(format + "SoleKey值不能为空");
return CommonResult.failed("文件MD5码不能为空不能为空");
if (StringUtils.isBlank(endTime)){
return CommonResult.failed("结束时间不能为空");
}
}
if (fileUpload.size() != files.length) {
log.info(format + "文件上传参数为空!");
return CommonResult.failed("文件上传数量与参数不一致");
}
// 参数不含上传的,不匹配
List<String> originalFileNames = fileUpload.stream().map(item -> String.valueOf(item.getFileName())).collect(Collectors.toList());
for (MultipartFile file : files) {
if (!originalFileNames.contains(file.getOriginalFilename())) {
log.info(format + "文件上传参数为空!");
return CommonResult.failed("原文件名不匹配!");
}
}
for (MultipartFile file : files) {
for (FileUpload uploadFileParam : fileUpload) {
if (uploadFileParam.getFileName().equals(file.getOriginalFilename())) {
if (taskService.fileUpload(file, uploadFileParam)) {
serialNumberIds.add(uploadFileParam.getSubassort());
} else {
failIds.add(uploadFileParam.getSubassort());
}
}
}
}
log.info("本次文件上传传输完成,成功流水号:" + JSONObject.toJSONString(serialNumberIds));
log.info("本次文件上传传输完成,失败流水号:" + JSONObject.toJSONString(failIds));
return CommonResult.success("本次文件上传传输完成");
}
/**
* @description:
* @author linjj
* @date: 2024/8/19 4:32
*/
@PostMapping(value = "compensate")
@ApiOperation("根据时间补偿采集器接口")
@ResponseBody
public CommonResult<?> compensate(@RequestParam @ApiParam(required = true, name = "startTime", value = "补偿开始时间") String startTime,
@RequestParam @ApiParam(required = true, name = "entTime", value = "补偿开始时间") String entTime,
@RequestParam @ApiParam(required = true, name = "collectId", value = "采集器id") String collectId) {
return taskService.compensate(startTime,entTime,collectId);
return medicalAdviceService.medicalCompensate(startTime,endTime);
}
}

@ -1,35 +0,0 @@
package com.example.duplicate.controller.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class ArchiveDetailDto {
private String id;
//文件路径
private String pdfPath;
//主键id
private String masterid;
//更新时间
private String uploaddatetime;
//更新时间
private String assortid;
//文件来源
private String source;
//分段信息
private String subassort;
//标题
private String title;
//标识
private String flag;
//标识
private String sys;
//文件唯一id
private String serialNumber;
//扩展字段
private String C1;
//扩展唯一标识
private String SoleKey;
}

@ -1,41 +0,0 @@
package com.example.duplicate.controller.param;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
/**
* @description: ArchiveOtherExtDto
* @author linjj
* @date: 2024/8/5 9:21
*/
@Data
public class ArchiveOtherExtDto implements Serializable {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "病案主键")
@TableId(value = "patient_id", type = IdType.ASSIGN_ID)
private Long id;
//更新时间
private String SycTime;
//任务id
private String otherID;
//采集器标识
private Integer sysFlag;
//个更新时间
private String sysUpdateTime;
//记帐号
private String jzh;
//住院号
private String zyh;
//标识
private Integer statusFlag;
//主键id
private String MID;
//扩展字段
private String C1;
}

@ -0,0 +1,44 @@
package com.example.duplicate.controller.param;
import lombok.Data;
/**
* @ClassName FileMeta
* @Description
* @Author linjj
* @Date 2025/9/25 15:55
* @Version 1.0
*/
@Data
public class FileMeta {
/** 本地文件完整路径 */
private final String path;
/** 患者唯一标识 */
private final String patientId;
/** 诊疗标识(就诊唯一标识) */
private final String uniqueIdentifier;
/** 文书编号(文件唯一标识) */
private final String fileNo;
/** 文书编号病案目录id */
private final String catalogueName;
/* 构造方法 */
public FileMeta(String path, String patientId, String uniqueIdentifier, String fileNo,String catalogueName) {
this.path = path;
this.patientId = patientId;
this.uniqueIdentifier = uniqueIdentifier;
this.fileNo = fileNo;
this.catalogueName=catalogueName;
}
public String getPath() { return path; }
public String getPatientId() { return patientId; }
public String getUniqueIdentifier() { return uniqueIdentifier; }
public String getFileNo() { return fileNo; }
public String getCatalogueName() { return catalogueName; }
}

@ -1,32 +0,0 @@
package com.example.duplicate.controller.param;
import lombok.Data;
/**
* @description:
* @author linjj
* @date: 2024/8/6 14:17
*/
@Data
public class FileUpload {
//主键id
private String masterid;
//分类id
private String assortid;
//来源
private String source;
//文件MD5码
private String subassort;
//标题
private String title;
//文件名
private String fileName;
//文件MD5码
private String SerialNumber;
//采集器id标识
private String C1;
//唯一主键
private String SoleKey;
}

@ -1,30 +0,0 @@
package com.example.duplicate.controller.param;
import com.example.duplicate.controller.vo.ArchiveMasterVo;
import lombok.Data;
/**
* @description:
* @author linjj
* @date: 2024/8/2 16:45
*/
@Data
public class PrintParam {
private String id;
//记帐号
private String jzh;
//住院号
private String inpNo;
//住院次数
private String visitId;
//患者姓名
private String name;
//出院科室
private String deptName;
//出院时间
private String dischargeDateTime;
//住院时间
private String admissionDateTime;
}

@ -1,11 +0,0 @@
package com.example.duplicate.controller.param;
import lombok.Data;
@Data
public class UploadBatchFileParam {
private String uploadFileParams;
}

@ -1,39 +0,0 @@
package com.example.duplicate.controller.param;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* @ClassName updateTaskDto
* @Description
* @Author linjj
* @Date 2024/3/8 11:10
* @Version 1.0
*/
@Data
public class updateTaskDto {
@ApiModelProperty(value="主键id",name="mid", required=true)
private String mid;
@ApiModelProperty(value="患者信息",name="sycObj", required=true)
private String sycObj;
@ApiModelProperty(value="任务状态",name="statusFlag", required=true)
private int statusFlag;
@ApiModelProperty(value="采集器id",name="sysFlag", required=true)
private int sysFlag;
@ApiModelProperty(value="开始时间",name="startTime", required=true)
private String startTime;
@ApiModelProperty(value="结束时间",name="endTime", required=true)
private String endTime;
@ApiModelProperty(value="备注",name="pinResult", required=true)
private String pinResult;
@ApiModelProperty(value="异常信息",name="errorInfo", required=false)
private String errorInfo;
@ApiModelProperty(value="异常信息图片",name="errorImage",required=false)
private String errorImage;
}

@ -1,85 +0,0 @@
package com.example.duplicate.controller.vo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
/**
* @description:
* @author linjj
* @date: 2024/8/5 9:09
*/
@Data
public class ArchiveOtherExtVo {
@ApiModelProperty(value = "病案主键")
@TableId(value = "patient_id", type = IdType.ASSIGN_ID)
private Long id;
private Date syctime;
private String sycobj;
private Long otherid;
private Integer sysflag;
private Date sysupdatetime;
private String jzh;
private String zyh;
private Date stime;
private Date etime;
private Integer statusflag;
private String presult;
private String mid;
private String did;
private String c1;
private String c2;
private String c3;
private String c4;
private String c5;
private String c6;
private String c7;
private String c8;
private String c9;
private String c10;
private BigDecimal n1;
private BigDecimal n2;
private BigDecimal n3;
private Date t1;
private Date t2;
private Date t3;
private Date t4;
private Date t5;
private Date t6;
}

@ -10,22 +10,18 @@ import lombok.Data;
* @Version 1.0
*/
@Data
public class ArchiveMasterVo {
public class CommomtableVo {
private String id;
//住院号
private String inpNo;
//住院次数
private String visitId;
//记帐号
private String patientId;
//出院科室
private String deptName;
//住院号
private String inpatientNo;
//出院时间
private String dischargeDateTime;
private String disDate;
//患者姓名
private String name;
//住院时间
private String admissionDateTime;
private String admissDate;
//文件存在目录
private String filePath;
}

@ -0,0 +1,19 @@
package com.example.duplicate.controller.vo;
import lombok.Data;
/**
* @ClassName TscanAssort
* @Description
* @Author linjj
* @Date 2025/9/25 15:40
* @Version 1.0
*/
@Data
public class TscanAssortVo {
//文件名
private String scanPage;
//分段id
private String assortId;
}

@ -1,34 +0,0 @@
package com.example.duplicate.controller.vo;
import lombok.Data;
/**
* @ClassName medicalCompensateVo
* @Description
* @Author linjj
* @Date 2025/7/25 14:48
* @Version 1.0
*/
@Data
public class medicalCompensateVo {
//采集器id
private String sysFlag;
//任务id
private String otherId;
private String id;
//住院号
private String inpNo;
//住院次数
private String visitId;
//记帐号
private String patientId;
//出院科室
private String deptName;
//出院时间
private String dischargeDateTime;
//患者姓名
private String name;
//住院时间
private String admissionDateTime;
}

@ -1,29 +0,0 @@
package com.example.duplicate.infrastructure.dao;
import com.example.duplicate.controller.param.ArchiveDetailDto;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @InterfaceName ArchiveDetailMapper
* @Description
* @Author linjj
* @Date 2024/8/6 14:29
* @Version 1.0
*/
@Mapper
public interface ArchiveDetailMapper {
List<ArchiveDetailDto> getDetailBySerialNumber(String serialNumber);
boolean deleteByPrimaryKey(String id);
boolean delFileBySource(@Param("masterId")String masterId,@Param("collectId")String collectId);
boolean insertSel(ArchiveDetailDto record);
}

@ -1,23 +0,0 @@
package com.example.duplicate.infrastructure.dao;
import com.example.duplicate.controller.vo.ArchiveMasterVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @InterfaceName Archive_master
* @Author linjj
* @Date 2024/8/2 15:54
* @Version 1.0
*/
@Mapper
public interface ArchiveMasterMapper {
//轮询根据时间获取患者信息
List<ArchiveMasterVo> getMedicalAdviceTask();
//根据masterId获取患者信息
List<ArchiveMasterVo> getArchiveMasterByMasterId(@Param("masterId")String masterId);
List<String> getMasterid(@Param("startTime")String startTime, @Param("entTime")String entTime);
}

@ -1,31 +0,0 @@
package com.example.duplicate.infrastructure.dao;
import com.example.duplicate.controller.param.ArchiveOtherExtDto;
import com.example.duplicate.controller.param.updateTaskDto;
import com.example.duplicate.controller.vo.ArchiveOtherExtVo;
import com.example.duplicate.controller.vo.medicalCompensateVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @InterfaceName ArchiveOtherExtMapper
* @Description
* @Author linjj
* @Date 2024/8/5 8:52
* @Version 1.0
*/
@Mapper
public interface ArchiveOtherExtMapper {
List<ArchiveOtherExtVo> getOtherByMidAndFlag(@Param("mid")String mid, @Param("sysFlag")int sysFlag);
Boolean addOther(ArchiveOtherExtDto archiveOtherExtDto);
Boolean updateByMid(updateTaskDto dto);
Boolean updateStatic(@Param("mid")String mid, @Param("sysFlag")String sysFlag);
List<medicalCompensateVo> medicalCompensate(@Param("statusFlag")int statusFlag);
}

@ -0,0 +1,22 @@
package com.example.duplicate.infrastructure.dao;
import com.example.duplicate.controller.vo.CommomtableVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @ClassName CommomtableMapper
* @Description commomtable
* @Author linjj
* @Date 2025/9/25 15:15
* @Version 1.0
*/
@Mapper
public interface CommomtableMapper {
//轮询根据时间获取患者信息
List<CommomtableVo> getCommomtable(@Param("startTime")String startTime, @Param("entTime")String entTime);
}

@ -0,0 +1,27 @@
package com.example.duplicate.infrastructure.dao;
import com.example.duplicate.controller.vo.CommomtableVo;
import com.example.duplicate.controller.vo.TscanAssortVo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @ClassName CommomtableMapper
* @Description commomtable
* @Author linjj
* @Date 2025/9/25 15:15
* @Version 1.0
*/
@Mapper
public interface TscanAssortMapper {
/**
* @Author: linjj
* @Description:
* @DateTime: 2025/9/25 15:51
* @Params: [patientId, isDel]
* @Return java.util.List<com.example.duplicate.controller.vo.TscanAssortVo>
*/
List<TscanAssortVo> getScanPage(@Param("patientId")String patientId,@Param("isDel")String isDel);
}

@ -4,25 +4,20 @@ import com.example.utils.CommonResult;
/**
* @InterfaceName MedicalAdviceService
* @Description
* @Description OFD
* @Author linjj
* @Date 2024/8/2 15:47
* @Version 1.0
*/
public interface MedicalAdviceService {
/**
* @description:
* @author linjj
* @date: 2024/8/2 15:52
*/
CommonResult<?> pollingAddTask();
/**
* @Author: linjj
* @Description:
* @DateTime: 2025/7/25 14:25
* @Params: []
* @Description:
* @DateTime: 2025/9/25 11:35
* @Params: [startTime, endTime]
* @Return com.example.utils.CommonResult<?>
*/
CommonResult<?> medicalCompensate();
CommonResult<?> medicalCompensate(String startTime,String endTime) throws Exception;
}

@ -1,73 +0,0 @@
package com.example.duplicate.service;
import com.example.duplicate.controller.param.updateTaskDto;
import com.example.duplicate.controller.param.FileUpload;
import com.example.utils.CommonResult;
import org.springframework.web.multipart.MultipartFile;
/**
* @InterfaceName TaskService
* @Description
* @Author linjj
* @Date 2024/8/5 14:44
* @Version 1.0
*/
public interface TaskService {
/**
* @description:
* @params: collectId
* @return: CommonResult
* @author linjj
* @date: 2024/8/5 14:41
*/
CommonResult GetTask(String collectId);
/**
* @description:
* @params: masterId
* @return: CommonResult
* @author linjj
* @date: 2024/8/5 15:32
*/
CommonResult repairTask(String masterId);
/**
* @description:
* @params: masterId
* @params: collectId
* @return: CommonResult
* @author linjj
* @date: 2024/8/5 17:25
*/
CommonResult repairTaskByCollectId(String masterId,String collectId);
/**
* @description: idid
* @params: masterId
* @params: collectId
* @author linjj
* @date: 2024/12/26 14:32
*/
CommonResult delFileBySource(String masterId,String collectId);
/**
* @description:
* @params: updateTaskDto
* @return: CommonResult
* @author linjj
* @date: 2024/8/6 9:27
*/
CommonResult updateTask(updateTaskDto dto);
/**
* @description:
* @params: file
* @params: FileUpload
* @return: Boolean
* @author linjj
* @date: 2024/8/6 14:22
*/
Boolean fileUpload(MultipartFile file, FileUpload dto);
/**
* @description: 7
* @author linjj
* @date: 2024/8/19 4:32
*/
CommonResult compensate(String startTime,String entTime,String collectId);
}

@ -1,30 +1,36 @@
package com.example.duplicate.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.example.duplicate.controller.param.ArchiveOtherExtDto;
import com.example.duplicate.controller.param.PrintParam;
import com.example.duplicate.controller.vo.ArchiveMasterVo;
import com.example.duplicate.controller.vo.ArchiveOtherExtVo;
import com.example.duplicate.controller.vo.medicalCompensateVo;
import com.example.duplicate.infrastructure.dao.ArchiveMasterMapper;
import com.example.duplicate.infrastructure.dao.ArchiveOtherExtMapper;
import com.alibaba.fastjson.JSONObject;
import com.example.duplicate.controller.param.FileMeta;
import com.example.duplicate.controller.vo.CommomtableVo;
import com.example.duplicate.controller.vo.TscanAssortVo;
import com.example.duplicate.infrastructure.dao.CommomtableMapper;
import com.example.duplicate.infrastructure.dao.TscanAssortMapper;
import com.example.duplicate.service.MedicalAdviceService;
import com.example.utils.CommonResult;
import com.example.utils.RedisMq;
import com.example.utils.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import javax.annotation.PostConstruct;
import java.io.File;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.*;
/**
* @ClassName MedicalAdviceServiceImpl
@ -37,117 +43,309 @@ import java.util.List;
@Slf4j
public class MedicalAdviceServiceImpl implements MedicalAdviceService {
@Value("${collectIdList}")
private String collectIdList;
//网关
@Value("${DOMAIN_URL}")
private String DOMAIN_URL;
//应用id
@Value("${APP_ID}")
private String APP_ID;
//公钥
@Value("${ACCESS_KEY}")
private String ACCESS_KEY;
//私钥
@Value("${SECRET_KEY}")
private String SECRET_KEY;
@Value("${tokenAPI}")
private String tokenAPI;
@Value("${addPatientInfoAPI}")
private String addPatientInfoAPI;
@Value("${emrUploadAPI}")
private String emrUploadAPI;
@Autowired
private ArchiveMasterMapper ArchiveMasterMapper;
private CommomtableMapper commomtableMapper;
@Autowired
private ArchiveOtherExtMapper archiveOtherExtMapper;
@Autowired(required = false)
private RedisMq redisMq;
private TscanAssortMapper tscanAssortMapper;
/* === 用于拼接后存放 === */
//获取token路径
private String tokenURL;
//同步患者信息路径
private String addPatientInfoAPIURL;
//上传文件接口路径
private String emrUploadURL;
/* === 依赖注入完成后拼接 === */
@PostConstruct
public void init() {
this.tokenURL = DOMAIN_URL + tokenAPI;
this.addPatientInfoAPIURL = DOMAIN_URL + addPatientInfoAPI;
this.emrUploadURL = DOMAIN_URL + emrUploadAPI;
}
private String redisKey = "docus:task:topic_collect_%s_queue:%s";
@Override
public CommonResult<?> pollingAddTask() {
//获取当前30分钟前出院病历生成任务
List<ArchiveMasterVo> medicalAdviceTask = ArchiveMasterMapper.getMedicalAdviceTask();
if (CollectionUtils.isEmpty(medicalAdviceTask)) {
log.info("当前没有需要生成任务的病历");
return CommonResult.failed("当前没有需要生成任务的病历");
}
PrintParam printParam = new PrintParam();
//任务表入参
ArchiveOtherExtDto dto = new ArchiveOtherExtDto();
//任务生成时间
Date date = new Date();
SimpleDateFormat SycTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//补偿所有采集器id集合
List<String> collectIds = Arrays.asList(collectIdList.split(","));
//生成任务
for (ArchiveMasterVo tasks : medicalAdviceTask) {
//增加所有采集id的任务
for (String collectId : collectIds) {
try {
//查询任务表是否存在,不存在新增
List<ArchiveOtherExtVo> others = archiveOtherExtMapper.getOtherByMidAndFlag(tasks.getId(), Integer.parseInt(collectId));
if (CollectionUtils.isEmpty(others)) {
//任务表新增
dto.setId(SnowflakeIdWorker.idWorker.nextId());
dto.setSycTime(SycTime.format(date));
dto.setOtherID("0");
dto.setSysFlag(Integer.parseInt(collectId));
dto.setSysUpdateTime(SycTime.format(date));
dto.setJzh(tasks.getPatientId());
dto.setZyh(tasks.getInpNo());
dto.setStatusFlag(0);
dto.setMID(tasks.getId());
//任务表新增任务
if (archiveOtherExtMapper.addOther(dto)) {
//存放队列消息
GenerateQueue(tasks, printParam, 5, collectId);
log.info("轮询增加任务成功,id为:" + tasks.getId());
public CommonResult<?> medicalCompensate(String startTime, String endTime) throws Exception {
//根据时间范围查询患者
List<CommomtableVo> commomtable = commomtableMapper.getCommomtable(startTime, endTime);
if (ObjectUtils.isEmpty(commomtable)){
return CommonResult.success("当前时间段没有可同步的患者");
}
//------------------------------------------------获取token--------------------------------------------------------
String ACCESS_TOKEN = getToken();
//------------------------------------------------轮询执行患者同步---------------------------------------------------
for (CommomtableVo list :commomtable) {
//患者同步
String msg = patientInfoSync(ACCESS_TOKEN, list);
//判断是否同步成功,不成功不进行文件上传操作
if (!"操作成功".equals(msg)) {
log.info("患者信息同步失败:" + list.getPatientId());
continue;
}
//-------------------------------------------------文件上传--------------------------------------------------------------------------
//根据病案主键获取文件信息
List<TscanAssortVo> scanPages = tscanAssortMapper.getScanPage(list.getPatientId(), "0");
if (ObjectUtils.isEmpty(commomtable)) {
log.info("当前患者查询不到影像记录:" + list.getPatientId());
continue;
}
//组织文件信息
List<FileMeta> files = getFiles(list, scanPages);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
/* 公共文本参数 */
builder.addPart("recordTypeId", new StringBody("413687918421381", ContentType.TEXT_PLAIN));
builder.addPart("planId", new StringBody("417408389604741", ContentType.TEXT_PLAIN));
builder.addPart("operateType", new StringBody("insert", ContentType.TEXT_PLAIN));
builder.addPart("storeWay", new StringBody("1", ContentType.TEXT_PLAIN));
builder.addPart("dataType", new StringBody("2", ContentType.TEXT_PLAIN));
builder.addPart("origin", new StringBody("999", ContentType.TEXT_PLAIN));
/* 循环塞文件 */
for (int i = 0; i < files.size(); i++) {
FileMeta m = files.get(i);
builder.addPart("fileInfoReqList[" + i + "].file",
new FileBody(new File(m.getPath())));
builder.addPart("fileInfoReqList[" + i + "].patientId",
new StringBody(m.getPatientId(), ContentType.TEXT_PLAIN));
builder.addPart("fileInfoReqList[" + i + "].uniqueIdentifier",
new StringBody(m.getUniqueIdentifier(), ContentType.TEXT_PLAIN));
builder.addPart("fileInfoReqList[" + i + "].fileNo",
new StringBody(m.getFileNo(), ContentType.TEXT_PLAIN));
builder.addPart("fileInfoReqList[" + i + "].catalogueName",
new StringBody(m.getCatalogueName(), ContentType.TEXT_PLAIN));
}
/* 3. 构建实体并发送 */
HttpEntity entity = builder.build();
// 打印实体内容
for (int i = 0; i < files.size(); i++) {
FileMeta m = files.get(i);
System.out.println("---- 第 " + i + " 个文件 非文件字段 ----");
System.out.println("recordTypeId = 413687918421381");
System.out.println("planId = 417408389604741");
System.out.println("operateType = insert");
System.out.println("storeWay = 1");
System.out.println("dataType = 2");
System.out.println("origin = 999");
System.out.println("fileInfoReqList[" + i + "].patientId = " + m.getPatientId());
System.out.println("fileInfoReqList[" + i + "].uniqueIdentifier = " + m.getUniqueIdentifier());
System.out.println("fileInfoReqList[" + i + "].fileNo = " + m.getFileNo());
System.out.println("fileInfoReqList[" + i + "].catalogueName = " + m.getCatalogueName());
/* 文件本身不打印 */
}
HttpPost post = new HttpPost(emrUploadURL);
post.setHeader("appId", APP_ID);
post.setHeader("accessKey", ACCESS_KEY);
post.setHeader("plss-auth", ACCESS_TOKEN);
post.setEntity(entity);
try (CloseableHttpClient client = HttpClients.createDefault();
CloseableHttpResponse resp = client.execute(post)) {
String body = EntityUtils.toString(resp.getEntity());
System.out.println("Status: " + resp.getStatusLine().getStatusCode());
System.out.println("Body : " + body);
/*结果判断 */
if (body.contains("\"msg\":\"操作成功\"")) {
System.out.println("批量上传成功:"+list.getPatientId());
} else {
//存在任务将任务表状态改为0为开始
archiveOtherExtMapper.updateStatic(tasks.getId(), collectId);
//存放队列消息
GenerateQueue(tasks, printParam, 5, collectId);
System.err.println("上传失败,见返回体");
}
log.info("轮询增加任务成功,id为:" + tasks.getId());
} catch (Exception e) {
log.error("轮询增加任务失败,id为:" + tasks.getId(), e);
}
}
return CommonResult.success("同步完成");
}
return CommonResult.success("轮询完成已经增加任务");
/**
* @Author: linjj
* @Description:
* @DateTime: 2025/9/25 16:18
* @Params: [list, scanPages]
* @Return java.util.List<com.example.duplicate.controller.param.FileMeta>
*/
private List<FileMeta> getFiles(CommomtableVo list, List<TscanAssortVo> scanPages) {
//文件信息集合
List<FileMeta> files = new ArrayList<>();
//组织文件信息集合
for (TscanAssortVo scanPage: scanPages){
files.add(new FileMeta(list.getFilePath()+ File.separatorChar+scanPage.getScanPage(), list.getPatientId(), list.getPatientId(),getID(),scanPage.getAssortId()));
}
return files;
}
@Override
public CommonResult<?> medicalCompensate() {
//查询未完成的首页任务
List<medicalCompensateVo> medicalCompensateVos = archiveOtherExtMapper.medicalCompensate(9);
if (CollectionUtils.isEmpty(medicalCompensateVos)) {
log.info("当前没有需要生成的首页任务");
return CommonResult.failed("当前没有需要生成的首页任务");
}
PrintParam printParam = new PrintParam();
//补偿任务
for (medicalCompensateVo tasks : medicalCompensateVos){
//存放队列消息
GenerateQueueCompensate(tasks, printParam, 1, tasks.getSysFlag());
}
return CommonResult.success("补偿任务完成");
}
//生成队列消息
private void GenerateQueue(ArchiveMasterVo task, PrintParam data, Integer ispriority, String collectid) {
data.setId(task.getId());
data.setInpNo(task.getInpNo());
data.setVisitId(task.getVisitId());
data.setJzh(task.getPatientId());
data.setDeptName(task.getDeptName());
data.setDischargeDateTime(task.getDischargeDateTime());
data.setName(task.getName());
data.setAdmissionDateTime(task.getAdmissionDateTime());
String key = String.format(redisKey, collectid, ispriority);
redisMq.push(key, JSON.toJSONString(data, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue));
}
//生成队列消息
private void GenerateQueueCompensate(medicalCompensateVo task, PrintParam data, Integer ispriority, String collectid) {
data.setId(task.getId());
data.setInpNo(task.getInpNo());
data.setVisitId(task.getVisitId());
data.setJzh(task.getPatientId());
data.setDeptName(task.getDeptName());
data.setDischargeDateTime(task.getDischargeDateTime());
data.setName(task.getName());
data.setAdmissionDateTime(task.getAdmissionDateTime());
String key = String.format(redisKey, collectid, ispriority);
redisMq.push(key, JSON.toJSONString(data, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue));
// private List<FileMeta> getFiles(CommomtableVo list, List<TscanAssortVo> scanPages) {
// List<FileMeta> files = new ArrayList<>();
// for (TscanAssortVo scanPage : scanPages) {
// // ① 原始值
// String rawName = scanPage.getScanPage();
// System.out.println("原始文件名 = |" + rawName + "|");
//
// // ② 拼好的完整路径
// File f = new File(list.getFilePath(), rawName);
// System.out.println(">>> 最终绝对路径 = " + f.getAbsolutePath());
// System.out.println(">>> 文件存在? = " + f.exists());
// System.out.println(">>> 是文件? = " + f.isFile());
// System.out.println(">>> 可读? = " + f.canRead());
//
// if (!f.exists()) {
// throw new RuntimeException("文件不存在: " + f.getAbsolutePath());
// }
//
// files.add(new FileMeta(
// f.getAbsolutePath(),
// list.getPatientId(),
// list.getPatientId(),
// getID(),
// scanPage.getAssortId()));
// }
// return files;
// }
/**
* @Author: linjj
* @Description:
* @DateTime: 2025/9/25 11:25
* @Params:
* @Return
*/
private String patientInfoSync(String ACCESS_TOKEN,CommomtableVo commomtableVo) throws Exception{
// 构造请求体 JSON
Map<String, Object> map = new HashMap<>();
map.put("UNIQUE_DENT_TYPE", 0);
map.put("PATIENT_ID", commomtableVo.getPatientId());
map.put("UNIQUE_IDENTIFIER", commomtableVo.getInpatientNo());
map.put("PATIENT_NAME", commomtableVo.getName());
map.put("ADMISSION_DATE_TIME", commomtableVo.getAdmissDate());
map.put("DISCHARGE_DATE_TIME", commomtableVo.getDisDate());
map.put("INSTITUTION_NAME", "中南大学湘雅二医院");
map.put("DEPT_ADMISSION_TO","null");
map.put("OUTP_OR_INP","2");
map.put("INP_NO",commomtableVo.getInpatientNo());
String json = JSON.toJSONString(map);
//创建 HttpClient 和 POST 请求
CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost(addPatientInfoAPIURL);
post.setHeader("Content-Type", "application/json");
post.setHeader("appId", APP_ID);
post.setHeader("accessKey", ACCESS_KEY); // 公钥
post.setHeader("plss-auth", ACCESS_TOKEN); // 认证 token
post.setEntity(new StringEntity(json, "UTF-8"));
//发送请求
try (CloseableHttpResponse resp = client.execute(post)) {
String body = EntityUtils.toString(resp.getEntity());
System.out.println("响应内容:" + body);
// 解析响应
JSONObject obj = JSON.parseObject(body);
String msg = obj.getString("msg");
if ("操作成功".equals(msg)) {
log.info("患者信息同步成功:"+commomtableVo.getPatientId());
return msg;
} else {
log.error("患者信息同步失败:"+commomtableVo.getPatientId()+"msg:"+msg);
return msg;
}
}
}
/**
* @Author: linjj
* @Description:token
* @Return String
*/
private String getToken() throws Exception{
String accessToken;
//构造 sk_validaccessKey + secretKey 拼接后做 MD5
String skValid = md5(ACCESS_KEY + SECRET_KEY);
String json = "{\"user_id\":null,\"sk_valid\":\"" + skValid + "\"}";
//HttpClient 实例
CloseableHttpClient client = HttpClients.createDefault();
//POST请求
HttpPost post = new HttpPost(tokenURL);
//设置请求头
post.setHeader("Content-Type", "application/json"); // JSON
post.setHeader("appId", APP_ID); // 应用 ID
post.setHeader("accessKey", ACCESS_KEY); // 公钥
post.setHeader("timestamp", String.valueOf(System.currentTimeMillis())); // 13 位时间戳
post.setHeader("plss-sign-type", "MD5"); // 签名算法
post.setHeader("plss-sign", md5(json + SECRET_KEY)); // 对 body+secretKey 再做 MD5
post.setEntity(new StringEntity(json, "UTF-8"));
//发送请求,拿到响应
try (CloseableHttpResponse resp = client.execute(post)) {
String body = EntityUtils.toString(resp.getEntity());
// 解析并校验
accessToken = parseToken(body);
}
return accessToken;
}
/**
* MD 32 MD5
*/
private static String md5(String raw) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(raw.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
}
/**
* msg access_token
* @Author: linjj
* @param respJson
* @return access_token
* @throws RuntimeException msg
*/
public static String parseToken(String respJson) {
JSONObject obj = JSON.parseObject(respJson);
String msg = obj.getString("msg");
if (!"操作成功".equals(msg)) {
throw new RuntimeException("获取 token 失败msg=" + msg);
}
JSONObject data = obj.getJSONObject("data");
String token = data.getString("access_token");
return token;
}
private String getID(){
//使用yyyyMMddHHmmssSSS格式作为文件名
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String newDate = format.format(date);
return newDate;
}
}

@ -1,330 +0,0 @@
package com.example.duplicate.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.example.duplicate.controller.param.*;
import com.example.duplicate.controller.vo.ArchiveMasterVo;
import com.example.duplicate.controller.vo.ArchiveOtherExtVo;
import com.example.duplicate.infrastructure.dao.ArchiveDetailMapper;
import com.example.duplicate.infrastructure.dao.ArchiveMasterMapper;
import com.example.duplicate.infrastructure.dao.ArchiveOtherExtMapper;
import com.example.duplicate.service.TaskService;
import com.example.utils.CommonResult;
import com.example.utils.RedisMq;
import com.example.utils.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
/**
* @ClassName TaskServiceImpl
* @Description
* @Author linjj
* @Date 2024/8/5 14:44
* @Version 1.0
*/
@Service
@Slf4j
public class TaskServiceImpl implements TaskService {
@Autowired(required = false)
private RedisMq redisMq;
private String redisKey = "docus:task:topic_collect_%s_queue:%s";
@Value("${repairCollectIds}")
private String repairCollectIds;
@Autowired
private ArchiveMasterMapper archiveMasterMapper;
@Autowired
private ArchiveOtherExtMapper archiveOtherExtMapper;
@Autowired
private ArchiveDetailMapper archiveDetailMapper;
@Autowired
private TaskService taskService;
@Value("${savePath}")
private String savePath;
@Override
public CommonResult GetTask(String collectId) {
String message = "";
for (int i = 10; i >= 1; i--) {
String key = String.format(redisKey, collectId, i);
message = redisMq.pop(key);
if (!StringUtils.isEmpty(message) && !message.equals("null")) {
break;
}
}
if (StringUtils.isEmpty(message) || message.equals("null")) {
return CommonResult.failed("暂无队列数据");
} else {
PrintParam data = JSON.parseObject(message, PrintParam.class);
log.info("采集器id为" + collectId + "的队列消费信息:" + data);
return CommonResult.success(data);
}
}
@Override
public CommonResult repairTask(String masterId) {
PrintParam printParam = new PrintParam();
//任务表入参
ArchiveOtherExtDto dto = new ArchiveOtherExtDto();
//任务生成时间
Date date = new Date();
SimpleDateFormat SycTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//补偿所有采集器id集合
List<String> collectIds = Arrays.asList(repairCollectIds.split(","));
//获取当前患者基础信息
List<ArchiveMasterVo> archiveMasters = archiveMasterMapper.getArchiveMasterByMasterId(masterId);
if (CollectionUtils.isEmpty(archiveMasters)) {
log.info("补偿所有采集查询不到masterId为:" + masterId + "的患者住院信息补偿失败");
return CommonResult.failed("补偿所有采集查询不到masterId为:" + masterId + "的患者住院信息补偿失败");
}
for (String collectId : collectIds) {
try {
//查询当前患者要补偿采集器是否存在任务,不存在时新增任务
List<ArchiveOtherExtVo> others = archiveOtherExtMapper.getOtherByMidAndFlag(archiveMasters.get(0).getId(), Integer.parseInt(collectId));
if (CollectionUtils.isEmpty(others)) {
//任务表新增
addOther(collectId, dto, date, SycTime, archiveMasters);
}
archiveOtherExtMapper.updateStatic(masterId, collectId);
GenerateQueue(archiveMasters.get(0), printParam, 10, collectId);
} catch (Exception e) {
log.error("masterId为:" + masterId + "的患者补偿所有采集器失败", e.getMessage(), e);
}
}
log.info("masterId为:" + masterId + "的患者所有采集器补偿成功");
return CommonResult.success("masterId为:" + masterId + "的患者所有采集器补偿成功");
}
@Override
public CommonResult repairTaskByCollectId(String masterId, String collectId) {
PrintParam printParam = new PrintParam();
//任务表入参
ArchiveOtherExtDto dto = new ArchiveOtherExtDto();
//任务生成时间
Date date = new Date();
SimpleDateFormat SycTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//获取当前患者基础信息
List<ArchiveMasterVo> archiveMasters = archiveMasterMapper.getArchiveMasterByMasterId(masterId);
if (CollectionUtils.isEmpty(archiveMasters)) {
log.info("补偿单个查询不到masterId为:" + masterId + "的患者住院信息补偿失败");
return CommonResult.failed("补偿单个查询不到masterId为:" + masterId + "的患者住院信息补偿失败");
}
//查询任务表数据是否存在不存在时任务表新增存在时将任务状态改为0
List<ArchiveOtherExtVo> others = archiveOtherExtMapper.getOtherByMidAndFlag(masterId, Integer.parseInt(collectId));
if (CollectionUtils.isEmpty(others)) {
addOther(collectId, dto, date, SycTime, archiveMasters);
} else {
archiveOtherExtMapper.updateStatic(masterId, collectId);
}
GenerateQueue(archiveMasters.get(0), printParam, 10, collectId);
log.info("补偿患者单个采集器成功masterId为:" + masterId + "的患者住院信息补偿成功");
return CommonResult.success("补偿患者单个采集器成功");
}
@Override
public CommonResult delFileBySource(String masterId, String collectId) {
try {
//根据患者masterIdcollectId删除
boolean stactic = archiveDetailMapper.delFileBySource(masterId, collectId);
if (stactic) {
return CommonResult.success("删除成功,masterId:" + masterId + "删除分类:" + collectId);
}
} catch (Exception e) {
log.error("删除接口失败:" + e.getMessage(), e);
return CommonResult.failed("删除失败,masterId:" + masterId + "删除分类:" + collectId);
}
return CommonResult.failed("删除失败,masterId:" + masterId + "删除分类:" + collectId);
}
@Override
public CommonResult updateTask(updateTaskDto dto) {
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String format = dateFormat.format(new Date());
log.info(format + "本次维护任务表传输参数为:" + JSONObject.toJSONString(dto));
if (StringUtils.isBlank(dto.getMid())) {
log.info(format + "Mid不能为空");
log.info(dto.getMid());
return CommonResult.failed("Mid名不能为空");
}
if (StringUtils.isBlank(dto.getStartTime())) {
log.info(format + "开始时间不能为空!");
return CommonResult.failed("开始时间不能为空");
}
if (StringUtils.isBlank(dto.getEndTime())) {
log.info(format + "结束时间不能为空!");
return CommonResult.failed("结束时间不能为空");
}
if (StringUtils.isBlank(String.valueOf(dto.getStatusFlag()))) {
log.info(format + "任务状态不能为空!");
return CommonResult.failed("任务状态不能为空");
}
if (StringUtils.isBlank(dto.getSycObj())) {
log.info(format + "SycObj患者信息不能为空");
return CommonResult.failed("SycObj患者信息不能为空");
}
if (StringUtils.isBlank(dto.getPinResult())) {
log.info(format + "备注信息不能为空!");
return CommonResult.failed("备注信息不能为空");
}
if (StringUtils.isBlank(String.valueOf(dto.getSysFlag()))) {
log.info(format + "任务分类不能为空!");
return CommonResult.failed("任务分类不能为空");
}
if (archiveOtherExtMapper.updateByMid(dto)) {
return CommonResult.success("id为:" + dto.getMid() + "任务表维护成功");
}
} catch (Exception e) {
log.error("维护任务表失败:" + dto.getMid() + "异常处理" + e.getMessage(), e);
}
return CommonResult.success("id为:" + dto.getMid() + "任务表维护失败");
}
@Override
public Boolean fileUpload(MultipartFile file, FileUpload dto) {
try {
//使用yyyyMMddHHmmssSSS格式作为文件名
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmssSSS");
String newDate = format.format(date);
//文件更新时间
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//文件保存目录
String filePathdir = savePath + File.separatorChar + dto.getMasterid();
File filePath = new File(filePathdir);
//判断文件夹是否存在不存在创建文件夹
if (!filePath.exists()) {
filePath.mkdirs();
}
//文件地址
String saveFilePath = filePathdir + File.separatorChar + newDate + ".pdf";
try {
file.transferTo(new File(saveFilePath));
} catch (IOException e) {
log.info("保存文件失败流水号:" + dto.getSubassort());
return false;
}
try {
//判断文件表是否存在流水号存则更新
List<ArchiveDetailDto> archiveDetailList = archiveDetailMapper.getDetailBySerialNumber(dto.getSoleKey());
if (!CollectionUtils.isEmpty(archiveDetailList)) {
log.info("保存文件接口存在删除记录:" + dto.getSubassort());
for (ArchiveDetailDto details : archiveDetailList) {
//存在删除对应记录
if (archiveDetailMapper.deleteByPrimaryKey(details.getId())) {
log.info("保存文件接口存在删除记录:" + dto.getSubassort());
File file1 = new File(details.getPdfPath());
try {
file1.delete(); // 删除照片
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//保存文件表
ArchiveDetailDto archiveDetail = new ArchiveDetailDto();
archiveDetail.setId(newDate);
archiveDetail.setPdfPath(saveFilePath);
archiveDetail.setMasterid(dto.getMasterid());
archiveDetail.setUploaddatetime(dateFormat.format(new Date()));
archiveDetail.setAssortid(dto.getAssortid());
archiveDetail.setSource(dto.getSource());
archiveDetail.setSubassort(dto.getSubassort());
archiveDetail.setTitle(dto.getTitle());
archiveDetail.setFlag("0");
archiveDetail.setC1(dto.getC1());
archiveDetail.setSoleKey(dto.getSoleKey());
if (archiveDetailMapper.insertSel(archiveDetail)) {
return true;
}
} catch (Exception e) {
log.error("异常处理:" + e.getMessage(), e);
return false;
}
} catch (Exception e) {
log.error("异常处理:" + e.getMessage(), e);
}
return false;
}
@Override
public CommonResult compensate(String startTime, String entTime, String collectId) {
//查询所有需要补偿患者id
List<String> ids = archiveMasterMapper.getMasterid(startTime, entTime);
for (String masterId : ids) {
PrintParam printParam = new PrintParam();
//任务表入参
ArchiveOtherExtDto dto = new ArchiveOtherExtDto();
//任务生成时间
Date date = new Date();
SimpleDateFormat SycTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//获取当前患者基础信息
List<ArchiveMasterVo> archiveMasters = archiveMasterMapper.getArchiveMasterByMasterId(masterId);
if (CollectionUtils.isEmpty(archiveMasters)) {
log.info("补偿所有采集查询不到masterId为:" + masterId + "的患者补偿采集器id为:"+collectId+"失败");
continue;
}
try {
//查询当前患者要补偿采集器是否存在任务,不存在时新增任务
List<ArchiveOtherExtVo> others = archiveOtherExtMapper.getOtherByMidAndFlag(archiveMasters.get(0).getId(), Integer.parseInt(collectId));
if (CollectionUtils.isEmpty(others)) {
addOther(collectId, dto, date, SycTime, archiveMasters);
}
//存在任务表中修改任务表状态
archiveOtherExtMapper.updateStatic(masterId, collectId);
GenerateQueue(archiveMasters.get(0), printParam, 10, collectId);
} catch (Exception e) {
log.error("masterId为:" + masterId + "的患者补偿采集器id为:"+collectId+"失败", e.getMessage(), e);
}
log.info("masterId为:" + masterId + "的患者补偿采集器id为:"+collectId+"成功");
}
return CommonResult.success("补偿完成");
}
private void addOther(String collectId, ArchiveOtherExtDto dto, Date date, SimpleDateFormat SycTime, List<ArchiveMasterVo> archiveMasters) {
//任务表新增
dto.setId(SnowflakeIdWorker.idWorker.nextId());
dto.setSycTime(SycTime.format(date));
dto.setOtherID("0");
dto.setSysFlag(Integer.parseInt(collectId));
dto.setSysUpdateTime(SycTime.format(date));
dto.setJzh(archiveMasters.get(0).getPatientId());
dto.setZyh(archiveMasters.get(0).getInpNo());
dto.setStatusFlag(0);
dto.setMID(archiveMasters.get(0).getId());
archiveOtherExtMapper.addOther(dto);
}
//生成队列消息
private void GenerateQueue(ArchiveMasterVo task, PrintParam data, Integer ispriority, String collectid) {
data.setId(task.getId());
data.setInpNo(task.getInpNo());
data.setVisitId(task.getVisitId());
data.setJzh(task.getPatientId());
data.setDeptName(task.getDeptName());
data.setDischargeDateTime(task.getDischargeDateTime());
data.setName(task.getName());
data.setAdmissionDateTime(task.getAdmissionDateTime());
String key = String.format(redisKey, collectid, ispriority);
redisMq.push(key, JSON.toJSONString(data, SerializerFeature.WriteDateUseDateFormat, SerializerFeature.WriteMapNullValue));
}
}

@ -1,54 +0,0 @@
package com.example.quartz;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @ClassName CollectorConfig
* @Description
* @Author linjj
* @Date 2024/8/2 14:45
* @Version 1.0
*/
@Configuration
public class CollectorConfig {
@Value("${medicalAdviceTime}")
private String medicalAdviceTime;
@Bean
public JobDetail MedicalAdvice() {
return JobBuilder.newJob(MedicalAdviceQuartz.class).withIdentity("MedicalAdviceQuartz").storeDurably().build();
}
@Bean
public Trigger pacsPushTrigger() {
return TriggerBuilder.newTrigger().forJob(MedicalAdvice())
.withIdentity("MedicalAdviceQuartz")
.withSchedule(CronScheduleBuilder.cronSchedule(medicalAdviceTime))
.build();
}
/* ------------------ 每天凌晨 0 点 ------------------ */
@Bean
public JobDetail dailyJob() {
return JobBuilder.newJob(DailyTaskQuartz.class)
.withIdentity("DailyTaskQuartz")
.storeDurably()
.build();
}
@Bean
public Trigger dailyTrigger() {
return TriggerBuilder.newTrigger()
.forJob(dailyJob())
.withIdentity("DailyTaskQuartzTrigger")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0 0 * * ?")) // 每天 00:00:00
.build();
}
}

@ -1,31 +0,0 @@
package com.example.quartz;
import com.example.duplicate.service.MedicalAdviceService;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;
import javax.annotation.Resource;
/**
* @ClassName DailyTaskQuartz
* @Description
* @Author linjj
* @Date 2025/7/25 14:24
* @Version 1.0
*/
public class DailyTaskQuartz extends QuartzJobBean {
@Resource
private MedicalAdviceService medicalAdviceService;
/**
*
* @param jobExecutionContext
* @throws JobExecutionException
*/
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
medicalAdviceService.medicalCompensate();
}
}

@ -1,28 +0,0 @@
package com.example.quartz;
import com.example.duplicate.service.MedicalAdviceService;
import com.example.utils.CommonResult;
import org.quartz.JobExecutionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import javax.annotation.Resource;
/**
* @description:
* @author linjj
* @date: 2024/8/2 15:46
*/
public class MedicalAdviceQuartz extends QuartzJobBean {
@Resource
private MedicalAdviceService medicalAdviceService;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) {
//每半小时轮询一次基础表增加任务
medicalAdviceService.pollingAddTask();
}
}

@ -0,0 +1,100 @@
package com.example.utils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.ofdrw.layout.OFDDoc;
import org.ofdrw.layout.PageLayout;
import org.ofdrw.layout.element.*;
import org.ofdrw.layout.element.canvas.Canvas;
import org.ofdrw.core.basicStructure.pageObj.Page;
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.Tesseract;
import net.sourceforge.tess4j.Word;
import org.ofdrw.layout.element.canvas.Drawer;
import org.ofdrw.layout.element.canvas.FontSetting;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
/**
* @ClassName PdfToDoubleLayerOFD
* @Description
* @Author linjj
* @Date 2025/8/4 14:53
* @Version 1.0
*/
public class PdfToDoubleLayerOFD {
public static void main(String[] args) throws Exception {
String pdfPath = "E:\\work\\pdf\\1.pdf"; // 源 PDF
String ofdPath = "E:\\work\\pdf\\2.ofd"; // 目标 OFD
String tessPath = "E:\\work\\ocr"; // Tesseract 语言包目录
//加载 PDF
PDDocument pdfDoc = PDDocument.load(new File(pdfPath));
PDFRenderer renderer = new PDFRenderer(pdfDoc);
//初始化 OCR
ITesseract tesseract = new Tesseract();
tesseract.setDatapath(tessPath);
tesseract.setLanguage("chi_sim+eng");
try (OFDDoc ofdDoc = new OFDDoc(Paths.get(ofdPath))) {
for (int i = 0; i < pdfDoc.getNumberOfPages(); i++) {
try {
BufferedImage image = renderer.renderImageWithDPI(i, 150);
if (image == null) {
System.err.println("警告: 第 " + (i+1) + " 页渲染失败");
continue;
}
File tempImage = File.createTempFile("page", ".png");
ImageIO.write(image, "png", tempImage);
PageLayout layout = new PageLayout((double) image.getWidth(), (double) image.getHeight());
ofdDoc.setDefaultPageLayout(layout);
// 添加图像层
ofdDoc.add(new Img(tempImage.toPath())
.setPosition(Position.Absolute)
.setX(0d).setY(0d)
.setWidth((double) image.getWidth())
.setHeight((double) image.getHeight()));
// 添加文字层
Canvas canvas = new Canvas((double) image.getWidth(), (double) image.getHeight());
int finalI = i;
canvas.setDrawer(ctx -> {
try {
List<Word> words = tesseract.getWords(image, ITesseract.RenderedFormat.HOCR.ordinal());
if (words.isEmpty()) {
System.err.println("警告: 第 " + (finalI +1) + " 页OCR未识别到文字");
}
for (Word word : words) {
double x = word.getBoundingBox().getX();
double y = image.getHeight() - word.getBoundingBox().getY() - word.getBoundingBox().getHeight();
ctx.setFont(FontSetting.getInstance(8.0));
ctx.setFillColor(0, 0, 0);
ctx.fillText(word.getText(), x, y);
}
} catch (Exception e) {
System.err.println("OCR处理错误: " + e.getMessage());
}
});
ofdDoc.add(canvas);
} catch (Exception e) {
System.err.println("处理第 " + (i+1) + " 页时出错: " + e.getMessage());
e.printStackTrace();
}
}
}
pdfDoc.close();
System.out.println("✅ 双层 OFD 完成:" + ofdPath);
}
}

@ -3,9 +3,9 @@ server:
spring:
datasource:
url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=emr_record
url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=gm_record
username: sa
password: docus@702
password: admin123
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=gm_record
# username: sa
# password: admin123
@ -17,29 +17,7 @@ spring:
#加快springboot初始化关闭jmx监控
jmx:
enabled: false
redis:
# Redis 服务器地址
host: redis.docus.cn
# host: 127.0.0.1
# 连接端口号
port: 6379
# #密码
# password: JSdocus@702
# 数据库索引0 - 15
database: 0
# 连接超时时间(毫秒)
timeout: 10000
# lettuce 参数
lettuce:
pool:
# 最大连接数(使用负值表示没有限制) 默认为 8
max-active: 10
# 最大阻塞等待时间(使用负值表示没有限制) 默认为 -1 ms
max-wait: -1
# 最大空闲连接 默认为 8
max-idle: 5
# 最小空闲连接 默认为 0
min-idle: 0
mybatis:
mapper-locations: classpath*:mapper/*Mapper.xml
@ -53,15 +31,19 @@ logging:
com.example.mapper: info
#网关
DOMAIN_URL : http://demo.zoyheal.com:30080/plss/prod-api
#应用标识id
APP_ID : 457789320062469
#公钥
ACCESS_KEY : 9fc11b8fd8caa03b778fa262bc2315f6a46e1119
#私钥
SECRET_KEY : 2665b762c85066689a61aab5b7c414143240a6643242a9046fac3cbf87d2af2c48af392e967f1834cb5be32f436714a0e802a70ea7dd668657a94665663f8cbf
#获取tokenAPI
tokenAPI : /open/med/v1/appid/auth
#患者信息同步接口API
addPatientInfoAPI: /open/med/medrecord_archiving/v1/medPatientInfo/addPatientInfo
#文件上传接口API
emrUploadAPI: /open/med/medreslibrar/v1/file/emrUploadV2
#定时轮速新增任务
medicalAdviceTime: 0 0/30 * * * ?
#medicalAdviceTime: 0/1 * * * * ?
#定时轮询时需要新增的采集标识
collectIdList: 1, 2,8
#补偿时,需要补偿的采集器标识,可以支持多个使用逗号','隔开
repairCollectIds: 1,2,8
#文件保存地址
savePath: D:\reload
#首页补偿v
medicalCompensate: 0 0 0 * * ?

@ -14,7 +14,7 @@
<Prudent>true</Prudent>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>
collector/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log
fushu/%d{yyyy-MM-dd}/%d{yyyy-MM-dd}.log
</FileNamePattern>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">

@ -1,96 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.duplicate.infrastructure.dao.ArchiveDetailMapper">
<insert id="insertSel">
insert into archive_detail
<trim prefix="(" suffix=")" suffixOverrides=",">
id,
<if test="pdfPath != null">
PDF_PATH,
</if>
<if test="masterid != null">
MasterID,
</if>
<if test="uploaddatetime != null">
UpLoadDateTime,
</if>
<if test="assortid != null">
AssortID,
</if>
<if test="source != null">
Source,
</if>
<if test="subassort != null">
SubAssort,
</if>
<if test="title != null">
Title,
</if>
<if test="flag != null">
flag,
</if>
<if test="sys != null">
Sys,
</if>
<if test="C1 != null">
C1,
</if>
<if test="SoleKey != null">
SoleKey,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<!--<if test="id != null and id!=''">-->
(select replace(newid(),'-','')),
<!--</if>-->
<if test="pdfPath != null">
#{pdfPath,jdbcType=NVARCHAR},
</if>
<if test="masterid != null">
#{masterid,jdbcType=NVARCHAR},
</if>
<if test="uploaddatetime != null">
#{uploaddatetime,jdbcType=NVARCHAR},
</if>
<if test="assortid != null">
#{assortid,jdbcType=NVARCHAR},
</if>
<if test="source != null">
#{source,jdbcType=NVARCHAR},
</if>
<if test="subassort != null">
#{subassort,jdbcType=NVARCHAR},
</if>
<if test="title != null">
#{title,jdbcType=NVARCHAR},
</if>
<if test="flag != null">
#{flag,jdbcType=NVARCHAR},
</if>
<if test="sys != null">
#{sys,jdbcType=NVARCHAR},
</if>
<if test="C1 != null">
#{C1,jdbcType=NVARCHAR},
</if>
<if test="SoleKey != null">
#{SoleKey,jdbcType=NVARCHAR},
</if>
</trim>
</insert>
<delete id="deleteByPrimaryKey">
delete from archive_detail
where id = #{id,jdbcType=NVARCHAR}
</delete>
<delete id="delFileBySource">
delete from archive_detail
where MasterID = #{masterId} AND Source IN (#{collectId, jdbcType=NVARCHAR})
</delete>
<select id="getDetailBySerialNumber" resultType="com.example.duplicate.controller.param.ArchiveDetailDto">
select * from archive_detail where SoleKey=#{serialNumber}
</select>
</mapper>

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.duplicate.infrastructure.dao.ArchiveMasterMapper">
<select id="getMedicalAdviceTask" resultType="com.example.duplicate.controller.vo.ArchiveMasterVo">
SELECT *
from archive_master
WHERE discharge_date_time >= dateadd(minute,-30, GETDATE())
</select>
<select id="getArchiveMasterByMasterId" resultType="com.example.duplicate.controller.vo.ArchiveMasterVo">
select *
from archive_master
where id = #{masterId}
</select>
<select id="getMasterid" resultType="java.lang.String">
select id from archive_master WHERE discharge_date_time>=#{startTime} and discharge_date_time &lt;=#{entTime}
</select>
</mapper>

@ -1,121 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.duplicate.infrastructure.dao.ArchiveOtherExtMapper">
<insert id="addOther">
insert into archive_other_ext
<trim prefix="(" suffix=")" suffixOverrides="," >
<if test="id != null" >
ID,
</if>
<if test="SycTime != null" >
SycTime,
</if>
<if test="otherID != null" >
otherID,
</if>
<if test="sysFlag != null" >
sysFlag,
</if>
<if test="sysUpdateTime != null" >
sysUpdateTime,
</if>
<if test="jzh != null" >
jzh,
</if>
<if test="zyh != null" >
zyh,
</if>
<if test="statusFlag != null" >
statusFlag,
</if>
<if test="MID != null" >
MID,
</if>
<if test="C1 != null" >
C1,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides="," >
<if test="id != null" >
#{id},
</if>
<if test="SycTime != null" >
#{SycTime},
</if>
<if test="otherID != null" >
#{otherID},
</if>
<if test="sysFlag != null" >
#{sysFlag},
</if>
<if test="sysUpdateTime != null" >
#{sysUpdateTime},
</if>
<if test="jzh != null" >
#{jzh},
</if>
<if test="zyh != null" >
#{zyh},
</if>
<if test="statusFlag != null" >
#{statusFlag},
</if>
<if test="MID != null" >
#{MID},
</if>
<if test="C1 != null" >
#{C1},
</if>
</trim>
</insert>
<select id="getOtherByMidAndFlag" resultType="com.example.duplicate.controller.vo.ArchiveOtherExtVo">
select * from archive_other_ext where MID=#{mid} and sysFlag=#{sysFlag}
</select>
<select id="medicalCompensate" resultType="com.example.duplicate.controller.vo.medicalCompensateVo">
SELECT
a.*,other.ID as otherId,other.sysFlag
FROM
archive_other_ext other
LEFT JOIN archive_master a ON a.id = other.MID
WHERE
statusFlag = #{statusFlag}
AND a.discharge_date_time >= DATEADD(DAY, -1, GETDATE()) -- 24小时前
AND a.discharge_date_time &lt; GETDATE() -- 不包含未来
</select>
<update id="updateByMid">
update archive_other_ext
<set >
<if test="sycObj != null" >
SycObj = #{sycObj},
</if>
<if test="startTime != null" >
stime = #{startTime},
</if>
<if test="endTime != null" >
eTime = #{endTime},
</if>
<if test="statusFlag != null" >
statusFlag = #{statusFlag},
</if>
<if test="pinResult != null" >
pResult = #{pinResult},
</if>
<if test="errorInfo != null" >
errorInfo = #{errorInfo},
</if>
<if test="errorImage != null" >
errorImage = #{errorImage},
</if>
</set>
where MID = #{mid} and sysFlag=#{sysFlag}
</update>
<update id="updateStatic">
update archive_other_ext set statusFlag=0 where MID = #{mid} and sysFlag=#{sysFlag}
</update>
</mapper>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.duplicate.infrastructure.dao.CommomtableMapper">
<select id="getCommomtable" resultType="com.example.duplicate.controller.vo.CommomtableVo">
select * from commomtable WHERE dis_date>=#{startTime} and dis_date &lt;=#{entTime}
</select>
</mapper>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.duplicate.infrastructure.dao.TscanAssortMapper">
<select id="getScanPage" resultType="com.example.duplicate.controller.vo.TscanAssortVo">
SELECT * FROM t_scan_assort WHERE patient_id=#{patientId} AND is_del=#{isDel}
</select>
</mapper>

@ -1,47 +1,171 @@
package com.example;
import com.example.utils.Md5Util;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
@RunWith(SpringRunner.class)
@Slf4j
@SpringBootTest(classes = com.example.SpringbootDemoApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoApplicationTests {
//网关
@Value("${DOMAIN_URL}")
private String DOMAIN_URL;
//应用id
@Value("${APP_ID}")
private String APP_ID;
//公钥
@Value("${ACCESS_KEY}")
private String ACCESS_KEY;
//私钥
@Value("${SECRET_KEY}")
private String SECRET_KEY;
@Value("${tokenAPI}")
private String tokenAPI;
@Value("${addPatientInfoAPI}")
private String addPatientInfoAPI;
@Value("${emrUploadAPI}")
private String emrUploadAPI;
@Test
public void contextLoads() {
String jpgPath = "E:\\pdf\\1\\2.jpg";
// 输出 PDF 文件路径
String pdfPath = "E:\\pdf\\2\\2.pdf";
public void contextLoads() throws Exception{
//根据出院的时间范围查询患者基础数据
String ACCESS_TOKEN = getToken();
log.info("获取 token 成功:" + ACCESS_TOKEN);
String result = patientInfoSync(ACCESS_TOKEN);
if (!result.equals("操作成功")){
return;
}
try (PDDocument document = new PDDocument()) {
PDPage page = new PDPage(PDRectangle.A4);
document.addPage(page);
}
/**
* @Author: linjj
* @Description:
* @DateTime: 2025/9/25 11:25
* @Params:
* @Return
*/
public String patientInfoSync(String ACCESS_TOKEN) throws Exception{
// 完整 URL网关地址 + 接口路径
String addPatientInfoAPIURL= DOMAIN_URL+addPatientInfoAPI;
// 构造请求体 JSON
Map<String, Object> map = new HashMap<>();
map.put("UNIQUE_DENT_TYPE", 0);
map.put("PATIENT_ID", "12345678");
map.put("UNIQUE_IDENTIFIER", "12345601");
map.put("PATIENT_NAME", "李四");
map.put("ADMISSION_DATE_TIME", "2020-03-18 14:30:00");
map.put("INSTITUTION_NAME", "北京XXX医院");
map.put("DEPT_ADMISSION_TO","妇科");
String json = JSON.toJSONString(map);
//创建 HttpClient 和 POST 请求
CloseableHttpClient client = HttpClients.createDefault();
HttpPost post = new HttpPost(addPatientInfoAPIURL);
post.setHeader("Content-Type", "application/json");
post.setHeader("appId", APP_ID);
post.setHeader("accessKey", ACCESS_KEY); // 公钥
post.setHeader("plss-auth", ACCESS_TOKEN); // 认证 token
post.setEntity(new StringEntity(json, "UTF-8"));
//发送请求
try (CloseableHttpResponse resp = client.execute(post)) {
String body = EntityUtils.toString(resp.getEntity());
System.out.println("响应内容:" + body);
// 解析响应
JSONObject obj = JSON.parseObject(body);
String msg = obj.getString("msg");
if ("操作成功".equals(msg)) {
System.out.println("✅ 患者信息同步成功!");
return msg;
} else {
System.err.println("❌ 同步失败msg=" + msg);
return msg;
}
}
}
/**
* @Author: linjj
* @Description:token
* @Return String
*/
public String getToken() throws Exception{
String accessToken;
// 完整 URL网关地址 + 接口路径
String tokenURL= DOMAIN_URL+tokenAPI;
//构造 sk_validaccessKey + secretKey 拼接后做 MD5
String skValid = md5(ACCESS_KEY + SECRET_KEY);
String json = "{\"user_id\":null,\"sk_valid\":\"" + skValid + "\"}";
//HttpClient 实例
CloseableHttpClient client = HttpClients.createDefault();
//POST请求
HttpPost post = new HttpPost(tokenURL);
//设置请求头
post.setHeader("Content-Type", "application/json"); // JSON
post.setHeader("appId", APP_ID); // 应用 ID
post.setHeader("accessKey", ACCESS_KEY); // 公钥
post.setHeader("timestamp", String.valueOf(System.currentTimeMillis())); // 13 位时间戳
post.setHeader("plss-sign-type", "MD5"); // 签名算法
post.setHeader("plss-sign", md5(json + SECRET_KEY)); // 对 body+secretKey 再做 MD5
post.setEntity(new StringEntity(json, "UTF-8"));
//发送请求,拿到响应
try (CloseableHttpResponse resp = client.execute(post)) {
String body = EntityUtils.toString(resp.getEntity());
// 解析并校验
accessToken = parseToken(body);
}
return accessToken;
}
PDImageXObject pdImage = PDImageXObject.createFromFile(jpgPath, document);
try (PDPageContentStream contentStream = new PDPageContentStream(document, page)) {
// 设置图片的位置和大小
contentStream.drawImage(pdImage, 0, 0, pdImage.getWidth(), pdImage.getHeight());
/**
* MD 32 MD5
*/
private static String md5(String raw) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] bytes = md.digest(raw.getBytes("UTF-8"));
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b & 0xff));
}
document.save(pdfPath);
} catch (IOException e) {
e.printStackTrace();
return sb.toString();
}
/**
* msg access_token
* @Author: linjj
* @param respJson
* @return access_token
* @throws RuntimeException msg
*/
public static String parseToken(String respJson) {
JSONObject obj = JSON.parseObject(respJson);
String msg = obj.getString("msg");
if (!"操作成功".equals(msg)) {
throw new RuntimeException("获取 token 失败msg=" + msg);
}
JSONObject data = obj.getJSONObject("data");
String token = data.getString("access_token");
return token;
}
}

Loading…
Cancel
Save