diff --git a/intc-common/intc-common-message/pom.xml b/intc-common/intc-common-message/pom.xml new file mode 100644 index 0000000..08b95d8 --- /dev/null +++ b/intc-common/intc-common-message/pom.xml @@ -0,0 +1,65 @@ + + + + com.intc + intc-common + 3.6.3 + + 4.0.0 + + intc-common-message + + + intc-common-message 消息通知服务(短信、语音等) + + + + + + com.aliyun + dysmsapi20170525 + 2.0.24 + + + + + com.aliyun + dyvmsapi20170525 + 3.2.2 + + + + + com.aliyun + tea-openapi + 0.3.4 + + + + + org.springframework.boot + spring-boot-starter + + + + + org.projectlombok + lombok + + + + + com.alibaba.fastjson2 + fastjson2 + + + + + com.intc + intc-common-core + + + + \ No newline at end of file diff --git a/intc-common/intc-common-message/src/main/java/com/intc/common/message/config/AliyunMessageProperties.java b/intc-common/intc-common-message/src/main/java/com/intc/common/message/config/AliyunMessageProperties.java new file mode 100644 index 0000000..443b7c0 --- /dev/null +++ b/intc-common/intc-common-message/src/main/java/com/intc/common/message/config/AliyunMessageProperties.java @@ -0,0 +1,77 @@ +package com.intc.common.message.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 阿里云消息服务配置 + * + * @author bot5 + * @date 2026-03-29 + */ +@Data +@ConfigurationProperties(prefix = "aliyun.message") +public class AliyunMessageProperties { + + /** + * 阿里云 AccessKey ID + */ + private String accessKeyId; + + /** + * 阿里云 AccessKey Secret + */ + private String accessKeySecret; + + /** + * 短信服务配置 + */ + private SmsConfig sms = new SmsConfig(); + + /** + * 语音服务配置 + */ + private VoiceConfig voice = new VoiceConfig(); + + @Data + public static class SmsConfig { + /** + * 短信签名名称 + */ + private String signName; + + /** + * 短信模板CODE(用药提醒) + */ + private String medicationRemindTemplateCode; + + /** + * 短信模板CODE(漏服提醒) + */ + private String missedRemindTemplateCode; + + /** + * 短信模板CODE(家属通知) + */ + private String familyNotifyTemplateCode; + } + + @Data + public static class VoiceConfig { + /** + * 语音通知模板CODE(用药提醒) + */ + private String medicationRemindTtsCode; + + /** + * 语音通知模板CODE(漏服提醒) + */ + private String missedRemindTtsCode; + + /** + * 被叫号码显示的呼入号码 + */ + private String calledShowNumber; + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseManageController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseManageController.java new file mode 100644 index 0000000..0903973 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseManageController.java @@ -0,0 +1,116 @@ +package com.intc.health.controller; + +import com.intc.common.core.web.controller.BaseController; +import com.intc.common.core.web.domain.AjaxResult; +import com.intc.common.core.web.page.TableDataInfo; +import com.intc.common.log.annotation.Log; +import com.intc.common.log.enums.BusinessType; +import com.intc.common.security.annotation.RequiresPermissions; +import com.intc.health.domain.ChronicDiseaseFollowUpRecord; +import com.intc.health.domain.ChronicDiseaseIndicatorRecord; +import com.intc.health.domain.ChronicDiseaseStatusHistory; +import com.intc.health.service.IChronicDiseaseManageService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +@Api(tags = "慢性疾病管理扩展") +@RestController +@RequestMapping("/chronicDiseaseManage") +public class ChronicDiseaseManageController extends BaseController { + @Resource + private IChronicDiseaseManageService chronicDiseaseManageService; + + @ApiOperation("查询慢病指标记录") + @RequiresPermissions("health:chronicDisease:list") + @GetMapping("/indicator/list") + public TableDataInfo indicatorList(ChronicDiseaseIndicatorRecord query) { + startPage(); + List list = chronicDiseaseManageService.selectIndicatorList(query); + return getDataTable(list); + } + + @ApiOperation("查询慢病指标详情") + @RequiresPermissions("health:chronicDisease:query") + @GetMapping("/indicator/{id}") + public AjaxResult indicatorInfo(@PathVariable Long id) { + return success(chronicDiseaseManageService.selectIndicatorById(id)); + } + + @ApiOperation("新增慢病指标记录") + @RequiresPermissions("health:chronicDisease:add") + @Log(title = "慢性疾病指标记录", businessType = BusinessType.INSERT) + @PostMapping("/indicator") + public AjaxResult indicatorAdd(@RequestBody ChronicDiseaseIndicatorRecord record) { + return toAjax(chronicDiseaseManageService.insertIndicator(record)); + } + + @ApiOperation("修改慢病指标记录") + @RequiresPermissions("health:chronicDisease:edit") + @Log(title = "慢性疾病指标记录", businessType = BusinessType.UPDATE) + @PutMapping("/indicator") + public AjaxResult indicatorEdit(@RequestBody ChronicDiseaseIndicatorRecord record) { + return toAjax(chronicDiseaseManageService.updateIndicator(record)); + } + + @ApiOperation("删除慢病指标记录") + @RequiresPermissions("health:chronicDisease:remove") + @Log(title = "慢性疾病指标记录", businessType = BusinessType.DELETE) + @DeleteMapping("/indicator/{ids}") + public AjaxResult indicatorRemove(@PathVariable Long[] ids) { + return toAjax(chronicDiseaseManageService.deleteIndicatorByIds(ids)); + } + + @ApiOperation("查询复诊随访记录") + @RequiresPermissions("health:chronicDisease:list") + @GetMapping("/followUp/list") + public TableDataInfo followUpList(ChronicDiseaseFollowUpRecord query) { + startPage(); + List list = chronicDiseaseManageService.selectFollowUpList(query); + return getDataTable(list); + } + + @ApiOperation("新增复诊随访记录") + @RequiresPermissions("health:chronicDisease:add") + @Log(title = "慢性疾病复诊随访", businessType = BusinessType.INSERT) + @PostMapping("/followUp") + public AjaxResult followUpAdd(@RequestBody ChronicDiseaseFollowUpRecord record) { + return toAjax(chronicDiseaseManageService.insertFollowUp(record)); + } + + @ApiOperation("修改复诊随访记录") + @RequiresPermissions("health:chronicDisease:edit") + @Log(title = "慢性疾病复诊随访", businessType = BusinessType.UPDATE) + @PutMapping("/followUp") + public AjaxResult followUpEdit(@RequestBody ChronicDiseaseFollowUpRecord record) { + return toAjax(chronicDiseaseManageService.updateFollowUp(record)); + } + + @ApiOperation("删除复诊随访记录") + @RequiresPermissions("health:chronicDisease:remove") + @Log(title = "慢性疾病复诊随访", businessType = BusinessType.DELETE) + @DeleteMapping("/followUp/{ids}") + public AjaxResult followUpRemove(@PathVariable Long[] ids) { + return toAjax(chronicDiseaseManageService.deleteFollowUpByIds(ids)); + } + + @ApiOperation("查询状态变更历史") + @RequiresPermissions("health:chronicDisease:list") + @GetMapping("/statusHistory/list") + public TableDataInfo statusHistoryList(ChronicDiseaseStatusHistory query) { + startPage(); + List list = chronicDiseaseManageService.selectStatusHistoryList(query); + return getDataTable(list); + } + + @ApiOperation("新增状态变更历史") + @RequiresPermissions("health:chronicDisease:edit") + @Log(title = "慢性疾病状态变更", businessType = BusinessType.INSERT) + @PostMapping("/statusHistory") + public AjaxResult statusHistoryAdd(@RequestBody ChronicDiseaseStatusHistory record) { + return toAjax(chronicDiseaseManageService.insertStatusHistory(record)); + } +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/StatisticAnalysisController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/StatisticAnalysisController.java index 6e58e80..8efe3e6 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/controller/StatisticAnalysisController.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/StatisticAnalysisController.java @@ -8,9 +8,12 @@ import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.util.Map; /** @@ -46,6 +49,20 @@ public class StatisticAnalysisController extends BaseController { return AjaxResult.success(resultMap); } + @ApiOperation("活动统计分析") + @GetMapping("/activityAnalysis") + public Map getActivityAnalysis(AnalysisDto analysisDto){ + Map resultMap = iStatisticAnalysisService.getActivityAnalysis(analysisDto); + return AjaxResult.success(resultMap); + } + + @ApiOperation("健康总览大屏") + @GetMapping("/healthScreen") + public Map getHealthScreen(AnalysisDto analysisDto){ + Map resultMap = iStatisticAnalysisService.getHealthScreen(analysisDto); + return AjaxResult.success(resultMap); + } + @ApiOperation("档案统计分析") @GetMapping("/recordAnalysis") public Map getRecordAnalysis(AnalysisDto analysisDto){ @@ -53,6 +70,19 @@ public class StatisticAnalysisController extends BaseController { return AjaxResult.success(resultMap); } + @ApiOperation("健康档案大屏") + @GetMapping("/recordScreen") + public Map getRecordScreen(AnalysisDto analysisDto){ + Map resultMap = iStatisticAnalysisService.getRecordScreen(analysisDto); + return AjaxResult.success(resultMap); + } + + @ApiOperation("导出健康档案完整信息") + @PostMapping("/recordFullExport") + public void exportRecordFull(HttpServletResponse response, AnalysisDto analysisDto) throws IOException { + iStatisticAnalysisService.exportRecordFull(response, analysisDto); + } + @ApiOperation("就医统计分析") @GetMapping("/doctorAnalysis") public Map getDoctorAnalysis(AnalysisDto analysisDto){ diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseFollowUpRecord.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseFollowUpRecord.java new file mode 100644 index 0000000..a28a10e --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseFollowUpRecord.java @@ -0,0 +1,58 @@ +package com.intc.health.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.intc.common.core.web.domain.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("慢性疾病复诊随访记录") +public class ChronicDiseaseFollowUpRecord extends BaseEntity { + private Long id; + + @ApiModelProperty("慢性疾病档案ID") + private Long chronicDiseaseId; + + @ApiModelProperty("成员ID") + private Long personId; + + @ApiModelProperty("类型:1-复诊 2-复查 3-随访") + private Integer followUpType; + + @JsonFormat(pattern = "yyyy-MM-dd") + @ApiModelProperty("复诊/随访日期") + private Date followUpDate; + + private String hospital; + + private String department; + + private String doctor; + + @ApiModelProperty("复查项目") + private String checkItems; + + @ApiModelProperty("结果") + private String result; + + @JsonFormat(pattern = "yyyy-MM-dd") + @ApiModelProperty("下次复诊日期") + private Date nextFollowUpDate; + + @ApiModelProperty("状态:1-待完成 2-已完成 3-已过期") + private Integer status; + + @ApiModelProperty("说明") + private String notes; + + private Integer delFlag; + + private String startTime; + + private String endTime; +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseIndicatorRecord.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseIndicatorRecord.java new file mode 100644 index 0000000..449c6e7 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseIndicatorRecord.java @@ -0,0 +1,58 @@ +package com.intc.health.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.intc.common.core.web.domain.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("慢性疾病指标记录") +public class ChronicDiseaseIndicatorRecord extends BaseEntity { + private Long id; + + @ApiModelProperty("慢性疾病档案ID") + private Long chronicDiseaseId; + + @ApiModelProperty("成员ID") + private Long personId; + + @ApiModelProperty("指标类型") + private String indicatorType; + + @ApiModelProperty("指标名称") + private String indicatorName; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("测量时间") + private Date measureTime; + + @ApiModelProperty("指标值") + private BigDecimal indicatorValue; + + @ApiModelProperty("指标单位") + private String indicatorUnit; + + @ApiModelProperty("目标下限") + private BigDecimal targetMin; + + @ApiModelProperty("目标上限") + private BigDecimal targetMax; + + @ApiModelProperty("状态:1-正常 2-偏高 3-偏低 4-需关注") + private Integer status; + + @ApiModelProperty("记录说明") + private String notes; + + private Integer delFlag; + + private String startTime; + + private String endTime; +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseStatusHistory.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseStatusHistory.java new file mode 100644 index 0000000..bb56741 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseStatusHistory.java @@ -0,0 +1,41 @@ +package com.intc.health.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.intc.common.core.web.domain.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.Date; + +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("慢性疾病状态变更历史") +public class ChronicDiseaseStatusHistory extends BaseEntity { + private Long id; + + @ApiModelProperty("慢性疾病档案ID") + private Long chronicDiseaseId; + + @ApiModelProperty("成员ID") + private Long personId; + + @ApiModelProperty("原状态") + private Integer oldStatus; + + @ApiModelProperty("新状态") + private Integer newStatus; + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @ApiModelProperty("变更时间") + private Date changeTime; + + @ApiModelProperty("变更原因") + private String reason; + + @ApiModelProperty("处理建议") + private String treatmentAdvice; + + private Integer delFlag; +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/AnalysisDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/AnalysisDto.java index 1759fa0..f53d0d6 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/AnalysisDto.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/AnalysisDto.java @@ -43,5 +43,20 @@ public class AnalysisDto extends BaseEntity implements Serializable @ApiModelProperty(value="档案id") private Long recordId; + /** 活动名称 */ + @ApiModelProperty(value="活动名称") + private String name; + + /** 活动类型 */ + @ApiModelProperty(value="活动类型") + private String activityType; + + /** 活动地点 */ + @ApiModelProperty(value="活动地点") + private String place; + + /** 活动量 */ + @ApiModelProperty(value="活动量") + private String activityVolume; } diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseManageMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseManageMapper.java new file mode 100644 index 0000000..21d1f5a --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseManageMapper.java @@ -0,0 +1,37 @@ +package com.intc.health.mapper; + +import com.intc.common.datascope.annotation.DataScope; +import com.intc.health.domain.ChronicDiseaseFollowUpRecord; +import com.intc.health.domain.ChronicDiseaseIndicatorRecord; +import com.intc.health.domain.ChronicDiseaseStatusHistory; + +import java.util.List; + +public interface ChronicDiseaseManageMapper { + @DataScope(businessAlias = "a") + List selectIndicatorList(ChronicDiseaseIndicatorRecord query); + + ChronicDiseaseIndicatorRecord selectIndicatorById(Long id); + + int insertIndicator(ChronicDiseaseIndicatorRecord record); + + int updateIndicator(ChronicDiseaseIndicatorRecord record); + + int removeIndicatorByIds(Long[] ids); + + @DataScope(businessAlias = "a") + List selectFollowUpList(ChronicDiseaseFollowUpRecord query); + + ChronicDiseaseFollowUpRecord selectFollowUpById(Long id); + + int insertFollowUp(ChronicDiseaseFollowUpRecord record); + + int updateFollowUp(ChronicDiseaseFollowUpRecord record); + + int removeFollowUpByIds(Long[] ids); + + @DataScope(businessAlias = "a") + List selectStatusHistoryList(ChronicDiseaseStatusHistory query); + + int insertStatusHistory(ChronicDiseaseStatusHistory record); +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/StatisticAnalysisMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/StatisticAnalysisMapper.java index 830a5a0..1e46362 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/StatisticAnalysisMapper.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/StatisticAnalysisMapper.java @@ -2,13 +2,16 @@ package com.intc.health.mapper; import com.intc.common.datascope.annotation.DataScope; import com.intc.health.domain.dto.HealthDoctorRecordDto; +import com.intc.health.domain.dto.HealthActivityDto; import com.intc.health.domain.dto.HealthMarRecordDto; import com.intc.health.domain.dto.HealthMilkPowderRecordDto; import com.intc.health.domain.dto.HealthRecordDto; +import com.intc.health.domain.dto.HealthTemperatureRecordDto; import com.intc.health.domain.vo.*; import org.apache.ibatis.annotations.Mapper; import java.util.List; +import java.util.Map; @Mapper public interface StatisticAnalysisMapper { @@ -98,6 +101,60 @@ public interface StatisticAnalysisMapper { @DataScope(businessAlias = "hp") public List selectStaticPersonList (HealthRecordDto dto); + /** + * 查询健康总览大屏成员风险排行 + */ + @DataScope(businessAlias = "hp") + public List selectHealthScreenPersonRankList(HealthRecordDto dto); + + /** + * 查询健康总览大屏就医汇总 + */ + @DataScope(businessAlias = "a") + public Map selectHealthScreenDoctorSummary(HealthDoctorRecordDto dto); + + /** + * 查询健康总览大屏用药汇总 + */ + @DataScope(businessAlias = "a") + public Map selectHealthScreenMedicineSummary(HealthMarRecordDto dto); + + /** + * 查询健康总览大屏体温汇总 + */ + @DataScope(businessAlias = "a") + public Map selectHealthScreenTemperatureSummary(HealthTemperatureRecordDto dto); + + /** + * 查询健康总览大屏活动汇总 + */ + @DataScope(businessAlias = "a") + public Map selectHealthScreenActivitySummary(HealthActivityDto dto); + + /** + * 查询健康总览大屏近期活动明细 + */ + @DataScope(businessAlias = "a") + public List selectHealthScreenActivityList(HealthActivityDto dto); + + /** + * 查询健康总览大屏近期就医明细 + */ + @DataScope(businessAlias = "a") + public List selectHealthScreenDoctorList(HealthDoctorRecordDto dto); + + /** + * 查询健康总览大屏近期用药明细 + */ + @DataScope(businessAlias = "a") + public List selectHealthScreenMedicineList(HealthMarRecordDto dto); + + /** + * 查询健康总览大屏近期体温明细 + */ + @DataScope(businessAlias = "a") + public List selectHealthScreenTemperatureList(HealthTemperatureRecordDto dto); + /** * 查询用药记录 diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IChronicDiseaseManageService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IChronicDiseaseManageService.java new file mode 100644 index 0000000..335e9f7 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IChronicDiseaseManageService.java @@ -0,0 +1,33 @@ +package com.intc.health.service; + +import com.intc.health.domain.ChronicDiseaseFollowUpRecord; +import com.intc.health.domain.ChronicDiseaseIndicatorRecord; +import com.intc.health.domain.ChronicDiseaseStatusHistory; + +import java.util.List; + +public interface IChronicDiseaseManageService { + List selectIndicatorList(ChronicDiseaseIndicatorRecord query); + + ChronicDiseaseIndicatorRecord selectIndicatorById(Long id); + + int insertIndicator(ChronicDiseaseIndicatorRecord record); + + int updateIndicator(ChronicDiseaseIndicatorRecord record); + + int deleteIndicatorByIds(Long[] ids); + + List selectFollowUpList(ChronicDiseaseFollowUpRecord query); + + ChronicDiseaseFollowUpRecord selectFollowUpById(Long id); + + int insertFollowUp(ChronicDiseaseFollowUpRecord record); + + int updateFollowUp(ChronicDiseaseFollowUpRecord record); + + int deleteFollowUpByIds(Long[] ids); + + List selectStatusHistoryList(ChronicDiseaseStatusHistory query); + + int insertStatusHistory(ChronicDiseaseStatusHistory record); +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IStatisticAnalysisService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IStatisticAnalysisService.java index 1cb9763..aec658b 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/IStatisticAnalysisService.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IStatisticAnalysisService.java @@ -2,6 +2,8 @@ package com.intc.health.service; import com.intc.health.domain.dto.AnalysisDto; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.util.Map; /** @@ -17,9 +19,17 @@ public interface IStatisticAnalysisService { public Map getHealthAnalysisInfo(); + public Map getActivityAnalysis(AnalysisDto analysisDto); + + public Map getHealthScreen(AnalysisDto analysisDto); + public Map getRecordAnalysis(AnalysisDto analysisDto); + public Map getRecordScreen(AnalysisDto analysisDto); + + public void exportRecordFull(HttpServletResponse response, AnalysisDto analysisDto) throws IOException; + public Map getDoctorAnalysis(AnalysisDto analysisDto); diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/ChronicDiseaseManageServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/ChronicDiseaseManageServiceImpl.java new file mode 100644 index 0000000..42bce07 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/ChronicDiseaseManageServiceImpl.java @@ -0,0 +1,109 @@ +package com.intc.health.service.impl; + +import com.intc.common.core.utils.DateUtils; +import com.intc.common.core.utils.IdWorker; +import com.intc.common.security.utils.SecurityUtils; +import com.intc.health.domain.ChronicDiseaseFollowUpRecord; +import com.intc.health.domain.ChronicDiseaseIndicatorRecord; +import com.intc.health.domain.ChronicDiseaseStatusHistory; +import com.intc.health.mapper.ChronicDiseaseManageMapper; +import com.intc.health.service.IChronicDiseaseManageService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.Date; +import java.util.List; + +@Service +public class ChronicDiseaseManageServiceImpl implements IChronicDiseaseManageService { + @Resource + private ChronicDiseaseManageMapper chronicDiseaseManageMapper; + + @Override + public List selectIndicatorList(ChronicDiseaseIndicatorRecord query) { + return chronicDiseaseManageMapper.selectIndicatorList(query); + } + + @Override + public ChronicDiseaseIndicatorRecord selectIndicatorById(Long id) { + return chronicDiseaseManageMapper.selectIndicatorById(id); + } + + @Override + public int insertIndicator(ChronicDiseaseIndicatorRecord record) { + record.setId(IdWorker.getId()); + record.setCreateBy(SecurityUtils.getUsername()); + record.setCreateTime(DateUtils.getNowDate()); + if (record.getMeasureTime() == null) { + record.setMeasureTime(new Date()); + } + if (record.getStatus() == null) { + record.setStatus(1); + } + return chronicDiseaseManageMapper.insertIndicator(record); + } + + @Override + public int updateIndicator(ChronicDiseaseIndicatorRecord record) { + record.setUpdateBy(SecurityUtils.getUsername()); + record.setUpdateTime(DateUtils.getNowDate()); + return chronicDiseaseManageMapper.updateIndicator(record); + } + + @Override + public int deleteIndicatorByIds(Long[] ids) { + return chronicDiseaseManageMapper.removeIndicatorByIds(ids); + } + + @Override + public List selectFollowUpList(ChronicDiseaseFollowUpRecord query) { + return chronicDiseaseManageMapper.selectFollowUpList(query); + } + + @Override + public ChronicDiseaseFollowUpRecord selectFollowUpById(Long id) { + return chronicDiseaseManageMapper.selectFollowUpById(id); + } + + @Override + public int insertFollowUp(ChronicDiseaseFollowUpRecord record) { + record.setId(IdWorker.getId()); + record.setCreateBy(SecurityUtils.getUsername()); + record.setCreateTime(DateUtils.getNowDate()); + if (record.getFollowUpType() == null) { + record.setFollowUpType(1); + } + if (record.getStatus() == null) { + record.setStatus(1); + } + return chronicDiseaseManageMapper.insertFollowUp(record); + } + + @Override + public int updateFollowUp(ChronicDiseaseFollowUpRecord record) { + record.setUpdateBy(SecurityUtils.getUsername()); + record.setUpdateTime(DateUtils.getNowDate()); + return chronicDiseaseManageMapper.updateFollowUp(record); + } + + @Override + public int deleteFollowUpByIds(Long[] ids) { + return chronicDiseaseManageMapper.removeFollowUpByIds(ids); + } + + @Override + public List selectStatusHistoryList(ChronicDiseaseStatusHistory query) { + return chronicDiseaseManageMapper.selectStatusHistoryList(query); + } + + @Override + public int insertStatusHistory(ChronicDiseaseStatusHistory record) { + record.setId(IdWorker.getId()); + record.setCreateBy(SecurityUtils.getUsername()); + record.setCreateTime(DateUtils.getNowDate()); + if (record.getChangeTime() == null) { + record.setChangeTime(new Date()); + } + return chronicDiseaseManageMapper.insertStatusHistory(record); + } +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/ChronicDiseaseRecordServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/ChronicDiseaseRecordServiceImpl.java index 8c6de32..7f8413a 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/ChronicDiseaseRecordServiceImpl.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/ChronicDiseaseRecordServiceImpl.java @@ -4,8 +4,10 @@ import com.intc.common.core.utils.DateUtils; import com.intc.common.core.utils.IdWorker; import com.intc.common.security.utils.SecurityUtils; import com.intc.health.domain.ChronicDiseaseRecord; +import com.intc.health.domain.ChronicDiseaseStatusHistory; import com.intc.health.domain.dto.ChronicDiseaseRecordDto; import com.intc.health.domain.vo.ChronicDiseaseRecordVo; +import com.intc.health.mapper.ChronicDiseaseManageMapper; import com.intc.health.mapper.ChronicDiseaseRecordMapper; import com.intc.health.service.IChronicDiseaseRecordService; import org.springframework.stereotype.Service; @@ -25,6 +27,9 @@ public class ChronicDiseaseRecordServiceImpl implements IChronicDiseaseRecordSer @Resource private ChronicDiseaseRecordMapper chronicDiseaseRecordMapper; + @Resource + private ChronicDiseaseManageMapper chronicDiseaseManageMapper; + /** * 查询慢性疾病档案 * @@ -93,9 +98,29 @@ public class ChronicDiseaseRecordServiceImpl implements IChronicDiseaseRecordSer @Override public int updateChronicDiseaseRecord(ChronicDiseaseRecord chronicDiseaseRecord) { + ChronicDiseaseRecordVo oldRecord = null; + if (chronicDiseaseRecord.getId() != null && chronicDiseaseRecord.getDiseaseStatus() != null) { + oldRecord = chronicDiseaseRecordMapper.selectChronicDiseaseRecordById(chronicDiseaseRecord.getId()); + } chronicDiseaseRecord.setUpdateBy(SecurityUtils.getUsername()); chronicDiseaseRecord.setUpdateTime(DateUtils.getNowDate()); - return chronicDiseaseRecordMapper.updateChronicDiseaseRecord(chronicDiseaseRecord); + int rows = chronicDiseaseRecordMapper.updateChronicDiseaseRecord(chronicDiseaseRecord); + if (rows > 0 && oldRecord != null && oldRecord.getDiseaseStatus() != null + && !oldRecord.getDiseaseStatus().equals(chronicDiseaseRecord.getDiseaseStatus())) { + ChronicDiseaseStatusHistory history = new ChronicDiseaseStatusHistory(); + history.setId(IdWorker.getId()); + history.setChronicDiseaseId(chronicDiseaseRecord.getId()); + history.setPersonId(oldRecord.getPersonId()); + history.setOldStatus(oldRecord.getDiseaseStatus()); + history.setNewStatus(chronicDiseaseRecord.getDiseaseStatus()); + history.setChangeTime(DateUtils.getNowDate()); + history.setReason(chronicDiseaseRecord.getRemark() != null ? chronicDiseaseRecord.getRemark() : "档案状态调整"); + history.setTreatmentAdvice(chronicDiseaseRecord.getNotes()); + history.setCreateBy(SecurityUtils.getUsername()); + history.setCreateTime(DateUtils.getNowDate()); + chronicDiseaseManageMapper.insertStatusHistory(history); + } + return rows; } /** @@ -121,4 +146,4 @@ public class ChronicDiseaseRecordServiceImpl implements IChronicDiseaseRecordSer { return chronicDiseaseRecordMapper.removeChronicDiseaseRecordById(id); } -} \ No newline at end of file +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/StatisticAnalysisImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/StatisticAnalysisImpl.java index 127e2e3..b9e01a9 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/StatisticAnalysisImpl.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/StatisticAnalysisImpl.java @@ -8,14 +8,33 @@ import com.intc.health.domain.dto.*; import com.intc.health.domain.vo.*; import com.intc.health.mapper.*; import com.intc.health.service.IStatisticAnalysisService; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.PrintSetup; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.VerticalAlignment; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.*; @Service +@Slf4j public class StatisticAnalysisImpl implements IStatisticAnalysisService { @Resource @@ -42,6 +61,9 @@ public class StatisticAnalysisImpl implements IStatisticAnalysisService { @Resource private HealthProcessRecordMapper healthProcessRecordMapper; + @Resource + private HealthDoctorRecordCostMapper healthDoctorRecordCostMapper; + @Override public Map getMarAnalysis(AnalysisDto analysisDto) { //返回数据 @@ -441,6 +463,140 @@ public class StatisticAnalysisImpl implements IStatisticAnalysisService { return map; } + + @Override + public Map getHealthScreen(AnalysisDto analysisDto) { + long begin = System.currentTimeMillis(); + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + HashMap map = new HashMap<>(); + Long personId = analysisDto == null ? null : analysisDto.getId(); + + List allPersonList = healthPersonMapper.selectHealthPersonList(new HealthPersonDto()); + List personList = filterHealthScreenPersonList(allPersonList, personId); + HealthRecordDto screenRecordDto = new HealthRecordDto(); + screenRecordDto.setPersonId(personId); + List recordList = healthRecordMapper.selectHealthRecordList(screenRecordDto); + long baseLoaded = System.currentTimeMillis(); + log.info("健康总览大屏-基础数据耗时: {}ms, personCount={}, recordCount={}", baseLoaded - begin, emptyList(personList).size(), emptyList(recordList).size()); + + String screenStartTime = new SimpleDateFormat("yyyy-MM-dd").format(DateUtils.addYears(new Date(), -1)); + HealthRecordDto screenTrendRecordDto = new HealthRecordDto(); + screenTrendRecordDto.setPersonId(personId); + screenTrendRecordDto.setStartTime(screenStartTime); + HealthDoctorRecordDto screenDoctorDto = new HealthDoctorRecordDto(); + screenDoctorDto.setStartTime(screenStartTime); + screenDoctorDto.setPersonId(personId); + HealthMarRecordDto screenMarDto = new HealthMarRecordDto(); + screenMarDto.setStartTime(screenStartTime); + screenMarDto.setPersonId(personId); + HealthTemperatureRecordDto screenTemperatureDto = new HealthTemperatureRecordDto(); + screenTemperatureDto.setStartTime(screenStartTime); + screenTemperatureDto.setPersonId(personId); + HealthActivityDto screenActivityDto = new HealthActivityDto(); + + List trendRecordList = healthRecordMapper.selectHealthRecordList(screenTrendRecordDto); + List activityList = statisticAnalysisMapper.selectHealthScreenActivityList(screenActivityDto); + List doctorRecordList = statisticAnalysisMapper.selectHealthScreenDoctorList(screenDoctorDto); + List marRecordList = statisticAnalysisMapper.selectHealthScreenMedicineList(screenMarDto); + List temperatureRecordList = statisticAnalysisMapper.selectHealthScreenTemperatureList(screenTemperatureDto); + HealthDoctorRecordDto eventDoctorDto = new HealthDoctorRecordDto(); + eventDoctorDto.setPersonId(personId); + HealthMarRecordDto eventMarDto = new HealthMarRecordDto(); + eventMarDto.setPersonId(personId); + HealthTemperatureRecordDto eventTemperatureDto = new HealthTemperatureRecordDto(); + eventTemperatureDto.setPersonId(personId); + List eventDoctorRecordList = statisticAnalysisMapper.selectHealthScreenDoctorList(eventDoctorDto); + List eventMarRecordList = statisticAnalysisMapper.selectHealthScreenMedicineList(eventMarDto); + List eventTemperatureRecordList = statisticAnalysisMapper.selectHealthScreenTemperatureList(eventTemperatureDto); + long detailLoaded = System.currentTimeMillis(); + log.info("健康总览大屏-展示明细耗时: {}ms, activity={}, yearDoctor={}, yearMedicine={}, recentTemperature={}", + detailLoaded - baseLoaded, + emptyList(activityList).size(), + emptyList(doctorRecordList).size(), + emptyList(marRecordList).size(), + emptyList(temperatureRecordList).size()); + + HealthRecordDto rankDto = new HealthRecordDto(); + rankDto.setPersonId(personId); + List staticPersonList = statisticAnalysisMapper.selectHealthScreenPersonRankList(rankDto); + long rankLoaded = System.currentTimeMillis(); + log.info("健康总览大屏-成员排行耗时: {}ms, rankCount={}", rankLoaded - detailLoaded, emptyList(staticPersonList).size()); + + HealthDoctorRecordDto doctorSummaryDto = new HealthDoctorRecordDto(); + doctorSummaryDto.setPersonId(personId); + HealthMarRecordDto medicineSummaryDto = new HealthMarRecordDto(); + medicineSummaryDto.setPersonId(personId); + HealthTemperatureRecordDto temperatureSummaryDto = new HealthTemperatureRecordDto(); + temperatureSummaryDto.setPersonId(personId); + Map doctorSummary = statisticAnalysisMapper.selectHealthScreenDoctorSummary(doctorSummaryDto); + Map medicineSummary = statisticAnalysisMapper.selectHealthScreenMedicineSummary(medicineSummaryDto); + Map temperatureSummary = statisticAnalysisMapper.selectHealthScreenTemperatureSummary(temperatureSummaryDto); + Map activitySummary = statisticAnalysisMapper.selectHealthScreenActivitySummary(new HealthActivityDto()); + long summaryLoaded = System.currentTimeMillis(); + log.info("健康总览大屏-汇总聚合耗时: {}ms", summaryLoaded - rankLoaded); + + double doctorCost = numberValue(doctorSummary, "doctorCost"); + double activityCost = numberValue(activitySummary, "activityCost"); + long doctorCount = longValue(doctorSummary, "doctorCount"); + long activityCount = longValue(activitySummary, "activityCount"); + long marCount = longValue(medicineSummary, "marCount"); + long temperatureTotalCount = longValue(temperatureSummary, "temperatureTotalCount"); + long feverDayCount = longValue(temperatureSummary, "feverDayCount"); + + HashMap summary = new HashMap<>(); + summary.put("selectedPersonId", personId); + summary.put("selectedPersonName", findHealthScreenPersonName(allPersonList, personId)); + summary.put("personCount", emptyList(personList).size()); + summary.put("healthRecordCount", emptyList(recordList).size()); + summary.put("activityCount", activityCount); + summary.put("activityCost", decimalFormat.format(activityCost)); + summary.put("doctorCount", doctorCount); + summary.put("doctorCost", decimalFormat.format(doctorCost)); + summary.put("hospitalCount", longValue(doctorSummary, "hospitalCount")); + summary.put("doctorTotalCount", longValue(doctorSummary, "doctorTotalCount")); + summary.put("marCount", marCount); + summary.put("marDayCount", longValue(medicineSummary, "marDayCount")); + summary.put("medicalTypeCount", longValue(medicineSummary, "medicalTypeCount")); + summary.put("temperatureTotalCount", temperatureTotalCount); + summary.put("feverDayCount", feverDayCount); + summary.put("avgDoctorCost", decimalFormat.format(doctorCount == 0 ? 0D : doctorCost / doctorCount)); + summary.put("avgActivityCost", decimalFormat.format(activityCount == 0 ? 0D : activityCost / activityCount)); + summary.put("avgRecordPerPerson", decimalFormat.format(emptyList(personList).isEmpty() ? 0D : (double) emptyList(recordList).size() / personList.size())); + summary.put("healthIndex", buildHealthScreenIndex(personList, recordList, doctorCount, marCount, feverDayCount, longValue(temperatureSummary, "higherTempCount"))); + + map.put("summary", summary); + Map dictCache = new HashMap<>(); + long buildStart = System.currentTimeMillis(); + Map temperature = buildScreenTemperature(eventTemperatureRecordList); + map.put("temperature", temperature); + long temperatureBuilt = System.currentTimeMillis(); + log.info("健康总览大屏-体温组装耗时: {}ms", temperatureBuilt - buildStart); + map.put("medicine", buildScreenMedicine(marRecordList, dictCache)); + long medicineBuilt = System.currentTimeMillis(); + log.info("健康总览大屏-用药组装耗时: {}ms", medicineBuilt - temperatureBuilt); + map.put("doctor", buildScreenDoctor(doctorRecordList)); + long doctorBuilt = System.currentTimeMillis(); + log.info("健康总览大屏-就医组装耗时: {}ms", doctorBuilt - medicineBuilt); + map.put("activity", buildHealthScreenActivity(activityList)); + long activityBuilt = System.currentTimeMillis(); + log.info("健康总览大屏-活动组装耗时: {}ms", activityBuilt - doctorBuilt); + Map record = buildHealthScreenRecord(recordList, personList, dictCache); + record.put("monthList", buildHealthScreenRecordMonthList(trendRecordList)); + map.put("record", record); + long recordBuilt = System.currentTimeMillis(); + log.info("健康总览大屏-档案组装耗时: {}ms", recordBuilt - activityBuilt); + map.put("personRankList", buildHealthScreenPersonRank(staticPersonList)); + long rankBuilt = System.currentTimeMillis(); + log.info("健康总览大屏-成员排行组装耗时: {}ms", rankBuilt - recordBuilt); + map.put("eventList", buildHealthScreenEvents(recordList, eventDoctorRecordList, eventMarRecordList, eventTemperatureRecordList, activityList, dictCache)); + long eventBuilt = System.currentTimeMillis(); + log.info("健康总览大屏-事件组装耗时: {}ms", eventBuilt - rankBuilt); + map.put("suggestionList", buildHealthScreenSuggestions(summary, temperatureRecordList, doctorRecordList, marRecordList)); + log.info("健康总览大屏-建议组装耗时: {}ms", System.currentTimeMillis() - eventBuilt); + log.info("健康总览大屏-总耗时: {}ms", System.currentTimeMillis() - begin); + return map; + } + @Override public Map getRecordAnalysis(AnalysisDto analysisDto) { //返回数据 @@ -598,6 +754,1979 @@ public class StatisticAnalysisImpl implements IStatisticAnalysisService { return map; } + @Override + public Map getRecordScreen(AnalysisDto analysisDto) { + HashMap map = new HashMap<>(); + Long recordId = analysisDto.getRecordId(); + analysisDto.setRecordId(recordId); + analysisDto.setType(StringUtils.isEmpty(analysisDto.getType()) ? "1" : analysisDto.getType()); + + if (recordId == null) { + fillEmptyRecordScreen(map); + return map; + } + + HealthRecordVo record = healthRecordMapper.selectHealthRecordById(recordId); + if (record == null) { + fillEmptyRecordScreen(map); + return map; + } + if (record.getRehabilitationTime() != null) { + record.setDuration(DateUtils.timeDistance(record.getRehabilitationTime(), record.getOccurTime())); + } else if (record.getOccurTime() != null) { + record.setDuration(DateUtils.timeDistance(new Date(), record.getOccurTime())); + } + + HealthDoctorRecordDto doctorRecordDto = new HealthDoctorRecordDto(); + doctorRecordDto.setHealthRecordId(recordId); + doctorRecordDto.setPersonId(analysisDto.getId()); + doctorRecordDto.setStartTime(analysisDto.getStartTime()); + doctorRecordDto.setEndTime(analysisDto.getEndTime()); + + HealthProcessRecordDto processRecordDto = new HealthProcessRecordDto(); + processRecordDto.setHealthRecordId(recordId); + processRecordDto.setPersonId(analysisDto.getId()); + processRecordDto.setStartTime(analysisDto.getStartTime()); + processRecordDto.setEndTime(analysisDto.getEndTime()); + + HealthTemperatureRecordDto temperatureRecordDto = new HealthTemperatureRecordDto(); + temperatureRecordDto.setHealthRecordId(recordId); + temperatureRecordDto.setPersonId(analysisDto.getId()); + temperatureRecordDto.setStartTime(analysisDto.getStartTime()); + temperatureRecordDto.setEndTime(analysisDto.getEndTime()); + + HealthMarRecordDto marRecordDto = new HealthMarRecordDto(); + marRecordDto.setHealthRecordId(recordId); + marRecordDto.setPersonId(analysisDto.getId()); + marRecordDto.setStartTime(analysisDto.getStartTime()); + marRecordDto.setEndTime(analysisDto.getEndTime()); + + List doctorRecordList = healthDoctorRecordMapper.selectHealthDoctorRecordList(doctorRecordDto); + List processRecordList = healthProcessRecordMapper.selectHealthProcessRecordList(processRecordDto); + List temperatureRecordList = temperatureRecordMapper.selectHealthTemperatureRecordList(temperatureRecordDto); + List marRecordList = marRecordMapper.selectHealthMarRecordList(marRecordDto); + + map.put("record", record); + map.put("summary", buildScreenSummary(record, doctorRecordList, processRecordList, temperatureRecordList, marRecordList)); + map.put("doctor", buildScreenDoctor(doctorRecordList)); + map.put("temperature", buildScreenTemperature(temperatureRecordList)); + map.put("medicine", buildScreenMedicine(marRecordList)); + map.put("doctorRecordList", doctorRecordList); + map.put("processRecordList", processRecordList); + map.put("temperatureRecordList", temperatureRecordList); + map.put("marRecordList", marRecordList); + + return map; + } + + private Map buildScreenSummary(HealthRecordVo record, List doctorRecordList, + List processRecordList, + List temperatureRecordList, + List marRecordList) { + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + HashMap summary = new HashMap<>(); + summary.put("healthRecordCount", record == null ? 0 : 1); + summary.put("processRecordCount", emptyList(processRecordList).size()); + summary.put("doctorCount", emptyList(doctorRecordList).size()); + summary.put("doctorCost", decimalFormat.format(emptyList(doctorRecordList).stream().mapToDouble(this::safeTotalCost).sum())); + summary.put("hospitalCount", emptyList(doctorRecordList).stream().map(HealthDoctorRecordVo::getHospitalName).filter(StringUtils::isNotEmpty).distinct().count()); + summary.put("doctorTotalCount", emptyList(doctorRecordList).stream().map(HealthDoctorRecordVo::getDoctor).filter(StringUtils::isNotEmpty).distinct().count()); + summary.put("marDayCount", distinctDosingDateCount(emptyList(marRecordList))); + summary.put("marCount", emptyList(marRecordList).size()); + summary.put("feverDayCount", emptyList(temperatureRecordList).stream() + .filter(item -> item.getTemperature() != null && item.getTemperature() >= 37) + .map(item -> formatDay(item.getMeasureTime())) + .filter(StringUtils::isNotEmpty) + .distinct() + .count()); + summary.put("recordList", record == null ? new ArrayList<>() : Collections.singletonList(record)); + + ArrayList> recordCostList = new ArrayList<>(); + if (record != null) { + Map costMap = new HashMap<>(); + costMap.put("time", record.getName()); + costMap.put("value", decimalFormat.format(emptyList(doctorRecordList).stream().mapToDouble(this::safeTotalCost).sum())); + recordCostList.add(costMap); + } + summary.put("recordCostList", recordCostList); + return summary; + } + + private Map buildScreenDoctor(List doctorRecordList) { + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + HashMap doctor = new HashMap<>(); + List list = emptyList(doctorRecordList); + doctor.put("doctorCount", list.size()); + double doctorCost = list.stream().mapToDouble(this::safeTotalCost).sum(); + doctor.put("doctorCost", decimalFormat.format(doctorCost)); + doctor.put("avgDoctorCost", decimalFormat.format(list.isEmpty() ? 0D : doctorCost / list.size())); + doctor.put("hospitalCount", list.stream().map(HealthDoctorRecordVo::getHospitalName).filter(StringUtils::isNotEmpty).distinct().count()); + doctor.put("doctorTotalCount", list.stream().map(HealthDoctorRecordVo::getDoctor).filter(StringUtils::isNotEmpty).distinct().count()); + doctor.put("clinicCount", list.stream().filter(item -> "1".equals(item.getType())).count()); + doctor.put("emergencyCount", list.stream().filter(item -> "2".equals(item.getType())).count()); + doctor.put("hospitalizedCount", list.stream().filter(item -> "3".equals(item.getType())).count()); + doctor.put("infusionCount", list.stream().filter(item -> "4".equals(item.getType())).count()); + doctor.put("onlineCount", list.stream().filter(item -> "5".equals(item.getType())).count()); + + TreeMap costByDay = new TreeMap<>(); + TreeMap countByDay = new TreeMap<>(); + for (HealthDoctorRecordVo item : list) { + String day = formatDay(item.getVisitingTime()); + if (StringUtils.isEmpty(day)) { + continue; + } + countByDay.put(day, countByDay.getOrDefault(day, 0) + 1); + costByDay.put(day, costByDay.getOrDefault(day, 0D) + safeTotalCost(item)); + } + ArrayList> doctorCountList = new ArrayList<>(); + for (Map.Entry entry : countByDay.entrySet()) { + Map dataMap = new HashMap<>(); + dataMap.put("time", entry.getKey()); + dataMap.put("value", entry.getValue()); + doctorCountList.add(dataMap); + } + ArrayList> doctorCostList = new ArrayList<>(); + for (Map.Entry entry : costByDay.entrySet()) { + Map dataMap = new HashMap<>(); + dataMap.put("time", entry.getKey()); + dataMap.put("value", decimalFormat.format(entry.getValue())); + doctorCostList.add(dataMap); + } + doctor.put("doctorCountList", doctorCountList); + doctor.put("doctorCostList", doctorCostList); + return doctor; + } + + private Map buildScreenTemperature(List temperatureRecordList) { + DecimalFormat decimalFormat = new DecimalFormat("#.###"); + SimpleDateFormat dateFormatSecond = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + HashMap temperature = new HashMap<>(); + List list = new ArrayList<>(emptyList(temperatureRecordList)); + list.sort(Comparator.comparing(HealthTemperatureRecordVo::getMeasureTime, Comparator.nullsLast(Date::compareTo))); + + int normalTempCount = 0; + int lowerTempCount = 0; + int middleTempCount = 0; + int higherTempCount = 0; + double total = 0D; + double maxTemp = 0D; + double minTemp = 0D; + int validCount = 0; + + ArrayList> temperatureList = new ArrayList<>(); + TreeMap dayMap = new TreeMap<>(); + for (HealthTemperatureRecordVo item : list) { + if (item.getTemperature() == null) { + continue; + } + double temp = item.getTemperature(); + validCount++; + total += temp; + maxTemp = validCount == 1 ? temp : Math.max(maxTemp, temp); + minTemp = validCount == 1 ? temp : Math.min(minTemp, temp); + if (temp < 36.9) { + normalTempCount++; + } else if (temp <= 37.5) { + lowerTempCount++; + } else if (temp < 38.5) { + middleTempCount++; + } else { + higherTempCount++; + } + + if (item.getMeasureTime() != null) { + Map dataMap = new HashMap<>(); + dataMap.put("time", dateFormatSecond.format(item.getMeasureTime())); + dataMap.put("value", decimalFormat.format(temp)); + temperatureList.add(dataMap); + } + + String day = formatDay(item.getMeasureTime()); + if (StringUtils.isNotEmpty(day)) { + HealthStaticAnalysisVo analysisVo = dayMap.computeIfAbsent(day, key -> { + HealthStaticAnalysisVo vo = new HealthStaticAnalysisVo(); + vo.setTime(key); + vo.setMax(0D); + vo.setMin(45D); + vo.setAverage(0D); + vo.setDetails(""); + return vo; + }); + analysisVo.setCount(analysisVo.getCount() + 1); + analysisVo.setMax(Math.max(analysisVo.getMax(), temp)); + analysisVo.setMin(Math.min(analysisVo.getMin(), temp)); + analysisVo.setAverage(analysisVo.getAverage() + temp); + analysisVo.setName(item.getPersonName()); + } + } + + ArrayList> tableList = new ArrayList<>(); + int feverDay = 0; + for (HealthStaticAnalysisVo item : dayMap.values()) { + if (item.getMax() > 37) { + feverDay++; + } + Map dataMap = new HashMap<>(); + dataMap.put("time", item.getTime()); + dataMap.put("count", item.getCount()); + dataMap.put("name", item.getName()); + dataMap.put("detail", item.getDetails()); + dataMap.put("max", item.getMax()); + dataMap.put("min", item.getMin() == 45D ? 0 : item.getMin()); + dataMap.put("average", item.getCount() == 0 ? "0" : decimalFormat.format(item.getAverage() / item.getCount())); + tableList.add(dataMap); + } + + temperature.put("averageTemp", validCount == 0 ? 0 : decimalFormat.format(total / validCount)); + temperature.put("totalCount", validCount); + temperature.put("normalTempCount", normalTempCount); + temperature.put("lowerTempCount", lowerTempCount); + temperature.put("middleTempCount", middleTempCount); + temperature.put("higherTempCount", higherTempCount); + temperature.put("maxTemp", maxTemp); + temperature.put("minTemp", minTemp); + temperature.put("feverDay", feverDay); + temperature.put("temperatureList", temperatureList); + temperature.put("tableList", tableList); + return temperature; + } + + private Map buildScreenMedicine(List marRecordList) { + return buildScreenMedicine(marRecordList, new HashMap<>()); + } + + private Map buildScreenMedicine(List marRecordList, Map dictCache) { + HashMap medicine = new HashMap<>(); + List list = emptyList(marRecordList); + LinkedHashMap> rankMap = new LinkedHashMap<>(); + TreeMap dayMap = new TreeMap<>(); + + for (HealthMarRecordVo item : list) { + String medicineName = StringUtils.isNotEmpty(item.getName()) ? item.getName() : "未命名药品"; + String unitName = StringUtils.isNotEmpty(item.getUnitName()) ? item.getUnitName() : cachedDictLabel(dictCache, "medical_unit", item.getUnit()); + String key = item.getMedicineId() + "|" + medicineName + "|" + item.getUnit() + "|" + item.getDosage(); + Map rank = rankMap.computeIfAbsent(key, value -> { + Map dataMap = new HashMap<>(); + dataMap.put("medicalName", medicineName); + dataMap.put("count", 0); + dataMap.put("unit", unitName); + dataMap.put("dosage", item.getDosage()); + dataMap.put("useDays", new HashSet()); + return dataMap; + }); + rank.put("count", ((Integer) rank.get("count")) + 1); + String day = formatDay(item.getDosingTime()); + if (StringUtils.isNotEmpty(day)) { + ((Set) rank.get("useDays")).add(day); + dayMap.put(day, dayMap.getOrDefault(day, 0) + 1); + } + } + + ArrayList> marMapList = new ArrayList<>(); + for (Map item : rankMap.values()) { + Set useDays = (Set) item.get("useDays"); + item.put("useDays", useDays.size()); + marMapList.add(item); + } + marMapList.sort((a, b) -> Integer.compare((Integer) b.get("count"), (Integer) a.get("count"))); + + ArrayList> marList = new ArrayList<>(); + for (Map.Entry entry : dayMap.entrySet()) { + Map dataMap = new HashMap<>(); + dataMap.put("time", entry.getKey()); + dataMap.put("value", entry.getValue()); + marList.add(dataMap); + } + + medicine.put("marCount", list.size()); + medicine.put("marCategoryCount", marMapList.size()); + medicine.put("marMapList", marMapList); + medicine.put("marDays", dayMap.size()); + medicine.put("marList", marList); + return medicine; + } + + private Map buildHealthScreenRecord(List recordList, + List personList, + Map dictCache) { + HashMap record = new HashMap<>(); + List list = new ArrayList<>(emptyList(recordList)); + int activeCount = 0; + int recoveredCount = 0; + int unknownStateCount = 0; + LinkedHashMap stateMap = new LinkedHashMap<>(); + LinkedHashMap typeMap = new LinkedHashMap<>(); + HashMap personRecordCountMap = new HashMap<>(); + TreeMap monthMap = new TreeMap<>(); + + for (HealthRecordVo item : list) { + if (item.getPersonId() != null) { + personRecordCountMap.put(item.getPersonId(), personRecordCountMap.getOrDefault(item.getPersonId(), 0) + 1); + } + + String state = StringUtils.isNotEmpty(item.getState()) ? item.getState() : "unknown"; + if ("1".equals(state)) { + activeCount++; + } else if ("2".equals(state) || item.getRehabilitationTime() != null) { + recoveredCount++; + } else { + unknownStateCount++; + } + String stateName = "unknown".equals(state) ? "未设置" : cachedDictLabel(dictCache, "health_record_state", state); + stateMap.put(stateName, stateMap.getOrDefault(stateName, 0) + 1); + + String type = StringUtils.isNotEmpty(item.getType()) ? item.getType() : "unknown"; + String typeName = "unknown".equals(type) ? "未设置" : cachedDictLabel(dictCache, "record_type", type); + typeMap.put(typeName, typeMap.getOrDefault(typeName, 0) + 1); + + String month = formatMonth(item.getOccurTime()); + if (StringUtils.isNotEmpty(month)) { + monthMap.put(month, monthMap.getOrDefault(month, 0) + 1); + } + } + + list.sort(Comparator.comparing(HealthRecordVo::getOccurTime, Comparator.nullsLast(Date::compareTo)).reversed()); + record.put("activeCount", activeCount); + record.put("recoveredCount", recoveredCount); + record.put("unknownStateCount", unknownStateCount); + record.put("stateList", toNameValueList(stateMap)); + record.put("typeList", toNameValueList(typeMap)); + record.put("personRecordList", buildPersonRecordRank(personRecordCountMap, personList)); + record.put("monthList", toTimeValueList(monthMap, 12)); + record.put("recentList", limitList(list, 8)); + return record; + } + + private List> buildHealthScreenRecordMonthList(List recordList) { + TreeMap monthMap = new TreeMap<>(); + for (HealthRecordVo item : emptyList(recordList)) { + String month = formatMonth(item.getOccurTime()); + if (StringUtils.isNotEmpty(month)) { + monthMap.put(month, monthMap.getOrDefault(month, 0) + 1); + } + } + return toTimeValueList(monthMap, 12); + } + + private List> buildPersonRecordRank(Map personRecordCountMap, + List personList) { + ArrayList> list = new ArrayList<>(); + for (HealthPersonVo person : emptyList(personList)) { + if (person.getId() == null) { + continue; + } + int count = personRecordCountMap.getOrDefault(person.getId(), 0); + Map dataMap = new HashMap<>(); + dataMap.put("name", StringUtils.isNotEmpty(person.getName()) ? person.getName() : "未命名成员"); + dataMap.put("value", count); + list.add(dataMap); + } + list.sort((a, b) -> Integer.compare((Integer) b.get("value"), (Integer) a.get("value"))); + return limitList(list, 12); + } + + private List filterHealthScreenPersonList(List personList, Long personId) { + if (personId == null) { + return emptyList(personList); + } + ArrayList list = new ArrayList<>(); + for (HealthPersonVo item : emptyList(personList)) { + if (Objects.equals(item.getId(), personId)) { + list.add(item); + break; + } + } + return list; + } + + private String findHealthScreenPersonName(List personList, Long personId) { + if (personId == null) { + return ""; + } + for (HealthPersonVo item : emptyList(personList)) { + if (Objects.equals(item.getId(), personId)) { + return item.getName(); + } + } + return ""; + } + + private Map buildHealthScreenActivity(List activityList) { + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + HashMap activity = new HashMap<>(); + TreeMap countMap = new TreeMap<>(); + TreeMap costMap = new TreeMap<>(); + LinkedHashMap typeMap = new LinkedHashMap<>(); + List list = new ArrayList<>(emptyList(activityList)); + + for (HealthActivityVo item : list) { + String day = formatDay(item.getStartTime()); + if (StringUtils.isNotEmpty(day)) { + countMap.put(day, countMap.getOrDefault(day, 0) + 1); + costMap.put(day, costMap.getOrDefault(day, 0D) + (item.getTotalCost() == null ? 0D : item.getTotalCost())); + } + String type = StringUtils.isNotEmpty(item.getType()) ? item.getType() : "未设置"; + typeMap.put(type, typeMap.getOrDefault(type, 0) + 1); + } + + list.sort(Comparator.comparing(HealthActivityVo::getStartTime, Comparator.nullsLast(Date::compareTo)).reversed()); + activity.put("countTrend", toTimeValueList(countMap, 14)); + activity.put("costTrend", toTimeValueList(costMap, 14, decimalFormat)); + activity.put("typeList", toNameValueList(typeMap)); + activity.put("recentList", limitList(list, 10)); + return activity; + } + + private List> buildHealthScreenPersonRank(List personList) { + ArrayList> list = new ArrayList<>(); + for (HealthStaticPersonVo item : emptyList(personList)) { + int doctorCount = parseInt(item.getDoctorCount()); + int feverDayCount = item.getFeverDayCount(); + int marCount = parseInt(item.getMarCount()); + int healthRecordCount = parseInt(item.getHealthRecordCount()); + double doctorCost = parseDouble(item.getDoctorCost()); + int riskScore = Math.min(100, + Math.min((int) Math.round(feverDayCount * 1.2), 35) + + Math.min((int) Math.round(doctorCount * 2.5), 30) + + Math.min((int) Math.round(marCount * 0.15), 12) + + Math.min(healthRecordCount * 2, 10) + + Math.min((int) Math.round(doctorCost / 1000), 13)); + Map dataMap = new HashMap<>(); + dataMap.put("personName", item.getPersonName()); + dataMap.put("healthRecordCount", healthRecordCount); + dataMap.put("doctorCount", doctorCount); + dataMap.put("doctorCost", item.getDoctorCost()); + dataMap.put("marCount", marCount); + dataMap.put("marDayCount", item.getMarDayCount()); + dataMap.put("feverDayCount", feverDayCount); + dataMap.put("riskScore", riskScore); + dataMap.put("riskLevel", riskScore >= 75 ? "重点关注" : riskScore >= 45 ? "持续观察" : "整体平稳"); + list.add(dataMap); + } + list.sort((a, b) -> Integer.compare((Integer) b.get("riskScore"), (Integer) a.get("riskScore"))); + return limitList(list, 8); + } + + private List> buildHealthScreenEvents(List recordList, + List doctorRecordList, + List marRecordList, + List temperatureRecordList, + List activityList, + Map dictCache) { + ArrayList> events = new ArrayList<>(); + for (HealthRecordVo item : emptyList(recordList)) { + addHealthScreenEvent(events, "档案", item.getName(), item.getPersonName(), item.getOccurTime(), cachedDictLabel(dictCache, "record_type", item.getType())); + } + for (HealthDoctorRecordVo item : emptyList(doctorRecordList)) { + addHealthScreenEvent(events, "就医", item.getHospitalName(), item.getPersonName(), item.getVisitingTime(), item.getDiagnosis()); + } + for (HealthMarRecordVo item : emptyList(marRecordList)) { + addHealthScreenEvent(events, "用药", StringUtils.isNotEmpty(item.getName()) ? item.getName() : "用药记录", item.getPersonName(), item.getDosingTime(), cachedDictLabel(dictCache, "mar_type", item.getType())); + } + for (HealthTemperatureRecordVo item : emptyList(temperatureRecordList)) { + addHealthScreenEvent(events, "体温", item.getTemperature() == null ? "--" : item.getTemperature() + "℃", item.getPersonName(), item.getMeasureTime(), item.getTemperature() != null && item.getTemperature() >= 37 ? "发热" : "正常"); + } + for (HealthActivityVo item : emptyList(activityList)) { + addHealthScreenEvent(events, "活动", item.getName(), item.getPartner(), item.getStartTime(), item.getPlace()); + } + events.sort((a, b) -> Long.compare((Long) b.get("sortTime"), (Long) a.get("sortTime"))); + return limitList(events, 50); + } + + private List> buildHealthScreenSuggestions(Map summary, + List temperatureRecordList, + List doctorRecordList, + List marRecordList) { + ArrayList> list = new ArrayList<>(); + int feverDayCount = parseInt(String.valueOf(summary.get("feverDayCount"))); + int doctorCount = parseInt(String.valueOf(summary.get("doctorCount"))); + int marCount = parseInt(String.valueOf(summary.get("marCount"))); + int temperatureCount = parseInt(String.valueOf(summary.get("temperatureTotalCount"))); + if (feverDayCount > 0) { + list.add(buildSuggestion("体温关注", "累计发热天数 " + feverDayCount + " 天,建议关注高温记录与就医结果。", "warning")); + } + if (doctorCount > 0) { + list.add(buildSuggestion("就医追踪", "已有 " + doctorCount + " 次就医记录,建议定期复盘诊断结果和费用结构。", "normal")); + } + if (marCount > 0) { + list.add(buildSuggestion("用药管理", "累计 " + marCount + " 次用药记录,建议结合用药计划检查执行稳定性。", "normal")); + } + if (temperatureCount == 0) { + list.add(buildSuggestion("体温数据", "暂无体温记录,建议补充日常监测数据。", "info")); + } + if (emptyList(doctorRecordList).isEmpty() && emptyList(marRecordList).isEmpty()) { + list.add(buildSuggestion("数据完整度", "就医和用药记录较少,可继续完善健康过程数据。", "info")); + } + return limitList(list, 5); + } + + private int buildHealthScreenIndex(List personList, + List recordList, + long doctorCount, + long marCount, + long feverDays, + long highTempCount) { + int score = 100; + int activeRecordCount = (int) emptyList(recordList).stream().filter(item -> "1".equals(item.getState()) || item.getRehabilitationTime() == null).count(); + score -= Math.min((int) feverDays * 5, 25); + score -= Math.min((int) highTempCount * 5, 20); + score -= Math.min((int) doctorCount * 2, 20); + score -= Math.min(activeRecordCount * 2, 12); + if (emptyList(personList).size() > 0 && emptyList(recordList).isEmpty()) { + score -= 10; + } + if (!emptyList(recordList).isEmpty() && marCount == 0 && doctorCount == 0) { + score -= 8; + } + return Math.max(score, 35); + } + + private double safeTotalCost(HealthDoctorRecordVo item) { + return item.getTotalCost() == null ? 0D : item.getTotalCost(); + } + + private int distinctDosingDateCount(List marRecordList) { + HashSet dateSet = new HashSet<>(); + for (HealthMarRecordVo item : marRecordList) { + String day = formatDay(item.getDosingTime()); + if (StringUtils.isNotEmpty(day)) { + dateSet.add(day); + } + } + return dateSet.size(); + } + + private String formatDay(Date date) { + if (date == null) { + return ""; + } + return new SimpleDateFormat("yyyy-MM-dd").format(date); + } + + private String formatMonth(Date date) { + if (date == null) { + return ""; + } + return new SimpleDateFormat("yyyy-MM").format(date); + } + + private void addHealthScreenEvent(List> events, String type, String title, String personName, Date time, String value) { + Map dataMap = new HashMap<>(); + dataMap.put("type", type); + dataMap.put("title", StringUtils.isNotEmpty(title) ? title : "--"); + dataMap.put("personName", StringUtils.isNotEmpty(personName) ? personName : "--"); + dataMap.put("time", formatDate(time)); + dataMap.put("value", StringUtils.isNotEmpty(value) ? value : "--"); + dataMap.put("sortTime", time == null ? 0L : time.getTime()); + events.add(dataMap); + } + + private Map buildSuggestion(String title, String content, String level) { + Map dataMap = new HashMap<>(); + dataMap.put("title", title); + dataMap.put("content", content); + dataMap.put("level", level); + return dataMap; + } + + private List> toNameValueList(Map source) { + ArrayList> list = new ArrayList<>(); + for (Map.Entry entry : source.entrySet()) { + Map dataMap = new HashMap<>(); + dataMap.put("name", entry.getKey()); + dataMap.put("value", entry.getValue()); + list.add(dataMap); + } + return list; + } + + private List> toTimeValueList(Map source, int limit) { + ArrayList> list = new ArrayList<>(); + for (Map.Entry entry : source.entrySet()) { + Map dataMap = new HashMap<>(); + dataMap.put("time", entry.getKey()); + dataMap.put("value", entry.getValue()); + list.add(dataMap); + } + return tailList(list, limit); + } + + private List> toTimeValueList(Map source, int limit, DecimalFormat decimalFormat) { + ArrayList> list = new ArrayList<>(); + for (Map.Entry entry : source.entrySet()) { + Map dataMap = new HashMap<>(); + dataMap.put("time", entry.getKey()); + dataMap.put("value", decimalFormat.format(entry.getValue())); + list.add(dataMap); + } + return tailList(list, limit); + } + + private List limitList(List source, int limit) { + if (source == null || source.size() <= limit) { + return source == null ? new ArrayList<>() : source; + } + return new ArrayList<>(source.subList(0, limit)); + } + + private List tailList(List source, int limit) { + if (source == null || source.size() <= limit) { + return source == null ? new ArrayList<>() : source; + } + return new ArrayList<>(source.subList(source.size() - limit, source.size())); + } + + private int parseInt(String value) { + if (StringUtils.isEmpty(value)) { + return 0; + } + try { + return Double.valueOf(value).intValue(); + } catch (NumberFormatException e) { + return 0; + } + } + + private double parseDouble(String value) { + if (StringUtils.isEmpty(value)) { + return 0D; + } + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + return 0D; + } + } + + private long longValue(Map map, String key) { + if (map == null || !map.containsKey(key) || map.get(key) == null) { + return 0L; + } + Object value = map.get(key); + if (value instanceof Number) { + return ((Number) value).longValue(); + } + try { + return Double.valueOf(String.valueOf(value)).longValue(); + } catch (NumberFormatException e) { + return 0L; + } + } + + private double numberValue(Map map, String key) { + if (map == null || !map.containsKey(key) || map.get(key) == null) { + return 0D; + } + Object value = map.get(key); + if (value instanceof Number) { + return ((Number) value).doubleValue(); + } + try { + return Double.parseDouble(String.valueOf(value)); + } catch (NumberFormatException e) { + return 0D; + } + } + + private void fillEmptyRecordScreen(Map map) { + HashMap summary = new HashMap<>(); + summary.put("processRecordCount", 0); + summary.put("doctorCount", 0); + summary.put("doctorCost", 0); + summary.put("marDayCount", 0); + summary.put("marCount", 0); + summary.put("feverDayCount", 0); + summary.put("recordList", new ArrayList<>()); + summary.put("recordCostList", new ArrayList<>()); + + HashMap doctor = new HashMap<>(); + doctor.put("doctorCostList", new ArrayList<>()); + + HashMap temperature = new HashMap<>(); + temperature.put("temperatureList", new ArrayList<>()); + temperature.put("averageTemp", 0); + temperature.put("maxTemp", 0); + temperature.put("minTemp", 0); + temperature.put("totalCount", 0); + + HashMap medicine = new HashMap<>(); + medicine.put("marMapList", new ArrayList<>()); + medicine.put("marList", new ArrayList<>()); + medicine.put("marDays", 0); + medicine.put("marCategoryCount", 0); + + map.put("record", null); + map.put("summary", summary); + map.put("doctor", doctor); + map.put("temperature", temperature); + map.put("medicine", medicine); + map.put("doctorRecordList", new ArrayList<>()); + map.put("processRecordList", new ArrayList<>()); + map.put("temperatureRecordList", new ArrayList<>()); + map.put("marRecordList", new ArrayList<>()); + } + + @Override + public void exportRecordFull(HttpServletResponse response, AnalysisDto analysisDto) throws IOException { + Long recordId = analysisDto.getRecordId(); + if (recordId == null) { + recordId = analysisDto.getId(); + } + if (recordId == null) { + throw new IllegalArgumentException("健康档案id不能为空"); + } + analysisDto.setRecordId(recordId); + analysisDto.setType(StringUtils.isEmpty(analysisDto.getType()) ? "1" : analysisDto.getType()); + + Map recordScreen = getRecordScreen(analysisDto); + HealthRecordVo record = (HealthRecordVo) recordScreen.get("record"); + String fileName = (record != null && StringUtils.isNotEmpty(record.getName()) ? record.getName() : "健康档案") + "健康档案报告.xlsx"; + + HealthDoctorRecordCostDto costDto = new HealthDoctorRecordCostDto(); + costDto.setHealthRecordId(recordId); + costDto.setPersonId(analysisDto.getId()); + List doctorRecordCostList = healthDoctorRecordCostMapper.selectHealthDoctorRecordCostList(costDto); + + try (Workbook workbook = new XSSFWorkbook()) { + createRecordReportSheet(workbook, recordScreen, doctorRecordCostList); + + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); + response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8")); + workbook.write(response.getOutputStream()); + } + } + + private AnalysisDto copyAnalysis(AnalysisDto source) { + AnalysisDto target = new AnalysisDto(); + target.setId(source.getId()); + target.setType(source.getType()); + target.setStartTime(source.getStartTime()); + target.setEndTime(source.getEndTime()); + target.setDataType(source.getDataType()); + target.setRecordId(source.getRecordId()); + return target; + } + + private List> buildRecordRows(HealthRecordVo record) { + List> rows = new ArrayList<>(); + if (record == null) { + return rows; + } + rows.add(Arrays.asList("档案名称", record.getName())); + rows.add(Arrays.asList("人员姓名", record.getPersonName())); + rows.add(Arrays.asList("档案类型", dictLabel("record_type", record.getType()))); + rows.add(Arrays.asList("档案状态", dictLabel("health_record_state", record.getState()))); + rows.add(Arrays.asList("发生原因", dictLabel("etiology", record.getEtiology()))); + rows.add(Arrays.asList("发生时间", formatReportDate(record.getOccurTime()))); + rows.add(Arrays.asList("康复时间", formatReportDate(record.getRehabilitationTime()))); + rows.add(Arrays.asList("康复周期", record.getDuration())); + rows.add(Arrays.asList("初期症状", record.getInitialSymptoms())); + rows.add(Arrays.asList("中期症状", record.getMediumTermSymptoms())); + rows.add(Arrays.asList("后期症状", record.getLaterStageSymptoms())); + rows.add(Arrays.asList("备注", record.getRemark())); + return rows; + } + + private List> buildSummaryRows(Map recordScreen) { + Map summary = (Map) recordScreen.get("summary"); + Map temperature = (Map) recordScreen.get("temperature"); + List> rows = new ArrayList<>(); + rows.add(Arrays.asList("过程记录", value(summary, "processRecordCount"))); + rows.add(Arrays.asList("就医次数", value(summary, "doctorCount"))); + rows.add(Arrays.asList("就医费用", value(summary, "doctorCost"))); + rows.add(Arrays.asList("就医医院", value(summary, "hospitalCount"))); + rows.add(Arrays.asList("医生数量", value(summary, "doctorTotalCount"))); + rows.add(Arrays.asList("用药天数", value(summary, "marDayCount"))); + rows.add(Arrays.asList("用药次数", value(summary, "marCount"))); + rows.add(Arrays.asList("发烧天数", value(summary, "feverDayCount"))); + rows.add(Arrays.asList("最高体温", value(temperature, "maxTemp"))); + rows.add(Arrays.asList("最低体温", value(temperature, "minTemp"))); + rows.add(Arrays.asList("平均体温", value(temperature, "averageTemp"))); + rows.add(Arrays.asList("测温次数", value(temperature, "totalCount"))); + return rows; + } + + private List> buildProcessRows(List list) { + List> rows = new ArrayList<>(); + for (HealthProcessRecordVo item : emptyList(list)) { + rows.add(Arrays.asList(formatDate(item.getRecordingTime()), item.getPersonName(), item.getHealthRecordName(), item.getContent(), item.getRemark())); + } + return rows; + } + + private List> buildDoctorRows(List list) { + List> rows = new ArrayList<>(); + for (HealthDoctorRecordVo item : emptyList(list)) { + rows.add(Arrays.asList(formatDate(item.getVisitingTime()), item.getPersonName(), item.getHealthRecordName(), item.getHospitalName(), item.getDepartments(), + item.getDoctor(), dictLabel("doctor_type", item.getType()), item.getTotalCost(), item.getDiagnosis(), item.getPrescribe(), item.getPartner(), item.getRemark())); + } + return rows; + } + + private List> buildDoctorCostRows(List list) { + List> rows = new ArrayList<>(); + for (HealthDoctorRecordCostVo item : emptyList(list)) { + rows.add(Arrays.asList(formatDate(item.getCostTime()), item.getCostName(), dictLabel("cost_type", item.getType()), dictLabel("check_type", item.getCheckType()), + item.getPrice(), item.getCount(), item.getUnit(), item.getTotalCost(), item.getRemark())); + } + return rows; + } + + private List> buildTemperatureRows(List list) { + List> rows = new ArrayList<>(); + for (HealthTemperatureRecordVo item : emptyList(list)) { + rows.add(Arrays.asList(formatDate(item.getMeasureTime()), item.getPersonName(), item.getHealthRecordName(), item.getTemperature(), item.getRemark())); + } + return rows; + } + + private List> buildMarRows(List list) { + List> rows = new ArrayList<>(); + for (HealthMarRecordVo item : emptyList(list)) { + rows.add(Arrays.asList(formatDate(item.getDosingTime()), item.getPersonName(), item.getHealthRecordName(), item.getName(), dictLabel("mar_type", item.getType()), + item.getDosage(), dictLabel("medical_unit", item.getUnit()), dictLabel("mar_resource", item.getResource()), dictLabel("mar_place", item.getPlace()), + item.getContent(), dictLabel("content_unit", item.getContentUnit()), item.getRemark())); + } + return rows; + } + + private void createRecordReportSheet(Workbook workbook, Map recordScreen, List doctorRecordCostList) { + Sheet sheet = workbook.createSheet("健康档案报告"); + setupRecordReportSheet(sheet); + + CellStyle titleStyle = createReportTitleStyle(workbook); + CellStyle subtitleStyle = createReportSubtitleStyle(workbook); + CellStyle sectionStyle = createReportSectionStyle(workbook); + CellStyle subSectionStyle = createReportSubSectionStyle(workbook); + CellStyle labelStyle = createReportLabelStyle(workbook); + CellStyle valueStyle = createReportValueStyle(workbook); + CellStyle tableHeaderStyle = createReportTableHeaderStyle(workbook); + CellStyle tableBodyStyle = createReportTableBodyStyle(workbook); + CellStyle tableNoWrapBodyStyle = createReportTableNoWrapBodyStyle(workbook); + + HealthRecordVo record = (HealthRecordVo) recordScreen.get("record"); + int rowIndex = 0; + + Row titleRow = sheet.createRow(rowIndex); + titleRow.setHeightInPoints(34); + String recordName = record == null || StringUtils.isEmpty(record.getName()) ? "健康档案" : record.getName(); + setMergedCell(sheet, rowIndex, rowIndex, 0, 7, + "健康档案报告 - " + recordName + " 导出时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()), + titleStyle); + rowIndex++; + rowIndex++; + + rowIndex = writeSectionTitle(sheet, rowIndex, "一、档案基础信息", sectionStyle); + rowIndex = writeKeyValueGrid(sheet, rowIndex, buildRecordReportRows(record), labelStyle, valueStyle); + rowIndex = writeWideKeyRows(sheet, rowIndex, buildRecordReportLongRows(record), labelStyle, valueStyle); + rowIndex++; + + rowIndex = writeSectionTitle(sheet, rowIndex, "二、核心统计概览", sectionStyle); + rowIndex = writeKeyValueGrid(sheet, rowIndex, buildReportSummaryRows(recordScreen), labelStyle, valueStyle); + rowIndex++; + + rowIndex = writeSectionTitle(sheet, rowIndex, "三、统计分析", sectionStyle); + rowIndex = writeSubSectionTitle(sheet, rowIndex, "每日体温用药明细", subSectionStyle); + rowIndex = writeDailyHealthDetailTable(sheet, rowIndex, buildDailyHealthDetailRows(recordScreen), tableHeaderStyle, tableBodyStyle); + rowIndex = writeSubSectionTitle(sheet, rowIndex, "体温统计", subSectionStyle); + rowIndex = writeReportTable(sheet, rowIndex, Arrays.asList("统计项", "数值", "统计项", "数值", "统计项", "数值", "统计项", "数值"), + buildTemperatureReportRows(recordScreen), 0, tableHeaderStyle, tableBodyStyle); + rowIndex = writeSubSectionTitle(sheet, rowIndex, "用药频次", subSectionStyle); + rowIndex = writeMedicineRankTable(sheet, rowIndex, buildMedicineRankReportRows(recordScreen), tableHeaderStyle, tableBodyStyle, tableNoWrapBodyStyle); + rowIndex = writeSubSectionTitle(sheet, rowIndex, "就医费用统计", subSectionStyle); + rowIndex = writeCostSummaryTable(sheet, rowIndex, buildCostSummaryReportRows(doctorRecordCostList), tableHeaderStyle, tableBodyStyle); + rowIndex++; + + rowIndex = writeSectionTitle(sheet, rowIndex, "四、档案全量明细", sectionStyle); + rowIndex = writeSubSectionTitle(sheet, rowIndex, "过程记录(共 " + emptyList((List) recordScreen.get("processRecordList")).size() + " 条)", subSectionStyle); + rowIndex = writeProcessReportTable(sheet, rowIndex, + buildProcessReportRows((List) recordScreen.get("processRecordList")), tableHeaderStyle, tableBodyStyle); + rowIndex = writeSubSectionTitle(sheet, rowIndex, "就医记录(共 " + emptyList((List) recordScreen.get("doctorRecordList")).size() + " 条)", subSectionStyle); + rowIndex = writeReportTable(sheet, rowIndex, Arrays.asList("就诊时间", "医院", "科室", "医生", "类型", "费用", "诊断", "处理及医嘱/备注"), + buildDoctorReportRows((List) recordScreen.get("doctorRecordList")), 0, tableHeaderStyle, tableBodyStyle); + rowIndex = writeSubSectionTitle(sheet, rowIndex, "就医费用明细(共 " + emptyList(doctorRecordCostList).size() + " 条)", subSectionStyle); + rowIndex = writeDoctorCostDetailTable(sheet, rowIndex, buildDoctorCostReportRows(doctorRecordCostList), tableHeaderStyle, tableBodyStyle); + rowIndex = writeSubSectionTitle(sheet, rowIndex, "体温记录(共 " + emptyList((List) recordScreen.get("temperatureRecordList")).size() + " 条)", subSectionStyle); + rowIndex = writeTemperatureDetailTable(sheet, rowIndex, buildTemperatureReportDetailRows((List) recordScreen.get("temperatureRecordList")), tableHeaderStyle, tableBodyStyle); + rowIndex = writeSubSectionTitle(sheet, rowIndex, "用药记录(共 " + emptyList((List) recordScreen.get("marRecordList")).size() + " 条)", subSectionStyle); + rowIndex = writeMarReportTable(sheet, rowIndex, buildMarReportRows((List) recordScreen.get("marRecordList")), tableHeaderStyle, tableBodyStyle, tableNoWrapBodyStyle); + + sheet.setRepeatingRows(CellRangeAddress.valueOf("1:1")); + workbook.setPrintArea(workbook.getSheetIndex(sheet), 0, 7, 0, Math.max(rowIndex, 1)); + } + + private void setupRecordReportSheet(Sheet sheet) { + int[] widths = {18, 14, 14, 18, 14, 18, 14, 22}; + for (int i = 0; i < widths.length; i++) { + sheet.setColumnWidth(i, widths[i] * 256); + } + sheet.setDisplayGridlines(false); + sheet.setFitToPage(true); + sheet.setAutobreaks(true); + sheet.createFreezePane(0, 2); + sheet.setMargin(Sheet.LeftMargin, 0.35D); + sheet.setMargin(Sheet.RightMargin, 0.35D); + sheet.setMargin(Sheet.TopMargin, 0.5D); + sheet.setMargin(Sheet.BottomMargin, 0.5D); + PrintSetup printSetup = sheet.getPrintSetup(); + printSetup.setPaperSize(PrintSetup.A4_PAPERSIZE); + printSetup.setFitWidth((short) 1); + printSetup.setFitHeight((short) 0); + printSetup.setLandscape(false); + sheet.setHorizontallyCenter(true); + } + + private List> buildRecordReportRows(HealthRecordVo record) { + List> rows = new ArrayList<>(); + if (record == null) { + rows.add(Arrays.asList("档案名称", "", "人员姓名", "", "档案类型", "", "档案状态", "")); + return rows; + } + rows.add(Arrays.asList("档案名称", record.getName(), "人员姓名", record.getPersonName(), "档案类型", dictLabel("record_type", record.getType()), "档案状态", dictLabel("health_record_state", record.getState()))); + rows.add(Arrays.asList("发生原因", dictLabel("etiology", record.getEtiology()), "发生时间", formatReportDate(record.getOccurTime()), "康复时间", formatReportDate(record.getRehabilitationTime()), "康复周期", record.getDuration())); + return rows; + } + + private List> buildRecordReportLongRows(HealthRecordVo record) { + List> rows = new ArrayList<>(); + if (record == null) { + return rows; + } + rows.add(Arrays.asList("初期症状", record.getInitialSymptoms())); + rows.add(Arrays.asList("中期症状", record.getMediumTermSymptoms())); + rows.add(Arrays.asList("后期症状", record.getLaterStageSymptoms())); + rows.add(Arrays.asList("备注", record.getRemark())); + return rows; + } + + private List> buildReportSummaryRows(Map recordScreen) { + Map summary = (Map) recordScreen.get("summary"); + Map temperature = (Map) recordScreen.get("temperature"); + List> rows = new ArrayList<>(); + rows.add(Arrays.asList("过程记录", value(summary, "processRecordCount"), "就医次数", value(summary, "doctorCount"), "就医费用", value(summary, "doctorCost"), "就医医院", value(summary, "hospitalCount"))); + rows.add(Arrays.asList("医生数量", value(summary, "doctorTotalCount"), "用药天数", value(summary, "marDayCount"), "用药次数", value(summary, "marCount"), "发热天数", value(summary, "feverDayCount"))); + rows.add(Arrays.asList("测温次数", value(temperature, "totalCount"), "平均体温", appendUnit(value(temperature, "averageTemp"), "℃"), "最高体温", appendUnit(value(temperature, "maxTemp"), "℃"), "最低体温", appendUnit(value(temperature, "minTemp"), "℃"))); + return rows; + } + + private List> buildDailyHealthDetailRows(Map recordScreen) { + TreeMap>> dayMap = new TreeMap<>(); + List processList = (List) recordScreen.get("processRecordList"); + List marList = (List) recordScreen.get("marRecordList"); + List temperatureList = (List) recordScreen.get("temperatureRecordList"); + + List sortedProcessList = new ArrayList<>(emptyList(processList)); + sortedProcessList.sort(Comparator.comparing(HealthProcessRecordVo::getRecordingTime, Comparator.nullsLast(Date::compareTo))); + for (HealthProcessRecordVo item : sortedProcessList) { + String day = formatDay(item.getRecordingTime()); + if (StringUtils.isNotEmpty(day)) { + dailyDetail(dayMap, day).get("process").add(formatTime(item.getRecordingTime()) + " " + stringify(item.getContent())); + } + } + + List sortedTemperatureList = new ArrayList<>(emptyList(temperatureList)); + sortedTemperatureList.sort(Comparator.comparing(HealthTemperatureRecordVo::getMeasureTime, Comparator.nullsLast(Date::compareTo))); + for (HealthTemperatureRecordVo item : sortedTemperatureList) { + String day = formatDay(item.getMeasureTime()); + if (StringUtils.isNotEmpty(day)) { + dailyDetail(dayMap, day).get("temperature").add(formatTime(item.getMeasureTime()) + " " + appendUnit(item.getTemperature(), "℃") + + (StringUtils.isNotEmpty(item.getRemark()) ? "(" + item.getRemark() + ")" : "")); + } + } + + List sortedMarList = new ArrayList<>(emptyList(marList)); + sortedMarList.sort(Comparator.comparing(HealthMarRecordVo::getDosingTime, Comparator.nullsLast(Date::compareTo))); + for (HealthMarRecordVo item : sortedMarList) { + String day = formatDay(item.getDosingTime()); + if (StringUtils.isNotEmpty(day)) { + String unit = dictLabel("medical_unit", item.getUnit()); + String content = appendUnit(item.getContent(), dictLabel("content_unit", item.getContentUnit())); + dailyDetail(dayMap, day).get("medicine").add(formatTime(item.getDosingTime()) + " " + stringify(item.getName()) + + " " + stringify(item.getDosage()) + (StringUtils.isNotEmpty(unit) ? "/" + unit : "") + + (StringUtils.isNotEmpty(content) ? " " + content : "")); + } + } + + List> rows = new ArrayList<>(); + for (Map.Entry>> entry : dayMap.entrySet()) { + Map> dataMap = entry.getValue(); + rows.add(Arrays.asList(entry.getKey(), joinLines(dataMap.get("process")), joinLines(dataMap.get("temperature")), joinLines(dataMap.get("medicine")))); + } + return rows; + } + + private Map> dailyDetail(TreeMap>> dayMap, String day) { + return dayMap.computeIfAbsent(day, key -> { + Map> dataMap = new HashMap<>(); + dataMap.put("process", new ArrayList<>()); + dataMap.put("temperature", new ArrayList<>()); + dataMap.put("medicine", new ArrayList<>()); + return dataMap; + }); + } + + private List> buildTemperatureReportRows(Map recordScreen) { + Map temperature = (Map) recordScreen.get("temperature"); + List> rows = new ArrayList<>(); + rows.add(Arrays.asList("测温次数", value(temperature, "totalCount"), "平均体温", appendUnit(value(temperature, "averageTemp"), "℃"), + "最高体温", appendUnit(value(temperature, "maxTemp"), "℃"), "最低体温", appendUnit(value(temperature, "minTemp"), "℃"))); + rows.add(Arrays.asList("正常次数", value(temperature, "normalTempCount"), "低热次数", value(temperature, "lowerTempCount"), + "中热次数", value(temperature, "middleTempCount"), "高热次数", value(temperature, "higherTempCount"))); + rows.add(Arrays.asList("发热天数", value(temperature, "feverDay"), "", "", "", "", "", "")); + return rows; + } + + private List> buildMedicineRankReportRows(Map recordScreen) { + Map medicine = (Map) recordScreen.get("medicine"); + List> rankList = medicine == null ? new ArrayList<>() : (List>) medicine.get("marMapList"); + List> rows = new ArrayList<>(); + for (Map item : emptyList(rankList)) { + String dosage = stringify(item.get("dosage")); + String unit = stringify(item.get("unit")); + rows.add(Arrays.asList(item.get("medicalName"), item.get("count"), item.get("useDays"), dosage + (StringUtils.isNotEmpty(unit) ? "/" + unit : ""))); + } + return rows; + } + + private List> buildCostSummaryReportRows(List list) { + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + LinkedHashMap> summaryMap = new LinkedHashMap<>(); + double totalCost = 0D; + for (HealthDoctorRecordCostVo item : emptyList(list)) { + double itemCost = item.getTotalCost() == null ? 0D : item.getTotalCost(); + totalCost += itemCost; + String typeName = dictLabel("cost_type", item.getType()); + typeName = StringUtils.isNotEmpty(typeName) ? typeName : "未分类"; + Map dataMap = summaryMap.computeIfAbsent(typeName, key -> { + Map valueMap = new HashMap<>(); + valueMap.put("count", 0); + valueMap.put("totalCost", 0D); + return valueMap; + }); + dataMap.put("count", ((Integer) dataMap.get("count")) + 1); + dataMap.put("totalCost", ((Double) dataMap.get("totalCost")) + itemCost); + } + + List> rows = new ArrayList<>(); + for (Map.Entry> entry : summaryMap.entrySet()) { + double itemTotal = (Double) entry.getValue().get("totalCost"); + rows.add(Arrays.asList(entry.getKey(), entry.getValue().get("count"), decimalFormat.format(itemTotal), totalCost == 0D ? "0%" : decimalFormat.format(itemTotal * 100 / totalCost) + "%")); + } + if (!rows.isEmpty()) { + rows.add(Arrays.asList("合计", emptyList(list).size(), decimalFormat.format(totalCost), "100%")); + } + return rows; + } + + private List> buildProcessReportRows(List list) { + List> rows = new ArrayList<>(); + List sortedList = new ArrayList<>(emptyList(list)); + sortedList.sort(Comparator.comparing(HealthProcessRecordVo::getRecordingTime, Comparator.nullsLast(Date::compareTo))); + for (HealthProcessRecordVo item : sortedList) { + rows.add(Arrays.asList(formatReportDate(item.getRecordingTime()), item.getPersonName(), item.getContent(), item.getRemark())); + } + return rows; + } + + private List> buildDoctorReportRows(List list) { + List> rows = new ArrayList<>(); + List sortedList = new ArrayList<>(emptyList(list)); + sortedList.sort(Comparator.comparing(HealthDoctorRecordVo::getVisitingTime, Comparator.nullsLast(Date::compareTo))); + for (HealthDoctorRecordVo item : sortedList) { + rows.add(Arrays.asList(formatReportDate(item.getVisitingTime()), item.getHospitalName(), item.getDepartments(), item.getDoctor(), dictLabel("doctor_type", item.getType()), + item.getTotalCost(), item.getDiagnosis(), joinText(item.getPrescribe(), item.getRemark()))); + } + return rows; + } + + private List> buildDoctorCostReportRows(List list) { + List> rows = new ArrayList<>(); + List sortedList = new ArrayList<>(emptyList(list)); + sortedList.sort(Comparator.comparing(HealthDoctorRecordCostVo::getCostTime, Comparator.nullsLast(Date::compareTo))); + for (HealthDoctorRecordCostVo item : sortedList) { + rows.add(Arrays.asList(formatReportDate(item.getCostTime()), item.getCostName(), item.getPrice(), item.getCount(), item.getUnit(), item.getTotalCost(), item.getRemark())); + } + return rows; + } + + private List> buildTemperatureReportDetailRows(List list) { + List> rows = new ArrayList<>(); + List sortedList = new ArrayList<>(emptyList(list)); + sortedList.sort(Comparator.comparing(HealthTemperatureRecordVo::getMeasureTime, Comparator.nullsLast(Date::compareTo))); + for (HealthTemperatureRecordVo item : sortedList) { + rows.add(Arrays.asList(formatReportDate(item.getMeasureTime()), item.getPersonName(), appendUnit(item.getTemperature(), "℃"), item.getRemark())); + } + return rows; + } + + private List> buildMarReportRows(List list) { + List> rows = new ArrayList<>(); + List sortedList = new ArrayList<>(emptyList(list)); + sortedList.sort(Comparator.comparing(HealthMarRecordVo::getDosingTime, Comparator.nullsLast(Date::compareTo))); + for (HealthMarRecordVo item : sortedList) { + rows.add(Arrays.asList(formatReportDate(item.getDosingTime()), item.getName(), dictLabel("mar_type", item.getType()), item.getDosage(), dictLabel("medical_unit", item.getUnit()), + appendUnit(item.getContent(), dictLabel("content_unit", item.getContentUnit())), item.getRemark())); + } + return rows; + } + + private int writeSectionTitle(Sheet sheet, int rowIndex, String title, CellStyle style) { + Row row = sheet.createRow(rowIndex); + row.setHeightInPoints(24); + setMergedCell(sheet, rowIndex, rowIndex, 0, 7, title, style); + return rowIndex + 1; + } + + private int writeSubSectionTitle(Sheet sheet, int rowIndex, String title, CellStyle style) { + Row row = sheet.createRow(rowIndex); + row.setHeightInPoints(22); + setMergedCell(sheet, rowIndex, rowIndex, 0, 7, title, style); + return rowIndex + 1; + } + + private int writeKeyValueGrid(Sheet sheet, int rowIndex, List> rows, CellStyle labelStyle, CellStyle valueStyle) { + if (rows == null || rows.isEmpty()) { + return rowIndex; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + for (int i = 0; i < 8; i++) { + Cell cell = row.createCell(i); + Object cellValue = i < rowData.size() ? rowData.get(i) : ""; + cell.setCellValue(stringify(cellValue)); + cell.setCellStyle(i % 2 == 0 ? labelStyle : valueStyle); + } + } + return rowIndex; + } + + private int writeWideKeyRows(Sheet sheet, int rowIndex, List> rows, CellStyle labelStyle, CellStyle valueStyle) { + if (rows == null || rows.isEmpty()) { + return rowIndex; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex); + row.setHeightInPoints(36); + Cell labelCell = row.createCell(0); + labelCell.setCellValue(stringify(rowData.get(0))); + labelCell.setCellStyle(labelStyle); + Cell valueCell = row.createCell(1); + valueCell.setCellValue(rowData.size() > 1 ? stringify(rowData.get(1)) : ""); + valueCell.setCellStyle(valueStyle); + for (int i = 2; i < 8; i++) { + Cell cell = row.createCell(i); + cell.setCellStyle(valueStyle); + } + sheet.addMergedRegion(new CellRangeAddress(rowIndex, rowIndex, 1, 7)); + rowIndex++; + } + return rowIndex; + } + + private int writeReportTable(Sheet sheet, int rowIndex, List headers, List> rows, int maxRows, CellStyle headerStyle, CellStyle bodyStyle) { + Row headerRow = sheet.createRow(rowIndex++); + headerRow.setHeightInPoints(24); + for (int i = 0; i < headers.size(); i++) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(headers.get(i)); + cell.setCellStyle(headerStyle); + } + if (rows == null || rows.isEmpty()) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, Math.max(headers.size() - 1, 0), "暂无数据", bodyStyle); + return rowIndex + 1; + } + + int writeCount = maxRows > 0 ? Math.min(maxRows, rows.size()) : rows.size(); + for (int i = 0; i < writeCount; i++) { + List rowData = rows.get(i); + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(32); + for (int j = 0; j < headers.size(); j++) { + Cell cell = row.createCell(j); + Object cellValue = j < rowData.size() ? rowData.get(j) : ""; + cell.setCellValue(stringify(cellValue)); + cell.setCellStyle(bodyStyle); + } + } + if (maxRows > 0 && rows.size() > maxRows) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(24); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, Math.max(headers.size() - 1, 0), "其余 " + (rows.size() - maxRows) + " 条明细请在系统中继续查看。", bodyStyle); + } + return rowIndex + 1; + } + + private int writeProcessReportTable(Sheet sheet, int rowIndex, List> rows, CellStyle headerStyle, CellStyle bodyStyle) { + Row headerRow = sheet.createRow(rowIndex++); + headerRow.setHeightInPoints(24); + setCell(headerRow, 0, "记录时间", headerStyle); + setCell(headerRow, 1, "人员", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 2, 5, "记录内容", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 6, 7, "备注", headerStyle); + if (rows == null || rows.isEmpty()) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 7, "暂无数据", bodyStyle); + return rowIndex + 1; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(32); + setCell(row, 0, rowData.size() > 0 ? rowData.get(0) : "", bodyStyle); + setCell(row, 1, rowData.size() > 1 ? rowData.get(1) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 2, 5, rowData.size() > 2 ? stringify(rowData.get(2)) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 6, 7, rowData.size() > 3 ? stringify(rowData.get(3)) : "", bodyStyle); + } + return rowIndex + 1; + } + + private int writeDailyHealthDetailTable(Sheet sheet, int rowIndex, List> rows, CellStyle headerStyle, CellStyle bodyStyle) { + Row headerRow = sheet.createRow(rowIndex++); + headerRow.setHeightInPoints(24); + setCell(headerRow, 0, "日期", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 1, 2, "过程明细", headerStyle); + setCell(headerRow, 3, "体温明细", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 4, 7, "用药明细", headerStyle); + if (rows == null || rows.isEmpty()) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 7, "暂无数据", bodyStyle); + return rowIndex + 1; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex++); + String processText = rowData.size() > 1 ? stringify(rowData.get(1)) : ""; + String temperatureText = rowData.size() > 2 ? stringify(rowData.get(2)) : ""; + String medicineText = rowData.size() > 3 ? stringify(rowData.get(3)) : ""; + row.setHeightInPoints(calcDetailRowHeight(processText, temperatureText, medicineText)); + setCell(row, 0, rowData.size() > 0 ? rowData.get(0) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 1, 2, processText, bodyStyle); + setCell(row, 3, temperatureText, bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 4, 7, medicineText, bodyStyle); + } + return rowIndex + 1; + } + + private int writeMedicineRankTable(Sheet sheet, int rowIndex, List> rows, CellStyle headerStyle, CellStyle bodyStyle, CellStyle noWrapBodyStyle) { + Row headerRow = sheet.createRow(rowIndex++); + headerRow.setHeightInPoints(24); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 0, 3, "药品", headerStyle); + setCell(headerRow, 4, "次数", headerStyle); + setCell(headerRow, 5, "用药天数", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 6, 7, "剂量/单位", headerStyle); + if (rows == null || rows.isEmpty()) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 7, "暂无数据", bodyStyle); + return rowIndex + 1; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 3, rowData.size() > 0 ? stringify(rowData.get(0)) : "", noWrapBodyStyle); + setCell(row, 4, rowData.size() > 1 ? rowData.get(1) : "", bodyStyle); + setCell(row, 5, rowData.size() > 2 ? rowData.get(2) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 6, 7, rowData.size() > 3 ? stringify(rowData.get(3)) : "", bodyStyle); + } + return rowIndex + 1; + } + + private int writeCostSummaryTable(Sheet sheet, int rowIndex, List> rows, CellStyle headerStyle, CellStyle bodyStyle) { + Row headerRow = sheet.createRow(rowIndex++); + headerRow.setHeightInPoints(24); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 0, 2, "费用类型", headerStyle); + setCell(headerRow, 3, "笔数", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 4, 5, "总金额", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 6, 7, "占比", headerStyle); + if (rows == null || rows.isEmpty()) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 7, "暂无数据", bodyStyle); + return rowIndex + 1; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 2, rowData.size() > 0 ? stringify(rowData.get(0)) : "", bodyStyle); + setCell(row, 3, rowData.size() > 1 ? rowData.get(1) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 4, 5, rowData.size() > 2 ? stringify(rowData.get(2)) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 6, 7, rowData.size() > 3 ? stringify(rowData.get(3)) : "", bodyStyle); + } + return rowIndex + 1; + } + + private int writeDoctorCostDetailTable(Sheet sheet, int rowIndex, List> rows, CellStyle headerStyle, CellStyle bodyStyle) { + Row headerRow = sheet.createRow(rowIndex++); + headerRow.setHeightInPoints(24); + setCell(headerRow, 0, "费用时间", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 1, 2, "费用名称", headerStyle); + setCell(headerRow, 3, "单价", headerStyle); + setCell(headerRow, 4, "数量", headerStyle); + setCell(headerRow, 5, "单位", headerStyle); + setCell(headerRow, 6, "总价", headerStyle); + setCell(headerRow, 7, "备注", headerStyle); + if (rows == null || rows.isEmpty()) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 7, "暂无数据", bodyStyle); + return rowIndex + 1; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(30); + setCell(row, 0, rowData.size() > 0 ? rowData.get(0) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 1, 2, rowData.size() > 1 ? stringify(rowData.get(1)) : "", bodyStyle); + setCell(row, 3, rowData.size() > 2 ? rowData.get(2) : "", bodyStyle); + setCell(row, 4, rowData.size() > 3 ? rowData.get(3) : "", bodyStyle); + setCell(row, 5, rowData.size() > 4 ? rowData.get(4) : "", bodyStyle); + setCell(row, 6, rowData.size() > 5 ? rowData.get(5) : "", bodyStyle); + setCell(row, 7, rowData.size() > 6 ? rowData.get(6) : "", bodyStyle); + } + return rowIndex + 1; + } + + private int writeTemperatureDetailTable(Sheet sheet, int rowIndex, List> rows, CellStyle headerStyle, CellStyle bodyStyle) { + Row headerRow = sheet.createRow(rowIndex++); + headerRow.setHeightInPoints(24); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 0, 1, "测量时间", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 2, 3, "人员", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 4, 5, "体温", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 6, 7, "备注", headerStyle); + if (rows == null || rows.isEmpty()) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 7, "暂无数据", bodyStyle); + return rowIndex + 1; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 1, rowData.size() > 0 ? stringify(rowData.get(0)) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 2, 3, rowData.size() > 1 ? stringify(rowData.get(1)) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 4, 5, rowData.size() > 2 ? stringify(rowData.get(2)) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 6, 7, rowData.size() > 3 ? stringify(rowData.get(3)) : "", bodyStyle); + } + return rowIndex + 1; + } + + private int writeMarReportTable(Sheet sheet, int rowIndex, List> rows, CellStyle headerStyle, CellStyle bodyStyle, CellStyle noWrapBodyStyle) { + Row headerRow = sheet.createRow(rowIndex++); + headerRow.setHeightInPoints(24); + setCell(headerRow, 0, "用药时间", headerStyle); + setMergedCell(sheet, headerRow.getRowNum(), headerRow.getRowNum(), 1, 3, "药品", headerStyle); + setCell(headerRow, 4, "类型", headerStyle); + setCell(headerRow, 5, "剂量", headerStyle); + setCell(headerRow, 6, "单位/含量", headerStyle); + setCell(headerRow, 7, "备注", headerStyle); + if (rows == null || rows.isEmpty()) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(28); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 0, 7, "暂无数据", bodyStyle); + return rowIndex + 1; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex++); + row.setHeightInPoints(30); + setCell(row, 0, rowData.size() > 0 ? rowData.get(0) : "", bodyStyle); + setMergedCell(sheet, row.getRowNum(), row.getRowNum(), 1, 3, rowData.size() > 1 ? stringify(rowData.get(1)) : "", noWrapBodyStyle); + setCell(row, 4, rowData.size() > 2 ? rowData.get(2) : "", bodyStyle); + setCell(row, 5, rowData.size() > 3 ? rowData.get(3) : "", bodyStyle); + setCell(row, 6, joinText(rowData.size() > 4 ? stringify(rowData.get(4)) : "", rowData.size() > 5 ? stringify(rowData.get(5)) : ""), bodyStyle); + setCell(row, 7, rowData.size() > 6 ? rowData.get(6) : "", bodyStyle); + } + return rowIndex + 1; + } + + private void setCell(Row row, int columnIndex, Object value, CellStyle style) { + Cell cell = row.getCell(columnIndex); + if (cell == null) { + cell = row.createCell(columnIndex); + } + cell.setCellValue(stringify(value)); + cell.setCellStyle(style); + } + + private void setMergedCell(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol, String value, CellStyle style) { + Row row = sheet.getRow(firstRow); + if (row == null) { + row = sheet.createRow(firstRow); + } + for (int i = firstCol; i <= lastCol; i++) { + Cell cell = row.getCell(i); + if (cell == null) { + cell = row.createCell(i); + } + cell.setCellStyle(style); + } + Cell cell = row.getCell(firstCol); + cell.setCellValue(value == null ? "" : value); + if (lastRow > firstRow || lastCol > firstCol) { + sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); + } + } + + private String appendUnit(Object value, String unit) { + String text = stringify(value); + if (StringUtils.isEmpty(text)) { + return ""; + } + return text + unit; + } + + private String joinText(String first, String second) { + if (StringUtils.isNotEmpty(first) && StringUtils.isNotEmpty(second)) { + return first + ";" + second; + } + return StringUtils.isNotEmpty(first) ? first : second; + } + + private String joinLines(List list) { + if (list == null || list.isEmpty()) { + return ""; + } + return String.join("\n", list); + } + + private float calcDetailRowHeight(String processText, String temperatureText, String medicineText) { + int lineCount = Math.max(countLines(processText), Math.max(countLines(temperatureText), countLines(medicineText))); + return Math.min(Math.max(24F, lineCount * 16F + 8F), 180F); + } + + private int countLines(String text) { + if (StringUtils.isEmpty(text)) { + return 1; + } + return text.split("\\n", -1).length; + } + + private String stringify(Object value) { + return value == null ? "" : String.valueOf(value); + } + + private List emptyList(List list) { + return list == null ? new ArrayList<>() : list; + } + + private Object value(Map map, String key) { + return map == null ? "" : map.get(key); + } + + private String dictLabel(String dictType, String value) { + if (StringUtils.isEmpty(value)) { + return ""; + } + String label = DictUtils.getDictLabel(dictType, value); + return StringUtils.isEmpty(label) ? value : label; + } + + private String cachedDictLabel(Map dictCache, String dictType, String value) { + if (StringUtils.isEmpty(value)) { + return ""; + } + if (dictCache == null) { + return dictLabel(dictType, value); + } + String key = dictType + ":" + value; + String label = dictCache.get(key); + if (label == null) { + label = dictLabel(dictType, value); + dictCache.put(key, label); + } + return label; + } + + private String formatDate(Date date) { + if (date == null) { + return ""; + } + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); + } + + private String formatReportDate(Date date) { + if (date == null) { + return ""; + } + return new SimpleDateFormat("yyyy-MM-dd HH:mm").format(date); + } + + private String formatTime(Date date) { + if (date == null) { + return ""; + } + return new SimpleDateFormat("HH:mm").format(date); + } + + private CellStyle createReportTitleStyle(Workbook workbook) { + CellStyle style = createBorderedStyle(workbook); + style.setFillForegroundColor(IndexedColors.DARK_BLUE.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font font = workbook.createFont(); + font.setBold(true); + font.setColor(IndexedColors.WHITE.getIndex()); + font.setFontHeightInPoints((short) 20); + style.setFont(font); + return style; + } + + private CellStyle createReportSubtitleStyle(Workbook workbook) { + CellStyle style = createBorderedStyle(workbook); + style.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setWrapText(true); + Font font = workbook.createFont(); + font.setColor(IndexedColors.DARK_BLUE.getIndex()); + font.setFontHeightInPoints((short) 10); + style.setFont(font); + return style; + } + + private CellStyle createReportSectionStyle(Workbook workbook) { + CellStyle style = createBorderedStyle(workbook); + style.setFillForegroundColor(IndexedColors.BLUE_GREY.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font font = workbook.createFont(); + font.setBold(true); + font.setColor(IndexedColors.WHITE.getIndex()); + font.setFontHeightInPoints((short) 12); + style.setFont(font); + return style; + } + + private CellStyle createReportSubSectionStyle(Workbook workbook) { + CellStyle style = createBorderedStyle(workbook); + style.setFillForegroundColor(IndexedColors.LIGHT_CORNFLOWER_BLUE.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font font = workbook.createFont(); + font.setBold(true); + font.setColor(IndexedColors.DARK_BLUE.getIndex()); + style.setFont(font); + return style; + } + + private CellStyle createReportLabelStyle(Workbook workbook) { + CellStyle style = createBorderedStyle(workbook); + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setWrapText(true); + Font font = workbook.createFont(); + font.setBold(true); + style.setFont(font); + return style; + } + + private CellStyle createReportValueStyle(Workbook workbook) { + CellStyle style = createBorderedStyle(workbook); + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setWrapText(true); + return style; + } + + private CellStyle createReportTableHeaderStyle(Workbook workbook) { + CellStyle style = createBorderedStyle(workbook); + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setWrapText(true); + Font font = workbook.createFont(); + font.setBold(true); + style.setFont(font); + return style; + } + + private CellStyle createReportTableBodyStyle(Workbook workbook) { + CellStyle style = createBorderedStyle(workbook); + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.TOP); + style.setWrapText(true); + return style; + } + + private CellStyle createReportTableNoWrapBodyStyle(Workbook workbook) { + CellStyle style = createBorderedStyle(workbook); + style.setAlignment(HorizontalAlignment.LEFT); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setWrapText(false); + return style; + } + + private CellStyle createBorderedStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setBorderTop(BorderStyle.THIN); + style.setBorderBottom(BorderStyle.THIN); + style.setBorderLeft(BorderStyle.THIN); + style.setBorderRight(BorderStyle.THIN); + style.setTopBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setBottomBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setLeftBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setRightBorderColor(IndexedColors.GREY_25_PERCENT.getIndex()); + return style; + } + + private CellStyle createHeaderStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + Font font = workbook.createFont(); + font.setBold(true); + style.setFont(font); + return style; + } + + private CellStyle createBodyStyle(Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setWrapText(true); + return style; + } + + private void createKeyValueSheet(Workbook workbook, String sheetName, CellStyle headerStyle, CellStyle bodyStyle, List> rows) { + createTableSheet(workbook, sheetName, headerStyle, bodyStyle, Arrays.asList("项目", "内容"), rows); + } + + private void createTableSheet(Workbook workbook, String sheetName, CellStyle headerStyle, CellStyle bodyStyle, List headers, List> rows) { + Sheet sheet = workbook.createSheet(sheetName); + Row headerRow = sheet.createRow(0); + for (int i = 0; i < headers.size(); i++) { + Cell cell = headerRow.createCell(i); + cell.setCellValue(headers.get(i)); + cell.setCellStyle(headerStyle); + sheet.setColumnWidth(i, Math.min(Math.max(headers.get(i).length() * 900, 4200), 12000)); + } + + int rowIndex = 1; + if (rows == null || rows.isEmpty()) { + Row row = sheet.createRow(rowIndex); + Cell cell = row.createCell(0); + cell.setCellValue("暂无数据"); + cell.setCellStyle(bodyStyle); + return; + } + for (List rowData : rows) { + Row row = sheet.createRow(rowIndex++); + for (int i = 0; i < headers.size(); i++) { + Cell cell = row.createCell(i); + Object cellValue = i < rowData.size() ? rowData.get(i) : ""; + cell.setCellValue(cellValue == null ? "" : String.valueOf(cellValue)); + cell.setCellStyle(bodyStyle); + } + } + } + + @Override + public Map getActivityAnalysis(AnalysisDto analysisDto) { + DecimalFormat decimalFormat = new DecimalFormat("#.##"); + HashMap map = new HashMap<>(); + if (analysisDto == null) { + analysisDto = new AnalysisDto(); + } + analysisDto.setType(StringUtils.isEmpty(analysisDto.getType()) ? "1" : analysisDto.getType()); + + Date[] dateRange = buildActivityDateRange(analysisDto); + List activityList = healthActivityMapper.selectHealthActivityList(new HealthActivityDto()); + ArrayList filterList = new ArrayList<>(); + for (HealthActivityVo item : emptyList(activityList)) { + if (!matchActivityAnalysis(item, analysisDto, dateRange[0], dateRange[1])) { + continue; + } + item.setExerciseTimeStr(formatActivityDuration(getActivityDurationSeconds(item))); + filterList.add(item); + } + filterList.sort(Comparator.comparing(HealthActivityVo::getStartTime, Comparator.nullsLast(Date::compareTo))); + + TreeMap countTrendMap = new TreeMap<>(); + TreeMap costTrendMap = new TreeMap<>(); + TreeMap durationTrendMap = new TreeMap<>(); + LinkedHashMap typeMap = new LinkedHashMap<>(); + LinkedHashMap volumeMap = new LinkedHashMap<>(); + HashMap> placeMap = new HashMap<>(); + HashMap> partnerMap = new HashMap<>(); + HashSet daySet = new HashSet<>(); + + double totalCost = 0D; + long totalSeconds = 0L; + double maxCost = 0D; + HealthActivityVo maxCostActivity = null; + HealthActivityVo longestActivity = null; + long longestSeconds = 0L; + + ArrayList> tableList = new ArrayList<>(); + for (HealthActivityVo item : filterList) { + double cost = item.getTotalCost() == null ? 0D : item.getTotalCost(); + long seconds = getActivityDurationSeconds(item); + totalCost += cost; + totalSeconds += seconds; + if (cost > maxCost) { + maxCost = cost; + maxCostActivity = item; + } + if (seconds > longestSeconds) { + longestSeconds = seconds; + longestActivity = item; + } + + String day = formatDay(item.getStartTime()); + String trendTime = formatActivityTrendTime(item.getStartTime(), analysisDto.getType()); + if (StringUtils.isNotEmpty(day)) { + daySet.add(day); + } + if (StringUtils.isNotEmpty(trendTime)) { + countTrendMap.put(trendTime, countTrendMap.getOrDefault(trendTime, 0) + 1); + costTrendMap.put(trendTime, costTrendMap.getOrDefault(trendTime, 0D) + cost); + durationTrendMap.put(trendTime, durationTrendMap.getOrDefault(trendTime, 0D) + seconds / 3600D); + } + + String typeName = dictLabel("activity_type", item.getType()); + typeName = StringUtils.isEmpty(typeName) ? "未设置" : typeName; + typeMap.put(typeName, typeMap.getOrDefault(typeName, 0) + 1); + + String volumeName = dictLabel("activity_exercise", item.getActivityVolume()); + volumeName = StringUtils.isEmpty(volumeName) ? "未设置" : volumeName; + volumeMap.put(volumeName, volumeMap.getOrDefault(volumeName, 0) + 1); + + addActivityRank(placeMap, StringUtils.isNotEmpty(item.getPlace()) ? item.getPlace() : "未设置", cost, seconds); + addActivityPartners(partnerMap, item.getPartner(), cost, seconds); + + Map table = new HashMap<>(); + table.put("time", formatActivityTrendTime(item.getStartTime(), analysisDto.getType())); + table.put("name", item.getName()); + table.put("type", item.getType()); + table.put("typeName", typeName); + table.put("place", item.getPlace()); + table.put("activityVolume", item.getActivityVolume()); + table.put("activityVolumeName", volumeName); + table.put("partner", item.getPartner()); + table.put("startTime", formatDate(item.getStartTime())); + table.put("endTime", formatDate(item.getEndTime())); + table.put("duration", formatActivityDuration(seconds)); + table.put("durationHours", decimalFormat.format(seconds / 3600D)); + table.put("totalCost", decimalFormat.format(cost)); + table.put("foods", item.getFoods()); + table.put("harvest", item.getHarvest()); + table.put("remark", item.getRemark()); + tableList.add(table); + } + + Collections.reverse(tableList); + + map.put("activityCount", filterList.size()); + map.put("activityDays", daySet.size()); + map.put("totalCost", decimalFormat.format(totalCost)); + map.put("totalHours", decimalFormat.format(totalSeconds / 3600D)); + map.put("avgCost", decimalFormat.format(filterList.isEmpty() ? 0D : totalCost / filterList.size())); + map.put("avgHours", decimalFormat.format(filterList.isEmpty() ? 0D : totalSeconds / 3600D / filterList.size())); + map.put("maxCost", decimalFormat.format(maxCost)); + map.put("maxCostName", maxCostActivity == null ? "--" : maxCostActivity.getName()); + map.put("longestHours", decimalFormat.format(longestSeconds / 3600D)); + map.put("longestName", longestActivity == null ? "--" : longestActivity.getName()); + map.put("typeList", toNameValueList(typeMap)); + map.put("volumeList", toNameValueList(volumeMap)); + map.put("placeList", sortActivityRank(placeMap, decimalFormat, 10)); + map.put("partnerList", sortActivityRank(partnerMap, decimalFormat, 10)); + map.put("countTrend", toTimeValueList(countTrendMap, 366)); + map.put("costTrend", toTimeValueList(costTrendMap, 366, decimalFormat)); + map.put("durationTrend", toTimeValueList(durationTrendMap, 366, decimalFormat)); + map.put("tableList", tableList); + return map; + } + + private Date[] buildActivityDateRange(AnalysisDto analysisDto) { + String startTime = analysisDto.getStartTime(); + String endTime = analysisDto.getEndTime(); + if ("2".equals(analysisDto.getType())) { + if (StringUtils.isNotEmpty(startTime)) { + startTime = startTime + "-01"; + } + if (StringUtils.isNotEmpty(endTime)) { + String currentMonth = new SimpleDateFormat("yyyy-MM").format(new Date()); + if (endTime.equals(currentMonth)) { + endTime = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); + } else { + endTime = getActivityMonthLastDay(endTime); + } + } + } else if ("3".equals(analysisDto.getType())) { + if (StringUtils.isNotEmpty(startTime)) { + startTime = startTime + "-01-01"; + } + if (StringUtils.isNotEmpty(endTime)) { + String currentYear = new SimpleDateFormat("yyyy").format(new Date()); + if (endTime.equals(currentYear)) { + endTime = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); + } else { + endTime = endTime + "-12-31"; + } + } + } + return new Date[]{parseActivityDate(startTime, false), parseActivityDate(endTime, true)}; + } + + private String getActivityMonthLastDay(String month) { + try { + Date date = new SimpleDateFormat("yyyy-MM-dd").parse(month + "-01"); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); + return new SimpleDateFormat("yyyy-MM-dd").format(calendar.getTime()); + } catch (Exception e) { + return month + "-31"; + } + } + + private Date parseActivityDate(String value, boolean endOfDay) { + if (StringUtils.isEmpty(value)) { + return null; + } + try { + Date date = new SimpleDateFormat("yyyy-MM-dd").parse(value); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + if (endOfDay) { + calendar.set(Calendar.HOUR_OF_DAY, 23); + calendar.set(Calendar.MINUTE, 59); + calendar.set(Calendar.SECOND, 59); + calendar.set(Calendar.MILLISECOND, 999); + } else { + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MILLISECOND, 0); + } + return calendar.getTime(); + } catch (Exception e) { + return null; + } + } + + private boolean matchActivityAnalysis(HealthActivityVo item, AnalysisDto analysisDto, Date startDate, Date endDate) { + if (item == null || item.getStartTime() == null) { + return false; + } + if (startDate != null && item.getStartTime().before(startDate)) { + return false; + } + if (endDate != null && item.getStartTime().after(endDate)) { + return false; + } + if (StringUtils.isNotEmpty(analysisDto.getName()) && (StringUtils.isEmpty(item.getName()) || !item.getName().contains(analysisDto.getName()))) { + return false; + } + if (StringUtils.isNotEmpty(analysisDto.getActivityType()) && !analysisDto.getActivityType().equals(item.getType())) { + return false; + } + if (StringUtils.isNotEmpty(analysisDto.getPlace()) && (StringUtils.isEmpty(item.getPlace()) || !item.getPlace().contains(analysisDto.getPlace()))) { + return false; + } + return StringUtils.isEmpty(analysisDto.getActivityVolume()) || analysisDto.getActivityVolume().equals(item.getActivityVolume()); + } + + private String formatActivityTrendTime(Date date, String type) { + if (date == null) { + return ""; + } + if ("2".equals(type)) { + return new SimpleDateFormat("yyyy-MM").format(date); + } + if ("3".equals(type)) { + return new SimpleDateFormat("yyyy").format(date); + } + return formatDay(date); + } + + private long getActivityDurationSeconds(HealthActivityVo item) { + if (item == null) { + return 0L; + } + if (StringUtils.isNotEmpty(item.getExerciseTime())) { + try { + return Math.max(Long.parseLong(item.getExerciseTime()), 0L); + } catch (NumberFormatException ignored) { + } + } + if (item.getStartTime() != null && item.getEndTime() != null) { + return Math.max((item.getEndTime().getTime() - item.getStartTime().getTime()) / 1000, 0L); + } + return 0L; + } + + private String formatActivityDuration(long seconds) { + long days = seconds / 86400; + long hours = (seconds % 86400) / 3600; + long minutes = (seconds % 3600) / 60; + if (days > 0) { + return days + "天" + hours + "小时" + minutes + "分钟"; + } + if (hours > 0) { + return hours + "小时" + minutes + "分钟"; + } + return minutes + "分钟"; + } + + private void addActivityPartners(Map> rankMap, String partner, double cost, long seconds) { + if (StringUtils.isEmpty(partner)) { + addActivityRank(rankMap, "未设置", cost, seconds); + return; + } + String[] names = partner.split("[,,、;;\\s]+"); + boolean added = false; + for (String name : names) { + if (StringUtils.isNotEmpty(name)) { + addActivityRank(rankMap, name, cost, seconds); + added = true; + } + } + if (!added) { + addActivityRank(rankMap, partner, cost, seconds); + } + } + + private void addActivityRank(Map> rankMap, String name, double cost, long seconds) { + Map rank = rankMap.computeIfAbsent(name, key -> { + Map dataMap = new HashMap<>(); + dataMap.put("name", key); + dataMap.put("count", 0); + dataMap.put("cost", 0D); + dataMap.put("seconds", 0L); + return dataMap; + }); + rank.put("count", ((Integer) rank.get("count")) + 1); + rank.put("cost", ((Double) rank.get("cost")) + cost); + rank.put("seconds", ((Long) rank.get("seconds")) + seconds); + } + + private List> sortActivityRank(Map> source, DecimalFormat decimalFormat, int limit) { + ArrayList> list = new ArrayList<>(); + for (Map item : source.values()) { + Map dataMap = new HashMap<>(); + long seconds = (Long) item.get("seconds"); + dataMap.put("name", item.get("name")); + dataMap.put("count", item.get("count")); + dataMap.put("cost", decimalFormat.format((Double) item.get("cost"))); + dataMap.put("hours", decimalFormat.format(seconds / 3600D)); + list.add(dataMap); + } + list.sort((a, b) -> Integer.compare((Integer) b.get("count"), (Integer) a.get("count"))); + return limitList(list, limit); + } + @Override public Map getDoctorAnalysis(AnalysisDto analysisDto) { //返回数据 diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/ChronicDiseaseManageMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/ChronicDiseaseManageMapper.xml new file mode 100644 index 0000000..170fe63 --- /dev/null +++ b/intc-modules/intc-health/src/main/resources/mapper/health/ChronicDiseaseManageMapper.xml @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select a.id, a.chronic_disease_id, a.person_id, a.indicator_type, a.indicator_name, + a.measure_time, a.indicator_value, a.indicator_unit, a.target_min, a.target_max, + a.status, a.notes, a.create_by, a.create_time, a.update_by, a.update_time, + a.remark, a.del_flag + from chronic_disease_indicator_record a + inner join health_person p on a.person_id = p.id and p.del_flag = '0' + + + + + + + + insert into chronic_disease_indicator_record + + id, + chronic_disease_id, + person_id, + indicator_type, + indicator_name, + measure_time, + indicator_value, + indicator_unit, + target_min, + target_max, + status, + notes, + create_by, + create_time, + remark, + del_flag, + + + #{id}, + #{chronicDiseaseId}, + #{personId}, + #{indicatorType}, + #{indicatorName}, + #{measureTime}, + #{indicatorValue}, + #{indicatorUnit}, + #{targetMin}, + #{targetMax}, + #{status}, + #{notes}, + #{createBy}, + #{createTime}, + #{remark}, + 0, + + + + + update chronic_disease_indicator_record + + chronic_disease_id = #{chronicDiseaseId}, + person_id = #{personId}, + indicator_type = #{indicatorType}, + indicator_name = #{indicatorName}, + measure_time = #{measureTime}, + indicator_value = #{indicatorValue}, + indicator_unit = #{indicatorUnit}, + target_min = #{targetMin}, + target_max = #{targetMax}, + status = #{status}, + notes = #{notes}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + update chronic_disease_indicator_record set del_flag = 1 where id in + #{id} + + + + select a.id, a.chronic_disease_id, a.person_id, a.follow_up_type, a.follow_up_date, + a.hospital, a.department, a.doctor, a.check_items, a.result, a.next_follow_up_date, + a.status, a.notes, a.create_by, a.create_time, a.update_by, a.update_time, + a.remark, a.del_flag + from chronic_disease_follow_up_record a + inner join health_person p on a.person_id = p.id and p.del_flag = '0' + + + + + + + + insert into chronic_disease_follow_up_record + + id, + chronic_disease_id, + person_id, + follow_up_type, + follow_up_date, + hospital, + department, + doctor, + check_items, + result, + next_follow_up_date, + status, + notes, + create_by, + create_time, + remark, + del_flag, + + + #{id}, + #{chronicDiseaseId}, + #{personId}, + #{followUpType}, + #{followUpDate}, + #{hospital}, + #{department}, + #{doctor}, + #{checkItems}, + #{result}, + #{nextFollowUpDate}, + #{status}, + #{notes}, + #{createBy}, + #{createTime}, + #{remark}, + 0, + + + + + update chronic_disease_follow_up_record + + chronic_disease_id = #{chronicDiseaseId}, + person_id = #{personId}, + follow_up_type = #{followUpType}, + follow_up_date = #{followUpDate}, + hospital = #{hospital}, + department = #{department}, + doctor = #{doctor}, + check_items = #{checkItems}, + result = #{result}, + next_follow_up_date = #{nextFollowUpDate}, + status = #{status}, + notes = #{notes}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + update chronic_disease_follow_up_record set del_flag = 1 where id in + #{id} + + + + select a.id, a.chronic_disease_id, a.person_id, a.old_status, a.new_status, + a.change_time, a.reason, a.treatment_advice, a.create_by, a.create_time, + a.update_by, a.update_time, a.remark, a.del_flag + from chronic_disease_status_history a + inner join health_person p on a.person_id = p.id and p.del_flag = '0' + + + + + + insert into chronic_disease_status_history + + id, + chronic_disease_id, + person_id, + old_status, + new_status, + change_time, + reason, + treatment_advice, + create_by, + create_time, + remark, + del_flag, + + + #{id}, + #{chronicDiseaseId}, + #{personId}, + #{oldStatus}, + #{newStatus}, + #{changeTime}, + #{reason}, + #{treatmentAdvice}, + #{createBy}, + #{createTime}, + #{remark}, + 0, + + + diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/ChronicDiseaseRecordMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/ChronicDiseaseRecordMapper.xml index b2aac63..23ce782 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/ChronicDiseaseRecordMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/ChronicDiseaseRecordMapper.xml @@ -33,7 +33,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" a.create_by, a.create_time, a.update_by, a.update_time, a.del_flag, a.remark, p.name as person_name from chronic_disease_record a - left join health_person p on a.person_id = p.id + inner join health_person p on a.person_id = p.id and p.del_flag = '0' where a.id = #{id} + and exists (select 1 from health_person hp where hp.id = a.person_id and hp.del_flag = '0') diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthDoctorRecordMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthDoctorRecordMapper.xml index 25e397a..1e1b9a9 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/HealthDoctorRecordMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/HealthDoctorRecordMapper.xml @@ -53,8 +53,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" hr."name" as health_record_name from health_doctor_record a - left join health_person hp on - hp.id = a.person_id + inner join health_person hp on + hp.id = a.person_id and hp.del_flag = '0' left join health_record hr on hr.id = a.health_record_id diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthHeightWeightRecordMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthHeightWeightRecordMapper.xml index 9c470f6..be34a0e 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/HealthHeightWeightRecordMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/HealthHeightWeightRecordMapper.xml @@ -35,8 +35,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" hp."name" as person_name from health_height_weight_record a - left join health_person hp on - hp.id = a.person_id + inner join health_person hp on + hp.id = a.person_id and hp.del_flag = '0' @@ -42,7 +43,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" @@ -64,6 +65,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ranking, sex, identity_card, + phone, #{id}, @@ -82,6 +84,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{ranking}, #{sex}, #{identityCard}, + #{phone}, @@ -103,6 +106,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ranking = #{ranking}, sex = #{sex}, identity_card = #{identityCard}, + phone = #{phone}, where id = #{id} diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthProcessRecordMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthProcessRecordMapper.xml index ea0d6a4..77ae423 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/HealthProcessRecordMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/HealthProcessRecordMapper.xml @@ -38,8 +38,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" hr."name" as health_record_name from health_process_record a - left join health_person hp on - hp.id = a.person_id + inner join health_person hp on + hp.id = a.person_id and hp.del_flag = '0' left join health_record hr on hr.id = a.health_record_id diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthRecordMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthRecordMapper.xml index a378a85..4c68b5d 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/HealthRecordMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/HealthRecordMapper.xml @@ -47,8 +47,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" hp."name" as person_name from health_record a - left join health_person hp on - hp.id = a.person_id + inner join health_person hp on + hp.id = a.person_id and hp.del_flag = '0' @@ -118,6 +118,7 @@ @@ -128,12 +129,14 @@ update medication_task set status = 2, update_time = current_timestamp where del_flag = 0 and status = 0 + and exists (select 1 from health_person hp where hp.id = person_id and hp.del_flag = '0') and (planned_date || ' ' || planned_time)::timestamp < #{expireThreshold} @@ -159,6 +162,7 @@ then 1 else 0 end) as ontime_tasks from medication_task where del_flag = 0 + and exists (select 1 from health_person hp where hp.id = person_id and hp.del_flag = '0') and person_id = #{personId} and planned_date >= #{startDate} and planned_date <= #{endDate} @@ -176,6 +180,7 @@ then 1 else 0 end) as ontime_tasks from medication_task where del_flag = 0 + and exists (select 1 from health_person hp where hp.id = person_id and hp.del_flag = '0') and person_id = #{personId} and planned_date >= #{startDate} and planned_date <= #{endDate} @@ -194,10 +199,11 @@ then 1 else 0 end) as ontime_tasks from medication_task where del_flag = 0 + and exists (select 1 from health_person hp where hp.id = person_id and hp.del_flag = '0') and person_id = #{personId} and planned_date >= #{startDate} and planned_date <= #{endDate} group by extract(hour from planned_time) order by hour - \ No newline at end of file + diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/StatisticAnalysisMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/StatisticAnalysisMapper.xml index ff6d343..cc1463f 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/StatisticAnalysisMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/StatisticAnalysisMapper.xml @@ -54,12 +54,13 @@ health_mar_record hmr left join health_medicine_basic hmb on hmb.id = hmr.medicine_id - left join health_person hp on - hp.id = hmr.person_id + inner join health_person hp on + hp.id = hmr.person_id and hp.del_flag = '0' left join health_record hr on hr.id = hmr.health_record_id hmr.del_flag = '0' + and exists (select 1 from health_person hp where hp.id = hmr.person_id and hp.del_flag = '0') and #{endTime}>=to_char(hmr.dosing_time, 'yyyy-MM-dd') @@ -92,6 +93,7 @@ left join health_record hr on hr.id=hmr.health_record_id hmr.del_flag = '0' + and exists (select 1 from health_person hp where hp.id = hmr.person_id and hp.del_flag = '0') and #{endTime}>=to_char(hr.occur_time, 'yyyy-MM-dd') @@ -112,6 +114,7 @@ left join health_record hr on hr.id=hmr.health_record_id hmr.del_flag = '0' + and exists (select 1 from health_person hp where hp.id = hmr.person_id and hp.del_flag = '0') and #{endTime}>=to_char(hr.occur_time, 'yyyy-MM-dd') @@ -133,6 +136,7 @@ left join health_record hr on hr.id=hmr.health_record_id hmr.del_flag = '0' + and exists (select 1 from health_person hp where hp.id = hmr.person_id and hp.del_flag = '0') and #{endTime}>=to_char(hr.occur_time, 'yyyy-MM-dd') @@ -155,6 +159,7 @@ left join health_record hr on hr.id=hmr.health_record_id hmr.del_flag = '0' + and exists (select 1 from health_person hp where hp.id = hmr.person_id and hp.del_flag = '0') and #{endTime}>=to_char(hr.occur_time, 'yyyy-MM-dd') @@ -180,6 +185,7 @@ left join health_record hr on hr.id=hmr.health_record_id hmr.del_flag = '0' + and exists (select 1 from health_person hp where hp.id = hmr.person_id and hp.del_flag = '0') and #{endTime}>=to_char(hr.occur_time, 'yyyy-MM-dd') @@ -204,6 +210,7 @@ left join health_record hr on hr.id=hmr.health_record_id hmr.del_flag = '0' + and exists (select 1 from health_person hp where hp.id = hmr.person_id and hp.del_flag = '0') and #{endTime}>=to_char(hr.occur_time, 'yyyy-MM-dd') @@ -225,6 +232,7 @@ left join health_record hr on hr.id=hmr.health_record_id hmr.del_flag = '0' and hmr.temperature>=37 + and exists (select 1 from health_person hp where hp.id = hmr.person_id and hp.del_flag = '0') and #{endTime}>=to_char(hr.occur_time, 'yyyy-MM-dd') @@ -241,89 +249,340 @@ + + + + + + + + + + + + + + + + + + - \ No newline at end of file +