From eaa823a8b72dad1f731b2b9017203ee608e6d94a Mon Sep 17 00:00:00 2001 From: bot5 Date: Tue, 17 Mar 2026 23:32:37 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat(health):=20=E6=96=B0=E5=A2=9E=E6=85=A2?= =?UTF-8?q?=E6=80=A7=E7=96=BE=E7=97=85=E6=A1=A3=E6=A1=88=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增慢性疾病档案实体类、VO、DTO - 新增Mapper接口和MyBatis映射文件 - 新增Service接口和实现类 - 新增Controller控制器 - 新增数据库建表SQL、菜单和字典数据 - 支持关联成员和疾病知识库 - 支持疾病状态管理和启用/停用 --- .../ChronicDiseaseRecordController.java | 128 +++++++++++++ .../health/domain/ChronicDiseaseRecord.java | 119 ++++++++++++ .../domain/dto/ChronicDiseaseRecordDto.java | 55 ++++++ .../domain/vo/ChronicDiseaseRecordVo.java | 24 +++ .../mapper/ChronicDiseaseRecordMapper.java | 87 +++++++++ .../service/IChronicDiseaseRecordService.java | 71 ++++++++ .../impl/ChronicDiseaseRecordServiceImpl.java | 124 +++++++++++++ .../health/ChronicDiseaseRecordMapper.xml | 172 ++++++++++++++++++ sql/chronic_disease_record.sql | 105 +++++++++++ 9 files changed, 885 insertions(+) create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseRecordController.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/ChronicDiseaseRecordDto.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/ChronicDiseaseRecordVo.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseRecordMapper.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/IChronicDiseaseRecordService.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/impl/ChronicDiseaseRecordServiceImpl.java create mode 100644 intc-modules/intc-health/src/main/resources/mapper/health/ChronicDiseaseRecordMapper.xml create mode 100644 sql/chronic_disease_record.sql diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseRecordController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseRecordController.java new file mode 100644 index 0000000..06d3524 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseRecordController.java @@ -0,0 +1,128 @@ +package com.intc.health.controller; + +import java.util.List; +import java.io.IOException; +import javax.servlet.http.HttpServletResponse; +import javax.annotation.Resource; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +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.ChronicDiseaseRecord; +import com.intc.health.domain.vo.ChronicDiseaseRecordVo; +import com.intc.health.domain.dto.ChronicDiseaseRecordDto; +import com.intc.health.service.IChronicDiseaseRecordService; +import com.intc.common.core.web.controller.BaseController; +import com.intc.common.core.web.domain.AjaxResult; +import com.intc.common.core.utils.poi.ExcelUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import com.intc.common.core.web.page.TableDataInfo; + +/** + * 慢性疾病档案Controller + * + * @author bot5 + * @date 2026-03-17 + */ +@Api(tags = "慢性疾病档案") +@RestController +@RequestMapping("/chronicDisease") +public class ChronicDiseaseRecordController extends BaseController +{ + @Resource + private IChronicDiseaseRecordService chronicDiseaseRecordService; + + /** + * 查询慢性疾病档案列表 + */ + @ApiOperation(value = "查询慢性疾病档案列表", response = ChronicDiseaseRecordVo.class) + @RequiresPermissions("health:chronicDisease:list") + @GetMapping("/list") + public TableDataInfo list(ChronicDiseaseRecordDto chronicDiseaseRecordDto) + { + startPage(); + List list = chronicDiseaseRecordService.selectChronicDiseaseRecordList(chronicDiseaseRecordDto); + return getDataTable(list); + } + + /** + * 根据成员ID查询慢性疾病档案列表 + */ + @ApiOperation(value = "根据成员ID查询慢性疾病档案列表", response = ChronicDiseaseRecordVo.class) + @RequiresPermissions("health:chronicDisease:list") + @GetMapping("/listByMember/{memberId}") + public AjaxResult listByMember(@PathVariable("memberId") Long memberId) + { + List list = chronicDiseaseRecordService.selectChronicDiseaseRecordByMemberId(memberId); + return success(list); + } + + /** + * 导出慢性疾病档案列表 + */ + @ApiOperation(value = "导出慢性疾病档案列表") + @RequiresPermissions("health:chronicDisease:export") + @Log(title = "慢性疾病档案", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, ChronicDiseaseRecordDto chronicDiseaseRecordDto) + { + List list = chronicDiseaseRecordService.selectChronicDiseaseRecordList(chronicDiseaseRecordDto); + ExcelUtil util = new ExcelUtil(ChronicDiseaseRecordVo.class); + util.exportExcel(response, list, "慢性疾病档案数据"); + } + + /** + * 获取慢性疾病档案详细信息 + */ + @ApiOperation(value = "获取慢性疾病档案详细信息") + @RequiresPermissions("health:chronicDisease:query") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(chronicDiseaseRecordService.selectChronicDiseaseRecordById(id)); + } + + /** + * 新增慢性疾病档案 + */ + @ApiOperation(value = "新增慢性疾病档案") + @RequiresPermissions("health:chronicDisease:add") + @Log(title = "慢性疾病档案", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody ChronicDiseaseRecord chronicDiseaseRecord) + { + return toAjax(chronicDiseaseRecordService.insertChronicDiseaseRecord(chronicDiseaseRecord)); + } + + /** + * 修改慢性疾病档案 + */ + @ApiOperation(value = "修改慢性疾病档案") + @RequiresPermissions("health:chronicDisease:edit") + @Log(title = "慢性疾病档案", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody ChronicDiseaseRecord chronicDiseaseRecord) + { + return toAjax(chronicDiseaseRecordService.updateChronicDiseaseRecord(chronicDiseaseRecord)); + } + + /** + * 删除慢性疾病档案 + */ + @ApiOperation(value = "删除慢性疾病档案") + @RequiresPermissions("health:chronicDisease:remove") + @Log(title = "慢性疾病档案", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(chronicDiseaseRecordService.deleteChronicDiseaseRecordByIds(ids)); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java new file mode 100644 index 0000000..6c4006b --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java @@ -0,0 +1,119 @@ +package com.intc.health.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.intc.common.core.annotation.Excel; +import com.intc.common.core.web.domain.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 慢性疾病档案对象 chronic_disease_record + * + * @author bot5 + * @date 2026-03-17 + */ +@ApiModel("慢性疾病档案对象") +@Data +public class ChronicDiseaseRecord extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键 */ + private Long id; + + /** 关联成员ID */ + @ApiModelProperty(value = "关联成员ID") + @NotNull(message = "成员不能为空") + @Excel(name = "成员ID") + private Long memberId; + + /** 成员名称(冗余字段) */ + @Excel(name = "成员名称") + private String memberName; + + /** 关联疾病ID(关联health_diseases表,可选) */ + @ApiModelProperty(value = "关联疾病ID") + @Excel(name = "疾病ID") + private Long diseaseId; + + /** 疾病名称 */ + @ApiModelProperty(value = "疾病名称") + @NotNull(message = "疾病名称不能为空") + @Excel(name = "疾病名称") + private String diseaseName; + + /** 疾病编码(ICD-10标准) */ + @ApiModelProperty(value = "疾病编码(ICD-10标准)") + @Excel(name = "疾病编码") + private String diseaseCode; + + /** 确诊日期 */ + @ApiModelProperty(value = "确诊日期") + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "确诊日期", width = 30, dateFormat = "yyyy-MM-dd") + private Date diagnosisDate; + + /** 状态:1-稳定 2-需关注 3-急性期 */ + @ApiModelProperty(value = "状态:1-稳定 2-需关注 3-急性期") + @NotNull(message = "状态不能为空") + @Excel(name = "状态", readConverterExp = "1=稳定,2=需关注,3=急性期") + private Integer diseaseStatus; + + /** 主治医生 */ + @ApiModelProperty(value = "主治医生") + @Excel(name = "主治医生") + private String mainDoctor; + + /** 就诊医院 */ + @ApiModelProperty(value = "就诊医院") + @Excel(name = "就诊医院") + private String hospital; + + /** 科室 */ + @ApiModelProperty(value = "科室") + @Excel(name = "科室") + private String department; + + /** 备注说明 */ + @ApiModelProperty(value = "备注说明") + private String notes; + + /** 是否启用:1-是 0-否 */ + @ApiModelProperty(value = "是否启用:1-是 0-否") + @Excel(name = "是否启用", readConverterExp = "1=是,0=否") + private Integer isActive; + + /** 删除标志(0代表存在 1代表删除) */ + private String delFlag; + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("memberId", getMemberId()) + .append("memberName", getMemberName()) + .append("diseaseId", getDiseaseId()) + .append("diseaseName", getDiseaseName()) + .append("diseaseCode", getDiseaseCode()) + .append("diagnosisDate", getDiagnosisDate()) + .append("diseaseStatus", getDiseaseStatus()) + .append("mainDoctor", getMainDoctor()) + .append("hospital", getHospital()) + .append("department", getDepartment()) + .append("notes", getNotes()) + .append("isActive", getIsActive()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("delFlag", getDelFlag()) + .append("remark", getRemark()) + .toString(); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/ChronicDiseaseRecordDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/ChronicDiseaseRecordDto.java new file mode 100644 index 0000000..bbb2fcc --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/ChronicDiseaseRecordDto.java @@ -0,0 +1,55 @@ +package com.intc.health.domain.dto; + +import lombok.Data; +import java.io.Serializable; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import com.fasterxml.jackson.annotation.JsonFormat; +import java.util.Date; + +/** + * 慢性疾病档案Dto对象 chronic_disease_record + * + * @author bot5 + * @date 2026-03-17 + */ +@ApiModel("慢性疾病档案Dto对象") +@Data +public class ChronicDiseaseRecordDto implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 关联成员ID */ + @ApiModelProperty(value = "关联成员ID") + private Long memberId; + + /** 关联疾病ID */ + @ApiModelProperty(value = "关联疾病ID") + private Long diseaseId; + + /** 疾病名称 */ + @ApiModelProperty(value = "疾病名称") + private String diseaseName; + + /** 疾病编码 */ + @ApiModelProperty(value = "疾病编码") + private String diseaseCode; + + /** 状态:1-稳定 2-需关注 3-急性期 */ + @ApiModelProperty(value = "状态") + private Integer diseaseStatus; + + /** 是否启用 */ + @ApiModelProperty(value = "是否启用") + private Integer isActive; + + /** 确诊日期-开始 */ + @ApiModelProperty(value = "确诊日期-开始") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date diagnosisDateStart; + + /** 确诊日期-结束 */ + @ApiModelProperty(value = "确诊日期-结束") + @JsonFormat(pattern = "yyyy-MM-dd") + private Date diagnosisDateEnd; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/ChronicDiseaseRecordVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/ChronicDiseaseRecordVo.java new file mode 100644 index 0000000..f464114 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/ChronicDiseaseRecordVo.java @@ -0,0 +1,24 @@ +package com.intc.health.domain.vo; + +import com.intc.health.domain.ChronicDiseaseRecord; +import lombok.Data; +import io.swagger.annotations.ApiModel; + +/** + * 慢性疾病档案Vo对象 chronic_disease_record + * + * @author bot5 + * @date 2026-03-17 + */ +@ApiModel("慢性疾病档案Vo对象") +@Data +public class ChronicDiseaseRecordVo extends ChronicDiseaseRecord +{ + private static final long serialVersionUID = 1L; + + /** 疾病类型(来自health_diseases表) */ + private String diseaseType; + + /** 疾病症状(来自health_diseases表) */ + private String diseaseSymptom; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseRecordMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseRecordMapper.java new file mode 100644 index 0000000..224f973 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseRecordMapper.java @@ -0,0 +1,87 @@ +package com.intc.health.mapper; + +import java.util.List; +import com.intc.health.domain.vo.ChronicDiseaseRecordVo; +import com.intc.health.domain.dto.ChronicDiseaseRecordDto; +import org.apache.ibatis.annotations.Param; + +/** + * 慢性疾病档案Mapper接口 + * + * @author bot5 + * @date 2026-03-17 + */ +public interface ChronicDiseaseRecordMapper +{ + /** + * 查询慢性疾病档案 + * + * @param id 慢性疾病档案主键 + * @return 慢性疾病档案 + */ + public ChronicDiseaseRecordVo selectChronicDiseaseRecordById(Long id); + + /** + * 查询慢性疾病档案列表 + * + * @param chronicDiseaseRecordDto 慢性疾病档案 + * @return 慢性疾病档案集合 + */ + public List selectChronicDiseaseRecordList(ChronicDiseaseRecordDto chronicDiseaseRecordDto); + + /** + * 根据成员ID查询慢性疾病档案列表 + * + * @param memberId 成员ID + * @return 慢性疾病档案集合 + */ + public List selectChronicDiseaseRecordByMemberId(Long memberId); + + /** + * 新增慢性疾病档案 + * + * @param chronicDiseaseRecord 慢性疾病档案 + * @return 结果 + */ + public int insertChronicDiseaseRecord(com.intc.health.domain.ChronicDiseaseRecord chronicDiseaseRecord); + + /** + * 修改慢性疾病档案 + * + * @param chronicDiseaseRecord 慢性疾病档案 + * @return 结果 + */ + public int updateChronicDiseaseRecord(com.intc.health.domain.ChronicDiseaseRecord chronicDiseaseRecord); + + /** + * 删除慢性疾病档案 + * + * @param id 慢性疾病档案主键 + * @return 结果 + */ + public int deleteChronicDiseaseRecordById(Long id); + + /** + * 批量删除慢性疾病档案 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteChronicDiseaseRecordByIds(Long[] ids); + + /** + * 逻辑删除慢性疾病档案 + * + * @param id 慢性疾病档案主键 + * @return 结果 + */ + public int removeChronicDiseaseRecordById(Long id); + + /** + * 批量逻辑删除慢性疾病档案 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int removeChronicDiseaseRecordByIds(Long[] ids); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IChronicDiseaseRecordService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IChronicDiseaseRecordService.java new file mode 100644 index 0000000..8a07b49 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IChronicDiseaseRecordService.java @@ -0,0 +1,71 @@ +package com.intc.health.service; + +import java.util.List; +import com.intc.health.domain.ChronicDiseaseRecord; +import com.intc.health.domain.dto.ChronicDiseaseRecordDto; +import com.intc.health.domain.vo.ChronicDiseaseRecordVo; + +/** + * 慢性疾病档案Service接口 + * + * @author bot5 + * @date 2026-03-17 + */ +public interface IChronicDiseaseRecordService +{ + /** + * 查询慢性疾病档案 + * + * @param id 慢性疾病档案主键 + * @return 慢性疾病档案 + */ + public ChronicDiseaseRecordVo selectChronicDiseaseRecordById(Long id); + + /** + * 查询慢性疾病档案列表 + * + * @param chronicDiseaseRecordDto 慢性疾病档案 + * @return 慢性疾病档案集合 + */ + public List selectChronicDiseaseRecordList(ChronicDiseaseRecordDto chronicDiseaseRecordDto); + + /** + * 根据成员ID查询慢性疾病档案列表 + * + * @param memberId 成员ID + * @return 慢性疾病档案集合 + */ + public List selectChronicDiseaseRecordByMemberId(Long memberId); + + /** + * 新增慢性疾病档案 + * + * @param chronicDiseaseRecord 慢性疾病档案 + * @return 结果 + */ + public int insertChronicDiseaseRecord(ChronicDiseaseRecord chronicDiseaseRecord); + + /** + * 修改慢性疾病档案 + * + * @param chronicDiseaseRecord 慢性疾病档案 + * @return 结果 + */ + public int updateChronicDiseaseRecord(ChronicDiseaseRecord chronicDiseaseRecord); + + /** + * 批量删除慢性疾病档案 + * + * @param ids 需要删除的慢性疾病档案主键集合 + * @return 结果 + */ + public int deleteChronicDiseaseRecordByIds(Long[] ids); + + /** + * 删除慢性疾病档案信息 + * + * @param id 慢性疾病档案主键 + * @return 结果 + */ + public int deleteChronicDiseaseRecordById(Long id); +} \ No newline at end of file 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 new file mode 100644 index 0000000..8c6de32 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/ChronicDiseaseRecordServiceImpl.java @@ -0,0 +1,124 @@ +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.ChronicDiseaseRecord; +import com.intc.health.domain.dto.ChronicDiseaseRecordDto; +import com.intc.health.domain.vo.ChronicDiseaseRecordVo; +import com.intc.health.mapper.ChronicDiseaseRecordMapper; +import com.intc.health.service.IChronicDiseaseRecordService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 慢性疾病档案Service业务层处理 + * + * @author bot5 + * @date 2026-03-17 + */ +@Service +public class ChronicDiseaseRecordServiceImpl implements IChronicDiseaseRecordService +{ + @Resource + private ChronicDiseaseRecordMapper chronicDiseaseRecordMapper; + + /** + * 查询慢性疾病档案 + * + * @param id 慢性疾病档案主键 + * @return 慢性疾病档案 + */ + @Override + public ChronicDiseaseRecordVo selectChronicDiseaseRecordById(Long id) + { + return chronicDiseaseRecordMapper.selectChronicDiseaseRecordById(id); + } + + /** + * 查询慢性疾病档案列表 + * + * @param chronicDiseaseRecordDto 慢性疾病档案 + * @return 慢性疾病档案 + */ + @Override + public List selectChronicDiseaseRecordList(ChronicDiseaseRecordDto chronicDiseaseRecordDto) + { + return chronicDiseaseRecordMapper.selectChronicDiseaseRecordList(chronicDiseaseRecordDto); + } + + /** + * 根据成员ID查询慢性疾病档案列表 + * + * @param memberId 成员ID + * @return 慢性疾病档案集合 + */ + @Override + public List selectChronicDiseaseRecordByMemberId(Long memberId) + { + return chronicDiseaseRecordMapper.selectChronicDiseaseRecordByMemberId(memberId); + } + + /** + * 新增慢性疾病档案 + * + * @param chronicDiseaseRecord 慢性疾病档案 + * @return 结果 + */ + @Override + public int insertChronicDiseaseRecord(ChronicDiseaseRecord chronicDiseaseRecord) + { + chronicDiseaseRecord.setCreateBy(SecurityUtils.getUsername()); + chronicDiseaseRecord.setCreateTime(DateUtils.getNowDate()); + chronicDiseaseRecord.setId(IdWorker.getId()); + // 默认启用 + if (chronicDiseaseRecord.getIsActive() == null) { + chronicDiseaseRecord.setIsActive(1); + } + // 默认状态为稳定 + if (chronicDiseaseRecord.getDiseaseStatus() == null) { + chronicDiseaseRecord.setDiseaseStatus(1); + } + return chronicDiseaseRecordMapper.insertChronicDiseaseRecord(chronicDiseaseRecord); + } + + /** + * 修改慢性疾病档案 + * + * @param chronicDiseaseRecord 慢性疾病档案 + * @return 结果 + */ + @Override + public int updateChronicDiseaseRecord(ChronicDiseaseRecord chronicDiseaseRecord) + { + chronicDiseaseRecord.setUpdateBy(SecurityUtils.getUsername()); + chronicDiseaseRecord.setUpdateTime(DateUtils.getNowDate()); + return chronicDiseaseRecordMapper.updateChronicDiseaseRecord(chronicDiseaseRecord); + } + + /** + * 批量删除慢性疾病档案 + * + * @param ids 需要删除的慢性疾病档案主键 + * @return 结果 + */ + @Override + public int deleteChronicDiseaseRecordByIds(Long[] ids) + { + return chronicDiseaseRecordMapper.removeChronicDiseaseRecordByIds(ids); + } + + /** + * 删除慢性疾病档案信息 + * + * @param id 慢性疾病档案主键 + * @return 结果 + */ + @Override + public int deleteChronicDiseaseRecordById(Long id) + { + return chronicDiseaseRecordMapper.removeChronicDiseaseRecordById(id); + } +} \ No newline at end of file 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 new file mode 100644 index 0000000..281774d --- /dev/null +++ b/intc-modules/intc-health/src/main/resources/mapper/health/ChronicDiseaseRecordMapper.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select a.id, a.member_id, a.disease_id, a.disease_name, a.disease_code, a.diagnosis_date, + a.disease_status, a.main_doctor, a.hospital, a.department, a.notes, a.is_active, + a.create_by, a.create_time, a.update_by, a.update_time, a.del_flag, a.remark, + p.name as member_name, + d.type as disease_type, + d.symptom as disease_symptom + from chronic_disease_record a + left join health_person p on a.member_id = p.id + left join health_diseases d on a.disease_id = d.id + + + + + + + + + + insert into chronic_disease_record + + id, + member_id, + disease_id, + disease_name, + disease_code, + diagnosis_date, + disease_status, + main_doctor, + hospital, + department, + notes, + is_active, + create_by, + create_time, + update_by, + update_time, + del_flag, + remark, + + + #{id}, + #{memberId}, + #{diseaseId}, + #{diseaseName}, + #{diseaseCode}, + #{diagnosisDate}, + #{diseaseStatus}, + #{mainDoctor}, + #{hospital}, + #{department}, + #{notes}, + #{isActive}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + #{delFlag}, + #{remark}, + + + + + update chronic_disease_record + + member_id = #{memberId}, + disease_id = #{diseaseId}, + disease_name = #{diseaseName}, + disease_code = #{diseaseCode}, + diagnosis_date = #{diagnosisDate}, + disease_status = #{diseaseStatus}, + main_doctor = #{mainDoctor}, + hospital = #{hospital}, + department = #{department}, + notes = #{notes}, + is_active = #{isActive}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from chronic_disease_record where id = #{id} + + + + delete from chronic_disease_record where id in + + #{id} + + + + + update chronic_disease_record set del_flag = '1' where id = #{id} + + + + update chronic_disease_record set del_flag = '1' where id in + + #{id} + + + \ No newline at end of file diff --git a/sql/chronic_disease_record.sql b/sql/chronic_disease_record.sql new file mode 100644 index 0000000..03eed8f --- /dev/null +++ b/sql/chronic_disease_record.sql @@ -0,0 +1,105 @@ +-- ======================================== +-- 慢性疾病档案表 +-- ======================================== +DROP TABLE IF EXISTS chronic_disease_record; +CREATE TABLE chronic_disease_record ( + id BIGSERIAL PRIMARY KEY, + member_id BIGINT NOT NULL, + disease_id BIGINT, + disease_name VARCHAR(100) NOT NULL, + disease_code VARCHAR(20), + diagnosis_date DATE, + disease_status SMALLINT NOT NULL DEFAULT 1, + main_doctor VARCHAR(50), + hospital VARCHAR(100), + department VARCHAR(50), + notes TEXT, + is_active SMALLINT DEFAULT 1, + -- 若依标准字段 + create_by VARCHAR(64) DEFAULT '', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64) DEFAULT '', + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + del_flag SMALLINT DEFAULT 0 +); + +COMMENT ON TABLE chronic_disease_record IS '慢性疾病档案表'; +COMMENT ON COLUMN chronic_disease_record.id IS '主键ID'; +COMMENT ON COLUMN chronic_disease_record.member_id IS '关联成员ID'; +COMMENT ON COLUMN chronic_disease_record.disease_id IS '关联疾病ID(关联health_diseases表)'; +COMMENT ON COLUMN chronic_disease_record.disease_name IS '疾病名称(高血压/糖尿病/冠心病等)'; +COMMENT ON COLUMN chronic_disease_record.disease_code IS '疾病编码(ICD-10标准)'; +COMMENT ON COLUMN chronic_disease_record.diagnosis_date IS '确诊日期'; +COMMENT ON COLUMN chronic_disease_record.disease_status IS '状态:1-稳定 2-需关注 3-急性期'; +COMMENT ON COLUMN chronic_disease_record.main_doctor IS '主治医生'; +COMMENT ON COLUMN chronic_disease_record.hospital IS '就诊医院'; +COMMENT ON COLUMN chronic_disease_record.department IS '科室'; +COMMENT ON COLUMN chronic_disease_record.notes IS '备注说明'; +COMMENT ON COLUMN chronic_disease_record.is_active IS '是否启用:1-是 0-否'; +COMMENT ON COLUMN chronic_disease_record.create_by IS '创建者'; +COMMENT ON COLUMN chronic_disease_record.create_time IS '创建时间'; +COMMENT ON COLUMN chronic_disease_record.update_by IS '更新者'; +COMMENT ON COLUMN chronic_disease_record.update_time IS '更新时间'; +COMMENT ON COLUMN chronic_disease_record.remark IS '备注'; +COMMENT ON COLUMN chronic_disease_record.del_flag IS '删除标记:0-正常 1-删除'; + +CREATE INDEX idx_cdr_member_id ON chronic_disease_record(member_id); +CREATE INDEX idx_cdr_disease_id ON chronic_disease_record(disease_id); +CREATE INDEX idx_cdr_disease_status ON chronic_disease_record(disease_status); +CREATE INDEX idx_cdr_is_active ON chronic_disease_record(is_active); + +-- ======================================== +-- 菜单 SQL(若依框架标准格式) +-- ======================================== +-- 慢性疾病档案菜单 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +VALUES ('慢性疾病档案', 0, 5, 'chronicDisease', 'health/chronicDisease/index', 1, 0, 'C', '0', '0', 'health:chronicDisease:list', '#', 'admin', NOW(), '慢性疾病档案菜单'); + +-- 获取刚插入的菜单ID +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮权限 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +VALUES ('慢性疾病档案查询', @parentId, 1, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:query', '#', 'admin', NOW(), ''); + +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +VALUES ('慢性疾病档案权增', @parentId, 2, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:add', '#', 'admin', NOW(), ''); + +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +VALUES ('慢性疾病档案修改', @parentId, 3, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:edit', '#', 'admin', NOW(), ''); + +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +VALUES ('慢性疾病档案删除', @parentId, 4, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:remove', '#', 'admin', NOW(), ''); + +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +VALUES ('慢性疾病档案导出', @parentId, 5, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:export', '#', 'admin', NOW(), ''); + +-- ======================================== +-- 字典数据 +-- ======================================== +-- 疾病状态字典 +INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark) +VALUES ('疾病状态', 'disease_status', '0', 'admin', NOW(), '慢性疾病状态'); + +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) +VALUES (1, '稳定', '1', 'disease_status', '', 'success', 'Y', '0', 'admin', NOW(), '疾病状态-稳定'); + +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) +VALUES (2, '需关注', '2', 'disease_status', '', 'warning', 'N', '0', 'admin', NOW(), '疾病状态-需关注'); + +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) +VALUES (3, '急性期', '3', 'disease_status', '', 'danger', 'N', '0', 'admin', NOW(), '疾病状态-急性期'); + +-- 是否启用字典(如果不存在) +INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark) +VALUES ('是否启用', 'is_active', '0', 'admin', NOW(), '是否启用状态') +ON CONFLICT (dict_type) DO NOTHING; + +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) +VALUES (1, '是', '1', 'is_active', '', 'success', 'Y', '0', 'admin', NOW(), '启用') +ON CONFLICT DO NOTHING; + +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) +VALUES (2, '否', '0', 'is_active', '', 'danger', 'N', '0', 'admin', NOW(), '停用') +ON CONFLICT DO NOTHING; \ No newline at end of file From 77e503c4602d5fb41c015e14cb93d78ae8469469 Mon Sep 17 00:00:00 2001 From: bot5 Date: Wed, 18 Mar 2026 14:10:32 +0800 Subject: [PATCH 2/7] =?UTF-8?q?feat(health):=20=E6=96=B0=E5=A2=9E=E7=94=A8?= =?UTF-8?q?=E8=8D=AF=E8=AE=A1=E5=88=92=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增用药计划(HealthMedicationPlan)和用药记录(HealthMedicationRecord)实体 - 包含完整的Controller/Service/Mapper层代码 - 支持用药计划的增删改查、暂停/恢复/结束操作 - 支持用药记录的服药/跳过操作 - 新增SQL建表脚本、字典数据和菜单权限 --- .../HealthMedicationPlanController.java | 145 ++++++++++++ .../HealthMedicationRecordController.java | 160 +++++++++++++ .../health/domain/HealthMedicationPlan.java | 139 ++++++++++++ .../health/domain/HealthMedicationRecord.java | 99 ++++++++ .../domain/dto/HealthMedicationPlanDto.java | 69 ++++++ .../domain/dto/HealthMedicationRecordDto.java | 65 ++++++ .../domain/vo/HealthMedicationPlanVo.java | 118 ++++++++++ .../domain/vo/HealthMedicationRecordVo.java | 87 +++++++ .../mapper/HealthMedicationPlanMapper.java | 86 +++++++ .../mapper/HealthMedicationRecordMapper.java | 106 +++++++++ .../service/IHealthMedicationPlanService.java | 87 +++++++ .../IHealthMedicationRecordService.java | 108 +++++++++ .../impl/HealthMedicationPlanServiceImpl.java | 188 +++++++++++++++ .../HealthMedicationRecordServiceImpl.java | 214 ++++++++++++++++++ .../health/HealthMedicationPlanMapper.xml | 190 ++++++++++++++++ .../health/HealthMedicationRecordMapper.xml | 172 ++++++++++++++ sql/medication.sql | 128 +++++++++++ 17 files changed, 2161 insertions(+) create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationPlanController.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationRecordController.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationPlan.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationRecord.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationPlanDto.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationRecordDto.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationPlanVo.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationRecordVo.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationPlanMapper.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationPlanService.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationRecordService.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationPlanServiceImpl.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationRecordServiceImpl.java create mode 100644 intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationPlanMapper.xml create mode 100644 intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml create mode 100644 sql/medication.sql diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationPlanController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationPlanController.java new file mode 100644 index 0000000..bea6b88 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationPlanController.java @@ -0,0 +1,145 @@ +package com.intc.health.controller; + +import com.intc.common.core.utils.poi.ExcelUtil; +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.HealthMedicationPlan; +import com.intc.health.domain.dto.HealthMedicationPlanDto; +import com.intc.health.domain.vo.HealthMedicationPlanVo; +import com.intc.health.service.IHealthMedicationPlanService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 用药计划Controller + * + * @author intc + * @date 2025-03-18 + */ +@Api(tags = "用药计划") +@RestController +@RequestMapping("/medicationPlan") +public class HealthMedicationPlanController extends BaseController +{ + @Resource + private IHealthMedicationPlanService healthMedicationPlanService; + + /** + * 查询用药计划列表 + */ + @ApiOperation(value = "查询用药计划列表", response = HealthMedicationPlanVo.class) + @RequiresPermissions("health:medicationPlan:list") + @GetMapping("/list") + public TableDataInfo list(HealthMedicationPlanDto dto) + { + startPage(); + List list = healthMedicationPlanService.selectHealthMedicationPlanList(dto); + return getDataTable(list); + } + + /** + * 导出用药计划列表 + */ + @ApiOperation(value = "导出用药计划列表") + @RequiresPermissions("health:medicationPlan:export") + @Log(title = "用药计划", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, HealthMedicationPlanDto dto) + { + List list = healthMedicationPlanService.selectHealthMedicationPlanList(dto); + ExcelUtil util = new ExcelUtil(HealthMedicationPlanVo.class); + util.exportExcel(response, list, "用药计划数据"); + } + + /** + * 获取用药计划详细信息 + */ + @ApiOperation(value = "获取用药计划详细信息") + @RequiresPermissions("health:medicationPlan:query") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(healthMedicationPlanService.selectHealthMedicationPlanById(id)); + } + + /** + * 新增用药计划 + */ + @ApiOperation(value = "新增用药计划") + @RequiresPermissions("health:medicationPlan:add") + @Log(title = "用药计划", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody HealthMedicationPlan plan) + { + return toAjax(healthMedicationPlanService.insertHealthMedicationPlan(plan)); + } + + /** + * 修改用药计划 + */ + @ApiOperation(value = "修改用药计划") + @RequiresPermissions("health:medicationPlan:edit") + @Log(title = "用药计划", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody HealthMedicationPlan plan) + { + return toAjax(healthMedicationPlanService.updateHealthMedicationPlan(plan)); + } + + /** + * 删除用药计划 + */ + @ApiOperation(value = "删除用药计划") + @RequiresPermissions("health:medicationPlan:remove") + @Log(title = "用药计划", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(healthMedicationPlanService.deleteHealthMedicationPlanByIds(ids)); + } + + /** + * 暂停用药计划 + */ + @ApiOperation(value = "暂停用药计划") + @RequiresPermissions("health:medicationPlan:edit") + @Log(title = "用药计划", businessType = BusinessType.UPDATE) + @PutMapping("/pause/{id}") + public AjaxResult pause(@PathVariable Long id) + { + return toAjax(healthMedicationPlanService.pauseHealthMedicationPlan(id)); + } + + /** + * 恢复用药计划 + */ + @ApiOperation(value = "恢复用药计划") + @RequiresPermissions("health:medicationPlan:edit") + @Log(title = "用药计划", businessType = BusinessType.UPDATE) + @PutMapping("/resume/{id}") + public AjaxResult resume(@PathVariable Long id) + { + return toAjax(healthMedicationPlanService.resumeHealthMedicationPlan(id)); + } + + /** + * 结束用药计划 + */ + @ApiOperation(value = "结束用药计划") + @RequiresPermissions("health:medicationPlan:edit") + @Log(title = "用药计划", businessType = BusinessType.UPDATE) + @PutMapping("/end/{id}") + public AjaxResult end(@PathVariable Long id) + { + return toAjax(healthMedicationPlanService.endHealthMedicationPlan(id)); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationRecordController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationRecordController.java new file mode 100644 index 0000000..6392cd8 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationRecordController.java @@ -0,0 +1,160 @@ +package com.intc.health.controller; + +import com.intc.common.core.utils.poi.ExcelUtil; +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.HealthMedicationRecord; +import com.intc.health.domain.dto.HealthMedicationRecordDto; +import com.intc.health.domain.vo.HealthMedicationRecordVo; +import com.intc.health.service.IHealthMedicationRecordService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 用药记录Controller + * + * @author intc + * @date 2025-03-18 + */ +@Api(tags = "用药记录") +@RestController +@RequestMapping("/medicationRecord") +public class HealthMedicationRecordController extends BaseController +{ + @Resource + private IHealthMedicationRecordService healthMedicationRecordService; + + /** + * 查询用药记录列表 + */ + @ApiOperation(value = "查询用药记录列表", response = HealthMedicationRecordVo.class) + @RequiresPermissions("health:medicationRecord:list") + @GetMapping("/list") + public TableDataInfo list(HealthMedicationRecordDto dto) + { + startPage(); + List list = healthMedicationRecordService.selectHealthMedicationRecordList(dto); + return getDataTable(list); + } + + /** + * 查询今日用药记录 + */ + @ApiOperation(value = "查询今日用药记录") + @RequiresPermissions("health:medicationRecord:list") + @GetMapping("/today") + public AjaxResult today(@RequestParam(required = false) Long personId) + { + List list = healthMedicationRecordService.getTodayRecords(personId); + return success(list); + } + + /** + * 查询某计划某天的用药记录 + */ + @ApiOperation(value = "查询某计划某天的用药记录") + @RequiresPermissions("health:medicationRecord:list") + @GetMapping("/plan/{planId}/date/{date}") + public AjaxResult getByPlanAndDate(@PathVariable Long planId, @PathVariable String date) + { + List list = healthMedicationRecordService.selectRecordByPlanAndDate(planId, date); + return success(list); + } + + /** + * 导出用药记录列表 + */ + @ApiOperation(value = "导出用药记录列表") + @RequiresPermissions("health:medicationRecord:export") + @Log(title = "用药记录", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(HttpServletResponse response, HealthMedicationRecordDto dto) + { + List list = healthMedicationRecordService.selectHealthMedicationRecordList(dto); + ExcelUtil util = new ExcelUtil(HealthMedicationRecordVo.class); + util.exportExcel(response, list, "用药记录数据"); + } + + /** + * 获取用药记录详细信息 + */ + @ApiOperation(value = "获取用药记录详细信息") + @RequiresPermissions("health:medicationRecord:query") + @GetMapping(value = "/{id}") + public AjaxResult getInfo(@PathVariable("id") Long id) + { + return success(healthMedicationRecordService.selectHealthMedicationRecordById(id)); + } + + /** + * 新增用药记录(手动记录补服) + */ + @ApiOperation(value = "新增用药记录") + @RequiresPermissions("health:medicationRecord:add") + @Log(title = "用药记录", businessType = BusinessType.INSERT) + @PostMapping + public AjaxResult add(@RequestBody HealthMedicationRecord record) + { + return toAjax(healthMedicationRecordService.insertHealthMedicationRecord(record)); + } + + /** + * 修改用药记录 + */ + @ApiOperation(value = "修改用药记录") + @RequiresPermissions("health:medicationRecord:edit") + @Log(title = "用药记录", businessType = BusinessType.UPDATE) + @PutMapping + public AjaxResult edit(@RequestBody HealthMedicationRecord record) + { + return toAjax(healthMedicationRecordService.updateHealthMedicationRecord(record)); + } + + /** + * 删除用药记录 + */ + @ApiOperation(value = "删除用药记录") + @RequiresPermissions("health:medicationRecord:remove") + @Log(title = "用药记录", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public AjaxResult remove(@PathVariable Long[] ids) + { + return toAjax(healthMedicationRecordService.deleteHealthMedicationRecordByIds(ids)); + } + + /** + * 服药(标记为已服用) + */ + @ApiOperation(value = "服药(标记为已服用)") + @RequiresPermissions("health:medicationRecord:edit") + @Log(title = "用药记录", businessType = BusinessType.UPDATE) + @PutMapping("/take/{id}") + public AjaxResult take(@PathVariable Long id, + @RequestParam(required = false) Double dosage, + @RequestParam(required = false) String remark) + { + return toAjax(healthMedicationRecordService.takeMedication(id, dosage, remark)); + } + + /** + * 跳过服药 + */ + @ApiOperation(value = "跳过服药") + @RequiresPermissions("health:medicationRecord:edit") + @Log(title = "用药记录", businessType = BusinessType.UPDATE) + @PutMapping("/skip/{id}") + public AjaxResult skip(@PathVariable Long id, + @RequestParam(required = false) String remark) + { + return toAjax(healthMedicationRecordService.skipMedication(id, remark)); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationPlan.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationPlan.java new file mode 100644 index 0000000..f0cf9af --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationPlan.java @@ -0,0 +1,139 @@ +package com.intc.health.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.intc.common.core.annotation.Excel; +import com.intc.common.core.web.domain.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 用药计划对象 health_medication_plan + * + * @author intc + * @date 2025-03-18 + */ +@ApiModel("用药计划对象") +@Data +public class HealthMedicationPlan extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键 */ + private Long id; + + /** 人员ID */ + @ApiModelProperty(value="人员ID") + @NotNull(message="人员ID不能为空") + @Excel(name = "人员ID") + private Long personId; + + /** 药品ID */ + @ApiModelProperty(value="药品ID") + @NotNull(message="药品ID不能为空") + @Excel(name = "药品ID") + private Long medicineId; + + /** 入库ID(用于扣减库存) */ + @ApiModelProperty(value="入库ID") + private Long stockInId; + + /** 计划名称 */ + @ApiModelProperty(value="计划名称") + @Excel(name = "计划名称") + private String planName; + + /** 每次剂量 */ + @ApiModelProperty(value="每次剂量") + @NotNull(message="剂量不能为空") + @Excel(name = "每次剂量") + private Double dosage; + + /** 剂量单位 */ + @ApiModelProperty(value="剂量单位") + @Excel(name = "剂量单位") + private String dosageUnit; + + /** 服药频率(每日次数) */ + @ApiModelProperty(value="服药频率") + @NotNull(message="服药频率不能为空") + @Excel(name = "服药频率") + private Integer frequency; + + /** 频率类型(1-每日 2-隔日 3-每周 4-自定义) */ + @ApiModelProperty(value="频率类型") + @Excel(name = "频率类型", readConverterExp = "1=每日,2=隔日,3=每周,4=自定义") + private String frequencyType; + + /** 服药时间点(JSON格式) */ + @ApiModelProperty(value="服药时间点") + private String timePoints; + + /** 周几服药(频率类型为每周时使用,JSON格式如[1,3,5]表示周一三五) */ + @ApiModelProperty(value="周几服药") + private String weekDays; + + /** 开始日期 */ + @ApiModelProperty(value="开始日期") + @NotNull(message="开始日期不能为空") + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "开始日期", width = 30, dateFormat = "yyyy-MM-dd") + private Date startDate; + + /** 结束日期 */ + @ApiModelProperty(value="结束日期") + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "结束日期", width = 30, dateFormat = "yyyy-MM-dd") + private Date endDate; + + /** 是否启用提醒(0-否 1-是) */ + @ApiModelProperty(value="是否启用提醒") + @Excel(name = "是否启用提醒", readConverterExp = "0=否,1=是") + private String reminderEnabled; + + /** 提前提醒时间(分钟) */ + @ApiModelProperty(value="提前提醒时间") + @Excel(name = "提前提醒时间(分钟)") + private Integer reminderMinutes; + + /** 状态(1-进行中 2-已结束 3-已暂停) */ + @ApiModelProperty(value="状态") + @Excel(name = "状态", readConverterExp = "1=进行中,2=已结束,3=已暂停") + private String status; + + /** 删除标志(0代表存在 1代表删除) */ + private String delFlag; + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("personId", getPersonId()) + .append("medicineId", getMedicineId()) + .append("stockInId", getStockInId()) + .append("planName", getPlanName()) + .append("dosage", getDosage()) + .append("dosageUnit", getDosageUnit()) + .append("frequency", getFrequency()) + .append("frequencyType", getFrequencyType()) + .append("timePoints", getTimePoints()) + .append("weekDays", getWeekDays()) + .append("startDate", getStartDate()) + .append("endDate", getEndDate()) + .append("reminderEnabled", getReminderEnabled()) + .append("reminderMinutes", getReminderMinutes()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("delFlag", getDelFlag()) + .append("remark", getRemark()) + .toString(); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationRecord.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationRecord.java new file mode 100644 index 0000000..190036e --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationRecord.java @@ -0,0 +1,99 @@ +package com.intc.health.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.intc.common.core.annotation.Excel; +import com.intc.common.core.web.domain.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +import javax.validation.constraints.NotNull; +import java.util.Date; + +/** + * 用药记录对象 health_medication_record + * + * @author intc + * @date 2025-03-18 + */ +@ApiModel("用药记录对象") +@Data +public class HealthMedicationRecord extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 主键 */ + private Long id; + + /** 计划ID */ + @ApiModelProperty(value="计划ID") + @NotNull(message="计划ID不能为空") + @Excel(name = "计划ID") + private Long planId; + + /** 人员ID */ + @ApiModelProperty(value="人员ID") + @NotNull(message="人员ID不能为空") + @Excel(name = "人员ID") + private Long personId; + + /** 药品ID */ + @ApiModelProperty(value="药品ID") + @NotNull(message="药品ID不能为空") + @Excel(name = "药品ID") + private Long medicineId; + + /** 计划服药时间 */ + @ApiModelProperty(value="计划服药时间") + @NotNull(message="计划服药时间不能为空") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "计划服药时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date scheduledTime; + + /** 实际服药时间 */ + @ApiModelProperty(value="实际服药时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "实际服药时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date actualTime; + + /** 服用剂量 */ + @ApiModelProperty(value="服用剂量") + @Excel(name = "服用剂量") + private Double dosage; + + /** 剂量单位 */ + @ApiModelProperty(value="剂量单位") + @Excel(name = "剂量单位") + private String dosageUnit; + + /** 状态(1-待服用 2-已服用 3-已跳过 4-已过期) */ + @ApiModelProperty(value="状态") + @Excel(name = "状态", readConverterExp = "1=待服用,2=已服用,3=已跳过,4=已过期") + private String status; + + /** 删除标志(0代表存在 1代表删除) */ + private String delFlag; + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) + .append("id", getId()) + .append("planId", getPlanId()) + .append("personId", getPersonId()) + .append("medicineId", getMedicineId()) + .append("scheduledTime", getScheduledTime()) + .append("actualTime", getActualTime()) + .append("dosage", getDosage()) + .append("dosageUnit", getDosageUnit()) + .append("status", getStatus()) + .append("createBy", getCreateBy()) + .append("createTime", getCreateTime()) + .append("updateBy", getUpdateBy()) + .append("updateTime", getUpdateTime()) + .append("delFlag", getDelFlag()) + .append("remark", getRemark()) + .toString(); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationPlanDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationPlanDto.java new file mode 100644 index 0000000..d9ba52e --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationPlanDto.java @@ -0,0 +1,69 @@ +package com.intc.health.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * 用药计划DTO对象 health_medication_plan + * + * @author intc + * @date 2025-03-18 + */ +@ApiModel("用药计划DTO对象") +@Data +public class HealthMedicationPlanDto +{ + /** 主键 */ + private Long id; + + /** 人员ID */ + @ApiModelProperty(value="人员ID") + private Long personId; + + /** 人员姓名(模糊查询) */ + @ApiModelProperty(value="人员姓名") + private String personName; + + /** 药品ID */ + @ApiModelProperty(value="药品ID") + private Long medicineId; + + /** 计划名称 */ + @ApiModelProperty(value="计划名称") + private String planName; + + /** 频率类型 */ + @ApiModelProperty(value="频率类型") + private String frequencyType; + + /** 状态 */ + @ApiModelProperty(value="状态") + private String status; + + /** 开始日期-起 */ + @ApiModelProperty(value="开始日期-起") + private Date startDateBegin; + + /** 开始日期-止 */ + @ApiModelProperty(value="开始日期-止") + private Date startDateEnd; + + /** 结束日期-起 */ + @ApiModelProperty(value="结束日期-起") + private Date endDateBegin; + + /** 结束日期-止 */ + @ApiModelProperty(value="结束日期-止") + private Date endDateEnd; + + /** 关键字(计划名称、药品名称) */ + @ApiModelProperty(value="关键字") + private String keys; + + /** 分页参数 */ + private Integer pageNum; + private Integer pageSize; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationRecordDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationRecordDto.java new file mode 100644 index 0000000..ed4706c --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationRecordDto.java @@ -0,0 +1,65 @@ +package com.intc.health.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * 用药记录DTO对象 health_medication_record + * + * @author intc + * @date 2025-03-18 + */ +@ApiModel("用药记录DTO对象") +@Data +public class HealthMedicationRecordDto +{ + /** 主键 */ + private Long id; + + /** 计划ID */ + @ApiModelProperty(value="计划ID") + private Long planId; + + /** 人员ID */ + @ApiModelProperty(value="人员ID") + private Long personId; + + /** 人员姓名 */ + @ApiModelProperty(value="人员姓名") + private String personName; + + /** 药品ID */ + @ApiModelProperty(value="药品ID") + private Long medicineId; + + /** 状态 */ + @ApiModelProperty(value="状态") + private String status; + + /** 计划服药时间-起 */ + @ApiModelProperty(value="计划服药时间-起") + private Date scheduledTimeBegin; + + /** 计划服药时间-止 */ + @ApiModelProperty(value="计划服药时间-止") + private Date scheduledTimeEnd; + + /** 实际服药时间-起 */ + @ApiModelProperty(value="实际服药时间-起") + private Date actualTimeBegin; + + /** 实际服药时间-止 */ + @ApiModelProperty(value="实际服药时间-止") + private Date actualTimeEnd; + + /** 日期(按日期查询某天所有记录) */ + @ApiModelProperty(value="日期") + private Date queryDate; + + /** 分页参数 */ + private Integer pageNum; + private Integer pageSize; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationPlanVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationPlanVo.java new file mode 100644 index 0000000..b3fd978 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationPlanVo.java @@ -0,0 +1,118 @@ +package com.intc.health.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.intc.common.core.annotation.Excel; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * 用药计划VO对象 health_medication_plan + * + * @author intc + * @date 2025-03-18 + */ +@ApiModel("用药计划VO对象") +@Data +public class HealthMedicationPlanVo +{ + /** 主键 */ + private Long id; + + /** 人员ID */ + @Excel(name = "人员ID") + private Long personId; + + /** 人员姓名 */ + @Excel(name = "人员姓名") + private String personName; + + /** 药品ID */ + @Excel(name = "药品ID") + private Long medicineId; + + /** 药品名称 */ + @Excel(name = "药品名称") + private String medicineName; + + /** 药品简称 */ + private String shortName; + + /** 品牌 */ + private String brand; + + /** 包装 */ + private String packaging; + + /** 入库ID */ + private Long stockInId; + + /** 计划名称 */ + @Excel(name = "计划名称") + private String planName; + + /** 每次剂量 */ + @Excel(name = "每次剂量") + private Double dosage; + + /** 剂量单位 */ + @Excel(name = "剂量单位") + private String dosageUnit; + + /** 服药频率 */ + @Excel(name = "服药频率") + private Integer frequency; + + /** 频率类型 */ + @Excel(name = "频率类型") + private String frequencyType; + + /** 服药时间点 */ + private String timePoints; + + /** 周几服药 */ + private String weekDays; + + /** 开始日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "开始日期", width = 30, dateFormat = "yyyy-MM-dd") + private Date startDate; + + /** 结束日期 */ + @JsonFormat(pattern = "yyyy-MM-dd") + @Excel(name = "结束日期", width = 30, dateFormat = "yyyy-MM-dd") + private Date endDate; + + /** 是否启用提醒 */ + @Excel(name = "是否启用提醒") + private String reminderEnabled; + + /** 提前提醒时间 */ + @Excel(name = "提前提醒时间(分钟)") + private Integer reminderMinutes; + + /** 状态 */ + @Excel(name = "状态") + private String status; + + /** 备注 */ + private String remark; + + /** 创建时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** 药品简称-品牌(组合显示) */ + private String medicineDisplayName; + + /** 今日已服药次数 */ + private Integer todayTakenCount; + + /** 今日应服药次数 */ + private Integer todayTotalCount; + + /** 剩余库存 */ + private Double stockLeft; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationRecordVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationRecordVo.java new file mode 100644 index 0000000..5fddc71 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationRecordVo.java @@ -0,0 +1,87 @@ +package com.intc.health.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.intc.common.core.annotation.Excel; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * 用药记录VO对象 health_medication_record + * + * @author intc + * @date 2025-03-18 + */ +@ApiModel("用药记录VO对象") +@Data +public class HealthMedicationRecordVo +{ + /** 主键 */ + private Long id; + + /** 计划ID */ + @Excel(name = "计划ID") + private Long planId; + + /** 人员ID */ + @Excel(name = "人员ID") + private Long personId; + + /** 人员姓名 */ + @Excel(name = "人员姓名") + private String personName; + + /** 药品ID */ + @Excel(name = "药品ID") + private Long medicineId; + + /** 药品名称 */ + @Excel(name = "药品名称") + private String medicineName; + + /** 药品简称 */ + private String shortName; + + /** 品牌 */ + private String brand; + + /** 包装 */ + private String packaging; + + /** 计划服药时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "计划服药时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date scheduledTime; + + /** 实际服药时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + @Excel(name = "实际服药时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") + private Date actualTime; + + /** 服用剂量 */ + @Excel(name = "服用剂量") + private Double dosage; + + /** 剂量单位 */ + @Excel(name = "剂量单位") + private String dosageUnit; + + /** 状态 */ + @Excel(name = "状态") + private String status; + + /** 备注 */ + private String remark; + + /** 创建时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + /** 药品简称-品牌(组合显示) */ + private String medicineDisplayName; + + /** 计划名称 */ + private String planName; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationPlanMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationPlanMapper.java new file mode 100644 index 0000000..aea7726 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationPlanMapper.java @@ -0,0 +1,86 @@ +package com.intc.health.mapper; + +import java.util.List; +import com.intc.health.domain.HealthMedicationPlan; +import com.intc.health.domain.dto.HealthMedicationPlanDto; +import com.intc.health.domain.vo.HealthMedicationPlanVo; + +/** + * 用药计划Mapper接口 + * + * @author intc + * @date 2025-03-18 + */ +public interface HealthMedicationPlanMapper +{ + /** + * 查询用药计划 + * + * @param id 用药计划主键 + * @return 用药计划 + */ + public HealthMedicationPlanVo selectHealthMedicationPlanById(Long id); + + /** + * 查询用药计划列表 + * + * @param dto 用药计划 + * @return 用药计划集合 + */ + public List selectHealthMedicationPlanList(HealthMedicationPlanDto dto); + + /** + * 查询进行中的用药计划列表(用于生成用药记录) + * + * @return 用药计划集合 + */ + public List selectActivePlanList(); + + /** + * 新增用药计划 + * + * @param healthMedicationPlan 用药计划 + * @return 结果 + */ + public int insertHealthMedicationPlan(HealthMedicationPlan healthMedicationPlan); + + /** + * 修改用药计划 + * + * @param healthMedicationPlan 用药计划 + * @return 结果 + */ + public int updateHealthMedicationPlan(HealthMedicationPlan healthMedicationPlan); + + /** + * 删除用药计划 + * + * @param id 用药计划主键 + * @return 结果 + */ + public int deleteHealthMedicationPlanById(Long id); + + /** + * 批量删除用药计划 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteHealthMedicationPlanByIds(Long[] ids); + + /** + * 逻辑删除用药计划 + * + * @param id 用药计划主键 + * @return 结果 + */ + public int removeHealthMedicationPlanById(Long id); + + /** + * 批量逻辑删除用药计划 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int removeHealthMedicationPlanByIds(Long[] ids); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java new file mode 100644 index 0000000..61042c8 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java @@ -0,0 +1,106 @@ +package com.intc.health.mapper; + +import java.util.List; +import com.intc.health.domain.HealthMedicationRecord; +import com.intc.health.domain.dto.HealthMedicationRecordDto; +import com.intc.health.domain.vo.HealthMedicationRecordVo; +import org.apache.ibatis.annotations.Param; + +/** + * 用药记录Mapper接口 + * + * @author intc + * @date 2025-03-18 + */ +public interface HealthMedicationRecordMapper +{ + /** + * 查询用药记录 + * + * @param id 用药记录主键 + * @return 用药记录 + */ + public HealthMedicationRecordVo selectHealthMedicationRecordById(Long id); + + /** + * 查询用药记录列表 + * + * @param dto 用药记录 + * @return 用药记录集合 + */ + public List selectHealthMedicationRecordList(HealthMedicationRecordDto dto); + + /** + * 查询某计划某天的用药记录 + * + * @param planId 计划ID + * @param date 日期 + * @return 用药记录集合 + */ + public List selectRecordByPlanAndDate(@Param("planId") Long planId, @Param("date") String date); + + /** + * 统计某计划某天已服药次数 + * + * @param planId 计划ID + * @param date 日期 + * @return 次数 + */ + public int countTakenByPlanAndDate(@Param("planId") Long planId, @Param("date") String date); + + /** + * 新增用药记录 + * + * @param record 用药记录 + * @return 结果 + */ + public int insertHealthMedicationRecord(HealthMedicationRecord record); + + /** + * 批量新增用药记录 + * + * @param records 用药记录列表 + * @return 结果 + */ + public int batchInsertHealthMedicationRecord(List records); + + /** + * 修改用药记录 + * + * @param record 用药记录 + * @return 结果 + */ + public int updateHealthMedicationRecord(HealthMedicationRecord record); + + /** + * 删除用药记录 + * + * @param id 用药记录主键 + * @return 结果 + */ + public int deleteHealthMedicationRecordById(Long id); + + /** + * 批量删除用药记录 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int deleteHealthMedicationRecordByIds(Long[] ids); + + /** + * 逻辑删除用药记录 + * + * @param id 用药记录主键 + * @return 结果 + */ + public int removeHealthMedicationRecordById(Long id); + + /** + * 批量逻辑删除用药记录 + * + * @param ids 需要删除的数据主键集合 + * @return 结果 + */ + public int removeHealthMedicationRecordByIds(Long[] ids); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationPlanService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationPlanService.java new file mode 100644 index 0000000..7c6aef3 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationPlanService.java @@ -0,0 +1,87 @@ +package com.intc.health.service; + +import java.util.List; +import com.intc.health.domain.HealthMedicationPlan; +import com.intc.health.domain.dto.HealthMedicationPlanDto; +import com.intc.health.domain.vo.HealthMedicationPlanVo; + +/** + * 用药计划Service接口 + * + * @author intc + * @date 2025-03-18 + */ +public interface IHealthMedicationPlanService +{ + /** + * 查询用药计划 + * + * @param id 用药计划主键 + * @return 用药计划 + */ + public HealthMedicationPlanVo selectHealthMedicationPlanById(Long id); + + /** + * 查询用药计划列表 + * + * @param dto 用药计划 + * @return 用药计划集合 + */ + public List selectHealthMedicationPlanList(HealthMedicationPlanDto dto); + + /** + * 新增用药计划 + * + * @param plan 用药计划 + * @return 结果 + */ + public int insertHealthMedicationPlan(HealthMedicationPlan plan); + + /** + * 修改用药计划 + * + * @param plan 用药计划 + * @return 结果 + */ + public int updateHealthMedicationPlan(HealthMedicationPlan plan); + + /** + * 批量删除用药计划 + * + * @param ids 需要删除的用药计划主键集合 + * @return 结果 + */ + public int deleteHealthMedicationPlanByIds(Long[] ids); + + /** + * 删除用药计划信息 + * + * @param id 用药计划主键 + * @return 结果 + */ + public int deleteHealthMedicationPlanById(Long id); + + /** + * 暂停用药计划 + * + * @param id 用药计划主键 + * @return 结果 + */ + public int pauseHealthMedicationPlan(Long id); + + /** + * 恢复用药计划 + * + * @param id 用药计划主键 + * @return 结果 + */ + public int resumeHealthMedicationPlan(Long id); + + /** + * 结束用药计划 + * + * @param id 用药计划主键 + * @return 结果 + */ + public int endHealthMedicationPlan(Long id); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationRecordService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationRecordService.java new file mode 100644 index 0000000..85eff4d --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationRecordService.java @@ -0,0 +1,108 @@ +package com.intc.health.service; + +import java.util.List; +import com.intc.health.domain.HealthMedicationRecord; +import com.intc.health.domain.dto.HealthMedicationRecordDto; +import com.intc.health.domain.vo.HealthMedicationRecordVo; + +/** + * 用药记录Service接口 + * + * @author intc + * @date 2025-03-18 + */ +public interface IHealthMedicationRecordService +{ + /** + * 查询用药记录 + * + * @param id 用药记录主键 + * @return 用药记录 + */ + public HealthMedicationRecordVo selectHealthMedicationRecordById(Long id); + + /** + * 查询用药记录列表 + * + * @param dto 用药记录 + * @return 用药记录集合 + */ + public List selectHealthMedicationRecordList(HealthMedicationRecordDto dto); + + /** + * 查询某计划某天的用药记录 + * + * @param planId 计划ID + * @param date 日期(yyyy-MM-dd) + * @return 用药记录集合 + */ + public List selectRecordByPlanAndDate(Long planId, String date); + + /** + * 新增用药记录 + * + * @param record 用药记录 + * @return 结果 + */ + public int insertHealthMedicationRecord(HealthMedicationRecord record); + + /** + * 修改用药记录 + * + * @param record 用药记录 + * @return 结果 + */ + public int updateHealthMedicationRecord(HealthMedicationRecord record); + + /** + * 批量删除用药记录 + * + * @param ids 需要删除的用药记录主键集合 + * @return 结果 + */ + public int deleteHealthMedicationRecordByIds(Long[] ids); + + /** + * 删除用药记录信息 + * + * @param id 用药记录主键 + * @return 结果 + */ + public int deleteHealthMedicationRecordById(Long id); + + /** + * 服药(标记为已服用) + * + * @param id 记录ID + * @param dosage 实际服用剂量 + * @param remark 备注 + * @return 结果 + */ + public int takeMedication(Long id, Double dosage, String remark); + + /** + * 跳过服药 + * + * @param id 记录ID + * @param remark 原因 + * @return 结果 + */ + public int skipMedication(Long id, String remark); + + /** + * 获取今日用药记录 + * + * @param personId 人员ID(可选) + * @return 用药记录集合 + */ + public List getTodayRecords(Long personId); + + /** + * 统计某计划某天已服药次数 + * + * @param planId 计划ID + * @param date 日期(yyyy-MM-dd) + * @return 次数 + */ + public int countTakenByPlanAndDate(Long planId, String date); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationPlanServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationPlanServiceImpl.java new file mode 100644 index 0000000..f09c5b3 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationPlanServiceImpl.java @@ -0,0 +1,188 @@ +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.HealthMedicationPlan; +import com.intc.health.domain.dto.HealthMedicationPlanDto; +import com.intc.health.domain.vo.HealthMedicationPlanVo; +import com.intc.health.mapper.HealthMedicationPlanMapper; +import com.intc.health.mapper.HealthMedicationRecordMapper; +import com.intc.health.service.IHealthMedicationPlanService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.List; + +/** + * 用药计划Service业务层处理 + * + * @author intc + * @date 2025-03-18 + */ +@Service +public class HealthMedicationPlanServiceImpl implements IHealthMedicationPlanService +{ + @Resource + private HealthMedicationPlanMapper healthMedicationPlanMapper; + + @Resource + private HealthMedicationRecordMapper healthMedicationRecordMapper; + + /** + * 查询用药计划 + * + * @param id 用药计划主键 + * @return 用药计划 + */ + @Override + public HealthMedicationPlanVo selectHealthMedicationPlanById(Long id) + { + HealthMedicationPlanVo vo = healthMedicationPlanMapper.selectHealthMedicationPlanById(id); + if (vo != null) { + // 设置药品显示名称 + vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); + // 统计今日服药情况 + String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + int takenCount = healthMedicationRecordMapper.countTakenByPlanAndDate(id, today); + vo.setTodayTakenCount(takenCount); + vo.setTodayTotalCount(vo.getFrequency()); + } + return vo; + } + + /** + * 查询用药计划列表 + * + * @param dto 用药计划 + * @return 用药计划 + */ + @Override + public List selectHealthMedicationPlanList(HealthMedicationPlanDto dto) + { + List list = healthMedicationPlanMapper.selectHealthMedicationPlanList(dto); + String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + for (HealthMedicationPlanVo vo : list) { + // 设置药品显示名称 + vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); + // 统计今日服药情况 + if ("1".equals(vo.getStatus())) { + int takenCount = healthMedicationRecordMapper.countTakenByPlanAndDate(vo.getId(), today); + vo.setTodayTakenCount(takenCount); + vo.setTodayTotalCount(vo.getFrequency()); + } + } + return list; + } + + /** + * 新增用药计划 + * + * @param plan 用药计划 + * @return 结果 + */ + @Override + public int insertHealthMedicationPlan(HealthMedicationPlan plan) + { + plan.setId(IdWorker.getId()); + plan.setCreateBy(SecurityUtils.getUsername()); + plan.setCreateTime(DateUtils.getNowDate()); + plan.setDelFlag("0"); + // 默认状态为进行中 + if (plan.getStatus() == null) { + plan.setStatus("1"); + } + return healthMedicationPlanMapper.insertHealthMedicationPlan(plan); + } + + /** + * 修改用药计划 + * + * @param plan 用药计划 + * @return 结果 + */ + @Override + public int updateHealthMedicationPlan(HealthMedicationPlan plan) + { + plan.setUpdateBy(SecurityUtils.getUsername()); + plan.setUpdateTime(DateUtils.getNowDate()); + return healthMedicationPlanMapper.updateHealthMedicationPlan(plan); + } + + /** + * 批量删除用药计划 + * + * @param ids 需要删除的用药计划主键 + * @return 结果 + */ + @Override + public int deleteHealthMedicationPlanByIds(Long[] ids) + { + return healthMedicationPlanMapper.removeHealthMedicationPlanByIds(ids); + } + + /** + * 删除用药计划信息 + * + * @param id 用药计划主键 + * @return 结果 + */ + @Override + public int deleteHealthMedicationPlanById(Long id) + { + return healthMedicationPlanMapper.removeHealthMedicationPlanById(id); + } + + /** + * 暂停用药计划 + * + * @param id 用药计划主键 + * @return 结果 + */ + @Override + public int pauseHealthMedicationPlan(Long id) + { + HealthMedicationPlan plan = new HealthMedicationPlan(); + plan.setId(id); + plan.setStatus("3"); // 已暂停 + plan.setUpdateBy(SecurityUtils.getUsername()); + plan.setUpdateTime(DateUtils.getNowDate()); + return healthMedicationPlanMapper.updateHealthMedicationPlan(plan); + } + + /** + * 恢复用药计划 + * + * @param id 用药计划主键 + * @return 结果 + */ + @Override + public int resumeHealthMedicationPlan(Long id) + { + HealthMedicationPlan plan = new HealthMedicationPlan(); + plan.setId(id); + plan.setStatus("1"); // 进行中 + plan.setUpdateBy(SecurityUtils.getUsername()); + plan.setUpdateTime(DateUtils.getNowDate()); + return healthMedicationPlanMapper.updateHealthMedicationPlan(plan); + } + + /** + * 结束用药计划 + * + * @param id 用药计划主键 + * @return 结果 + */ + @Override + public int endHealthMedicationPlan(Long id) + { + HealthMedicationPlan plan = new HealthMedicationPlan(); + plan.setId(id); + plan.setStatus("2"); // 已结束 + plan.setUpdateBy(SecurityUtils.getUsername()); + plan.setUpdateTime(DateUtils.getNowDate()); + return healthMedicationPlanMapper.updateHealthMedicationPlan(plan); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationRecordServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationRecordServiceImpl.java new file mode 100644 index 0000000..0e7e713 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationRecordServiceImpl.java @@ -0,0 +1,214 @@ +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.HealthMedicationRecord; +import com.intc.health.domain.dto.HealthMedicationRecordDto; +import com.intc.health.domain.vo.HealthMedicationRecordVo; +import com.intc.health.mapper.HealthMedicationRecordMapper; +import com.intc.health.service.IHealthMedicationRecordService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Date; +import java.util.List; + +/** + * 用药记录Service业务层处理 + * + * @author intc + * @date 2025-03-18 + */ +@Service +public class HealthMedicationRecordServiceImpl implements IHealthMedicationRecordService +{ + @Resource + private HealthMedicationRecordMapper healthMedicationRecordMapper; + + /** + * 查询用药记录 + * + * @param id 用药记录主键 + * @return 用药记录 + */ + @Override + public HealthMedicationRecordVo selectHealthMedicationRecordById(Long id) + { + HealthMedicationRecordVo vo = healthMedicationRecordMapper.selectHealthMedicationRecordById(id); + if (vo != null) { + vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); + } + return vo; + } + + /** + * 查询用药记录列表 + * + * @param dto 用药记录 + * @return 用药记录 + */ + @Override + public List selectHealthMedicationRecordList(HealthMedicationRecordDto dto) + { + List list = healthMedicationRecordMapper.selectHealthMedicationRecordList(dto); + for (HealthMedicationRecordVo vo : list) { + vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); + } + return list; + } + + /** + * 查询某计划某天的用药记录 + * + * @param planId 计划ID + * @param date 日期(yyyy-MM-dd) + * @return 用药记录集合 + */ + @Override + public List selectRecordByPlanAndDate(Long planId, String date) + { + List list = healthMedicationRecordMapper.selectRecordByPlanAndDate(planId, date); + for (HealthMedicationRecordVo vo : list) { + vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); + } + return list; + } + + /** + * 新增用药记录 + * + * @param record 用药记录 + * @return 结果 + */ + @Override + public int insertHealthMedicationRecord(HealthMedicationRecord record) + { + record.setId(IdWorker.getId()); + record.setCreateBy(SecurityUtils.getUsername()); + record.setCreateTime(DateUtils.getNowDate()); + record.setDelFlag("0"); + // 默认状态为待服用 + if (record.getStatus() == null) { + record.setStatus("1"); + } + return healthMedicationRecordMapper.insertHealthMedicationRecord(record); + } + + /** + * 修改用药记录 + * + * @param record 用药记录 + * @return 结果 + */ + @Override + public int updateHealthMedicationRecord(HealthMedicationRecord record) + { + record.setUpdateBy(SecurityUtils.getUsername()); + record.setUpdateTime(DateUtils.getNowDate()); + return healthMedicationRecordMapper.updateHealthMedicationRecord(record); + } + + /** + * 批量删除用药记录 + * + * @param ids 需要删除的用药记录主键 + * @return 结果 + */ + @Override + public int deleteHealthMedicationRecordByIds(Long[] ids) + { + return healthMedicationRecordMapper.removeHealthMedicationRecordByIds(ids); + } + + /** + * 删除用药记录信息 + * + * @param id 用药记录主键 + * @return 结果 + */ + @Override + public int deleteHealthMedicationRecordById(Long id) + { + return healthMedicationRecordMapper.removeHealthMedicationRecordById(id); + } + + /** + * 服药(标记为已服用) + * + * @param id 记录ID + * @param dosage 实际服用剂量 + * @param remark 备注 + * @return 结果 + */ + @Override + public int takeMedication(Long id, Double dosage, String remark) + { + HealthMedicationRecord record = new HealthMedicationRecord(); + record.setId(id); + record.setStatus("2"); // 已服用 + record.setActualTime(new Date()); + if (dosage != null) { + record.setDosage(dosage); + } + if (remark != null) { + record.setRemark(remark); + } + record.setUpdateBy(SecurityUtils.getUsername()); + record.setUpdateTime(DateUtils.getNowDate()); + return healthMedicationRecordMapper.updateHealthMedicationRecord(record); + } + + /** + * 跳过服药 + * + * @param id 记录ID + * @param remark 原因 + * @return 结果 + */ + @Override + public int skipMedication(Long id, String remark) + { + HealthMedicationRecord record = new HealthMedicationRecord(); + record.setId(id); + record.setStatus("3"); // 已跳过 + if (remark != null) { + record.setRemark(remark); + } + record.setUpdateBy(SecurityUtils.getUsername()); + record.setUpdateTime(DateUtils.getNowDate()); + return healthMedicationRecordMapper.updateHealthMedicationRecord(record); + } + + /** + * 获取今日用药记录 + * + * @param personId 人员ID(可选) + * @return 用药记录集合 + */ + @Override + public List getTodayRecords(Long personId) + { + HealthMedicationRecordDto dto = new HealthMedicationRecordDto(); + dto.setQueryDate(new Date()); + if (personId != null) { + dto.setPersonId(personId); + } + return selectHealthMedicationRecordList(dto); + } + + /** + * 统计某计划某天已服药次数 + * + * @param planId 计划ID + * @param date 日期(yyyy-MM-dd) + * @return 次数 + */ + @Override + public int countTakenByPlanAndDate(Long planId, String date) + { + return healthMedicationRecordMapper.countTakenByPlanAndDate(planId, date); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationPlanMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationPlanMapper.xml new file mode 100644 index 0000000..ed091c4 --- /dev/null +++ b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationPlanMapper.xml @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select + a.id, + a.person_id, + p.name as person_name, + a.medicine_id, + m.name as medicine_name, + m.short_name, + m.brand, + m.packaging, + a.stock_in_id, + a.plan_name, + a.dosage, + a.dosage_unit, + a.frequency, + a.frequency_type, + a.time_points, + a.week_days, + a.start_date, + a.end_date, + a.reminder_enabled, + a.reminder_minutes, + a.status, + a.remark, + a.create_time + from + health_medication_plan a + left join health_person p on a.person_id = p.id + left join health_medicine_basic m on a.medicine_id = m.id + + + + + + + + + + insert into health_medication_plan + + id, + person_id, + medicine_id, + stock_in_id, + plan_name, + dosage, + dosage_unit, + frequency, + frequency_type, + time_points, + week_days, + start_date, + end_date, + reminder_enabled, + reminder_minutes, + status, + create_by, + create_time, + del_flag, + remark, + + + #{id}, + #{personId}, + #{medicineId}, + #{stockInId}, + #{planName}, + #{dosage}, + #{dosageUnit}, + #{frequency}, + #{frequencyType}, + #{timePoints}, + #{weekDays}, + #{startDate}, + #{endDate}, + #{reminderEnabled}, + #{reminderMinutes}, + #{status}, + #{createBy}, + #{createTime}, + #{delFlag}, + #{remark}, + + + + + update health_medication_plan + + person_id = #{personId}, + medicine_id = #{medicineId}, + stock_in_id = #{stockInId}, + plan_name = #{planName}, + dosage = #{dosage}, + dosage_unit = #{dosageUnit}, + frequency = #{frequency}, + frequency_type = #{frequencyType}, + time_points = #{timePoints}, + week_days = #{weekDays}, + start_date = #{startDate}, + end_date = #{endDate}, + reminder_enabled = #{reminderEnabled}, + reminder_minutes = #{reminderMinutes}, + status = #{status}, + update_by = #{updateBy}, + update_time = #{updateTime}, + del_flag = #{delFlag}, + remark = #{remark}, + + where id = #{id} + + + + delete from health_medication_plan where id = #{id} + + + + delete from health_medication_plan where id in + + #{id} + + + + + update health_medication_plan set del_flag='1' where id = #{id} + + + + update health_medication_plan set del_flag='1' where id in + + #{id} + + + \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml new file mode 100644 index 0000000..89b6b6f --- /dev/null +++ b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + select + a.id, + a.plan_id, + a.person_id, + p.name as person_name, + a.medicine_id, + m.name as medicine_name, + m.short_name, + m.brand, + m.packaging, + a.scheduled_time, + a.actual_time, + a.dosage, + a.dosage_unit, + a.status, + a.remark, + a.create_time, + pl.plan_name + from + health_medication_record a + left join health_person p on a.person_id = p.id + left join health_medicine_basic m on a.medicine_id = m.id + left join health_medication_plan pl on a.plan_id = pl.id + + + + + + + + + + + + insert into health_medication_record + + id, + plan_id, + person_id, + medicine_id, + scheduled_time, + actual_time, + dosage, + dosage_unit, + status, + create_by, + create_time, + del_flag, + remark, + + + #{id}, + #{planId}, + #{personId}, + #{medicineId}, + #{scheduledTime}, + #{actualTime}, + #{dosage}, + #{dosageUnit}, + #{status}, + #{createBy}, + #{createTime}, + #{delFlag}, + #{remark}, + + + + + insert into health_medication_record (id, plan_id, person_id, medicine_id, scheduled_time, dosage, dosage_unit, status, create_time, del_flag) + values + + (#{item.id}, #{item.planId}, #{item.personId}, #{item.medicineId}, #{item.scheduledTime}, #{item.dosage}, #{item.dosageUnit}, #{item.status}, #{item.createTime}, '0') + + + + + update health_medication_record + + plan_id = #{planId}, + person_id = #{personId}, + medicine_id = #{medicineId}, + scheduled_time = #{scheduledTime}, + actual_time = #{actualTime}, + dosage = #{dosage}, + dosage_unit = #{dosageUnit}, + status = #{status}, + update_by = #{updateBy}, + update_time = #{updateTime}, + del_flag = #{delFlag}, + remark = #{remark}, + + where id = #{id} + + + + delete from health_medication_record where id = #{id} + + + + delete from health_medication_record where id in + + #{id} + + + + + update health_medication_record set del_flag='1' where id = #{id} + + + + update health_medication_record set del_flag='1' where id in + + #{id} + + + \ No newline at end of file diff --git a/sql/medication.sql b/sql/medication.sql new file mode 100644 index 0000000..896f87c --- /dev/null +++ b/sql/medication.sql @@ -0,0 +1,128 @@ +-- ---------------------------- +-- 用药计划表 +-- ---------------------------- +DROP TABLE IF EXISTS health_medication_plan; +CREATE TABLE health_medication_plan ( + id BIGINT NOT NULL, + person_id BIGINT NOT NULL, + medicine_id BIGINT NOT NULL, + stock_in_id BIGINT NULL, + plan_name VARCHAR(200) NULL, + dosage DECIMAL(10,2) NOT NULL, + dosage_unit VARCHAR(20) NULL, + frequency INT NOT NULL, + frequency_type CHAR(1) DEFAULT '1', + time_points VARCHAR(500) NULL, + week_days VARCHAR(50) NULL, + start_date DATE NOT NULL, + end_date DATE NULL, + reminder_enabled CHAR(1) DEFAULT '0', + reminder_minutes INT DEFAULT 15, + status CHAR(1) DEFAULT '1', + del_flag CHAR(1) DEFAULT '0', + create_by VARCHAR(64) DEFAULT '', + create_time DATETIME NULL, + update_by VARCHAR(64) DEFAULT '', + update_time DATETIME NULL, + remark VARCHAR(500) NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB COMMENT='用药计划表'; + +CREATE INDEX idx_person_id ON health_medication_plan(person_id); +CREATE INDEX idx_medicine_id ON health_medication_plan(medicine_id); +CREATE INDEX idx_status ON health_medication_plan(status); +CREATE INDEX idx_start_date ON health_medication_plan(start_date); + +-- ---------------------------- +-- 用药记录表 +-- ---------------------------- +DROP TABLE IF EXISTS health_medication_record; +CREATE TABLE health_medication_record ( + id BIGINT NOT NULL, + plan_id BIGINT NOT NULL, + person_id BIGINT NOT NULL, + medicine_id BIGINT NOT NULL, + scheduled_time DATETIME NOT NULL, + actual_time DATETIME NULL, + dosage DECIMAL(10,2) NULL, + dosage_unit VARCHAR(20) NULL, + status CHAR(1) DEFAULT '1', + del_flag CHAR(1) DEFAULT '0', + create_by VARCHAR(64) DEFAULT '', + create_time DATETIME NULL, + update_by VARCHAR(64) DEFAULT '', + update_time DATETIME NULL, + remark VARCHAR(500) NULL, + PRIMARY KEY (id) +) ENGINE=InnoDB COMMENT='用药记录表'; + +CREATE INDEX idx_plan_id ON health_medication_record(plan_id); +CREATE INDEX idx_person_id ON health_medication_record(person_id); +CREATE INDEX idx_scheduled_time ON health_medication_record(scheduled_time); +CREATE INDEX idx_status ON health_medication_record(status); + +-- ---------------------------- +-- 字典数据 +-- ---------------------------- +INSERT INTO sys_dict_type (dict_id, dict_name, dict_type, status, create_by, create_time, remark) +VALUES +(nextval('seq_sys_dict_type'), '用药频率类型', 'medication_frequency_type', '0', 'admin', NOW(), '用药频率类型字典'), +(nextval('seq_sys_dict_type'), '用药计划状态', 'medication_plan_status', '0', 'admin', NOW(), '用药计划状态字典'), +(nextval('seq_sys_dict_type'), '用药记录状态', 'medication_record_status', '0', 'admin', NOW(), '用药记录状态字典'); + +INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) +VALUES +(nextval('seq_sys_dict_data'), 1, '每日', '1', 'medication_frequency_type', '', 'primary', 'Y', '0', 'admin', NOW(), NULL), +(nextval('seq_sys_dict_data'), 2, '隔日', '2', 'medication_frequency_type', '', 'success', 'N', '0', 'admin', NOW(), NULL), +(nextval('seq_sys_dict_data'), 3, '每周', '3', 'medication_frequency_type', '', 'info', 'N', '0', 'admin', NOW(), NULL), +(nextval('seq_sys_dict_data'), 4, '自定义', '4', 'medication_frequency_type', '', 'warning', 'N', '0', 'admin', NOW(), NULL); + +INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) +VALUES +(nextval('seq_sys_dict_data'), 1, '进行中', '1', 'medication_plan_status', '', 'primary', 'Y', '0', 'admin', NOW(), NULL), +(nextval('seq_sys_dict_data'), 2, '已结束', '2', 'medication_plan_status', '', 'info', 'N', '0', 'admin', NOW(), NULL), +(nextval('seq_sys_dict_data'), 3, '已暂停', '3', 'medication_plan_status', '', 'warning', 'N', '0', 'admin', NOW(), NULL); + +INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) +VALUES +(nextval('seq_sys_dict_data'), 1, '待服用', '1', 'medication_record_status', '', 'warning', 'Y', '0', 'admin', NOW(), NULL), +(nextval('seq_sys_dict_data'), 2, '已服用', '2', 'medication_record_status', '', 'success', 'N', '0', 'admin', NOW(), NULL), +(nextval('seq_sys_dict_data'), 3, '已跳过', '3', 'medication_record_status', '', 'info', 'N', '0', 'admin', NOW(), NULL), +(nextval('seq_sys_dict_data'), 4, '已过期', '4', 'medication_record_status', '', 'danger', 'N', '0', 'admin', NOW(), NULL); + +-- ---------------------------- +-- 菜单权限 +-- ---------------------------- +-- 用药计划菜单 +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +VALUES +(nextval('seq_sys_menu'), '用药计划', (SELECT menu_id FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1), 10, 'medicationPlan', 'health/medicationPlan/index', NULL, 1, 0, 'C', '0', '0', 'health:medicationPlan:list', 'calendar', 'admin', NOW(), '用药计划菜单'); + +-- 用药计划按钮权限 +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT nextval('seq_sys_menu'), '用药计划查询', m.menu_id, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:query', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' +UNION ALL +SELECT nextval('seq_sys_menu'), '用药计划新增', m.menu_id, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:add', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' +UNION ALL +SELECT nextval('seq_sys_menu'), '用药计划修改', m.menu_id, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:edit', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' +UNION ALL +SELECT nextval('seq_sys_menu'), '用药计划删除', m.menu_id, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:remove', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' +UNION ALL +SELECT nextval('seq_sys_menu'), '用药计划导出', m.menu_id, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:export', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list'; + +-- 用药记录菜单 +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +VALUES +(nextval('seq_sys_menu'), '用药记录', (SELECT menu_id FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1), 11, 'medicationRecord', 'health/medicationRecord/index', NULL, 1, 0, 'C', '0', '0', 'health:medicationRecord:list', 'log', 'admin', NOW(), '用药记录菜单'); + +-- 用药记录按钮权限 +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT nextval('seq_sys_menu'), '用药记录查询', m.menu_id, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:query', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list' +UNION ALL +SELECT nextval('seq_sys_menu'), '用药记录新增', m.menu_id, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:add', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list' +UNION ALL +SELECT nextval('seq_sys_menu'), '用药记录修改', m.menu_id, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:edit', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list' +UNION ALL +SELECT nextval('seq_sys_menu'), '用药记录删除', m.menu_id, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:remove', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list' +UNION ALL +SELECT nextval('seq_sys_menu'), '用药记录导出', m.menu_id, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:export', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list'; \ No newline at end of file From f5c9868a076556fbda2105b8c19c5a6d77360ecd Mon Sep 17 00:00:00 2001 From: bot5 Date: Thu, 19 Mar 2026 08:25:36 +0800 Subject: [PATCH 3/7] =?UTF-8?q?feat(health):=20=E6=96=B0=E5=A2=9E=E6=9C=8D?= =?UTF-8?q?=E8=8D=AF=E4=BB=BB=E5=8A=A1=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 MedicationTaskJob:每日生成服药任务、标记过期记录 - 新增 MedicationRemindJob:扫描并发送服药提醒 - 扩展 HealthMedicationRecordMapper:新增统计和查询方法 - 新增定时任务配置SQL和提醒日志表 --- .../mapper/HealthMedicationRecordMapper.java | 26 ++ .../intc/health/task/MedicationRemindJob.java | 153 ++++++++ .../intc/health/task/MedicationTaskJob.java | 333 ++++++++++++++++++ .../health/HealthMedicationRecordMapper.xml | 21 ++ sql/20250319-medication-task-job.sql | 90 +++++ 5 files changed, 623 insertions(+) create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java create mode 100644 sql/20250319-medication-task-job.sql diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java index 61042c8..1248135 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java @@ -103,4 +103,30 @@ public interface HealthMedicationRecordMapper * @return 结果 */ public int removeHealthMedicationRecordByIds(Long[] ids); + + /** + * 统计某计划某天的记录数(用于检查是否已生成) + * + * @param planId 计划ID + * @param date 日期 + * @return 记录数 + */ + public int countByPlanAndDate(@Param("planId") Long planId, @Param("date") String date); + + /** + * 标记过期的服药记录(超过24小时未服用) + * + * @param expireThreshold 过期阈值时间 + * @return 更新的记录数 + */ + public int markExpiredRecords(@Param("expireThreshold") java.time.LocalDateTime expireThreshold); + + /** + * 查询待提醒的服药记录 + * + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 服药记录集合 + */ + public List selectPendingRemindRecords(@Param("startTime") java.time.LocalDateTime startTime, @Param("endTime") java.time.LocalDateTime endTime); } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java new file mode 100644 index 0000000..56864e0 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java @@ -0,0 +1,153 @@ +package com.intc.health.task; + +import com.intc.health.domain.vo.HealthMedicationRecordVo; +import com.intc.health.mapper.HealthMedicationRecordMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 用药提醒定时器 + * 用于扫描待提醒的服药任务并发送提醒 + * + * @author bot5 + * @date 2026-03-19 + */ +@Component("medicationRemindJob") +public class MedicationRemindJob { + + private static final Logger log = LoggerFactory.getLogger(MedicationRemindJob.class); + + @Resource + private HealthMedicationRecordMapper recordMapper; + + // TODO: 注入消息推送服务,后续实现 + // @Resource + // private MessagePushService messagePushService; + + /** + * 扫描并发送服药提醒 + * 定时任务配置:每分钟执行 + * 调用方式:medicationRemindJob.scanAndSendReminders + */ + public void scanAndSendReminders() { + log.debug("========== 开始扫描服药提醒 =========="); + + LocalDateTime now = LocalDateTime.now(); + // 扫描未来1分钟内的待服药记录 + LocalDateTime startTime = now.plusMinutes(-1); + LocalDateTime endTime = now.plusMinutes(1); + + List pendingRecords = recordMapper.selectPendingRemindRecords(startTime, endTime); + + if (pendingRecords == null || pendingRecords.isEmpty()) { + log.debug("没有需要提醒的服药记录"); + return; + } + + log.info("发现 {} 条待提醒的服药记录", pendingRecords.size()); + + for (HealthMedicationRecordVo record : pendingRecords) { + try { + sendReminder(record); + } catch (Exception e) { + log.error("发送服药提醒失败,记录ID: {}, 错误: {}", record.getId(), e.getMessage(), e); + } + } + + log.debug("========== 服药提醒扫描完成 =========="); + } + + /** + * 发送服药提醒 + * + * @param record 服药记录 + */ + private void sendReminder(HealthMedicationRecordVo record) { + log.info("发送服药提醒: 人员={}, 药品={}, 计划时间={}", + record.getPersonName(), + record.getMedicineName(), + record.getScheduledTime()); + + // TODO: 实现消息推送逻辑 + // 1. 查询用户的提醒设置 + // 2. 根据设置选择推送渠道(APP推送/微信/短信) + // 3. 发送推送消息 + // 4. 记录提醒日志 + + // 暂时只打印日志 + String message = String.format("【服药提醒】%s,请按时服用 %s,剂量:%s%s", + record.getPersonName(), + record.getMedicineName(), + record.getDosage() != null ? record.getDosage() : "", + record.getDosageUnit() != null ? record.getDosageUnit() : ""); + + log.info("推送消息: {}", message); + + // TODO: 调用消息推送服务 + // messagePushService.push(record.getPersonId(), message); + } + + /** + * 扫描超时未服药记录并发送二次提醒 + * 定时任务配置:每5分钟执行 + * 调用方式:medicationRemindJob.scanOverdueRecords + */ + public void scanOverdueRecords() { + log.debug("========== 开始扫描超时未服药记录 =========="); + + LocalDateTime now = LocalDateTime.now(); + // 扫描超过计划时间30分钟仍未服药的记录 + LocalDateTime overdueThreshold = now.minusMinutes(30); + + // 查询超时的待服药记录 + List overdueRecords = recordMapper.selectPendingRemindRecords( + overdueThreshold.minusMinutes(5), // 查询5分钟内超时的 + overdueThreshold + ); + + if (overdueRecords == null || overdueRecords.isEmpty()) { + log.debug("没有超时未服药记录"); + return; + } + + log.info("发现 {} 条超时未服药记录", overdueRecords.size()); + + for (HealthMedicationRecordVo record : overdueRecords) { + try { + sendOverdueReminder(record); + } catch (Exception e) { + log.error("发送超时提醒失败,记录ID: {}, 错误: {}", record.getId(), e.getMessage(), e); + } + } + + log.debug("========== 超时未服药扫描完成 =========="); + } + + /** + * 发送超时提醒(二次提醒/通知家属) + * + * @param record 服药记录 + */ + private void sendOverdueReminder(HealthMedicationRecordVo record) { + log.warn("超时未服药: 人员={}, 药品={}, 计划时间={}", + record.getPersonName(), + record.getMedicineName(), + record.getScheduledTime()); + + // TODO: 实现超时提醒逻辑 + // 1. 发送二次提醒给用户 + // 2. 如果配置了家属通知,同时通知家属 + // 3. 记录提醒日志 + + String message = String.format("【漏服提醒】%s 未按时服用 %s,请及时处理", + record.getPersonName(), + record.getMedicineName()); + + log.info("推送超时消息: {}", message); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java new file mode 100644 index 0000000..6194b4c --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java @@ -0,0 +1,333 @@ +package com.intc.health.task; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.intc.common.core.utils.IdWorker; +import com.intc.health.domain.HealthMedicationRecord; +import com.intc.health.domain.vo.HealthMedicationPlanVo; +import com.intc.health.mapper.HealthMedicationPlanMapper; +import com.intc.health.mapper.HealthMedicationRecordMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * 用药任务定时器 + * 用于每日自动生成服药记录 + * + * @author bot5 + * @date 2026-03-19 + */ +@Component("medicationTaskJob") +public class MedicationTaskJob { + + private static final Logger log = LoggerFactory.getLogger(MedicationTaskJob.class); + + @Resource + private HealthMedicationPlanMapper planMapper; + + @Resource + private HealthMedicationRecordMapper recordMapper; + + /** + * 每日生成服药任务 + * 定时任务配置:每日 00:05 执行 + * 调用方式:medicationTaskJob.generateDailyTasks + */ + public void generateDailyTasks() { + log.info("========== 开始生成每日服药任务 =========="); + LocalDate today = LocalDate.now(); + int generatedCount = generateTasksForDate(today); + log.info("========== 每日服药任务生成完成,共生成 {} 条记录 ==========", generatedCount); + } + + /** + * 生成指定日期的服药任务 + * 可用于补生成历史任务 + * + * @param date 日期 + * @return 生成的记录数 + */ + public int generateTasksForDate(LocalDate date) { + int generatedCount = 0; + + // 查询所有进行中的计划 + List activePlans = planMapper.selectActivePlanList(); + if (activePlans == null || activePlans.isEmpty()) { + log.info("没有进行中的用药计划"); + return 0; + } + + String dateStr = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + + for (HealthMedicationPlanVo plan : activePlans) { + try { + // 检查该计划当天是否需要服药 + if (!shouldTakeMedicineOnDate(plan, date)) { + log.debug("计划 {} 在 {} 不需要服药", plan.getPlanName(), dateStr); + continue; + } + + // 检查该计划当天是否已生成过记录 + int existCount = recordMapper.countByPlanAndDate(plan.getId(), dateStr); + if (existCount > 0) { + log.debug("计划 {} 在 {} 已有 {} 条记录,跳过", plan.getPlanName(), dateStr, existCount); + continue; + } + + // 生成当天的服药记录 + List records = generateRecordsForPlan(plan, date); + if (!records.isEmpty()) { + recordMapper.batchInsertHealthMedicationRecord(records); + generatedCount += records.size(); + log.info("计划 {} 在 {} 生成了 {} 条服药记录", plan.getPlanName(), dateStr, records.size()); + } + } catch (Exception e) { + log.error("生成计划 {} 的服药记录失败: {}", plan.getId(), e.getMessage(), e); + } + } + + return generatedCount; + } + + /** + * 判断某计划在指定日期是否需要服药 + * + * @param plan 用药计划 + * @param date 日期 + * @return true-需要服药,false-不需要 + */ + private boolean shouldTakeMedicineOnDate(HealthMedicationPlanVo plan, LocalDate date) { + // 检查是否在计划日期范围内 + LocalDate startDate = plan.getStartDate() != null ? + plan.getStartDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate() : null; + LocalDate endDate = plan.getEndDate() != null ? + plan.getEndDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate() : null; + + if (startDate != null && date.isBefore(startDate)) { + return false; + } + if (endDate != null && date.isAfter(endDate)) { + return false; + } + + // 根据频率类型判断 + String frequencyType = plan.getFrequencyType(); + if (frequencyType == null) { + frequencyType = "1"; // 默认每日 + } + + switch (frequencyType) { + case "1": // 每日 + return true; + case "2": // 隔日 + return shouldTakeOnAlternateDay(plan, date); + case "3": // 每周 + return shouldTakeOnWeekly(plan, date); + case "4": // 自定义 + return shouldTakeOnCustom(plan, date); + default: + return true; + } + } + + /** + * 判断隔日服药 + */ + private boolean shouldTakeOnAlternateDay(HealthMedicationPlanVo plan, LocalDate date) { + LocalDate startDate = plan.getStartDate() != null ? + plan.getStartDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate() : date; + long daysBetween = ChronoUnit.DAYS.between(startDate, date); + return daysBetween % 2 == 0; + } + + /** + * 判断每周服药 + */ + private boolean shouldTakeOnWeekly(HealthMedicationPlanVo plan, LocalDate date) { + String weekDays = plan.getWeekDays(); + if (weekDays == null || weekDays.isEmpty()) { + return true; + } + + try { + // weekDays 格式为 JSON 数组,如 [1,3,5] 表示周一三五 + JSONArray daysArray = JSON.parseArray(weekDays); + DayOfWeek dayOfWeek = date.getDayOfWeek(); + int dayValue = dayOfWeek.getValue(); // 1=周一, 7=周日 + + for (int i = 0; i < daysArray.size(); i++) { + if (daysArray.getInteger(i) == dayValue) { + return true; + } + } + return false; + } catch (Exception e) { + log.error("解析周几配置失败: {}", weekDays, e); + return true; + } + } + + /** + * 判断自定义频率服药 + * 暂时默认返回 true,后续可根据具体需求扩展 + */ + private boolean shouldTakeOnCustom(HealthMedicationPlanVo plan, LocalDate date) { + // 自定义频率可以根据 remark 或其他字段配置 + // 暂时默认每日都服药 + return true; + } + + /** + * 为某个计划生成指定日期的服药记录 + * + * @param plan 用药计划 + * @param date 日期 + * @return 服药记录列表 + */ + private List generateRecordsForPlan(HealthMedicationPlanVo plan, LocalDate date) { + List records = new ArrayList<>(); + + // 获取服药时间点 + String timePoints = plan.getTimePoints(); + if (timePoints == null || timePoints.isEmpty()) { + // 如果没有配置时间点,根据频率生成默认时间点 + timePoints = generateDefaultTimePoints(plan.getFrequency()); + } + + try { + JSONArray timePointsArray = JSON.parseArray(timePoints); + LocalDateTime now = LocalDateTime.now(); + + for (int i = 0; i < timePointsArray.size(); i++) { + String timeStr = timePointsArray.getString(i); + LocalTime time = parseTime(timeStr); + + HealthMedicationRecord record = new HealthMedicationRecord(); + record.setId(IdWorker.getId()); + record.setPlanId(plan.getId()); + record.setPersonId(plan.getPersonId()); + record.setMedicineId(plan.getMedicineId()); + record.setScheduledTime(LocalDateTime.of(date, time)); + record.setDosage(plan.getDosage()); + record.setDosageUnit(plan.getDosageUnit()); + record.setStatus("1"); // 待服用 + record.setCreateTime(now); + record.setDelFlag("0"); + + records.add(record); + } + } catch (Exception e) { + log.error("解析时间点配置失败: {}", timePoints, e); + } + + return records; + } + + /** + * 根据每日次数生成默认时间点 + * + * @param frequency 每日次数 + * @return JSON 格式的时间点数组 + */ + private String generateDefaultTimePoints(Integer frequency) { + if (frequency == null || frequency <= 0) { + frequency = 1; + } + + JSONArray timePoints = new JSONArray(); + switch (frequency) { + case 1: + timePoints.add("08:00"); + break; + case 2: + timePoints.add("08:00"); + timePoints.add("20:00"); + break; + case 3: + timePoints.add("08:00"); + timePoints.add("12:00"); + timePoints.add("20:00"); + break; + case 4: + timePoints.add("08:00"); + timePoints.add("12:00"); + timePoints.add("16:00"); + timePoints.add("20:00"); + break; + default: + // 超过4次,均匀分布在 8:00-22:00 之间 + int startHour = 8; + int endHour = 22; + int interval = (endHour - startHour) / frequency; + for (int i = 0; i < frequency; i++) { + int hour = startHour + i * interval; + timePoints.add(String.format("%02d:00", hour)); + } + } + + return timePoints.toJSONString(); + } + + /** + * 解析时间字符串 + * + * @param timeStr 时间字符串,格式如 "08:00" 或 "8:00" + * @return LocalTime + */ + private LocalTime parseTime(String timeStr) { + try { + // 支持多种格式 + String normalized = timeStr.trim(); + if (normalized.length() == 4 && !normalized.contains(":")) { + // "0800" -> "08:00" + normalized = normalized.substring(0, 2) + ":" + normalized.substring(2); + } + + String[] parts = normalized.split(":"); + int hour = Integer.parseInt(parts[0]); + int minute = parts.length > 1 ? Integer.parseInt(parts[1]) : 0; + return LocalTime.of(hour, minute); + } catch (Exception e) { + log.warn("解析时间失败: {},使用默认时间 08:00", timeStr); + return LocalTime.of(8, 0); + } + } + + /** + * 检查并标记过期的服药记录 + * 定时任务配置:每5分钟执行 + * 调用方式:medicationTaskJob.markExpiredRecords + */ + public void markExpiredRecords() { + log.info("========== 开始检查过期服药记录 =========="); + LocalDateTime now = LocalDateTime.now(); + // 超过计划时间24小时的记录标记为过期 + LocalDateTime expireThreshold = now.minusHours(24); + + int count = recordMapper.markExpiredRecords(expireThreshold); + log.info("========== 标记过期记录完成,共 {} 条 ==========", count); + } + + /** + * 手动触发生成指定日期的任务(用于测试或补录) + * + * @param dateStr 日期字符串,格式 yyyy-MM-dd + * @return 生成的记录数 + */ + public int generateTasksManually(String dateStr) { + LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + return generateTasksForDate(date); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml index 89b6b6f..d12edd9 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml @@ -169,4 +169,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{id} + + + + + update health_medication_record + set status = '4', update_time = current_timestamp + where del_flag='0' and status = '1' + and scheduled_time < #{expireThreshold} + + + \ No newline at end of file diff --git a/sql/20250319-medication-task-job.sql b/sql/20250319-medication-task-job.sql new file mode 100644 index 0000000..f04ccb9 --- /dev/null +++ b/sql/20250319-medication-task-job.sql @@ -0,0 +1,90 @@ +-- ======================================== +-- 用药任务定时任务配置 +-- 在 sys_job 表中插入定时任务 +-- ======================================== + +-- 1. 每日生成服药任务(每日 00:05 执行) +INSERT INTO sys_job (job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) +VALUES ( + nextval('seq_sys_job'), + '每日生成服药任务', + 'DEFAULT', + 'medicationTaskJob.generateDailyTasks', + '0 5 0 * * ?', + '2', + '1', + '0', + 'admin', + NOW(), + '每日凌晨00:05自动生成当天的服药任务' +); + +-- 2. 扫描并发送服药提醒(每分钟执行) +INSERT INTO sys_job (job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) +VALUES ( + nextval('seq_sys_job'), + '扫描服药提醒', + 'DEFAULT', + 'medicationRemindJob.scanAndSendReminders', + '0 * * * * ?', + '2', + '1', + '0', + 'admin', + NOW(), + '每分钟扫描待提醒的服药任务并发送提醒' +); + +-- 3. 扫描超时未服药记录(每5分钟执行) +INSERT INTO sys_job (job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) +VALUES ( + nextval('seq_sys_job'), + '扫描超时未服药', + 'DEFAULT', + 'medicationRemindJob.scanOverdueRecords', + '0 */5 * * * ?', + '2', + '1', + '0', + 'admin', + NOW(), + '每5分钟扫描超时未服药的记录并发送提醒' +); + +-- 4. 标记过期服药记录(每小时执行) +INSERT INTO sys_job (job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) +VALUES ( + nextval('seq_sys_job'), + '标记过期服药记录', + 'DEFAULT', + 'medicationTaskJob.markExpiredRecords', + '0 0 * * * ?', + '2', + '1', + '0', + 'admin', + NOW(), + '每小时检查并标记过期的服药记录' +); + +-- ======================================== +-- 提醒日志表(可选,用于记录提醒历史) +-- ======================================== +DROP TABLE IF EXISTS health_medication_remind_log; +CREATE TABLE health_medication_remind_log ( + id BIGINT NOT NULL, + record_id BIGINT NOT NULL, + plan_id BIGINT NOT NULL, + person_id BIGINT NOT NULL, + remind_type CHAR(1) DEFAULT '1' COMMENT '提醒类型:1-按时提醒 2-超时提醒 3-漏服通知家属', + remind_time DATETIME NOT NULL, + remind_channel VARCHAR(20) DEFAULT 'app' COMMENT '提醒渠道:app/sms/wechat', + remind_result CHAR(1) DEFAULT '1' COMMENT '结果:1-成功 2-失败', + error_msg VARCHAR(500) NULL, + create_time DATETIME DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id) +) ENGINE=InnoDB COMMENT='用药提醒日志表'; + +CREATE INDEX idx_rmrl_record_id ON health_medication_remind_log(record_id); +CREATE INDEX idx_rmrl_person_id ON health_medication_remind_log(person_id); +CREATE INDEX idx_rmrl_remind_time ON health_medication_remind_log(remind_time); \ No newline at end of file From 8d71009f3a8371e8791cba1db6c2077ecaa3df76 Mon Sep 17 00:00:00 2001 From: bot5 Date: Thu, 19 Mar 2026 08:34:42 +0800 Subject: [PATCH 4/7] =?UTF-8?q?feat(health):=20=E6=96=B0=E5=A2=9E=E4=BE=9D?= =?UTF-8?q?=E4=BB=8E=E6=80=A7=E7=BB=9F=E8=AE=A1=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 MedicationAdherenceController:统计API接口 - 新增 IMedicationAdherenceService:统计服务接口 - 新增 MedicationAdherenceServiceImpl:统计服务实现 - 新增 MedicationAdherenceVo/DailyAdherenceVo:统计VO - 扩展 HealthMedicationRecordMapper:新增统计SQL - 新增菜单和统计汇总表SQL --- .../MedicationAdherenceController.java | 127 +++++++ .../domain/dto/MedicationAdherenceDto.java | 34 ++ .../health/domain/vo/DailyAdherenceVo.java | 42 +++ .../domain/vo/MedicationAdherenceVo.java | 60 ++++ .../mapper/HealthMedicationRecordMapper.java | 50 +++ .../service/IMedicationAdherenceService.java | 74 ++++ .../impl/MedicationAdherenceServiceImpl.java | 321 ++++++++++++++++++ .../health/HealthMedicationRecordMapper.xml | 117 +++++++ sql/20250319-medication-adherence.sql | 53 +++ 9 files changed, 878 insertions(+) create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationAdherenceDto.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/DailyAdherenceVo.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationAdherenceVo.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationAdherenceService.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationAdherenceServiceImpl.java create mode 100644 sql/20250319-medication-adherence.sql diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java new file mode 100644 index 0000000..3ea6897 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java @@ -0,0 +1,127 @@ +package com.intc.health.controller; + +import com.intc.common.core.web.domain.AjaxResult; +import com.intc.health.domain.dto.MedicationAdherenceDto; +import com.intc.health.domain.vo.DailyAdherenceVo; +import com.intc.health.domain.vo.MedicationAdherenceVo; +import com.intc.health.service.IMedicationAdherenceService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +/** + * 依从性统计Controller + * + * @author bot5 + * @date 2026-03-19 + */ +@RestController +@RequestMapping("/health/adherence") +@Api(tags = "依从性统计") +public class MedicationAdherenceController { + + @Resource + private IMedicationAdherenceService adherenceService; + + /** + * 获取总体依从性统计 + */ + @GetMapping("/overall") + @ApiOperation("获取总体依从性统计") + public AjaxResult getOverallAdherence(MedicationAdherenceDto dto) { + MedicationAdherenceVo vo = adherenceService.getOverallAdherence(dto); + return AjaxResult.success(vo); + } + + /** + * 获取每日依从性统计列表(趋势图) + */ + @GetMapping("/daily") + @ApiOperation("获取每日依从性统计列表") + public AjaxResult getDailyAdherenceList(MedicationAdherenceDto dto) { + List list = adherenceService.getDailyAdherenceList(dto); + return AjaxResult.success(list); + } + + /** + * 获取日历视图数据 + */ + @GetMapping("/calendar") + @ApiOperation("获取日历视图数据") + public AjaxResult getCalendarData( + @RequestParam(required = false) Long personId, + @RequestParam String yearMonth) { + List list = adherenceService.getCalendarData(personId, yearMonth); + return AjaxResult.success(list); + } + + /** + * 获取各时段服药统计 + */ + @GetMapping("/timeSlot") + @ApiOperation("获取各时段服药统计") + public AjaxResult getTimeSlotAdherence(MedicationAdherenceDto dto) { + Map map = adherenceService.getTimeSlotAdherence(dto); + return AjaxResult.success(map); + } + + /** + * 获取各药品依从性统计 + */ + @GetMapping("/medicine") + @ApiOperation("获取各药品依从性统计") + public AjaxResult getMedicineAdherenceList(MedicationAdherenceDto dto) { + List list = adherenceService.getMedicineAdherenceList(dto); + return AjaxResult.success(list); + } + + /** + * 获取各人员依从性统计 + */ + @GetMapping("/person") + @ApiOperation("获取各人员依从性统计") + public AjaxResult getPersonAdherenceList(MedicationAdherenceDto dto) { + List list = adherenceService.getPersonAdherenceList(dto); + return AjaxResult.success(list); + } + + /** + * 获取漏服原因统计 + */ + @GetMapping("/missedReason") + @ApiOperation("获取漏服原因统计") + public AjaxResult getMissedReasonStats(MedicationAdherenceDto dto) { + Map map = adherenceService.getMissedReasonStats(dto); + return AjaxResult.success(map); + } + + /** + * 获取仪表盘概览数据 + */ + @GetMapping("/dashboard") + @ApiOperation("获取仪表盘概览数据") + public AjaxResult getDashboard(@RequestParam(required = false) Long personId) { + // 获取最近7天的统计数据 + MedicationAdherenceDto dto = new MedicationAdherenceDto(); + dto.setPersonId(personId); + dto.setStartDate(java.time.LocalDate.now().minusDays(7).toString()); + dto.setEndDate(java.time.LocalDate.now().toString()); + + Map result = new java.util.HashMap<>(); + + // 总体统计 + result.put("overall", adherenceService.getOverallAdherence(dto)); + + // 每日趋势 + result.put("dailyTrend", adherenceService.getDailyAdherenceList(dto)); + + // 时段统计 + result.put("timeSlot", adherenceService.getTimeSlotAdherence(dto)); + + return AjaxResult.success(result); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationAdherenceDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationAdherenceDto.java new file mode 100644 index 0000000..422edae --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationAdherenceDto.java @@ -0,0 +1,34 @@ +package com.intc.health.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 依从性统计查询DTO + * + * @author bot5 + * @date 2026-03-19 + */ +@Data +@ApiModel("依从性统计查询DTO") +public class MedicationAdherenceDto { + + @ApiModelProperty("人员ID") + private Long personId; + + @ApiModelProperty("计划ID") + private Long planId; + + @ApiModelProperty("开始日期(yyyy-MM-dd)") + private String startDate; + + @ApiModelProperty("结束日期(yyyy-MM-dd)") + private String endDate; + + @ApiModelProperty("统计类型:day-日,week-周,month-月,quarter-季度") + private String statType; + + @ApiModelProperty("药品ID") + private Long medicineId; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/DailyAdherenceVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/DailyAdherenceVo.java new file mode 100644 index 0000000..94598c5 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/DailyAdherenceVo.java @@ -0,0 +1,42 @@ +package com.intc.health.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 每日依从性统计VO + * + * @author bot5 + * @date 2026-03-19 + */ +@Data +@ApiModel("每日依从性统计VO") +public class DailyAdherenceVo { + + @ApiModelProperty("日期") + private String date; + + @ApiModelProperty("总任务数") + private Integer totalTasks; + + @ApiModelProperty("已服药数") + private Integer completedTasks; + + @ApiModelProperty("漏服数") + private Integer missedTasks; + + @ApiModelProperty("跳过数") + private Integer skippedTasks; + + @ApiModelProperty("准时服药数") + private Integer ontimeTasks; + + @ApiModelProperty("服药率(%)") + private BigDecimal adherenceRate; + + @ApiModelProperty("准时率(%)") + private BigDecimal ontimeRate; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationAdherenceVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationAdherenceVo.java new file mode 100644 index 0000000..88db068 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationAdherenceVo.java @@ -0,0 +1,60 @@ +package com.intc.health.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 依从性统计VO + * + * @author bot5 + * @date 2026-03-19 + */ +@Data +@ApiModel("依从性统计VO") +public class MedicationAdherenceVo { + + @ApiModelProperty("总任务数") + private Integer totalTasks; + + @ApiModelProperty("已服药数") + private Integer completedTasks; + + @ApiModelProperty("漏服数") + private Integer missedTasks; + + @ApiModelProperty("跳过数") + private Integer skippedTasks; + + @ApiModelProperty("待服用数") + private Integer pendingTasks; + + @ApiModelProperty("准时服药数") + private Integer ontimeTasks; + + @ApiModelProperty("服药率(%)") + private BigDecimal adherenceRate; + + @ApiModelProperty("准时率(%)") + private BigDecimal ontimeRate; + + @ApiModelProperty("统计开始日期") + private String startDate; + + @ApiModelProperty("统计结束日期") + private String endDate; + + @ApiModelProperty("人员ID") + private Long personId; + + @ApiModelProperty("人员名称") + private String personName; + + @ApiModelProperty("计划ID") + private Long planId; + + @ApiModelProperty("计划名称") + private String planName; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java index 1248135..5dee335 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java @@ -129,4 +129,54 @@ public interface HealthMedicationRecordMapper * @return 服药记录集合 */ public List selectPendingRemindRecords(@Param("startTime") java.time.LocalDateTime startTime, @Param("endTime") java.time.LocalDateTime endTime); + + // ========== 依从性统计相关 ========== + + /** + * 获取总体依从性统计 + * + * @param dto 查询参数 + * @return 统计结果Map + */ + public java.util.Map getAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); + + /** + * 获取每日依从性统计 + * + * @param dto 查询参数 + * @return 每日统计列表 + */ + public java.util.List> getDailyAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); + + /** + * 获取时段依从性统计 + * + * @param dto 查询参数 + * @return 时段统计列表 + */ + public java.util.List> getTimeSlotAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); + + /** + * 获取药品依从性统计 + * + * @param dto 查询参数 + * @return 药品统计列表 + */ + public java.util.List> getMedicineAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); + + /** + * 获取人员依从性统计 + * + * @param dto 查询参数 + * @return 人员统计列表 + */ + public java.util.List> getPersonAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); + + /** + * 获取漏服原因统计 + * + * @param dto 查询参数 + * @return 原因统计列表 + */ + public java.util.List> getMissedReasonStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationAdherenceService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationAdherenceService.java new file mode 100644 index 0000000..77aaa98 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationAdherenceService.java @@ -0,0 +1,74 @@ +package com.intc.health.service; + +import com.intc.health.domain.dto.MedicationAdherenceDto; +import com.intc.health.domain.vo.DailyAdherenceVo; +import com.intc.health.domain.vo.MedicationAdherenceVo; + +import java.util.List; +import java.util.Map; + +/** + * 依从性统计Service接口 + * + * @author bot5 + * @date 2026-03-19 + */ +public interface IMedicationAdherenceService { + + /** + * 获取总体依从性统计 + * + * @param dto 查询参数 + * @return 统计结果 + */ + MedicationAdherenceVo getOverallAdherence(MedicationAdherenceDto dto); + + /** + * 获取每日依从性统计列表(用于趋势图) + * + * @param dto 查询参数 + * @return 每日统计列表 + */ + List getDailyAdherenceList(MedicationAdherenceDto dto); + + /** + * 获取日历视图数据(某月的每日统计) + * + * @param personId 人员ID + * @param yearMonth 年月(yyyy-MM) + * @return 每日统计列表 + */ + List getCalendarData(Long personId, String yearMonth); + + /** + * 获取各时段服药统计(早中晚) + * + * @param dto 查询参数 + * @return 时段统计Map + */ + Map getTimeSlotAdherence(MedicationAdherenceDto dto); + + /** + * 获取各药品依从性统计 + * + * @param dto 查询参数 + * @return 药品统计列表 + */ + List getMedicineAdherenceList(MedicationAdherenceDto dto); + + /** + * 获取各人员依从性统计(家属视角) + * + * @param dto 查询参数 + * @return 人员统计列表 + */ + List getPersonAdherenceList(MedicationAdherenceDto dto); + + /** + * 获取漏服原因统计 + * + * @param dto 查询参数 + * @return 原因统计Map + */ + Map getMissedReasonStats(MedicationAdherenceDto dto); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationAdherenceServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationAdherenceServiceImpl.java new file mode 100644 index 0000000..e87e31d --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationAdherenceServiceImpl.java @@ -0,0 +1,321 @@ +package com.intc.health.service.impl; + +import com.intc.health.domain.dto.MedicationAdherenceDto; +import com.intc.health.domain.vo.DailyAdherenceVo; +import com.intc.health.domain.vo.MedicationAdherenceVo; +import com.intc.health.mapper.HealthMedicationRecordMapper; +import com.intc.health.service.IMedicationAdherenceService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.time.LocalDate; +import java.time.YearMonth; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; +import java.util.*; + +/** + * 依从性统计Service业务层处理 + * + * @author bot5 + * @date 2026-03-19 + */ +@Service +public class MedicationAdherenceServiceImpl implements IMedicationAdherenceService { + + @Resource + private HealthMedicationRecordMapper recordMapper; + + @Override + public MedicationAdherenceVo getOverallAdherence(MedicationAdherenceDto dto) { + Map stats = recordMapper.getAdherenceStats(dto); + + MedicationAdherenceVo vo = new MedicationAdherenceVo(); + vo.setTotalTasks(getIntValue(stats, "total_tasks")); + vo.setCompletedTasks(getIntValue(stats, "completed_tasks")); + vo.setMissedTasks(getIntValue(stats, "missed_tasks")); + vo.setSkippedTasks(getIntValue(stats, "skipped_tasks")); + vo.setPendingTasks(getIntValue(stats, "pending_tasks")); + vo.setOntimeTasks(getIntValue(stats, "ontime_tasks")); + + // 计算服药率 + if (vo.getTotalTasks() > 0) { + BigDecimal rate = BigDecimal.valueOf(vo.getCompletedTasks()) + .multiply(BigDecimal.valueOf(100)) + .divide(BigDecimal.valueOf(vo.getTotalTasks()), 2, RoundingMode.HALF_UP); + vo.setAdherenceRate(rate); + } else { + vo.setAdherenceRate(BigDecimal.ZERO); + } + + // 计算准时率 + if (vo.getCompletedTasks() > 0) { + BigDecimal rate = BigDecimal.valueOf(vo.getOntimeTasks()) + .multiply(BigDecimal.valueOf(100)) + .divide(BigDecimal.valueOf(vo.getCompletedTasks()), 2, RoundingMode.HALF_UP); + vo.setOntimeRate(rate); + } else { + vo.setOntimeRate(BigDecimal.ZERO); + } + + vo.setStartDate(dto.getStartDate()); + vo.setEndDate(dto.getEndDate()); + vo.setPersonId(dto.getPersonId()); + vo.setPlanId(dto.getPlanId()); + + return vo; + } + + @Override + public List getDailyAdherenceList(MedicationAdherenceDto dto) { + List> dailyStats = recordMapper.getDailyAdherenceStats(dto); + + List result = new ArrayList<>(); + for (Map stat : dailyStats) { + DailyAdherenceVo vo = new DailyAdherenceVo(); + vo.setDate(getStringValue(stat, "stat_date")); + vo.setTotalTasks(getIntValue(stat, "total_tasks")); + vo.setCompletedTasks(getIntValue(stat, "completed_tasks")); + vo.setMissedTasks(getIntValue(stat, "missed_tasks")); + vo.setSkippedTasks(getIntValue(stat, "skipped_tasks")); + vo.setOntimeTasks(getIntValue(stat, "ontime_tasks")); + + // 计算服药率 + if (vo.getTotalTasks() > 0) { + BigDecimal rate = BigDecimal.valueOf(vo.getCompletedTasks()) + .multiply(BigDecimal.valueOf(100)) + .divide(BigDecimal.valueOf(vo.getTotalTasks()), 2, RoundingMode.HALF_UP); + vo.setAdherenceRate(rate); + } else { + vo.setAdherenceRate(BigDecimal.ZERO); + } + + // 计算准时率 + if (vo.getCompletedTasks() > 0) { + BigDecimal rate = BigDecimal.valueOf(vo.getOntimeTasks()) + .multiply(BigDecimal.valueOf(100)) + .divide(BigDecimal.valueOf(vo.getCompletedTasks()), 2, RoundingMode.HALF_UP); + vo.setOntimeRate(rate); + } else { + vo.setOntimeRate(BigDecimal.ZERO); + } + + result.add(vo); + } + + return result; + } + + @Override + public List getCalendarData(Long personId, String yearMonth) { + // 解析年月 + YearMonth ym = YearMonth.parse(yearMonth, DateTimeFormatter.ofPattern("yyyy-MM")); + LocalDate startDate = ym.atDay(1); + LocalDate endDate = ym.atEndOfMonth(); + + MedicationAdherenceDto dto = new MedicationAdherenceDto(); + dto.setPersonId(personId); + dto.setStartDate(startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + dto.setEndDate(endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + + List dailyList = getDailyAdherenceList(dto); + + // 补全缺失的日期 + List result = new ArrayList<>(); + Map dateMap = new HashMap<>(); + for (DailyAdherenceVo vo : dailyList) { + dateMap.put(vo.getDate(), vo); + } + + long days = ChronoUnit.DAYS.between(startDate, endDate) + 1; + for (int i = 0; i < days; i++) { + LocalDate date = startDate.plusDays(i); + String dateStr = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + + if (dateMap.containsKey(dateStr)) { + result.add(dateMap.get(dateStr)); + } else { + // 没有数据的日期补零 + DailyAdherenceVo vo = new DailyAdherenceVo(); + vo.setDate(dateStr); + vo.setTotalTasks(0); + vo.setCompletedTasks(0); + vo.setMissedTasks(0); + vo.setSkippedTasks(0); + vo.setOntimeTasks(0); + vo.setAdherenceRate(BigDecimal.ZERO); + vo.setOntimeRate(BigDecimal.ZERO); + result.add(vo); + } + } + + return result; + } + + @Override + public Map getTimeSlotAdherence(MedicationAdherenceDto dto) { + List> slotStats = recordMapper.getTimeSlotAdherenceStats(dto); + + Map result = new LinkedHashMap<>(); + result.put("morning", new MedicationAdherenceVo()); // 6:00-12:00 + result.put("afternoon", new MedicationAdherenceVo()); // 12:00-18:00 + result.put("evening", new MedicationAdherenceVo()); // 18:00-24:00 + result.put("night", new MedicationAdherenceVo()); // 0:00-6:00 + + for (Map stat : slotStats) { + int hour = getIntValue(stat, "hour"); + String slotKey = getTimeSlot(hour); + + MedicationAdherenceVo vo = result.get(slotKey); + if (vo.getTotalTasks() == null) { + vo.setTotalTasks(0); + vo.setCompletedTasks(0); + vo.setMissedTasks(0); + vo.setOntimeTasks(0); + } + + vo.setTotalTasks(vo.getTotalTasks() + getIntValue(stat, "total_tasks")); + vo.setCompletedTasks(vo.getCompletedTasks() + getIntValue(stat, "completed_tasks")); + vo.setMissedTasks(vo.getMissedTasks() + getIntValue(stat, "missed_tasks")); + vo.setOntimeTasks(vo.getOntimeTasks() + getIntValue(stat, "ontime_tasks")); + } + + // 计算各时段的服药率 + for (Map.Entry entry : result.entrySet()) { + MedicationAdherenceVo vo = entry.getValue(); + if (vo.getTotalTasks() != null && vo.getTotalTasks() > 0) { + BigDecimal rate = BigDecimal.valueOf(vo.getCompletedTasks()) + .multiply(BigDecimal.valueOf(100)) + .divide(BigDecimal.valueOf(vo.getTotalTasks()), 2, RoundingMode.HALF_UP); + vo.setAdherenceRate(rate); + } else { + vo.setAdherenceRate(BigDecimal.ZERO); + } + } + + return result; + } + + @Override + public List getMedicineAdherenceList(MedicationAdherenceDto dto) { + List> medicineStats = recordMapper.getMedicineAdherenceStats(dto); + + List result = new ArrayList<>(); + for (Map stat : medicineStats) { + MedicationAdherenceVo vo = new MedicationAdherenceVo(); + vo.setTotalTasks(getIntValue(stat, "total_tasks")); + vo.setCompletedTasks(getIntValue(stat, "completed_tasks")); + vo.setMissedTasks(getIntValue(stat, "missed_tasks")); + vo.setOntimeTasks(getIntValue(stat, "ontime_tasks")); + + // 药品信息 + // planId 和 planName 需要从查询结果获取 + + // 计算服药率 + if (vo.getTotalTasks() > 0) { + BigDecimal rate = BigDecimal.valueOf(vo.getCompletedTasks()) + .multiply(BigDecimal.valueOf(100)) + .divide(BigDecimal.valueOf(vo.getTotalTasks()), 2, RoundingMode.HALF_UP); + vo.setAdherenceRate(rate); + } else { + vo.setAdherenceRate(BigDecimal.ZERO); + } + + result.add(vo); + } + + return result; + } + + @Override + public List getPersonAdherenceList(MedicationAdherenceDto dto) { + List> personStats = recordMapper.getPersonAdherenceStats(dto); + + List result = new ArrayList<>(); + for (Map stat : personStats) { + MedicationAdherenceVo vo = new MedicationAdherenceVo(); + vo.setPersonId(getLongValue(stat, "person_id")); + vo.setPersonName(getStringValue(stat, "person_name")); + vo.setTotalTasks(getIntValue(stat, "total_tasks")); + vo.setCompletedTasks(getIntValue(stat, "completed_tasks")); + vo.setMissedTasks(getIntValue(stat, "missed_tasks")); + vo.setOntimeTasks(getIntValue(stat, "ontime_tasks")); + + // 计算服药率 + if (vo.getTotalTasks() > 0) { + BigDecimal rate = BigDecimal.valueOf(vo.getCompletedTasks()) + .multiply(BigDecimal.valueOf(100)) + .divide(BigDecimal.valueOf(vo.getTotalTasks()), 2, RoundingMode.HALF_UP); + vo.setAdherenceRate(rate); + } else { + vo.setAdherenceRate(BigDecimal.ZERO); + } + + result.add(vo); + } + + return result; + } + + @Override + public Map getMissedReasonStats(MedicationAdherenceDto dto) { + List> reasonStats = recordMapper.getMissedReasonStats(dto); + + Map result = new LinkedHashMap<>(); + for (Map stat : reasonStats) { + String reason = getStringValue(stat, "remark"); + if (reason == null || reason.isEmpty()) { + reason = "未填写原因"; + } + int count = getIntValue(stat, "count"); + result.merge(reason, count, Integer::sum); + } + + return result; + } + + // ========== 辅助方法 ========== + + private String getTimeSlot(int hour) { + if (hour >= 6 && hour < 12) { + return "morning"; + } else if (hour >= 12 && hour < 18) { + return "afternoon"; + } else if (hour >= 18 && hour < 24) { + return "evening"; + } else { + return "night"; + } + } + + private Integer getIntValue(Map map, String key) { + if (map == null || map.get(key) == null) { + return 0; + } + Object value = map.get(key); + if (value instanceof Number) { + return ((Number) value).intValue(); + } + return 0; + } + + private Long getLongValue(Map map, String key) { + if (map == null || map.get(key) == null) { + return null; + } + Object value = map.get(key); + if (value instanceof Number) { + return ((Number) value).longValue(); + } + return null; + } + + private String getStringValue(Map map, String key) { + if (map == null || map.get(key) == null) { + return null; + } + return map.get(key).toString(); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml index d12edd9..bdc58a9 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml @@ -190,4 +190,121 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and a.scheduled_time <= #{endTime} order by a.scheduled_time asc + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sql/20250319-medication-adherence.sql b/sql/20250319-medication-adherence.sql new file mode 100644 index 0000000..ff539f4 --- /dev/null +++ b/sql/20250319-medication-adherence.sql @@ -0,0 +1,53 @@ +-- ======================================== +-- 依从性统计功能 - SQL脚本 +-- ======================================== + +-- 用药统计菜单 +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +VALUES ( + nextval('seq_sys_menu'), + '用药统计', + (SELECT menu_id FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1), + 12, + 'medicationStatistic', + 'health/medicationStatistic/index', + NULL, + 1, + 0, + 'C', + '0', + '0', + 'health:medicationStatistic:query', + 'chart', + 'admin', + NOW(), + '用药统计菜单' +); + +-- 用药统计按钮权限 +INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT nextval('seq_sys_menu'), '用药统计查询', m.menu_id, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationStatistic:query', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationStatistic:query'; + +-- ======================================== +-- 添加依从性统计汇总表(可选,用于预计算性能优化) +-- ======================================== +DROP TABLE IF EXISTS health_medication_adherence_stats; +CREATE TABLE health_medication_adherence_stats ( + id BIGINT NOT NULL, + person_id BIGINT NOT NULL, + plan_id BIGINT NULL, + stat_date DATE NOT NULL, + total_tasks INT DEFAULT 0, + completed_tasks INT DEFAULT 0, + missed_tasks INT DEFAULT 0, + skipped_tasks INT DEFAULT 0, + ontime_tasks INT DEFAULT 0, + adherence_rate DECIMAL(5,2) DEFAULT 0.00, + ontime_rate DECIMAL(5,2) DEFAULT 0.00, + create_time DATETIME DEFAULT CURRENT_TIMESTAMP, + update_time DATETIME DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id) +) ENGINE=InnoDB COMMENT='依从性统计汇总表'; + +CREATE UNIQUE INDEX idx_hmas_person_date ON health_medication_adherence_stats(person_id, stat_date, plan_id); +CREATE INDEX idx_hmas_stat_date ON health_medication_adherence_stats(stat_date); \ No newline at end of file From 191f6e1cafdd98dfe32d4824c6356e3f7e58b54b Mon Sep 17 00:00:00 2001 From: bot5 Date: Thu, 19 Mar 2026 20:19:56 +0800 Subject: [PATCH 5/7] =?UTF-8?q?refactor(health):=20=E6=8C=89=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E8=A7=84=E8=8C=83=E9=87=8D=E6=9E=84=E7=94=A8=E8=8D=AF?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【重大重构】完全按照功能规划文档重写 ## 表结构变更 - medication_plan: 用药计划表(按文档设计) - medication_task: 服药任务表(按文档设计) - medication_remind_log: 提醒日志表 - medicine_stock_log: 库存变动表 - medication_adherence_stats: 统计汇总表 ## 字段变更 - frequency_config: JSONB 频次配置 - time_slots: JSONB 时段配置 - family_member_ids: JSONB 家属通知 - status: 状态值按文档规范(0-待服药 1-已服药 2-漏服 3-跳过) ## 新增组件 - JsonNodeTypeHandler: PostgreSQL JSONB 类型处理器 ## SQL 脚本 - medication_module_pg.sql: 建表语句(PostgreSQL) - medication_menu_pg.sql: 菜单权限配置 - medication_job_pg.sql: 定时任务配置 --- .../core/handler/JsonNodeTypeHandler.java | 63 ++++ .../HealthMedicationPlanController.java | 145 -------- .../HealthMedicationRecordController.java | 160 --------- .../MedicationAdherenceController.java | 94 ++---- .../controller/MedicationPlanController.java | 97 ++++++ .../controller/MedicationTaskController.java | 80 +++++ .../health/domain/ChronicDiseaseRecord.java | 105 ++---- .../health/domain/HealthMedicationPlan.java | 139 -------- .../health/domain/HealthMedicationRecord.java | 99 ------ .../intc/health/domain/MedicationPlan.java | 83 +++++ .../intc/health/domain/MedicationTask.java | 69 ++++ .../domain/dto/HealthMedicationPlanDto.java | 69 ---- .../domain/dto/HealthMedicationRecordDto.java | 65 ---- .../health/domain/dto/MedicationPlanDto.java | 56 +++ .../health/domain/dto/MedicationTaskDto.java | 42 +++ .../domain/vo/HealthMedicationPlanVo.java | 118 ------- .../domain/vo/HealthMedicationRecordVo.java | 87 ----- .../health/domain/vo/MedicationPlanVo.java | 93 +++++ .../health/domain/vo/MedicationTaskVo.java | 75 ++++ .../mapper/HealthMedicationPlanMapper.java | 86 ----- .../mapper/HealthMedicationRecordMapper.java | 182 ---------- .../health/mapper/MedicationPlanMapper.java | 62 ++++ .../health/mapper/MedicationTaskMapper.java | 107 ++++++ .../service/IHealthMedicationPlanService.java | 87 ----- .../IHealthMedicationRecordService.java | 108 ------ .../service/IMedicationAdherenceService.java | 53 +-- .../service/IMedicationPlanService.java | 56 +++ .../service/IMedicationTaskService.java | 56 +++ .../impl/HealthMedicationPlanServiceImpl.java | 188 ----------- .../HealthMedicationRecordServiceImpl.java | 214 ------------ .../impl/MedicationAdherenceServiceImpl.java | 168 ++------- .../impl/MedicationPlanServiceImpl.java | 94 ++++++ .../impl/MedicationTaskServiceImpl.java | 93 +++++ .../intc/health/task/MedicationRemindJob.java | 117 +++---- .../intc/health/task/MedicationTaskJob.java | 319 +++++++----------- .../health/HealthMedicationPlanMapper.xml | 190 ----------- .../health/HealthMedicationRecordMapper.xml | 310 ----------------- .../mapper/health/MedicationPlanMapper.xml | 138 ++++++++ .../mapper/health/MedicationTaskMapper.xml | 196 +++++++++++ sql/20250319-medication-adherence.sql | 53 --- sql/20250319-medication-task-job.sql | 90 ----- sql/chronic_disease_record.sql | 105 ------ sql/medication.sql | 128 ------- sql/medication_job_pg.sql | 64 ++++ sql/medication_menu_pg.sql | 106 ++++++ sql/medication_module_pg.sql | 293 ++++++++++++++++ 46 files changed, 2159 insertions(+), 3243 deletions(-) create mode 100644 intc-common/intc-common-core/src/main/java/com/intc/common/core/handler/JsonNodeTypeHandler.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationPlanController.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationRecordController.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationPlanController.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationPlan.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationRecord.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationPlan.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationTask.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationPlanDto.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationRecordDto.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationPlanDto.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationTaskDto.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationPlanVo.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationRecordVo.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationPlanMapper.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationPlanMapper.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationTaskMapper.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationPlanService.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationRecordService.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationPlanService.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationTaskService.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationPlanServiceImpl.java delete mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationRecordServiceImpl.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationTaskServiceImpl.java delete mode 100644 intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationPlanMapper.xml delete mode 100644 intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml create mode 100644 intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml create mode 100644 intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml delete mode 100644 sql/20250319-medication-adherence.sql delete mode 100644 sql/20250319-medication-task-job.sql delete mode 100644 sql/chronic_disease_record.sql delete mode 100644 sql/medication.sql create mode 100644 sql/medication_job_pg.sql create mode 100644 sql/medication_menu_pg.sql create mode 100644 sql/medication_module_pg.sql diff --git a/intc-common/intc-common-core/src/main/java/com/intc/common/core/handler/JsonNodeTypeHandler.java b/intc-common/intc-common-core/src/main/java/com/intc/common/core/handler/JsonNodeTypeHandler.java new file mode 100644 index 0000000..cdb6ee5 --- /dev/null +++ b/intc-common/intc-common-core/src/main/java/com/intc/common/core/handler/JsonNodeTypeHandler.java @@ -0,0 +1,63 @@ +package com.intc.common.core.handler; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; +import org.apache.ibatis.type.MappedTypes; +import org.postgresql.util.PGobject; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * PostgreSQL JSONB 类型处理器 + * 用于 MyBatis 映射 JsonNode 类型 + * + * @author bot5 + * @date 2026-03-19 + */ +@MappedTypes(JsonNode.class) +public class JsonNodeTypeHandler extends BaseTypeHandler { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, JsonNode parameter, JdbcType jdbcType) throws SQLException { + PGobject pgObject = new PGobject(); + pgObject.setType("jsonb"); + pgObject.setValue(parameter.toString()); + ps.setObject(i, pgObject); + } + + @Override + public JsonNode getNullableResult(ResultSet rs, String columnName) throws SQLException { + String value = rs.getString(columnName); + return parseJson(value); + } + + @Override + public JsonNode getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + String value = rs.getString(columnIndex); + return parseJson(value); + } + + @Override + public JsonNode getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + String value = cs.getString(columnIndex); + return parseJson(value); + } + + private JsonNode parseJson(String value) { + if (value == null || value.isEmpty()) { + return null; + } + try { + return objectMapper.readTree(value); + } catch (Exception e) { + return null; + } + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationPlanController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationPlanController.java deleted file mode 100644 index bea6b88..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationPlanController.java +++ /dev/null @@ -1,145 +0,0 @@ -package com.intc.health.controller; - -import com.intc.common.core.utils.poi.ExcelUtil; -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.HealthMedicationPlan; -import com.intc.health.domain.dto.HealthMedicationPlanDto; -import com.intc.health.domain.vo.HealthMedicationPlanVo; -import com.intc.health.service.IHealthMedicationPlanService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -/** - * 用药计划Controller - * - * @author intc - * @date 2025-03-18 - */ -@Api(tags = "用药计划") -@RestController -@RequestMapping("/medicationPlan") -public class HealthMedicationPlanController extends BaseController -{ - @Resource - private IHealthMedicationPlanService healthMedicationPlanService; - - /** - * 查询用药计划列表 - */ - @ApiOperation(value = "查询用药计划列表", response = HealthMedicationPlanVo.class) - @RequiresPermissions("health:medicationPlan:list") - @GetMapping("/list") - public TableDataInfo list(HealthMedicationPlanDto dto) - { - startPage(); - List list = healthMedicationPlanService.selectHealthMedicationPlanList(dto); - return getDataTable(list); - } - - /** - * 导出用药计划列表 - */ - @ApiOperation(value = "导出用药计划列表") - @RequiresPermissions("health:medicationPlan:export") - @Log(title = "用药计划", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, HealthMedicationPlanDto dto) - { - List list = healthMedicationPlanService.selectHealthMedicationPlanList(dto); - ExcelUtil util = new ExcelUtil(HealthMedicationPlanVo.class); - util.exportExcel(response, list, "用药计划数据"); - } - - /** - * 获取用药计划详细信息 - */ - @ApiOperation(value = "获取用药计划详细信息") - @RequiresPermissions("health:medicationPlan:query") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) - { - return success(healthMedicationPlanService.selectHealthMedicationPlanById(id)); - } - - /** - * 新增用药计划 - */ - @ApiOperation(value = "新增用药计划") - @RequiresPermissions("health:medicationPlan:add") - @Log(title = "用药计划", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody HealthMedicationPlan plan) - { - return toAjax(healthMedicationPlanService.insertHealthMedicationPlan(plan)); - } - - /** - * 修改用药计划 - */ - @ApiOperation(value = "修改用药计划") - @RequiresPermissions("health:medicationPlan:edit") - @Log(title = "用药计划", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody HealthMedicationPlan plan) - { - return toAjax(healthMedicationPlanService.updateHealthMedicationPlan(plan)); - } - - /** - * 删除用药计划 - */ - @ApiOperation(value = "删除用药计划") - @RequiresPermissions("health:medicationPlan:remove") - @Log(title = "用药计划", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable Long[] ids) - { - return toAjax(healthMedicationPlanService.deleteHealthMedicationPlanByIds(ids)); - } - - /** - * 暂停用药计划 - */ - @ApiOperation(value = "暂停用药计划") - @RequiresPermissions("health:medicationPlan:edit") - @Log(title = "用药计划", businessType = BusinessType.UPDATE) - @PutMapping("/pause/{id}") - public AjaxResult pause(@PathVariable Long id) - { - return toAjax(healthMedicationPlanService.pauseHealthMedicationPlan(id)); - } - - /** - * 恢复用药计划 - */ - @ApiOperation(value = "恢复用药计划") - @RequiresPermissions("health:medicationPlan:edit") - @Log(title = "用药计划", businessType = BusinessType.UPDATE) - @PutMapping("/resume/{id}") - public AjaxResult resume(@PathVariable Long id) - { - return toAjax(healthMedicationPlanService.resumeHealthMedicationPlan(id)); - } - - /** - * 结束用药计划 - */ - @ApiOperation(value = "结束用药计划") - @RequiresPermissions("health:medicationPlan:edit") - @Log(title = "用药计划", businessType = BusinessType.UPDATE) - @PutMapping("/end/{id}") - public AjaxResult end(@PathVariable Long id) - { - return toAjax(healthMedicationPlanService.endHealthMedicationPlan(id)); - } -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationRecordController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationRecordController.java deleted file mode 100644 index 6392cd8..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthMedicationRecordController.java +++ /dev/null @@ -1,160 +0,0 @@ -package com.intc.health.controller; - -import com.intc.common.core.utils.poi.ExcelUtil; -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.HealthMedicationRecord; -import com.intc.health.domain.dto.HealthMedicationRecordDto; -import com.intc.health.domain.vo.HealthMedicationRecordVo; -import com.intc.health.service.IHealthMedicationRecordService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import org.springframework.web.bind.annotation.*; - -import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; -import java.util.List; - -/** - * 用药记录Controller - * - * @author intc - * @date 2025-03-18 - */ -@Api(tags = "用药记录") -@RestController -@RequestMapping("/medicationRecord") -public class HealthMedicationRecordController extends BaseController -{ - @Resource - private IHealthMedicationRecordService healthMedicationRecordService; - - /** - * 查询用药记录列表 - */ - @ApiOperation(value = "查询用药记录列表", response = HealthMedicationRecordVo.class) - @RequiresPermissions("health:medicationRecord:list") - @GetMapping("/list") - public TableDataInfo list(HealthMedicationRecordDto dto) - { - startPage(); - List list = healthMedicationRecordService.selectHealthMedicationRecordList(dto); - return getDataTable(list); - } - - /** - * 查询今日用药记录 - */ - @ApiOperation(value = "查询今日用药记录") - @RequiresPermissions("health:medicationRecord:list") - @GetMapping("/today") - public AjaxResult today(@RequestParam(required = false) Long personId) - { - List list = healthMedicationRecordService.getTodayRecords(personId); - return success(list); - } - - /** - * 查询某计划某天的用药记录 - */ - @ApiOperation(value = "查询某计划某天的用药记录") - @RequiresPermissions("health:medicationRecord:list") - @GetMapping("/plan/{planId}/date/{date}") - public AjaxResult getByPlanAndDate(@PathVariable Long planId, @PathVariable String date) - { - List list = healthMedicationRecordService.selectRecordByPlanAndDate(planId, date); - return success(list); - } - - /** - * 导出用药记录列表 - */ - @ApiOperation(value = "导出用药记录列表") - @RequiresPermissions("health:medicationRecord:export") - @Log(title = "用药记录", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, HealthMedicationRecordDto dto) - { - List list = healthMedicationRecordService.selectHealthMedicationRecordList(dto); - ExcelUtil util = new ExcelUtil(HealthMedicationRecordVo.class); - util.exportExcel(response, list, "用药记录数据"); - } - - /** - * 获取用药记录详细信息 - */ - @ApiOperation(value = "获取用药记录详细信息") - @RequiresPermissions("health:medicationRecord:query") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) - { - return success(healthMedicationRecordService.selectHealthMedicationRecordById(id)); - } - - /** - * 新增用药记录(手动记录补服) - */ - @ApiOperation(value = "新增用药记录") - @RequiresPermissions("health:medicationRecord:add") - @Log(title = "用药记录", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody HealthMedicationRecord record) - { - return toAjax(healthMedicationRecordService.insertHealthMedicationRecord(record)); - } - - /** - * 修改用药记录 - */ - @ApiOperation(value = "修改用药记录") - @RequiresPermissions("health:medicationRecord:edit") - @Log(title = "用药记录", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody HealthMedicationRecord record) - { - return toAjax(healthMedicationRecordService.updateHealthMedicationRecord(record)); - } - - /** - * 删除用药记录 - */ - @ApiOperation(value = "删除用药记录") - @RequiresPermissions("health:medicationRecord:remove") - @Log(title = "用药记录", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable Long[] ids) - { - return toAjax(healthMedicationRecordService.deleteHealthMedicationRecordByIds(ids)); - } - - /** - * 服药(标记为已服用) - */ - @ApiOperation(value = "服药(标记为已服用)") - @RequiresPermissions("health:medicationRecord:edit") - @Log(title = "用药记录", businessType = BusinessType.UPDATE) - @PutMapping("/take/{id}") - public AjaxResult take(@PathVariable Long id, - @RequestParam(required = false) Double dosage, - @RequestParam(required = false) String remark) - { - return toAjax(healthMedicationRecordService.takeMedication(id, dosage, remark)); - } - - /** - * 跳过服药 - */ - @ApiOperation(value = "跳过服药") - @RequiresPermissions("health:medicationRecord:edit") - @Log(title = "用药记录", businessType = BusinessType.UPDATE) - @PutMapping("/skip/{id}") - public AjaxResult skip(@PathVariable Long id, - @RequestParam(required = false) String remark) - { - return toAjax(healthMedicationRecordService.skipMedication(id, remark)); - } -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java index 3ea6897..3f02a8d 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java @@ -1,15 +1,16 @@ package com.intc.health.controller; import com.intc.common.core.web.domain.AjaxResult; -import com.intc.health.domain.dto.MedicationAdherenceDto; import com.intc.health.domain.vo.DailyAdherenceVo; import com.intc.health.domain.vo.MedicationAdherenceVo; import com.intc.health.service.IMedicationAdherenceService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; +import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.time.LocalDate; import java.util.List; import java.util.Map; @@ -27,100 +28,55 @@ public class MedicationAdherenceController { @Resource private IMedicationAdherenceService adherenceService; - /** - * 获取总体依从性统计 - */ @GetMapping("/overall") @ApiOperation("获取总体依从性统计") - public AjaxResult getOverallAdherence(MedicationAdherenceDto dto) { - MedicationAdherenceVo vo = adherenceService.getOverallAdherence(dto); + public AjaxResult getOverallAdherence( + @RequestParam(required = false) Long memberId, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) { + MedicationAdherenceVo vo = adherenceService.getOverallAdherence(memberId, startDate, endDate); return AjaxResult.success(vo); } - /** - * 获取每日依从性统计列表(趋势图) - */ @GetMapping("/daily") @ApiOperation("获取每日依从性统计列表") - public AjaxResult getDailyAdherenceList(MedicationAdherenceDto dto) { - List list = adherenceService.getDailyAdherenceList(dto); + public AjaxResult getDailyAdherenceList( + @RequestParam(required = false) Long memberId, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) { + List list = adherenceService.getDailyAdherenceList(memberId, startDate, endDate); return AjaxResult.success(list); } - /** - * 获取日历视图数据 - */ @GetMapping("/calendar") @ApiOperation("获取日历视图数据") public AjaxResult getCalendarData( - @RequestParam(required = false) Long personId, + @RequestParam(required = false) Long memberId, @RequestParam String yearMonth) { - List list = adherenceService.getCalendarData(personId, yearMonth); + List list = adherenceService.getCalendarData(memberId, yearMonth); return AjaxResult.success(list); } - /** - * 获取各时段服药统计 - */ @GetMapping("/timeSlot") @ApiOperation("获取各时段服药统计") - public AjaxResult getTimeSlotAdherence(MedicationAdherenceDto dto) { - Map map = adherenceService.getTimeSlotAdherence(dto); + public AjaxResult getTimeSlotAdherence( + @RequestParam(required = false) Long memberId, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, + @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) { + Map map = adherenceService.getTimeSlotAdherence(memberId, startDate, endDate); return AjaxResult.success(map); } - /** - * 获取各药品依从性统计 - */ - @GetMapping("/medicine") - @ApiOperation("获取各药品依从性统计") - public AjaxResult getMedicineAdherenceList(MedicationAdherenceDto dto) { - List list = adherenceService.getMedicineAdherenceList(dto); - return AjaxResult.success(list); - } - - /** - * 获取各人员依从性统计 - */ - @GetMapping("/person") - @ApiOperation("获取各人员依从性统计") - public AjaxResult getPersonAdherenceList(MedicationAdherenceDto dto) { - List list = adherenceService.getPersonAdherenceList(dto); - return AjaxResult.success(list); - } - - /** - * 获取漏服原因统计 - */ - @GetMapping("/missedReason") - @ApiOperation("获取漏服原因统计") - public AjaxResult getMissedReasonStats(MedicationAdherenceDto dto) { - Map map = adherenceService.getMissedReasonStats(dto); - return AjaxResult.success(map); - } - - /** - * 获取仪表盘概览数据 - */ @GetMapping("/dashboard") @ApiOperation("获取仪表盘概览数据") - public AjaxResult getDashboard(@RequestParam(required = false) Long personId) { - // 获取最近7天的统计数据 - MedicationAdherenceDto dto = new MedicationAdherenceDto(); - dto.setPersonId(personId); - dto.setStartDate(java.time.LocalDate.now().minusDays(7).toString()); - dto.setEndDate(java.time.LocalDate.now().toString()); + public AjaxResult getDashboard(@RequestParam(required = false) Long memberId) { + LocalDate today = LocalDate.now(); + LocalDate weekAgo = today.minusDays(7); Map result = new java.util.HashMap<>(); - - // 总体统计 - result.put("overall", adherenceService.getOverallAdherence(dto)); - - // 每日趋势 - result.put("dailyTrend", adherenceService.getDailyAdherenceList(dto)); - - // 时段统计 - result.put("timeSlot", adherenceService.getTimeSlotAdherence(dto)); + result.put("overall", adherenceService.getOverallAdherence(memberId, weekAgo, today)); + result.put("dailyTrend", adherenceService.getDailyAdherenceList(memberId, weekAgo, today)); + result.put("timeSlot", adherenceService.getTimeSlotAdherence(memberId, weekAgo, today)); return AjaxResult.success(result); } diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationPlanController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationPlanController.java new file mode 100644 index 0000000..2949623 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationPlanController.java @@ -0,0 +1,97 @@ +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.MedicationPlan; +import com.intc.health.domain.dto.MedicationPlanDto; +import com.intc.health.domain.vo.MedicationPlanVo; +import com.intc.health.service.IMedicationPlanService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用药计划Controller + * + * @author bot5 + * @date 2026-03-19 + */ +@RestController +@RequestMapping("/health/medicationPlan") +@Api(tags = "用药计划管理") +public class MedicationPlanController extends BaseController { + + @Resource + private IMedicationPlanService planService; + + @GetMapping("/list") + @ApiOperation("查询用药计划列表") + @RequiresPermissions("health:medicationPlan:list") + public TableDataInfo list(MedicationPlanDto dto) { + startPage(); + List list = planService.selectList(dto); + return getDataTable(list); + } + + @GetMapping("/{id}") + @ApiOperation("查询用药计划详情") + @RequiresPermissions("health:medicationPlan:query") + public AjaxResult getInfo(@PathVariable Long id) { + return success(planService.selectById(id)); + } + + @PostMapping + @ApiOperation("新增用药计划") + @RequiresPermissions("health:medicationPlan:add") + @Log(title = "用药计划", businessType = BusinessType.INSERT) + public AjaxResult add(@RequestBody MedicationPlan plan) { + return toAjax(planService.insert(plan)); + } + + @PutMapping + @ApiOperation("修改用药计划") + @RequiresPermissions("health:medicationPlan:edit") + @Log(title = "用药计划", businessType = BusinessType.UPDATE) + public AjaxResult edit(@RequestBody MedicationPlan plan) { + return toAjax(planService.update(plan)); + } + + @DeleteMapping("/{ids}") + @ApiOperation("删除用药计划") + @RequiresPermissions("health:medicationPlan:remove") + @Log(title = "用药计划", businessType = BusinessType.DELETE) + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(planService.deleteByIds(ids)); + } + + @PutMapping("/pause/{id}") + @ApiOperation("暂停用药计划") + @RequiresPermissions("health:medicationPlan:edit") + @Log(title = "用药计划", businessType = BusinessType.UPDATE) + public AjaxResult pause(@PathVariable Long id) { + return toAjax(planService.pause(id)); + } + + @PutMapping("/resume/{id}") + @ApiOperation("恢复用药计划") + @RequiresPermissions("health:medicationPlan:edit") + @Log(title = "用药计划", businessType = BusinessType.UPDATE) + public AjaxResult resume(@PathVariable Long id) { + return toAjax(planService.resume(id)); + } + + @PutMapping("/end/{id}") + @ApiOperation("结束用药计划") + @RequiresPermissions("health:medicationPlan:edit") + @Log(title = "用药计划", businessType = BusinessType.UPDATE) + public AjaxResult end(@PathVariable Long id) { + return toAjax(planService.end(id)); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java new file mode 100644 index 0000000..e1757e5 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java @@ -0,0 +1,80 @@ +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.dto.MedicationTaskDto; +import com.intc.health.domain.vo.MedicationTaskVo; +import com.intc.health.service.IMedicationTaskService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 服药任务Controller + * + * @author bot5 + * @date 2026-03-19 + */ +@RestController +@RequestMapping("/health/medicationTask") +@Api(tags = "服药任务管理") +public class MedicationTaskController extends BaseController { + + @Resource + private IMedicationTaskService taskService; + + @GetMapping("/list") + @ApiOperation("查询服药任务列表") + @RequiresPermissions("health:medicationTask:list") + public TableDataInfo list(MedicationTaskDto dto) { + startPage(); + List list = taskService.selectList(dto); + return getDataTable(list); + } + + @GetMapping("/{id}") + @ApiOperation("查询服药任务详情") + @RequiresPermissions("health:medicationTask:query") + public AjaxResult getInfo(@PathVariable Long id) { + return success(taskService.selectById(id)); + } + + @DeleteMapping("/{ids}") + @ApiOperation("删除服药任务") + @RequiresPermissions("health:medicationTask:remove") + @Log(title = "服药任务", businessType = BusinessType.DELETE) + public AjaxResult remove(@PathVariable Long[] ids) { + return toAjax(taskService.deleteByIds(ids)); + } + + @PutMapping("/confirm/{id}") + @ApiOperation("确认服药") + @RequiresPermissions("health:medicationTask:edit") + @Log(title = "服药任务", businessType = BusinessType.UPDATE) + public AjaxResult confirm(@PathVariable Long id, @RequestParam(required = false) Integer confirmType) { + return toAjax(taskService.confirm(id, confirmType)); + } + + @PutMapping("/skip/{id}") + @ApiOperation("跳过服药") + @RequiresPermissions("health:medicationTask:edit") + @Log(title = "服药任务", businessType = BusinessType.UPDATE) + public AjaxResult skip(@PathVariable Long id, @RequestParam(required = false) String notes) { + return toAjax(taskService.skip(id, notes)); + } + + @PutMapping("/missed/{id}") + @ApiOperation("标记漏服") + @RequiresPermissions("health:medicationTask:edit") + @Log(title = "服药任务", businessType = BusinessType.UPDATE) + public AjaxResult missed(@PathVariable Long id, @RequestParam(required = false) String notes) { + return toAjax(taskService.markMissed(id, notes)); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java index 6c4006b..6327f99 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java @@ -1,119 +1,52 @@ package com.intc.health.domain; -import com.fasterxml.jackson.annotation.JsonFormat; -import com.intc.common.core.annotation.Excel; -import com.intc.common.core.web.domain.BaseEntity; +import com.intc.common.core.domain.BaseEntity; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import javax.validation.constraints.NotNull; -import java.util.Date; +import lombok.EqualsAndHashCode; /** * 慢性疾病档案对象 chronic_disease_record * * @author bot5 - * @date 2026-03-17 + * @date 2026-03-19 */ -@ApiModel("慢性疾病档案对象") @Data -public class ChronicDiseaseRecord extends BaseEntity -{ - private static final long serialVersionUID = 1L; +@EqualsAndHashCode(callSuper = true) +@ApiModel("慢性疾病档案") +public class ChronicDiseaseRecord extends BaseEntity { - /** 主键 */ + @ApiModelProperty("主键ID") private Long id; - /** 关联成员ID */ - @ApiModelProperty(value = "关联成员ID") - @NotNull(message = "成员不能为空") - @Excel(name = "成员ID") + @ApiModelProperty("关联成员ID") private Long memberId; - /** 成员名称(冗余字段) */ - @Excel(name = "成员名称") - private String memberName; - - /** 关联疾病ID(关联health_diseases表,可选) */ - @ApiModelProperty(value = "关联疾病ID") - @Excel(name = "疾病ID") - private Long diseaseId; - - /** 疾病名称 */ - @ApiModelProperty(value = "疾病名称") - @NotNull(message = "疾病名称不能为空") - @Excel(name = "疾病名称") + @ApiModelProperty("疾病名称") private String diseaseName; - /** 疾病编码(ICD-10标准) */ - @ApiModelProperty(value = "疾病编码(ICD-10标准)") - @Excel(name = "疾病编码") + @ApiModelProperty("疾病编码(ICD-10标准)") private String diseaseCode; - /** 确诊日期 */ - @ApiModelProperty(value = "确诊日期") - @JsonFormat(pattern = "yyyy-MM-dd") - @Excel(name = "确诊日期", width = 30, dateFormat = "yyyy-MM-dd") - private Date diagnosisDate; + @ApiModelProperty("确诊日期") + private String diagnosisDate; - /** 状态:1-稳定 2-需关注 3-急性期 */ - @ApiModelProperty(value = "状态:1-稳定 2-需关注 3-急性期") - @NotNull(message = "状态不能为空") - @Excel(name = "状态", readConverterExp = "1=稳定,2=需关注,3=急性期") + @ApiModelProperty("状态:1-稳定 2-需关注 3-急性期") private Integer diseaseStatus; - /** 主治医生 */ - @ApiModelProperty(value = "主治医生") - @Excel(name = "主治医生") + @ApiModelProperty("主治医生") private String mainDoctor; - /** 就诊医院 */ - @ApiModelProperty(value = "就诊医院") - @Excel(name = "就诊医院") + @ApiModelProperty("就诊医院") private String hospital; - /** 科室 */ - @ApiModelProperty(value = "科室") - @Excel(name = "科室") + @ApiModelProperty("科室") private String department; - /** 备注说明 */ - @ApiModelProperty(value = "备注说明") + @ApiModelProperty("备注说明") private String notes; - /** 是否启用:1-是 0-否 */ - @ApiModelProperty(value = "是否启用:1-是 0-否") - @Excel(name = "是否启用", readConverterExp = "1=是,0=否") - private Integer isActive; - - /** 删除标志(0代表存在 1代表删除) */ - private String delFlag; - - @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) - .append("id", getId()) - .append("memberId", getMemberId()) - .append("memberName", getMemberName()) - .append("diseaseId", getDiseaseId()) - .append("diseaseName", getDiseaseName()) - .append("diseaseCode", getDiseaseCode()) - .append("diagnosisDate", getDiagnosisDate()) - .append("diseaseStatus", getDiseaseStatus()) - .append("mainDoctor", getMainDoctor()) - .append("hospital", getHospital()) - .append("department", getDepartment()) - .append("notes", getNotes()) - .append("isActive", getIsActive()) - .append("createBy", getCreateBy()) - .append("createTime", getCreateTime()) - .append("updateBy", getUpdateBy()) - .append("updateTime", getUpdateTime()) - .append("delFlag", getDelFlag()) - .append("remark", getRemark()) - .toString(); - } + @ApiModelProperty("删除标记:0-正常 1-删除") + private Integer delFlag; } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationPlan.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationPlan.java deleted file mode 100644 index f0cf9af..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationPlan.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.intc.health.domain; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.intc.common.core.annotation.Excel; -import com.intc.common.core.web.domain.BaseEntity; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import javax.validation.constraints.NotNull; -import java.util.Date; - -/** - * 用药计划对象 health_medication_plan - * - * @author intc - * @date 2025-03-18 - */ -@ApiModel("用药计划对象") -@Data -public class HealthMedicationPlan extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** 主键 */ - private Long id; - - /** 人员ID */ - @ApiModelProperty(value="人员ID") - @NotNull(message="人员ID不能为空") - @Excel(name = "人员ID") - private Long personId; - - /** 药品ID */ - @ApiModelProperty(value="药品ID") - @NotNull(message="药品ID不能为空") - @Excel(name = "药品ID") - private Long medicineId; - - /** 入库ID(用于扣减库存) */ - @ApiModelProperty(value="入库ID") - private Long stockInId; - - /** 计划名称 */ - @ApiModelProperty(value="计划名称") - @Excel(name = "计划名称") - private String planName; - - /** 每次剂量 */ - @ApiModelProperty(value="每次剂量") - @NotNull(message="剂量不能为空") - @Excel(name = "每次剂量") - private Double dosage; - - /** 剂量单位 */ - @ApiModelProperty(value="剂量单位") - @Excel(name = "剂量单位") - private String dosageUnit; - - /** 服药频率(每日次数) */ - @ApiModelProperty(value="服药频率") - @NotNull(message="服药频率不能为空") - @Excel(name = "服药频率") - private Integer frequency; - - /** 频率类型(1-每日 2-隔日 3-每周 4-自定义) */ - @ApiModelProperty(value="频率类型") - @Excel(name = "频率类型", readConverterExp = "1=每日,2=隔日,3=每周,4=自定义") - private String frequencyType; - - /** 服药时间点(JSON格式) */ - @ApiModelProperty(value="服药时间点") - private String timePoints; - - /** 周几服药(频率类型为每周时使用,JSON格式如[1,3,5]表示周一三五) */ - @ApiModelProperty(value="周几服药") - private String weekDays; - - /** 开始日期 */ - @ApiModelProperty(value="开始日期") - @NotNull(message="开始日期不能为空") - @JsonFormat(pattern = "yyyy-MM-dd") - @Excel(name = "开始日期", width = 30, dateFormat = "yyyy-MM-dd") - private Date startDate; - - /** 结束日期 */ - @ApiModelProperty(value="结束日期") - @JsonFormat(pattern = "yyyy-MM-dd") - @Excel(name = "结束日期", width = 30, dateFormat = "yyyy-MM-dd") - private Date endDate; - - /** 是否启用提醒(0-否 1-是) */ - @ApiModelProperty(value="是否启用提醒") - @Excel(name = "是否启用提醒", readConverterExp = "0=否,1=是") - private String reminderEnabled; - - /** 提前提醒时间(分钟) */ - @ApiModelProperty(value="提前提醒时间") - @Excel(name = "提前提醒时间(分钟)") - private Integer reminderMinutes; - - /** 状态(1-进行中 2-已结束 3-已暂停) */ - @ApiModelProperty(value="状态") - @Excel(name = "状态", readConverterExp = "1=进行中,2=已结束,3=已暂停") - private String status; - - /** 删除标志(0代表存在 1代表删除) */ - private String delFlag; - - @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) - .append("id", getId()) - .append("personId", getPersonId()) - .append("medicineId", getMedicineId()) - .append("stockInId", getStockInId()) - .append("planName", getPlanName()) - .append("dosage", getDosage()) - .append("dosageUnit", getDosageUnit()) - .append("frequency", getFrequency()) - .append("frequencyType", getFrequencyType()) - .append("timePoints", getTimePoints()) - .append("weekDays", getWeekDays()) - .append("startDate", getStartDate()) - .append("endDate", getEndDate()) - .append("reminderEnabled", getReminderEnabled()) - .append("reminderMinutes", getReminderMinutes()) - .append("status", getStatus()) - .append("createBy", getCreateBy()) - .append("createTime", getCreateTime()) - .append("updateBy", getUpdateBy()) - .append("updateTime", getUpdateTime()) - .append("delFlag", getDelFlag()) - .append("remark", getRemark()) - .toString(); - } -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationRecord.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationRecord.java deleted file mode 100644 index 190036e..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/HealthMedicationRecord.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.intc.health.domain; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.intc.common.core.annotation.Excel; -import com.intc.common.core.web.domain.BaseEntity; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; -import org.apache.commons.lang3.builder.ToStringBuilder; -import org.apache.commons.lang3.builder.ToStringStyle; - -import javax.validation.constraints.NotNull; -import java.util.Date; - -/** - * 用药记录对象 health_medication_record - * - * @author intc - * @date 2025-03-18 - */ -@ApiModel("用药记录对象") -@Data -public class HealthMedicationRecord extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** 主键 */ - private Long id; - - /** 计划ID */ - @ApiModelProperty(value="计划ID") - @NotNull(message="计划ID不能为空") - @Excel(name = "计划ID") - private Long planId; - - /** 人员ID */ - @ApiModelProperty(value="人员ID") - @NotNull(message="人员ID不能为空") - @Excel(name = "人员ID") - private Long personId; - - /** 药品ID */ - @ApiModelProperty(value="药品ID") - @NotNull(message="药品ID不能为空") - @Excel(name = "药品ID") - private Long medicineId; - - /** 计划服药时间 */ - @ApiModelProperty(value="计划服药时间") - @NotNull(message="计划服药时间不能为空") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - @Excel(name = "计划服药时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") - private Date scheduledTime; - - /** 实际服药时间 */ - @ApiModelProperty(value="实际服药时间") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - @Excel(name = "实际服药时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") - private Date actualTime; - - /** 服用剂量 */ - @ApiModelProperty(value="服用剂量") - @Excel(name = "服用剂量") - private Double dosage; - - /** 剂量单位 */ - @ApiModelProperty(value="剂量单位") - @Excel(name = "剂量单位") - private String dosageUnit; - - /** 状态(1-待服用 2-已服用 3-已跳过 4-已过期) */ - @ApiModelProperty(value="状态") - @Excel(name = "状态", readConverterExp = "1=待服用,2=已服用,3=已跳过,4=已过期") - private String status; - - /** 删除标志(0代表存在 1代表删除) */ - private String delFlag; - - @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) - .append("id", getId()) - .append("planId", getPlanId()) - .append("personId", getPersonId()) - .append("medicineId", getMedicineId()) - .append("scheduledTime", getScheduledTime()) - .append("actualTime", getActualTime()) - .append("dosage", getDosage()) - .append("dosageUnit", getDosageUnit()) - .append("status", getStatus()) - .append("createBy", getCreateBy()) - .append("createTime", getCreateTime()) - .append("updateBy", getUpdateBy()) - .append("updateTime", getUpdateTime()) - .append("delFlag", getDelFlag()) - .append("remark", getRemark()) - .toString(); - } -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationPlan.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationPlan.java new file mode 100644 index 0000000..91d7287 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationPlan.java @@ -0,0 +1,83 @@ +package com.intc.health.domain; + +import com.fasterxml.jackson.databind.JsonNode; +import com.intc.common.core.domain.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** + * 用药计划对象 medication_plan + * + * @author bot5 + * @date 2026-03-19 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("用药计划") +public class MedicationPlan extends BaseEntity { + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("关联成员ID") + private Long memberId; + + @ApiModelProperty("关联慢性疾病ID") + private Long chronicDiseaseId; + + @ApiModelProperty("计划名称") + private String planName; + + @ApiModelProperty("关联药品ID") + private Long medicineId; + + @ApiModelProperty("药品名称") + private String medicineName; + + @ApiModelProperty("药品规格") + private String specification; + + @ApiModelProperty("单次剂量") + private BigDecimal dosagePerTime; + + @ApiModelProperty("剂量单位") + private String dosageUnit; + + @ApiModelProperty("频次类型:1-每天 2-每周 3-隔天 4-自定义") + private Integer frequencyType; + + @ApiModelProperty("频次配置(JSON格式)") + private JsonNode frequencyConfig; + + @ApiModelProperty("服药时段配置") + private JsonNode timeSlots; + + @ApiModelProperty("开始日期") + private LocalDate startDate; + + @ApiModelProperty("结束日期") + private LocalDate endDate; + + @ApiModelProperty("是否开启提醒:1-是 0-否") + private Integer remindEnabled; + + @ApiModelProperty("提前提醒分钟数") + private Integer remindAdvanceMin; + + @ApiModelProperty("漏服是否通知家属:1-是 0-否") + private Integer notifyFamily; + + @ApiModelProperty("通知家属成员ID列表") + private JsonNode familyMemberIds; + + @ApiModelProperty("状态:1-执行中 2-已暂停 3-已结束") + private Integer status; + + @ApiModelProperty("删除标记:0-正常 1-删除") + private Integer delFlag; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationTask.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationTask.java new file mode 100644 index 0000000..43a3c73 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationTask.java @@ -0,0 +1,69 @@ +package com.intc.health.domain; + +import com.intc.common.core.domain.BaseEntity; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +/** + * 服药任务对象 medication_task + * + * @author bot5 + * @date 2026-03-19 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@ApiModel("服药任务") +public class MedicationTask extends BaseEntity { + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("关联用药计划ID") + private Long planId; + + @ApiModelProperty("关联成员ID") + private Long memberId; + + @ApiModelProperty("药品名称") + private String medicineName; + + @ApiModelProperty("计划服药日期") + private LocalDate plannedDate; + + @ApiModelProperty("计划服药时间") + private LocalTime plannedTime; + + @ApiModelProperty("计划剂量") + private BigDecimal plannedDosage; + + @ApiModelProperty("实际服药时间") + private LocalDateTime actualTime; + + @ApiModelProperty("实际剂量") + private BigDecimal actualDosage; + + @ApiModelProperty("状态:0-待服药 1-已服药 2-漏服 3-跳过") + private Integer status; + + @ApiModelProperty("确认方式:1-用户确认 2-家属代确认 3-系统自动") + private Integer confirmType; + + @ApiModelProperty("备注(如漏服原因)") + private String notes; + + @ApiModelProperty("提醒状态:0-未提醒 1-已提醒 2-已超时提醒") + private Integer remindStatus; + + @ApiModelProperty("提醒时间") + private LocalDateTime remindTime; + + @ApiModelProperty("删除标记:0-正常 1-删除") + private Integer delFlag; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationPlanDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationPlanDto.java deleted file mode 100644 index d9ba52e..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationPlanDto.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.intc.health.domain.dto; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; - -import java.util.Date; - -/** - * 用药计划DTO对象 health_medication_plan - * - * @author intc - * @date 2025-03-18 - */ -@ApiModel("用药计划DTO对象") -@Data -public class HealthMedicationPlanDto -{ - /** 主键 */ - private Long id; - - /** 人员ID */ - @ApiModelProperty(value="人员ID") - private Long personId; - - /** 人员姓名(模糊查询) */ - @ApiModelProperty(value="人员姓名") - private String personName; - - /** 药品ID */ - @ApiModelProperty(value="药品ID") - private Long medicineId; - - /** 计划名称 */ - @ApiModelProperty(value="计划名称") - private String planName; - - /** 频率类型 */ - @ApiModelProperty(value="频率类型") - private String frequencyType; - - /** 状态 */ - @ApiModelProperty(value="状态") - private String status; - - /** 开始日期-起 */ - @ApiModelProperty(value="开始日期-起") - private Date startDateBegin; - - /** 开始日期-止 */ - @ApiModelProperty(value="开始日期-止") - private Date startDateEnd; - - /** 结束日期-起 */ - @ApiModelProperty(value="结束日期-起") - private Date endDateBegin; - - /** 结束日期-止 */ - @ApiModelProperty(value="结束日期-止") - private Date endDateEnd; - - /** 关键字(计划名称、药品名称) */ - @ApiModelProperty(value="关键字") - private String keys; - - /** 分页参数 */ - private Integer pageNum; - private Integer pageSize; -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationRecordDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationRecordDto.java deleted file mode 100644 index ed4706c..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/HealthMedicationRecordDto.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.intc.health.domain.dto; - -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; - -import java.util.Date; - -/** - * 用药记录DTO对象 health_medication_record - * - * @author intc - * @date 2025-03-18 - */ -@ApiModel("用药记录DTO对象") -@Data -public class HealthMedicationRecordDto -{ - /** 主键 */ - private Long id; - - /** 计划ID */ - @ApiModelProperty(value="计划ID") - private Long planId; - - /** 人员ID */ - @ApiModelProperty(value="人员ID") - private Long personId; - - /** 人员姓名 */ - @ApiModelProperty(value="人员姓名") - private String personName; - - /** 药品ID */ - @ApiModelProperty(value="药品ID") - private Long medicineId; - - /** 状态 */ - @ApiModelProperty(value="状态") - private String status; - - /** 计划服药时间-起 */ - @ApiModelProperty(value="计划服药时间-起") - private Date scheduledTimeBegin; - - /** 计划服药时间-止 */ - @ApiModelProperty(value="计划服药时间-止") - private Date scheduledTimeEnd; - - /** 实际服药时间-起 */ - @ApiModelProperty(value="实际服药时间-起") - private Date actualTimeBegin; - - /** 实际服药时间-止 */ - @ApiModelProperty(value="实际服药时间-止") - private Date actualTimeEnd; - - /** 日期(按日期查询某天所有记录) */ - @ApiModelProperty(value="日期") - private Date queryDate; - - /** 分页参数 */ - private Integer pageNum; - private Integer pageSize; -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationPlanDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationPlanDto.java new file mode 100644 index 0000000..f634a5e --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationPlanDto.java @@ -0,0 +1,56 @@ +package com.intc.health.domain.dto; + +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; + +/** + * 用药计划查询DTO + * + * @author bot5 + * @date 2026-03-19 + */ +@Data +@ApiModel("用药计划查询DTO") +public class MedicationPlanDto { + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("关联成员ID") + private Long memberId; + + @ApiModelProperty("关联慢性疾病ID") + private Long chronicDiseaseId; + + @ApiModelProperty("计划名称") + private String planName; + + @ApiModelProperty("关联药品ID") + private Long medicineId; + + @ApiModelProperty("药品名称") + private String medicineName; + + @ApiModelProperty("状态:1-执行中 2-已暂停 3-已结束") + private Integer status; + + @ApiModelProperty("开始日期-起") + private String startDateBegin; + + @ApiModelProperty("开始日期-止") + private String startDateEnd; + + @ApiModelProperty("结束日期-起") + private String endDateBegin; + + @ApiModelProperty("结束日期-止") + private String endDateEnd; + + @ApiModelProperty("关键字搜索") + private String keyword; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationTaskDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationTaskDto.java new file mode 100644 index 0000000..ef9fbbb --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationTaskDto.java @@ -0,0 +1,42 @@ +package com.intc.health.domain.dto; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.time.LocalDate; + +/** + * 服药任务查询DTO + * + * @author bot5 + * @date 2026-03-19 + */ +@Data +@ApiModel("服药任务查询DTO") +public class MedicationTaskDto { + + @ApiModelProperty("关联用药计划ID") + private Long planId; + + @ApiModelProperty("关联成员ID") + private Long memberId; + + @ApiModelProperty("药品名称") + private String medicineName; + + @ApiModelProperty("计划服药日期-起") + private String plannedDateBegin; + + @ApiModelProperty("计划服药日期-止") + private String plannedDateEnd; + + @ApiModelProperty("状态:0-待服药 1-已服药 2-漏服 3-跳过") + private Integer status; + + @ApiModelProperty("查询日期(yyyy-MM-dd)") + private String queryDate; + + @ApiModelProperty("关键字搜索") + private String keyword; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationPlanVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationPlanVo.java deleted file mode 100644 index b3fd978..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationPlanVo.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.intc.health.domain.vo; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.intc.common.core.annotation.Excel; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; - -import java.util.Date; - -/** - * 用药计划VO对象 health_medication_plan - * - * @author intc - * @date 2025-03-18 - */ -@ApiModel("用药计划VO对象") -@Data -public class HealthMedicationPlanVo -{ - /** 主键 */ - private Long id; - - /** 人员ID */ - @Excel(name = "人员ID") - private Long personId; - - /** 人员姓名 */ - @Excel(name = "人员姓名") - private String personName; - - /** 药品ID */ - @Excel(name = "药品ID") - private Long medicineId; - - /** 药品名称 */ - @Excel(name = "药品名称") - private String medicineName; - - /** 药品简称 */ - private String shortName; - - /** 品牌 */ - private String brand; - - /** 包装 */ - private String packaging; - - /** 入库ID */ - private Long stockInId; - - /** 计划名称 */ - @Excel(name = "计划名称") - private String planName; - - /** 每次剂量 */ - @Excel(name = "每次剂量") - private Double dosage; - - /** 剂量单位 */ - @Excel(name = "剂量单位") - private String dosageUnit; - - /** 服药频率 */ - @Excel(name = "服药频率") - private Integer frequency; - - /** 频率类型 */ - @Excel(name = "频率类型") - private String frequencyType; - - /** 服药时间点 */ - private String timePoints; - - /** 周几服药 */ - private String weekDays; - - /** 开始日期 */ - @JsonFormat(pattern = "yyyy-MM-dd") - @Excel(name = "开始日期", width = 30, dateFormat = "yyyy-MM-dd") - private Date startDate; - - /** 结束日期 */ - @JsonFormat(pattern = "yyyy-MM-dd") - @Excel(name = "结束日期", width = 30, dateFormat = "yyyy-MM-dd") - private Date endDate; - - /** 是否启用提醒 */ - @Excel(name = "是否启用提醒") - private String reminderEnabled; - - /** 提前提醒时间 */ - @Excel(name = "提前提醒时间(分钟)") - private Integer reminderMinutes; - - /** 状态 */ - @Excel(name = "状态") - private String status; - - /** 备注 */ - private String remark; - - /** 创建时间 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; - - /** 药品简称-品牌(组合显示) */ - private String medicineDisplayName; - - /** 今日已服药次数 */ - private Integer todayTakenCount; - - /** 今日应服药次数 */ - private Integer todayTotalCount; - - /** 剩余库存 */ - private Double stockLeft; -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationRecordVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationRecordVo.java deleted file mode 100644 index 5fddc71..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/HealthMedicationRecordVo.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.intc.health.domain.vo; - -import com.fasterxml.jackson.annotation.JsonFormat; -import com.intc.common.core.annotation.Excel; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import lombok.Data; - -import java.util.Date; - -/** - * 用药记录VO对象 health_medication_record - * - * @author intc - * @date 2025-03-18 - */ -@ApiModel("用药记录VO对象") -@Data -public class HealthMedicationRecordVo -{ - /** 主键 */ - private Long id; - - /** 计划ID */ - @Excel(name = "计划ID") - private Long planId; - - /** 人员ID */ - @Excel(name = "人员ID") - private Long personId; - - /** 人员姓名 */ - @Excel(name = "人员姓名") - private String personName; - - /** 药品ID */ - @Excel(name = "药品ID") - private Long medicineId; - - /** 药品名称 */ - @Excel(name = "药品名称") - private String medicineName; - - /** 药品简称 */ - private String shortName; - - /** 品牌 */ - private String brand; - - /** 包装 */ - private String packaging; - - /** 计划服药时间 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - @Excel(name = "计划服药时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") - private Date scheduledTime; - - /** 实际服药时间 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - @Excel(name = "实际服药时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss") - private Date actualTime; - - /** 服用剂量 */ - @Excel(name = "服用剂量") - private Double dosage; - - /** 剂量单位 */ - @Excel(name = "剂量单位") - private String dosageUnit; - - /** 状态 */ - @Excel(name = "状态") - private String status; - - /** 备注 */ - private String remark; - - /** 创建时间 */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") - private Date createTime; - - /** 药品简称-品牌(组合显示) */ - private String medicineDisplayName; - - /** 计划名称 */ - private String planName; -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java new file mode 100644 index 0000000..afbfb1a --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java @@ -0,0 +1,93 @@ +package com.intc.health.domain.vo; + +import com.fasterxml.jackson.databind.JsonNode; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + * 用药计划VO + * + * @author bot5 + * @date 2026-03-19 + */ +@Data +@ApiModel("用药计划VO") +public class MedicationPlanVo { + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("关联成员ID") + private Long memberId; + + @ApiModelProperty("成员名称") + private String memberName; + + @ApiModelProperty("关联慢性疾病ID") + private Long chronicDiseaseId; + + @ApiModelProperty("慢性疾病名称") + private String chronicDiseaseName; + + @ApiModelProperty("计划名称") + private String planName; + + @ApiModelProperty("关联药品ID") + private Long medicineId; + + @ApiModelProperty("药品名称") + private String medicineName; + + @ApiModelProperty("药品规格") + private String specification; + + @ApiModelProperty("单次剂量") + private BigDecimal dosagePerTime; + + @ApiModelProperty("剂量单位") + private String dosageUnit; + + @ApiModelProperty("频次类型:1-每天 2-每周 3-隔天 4-自定义") + private Integer frequencyType; + + @ApiModelProperty("频次配置(JSON格式)") + private JsonNode frequencyConfig; + + @ApiModelProperty("服药时段配置") + private JsonNode timeSlots; + + @ApiModelProperty("开始日期") + private LocalDate startDate; + + @ApiModelProperty("结束日期") + private LocalDate endDate; + + @ApiModelProperty("是否开启提醒:1-是 0-否") + private Integer remindEnabled; + + @ApiModelProperty("提前提醒分钟数") + private Integer remindAdvanceMin; + + @ApiModelProperty("漏服是否通知家属:1-是 0-否") + private Integer notifyFamily; + + @ApiModelProperty("通知家属成员ID列表") + private JsonNode familyMemberIds; + + @ApiModelProperty("状态:1-执行中 2-已暂停 3-已结束") + private Integer status; + + @ApiModelProperty("今日任务统计") + private Integer todayTotal; + + @ApiModelProperty("今日已完成") + private Integer todayCompleted; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java new file mode 100644 index 0000000..1f03a8f --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java @@ -0,0 +1,75 @@ +package com.intc.health.domain.vo; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +/** + * 服药任务VO + * + * @author bot5 + * @date 2026-03-19 + */ +@Data +@ApiModel("服药任务VO") +public class MedicationTaskVo { + + @ApiModelProperty("主键ID") + private Long id; + + @ApiModelProperty("关联用药计划ID") + private Long planId; + + @ApiModelProperty("计划名称") + private String planName; + + @ApiModelProperty("关联成员ID") + private Long memberId; + + @ApiModelProperty("成员名称") + private String memberName; + + @ApiModelProperty("药品名称") + private String medicineName; + + @ApiModelProperty("计划服药日期") + private LocalDate plannedDate; + + @ApiModelProperty("计划服药时间") + private LocalTime plannedTime; + + @ApiModelProperty("计划剂量") + private BigDecimal plannedDosage; + + @ApiModelProperty("实际服药时间") + private LocalDateTime actualTime; + + @ApiModelProperty("实际剂量") + private BigDecimal actualDosage; + + @ApiModelProperty("状态:0-待服药 1-已服药 2-漏服 3-跳过") + private Integer status; + + @ApiModelProperty("状态名称") + private String statusName; + + @ApiModelProperty("确认方式:1-用户确认 2-家属代确认 3-系统自动") + private Integer confirmType; + + @ApiModelProperty("备注(如漏服原因)") + private String notes; + + @ApiModelProperty("提醒状态:0-未提醒 1-已提醒 2-已超时提醒") + private Integer remindStatus; + + @ApiModelProperty("提醒时间") + private LocalDateTime remindTime; + + @ApiModelProperty("创建时间") + private LocalDateTime createTime; +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationPlanMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationPlanMapper.java deleted file mode 100644 index aea7726..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationPlanMapper.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.intc.health.mapper; - -import java.util.List; -import com.intc.health.domain.HealthMedicationPlan; -import com.intc.health.domain.dto.HealthMedicationPlanDto; -import com.intc.health.domain.vo.HealthMedicationPlanVo; - -/** - * 用药计划Mapper接口 - * - * @author intc - * @date 2025-03-18 - */ -public interface HealthMedicationPlanMapper -{ - /** - * 查询用药计划 - * - * @param id 用药计划主键 - * @return 用药计划 - */ - public HealthMedicationPlanVo selectHealthMedicationPlanById(Long id); - - /** - * 查询用药计划列表 - * - * @param dto 用药计划 - * @return 用药计划集合 - */ - public List selectHealthMedicationPlanList(HealthMedicationPlanDto dto); - - /** - * 查询进行中的用药计划列表(用于生成用药记录) - * - * @return 用药计划集合 - */ - public List selectActivePlanList(); - - /** - * 新增用药计划 - * - * @param healthMedicationPlan 用药计划 - * @return 结果 - */ - public int insertHealthMedicationPlan(HealthMedicationPlan healthMedicationPlan); - - /** - * 修改用药计划 - * - * @param healthMedicationPlan 用药计划 - * @return 结果 - */ - public int updateHealthMedicationPlan(HealthMedicationPlan healthMedicationPlan); - - /** - * 删除用药计划 - * - * @param id 用药计划主键 - * @return 结果 - */ - public int deleteHealthMedicationPlanById(Long id); - - /** - * 批量删除用药计划 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - public int deleteHealthMedicationPlanByIds(Long[] ids); - - /** - * 逻辑删除用药计划 - * - * @param id 用药计划主键 - * @return 结果 - */ - public int removeHealthMedicationPlanById(Long id); - - /** - * 批量逻辑删除用药计划 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - public int removeHealthMedicationPlanByIds(Long[] ids); -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java deleted file mode 100644 index 5dee335..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/HealthMedicationRecordMapper.java +++ /dev/null @@ -1,182 +0,0 @@ -package com.intc.health.mapper; - -import java.util.List; -import com.intc.health.domain.HealthMedicationRecord; -import com.intc.health.domain.dto.HealthMedicationRecordDto; -import com.intc.health.domain.vo.HealthMedicationRecordVo; -import org.apache.ibatis.annotations.Param; - -/** - * 用药记录Mapper接口 - * - * @author intc - * @date 2025-03-18 - */ -public interface HealthMedicationRecordMapper -{ - /** - * 查询用药记录 - * - * @param id 用药记录主键 - * @return 用药记录 - */ - public HealthMedicationRecordVo selectHealthMedicationRecordById(Long id); - - /** - * 查询用药记录列表 - * - * @param dto 用药记录 - * @return 用药记录集合 - */ - public List selectHealthMedicationRecordList(HealthMedicationRecordDto dto); - - /** - * 查询某计划某天的用药记录 - * - * @param planId 计划ID - * @param date 日期 - * @return 用药记录集合 - */ - public List selectRecordByPlanAndDate(@Param("planId") Long planId, @Param("date") String date); - - /** - * 统计某计划某天已服药次数 - * - * @param planId 计划ID - * @param date 日期 - * @return 次数 - */ - public int countTakenByPlanAndDate(@Param("planId") Long planId, @Param("date") String date); - - /** - * 新增用药记录 - * - * @param record 用药记录 - * @return 结果 - */ - public int insertHealthMedicationRecord(HealthMedicationRecord record); - - /** - * 批量新增用药记录 - * - * @param records 用药记录列表 - * @return 结果 - */ - public int batchInsertHealthMedicationRecord(List records); - - /** - * 修改用药记录 - * - * @param record 用药记录 - * @return 结果 - */ - public int updateHealthMedicationRecord(HealthMedicationRecord record); - - /** - * 删除用药记录 - * - * @param id 用药记录主键 - * @return 结果 - */ - public int deleteHealthMedicationRecordById(Long id); - - /** - * 批量删除用药记录 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - public int deleteHealthMedicationRecordByIds(Long[] ids); - - /** - * 逻辑删除用药记录 - * - * @param id 用药记录主键 - * @return 结果 - */ - public int removeHealthMedicationRecordById(Long id); - - /** - * 批量逻辑删除用药记录 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - public int removeHealthMedicationRecordByIds(Long[] ids); - - /** - * 统计某计划某天的记录数(用于检查是否已生成) - * - * @param planId 计划ID - * @param date 日期 - * @return 记录数 - */ - public int countByPlanAndDate(@Param("planId") Long planId, @Param("date") String date); - - /** - * 标记过期的服药记录(超过24小时未服用) - * - * @param expireThreshold 过期阈值时间 - * @return 更新的记录数 - */ - public int markExpiredRecords(@Param("expireThreshold") java.time.LocalDateTime expireThreshold); - - /** - * 查询待提醒的服药记录 - * - * @param startTime 开始时间 - * @param endTime 结束时间 - * @return 服药记录集合 - */ - public List selectPendingRemindRecords(@Param("startTime") java.time.LocalDateTime startTime, @Param("endTime") java.time.LocalDateTime endTime); - - // ========== 依从性统计相关 ========== - - /** - * 获取总体依从性统计 - * - * @param dto 查询参数 - * @return 统计结果Map - */ - public java.util.Map getAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); - - /** - * 获取每日依从性统计 - * - * @param dto 查询参数 - * @return 每日统计列表 - */ - public java.util.List> getDailyAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); - - /** - * 获取时段依从性统计 - * - * @param dto 查询参数 - * @return 时段统计列表 - */ - public java.util.List> getTimeSlotAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); - - /** - * 获取药品依从性统计 - * - * @param dto 查询参数 - * @return 药品统计列表 - */ - public java.util.List> getMedicineAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); - - /** - * 获取人员依从性统计 - * - * @param dto 查询参数 - * @return 人员统计列表 - */ - public java.util.List> getPersonAdherenceStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); - - /** - * 获取漏服原因统计 - * - * @param dto 查询参数 - * @return 原因统计列表 - */ - public java.util.List> getMissedReasonStats(@Param("dto") com.intc.health.domain.dto.MedicationAdherenceDto dto); -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationPlanMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationPlanMapper.java new file mode 100644 index 0000000..407cd7c --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationPlanMapper.java @@ -0,0 +1,62 @@ +package com.intc.health.mapper; + +import com.intc.health.domain.MedicationPlan; +import com.intc.health.domain.dto.MedicationPlanDto; +import com.intc.health.domain.vo.MedicationPlanVo; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 用药计划Mapper接口 + * + * @author bot5 + * @date 2026-03-19 + */ +public interface MedicationPlanMapper { + + /** + * 查询用药计划 + */ + MedicationPlanVo selectById(Long id); + + /** + * 查询用药计划列表 + */ + List selectList(MedicationPlanDto dto); + + /** + * 查询执行中的用药计划列表(用于生成任务) + */ + List selectActiveList(); + + /** + * 新增用药计划 + */ + int insert(MedicationPlan plan); + + /** + * 修改用药计划 + */ + int update(MedicationPlan plan); + + /** + * 删除用药计划 + */ + int deleteById(Long id); + + /** + * 批量删除用药计划 + */ + int deleteByIds(Long[] ids); + + /** + * 逻辑删除用药计划 + */ + int removeById(Long id); + + /** + * 批量逻辑删除用药计划 + */ + int removeByIds(Long[] ids); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationTaskMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationTaskMapper.java new file mode 100644 index 0000000..cfb54a8 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationTaskMapper.java @@ -0,0 +1,107 @@ +package com.intc.health.mapper; + +import com.intc.health.domain.MedicationTask; +import com.intc.health.domain.dto.MedicationTaskDto; +import com.intc.health.domain.vo.MedicationTaskVo; +import org.apache.ibatis.annotations.Param; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 服药任务Mapper接口 + * + * @author bot5 + * @date 2026-03-19 + */ +public interface MedicationTaskMapper { + + /** + * 查询服药任务 + */ + MedicationTaskVo selectById(Long id); + + /** + * 查询服药任务列表 + */ + List selectList(MedicationTaskDto dto); + + /** + * 新增服药任务 + */ + int insert(MedicationTask task); + + /** + * 批量新增服药任务 + */ + int batchInsert(List tasks); + + /** + * 修改服药任务 + */ + int update(MedicationTask task); + + /** + * 删除服药任务 + */ + int deleteById(Long id); + + /** + * 批量删除服药任务 + */ + int deleteByIds(Long[] ids); + + /** + * 逻辑删除服药任务 + */ + int removeById(Long id); + + /** + * 批量逻辑删除服药任务 + */ + int removeByIds(Long[] ids); + + /** + * 统计某计划某天的任务数 + */ + int countByPlanAndDate(@Param("planId") Long planId, @Param("date") LocalDate date); + + /** + * 统计某计划某天的已服药数 + */ + int countCompletedByPlanAndDate(@Param("planId") Long planId, @Param("date") LocalDate date); + + /** + * 标记过期任务(超过24小时未服药) + */ + int markExpired(@Param("expireThreshold") LocalDateTime threshold); + + /** + * 查询待提醒的任务 + */ + List selectPendingRemind(@Param("startTime") LocalDateTime startTime, @Param("endTime") LocalDateTime endTime); + + // ========== 依从性统计 ========== + + /** + * 获取总体统计 + */ + java.util.Map getOverallStats(@Param("memberId") Long memberId, + @Param("startDate") LocalDate startDate, + @Param("endDate") LocalDate endDate); + + /** + * 获取每日统计 + */ + List> getDailyStats(@Param("memberId") Long memberId, + @Param("startDate") LocalDate startDate, + @Param("endDate") LocalDate endDate); + + /** + * 获取时段统计 + */ + List> getTimeSlotStats(@Param("memberId") Long memberId, + @Param("startDate") LocalDate startDate, + @Param("endDate") LocalDate endDate); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationPlanService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationPlanService.java deleted file mode 100644 index 7c6aef3..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationPlanService.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.intc.health.service; - -import java.util.List; -import com.intc.health.domain.HealthMedicationPlan; -import com.intc.health.domain.dto.HealthMedicationPlanDto; -import com.intc.health.domain.vo.HealthMedicationPlanVo; - -/** - * 用药计划Service接口 - * - * @author intc - * @date 2025-03-18 - */ -public interface IHealthMedicationPlanService -{ - /** - * 查询用药计划 - * - * @param id 用药计划主键 - * @return 用药计划 - */ - public HealthMedicationPlanVo selectHealthMedicationPlanById(Long id); - - /** - * 查询用药计划列表 - * - * @param dto 用药计划 - * @return 用药计划集合 - */ - public List selectHealthMedicationPlanList(HealthMedicationPlanDto dto); - - /** - * 新增用药计划 - * - * @param plan 用药计划 - * @return 结果 - */ - public int insertHealthMedicationPlan(HealthMedicationPlan plan); - - /** - * 修改用药计划 - * - * @param plan 用药计划 - * @return 结果 - */ - public int updateHealthMedicationPlan(HealthMedicationPlan plan); - - /** - * 批量删除用药计划 - * - * @param ids 需要删除的用药计划主键集合 - * @return 结果 - */ - public int deleteHealthMedicationPlanByIds(Long[] ids); - - /** - * 删除用药计划信息 - * - * @param id 用药计划主键 - * @return 结果 - */ - public int deleteHealthMedicationPlanById(Long id); - - /** - * 暂停用药计划 - * - * @param id 用药计划主键 - * @return 结果 - */ - public int pauseHealthMedicationPlan(Long id); - - /** - * 恢复用药计划 - * - * @param id 用药计划主键 - * @return 结果 - */ - public int resumeHealthMedicationPlan(Long id); - - /** - * 结束用药计划 - * - * @param id 用药计划主键 - * @return 结果 - */ - public int endHealthMedicationPlan(Long id); -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationRecordService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationRecordService.java deleted file mode 100644 index 85eff4d..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/IHealthMedicationRecordService.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.intc.health.service; - -import java.util.List; -import com.intc.health.domain.HealthMedicationRecord; -import com.intc.health.domain.dto.HealthMedicationRecordDto; -import com.intc.health.domain.vo.HealthMedicationRecordVo; - -/** - * 用药记录Service接口 - * - * @author intc - * @date 2025-03-18 - */ -public interface IHealthMedicationRecordService -{ - /** - * 查询用药记录 - * - * @param id 用药记录主键 - * @return 用药记录 - */ - public HealthMedicationRecordVo selectHealthMedicationRecordById(Long id); - - /** - * 查询用药记录列表 - * - * @param dto 用药记录 - * @return 用药记录集合 - */ - public List selectHealthMedicationRecordList(HealthMedicationRecordDto dto); - - /** - * 查询某计划某天的用药记录 - * - * @param planId 计划ID - * @param date 日期(yyyy-MM-dd) - * @return 用药记录集合 - */ - public List selectRecordByPlanAndDate(Long planId, String date); - - /** - * 新增用药记录 - * - * @param record 用药记录 - * @return 结果 - */ - public int insertHealthMedicationRecord(HealthMedicationRecord record); - - /** - * 修改用药记录 - * - * @param record 用药记录 - * @return 结果 - */ - public int updateHealthMedicationRecord(HealthMedicationRecord record); - - /** - * 批量删除用药记录 - * - * @param ids 需要删除的用药记录主键集合 - * @return 结果 - */ - public int deleteHealthMedicationRecordByIds(Long[] ids); - - /** - * 删除用药记录信息 - * - * @param id 用药记录主键 - * @return 结果 - */ - public int deleteHealthMedicationRecordById(Long id); - - /** - * 服药(标记为已服用) - * - * @param id 记录ID - * @param dosage 实际服用剂量 - * @param remark 备注 - * @return 结果 - */ - public int takeMedication(Long id, Double dosage, String remark); - - /** - * 跳过服药 - * - * @param id 记录ID - * @param remark 原因 - * @return 结果 - */ - public int skipMedication(Long id, String remark); - - /** - * 获取今日用药记录 - * - * @param personId 人员ID(可选) - * @return 用药记录集合 - */ - public List getTodayRecords(Long personId); - - /** - * 统计某计划某天已服药次数 - * - * @param planId 计划ID - * @param date 日期(yyyy-MM-dd) - * @return 次数 - */ - public int countTakenByPlanAndDate(Long planId, String date); -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationAdherenceService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationAdherenceService.java index 77aaa98..8d4b5e4 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationAdherenceService.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationAdherenceService.java @@ -1,9 +1,9 @@ package com.intc.health.service; -import com.intc.health.domain.dto.MedicationAdherenceDto; import com.intc.health.domain.vo.DailyAdherenceVo; import com.intc.health.domain.vo.MedicationAdherenceVo; +import java.time.LocalDate; import java.util.List; import java.util.Map; @@ -17,58 +17,21 @@ public interface IMedicationAdherenceService { /** * 获取总体依从性统计 - * - * @param dto 查询参数 - * @return 统计结果 */ - MedicationAdherenceVo getOverallAdherence(MedicationAdherenceDto dto); + MedicationAdherenceVo getOverallAdherence(Long memberId, LocalDate startDate, LocalDate endDate); /** - * 获取每日依从性统计列表(用于趋势图) - * - * @param dto 查询参数 - * @return 每日统计列表 + * 获取每日依从性统计列表 */ - List getDailyAdherenceList(MedicationAdherenceDto dto); + List getDailyAdherenceList(Long memberId, LocalDate startDate, LocalDate endDate); /** - * 获取日历视图数据(某月的每日统计) - * - * @param personId 人员ID - * @param yearMonth 年月(yyyy-MM) - * @return 每日统计列表 + * 获取日历视图数据 */ - List getCalendarData(Long personId, String yearMonth); + List getCalendarData(Long memberId, String yearMonth); /** - * 获取各时段服药统计(早中晚) - * - * @param dto 查询参数 - * @return 时段统计Map + * 获取各时段服药统计 */ - Map getTimeSlotAdherence(MedicationAdherenceDto dto); - - /** - * 获取各药品依从性统计 - * - * @param dto 查询参数 - * @return 药品统计列表 - */ - List getMedicineAdherenceList(MedicationAdherenceDto dto); - - /** - * 获取各人员依从性统计(家属视角) - * - * @param dto 查询参数 - * @return 人员统计列表 - */ - List getPersonAdherenceList(MedicationAdherenceDto dto); - - /** - * 获取漏服原因统计 - * - * @param dto 查询参数 - * @return 原因统计Map - */ - Map getMissedReasonStats(MedicationAdherenceDto dto); + Map getTimeSlotAdherence(Long memberId, LocalDate startDate, LocalDate endDate); } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationPlanService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationPlanService.java new file mode 100644 index 0000000..0a5df55 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationPlanService.java @@ -0,0 +1,56 @@ +package com.intc.health.service; + +import com.intc.health.domain.MedicationPlan; +import com.intc.health.domain.dto.MedicationPlanDto; +import com.intc.health.domain.vo.MedicationPlanVo; + +import java.util.List; + +/** + * 用药计划Service接口 + * + * @author bot5 + * @date 2026-03-19 + */ +public interface IMedicationPlanService { + + /** + * 查询用药计划 + */ + MedicationPlanVo selectById(Long id); + + /** + * 查询用药计划列表 + */ + List selectList(MedicationPlanDto dto); + + /** + * 新增用药计划 + */ + int insert(MedicationPlan plan); + + /** + * 修改用药计划 + */ + int update(MedicationPlan plan); + + /** + * 删除用药计划 + */ + int deleteByIds(Long[] ids); + + /** + * 暂停用药计划 + */ + int pause(Long id); + + /** + * 恢复用药计划 + */ + int resume(Long id); + + /** + * 结束用药计划 + */ + int end(Long id); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationTaskService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationTaskService.java new file mode 100644 index 0000000..4354210 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationTaskService.java @@ -0,0 +1,56 @@ +package com.intc.health.service; + +import com.intc.health.domain.MedicationTask; +import com.intc.health.domain.dto.MedicationTaskDto; +import com.intc.health.domain.vo.MedicationTaskVo; + +import java.util.List; + +/** + * 服药任务Service接口 + * + * @author bot5 + * @date 2026-03-19 + */ +public interface IMedicationTaskService { + + /** + * 查询服药任务 + */ + MedicationTaskVo selectById(Long id); + + /** + * 查询服药任务列表 + */ + List selectList(MedicationTaskDto dto); + + /** + * 新增服药任务 + */ + int insert(MedicationTask task); + + /** + * 修改服药任务 + */ + int update(MedicationTask task); + + /** + * 删除服药任务 + */ + int deleteByIds(Long[] ids); + + /** + * 确认服药 + */ + int confirm(Long id, Integer confirmType); + + /** + * 跳过服药 + */ + int skip(Long id, String notes); + + /** + * 标记漏服 + */ + int markMissed(Long id, String notes); +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationPlanServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationPlanServiceImpl.java deleted file mode 100644 index f09c5b3..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationPlanServiceImpl.java +++ /dev/null @@ -1,188 +0,0 @@ -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.HealthMedicationPlan; -import com.intc.health.domain.dto.HealthMedicationPlanDto; -import com.intc.health.domain.vo.HealthMedicationPlanVo; -import com.intc.health.mapper.HealthMedicationPlanMapper; -import com.intc.health.mapper.HealthMedicationRecordMapper; -import com.intc.health.service.IHealthMedicationPlanService; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.List; - -/** - * 用药计划Service业务层处理 - * - * @author intc - * @date 2025-03-18 - */ -@Service -public class HealthMedicationPlanServiceImpl implements IHealthMedicationPlanService -{ - @Resource - private HealthMedicationPlanMapper healthMedicationPlanMapper; - - @Resource - private HealthMedicationRecordMapper healthMedicationRecordMapper; - - /** - * 查询用药计划 - * - * @param id 用药计划主键 - * @return 用药计划 - */ - @Override - public HealthMedicationPlanVo selectHealthMedicationPlanById(Long id) - { - HealthMedicationPlanVo vo = healthMedicationPlanMapper.selectHealthMedicationPlanById(id); - if (vo != null) { - // 设置药品显示名称 - vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); - // 统计今日服药情况 - String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); - int takenCount = healthMedicationRecordMapper.countTakenByPlanAndDate(id, today); - vo.setTodayTakenCount(takenCount); - vo.setTodayTotalCount(vo.getFrequency()); - } - return vo; - } - - /** - * 查询用药计划列表 - * - * @param dto 用药计划 - * @return 用药计划 - */ - @Override - public List selectHealthMedicationPlanList(HealthMedicationPlanDto dto) - { - List list = healthMedicationPlanMapper.selectHealthMedicationPlanList(dto); - String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); - for (HealthMedicationPlanVo vo : list) { - // 设置药品显示名称 - vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); - // 统计今日服药情况 - if ("1".equals(vo.getStatus())) { - int takenCount = healthMedicationRecordMapper.countTakenByPlanAndDate(vo.getId(), today); - vo.setTodayTakenCount(takenCount); - vo.setTodayTotalCount(vo.getFrequency()); - } - } - return list; - } - - /** - * 新增用药计划 - * - * @param plan 用药计划 - * @return 结果 - */ - @Override - public int insertHealthMedicationPlan(HealthMedicationPlan plan) - { - plan.setId(IdWorker.getId()); - plan.setCreateBy(SecurityUtils.getUsername()); - plan.setCreateTime(DateUtils.getNowDate()); - plan.setDelFlag("0"); - // 默认状态为进行中 - if (plan.getStatus() == null) { - plan.setStatus("1"); - } - return healthMedicationPlanMapper.insertHealthMedicationPlan(plan); - } - - /** - * 修改用药计划 - * - * @param plan 用药计划 - * @return 结果 - */ - @Override - public int updateHealthMedicationPlan(HealthMedicationPlan plan) - { - plan.setUpdateBy(SecurityUtils.getUsername()); - plan.setUpdateTime(DateUtils.getNowDate()); - return healthMedicationPlanMapper.updateHealthMedicationPlan(plan); - } - - /** - * 批量删除用药计划 - * - * @param ids 需要删除的用药计划主键 - * @return 结果 - */ - @Override - public int deleteHealthMedicationPlanByIds(Long[] ids) - { - return healthMedicationPlanMapper.removeHealthMedicationPlanByIds(ids); - } - - /** - * 删除用药计划信息 - * - * @param id 用药计划主键 - * @return 结果 - */ - @Override - public int deleteHealthMedicationPlanById(Long id) - { - return healthMedicationPlanMapper.removeHealthMedicationPlanById(id); - } - - /** - * 暂停用药计划 - * - * @param id 用药计划主键 - * @return 结果 - */ - @Override - public int pauseHealthMedicationPlan(Long id) - { - HealthMedicationPlan plan = new HealthMedicationPlan(); - plan.setId(id); - plan.setStatus("3"); // 已暂停 - plan.setUpdateBy(SecurityUtils.getUsername()); - plan.setUpdateTime(DateUtils.getNowDate()); - return healthMedicationPlanMapper.updateHealthMedicationPlan(plan); - } - - /** - * 恢复用药计划 - * - * @param id 用药计划主键 - * @return 结果 - */ - @Override - public int resumeHealthMedicationPlan(Long id) - { - HealthMedicationPlan plan = new HealthMedicationPlan(); - plan.setId(id); - plan.setStatus("1"); // 进行中 - plan.setUpdateBy(SecurityUtils.getUsername()); - plan.setUpdateTime(DateUtils.getNowDate()); - return healthMedicationPlanMapper.updateHealthMedicationPlan(plan); - } - - /** - * 结束用药计划 - * - * @param id 用药计划主键 - * @return 结果 - */ - @Override - public int endHealthMedicationPlan(Long id) - { - HealthMedicationPlan plan = new HealthMedicationPlan(); - plan.setId(id); - plan.setStatus("2"); // 已结束 - plan.setUpdateBy(SecurityUtils.getUsername()); - plan.setUpdateTime(DateUtils.getNowDate()); - return healthMedicationPlanMapper.updateHealthMedicationPlan(plan); - } -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationRecordServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationRecordServiceImpl.java deleted file mode 100644 index 0e7e713..0000000 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/HealthMedicationRecordServiceImpl.java +++ /dev/null @@ -1,214 +0,0 @@ -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.HealthMedicationRecord; -import com.intc.health.domain.dto.HealthMedicationRecordDto; -import com.intc.health.domain.vo.HealthMedicationRecordVo; -import com.intc.health.mapper.HealthMedicationRecordMapper; -import com.intc.health.service.IHealthMedicationRecordService; -import org.springframework.stereotype.Service; - -import javax.annotation.Resource; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.Date; -import java.util.List; - -/** - * 用药记录Service业务层处理 - * - * @author intc - * @date 2025-03-18 - */ -@Service -public class HealthMedicationRecordServiceImpl implements IHealthMedicationRecordService -{ - @Resource - private HealthMedicationRecordMapper healthMedicationRecordMapper; - - /** - * 查询用药记录 - * - * @param id 用药记录主键 - * @return 用药记录 - */ - @Override - public HealthMedicationRecordVo selectHealthMedicationRecordById(Long id) - { - HealthMedicationRecordVo vo = healthMedicationRecordMapper.selectHealthMedicationRecordById(id); - if (vo != null) { - vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); - } - return vo; - } - - /** - * 查询用药记录列表 - * - * @param dto 用药记录 - * @return 用药记录 - */ - @Override - public List selectHealthMedicationRecordList(HealthMedicationRecordDto dto) - { - List list = healthMedicationRecordMapper.selectHealthMedicationRecordList(dto); - for (HealthMedicationRecordVo vo : list) { - vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); - } - return list; - } - - /** - * 查询某计划某天的用药记录 - * - * @param planId 计划ID - * @param date 日期(yyyy-MM-dd) - * @return 用药记录集合 - */ - @Override - public List selectRecordByPlanAndDate(Long planId, String date) - { - List list = healthMedicationRecordMapper.selectRecordByPlanAndDate(planId, date); - for (HealthMedicationRecordVo vo : list) { - vo.setMedicineDisplayName(vo.getShortName() + "-" + vo.getBrand() + "(" + vo.getPackaging() + ")"); - } - return list; - } - - /** - * 新增用药记录 - * - * @param record 用药记录 - * @return 结果 - */ - @Override - public int insertHealthMedicationRecord(HealthMedicationRecord record) - { - record.setId(IdWorker.getId()); - record.setCreateBy(SecurityUtils.getUsername()); - record.setCreateTime(DateUtils.getNowDate()); - record.setDelFlag("0"); - // 默认状态为待服用 - if (record.getStatus() == null) { - record.setStatus("1"); - } - return healthMedicationRecordMapper.insertHealthMedicationRecord(record); - } - - /** - * 修改用药记录 - * - * @param record 用药记录 - * @return 结果 - */ - @Override - public int updateHealthMedicationRecord(HealthMedicationRecord record) - { - record.setUpdateBy(SecurityUtils.getUsername()); - record.setUpdateTime(DateUtils.getNowDate()); - return healthMedicationRecordMapper.updateHealthMedicationRecord(record); - } - - /** - * 批量删除用药记录 - * - * @param ids 需要删除的用药记录主键 - * @return 结果 - */ - @Override - public int deleteHealthMedicationRecordByIds(Long[] ids) - { - return healthMedicationRecordMapper.removeHealthMedicationRecordByIds(ids); - } - - /** - * 删除用药记录信息 - * - * @param id 用药记录主键 - * @return 结果 - */ - @Override - public int deleteHealthMedicationRecordById(Long id) - { - return healthMedicationRecordMapper.removeHealthMedicationRecordById(id); - } - - /** - * 服药(标记为已服用) - * - * @param id 记录ID - * @param dosage 实际服用剂量 - * @param remark 备注 - * @return 结果 - */ - @Override - public int takeMedication(Long id, Double dosage, String remark) - { - HealthMedicationRecord record = new HealthMedicationRecord(); - record.setId(id); - record.setStatus("2"); // 已服用 - record.setActualTime(new Date()); - if (dosage != null) { - record.setDosage(dosage); - } - if (remark != null) { - record.setRemark(remark); - } - record.setUpdateBy(SecurityUtils.getUsername()); - record.setUpdateTime(DateUtils.getNowDate()); - return healthMedicationRecordMapper.updateHealthMedicationRecord(record); - } - - /** - * 跳过服药 - * - * @param id 记录ID - * @param remark 原因 - * @return 结果 - */ - @Override - public int skipMedication(Long id, String remark) - { - HealthMedicationRecord record = new HealthMedicationRecord(); - record.setId(id); - record.setStatus("3"); // 已跳过 - if (remark != null) { - record.setRemark(remark); - } - record.setUpdateBy(SecurityUtils.getUsername()); - record.setUpdateTime(DateUtils.getNowDate()); - return healthMedicationRecordMapper.updateHealthMedicationRecord(record); - } - - /** - * 获取今日用药记录 - * - * @param personId 人员ID(可选) - * @return 用药记录集合 - */ - @Override - public List getTodayRecords(Long personId) - { - HealthMedicationRecordDto dto = new HealthMedicationRecordDto(); - dto.setQueryDate(new Date()); - if (personId != null) { - dto.setPersonId(personId); - } - return selectHealthMedicationRecordList(dto); - } - - /** - * 统计某计划某天已服药次数 - * - * @param planId 计划ID - * @param date 日期(yyyy-MM-dd) - * @return 次数 - */ - @Override - public int countTakenByPlanAndDate(Long planId, String date) - { - return healthMedicationRecordMapper.countTakenByPlanAndDate(planId, date); - } -} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationAdherenceServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationAdherenceServiceImpl.java index e87e31d..e16a7d6 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationAdherenceServiceImpl.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationAdherenceServiceImpl.java @@ -1,10 +1,9 @@ package com.intc.health.service.impl; -import com.intc.health.domain.dto.MedicationAdherenceDto; -import com.intc.health.domain.vo.DailyAdherenceVo; -import com.intc.health.domain.vo.MedicationAdherenceVo; -import com.intc.health.mapper.HealthMedicationRecordMapper; +import com.intc.health.mapper.MedicationTaskMapper; import com.intc.health.service.IMedicationAdherenceService; +import com.intc.health.domain.vo.MedicationAdherenceVo; +import com.intc.health.domain.vo.DailyAdherenceVo; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -17,7 +16,7 @@ import java.time.temporal.ChronoUnit; import java.util.*; /** - * 依从性统计Service业务层处理 + * 依从性统计Service实现 * * @author bot5 * @date 2026-03-19 @@ -26,11 +25,11 @@ import java.util.*; public class MedicationAdherenceServiceImpl implements IMedicationAdherenceService { @Resource - private HealthMedicationRecordMapper recordMapper; + private MedicationTaskMapper taskMapper; @Override - public MedicationAdherenceVo getOverallAdherence(MedicationAdherenceDto dto) { - Map stats = recordMapper.getAdherenceStats(dto); + public MedicationAdherenceVo getOverallAdherence(Long memberId, LocalDate startDate, LocalDate endDate) { + Map stats = taskMapper.getOverallStats(memberId, startDate, endDate); MedicationAdherenceVo vo = new MedicationAdherenceVo(); vo.setTotalTasks(getIntValue(stats, "total_tasks")); @@ -60,17 +59,12 @@ public class MedicationAdherenceServiceImpl implements IMedicationAdherenceServi vo.setOntimeRate(BigDecimal.ZERO); } - vo.setStartDate(dto.getStartDate()); - vo.setEndDate(dto.getEndDate()); - vo.setPersonId(dto.getPersonId()); - vo.setPlanId(dto.getPlanId()); - return vo; } @Override - public List getDailyAdherenceList(MedicationAdherenceDto dto) { - List> dailyStats = recordMapper.getDailyAdherenceStats(dto); + public List getDailyAdherenceList(Long memberId, LocalDate startDate, LocalDate endDate) { + List> dailyStats = taskMapper.getDailyStats(memberId, startDate, endDate); List result = new ArrayList<>(); for (Map stat : dailyStats) { @@ -82,7 +76,6 @@ public class MedicationAdherenceServiceImpl implements IMedicationAdherenceServi vo.setSkippedTasks(getIntValue(stat, "skipped_tasks")); vo.setOntimeTasks(getIntValue(stat, "ontime_tasks")); - // 计算服药率 if (vo.getTotalTasks() > 0) { BigDecimal rate = BigDecimal.valueOf(vo.getCompletedTasks()) .multiply(BigDecimal.valueOf(100)) @@ -92,7 +85,6 @@ public class MedicationAdherenceServiceImpl implements IMedicationAdherenceServi vo.setAdherenceRate(BigDecimal.ZERO); } - // 计算准时率 if (vo.getCompletedTasks() > 0) { BigDecimal rate = BigDecimal.valueOf(vo.getOntimeTasks()) .multiply(BigDecimal.valueOf(100)) @@ -109,20 +101,14 @@ public class MedicationAdherenceServiceImpl implements IMedicationAdherenceServi } @Override - public List getCalendarData(Long personId, String yearMonth) { - // 解析年月 + public List getCalendarData(Long memberId, String yearMonth) { YearMonth ym = YearMonth.parse(yearMonth, DateTimeFormatter.ofPattern("yyyy-MM")); LocalDate startDate = ym.atDay(1); LocalDate endDate = ym.atEndOfMonth(); - MedicationAdherenceDto dto = new MedicationAdherenceDto(); - dto.setPersonId(personId); - dto.setStartDate(startDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); - dto.setEndDate(endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + List dailyList = getDailyAdherenceList(memberId, startDate, endDate); - List dailyList = getDailyAdherenceList(dto); - - // 补全缺失的日期 + // 补全缺失日期 List result = new ArrayList<>(); Map dateMap = new HashMap<>(); for (DailyAdherenceVo vo : dailyList) { @@ -137,7 +123,6 @@ public class MedicationAdherenceServiceImpl implements IMedicationAdherenceServi if (dateMap.containsKey(dateStr)) { result.add(dateMap.get(dateStr)); } else { - // 没有数据的日期补零 DailyAdherenceVo vo = new DailyAdherenceVo(); vo.setDate(dateStr); vo.setTotalTasks(0); @@ -155,14 +140,14 @@ public class MedicationAdherenceServiceImpl implements IMedicationAdherenceServi } @Override - public Map getTimeSlotAdherence(MedicationAdherenceDto dto) { - List> slotStats = recordMapper.getTimeSlotAdherenceStats(dto); + public Map getTimeSlotAdherence(Long memberId, LocalDate startDate, LocalDate endDate) { + List> slotStats = taskMapper.getTimeSlotStats(memberId, startDate, endDate); Map result = new LinkedHashMap<>(); - result.put("morning", new MedicationAdherenceVo()); // 6:00-12:00 - result.put("afternoon", new MedicationAdherenceVo()); // 12:00-18:00 - result.put("evening", new MedicationAdherenceVo()); // 18:00-24:00 - result.put("night", new MedicationAdherenceVo()); // 0:00-6:00 + result.put("morning", new MedicationAdherenceVo()); + result.put("afternoon", new MedicationAdherenceVo()); + result.put("evening", new MedicationAdherenceVo()); + result.put("night", new MedicationAdherenceVo()); for (Map stat : slotStats) { int hour = getIntValue(stat, "hour"); @@ -182,7 +167,6 @@ public class MedicationAdherenceServiceImpl implements IMedicationAdherenceServi vo.setOntimeTasks(vo.getOntimeTasks() + getIntValue(stat, "ontime_tasks")); } - // 计算各时段的服药率 for (Map.Entry entry : result.entrySet()) { MedicationAdherenceVo vo = entry.getValue(); if (vo.getTotalTasks() != null && vo.getTotalTasks() > 0) { @@ -198,124 +182,22 @@ public class MedicationAdherenceServiceImpl implements IMedicationAdherenceServi return result; } - @Override - public List getMedicineAdherenceList(MedicationAdherenceDto dto) { - List> medicineStats = recordMapper.getMedicineAdherenceStats(dto); - - List result = new ArrayList<>(); - for (Map stat : medicineStats) { - MedicationAdherenceVo vo = new MedicationAdherenceVo(); - vo.setTotalTasks(getIntValue(stat, "total_tasks")); - vo.setCompletedTasks(getIntValue(stat, "completed_tasks")); - vo.setMissedTasks(getIntValue(stat, "missed_tasks")); - vo.setOntimeTasks(getIntValue(stat, "ontime_tasks")); - - // 药品信息 - // planId 和 planName 需要从查询结果获取 - - // 计算服药率 - if (vo.getTotalTasks() > 0) { - BigDecimal rate = BigDecimal.valueOf(vo.getCompletedTasks()) - .multiply(BigDecimal.valueOf(100)) - .divide(BigDecimal.valueOf(vo.getTotalTasks()), 2, RoundingMode.HALF_UP); - vo.setAdherenceRate(rate); - } else { - vo.setAdherenceRate(BigDecimal.ZERO); - } - - result.add(vo); - } - - return result; - } - - @Override - public List getPersonAdherenceList(MedicationAdherenceDto dto) { - List> personStats = recordMapper.getPersonAdherenceStats(dto); - - List result = new ArrayList<>(); - for (Map stat : personStats) { - MedicationAdherenceVo vo = new MedicationAdherenceVo(); - vo.setPersonId(getLongValue(stat, "person_id")); - vo.setPersonName(getStringValue(stat, "person_name")); - vo.setTotalTasks(getIntValue(stat, "total_tasks")); - vo.setCompletedTasks(getIntValue(stat, "completed_tasks")); - vo.setMissedTasks(getIntValue(stat, "missed_tasks")); - vo.setOntimeTasks(getIntValue(stat, "ontime_tasks")); - - // 计算服药率 - if (vo.getTotalTasks() > 0) { - BigDecimal rate = BigDecimal.valueOf(vo.getCompletedTasks()) - .multiply(BigDecimal.valueOf(100)) - .divide(BigDecimal.valueOf(vo.getTotalTasks()), 2, RoundingMode.HALF_UP); - vo.setAdherenceRate(rate); - } else { - vo.setAdherenceRate(BigDecimal.ZERO); - } - - result.add(vo); - } - - return result; - } - - @Override - public Map getMissedReasonStats(MedicationAdherenceDto dto) { - List> reasonStats = recordMapper.getMissedReasonStats(dto); - - Map result = new LinkedHashMap<>(); - for (Map stat : reasonStats) { - String reason = getStringValue(stat, "remark"); - if (reason == null || reason.isEmpty()) { - reason = "未填写原因"; - } - int count = getIntValue(stat, "count"); - result.merge(reason, count, Integer::sum); - } - - return result; - } - - // ========== 辅助方法 ========== - private String getTimeSlot(int hour) { - if (hour >= 6 && hour < 12) { - return "morning"; - } else if (hour >= 12 && hour < 18) { - return "afternoon"; - } else if (hour >= 18 && hour < 24) { - return "evening"; - } else { - return "night"; - } + if (hour >= 6 && hour < 12) return "morning"; + if (hour >= 12 && hour < 18) return "afternoon"; + if (hour >= 18 && hour < 24) return "evening"; + return "night"; } private Integer getIntValue(Map map, String key) { - if (map == null || map.get(key) == null) { - return 0; - } + if (map == null || map.get(key) == null) return 0; Object value = map.get(key); - if (value instanceof Number) { - return ((Number) value).intValue(); - } + if (value instanceof Number) return ((Number) value).intValue(); return 0; } - private Long getLongValue(Map map, String key) { - if (map == null || map.get(key) == null) { - return null; - } - Object value = map.get(key); - if (value instanceof Number) { - return ((Number) value).longValue(); - } - return null; - } - private String getStringValue(Map map, String key) { - if (map == null || map.get(key) == null) { - return null; - } + if (map == null || map.get(key) == null) return null; return map.get(key).toString(); } } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java new file mode 100644 index 0000000..e05e7b1 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java @@ -0,0 +1,94 @@ +package com.intc.health.service.impl; + +import com.intc.common.core.utils.DateUtils; +import com.intc.common.security.utils.SecurityUtils; +import com.intc.health.domain.MedicationPlan; +import com.intc.health.domain.dto.MedicationPlanDto; +import com.intc.health.domain.vo.MedicationPlanVo; +import com.intc.health.mapper.MedicationPlanMapper; +import com.intc.health.service.IMedicationPlanService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 用药计划Service实现 + * + * @author bot5 + * @date 2026-03-19 + */ +@Service +public class MedicationPlanServiceImpl implements IMedicationPlanService { + + @Resource + private MedicationPlanMapper planMapper; + + @Override + public MedicationPlanVo selectById(Long id) { + MedicationPlanVo vo = planMapper.selectById(id); + if (vo != null) { + // 统计今日任务情况 + // TODO: 添加今日任务统计 + } + return vo; + } + + @Override + public List selectList(MedicationPlanDto dto) { + List list = planMapper.selectList(dto); + // TODO: 可以添加今日任务统计 + return list; + } + + @Override + public int insert(MedicationPlan plan) { + plan.setStatus(1); // 默认执行中 + plan.setDelFlag(0); + plan.setCreateBy(SecurityUtils.getUsername()); + plan.setCreateTime(DateUtils.getNowDate()); + return planMapper.insert(plan); + } + + @Override + public int update(MedicationPlan plan) { + plan.setUpdateBy(SecurityUtils.getUsername()); + plan.setUpdateTime(DateUtils.getNowDate()); + return planMapper.update(plan); + } + + @Override + public int deleteByIds(Long[] ids) { + return planMapper.removeByIds(ids); + } + + @Override + public int pause(Long id) { + MedicationPlan plan = new MedicationPlan(); + plan.setId(id); + plan.setStatus(2); // 已暂停 + plan.setUpdateBy(SecurityUtils.getUsername()); + plan.setUpdateTime(DateUtils.getNowDate()); + return planMapper.update(plan); + } + + @Override + public int resume(Long id) { + MedicationPlan plan = new MedicationPlan(); + plan.setId(id); + plan.setStatus(1); // 执行中 + plan.setUpdateBy(SecurityUtils.getUsername()); + plan.setUpdateTime(DateUtils.getNowDate()); + return planMapper.update(plan); + } + + @Override + public int end(Long id) { + MedicationPlan plan = new MedicationPlan(); + plan.setId(id); + plan.setStatus(3); // 已结束 + plan.setUpdateBy(SecurityUtils.getUsername()); + plan.setUpdateTime(DateUtils.getNowDate()); + return planMapper.update(plan); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationTaskServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationTaskServiceImpl.java new file mode 100644 index 0000000..ce00e2b --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationTaskServiceImpl.java @@ -0,0 +1,93 @@ +package com.intc.health.service.impl; + +import com.intc.common.core.utils.DateUtils; +import com.intc.common.security.utils.SecurityUtils; +import com.intc.health.domain.MedicationTask; +import com.intc.health.domain.dto.MedicationTaskDto; +import com.intc.health.domain.vo.MedicationTaskVo; +import com.intc.health.mapper.MedicationTaskMapper; +import com.intc.health.service.IMedicationTaskService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 服药任务Service实现 + * + * @author bot5 + * @date 2026-03-19 + */ +@Service +public class MedicationTaskServiceImpl implements IMedicationTaskService { + + @Resource + private MedicationTaskMapper taskMapper; + + @Override + public MedicationTaskVo selectById(Long id) { + return taskMapper.selectById(id); + } + + @Override + public List selectList(MedicationTaskDto dto) { + return taskMapper.selectList(dto); + } + + @Override + public int insert(MedicationTask task) { + task.setStatus(0); // 待服药 + task.setRemindStatus(0); // 未提醒 + task.setDelFlag(0); + task.setCreateBy(SecurityUtils.getUsername()); + task.setCreateTime(DateUtils.getNowDate()); + return taskMapper.insert(task); + } + + @Override + public int update(MedicationTask task) { + task.setUpdateBy(SecurityUtils.getUsername()); + task.setUpdateTime(DateUtils.getNowDate()); + return taskMapper.update(task); + } + + @Override + public int deleteByIds(Long[] ids) { + return taskMapper.removeByIds(ids); + } + + @Override + public int confirm(Long id, Integer confirmType) { + MedicationTask task = new MedicationTask(); + task.setId(id); + task.setStatus(1); // 已服药 + task.setConfirmType(confirmType != null ? confirmType : 1); + task.setActualTime(LocalDateTime.now()); + task.setUpdateBy(SecurityUtils.getUsername()); + task.setUpdateTime(DateUtils.getNowDate()); + return taskMapper.update(task); + } + + @Override + public int skip(Long id, String notes) { + MedicationTask task = new MedicationTask(); + task.setId(id); + task.setStatus(3); // 跳过 + task.setNotes(notes); + task.setUpdateBy(SecurityUtils.getUsername()); + task.setUpdateTime(DateUtils.getNowDate()); + return taskMapper.update(task); + } + + @Override + public int markMissed(Long id, String notes) { + MedicationTask task = new MedicationTask(); + task.setId(id); + task.setStatus(2); // 漏服 + task.setNotes(notes); + task.setUpdateBy(SecurityUtils.getUsername()); + task.setUpdateTime(DateUtils.getNowDate()); + return taskMapper.update(task); + } +} \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java index 56864e0..616bbc3 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java @@ -1,18 +1,19 @@ package com.intc.health.task; -import com.intc.health.domain.vo.HealthMedicationRecordVo; -import com.intc.health.mapper.HealthMedicationRecordMapper; +import com.intc.health.domain.vo.MedicationTaskVo; +import com.intc.health.mapper.MedicationTaskMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.List; /** * 用药提醒定时器 - * 用于扫描待提醒的服药任务并发送提醒 * * @author bot5 * @date 2026-03-19 @@ -23,131 +24,93 @@ public class MedicationRemindJob { private static final Logger log = LoggerFactory.getLogger(MedicationRemindJob.class); @Resource - private HealthMedicationRecordMapper recordMapper; - - // TODO: 注入消息推送服务,后续实现 - // @Resource - // private MessagePushService messagePushService; + private MedicationTaskMapper taskMapper; /** - * 扫描并发送服药提醒 + * 扫描并发送提醒 * 定时任务配置:每分钟执行 - * 调用方式:medicationRemindJob.scanAndSendReminders */ public void scanAndSendReminders() { log.debug("========== 开始扫描服药提醒 =========="); LocalDateTime now = LocalDateTime.now(); - // 扫描未来1分钟内的待服药记录 - LocalDateTime startTime = now.plusMinutes(-1); + // 扫描未来1分钟内的待服药任务 + LocalDateTime startTime = now.minusMinutes(1); LocalDateTime endTime = now.plusMinutes(1); - List pendingRecords = recordMapper.selectPendingRemindRecords(startTime, endTime); + List pendingTasks = taskMapper.selectPendingRemind(startTime, endTime); - if (pendingRecords == null || pendingRecords.isEmpty()) { - log.debug("没有需要提醒的服药记录"); + if (pendingTasks == null || pendingTasks.isEmpty()) { return; } - log.info("发现 {} 条待提醒的服药记录", pendingRecords.size()); + log.info("发现 {} 条待提醒的服药任务", pendingTasks.size()); - for (HealthMedicationRecordVo record : pendingRecords) { + for (MedicationTaskVo task : pendingTasks) { try { - sendReminder(record); + sendReminder(task); } catch (Exception e) { - log.error("发送服药提醒失败,记录ID: {}, 错误: {}", record.getId(), e.getMessage(), e); + log.error("发送提醒失败,任务ID: {}", task.getId(), e); } } - - log.debug("========== 服药提醒扫描完成 =========="); } /** - * 发送服药提醒 - * - * @param record 服药记录 + * 发送提醒 */ - private void sendReminder(HealthMedicationRecordVo record) { - log.info("发送服药提醒: 人员={}, 药品={}, 计划时间={}", - record.getPersonName(), - record.getMedicineName(), - record.getScheduledTime()); + private void sendReminder(MedicationTaskVo task) { + log.info("发送提醒: 成员={}, 药品={}, 计划时间={} {}", + task.getMemberName(), task.getMedicineName(), + task.getPlannedDate(), task.getPlannedTime()); - // TODO: 实现消息推送逻辑 + // TODO: 实现消息推送 // 1. 查询用户的提醒设置 - // 2. 根据设置选择推送渠道(APP推送/微信/短信) + // 2. 根据设置选择推送渠道 // 3. 发送推送消息 // 4. 记录提醒日志 - - // 暂时只打印日志 - String message = String.format("【服药提醒】%s,请按时服用 %s,剂量:%s%s", - record.getPersonName(), - record.getMedicineName(), - record.getDosage() != null ? record.getDosage() : "", - record.getDosageUnit() != null ? record.getDosageUnit() : ""); - - log.info("推送消息: {}", message); - - // TODO: 调用消息推送服务 - // messagePushService.push(record.getPersonId(), message); } /** - * 扫描超时未服药记录并发送二次提醒 + * 扫描超时未服药任务 * 定时任务配置:每5分钟执行 - * 调用方式:medicationRemindJob.scanOverdueRecords */ public void scanOverdueRecords() { - log.debug("========== 开始扫描超时未服药记录 =========="); + log.debug("========== 开始扫描超时未服药任务 =========="); LocalDateTime now = LocalDateTime.now(); - // 扫描超过计划时间30分钟仍未服药的记录 + // 扫描超过计划时间30分钟仍未服药的任务 LocalDateTime overdueThreshold = now.minusMinutes(30); - // 查询超时的待服药记录 - List overdueRecords = recordMapper.selectPendingRemindRecords( - overdueThreshold.minusMinutes(5), // 查询5分钟内超时的 - overdueThreshold - ); + LocalDateTime startTime = overdueThreshold.minusMinutes(5); + LocalDateTime endTime = overdueThreshold; - if (overdueRecords == null || overdueRecords.isEmpty()) { - log.debug("没有超时未服药记录"); + List overdueTasks = taskMapper.selectPendingRemind(startTime, endTime); + + if (overdueTasks == null || overdueTasks.isEmpty()) { return; } - log.info("发现 {} 条超时未服药记录", overdueRecords.size()); + log.info("发现 {} 条超时未服药任务", overdueTasks.size()); - for (HealthMedicationRecordVo record : overdueRecords) { + for (MedicationTaskVo task : overdueTasks) { try { - sendOverdueReminder(record); + sendOverdueReminder(task); } catch (Exception e) { - log.error("发送超时提醒失败,记录ID: {}, 错误: {}", record.getId(), e.getMessage(), e); + log.error("发送超时提醒失败,任务ID: {}", task.getId(), e); } } - - log.debug("========== 超时未服药扫描完成 =========="); } /** - * 发送超时提醒(二次提醒/通知家属) - * - * @param record 服药记录 + * 发送超时提醒 */ - private void sendOverdueReminder(HealthMedicationRecordVo record) { - log.warn("超时未服药: 人员={}, 药品={}, 计划时间={}", - record.getPersonName(), - record.getMedicineName(), - record.getScheduledTime()); + private void sendOverdueReminder(MedicationTaskVo task) { + log.warn("超时未服药: 成员={}, 药品={}, 计划时间={} {}", + task.getMemberName(), task.getMedicineName(), + task.getPlannedDate(), task.getPlannedTime()); // TODO: 实现超时提醒逻辑 - // 1. 发送二次提醒给用户 - // 2. 如果配置了家属通知,同时通知家属 - // 3. 记录提醒日志 - - String message = String.format("【漏服提醒】%s 未按时服用 %s,请及时处理", - record.getPersonName(), - record.getMedicineName()); - - log.info("推送超时消息: {}", message); + // 1. 发送二次提醒 + // 2. 如果配置了家属通知,通知家属 } } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java index 6194b4c..eeeb79f 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java @@ -1,30 +1,28 @@ package com.intc.health.task; -import com.alibaba.fastjson2.JSON; -import com.alibaba.fastjson2.JSONArray; -import com.intc.common.core.utils.IdWorker; -import com.intc.health.domain.HealthMedicationRecord; -import com.intc.health.domain.vo.HealthMedicationPlanVo; -import com.intc.health.mapper.HealthMedicationPlanMapper; -import com.intc.health.mapper.HealthMedicationRecordMapper; +import com.fasterxml.jackson.databind.JsonNode; +import com.intc.common.core.utils.DateUtils; +import com.intc.health.domain.MedicationTask; +import com.intc.health.domain.vo.MedicationPlanVo; +import com.intc.health.mapper.MedicationPlanMapper; +import com.intc.health.mapper.MedicationTaskMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.math.BigDecimal; import java.time.DayOfWeek; import java.time.LocalDate; -import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** - * 用药任务定时器 - * 用于每日自动生成服药记录 + * 服药任务生成定时器 + * 按文档规范实现 * * @author bot5 * @date 2026-03-19 @@ -35,15 +33,14 @@ public class MedicationTaskJob { private static final Logger log = LoggerFactory.getLogger(MedicationTaskJob.class); @Resource - private HealthMedicationPlanMapper planMapper; + private MedicationPlanMapper planMapper; @Resource - private HealthMedicationRecordMapper recordMapper; + private MedicationTaskMapper taskMapper; /** * 每日生成服药任务 * 定时任务配置:每日 00:05 执行 - * 调用方式:medicationTaskJob.generateDailyTasks */ public void generateDailyTasks() { log.info("========== 开始生成每日服药任务 =========="); @@ -54,47 +51,39 @@ public class MedicationTaskJob { /** * 生成指定日期的服药任务 - * 可用于补生成历史任务 - * - * @param date 日期 - * @return 生成的记录数 */ public int generateTasksForDate(LocalDate date) { int generatedCount = 0; - // 查询所有进行中的计划 - List activePlans = planMapper.selectActivePlanList(); + // 查询所有执行中的计划 + List activePlans = planMapper.selectActiveList(); if (activePlans == null || activePlans.isEmpty()) { - log.info("没有进行中的用药计划"); + log.info("没有执行中的用药计划"); return 0; } - String dateStr = date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); - - for (HealthMedicationPlanVo plan : activePlans) { + for (MedicationPlanVo plan : activePlans) { try { // 检查该计划当天是否需要服药 if (!shouldTakeMedicineOnDate(plan, date)) { - log.debug("计划 {} 在 {} 不需要服药", plan.getPlanName(), dateStr); continue; } - // 检查该计划当天是否已生成过记录 - int existCount = recordMapper.countByPlanAndDate(plan.getId(), dateStr); + // 检查是否已生成过任务 + int existCount = taskMapper.countByPlanAndDate(plan.getId(), date); if (existCount > 0) { - log.debug("计划 {} 在 {} 已有 {} 条记录,跳过", plan.getPlanName(), dateStr, existCount); continue; } - // 生成当天的服药记录 - List records = generateRecordsForPlan(plan, date); - if (!records.isEmpty()) { - recordMapper.batchInsertHealthMedicationRecord(records); - generatedCount += records.size(); - log.info("计划 {} 在 {} 生成了 {} 条服药记录", plan.getPlanName(), dateStr, records.size()); + // 生成任务 + List tasks = generateTasksForPlan(plan, date); + if (!tasks.isEmpty()) { + taskMapper.batchInsert(tasks); + generatedCount += tasks.size(); + log.info("计划 {} 在 {} 生成了 {} 条任务", plan.getPlanName(), date, tasks.size()); } } catch (Exception e) { - log.error("生成计划 {} 的服药记录失败: {}", plan.getId(), e.getMessage(), e); + log.error("生成计划 {} 的任务失败: {}", plan.getId(), e.getMessage(), e); } } @@ -103,39 +92,30 @@ public class MedicationTaskJob { /** * 判断某计划在指定日期是否需要服药 - * - * @param plan 用药计划 - * @param date 日期 - * @return true-需要服药,false-不需要 */ - private boolean shouldTakeMedicineOnDate(HealthMedicationPlanVo plan, LocalDate date) { - // 检查是否在计划日期范围内 - LocalDate startDate = plan.getStartDate() != null ? - plan.getStartDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate() : null; - LocalDate endDate = plan.getEndDate() != null ? - plan.getEndDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate() : null; - - if (startDate != null && date.isBefore(startDate)) { + private boolean shouldTakeMedicineOnDate(MedicationPlanVo plan, LocalDate date) { + // 检查日期范围 + if (plan.getStartDate() != null && date.isBefore(plan.getStartDate())) { return false; } - if (endDate != null && date.isAfter(endDate)) { + if (plan.getEndDate() != null && date.isAfter(plan.getEndDate())) { return false; } - // 根据频率类型判断 - String frequencyType = plan.getFrequencyType(); + // 根据频次类型判断 + Integer frequencyType = plan.getFrequencyType(); if (frequencyType == null) { - frequencyType = "1"; // 默认每日 + frequencyType = 1; } switch (frequencyType) { - case "1": // 每日 + case 1: // 每天 return true; - case "2": // 隔日 - return shouldTakeOnAlternateDay(plan, date); - case "3": // 每周 + case 2: // 每周 return shouldTakeOnWeekly(plan, date); - case "4": // 自定义 + case 3: // 隔天 + return shouldTakeOnAlternate(plan, date); + case 4: // 自定义 return shouldTakeOnCustom(plan, date); default: return true; @@ -143,191 +123,130 @@ public class MedicationTaskJob { } /** - * 判断隔日服药 + * 每周服药判断 */ - private boolean shouldTakeOnAlternateDay(HealthMedicationPlanVo plan, LocalDate date) { - LocalDate startDate = plan.getStartDate() != null ? - plan.getStartDate().toInstant().atZone(java.time.ZoneId.systemDefault()).toLocalDate() : date; - long daysBetween = ChronoUnit.DAYS.between(startDate, date); - return daysBetween % 2 == 0; - } - - /** - * 判断每周服药 - */ - private boolean shouldTakeOnWeekly(HealthMedicationPlanVo plan, LocalDate date) { - String weekDays = plan.getWeekDays(); - if (weekDays == null || weekDays.isEmpty()) { + private boolean shouldTakeOnWeekly(MedicationPlanVo plan, LocalDate date) { + JsonNode config = plan.getFrequencyConfig(); + if (config == null || !config.has("days")) { return true; } - try { - // weekDays 格式为 JSON 数组,如 [1,3,5] 表示周一三五 - JSONArray daysArray = JSON.parseArray(weekDays); - DayOfWeek dayOfWeek = date.getDayOfWeek(); - int dayValue = dayOfWeek.getValue(); // 1=周一, 7=周日 + JsonNode daysNode = config.get("days"); + if (!daysNode.isArray()) { + return true; + } - for (int i = 0; i < daysArray.size(); i++) { - if (daysArray.getInteger(i) == dayValue) { - return true; - } + DayOfWeek dayOfWeek = date.getDayOfWeek(); + int dayValue = dayOfWeek.getValue(); // 1=周一, 7=周日 + + for (JsonNode day : daysNode) { + if (day.asInt() == dayValue) { + return true; } - return false; - } catch (Exception e) { - log.error("解析周几配置失败: {}", weekDays, e); - return true; } + return false; } /** - * 判断自定义频率服药 - * 暂时默认返回 true,后续可根据具体需求扩展 + * 隔天服药判断 */ - private boolean shouldTakeOnCustom(HealthMedicationPlanVo plan, LocalDate date) { - // 自定义频率可以根据 remark 或其他字段配置 - // 暂时默认每日都服药 + private boolean shouldTakeOnAlternate(MedicationPlanVo plan, LocalDate date) { + LocalDate startDate = plan.getStartDate(); + if (startDate == null) { + startDate = date; + } + + JsonNode config = plan.getFrequencyConfig(); + int intervalDays = 2; // 默认隔天 + if (config != null && config.has("interval_days")) { + intervalDays = config.get("interval_days").asInt(2); + } + + long daysBetween = ChronoUnit.DAYS.between(startDate, date); + return daysBetween % intervalDays == 0; + } + + /** + * 自定义频次判断 + */ + private boolean shouldTakeOnCustom(MedicationPlanVo plan, LocalDate date) { + // 自定义频次,暂时默认返回 true return true; } /** - * 为某个计划生成指定日期的服药记录 - * - * @param plan 用药计划 - * @param date 日期 - * @return 服药记录列表 + * 为某个计划生成指定日期的任务 */ - private List generateRecordsForPlan(HealthMedicationPlanVo plan, LocalDate date) { - List records = new ArrayList<>(); + private List generateTasksForPlan(MedicationPlanVo plan, LocalDate date) { + List tasks = new ArrayList<>(); - // 获取服药时间点 - String timePoints = plan.getTimePoints(); - if (timePoints == null || timePoints.isEmpty()) { - // 如果没有配置时间点,根据频率生成默认时间点 - timePoints = generateDefaultTimePoints(plan.getFrequency()); + JsonNode timeSlots = plan.getTimeSlots(); + if (timeSlots == null || !timeSlots.isArray()) { + // 如果没有配置时段,使用默认时段 + timeSlots = createDefaultTimeSlots(plan); } - try { - JSONArray timePointsArray = JSON.parseArray(timePoints); - LocalDateTime now = LocalDateTime.now(); - - for (int i = 0; i < timePointsArray.size(); i++) { - String timeStr = timePointsArray.getString(i); - LocalTime time = parseTime(timeStr); - - HealthMedicationRecord record = new HealthMedicationRecord(); - record.setId(IdWorker.getId()); - record.setPlanId(plan.getId()); - record.setPersonId(plan.getPersonId()); - record.setMedicineId(plan.getMedicineId()); - record.setScheduledTime(LocalDateTime.of(date, time)); - record.setDosage(plan.getDosage()); - record.setDosageUnit(plan.getDosageUnit()); - record.setStatus("1"); // 待服用 - record.setCreateTime(now); - record.setDelFlag("0"); - - records.add(record); + for (JsonNode slot : timeSlots) { + if (!slot.has("enabled") || !slot.get("enabled").asBoolean(true)) { + continue; } - } catch (Exception e) { - log.error("解析时间点配置失败: {}", timePoints, e); + + String timeStr = slot.has("time") ? slot.get("time").asText() : "08:00"; + LocalTime time = parseTime(timeStr); + + BigDecimal dosage = plan.getDosagePerTime(); + if (slot.has("dosage")) { + dosage = new BigDecimal(slot.get("dosage").asText()); + } + + MedicationTask task = new MedicationTask(); + task.setPlanId(plan.getId()); + task.setMemberId(plan.getMemberId()); + task.setMedicineName(plan.getMedicineName()); + task.setPlannedDate(date); + task.setPlannedTime(time); + task.setPlannedDosage(dosage); + task.setStatus(0); // 待服药 + task.setRemindStatus(0); // 未提醒 + task.setCreateTime(DateUtils.getNowDate()); + + tasks.add(task); } - return records; + return tasks; } /** - * 根据每日次数生成默认时间点 - * - * @param frequency 每日次数 - * @return JSON 格式的时间点数组 + * 创建默认时段配置 */ - private String generateDefaultTimePoints(Integer frequency) { - if (frequency == null || frequency <= 0) { - frequency = 1; + private JsonNode createDefaultTimeSlots(MedicationPlanVo plan) { + // 根据剂量单位推测服药时段 + String json = "[{\"slot_name\":\"早\",\"time\":\"08:00\",\"dosage\":1,\"enabled\":true}]"; + try { + return new com.fasterxml.jackson.databind.ObjectMapper().readTree(json); + } catch (Exception e) { + return null; } - - JSONArray timePoints = new JSONArray(); - switch (frequency) { - case 1: - timePoints.add("08:00"); - break; - case 2: - timePoints.add("08:00"); - timePoints.add("20:00"); - break; - case 3: - timePoints.add("08:00"); - timePoints.add("12:00"); - timePoints.add("20:00"); - break; - case 4: - timePoints.add("08:00"); - timePoints.add("12:00"); - timePoints.add("16:00"); - timePoints.add("20:00"); - break; - default: - // 超过4次,均匀分布在 8:00-22:00 之间 - int startHour = 8; - int endHour = 22; - int interval = (endHour - startHour) / frequency; - for (int i = 0; i < frequency; i++) { - int hour = startHour + i * interval; - timePoints.add(String.format("%02d:00", hour)); - } - } - - return timePoints.toJSONString(); } /** * 解析时间字符串 - * - * @param timeStr 时间字符串,格式如 "08:00" 或 "8:00" - * @return LocalTime */ private LocalTime parseTime(String timeStr) { try { - // 支持多种格式 - String normalized = timeStr.trim(); - if (normalized.length() == 4 && !normalized.contains(":")) { - // "0800" -> "08:00" - normalized = normalized.substring(0, 2) + ":" + normalized.substring(2); - } - - String[] parts = normalized.split(":"); - int hour = Integer.parseInt(parts[0]); - int minute = parts.length > 1 ? Integer.parseInt(parts[1]) : 0; - return LocalTime.of(hour, minute); + return LocalTime.parse(timeStr, DateTimeFormatter.ofPattern("HH:mm")); } catch (Exception e) { - log.warn("解析时间失败: {},使用默认时间 08:00", timeStr); return LocalTime.of(8, 0); } } /** - * 检查并标记过期的服药记录 - * 定时任务配置:每5分钟执行 - * 调用方式:medicationTaskJob.markExpiredRecords + * 标记过期任务 */ public void markExpiredRecords() { - log.info("========== 开始检查过期服药记录 =========="); - LocalDateTime now = LocalDateTime.now(); - // 超过计划时间24小时的记录标记为过期 - LocalDateTime expireThreshold = now.minusHours(24); - - int count = recordMapper.markExpiredRecords(expireThreshold); - log.info("========== 标记过期记录完成,共 {} 条 ==========", count); - } - - /** - * 手动触发生成指定日期的任务(用于测试或补录) - * - * @param dateStr 日期字符串,格式 yyyy-MM-dd - * @return 生成的记录数 - */ - public int generateTasksManually(String dateStr) { - LocalDate date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("yyyy-MM-dd")); - return generateTasksForDate(date); + log.info("========== 开始标记过期服药任务 =========="); + LocalDateTime expireThreshold = LocalDateTime.now().minusHours(24); + int count = taskMapper.markExpired(expireThreshold); + log.info("========== 标记过期任务完成,共 {} 条 ==========", count); } } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationPlanMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationPlanMapper.xml deleted file mode 100644 index ed091c4..0000000 --- a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationPlanMapper.xml +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select - a.id, - a.person_id, - p.name as person_name, - a.medicine_id, - m.name as medicine_name, - m.short_name, - m.brand, - m.packaging, - a.stock_in_id, - a.plan_name, - a.dosage, - a.dosage_unit, - a.frequency, - a.frequency_type, - a.time_points, - a.week_days, - a.start_date, - a.end_date, - a.reminder_enabled, - a.reminder_minutes, - a.status, - a.remark, - a.create_time - from - health_medication_plan a - left join health_person p on a.person_id = p.id - left join health_medicine_basic m on a.medicine_id = m.id - - - - - - - - - - insert into health_medication_plan - - id, - person_id, - medicine_id, - stock_in_id, - plan_name, - dosage, - dosage_unit, - frequency, - frequency_type, - time_points, - week_days, - start_date, - end_date, - reminder_enabled, - reminder_minutes, - status, - create_by, - create_time, - del_flag, - remark, - - - #{id}, - #{personId}, - #{medicineId}, - #{stockInId}, - #{planName}, - #{dosage}, - #{dosageUnit}, - #{frequency}, - #{frequencyType}, - #{timePoints}, - #{weekDays}, - #{startDate}, - #{endDate}, - #{reminderEnabled}, - #{reminderMinutes}, - #{status}, - #{createBy}, - #{createTime}, - #{delFlag}, - #{remark}, - - - - - update health_medication_plan - - person_id = #{personId}, - medicine_id = #{medicineId}, - stock_in_id = #{stockInId}, - plan_name = #{planName}, - dosage = #{dosage}, - dosage_unit = #{dosageUnit}, - frequency = #{frequency}, - frequency_type = #{frequencyType}, - time_points = #{timePoints}, - week_days = #{weekDays}, - start_date = #{startDate}, - end_date = #{endDate}, - reminder_enabled = #{reminderEnabled}, - reminder_minutes = #{reminderMinutes}, - status = #{status}, - update_by = #{updateBy}, - update_time = #{updateTime}, - del_flag = #{delFlag}, - remark = #{remark}, - - where id = #{id} - - - - delete from health_medication_plan where id = #{id} - - - - delete from health_medication_plan where id in - - #{id} - - - - - update health_medication_plan set del_flag='1' where id = #{id} - - - - update health_medication_plan set del_flag='1' where id in - - #{id} - - - \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml deleted file mode 100644 index bdc58a9..0000000 --- a/intc-modules/intc-health/src/main/resources/mapper/health/HealthMedicationRecordMapper.xml +++ /dev/null @@ -1,310 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - select - a.id, - a.plan_id, - a.person_id, - p.name as person_name, - a.medicine_id, - m.name as medicine_name, - m.short_name, - m.brand, - m.packaging, - a.scheduled_time, - a.actual_time, - a.dosage, - a.dosage_unit, - a.status, - a.remark, - a.create_time, - pl.plan_name - from - health_medication_record a - left join health_person p on a.person_id = p.id - left join health_medicine_basic m on a.medicine_id = m.id - left join health_medication_plan pl on a.plan_id = pl.id - - - - - - - - - - - - insert into health_medication_record - - id, - plan_id, - person_id, - medicine_id, - scheduled_time, - actual_time, - dosage, - dosage_unit, - status, - create_by, - create_time, - del_flag, - remark, - - - #{id}, - #{planId}, - #{personId}, - #{medicineId}, - #{scheduledTime}, - #{actualTime}, - #{dosage}, - #{dosageUnit}, - #{status}, - #{createBy}, - #{createTime}, - #{delFlag}, - #{remark}, - - - - - insert into health_medication_record (id, plan_id, person_id, medicine_id, scheduled_time, dosage, dosage_unit, status, create_time, del_flag) - values - - (#{item.id}, #{item.planId}, #{item.personId}, #{item.medicineId}, #{item.scheduledTime}, #{item.dosage}, #{item.dosageUnit}, #{item.status}, #{item.createTime}, '0') - - - - - update health_medication_record - - plan_id = #{planId}, - person_id = #{personId}, - medicine_id = #{medicineId}, - scheduled_time = #{scheduledTime}, - actual_time = #{actualTime}, - dosage = #{dosage}, - dosage_unit = #{dosageUnit}, - status = #{status}, - update_by = #{updateBy}, - update_time = #{updateTime}, - del_flag = #{delFlag}, - remark = #{remark}, - - where id = #{id} - - - - delete from health_medication_record where id = #{id} - - - - delete from health_medication_record where id in - - #{id} - - - - - update health_medication_record set del_flag='1' where id = #{id} - - - - update health_medication_record set del_flag='1' where id in - - #{id} - - - - - - - update health_medication_record - set status = '4', update_time = current_timestamp - where del_flag='0' and status = '1' - and scheduled_time < #{expireThreshold} - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml new file mode 100644 index 0000000..2b194af --- /dev/null +++ b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select a.id, a.member_id, p.name as member_name, a.chronic_disease_id, + c.disease_name as chronic_disease_name, a.plan_name, a.medicine_id, + a.medicine_name, a.specification, a.dosage_per_time, a.dosage_unit, + a.frequency_type, a.frequency_config, a.time_slots, a.start_date, a.end_date, + a.remind_enabled, a.remind_advance_min, a.notify_family, a.family_member_ids, + a.status, a.create_time + from medication_plan a + left join health_person p on a.member_id = p.id + left join chronic_disease_record c on a.chronic_disease_id = c.id + + + + + + + + + + insert into medication_plan ( + member_id, chronic_disease_id, plan_name, medicine_id, medicine_name, + specification, dosage_per_time, dosage_unit, frequency_type, + frequency_config, time_slots, start_date, end_date, + remind_enabled, remind_advance_min, notify_family, family_member_ids, status, + create_by, create_time, remark, del_flag + ) values ( + #{memberId}, #{chronicDiseaseId}, #{planName}, #{medicineId}, #{medicineName}, + #{specification}, #{dosagePerTime}, #{dosageUnit}, #{frequencyType}, + #{frequencyConfig, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, + #{timeSlots, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, + #{startDate}, #{endDate}, + #{remindEnabled}, #{remindAdvanceMin}, #{notifyFamily}, + #{familyMemberIds, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, + #{status}, + #{createBy}, #{createTime}, #{remark}, 0 + ) + + + + update medication_plan + + member_id = #{memberId}, + chronic_disease_id = #{chronicDiseaseId}, + plan_name = #{planName}, + medicine_id = #{medicineId}, + medicine_name = #{medicineName}, + specification = #{specification}, + dosage_per_time = #{dosagePerTime}, + dosage_unit = #{dosageUnit}, + frequency_type = #{frequencyType}, + frequency_config = #{frequencyConfig, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, + time_slots = #{timeSlots, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, + start_date = #{startDate}, + end_date = #{endDate}, + remind_enabled = #{remindEnabled}, + remind_advance_min = #{remindAdvanceMin}, + notify_family = #{notifyFamily}, + family_member_ids = #{familyMemberIds, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, + status = #{status}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from medication_plan where id = #{id} + + + + delete from medication_plan where id in + #{id} + + + + update medication_plan set del_flag = 1 where id = #{id} + + + + update medication_plan set del_flag = 1 where id in + #{id} + + \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml new file mode 100644 index 0000000..2d221e6 --- /dev/null +++ b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + select a.id, a.plan_id, p.plan_name, a.member_id, m.name as member_name, + a.medicine_name, a.planned_date, a.planned_time, a.planned_dosage, + a.actual_time, a.actual_dosage, a.status, a.confirm_type, a.notes, + a.remind_status, a.remind_time, a.create_time + from medication_task a + left join medication_plan p on a.plan_id = p.id + left join health_person m on a.member_id = m.id + + + + + + + + insert into medication_task ( + plan_id, member_id, medicine_name, planned_date, planned_time, + planned_dosage, actual_time, actual_dosage, status, confirm_type, + notes, remind_status, remind_time, create_by, create_time, remark, del_flag + ) values ( + #{planId}, #{memberId}, #{medicineName}, #{plannedDate}, #{plannedTime}, + #{plannedDosage}, #{actualTime}, #{actualDosage}, #{status}, #{confirmType}, + #{notes}, #{remindStatus}, #{remindTime}, #{createBy}, #{createTime}, #{remark}, 0 + ) + + + + insert into medication_task ( + plan_id, member_id, medicine_name, planned_date, planned_time, + planned_dosage, status, remind_status, create_time, del_flag + ) values + + (#{item.planId}, #{item.memberId}, #{item.medicineName}, #{item.plannedDate}, #{item.plannedTime}, + #{item.plannedDosage}, #{item.status}, #{item.remindStatus}, #{item.createTime}, 0) + + + + + update medication_task + + actual_time = #{actualTime}, + actual_dosage = #{actualDosage}, + status = #{status}, + confirm_type = #{confirmType}, + notes = #{notes}, + remind_status = #{remindStatus}, + remind_time = #{remindTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + remark = #{remark}, + + where id = #{id} + + + + delete from medication_task where id = #{id} + + + + delete from medication_task where id in + #{id} + + + + update medication_task set del_flag = 1 where id = #{id} + + + + update medication_task set del_flag = 1 where id in + #{id} + + + + + + + + update medication_task + set status = 2, update_time = current_timestamp + where del_flag = 0 and status = 0 + and (planned_date || ' ' || planned_time)::timestamp < #{expireThreshold} + + + + + + + + + + + + \ No newline at end of file diff --git a/sql/20250319-medication-adherence.sql b/sql/20250319-medication-adherence.sql deleted file mode 100644 index ff539f4..0000000 --- a/sql/20250319-medication-adherence.sql +++ /dev/null @@ -1,53 +0,0 @@ --- ======================================== --- 依从性统计功能 - SQL脚本 --- ======================================== - --- 用药统计菜单 -INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -VALUES ( - nextval('seq_sys_menu'), - '用药统计', - (SELECT menu_id FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1), - 12, - 'medicationStatistic', - 'health/medicationStatistic/index', - NULL, - 1, - 0, - 'C', - '0', - '0', - 'health:medicationStatistic:query', - 'chart', - 'admin', - NOW(), - '用药统计菜单' -); - --- 用药统计按钮权限 -INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -SELECT nextval('seq_sys_menu'), '用药统计查询', m.menu_id, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationStatistic:query', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationStatistic:query'; - --- ======================================== --- 添加依从性统计汇总表(可选,用于预计算性能优化) --- ======================================== -DROP TABLE IF EXISTS health_medication_adherence_stats; -CREATE TABLE health_medication_adherence_stats ( - id BIGINT NOT NULL, - person_id BIGINT NOT NULL, - plan_id BIGINT NULL, - stat_date DATE NOT NULL, - total_tasks INT DEFAULT 0, - completed_tasks INT DEFAULT 0, - missed_tasks INT DEFAULT 0, - skipped_tasks INT DEFAULT 0, - ontime_tasks INT DEFAULT 0, - adherence_rate DECIMAL(5,2) DEFAULT 0.00, - ontime_rate DECIMAL(5,2) DEFAULT 0.00, - create_time DATETIME DEFAULT CURRENT_TIMESTAMP, - update_time DATETIME DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (id) -) ENGINE=InnoDB COMMENT='依从性统计汇总表'; - -CREATE UNIQUE INDEX idx_hmas_person_date ON health_medication_adherence_stats(person_id, stat_date, plan_id); -CREATE INDEX idx_hmas_stat_date ON health_medication_adherence_stats(stat_date); \ No newline at end of file diff --git a/sql/20250319-medication-task-job.sql b/sql/20250319-medication-task-job.sql deleted file mode 100644 index f04ccb9..0000000 --- a/sql/20250319-medication-task-job.sql +++ /dev/null @@ -1,90 +0,0 @@ --- ======================================== --- 用药任务定时任务配置 --- 在 sys_job 表中插入定时任务 --- ======================================== - --- 1. 每日生成服药任务(每日 00:05 执行) -INSERT INTO sys_job (job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) -VALUES ( - nextval('seq_sys_job'), - '每日生成服药任务', - 'DEFAULT', - 'medicationTaskJob.generateDailyTasks', - '0 5 0 * * ?', - '2', - '1', - '0', - 'admin', - NOW(), - '每日凌晨00:05自动生成当天的服药任务' -); - --- 2. 扫描并发送服药提醒(每分钟执行) -INSERT INTO sys_job (job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) -VALUES ( - nextval('seq_sys_job'), - '扫描服药提醒', - 'DEFAULT', - 'medicationRemindJob.scanAndSendReminders', - '0 * * * * ?', - '2', - '1', - '0', - 'admin', - NOW(), - '每分钟扫描待提醒的服药任务并发送提醒' -); - --- 3. 扫描超时未服药记录(每5分钟执行) -INSERT INTO sys_job (job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) -VALUES ( - nextval('seq_sys_job'), - '扫描超时未服药', - 'DEFAULT', - 'medicationRemindJob.scanOverdueRecords', - '0 */5 * * * ?', - '2', - '1', - '0', - 'admin', - NOW(), - '每5分钟扫描超时未服药的记录并发送提醒' -); - --- 4. 标记过期服药记录(每小时执行) -INSERT INTO sys_job (job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) -VALUES ( - nextval('seq_sys_job'), - '标记过期服药记录', - 'DEFAULT', - 'medicationTaskJob.markExpiredRecords', - '0 0 * * * ?', - '2', - '1', - '0', - 'admin', - NOW(), - '每小时检查并标记过期的服药记录' -); - --- ======================================== --- 提醒日志表(可选,用于记录提醒历史) --- ======================================== -DROP TABLE IF EXISTS health_medication_remind_log; -CREATE TABLE health_medication_remind_log ( - id BIGINT NOT NULL, - record_id BIGINT NOT NULL, - plan_id BIGINT NOT NULL, - person_id BIGINT NOT NULL, - remind_type CHAR(1) DEFAULT '1' COMMENT '提醒类型:1-按时提醒 2-超时提醒 3-漏服通知家属', - remind_time DATETIME NOT NULL, - remind_channel VARCHAR(20) DEFAULT 'app' COMMENT '提醒渠道:app/sms/wechat', - remind_result CHAR(1) DEFAULT '1' COMMENT '结果:1-成功 2-失败', - error_msg VARCHAR(500) NULL, - create_time DATETIME DEFAULT CURRENT_TIMESTAMP, - PRIMARY KEY (id) -) ENGINE=InnoDB COMMENT='用药提醒日志表'; - -CREATE INDEX idx_rmrl_record_id ON health_medication_remind_log(record_id); -CREATE INDEX idx_rmrl_person_id ON health_medication_remind_log(person_id); -CREATE INDEX idx_rmrl_remind_time ON health_medication_remind_log(remind_time); \ No newline at end of file diff --git a/sql/chronic_disease_record.sql b/sql/chronic_disease_record.sql deleted file mode 100644 index 03eed8f..0000000 --- a/sql/chronic_disease_record.sql +++ /dev/null @@ -1,105 +0,0 @@ --- ======================================== --- 慢性疾病档案表 --- ======================================== -DROP TABLE IF EXISTS chronic_disease_record; -CREATE TABLE chronic_disease_record ( - id BIGSERIAL PRIMARY KEY, - member_id BIGINT NOT NULL, - disease_id BIGINT, - disease_name VARCHAR(100) NOT NULL, - disease_code VARCHAR(20), - diagnosis_date DATE, - disease_status SMALLINT NOT NULL DEFAULT 1, - main_doctor VARCHAR(50), - hospital VARCHAR(100), - department VARCHAR(50), - notes TEXT, - is_active SMALLINT DEFAULT 1, - -- 若依标准字段 - create_by VARCHAR(64) DEFAULT '', - create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - update_by VARCHAR(64) DEFAULT '', - update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - remark VARCHAR(500) DEFAULT '', - del_flag SMALLINT DEFAULT 0 -); - -COMMENT ON TABLE chronic_disease_record IS '慢性疾病档案表'; -COMMENT ON COLUMN chronic_disease_record.id IS '主键ID'; -COMMENT ON COLUMN chronic_disease_record.member_id IS '关联成员ID'; -COMMENT ON COLUMN chronic_disease_record.disease_id IS '关联疾病ID(关联health_diseases表)'; -COMMENT ON COLUMN chronic_disease_record.disease_name IS '疾病名称(高血压/糖尿病/冠心病等)'; -COMMENT ON COLUMN chronic_disease_record.disease_code IS '疾病编码(ICD-10标准)'; -COMMENT ON COLUMN chronic_disease_record.diagnosis_date IS '确诊日期'; -COMMENT ON COLUMN chronic_disease_record.disease_status IS '状态:1-稳定 2-需关注 3-急性期'; -COMMENT ON COLUMN chronic_disease_record.main_doctor IS '主治医生'; -COMMENT ON COLUMN chronic_disease_record.hospital IS '就诊医院'; -COMMENT ON COLUMN chronic_disease_record.department IS '科室'; -COMMENT ON COLUMN chronic_disease_record.notes IS '备注说明'; -COMMENT ON COLUMN chronic_disease_record.is_active IS '是否启用:1-是 0-否'; -COMMENT ON COLUMN chronic_disease_record.create_by IS '创建者'; -COMMENT ON COLUMN chronic_disease_record.create_time IS '创建时间'; -COMMENT ON COLUMN chronic_disease_record.update_by IS '更新者'; -COMMENT ON COLUMN chronic_disease_record.update_time IS '更新时间'; -COMMENT ON COLUMN chronic_disease_record.remark IS '备注'; -COMMENT ON COLUMN chronic_disease_record.del_flag IS '删除标记:0-正常 1-删除'; - -CREATE INDEX idx_cdr_member_id ON chronic_disease_record(member_id); -CREATE INDEX idx_cdr_disease_id ON chronic_disease_record(disease_id); -CREATE INDEX idx_cdr_disease_status ON chronic_disease_record(disease_status); -CREATE INDEX idx_cdr_is_active ON chronic_disease_record(is_active); - --- ======================================== --- 菜单 SQL(若依框架标准格式) --- ======================================== --- 慢性疾病档案菜单 -INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -VALUES ('慢性疾病档案', 0, 5, 'chronicDisease', 'health/chronicDisease/index', 1, 0, 'C', '0', '0', 'health:chronicDisease:list', '#', 'admin', NOW(), '慢性疾病档案菜单'); - --- 获取刚插入的菜单ID -SELECT @parentId := LAST_INSERT_ID(); - --- 按钮权限 -INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -VALUES ('慢性疾病档案查询', @parentId, 1, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:query', '#', 'admin', NOW(), ''); - -INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -VALUES ('慢性疾病档案权增', @parentId, 2, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:add', '#', 'admin', NOW(), ''); - -INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -VALUES ('慢性疾病档案修改', @parentId, 3, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:edit', '#', 'admin', NOW(), ''); - -INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -VALUES ('慢性疾病档案删除', @parentId, 4, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:remove', '#', 'admin', NOW(), ''); - -INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -VALUES ('慢性疾病档案导出', @parentId, 5, '#', '', 1, 0, 'F', '0', '0', 'health:chronicDisease:export', '#', 'admin', NOW(), ''); - --- ======================================== --- 字典数据 --- ======================================== --- 疾病状态字典 -INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark) -VALUES ('疾病状态', 'disease_status', '0', 'admin', NOW(), '慢性疾病状态'); - -INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) -VALUES (1, '稳定', '1', 'disease_status', '', 'success', 'Y', '0', 'admin', NOW(), '疾病状态-稳定'); - -INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) -VALUES (2, '需关注', '2', 'disease_status', '', 'warning', 'N', '0', 'admin', NOW(), '疾病状态-需关注'); - -INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) -VALUES (3, '急性期', '3', 'disease_status', '', 'danger', 'N', '0', 'admin', NOW(), '疾病状态-急性期'); - --- 是否启用字典(如果不存在) -INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark) -VALUES ('是否启用', 'is_active', '0', 'admin', NOW(), '是否启用状态') -ON CONFLICT (dict_type) DO NOTHING; - -INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) -VALUES (1, '是', '1', 'is_active', '', 'success', 'Y', '0', 'admin', NOW(), '启用') -ON CONFLICT DO NOTHING; - -INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) -VALUES (2, '否', '0', 'is_active', '', 'danger', 'N', '0', 'admin', NOW(), '停用') -ON CONFLICT DO NOTHING; \ No newline at end of file diff --git a/sql/medication.sql b/sql/medication.sql deleted file mode 100644 index 896f87c..0000000 --- a/sql/medication.sql +++ /dev/null @@ -1,128 +0,0 @@ --- ---------------------------- --- 用药计划表 --- ---------------------------- -DROP TABLE IF EXISTS health_medication_plan; -CREATE TABLE health_medication_plan ( - id BIGINT NOT NULL, - person_id BIGINT NOT NULL, - medicine_id BIGINT NOT NULL, - stock_in_id BIGINT NULL, - plan_name VARCHAR(200) NULL, - dosage DECIMAL(10,2) NOT NULL, - dosage_unit VARCHAR(20) NULL, - frequency INT NOT NULL, - frequency_type CHAR(1) DEFAULT '1', - time_points VARCHAR(500) NULL, - week_days VARCHAR(50) NULL, - start_date DATE NOT NULL, - end_date DATE NULL, - reminder_enabled CHAR(1) DEFAULT '0', - reminder_minutes INT DEFAULT 15, - status CHAR(1) DEFAULT '1', - del_flag CHAR(1) DEFAULT '0', - create_by VARCHAR(64) DEFAULT '', - create_time DATETIME NULL, - update_by VARCHAR(64) DEFAULT '', - update_time DATETIME NULL, - remark VARCHAR(500) NULL, - PRIMARY KEY (id) -) ENGINE=InnoDB COMMENT='用药计划表'; - -CREATE INDEX idx_person_id ON health_medication_plan(person_id); -CREATE INDEX idx_medicine_id ON health_medication_plan(medicine_id); -CREATE INDEX idx_status ON health_medication_plan(status); -CREATE INDEX idx_start_date ON health_medication_plan(start_date); - --- ---------------------------- --- 用药记录表 --- ---------------------------- -DROP TABLE IF EXISTS health_medication_record; -CREATE TABLE health_medication_record ( - id BIGINT NOT NULL, - plan_id BIGINT NOT NULL, - person_id BIGINT NOT NULL, - medicine_id BIGINT NOT NULL, - scheduled_time DATETIME NOT NULL, - actual_time DATETIME NULL, - dosage DECIMAL(10,2) NULL, - dosage_unit VARCHAR(20) NULL, - status CHAR(1) DEFAULT '1', - del_flag CHAR(1) DEFAULT '0', - create_by VARCHAR(64) DEFAULT '', - create_time DATETIME NULL, - update_by VARCHAR(64) DEFAULT '', - update_time DATETIME NULL, - remark VARCHAR(500) NULL, - PRIMARY KEY (id) -) ENGINE=InnoDB COMMENT='用药记录表'; - -CREATE INDEX idx_plan_id ON health_medication_record(plan_id); -CREATE INDEX idx_person_id ON health_medication_record(person_id); -CREATE INDEX idx_scheduled_time ON health_medication_record(scheduled_time); -CREATE INDEX idx_status ON health_medication_record(status); - --- ---------------------------- --- 字典数据 --- ---------------------------- -INSERT INTO sys_dict_type (dict_id, dict_name, dict_type, status, create_by, create_time, remark) -VALUES -(nextval('seq_sys_dict_type'), '用药频率类型', 'medication_frequency_type', '0', 'admin', NOW(), '用药频率类型字典'), -(nextval('seq_sys_dict_type'), '用药计划状态', 'medication_plan_status', '0', 'admin', NOW(), '用药计划状态字典'), -(nextval('seq_sys_dict_type'), '用药记录状态', 'medication_record_status', '0', 'admin', NOW(), '用药记录状态字典'); - -INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) -VALUES -(nextval('seq_sys_dict_data'), 1, '每日', '1', 'medication_frequency_type', '', 'primary', 'Y', '0', 'admin', NOW(), NULL), -(nextval('seq_sys_dict_data'), 2, '隔日', '2', 'medication_frequency_type', '', 'success', 'N', '0', 'admin', NOW(), NULL), -(nextval('seq_sys_dict_data'), 3, '每周', '3', 'medication_frequency_type', '', 'info', 'N', '0', 'admin', NOW(), NULL), -(nextval('seq_sys_dict_data'), 4, '自定义', '4', 'medication_frequency_type', '', 'warning', 'N', '0', 'admin', NOW(), NULL); - -INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) -VALUES -(nextval('seq_sys_dict_data'), 1, '进行中', '1', 'medication_plan_status', '', 'primary', 'Y', '0', 'admin', NOW(), NULL), -(nextval('seq_sys_dict_data'), 2, '已结束', '2', 'medication_plan_status', '', 'info', 'N', '0', 'admin', NOW(), NULL), -(nextval('seq_sys_dict_data'), 3, '已暂停', '3', 'medication_plan_status', '', 'warning', 'N', '0', 'admin', NOW(), NULL); - -INSERT INTO sys_dict_data (dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark) -VALUES -(nextval('seq_sys_dict_data'), 1, '待服用', '1', 'medication_record_status', '', 'warning', 'Y', '0', 'admin', NOW(), NULL), -(nextval('seq_sys_dict_data'), 2, '已服用', '2', 'medication_record_status', '', 'success', 'N', '0', 'admin', NOW(), NULL), -(nextval('seq_sys_dict_data'), 3, '已跳过', '3', 'medication_record_status', '', 'info', 'N', '0', 'admin', NOW(), NULL), -(nextval('seq_sys_dict_data'), 4, '已过期', '4', 'medication_record_status', '', 'danger', 'N', '0', 'admin', NOW(), NULL); - --- ---------------------------- --- 菜单权限 --- ---------------------------- --- 用药计划菜单 -INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -VALUES -(nextval('seq_sys_menu'), '用药计划', (SELECT menu_id FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1), 10, 'medicationPlan', 'health/medicationPlan/index', NULL, 1, 0, 'C', '0', '0', 'health:medicationPlan:list', 'calendar', 'admin', NOW(), '用药计划菜单'); - --- 用药计划按钮权限 -INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -SELECT nextval('seq_sys_menu'), '用药计划查询', m.menu_id, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:query', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' -UNION ALL -SELECT nextval('seq_sys_menu'), '用药计划新增', m.menu_id, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:add', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' -UNION ALL -SELECT nextval('seq_sys_menu'), '用药计划修改', m.menu_id, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:edit', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' -UNION ALL -SELECT nextval('seq_sys_menu'), '用药计划删除', m.menu_id, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:remove', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' -UNION ALL -SELECT nextval('seq_sys_menu'), '用药计划导出', m.menu_id, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:export', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list'; - --- 用药记录菜单 -INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -VALUES -(nextval('seq_sys_menu'), '用药记录', (SELECT menu_id FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1), 11, 'medicationRecord', 'health/medicationRecord/index', NULL, 1, 0, 'C', '0', '0', 'health:medicationRecord:list', 'log', 'admin', NOW(), '用药记录菜单'); - --- 用药记录按钮权限 -INSERT INTO sys_menu (menu_id, menu_name, parent_id, order_num, path, component, query, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) -SELECT nextval('seq_sys_menu'), '用药记录查询', m.menu_id, 1, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:query', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list' -UNION ALL -SELECT nextval('seq_sys_menu'), '用药记录新增', m.menu_id, 2, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:add', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list' -UNION ALL -SELECT nextval('seq_sys_menu'), '用药记录修改', m.menu_id, 3, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:edit', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list' -UNION ALL -SELECT nextval('seq_sys_menu'), '用药记录删除', m.menu_id, 4, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:remove', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list' -UNION ALL -SELECT nextval('seq_sys_menu'), '用药记录导出', m.menu_id, 5, '', NULL, NULL, 1, 0, 'F', '0', '0', 'health:medicationRecord:export', '#', 'admin', NOW(), '' FROM sys_menu m WHERE m.perms = 'health:medicationRecord:list'; \ No newline at end of file diff --git a/sql/medication_job_pg.sql b/sql/medication_job_pg.sql new file mode 100644 index 0000000..44d7b56 --- /dev/null +++ b/sql/medication_job_pg.sql @@ -0,0 +1,64 @@ +-- ======================================== +-- 用药管理模块 - 定时任务配置 +-- PostgreSQL 版本 +-- ======================================== + +-- 1. 每日生成服药任务(每日 00:05 执行) +INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) +VALUES ( + '每日生成服药任务', + 'DEFAULT', + 'medicationTaskJob.generateDailyTasks', + '0 5 0 * * ?', + '2', + '1', + '0', + 'admin', + NOW(), + '每日凌晨00:05自动生成当天的服药任务' +); + +-- 2. 扫描并发送服药提醒(每分钟执行) +INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) +VALUES ( + '扫描服药提醒', + 'DEFAULT', + 'medicationRemindJob.scanAndSendReminders', + '0 * * * * ?', + '2', + '1', + '0', + 'admin', + NOW(), + '每分钟扫描待提醒的服药任务并发送提醒' +); + +-- 3. 扫描超时未服药记录(每5分钟执行) +INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) +VALUES ( + '扫描超时未服药', + 'DEFAULT', + 'medicationRemindJob.scanOverdueRecords', + '0 */5 * * * ?', + '2', + '1', + '0', + 'admin', + NOW(), + '每5分钟扫描超时未服药的记录并发送提醒' +); + +-- 4. 标记过期服药记录(每小时执行) +INSERT INTO sys_job (job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark) +VALUES ( + '标记过期服药记录', + 'DEFAULT', + 'medicationTaskJob.markExpiredRecords', + '0 0 * * * ?', + '2', + '1', + '0', + 'admin', + NOW(), + '每小时检查并标记过期的服药记录' +); \ No newline at end of file diff --git a/sql/medication_menu_pg.sql b/sql/medication_menu_pg.sql new file mode 100644 index 0000000..3a49f92 --- /dev/null +++ b/sql/medication_menu_pg.sql @@ -0,0 +1,106 @@ +-- ======================================== +-- 用药管理模块 - 菜单权限配置 +-- PostgreSQL 版本 +-- ======================================== + +-- 用药计划菜单 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT '用药计划', menu_id, 10, 'medicationPlan', 'health/medicationPlan/index', 1, 0, 'C', '0', '0', 'health:medicationPlan:list', 'calendar', 'admin', NOW(), '用药计划菜单' +FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1; + +-- 用药计划按钮权限 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT '用药计划查询', m.menu_id, 1, '', NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:query', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' +UNION ALL +SELECT '用药计划新增', m.menu_id, 2, '', NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:add', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' +UNION ALL +SELECT '用药计划修改', m.menu_id, 3, '', NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:edit', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list' +UNION ALL +SELECT '用药计划删除', m.menu_id, 4, '', NULL, 1, 0, 'F', '0', '0', 'health:medicationPlan:remove', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:medicationPlan:list'; + +-- 用药任务菜单 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT '用药任务', menu_id, 11, 'medicationTask', 'health/medicationTask/index', 1, 0, 'C', '0', '0', 'health:medicationTask:list', 'log', 'admin', NOW(), '用药任务菜单' +FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1; + +-- 用药任务按钮权限 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT '用药任务查询', m.menu_id, 1, '', NULL, 1, 0, 'F', '0', '0', 'health:medicationTask:query', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:medicationTask:list' +UNION ALL +SELECT '用药任务修改', m.menu_id, 2, '', NULL, 1, 0, 'F', '0', '0', 'health:medicationTask:edit', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:medicationTask:list' +UNION ALL +SELECT '用药任务删除', m.menu_id, 3, '', NULL, 1, 0, 'F', '0', '0', 'health:medicationTask:remove', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:medicationTask:list'; + +-- 用药统计菜单 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT '用药统计', menu_id, 12, 'medicationStatistic', 'health/medicationStatistic/index', 1, 0, 'C', '0', '0', 'health:medicationStatistic:query', 'chart', 'admin', NOW(), '用药统计菜单' +FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1; + +-- 慢性疾病档案菜单 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT '慢性疾病档案', menu_id, 9, 'chronicDisease', 'health/chronicDisease/index', 1, 0, 'C', '0', '0', 'health:chronicDisease:list', 'folder', 'admin', NOW(), '慢性疾病档案菜单' +FROM sys_menu WHERE menu_name = '健康管理' LIMIT 1; + +-- 慢性疾病档案按钮权限 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) +SELECT '慢性疾病档案查询', m.menu_id, 1, '', NULL, 1, 0, 'F', '0', '0', 'health:chronicDisease:query', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:chronicDisease:list' +UNION ALL +SELECT '慢性疾病档案新增', m.menu_id, 2, '', NULL, 1, 0, 'F', '0', '0', 'health:chronicDisease:add', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:chronicDisease:list' +UNION ALL +SELECT '慢性疾病档案修改', m.menu_id, 3, '', NULL, 1, 0, 'F', '0', '0', 'health:chronicDisease:edit', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:chronicDisease:list' +UNION ALL +SELECT '慢性疾病档案删除', m.menu_id, 4, '', NULL, 1, 0, 'F', '0', '0', 'health:chronicDisease:remove', '#', 'admin', NOW(), '' +FROM sys_menu m WHERE m.perms = 'health:chronicDisease:list'; + +-- ======================================== +-- 字典类型 +-- ======================================== +INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark) +VALUES +('用药频率类型', 'medication_frequency_type', '0', 'admin', NOW(), '用药频率类型字典'), +('用药计划状态', 'medication_plan_status', '0', 'admin', NOW(), '用药计划状态字典'), +('服药任务状态', 'medication_task_status', '0', 'admin', NOW(), '服药任务状态字典'), +('疾病状态', 'disease_status', '0', 'admin', NOW(), '疾病状态字典'); + +-- ======================================== +-- 字典数据 +-- ======================================== +-- 用药频率类型 +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time) +VALUES +(1, '每天', '1', 'medication_frequency_type', '', 'primary', 'Y', '0', 'admin', NOW()), +(2, '每周', '2', 'medication_frequency_type', '', 'success', 'N', '0', 'admin', NOW()), +(3, '隔天', '3', 'medication_frequency_type', '', 'info', 'N', '0', 'admin', NOW()), +(4, '自定义', '4', 'medication_frequency_type', '', 'warning', 'N', '0', 'admin', NOW()); + +-- 用药计划状态 +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time) +VALUES +(1, '执行中', '1', 'medication_plan_status', '', 'primary', 'Y', '0', 'admin', NOW()), +(2, '已暂停', '2', 'medication_plan_status', '', 'warning', 'N', '0', 'admin', NOW()), +(3, '已结束', '3', 'medication_plan_status', '', 'info', 'N', '0', 'admin', NOW()); + +-- 服药任务状态 +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time) +VALUES +(0, '待服药', '0', 'medication_task_status', '', 'warning', 'Y', '0', 'admin', NOW()), +(1, '已服药', '1', 'medication_task_status', '', 'success', 'N', '0', 'admin', NOW()), +(2, '漏服', '2', 'medication_task_status', '', 'danger', 'N', '0', 'admin', NOW()), +(3, '跳过', '3', 'medication_task_status', '', 'info', 'N', '0', 'admin', NOW()); + +-- 疾病状态 +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time) +VALUES +(1, '稳定', '1', 'disease_status', '', 'success', 'Y', '0', 'admin', NOW()), +(2, '需关注', '2', 'disease_status', '', 'warning', 'N', '0', 'admin', NOW()), +(3, '急性期', '3', 'disease_status', '', 'danger', 'N', '0', 'admin', NOW()); \ No newline at end of file diff --git a/sql/medication_module_pg.sql b/sql/medication_module_pg.sql new file mode 100644 index 0000000..28dfe74 --- /dev/null +++ b/sql/medication_module_pg.sql @@ -0,0 +1,293 @@ +-- ======================================== +-- 用药管理模块 - PostgreSQL 建表语句 +-- 依据:慢性病用药管理模块-功能规划文档 +-- ======================================== + +-- ======================================== +-- 1. 慢性疾病档案表 +-- ======================================== +DROP TABLE IF EXISTS chronic_disease_record; +CREATE TABLE chronic_disease_record ( + id BIGSERIAL PRIMARY KEY, + member_id BIGINT NOT NULL, + disease_name VARCHAR(100) NOT NULL, + disease_code VARCHAR(20), + diagnosis_date DATE, + disease_status SMALLINT NOT NULL DEFAULT 1, + main_doctor VARCHAR(50), + hospital VARCHAR(100), + department VARCHAR(50), + notes TEXT, + -- 若依标准字段 + create_by VARCHAR(64) DEFAULT '', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64) DEFAULT '', + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + del_flag SMALLINT DEFAULT 0 +); + +COMMENT ON TABLE chronic_disease_record IS '慢性疾病档案表'; +COMMENT ON COLUMN chronic_disease_record.id IS '主键ID'; +COMMENT ON COLUMN chronic_disease_record.member_id IS '关联成员ID'; +COMMENT ON COLUMN chronic_disease_record.disease_name IS '疾病名称(高血压/糖尿病/冠心病等)'; +COMMENT ON COLUMN chronic_disease_record.disease_code IS '疾病编码(ICD-10标准)'; +COMMENT ON COLUMN chronic_disease_record.diagnosis_date IS '确诊日期'; +COMMENT ON COLUMN chronic_disease_record.disease_status IS '状态:1-稳定 2-需关注 3-急性期'; +COMMENT ON COLUMN chronic_disease_record.main_doctor IS '主治医生'; +COMMENT ON COLUMN chronic_disease_record.hospital IS '就诊医院'; +COMMENT ON COLUMN chronic_disease_record.department IS '科室'; +COMMENT ON COLUMN chronic_disease_record.notes IS '备注说明'; +COMMENT ON COLUMN chronic_disease_record.create_by IS '创建者'; +COMMENT ON COLUMN chronic_disease_record.create_time IS '创建时间'; +COMMENT ON COLUMN chronic_disease_record.update_by IS '更新者'; +COMMENT ON COLUMN chronic_disease_record.update_time IS '更新时间'; +COMMENT ON COLUMN chronic_disease_record.remark IS '备注'; +COMMENT ON COLUMN chronic_disease_record.del_flag IS '删除标记:0-正常 1-删除'; + +CREATE INDEX idx_cdr_member_id ON chronic_disease_record(member_id); +CREATE INDEX idx_cdr_disease_status ON chronic_disease_record(disease_status); + +-- ======================================== +-- 2. 用药计划表 +-- ======================================== +DROP TABLE IF EXISTS medication_plan; +CREATE TABLE medication_plan ( + id BIGSERIAL PRIMARY KEY, + member_id BIGINT NOT NULL, + chronic_disease_id BIGINT, + plan_name VARCHAR(100) NOT NULL, + medicine_id BIGINT NOT NULL, + medicine_name VARCHAR(100) NOT NULL, + specification VARCHAR(50), + dosage_per_time DECIMAL(10,2) NOT NULL, + dosage_unit VARCHAR(20) NOT NULL, + frequency_type SMALLINT NOT NULL, + frequency_config JSONB NOT NULL, + time_slots JSONB NOT NULL, + start_date DATE NOT NULL, + end_date DATE, + remind_enabled SMALLINT NOT NULL DEFAULT 1, + remind_advance_min INTEGER, + notify_family SMALLINT DEFAULT 0, + family_member_ids JSONB, + status SMALLINT NOT NULL DEFAULT 1, + -- 若依标准字段 + create_by VARCHAR(64) DEFAULT '', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64) DEFAULT '', + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + del_flag SMALLINT DEFAULT 0 +); + +COMMENT ON TABLE medication_plan IS '用药计划表'; +COMMENT ON COLUMN medication_plan.id IS '主键ID'; +COMMENT ON COLUMN medication_plan.member_id IS '关联成员ID'; +COMMENT ON COLUMN medication_plan.chronic_disease_id IS '关联慢性疾病ID'; +COMMENT ON COLUMN medication_plan.plan_name IS '计划名称(如"降压药计划")'; +COMMENT ON COLUMN medication_plan.medicine_id IS '关联药品ID'; +COMMENT ON COLUMN medication_plan.medicine_name IS '药品名称(冗余字段)'; +COMMENT ON COLUMN medication_plan.specification IS '药品规格(如"10mg/片")'; +COMMENT ON COLUMN medication_plan.dosage_per_time IS '单次剂量'; +COMMENT ON COLUMN medication_plan.dosage_unit IS '剂量单位(片/粒/毫升/喷)'; +COMMENT ON COLUMN medication_plan.frequency_type IS '频次类型:1-每天 2-每周 3-隔天 4-自定义'; +COMMENT ON COLUMN medication_plan.frequency_config IS '频次配置(JSON格式)'; +COMMENT ON COLUMN medication_plan.time_slots IS '服药时段配置'; +COMMENT ON COLUMN medication_plan.start_date IS '开始日期'; +COMMENT ON COLUMN medication_plan.end_date IS '结束日期(空表示长期)'; +COMMENT ON COLUMN medication_plan.remind_enabled IS '是否开启提醒:1-是 0-否'; +COMMENT ON COLUMN medication_plan.remind_advance_min IS '提前提醒分钟数'; +COMMENT ON COLUMN medication_plan.notify_family IS '漏服是否通知家属:1-是 0-否'; +COMMENT ON COLUMN medication_plan.family_member_ids IS '通知家属成员ID列表'; +COMMENT ON COLUMN medication_plan.status IS '状态:1-执行中 2-已暂停 3-已结束'; +COMMENT ON COLUMN medication_plan.create_by IS '创建者'; +COMMENT ON COLUMN medication_plan.create_time IS '创建时间'; +COMMENT ON COLUMN medication_plan.update_by IS '更新者'; +COMMENT ON COLUMN medication_plan.update_time IS '更新时间'; +COMMENT ON COLUMN medication_plan.remark IS '备注'; +COMMENT ON COLUMN medication_plan.del_flag IS '删除标记:0-正常 1-删除'; + +CREATE INDEX idx_mp_member_id ON medication_plan(member_id); +CREATE INDEX idx_mp_status ON medication_plan(status); +CREATE INDEX idx_mp_medicine_id ON medication_plan(medicine_id); + +-- ======================================== +-- 3. 服药任务表 +-- ======================================== +DROP TABLE IF EXISTS medication_task; +CREATE TABLE medication_task ( + id BIGSERIAL PRIMARY KEY, + plan_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, + medicine_name VARCHAR(100) NOT NULL, + planned_date DATE NOT NULL, + planned_time TIME NOT NULL, + planned_dosage DECIMAL(10,2) NOT NULL, + actual_time TIMESTAMP, + actual_dosage DECIMAL(10,2), + status SMALLINT NOT NULL DEFAULT 0, + confirm_type SMALLINT, + notes VARCHAR(255), + remind_status SMALLINT DEFAULT 0, + remind_time TIMESTAMP, + -- 若依标准字段 + create_by VARCHAR(64) DEFAULT '', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64) DEFAULT '', + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + del_flag SMALLINT DEFAULT 0 +); + +COMMENT ON TABLE medication_task IS '服药任务表'; +COMMENT ON COLUMN medication_task.id IS '主键ID'; +COMMENT ON COLUMN medication_task.plan_id IS '关联用药计划ID'; +COMMENT ON COLUMN medication_task.member_id IS '关联成员ID'; +COMMENT ON COLUMN medication_task.medicine_name IS '药品名称'; +COMMENT ON COLUMN medication_task.planned_date IS '计划服药日期'; +COMMENT ON COLUMN medication_task.planned_time IS '计划服药时间'; +COMMENT ON COLUMN medication_task.planned_dosage IS '计划剂量'; +COMMENT ON COLUMN medication_task.actual_time IS '实际服药时间'; +COMMENT ON COLUMN medication_task.actual_dosage IS '实际剂量'; +COMMENT ON COLUMN medication_task.status IS '状态:0-待服药 1-已服药 2-漏服 3-跳过'; +COMMENT ON COLUMN medication_task.confirm_type IS '确认方式:1-用户确认 2-家属代确认 3-系统自动'; +COMMENT ON COLUMN medication_task.notes IS '备注(如漏服原因)'; +COMMENT ON COLUMN medication_task.remind_status IS '提醒状态:0-未提醒 1-已提醒 2-已超时提醒'; +COMMENT ON COLUMN medication_task.remind_time IS '提醒时间'; +COMMENT ON COLUMN medication_task.create_by IS '创建者'; +COMMENT ON COLUMN medication_task.create_time IS '创建时间'; +COMMENT ON COLUMN medication_task.update_by IS '更新者'; +COMMENT ON COLUMN medication_task.update_time IS '更新时间'; +COMMENT ON COLUMN medication_task.remark IS '备注'; +COMMENT ON COLUMN medication_task.del_flag IS '删除标记:0-正常 1-删除'; + +CREATE INDEX idx_mt_plan_id ON medication_task(plan_id); +CREATE INDEX idx_mt_member_id ON medication_task(member_id); +CREATE INDEX idx_mt_planned_date ON medication_task(planned_date); +CREATE INDEX idx_mt_status ON medication_task(status); +CREATE INDEX idx_mt_planned_datetime ON medication_task(planned_date, planned_time); + +-- ======================================== +-- 4. 用药提醒日志表 +-- ======================================== +DROP TABLE IF EXISTS medication_remind_log; +CREATE TABLE medication_remind_log ( + id BIGSERIAL PRIMARY KEY, + task_id BIGINT NOT NULL, + remind_type SMALLINT NOT NULL, + remind_time TIMESTAMP NOT NULL, + remind_channel VARCHAR(20) NOT NULL, + remind_result SMALLINT NOT NULL, + error_msg VARCHAR(255), + -- 若依标准字段 + create_by VARCHAR(64) DEFAULT '', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64) DEFAULT '', + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + del_flag SMALLINT DEFAULT 0 +); + +COMMENT ON TABLE medication_remind_log IS '用药提醒日志表'; +COMMENT ON COLUMN medication_remind_log.id IS '主键ID'; +COMMENT ON COLUMN medication_remind_log.task_id IS '关联服药任务ID'; +COMMENT ON COLUMN medication_remind_log.remind_type IS '提醒类型:1-按时提醒 2-超时提醒 3-漏服通知家属'; +COMMENT ON COLUMN medication_remind_log.remind_time IS '提醒时间'; +COMMENT ON COLUMN medication_remind_log.remind_channel IS '提醒渠道:app/sms/wechat'; +COMMENT ON COLUMN medication_remind_log.remind_result IS '结果:1-成功 2-失败'; +COMMENT ON COLUMN medication_remind_log.error_msg IS '错误信息'; +COMMENT ON COLUMN medication_remind_log.create_by IS '创建者'; +COMMENT ON COLUMN medication_remind_log.create_time IS '创建时间'; +COMMENT ON COLUMN medication_remind_log.update_by IS '更新者'; +COMMENT ON COLUMN medication_remind_log.update_time IS '更新时间'; +COMMENT ON COLUMN medication_remind_log.remark IS '备注'; +COMMENT ON COLUMN medication_remind_log.del_flag IS '删除标记:0-正常 1-删除'; + +CREATE INDEX idx_mrl_task_id ON medication_remind_log(task_id); +CREATE INDEX idx_mrl_remind_time ON medication_remind_log(remind_time); + +-- ======================================== +-- 5. 药品库存变动表 +-- ======================================== +DROP TABLE IF EXISTS medicine_stock_log; +CREATE TABLE medicine_stock_log ( + id BIGSERIAL PRIMARY KEY, + medicine_id BIGINT NOT NULL, + member_id BIGINT NOT NULL, + change_type SMALLINT NOT NULL, + change_quantity DECIMAL(10,2) NOT NULL, + before_quantity DECIMAL(10,2) NOT NULL, + after_quantity DECIMAL(10,2) NOT NULL, + relate_id BIGINT, + notes VARCHAR(255), + -- 若依标准字段 + create_by VARCHAR(64) DEFAULT '', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64) DEFAULT '', + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + del_flag SMALLINT DEFAULT 0 +); + +COMMENT ON TABLE medicine_stock_log IS '药品库存变动表'; +COMMENT ON COLUMN medicine_stock_log.id IS '主键ID'; +COMMENT ON COLUMN medicine_stock_log.medicine_id IS '关联药品ID'; +COMMENT ON COLUMN medicine_stock_log.member_id IS '关联成员ID'; +COMMENT ON COLUMN medicine_stock_log.change_type IS '变动类型:1-入库 2-服药消耗 3-手动调整 4-过期报废'; +COMMENT ON COLUMN medicine_stock_log.change_quantity IS '变动数量(正数为增,负数为减)'; +COMMENT ON COLUMN medicine_stock_log.before_quantity IS '变动前库存'; +COMMENT ON COLUMN medicine_stock_log.after_quantity IS '变动后库存'; +COMMENT ON COLUMN medicine_stock_log.relate_id IS '关联ID(入库ID/任务ID等)'; +COMMENT ON COLUMN medicine_stock_log.notes IS '备注'; +COMMENT ON COLUMN medicine_stock_log.create_by IS '创建者'; +COMMENT ON COLUMN medicine_stock_log.create_time IS '创建时间'; +COMMENT ON COLUMN medicine_stock_log.update_by IS '更新者'; +COMMENT ON COLUMN medicine_stock_log.update_time IS '更新时间'; +COMMENT ON COLUMN medicine_stock_log.remark IS '备注'; +COMMENT ON COLUMN medicine_stock_log.del_flag IS '删除标记:0-正常 1-删除'; + +CREATE INDEX idx_msl_medicine_id ON medicine_stock_log(medicine_id); +CREATE INDEX idx_msl_member_id ON medicine_stock_log(member_id); +CREATE INDEX idx_msl_create_time ON medicine_stock_log(create_time); + +-- ======================================== +-- 6. 依从性统计汇总表 +-- ======================================== +DROP TABLE IF EXISTS medication_adherence_stats; +CREATE TABLE medication_adherence_stats ( + id BIGSERIAL PRIMARY KEY, + member_id BIGINT NOT NULL, + plan_id BIGINT, + stat_date DATE NOT NULL, + total_tasks INTEGER NOT NULL DEFAULT 0, + completed_tasks INTEGER NOT NULL DEFAULT 0, + missed_tasks INTEGER NOT NULL DEFAULT 0, + skipped_tasks INTEGER NOT NULL DEFAULT 0, + ontime_tasks INTEGER NOT NULL DEFAULT 0, + adherence_rate DECIMAL(5,2) NOT NULL DEFAULT 0.00, + ontime_rate DECIMAL(5,2) NOT NULL DEFAULT 0.00, + -- 若依标准字段 + create_by VARCHAR(64) DEFAULT '', + create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + update_by VARCHAR(64) DEFAULT '', + update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + remark VARCHAR(500) DEFAULT '', + del_flag SMALLINT DEFAULT 0 +); + +COMMENT ON TABLE medication_adherence_stats IS '依从性统计汇总表'; +COMMENT ON COLUMN medication_adherence_stats.id IS '主键ID'; +COMMENT ON COLUMN medication_adherence_stats.member_id IS '关联成员ID'; +COMMENT ON COLUMN medication_adherence_stats.plan_id IS '关联用药计划ID(为空表示该成员汇总)'; +COMMENT ON COLUMN medication_adherence_stats.stat_date IS '统计日期'; +COMMENT ON COLUMN medication_adherence_stats.total_tasks IS '总任务数'; +COMMENT ON COLUMN medication_adherence_stats.completed_tasks IS '已完成任务数'; +COMMENT ON COLUMN medication_adherence_stats.missed_tasks IS '漏服任务数'; +COMMENT ON COLUMN medication_adherence_stats.skipped_tasks IS '跳过任务数'; +COMMENT ON COLUMN medication_adherence_stats.ontime_tasks IS '准时服药任务数'; +COMMENT ON COLUMN medication_adherence_stats.adherence_rate IS '服药率(%)'; +COMMENT ON COLUMN medication_adherence_stats.ontime_rate IS '准时率(%)'; + +CREATE UNIQUE INDEX idx_mas_member_date ON medication_adherence_stats(member_id, stat_date, plan_id); +CREATE INDEX idx_mas_stat_date ON medication_adherence_stats(stat_date); \ No newline at end of file From 8821e0142251edbbc9bd6e78b3d67e894d5af4ff Mon Sep 17 00:00:00 2001 From: tianyongbao Date: Sat, 21 Mar 2026 10:51:35 +0800 Subject: [PATCH 6/7] =?UTF-8?q?fix:=20=E6=85=A2=E6=80=A7=E7=97=85=E7=AE=A1?= =?UTF-8?q?=E7=90=86=E8=87=AA=E6=B5=8B=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- intc-common/intc-common-core/pom.xml | 6 ++ .../ChronicDiseaseRecordController.java | 6 +- .../MedicationAdherenceController.java | 26 +++---- .../controller/MedicationPlanController.java | 2 +- .../controller/MedicationTaskController.java | 2 +- .../health/domain/ChronicDiseaseRecord.java | 7 +- .../intc/health/domain/MedicationPlan.java | 4 +- .../intc/health/domain/MedicationTask.java | 4 +- .../domain/dto/ChronicDiseaseRecordDto.java | 6 +- .../health/domain/dto/MedicationPlanDto.java | 2 +- .../health/domain/dto/MedicationTaskDto.java | 2 +- .../domain/vo/ChronicDiseaseRecordVo.java | 6 +- .../health/domain/vo/MedicationPlanVo.java | 4 +- .../health/domain/vo/MedicationTaskVo.java | 4 +- .../impl/MedicationPlanServiceImpl.java | 15 +++- .../intc/health/task/MedicationRemindJob.java | 4 +- .../intc/health/task/MedicationTaskJob.java | 3 +- .../health/ChronicDiseaseRecordMapper.xml | 36 ++++----- .../mapper/health/MedicationPlanMapper.xml | 78 +++++++++++++------ .../mapper/health/MedicationTaskMapper.xml | 24 +++--- 20 files changed, 140 insertions(+), 101 deletions(-) diff --git a/intc-common/intc-common-core/pom.xml b/intc-common/intc-common-core/pom.xml index 7ae2228..33431b0 100644 --- a/intc-common/intc-common-core/pom.xml +++ b/intc-common/intc-common-core/pom.xml @@ -145,6 +145,12 @@ mybatis-plus-extension 3.5.5 + + + org.postgresql + postgresql + provided + diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseRecordController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseRecordController.java index 06d3524..44e7e5b 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseRecordController.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/ChronicDiseaseRecordController.java @@ -58,10 +58,10 @@ public class ChronicDiseaseRecordController extends BaseController */ @ApiOperation(value = "根据成员ID查询慢性疾病档案列表", response = ChronicDiseaseRecordVo.class) @RequiresPermissions("health:chronicDisease:list") - @GetMapping("/listByMember/{memberId}") - public AjaxResult listByMember(@PathVariable("memberId") Long memberId) + @GetMapping({"/listByPerson/{personId}", "/listByMember/{personId}"}) + public AjaxResult listByMember(@PathVariable("personId") Long personId) { - List list = chronicDiseaseRecordService.selectChronicDiseaseRecordByMemberId(memberId); + List list = chronicDiseaseRecordService.selectChronicDiseaseRecordByMemberId(personId); return success(list); } diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java index 3f02a8d..692df09 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationAdherenceController.java @@ -21,7 +21,7 @@ import java.util.Map; * @date 2026-03-19 */ @RestController -@RequestMapping("/health/adherence") +@RequestMapping("/adherence") @Api(tags = "依从性统计") public class MedicationAdherenceController { @@ -31,52 +31,52 @@ public class MedicationAdherenceController { @GetMapping("/overall") @ApiOperation("获取总体依从性统计") public AjaxResult getOverallAdherence( - @RequestParam(required = false) Long memberId, + @RequestParam(required = false) Long personId, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) { - MedicationAdherenceVo vo = adherenceService.getOverallAdherence(memberId, startDate, endDate); + MedicationAdherenceVo vo = adherenceService.getOverallAdherence(personId, startDate, endDate); return AjaxResult.success(vo); } @GetMapping("/daily") @ApiOperation("获取每日依从性统计列表") public AjaxResult getDailyAdherenceList( - @RequestParam(required = false) Long memberId, + @RequestParam(required = false) Long personId, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) { - List list = adherenceService.getDailyAdherenceList(memberId, startDate, endDate); + List list = adherenceService.getDailyAdherenceList(personId, startDate, endDate); return AjaxResult.success(list); } @GetMapping("/calendar") @ApiOperation("获取日历视图数据") public AjaxResult getCalendarData( - @RequestParam(required = false) Long memberId, + @RequestParam(required = false) Long personId, @RequestParam String yearMonth) { - List list = adherenceService.getCalendarData(memberId, yearMonth); + List list = adherenceService.getCalendarData(personId, yearMonth); return AjaxResult.success(list); } @GetMapping("/timeSlot") @ApiOperation("获取各时段服药统计") public AjaxResult getTimeSlotAdherence( - @RequestParam(required = false) Long memberId, + @RequestParam(required = false) Long personId, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate startDate, @RequestParam(required = false) @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate endDate) { - Map map = adherenceService.getTimeSlotAdherence(memberId, startDate, endDate); + Map map = adherenceService.getTimeSlotAdherence(personId, startDate, endDate); return AjaxResult.success(map); } @GetMapping("/dashboard") @ApiOperation("获取仪表盘概览数据") - public AjaxResult getDashboard(@RequestParam(required = false) Long memberId) { + public AjaxResult getDashboard(@RequestParam(required = false) Long personId) { LocalDate today = LocalDate.now(); LocalDate weekAgo = today.minusDays(7); Map result = new java.util.HashMap<>(); - result.put("overall", adherenceService.getOverallAdherence(memberId, weekAgo, today)); - result.put("dailyTrend", adherenceService.getDailyAdherenceList(memberId, weekAgo, today)); - result.put("timeSlot", adherenceService.getTimeSlotAdherence(memberId, weekAgo, today)); + result.put("overall", adherenceService.getOverallAdherence(personId, weekAgo, today)); + result.put("dailyTrend", adherenceService.getDailyAdherenceList(personId, weekAgo, today)); + result.put("timeSlot", adherenceService.getTimeSlotAdherence(personId, weekAgo, today)); return AjaxResult.success(result); } diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationPlanController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationPlanController.java index 2949623..4f3ff56 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationPlanController.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationPlanController.java @@ -24,7 +24,7 @@ import java.util.List; * @date 2026-03-19 */ @RestController -@RequestMapping("/health/medicationPlan") +@RequestMapping("/medicationPlan") @Api(tags = "用药计划管理") public class MedicationPlanController extends BaseController { diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java index e1757e5..90b0fd5 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java @@ -23,7 +23,7 @@ import java.util.List; * @date 2026-03-19 */ @RestController -@RequestMapping("/health/medicationTask") +@RequestMapping("/medicationTask") @Api(tags = "服药任务管理") public class MedicationTaskController extends BaseController { diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java index 6327f99..6591fd0 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java @@ -1,6 +1,6 @@ package com.intc.health.domain; -import com.intc.common.core.domain.BaseEntity; +import com.intc.common.core.web.domain.BaseEntity; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -21,7 +21,7 @@ public class ChronicDiseaseRecord extends BaseEntity { private Long id; @ApiModelProperty("关联成员ID") - private Long memberId; + private Long personId; @ApiModelProperty("疾病名称") private String diseaseName; @@ -47,6 +47,9 @@ public class ChronicDiseaseRecord extends BaseEntity { @ApiModelProperty("备注说明") private String notes; + @ApiModelProperty("是否启用:1-启用 0-禁用") + private Integer isActive; + @ApiModelProperty("删除标记:0-正常 1-删除") private Integer delFlag; } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationPlan.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationPlan.java index 91d7287..76460b3 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationPlan.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationPlan.java @@ -1,7 +1,7 @@ package com.intc.health.domain; import com.fasterxml.jackson.databind.JsonNode; -import com.intc.common.core.domain.BaseEntity; +import com.intc.common.core.web.domain.BaseEntity; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -25,7 +25,7 @@ public class MedicationPlan extends BaseEntity { private Long id; @ApiModelProperty("关联成员ID") - private Long memberId; + private Long personId; @ApiModelProperty("关联慢性疾病ID") private Long chronicDiseaseId; diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationTask.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationTask.java index 43a3c73..235e3cb 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationTask.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/MedicationTask.java @@ -1,6 +1,6 @@ package com.intc.health.domain; -import com.intc.common.core.domain.BaseEntity; +import com.intc.common.core.web.domain.BaseEntity; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; @@ -29,7 +29,7 @@ public class MedicationTask extends BaseEntity { private Long planId; @ApiModelProperty("关联成员ID") - private Long memberId; + private Long personId; @ApiModelProperty("药品名称") private String medicineName; diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/ChronicDiseaseRecordDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/ChronicDiseaseRecordDto.java index bbb2fcc..e2d8b76 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/ChronicDiseaseRecordDto.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/ChronicDiseaseRecordDto.java @@ -21,11 +21,7 @@ public class ChronicDiseaseRecordDto implements Serializable /** 关联成员ID */ @ApiModelProperty(value = "关联成员ID") - private Long memberId; - - /** 关联疾病ID */ - @ApiModelProperty(value = "关联疾病ID") - private Long diseaseId; + private Long personId; /** 疾病名称 */ @ApiModelProperty(value = "疾病名称") diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationPlanDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationPlanDto.java index f634a5e..bb49c58 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationPlanDto.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationPlanDto.java @@ -22,7 +22,7 @@ public class MedicationPlanDto { private Long id; @ApiModelProperty("关联成员ID") - private Long memberId; + private Long personId; @ApiModelProperty("关联慢性疾病ID") private Long chronicDiseaseId; diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationTaskDto.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationTaskDto.java index ef9fbbb..13a5a4d 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationTaskDto.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/dto/MedicationTaskDto.java @@ -20,7 +20,7 @@ public class MedicationTaskDto { private Long planId; @ApiModelProperty("关联成员ID") - private Long memberId; + private Long personId; @ApiModelProperty("药品名称") private String medicineName; diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/ChronicDiseaseRecordVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/ChronicDiseaseRecordVo.java index f464114..dda41d7 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/ChronicDiseaseRecordVo.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/ChronicDiseaseRecordVo.java @@ -16,9 +16,7 @@ public class ChronicDiseaseRecordVo extends ChronicDiseaseRecord { private static final long serialVersionUID = 1L; - /** 疾病类型(来自health_diseases表) */ - private String diseaseType; + /** 成员姓名(来自health_person表) */ + private String personName; - /** 疾病症状(来自health_diseases表) */ - private String diseaseSymptom; } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java index afbfb1a..91a9533 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java @@ -23,10 +23,10 @@ public class MedicationPlanVo { private Long id; @ApiModelProperty("关联成员ID") - private Long memberId; + private Long personId; @ApiModelProperty("成员名称") - private String memberName; + private String personName; @ApiModelProperty("关联慢性疾病ID") private Long chronicDiseaseId; diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java index 1f03a8f..52d0c33 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java @@ -29,10 +29,10 @@ public class MedicationTaskVo { private String planName; @ApiModelProperty("关联成员ID") - private Long memberId; + private Long personId; @ApiModelProperty("成员名称") - private String memberName; + private String personName; @ApiModelProperty("药品名称") private String medicineName; diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java index e05e7b1..9d426ab 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java @@ -1,5 +1,6 @@ package com.intc.health.service.impl; +import com.intc.common.core.exception.ServiceException; import com.intc.common.core.utils.DateUtils; import com.intc.common.security.utils.SecurityUtils; import com.intc.health.domain.MedicationPlan; @@ -43,6 +44,18 @@ public class MedicationPlanServiceImpl implements IMedicationPlanService { @Override public int insert(MedicationPlan plan) { + if (plan.getPersonId() == null) { + throw new ServiceException("关联成员ID不能为空"); + } + if (plan.getMedicineName() == null || plan.getMedicineName().isEmpty()) { + throw new ServiceException("药品名称不能为空"); + } + if (plan.getFrequencyType() == null) { + throw new ServiceException("频次类型不能为空"); + } + if (plan.getStartDate() == null) { + throw new ServiceException("开始日期不能为空"); + } plan.setStatus(1); // 默认执行中 plan.setDelFlag(0); plan.setCreateBy(SecurityUtils.getUsername()); @@ -91,4 +104,4 @@ public class MedicationPlanServiceImpl implements IMedicationPlanService { plan.setUpdateTime(DateUtils.getNowDate()); return planMapper.update(plan); } -} \ No newline at end of file +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java index 616bbc3..cd8f689 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationRemindJob.java @@ -60,7 +60,7 @@ public class MedicationRemindJob { */ private void sendReminder(MedicationTaskVo task) { log.info("发送提醒: 成员={}, 药品={}, 计划时间={} {}", - task.getMemberName(), task.getMedicineName(), + task.getPersonName(), task.getMedicineName(), task.getPlannedDate(), task.getPlannedTime()); // TODO: 实现消息推送 @@ -106,7 +106,7 @@ public class MedicationRemindJob { */ private void sendOverdueReminder(MedicationTaskVo task) { log.warn("超时未服药: 成员={}, 药品={}, 计划时间={} {}", - task.getMemberName(), task.getMedicineName(), + task.getPersonName(), task.getMedicineName(), task.getPlannedDate(), task.getPlannedTime()); // TODO: 实现超时提醒逻辑 diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java index eeeb79f..efdc836 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java @@ -14,6 +14,7 @@ import javax.annotation.Resource; import java.math.BigDecimal; import java.time.DayOfWeek; import java.time.LocalDate; +import java.time.LocalDateTime; import java.time.LocalTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; @@ -201,7 +202,7 @@ public class MedicationTaskJob { MedicationTask task = new MedicationTask(); task.setPlanId(plan.getId()); - task.setMemberId(plan.getMemberId()); + task.setPersonId(plan.getPersonId()); task.setMedicineName(plan.getMedicineName()); task.setPlannedDate(date); task.setPlannedTime(time); 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 281774d..baadaf2 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 @@ -6,9 +6,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - - + + + @@ -24,31 +24,24 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - - + - select a.id, a.member_id, a.disease_id, a.disease_name, a.disease_code, a.diagnosis_date, + select a.id, a.person_id, a.disease_name, a.disease_code, a.diagnosis_date, a.disease_status, a.main_doctor, a.hospital, a.department, a.notes, a.is_active, a.create_by, a.create_time, a.update_by, a.update_time, a.del_flag, a.remark, - p.name as member_name, - d.type as disease_type, - d.symptom as disease_symptom + p.name as person_name from chronic_disease_record a - left join health_person p on a.member_id = p.id - left join health_diseases d on a.disease_id = d.id + left join health_person p on a.person_id = p.id - where a.del_flag = '0' and a.is_active = 1 and a.member_id = #{memberId} + where a.del_flag = '0' and a.is_active = 1 and a.person_id = #{personId} order by a.disease_status desc, a.create_time desc @@ -87,8 +80,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" insert into chronic_disease_record id, - member_id, - disease_id, + person_id, disease_name, disease_code, diagnosis_date, @@ -107,8 +99,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{id}, - #{memberId}, - #{diseaseId}, + #{personId}, #{diseaseName}, #{diseaseCode}, #{diagnosisDate}, @@ -130,8 +121,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update chronic_disease_record - member_id = #{memberId}, - disease_id = #{diseaseId}, + person_id = #{personId}, disease_name = #{diseaseName}, disease_code = #{diseaseCode}, diagnosis_date = #{diagnosisDate}, diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml index 2b194af..e11f3a2 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml @@ -4,8 +4,8 @@ - - + + @@ -28,14 +28,14 @@ - select a.id, a.member_id, p.name as member_name, a.chronic_disease_id, + select a.id, a.person_id, p.name as person_name, a.chronic_disease_id, c.disease_name as chronic_disease_name, a.plan_name, a.medicine_id, a.medicine_name, a.specification, a.dosage_per_time, a.dosage_unit, a.frequency_type, a.frequency_config, a.time_slots, a.start_date, a.end_date, a.remind_enabled, a.remind_advance_min, a.notify_family, a.family_member_ids, a.status, a.create_time from medication_plan a - left join health_person p on a.member_id = p.id + left join health_person p on a.person_id = p.id left join chronic_disease_record c on a.chronic_disease_id = c.id @@ -48,7 +48,7 @@ a.del_flag = 0 - and a.member_id = #{memberId} + and a.person_id = #{personId} and a.chronic_disease_id = #{chronicDiseaseId} and a.plan_name like '%' || #{planName} || '%' and a.medicine_id = #{medicineId} @@ -71,29 +71,61 @@ - insert into medication_plan ( - member_id, chronic_disease_id, plan_name, medicine_id, medicine_name, - specification, dosage_per_time, dosage_unit, frequency_type, - frequency_config, time_slots, start_date, end_date, - remind_enabled, remind_advance_min, notify_family, family_member_ids, status, - create_by, create_time, remark, del_flag - ) values ( - #{memberId}, #{chronicDiseaseId}, #{planName}, #{medicineId}, #{medicineName}, - #{specification}, #{dosagePerTime}, #{dosageUnit}, #{frequencyType}, - #{frequencyConfig, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, - #{timeSlots, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, - #{startDate}, #{endDate}, - #{remindEnabled}, #{remindAdvanceMin}, #{notifyFamily}, - #{familyMemberIds, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, - #{status}, - #{createBy}, #{createTime}, #{remark}, 0 - ) + insert into medication_plan + + person_id, + chronic_disease_id, + plan_name, + medicine_id, + medicine_name, + specification, + dosage_per_time, + dosage_unit, + frequency_type, + frequency_config, + time_slots, + start_date, + end_date, + remind_enabled, + remind_advance_min, + notify_family, + family_member_ids, + status, + create_by, + create_time, + remark, + del_flag, + + + #{personId}, + #{chronicDiseaseId}, + #{planName}, + #{medicineId}, + #{medicineName}, + #{specification}, + #{dosagePerTime}, + #{dosageUnit}, + #{frequencyType}, + #{frequencyConfig, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, + #{timeSlots, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, + #{startDate}, + #{endDate}, + #{remindEnabled}, + #{remindAdvanceMin}, + #{notifyFamily}, + #{familyMemberIds, typeHandler=com.intc.common.core.handler.JsonNodeTypeHandler}, + #{status}, + #{createBy}, + #{createTime}, + #{remark}, + 0, + update medication_plan - member_id = #{memberId}, + person_id = #{personId}, chronic_disease_id = #{chronicDiseaseId}, plan_name = #{planName}, medicine_id = #{medicineId}, diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml index 2d221e6..f143cd8 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml @@ -6,8 +6,8 @@ - - + + @@ -23,13 +23,13 @@ - select a.id, a.plan_id, p.plan_name, a.member_id, m.name as member_name, + select a.id, a.plan_id, p.plan_name, a.person_id, m.name as person_name, a.medicine_name, a.planned_date, a.planned_time, a.planned_dosage, a.actual_time, a.actual_dosage, a.status, a.confirm_type, a.notes, a.remind_status, a.remind_time, a.create_time from medication_task a left join medication_plan p on a.plan_id = p.id - left join health_person m on a.member_id = m.id + left join health_person m on a.person_id = m.id @@ -169,7 +169,7 @@ then 1 else 0 end) as ontime_tasks from medication_task where del_flag = 0 - and member_id = #{memberId} + and person_id = #{personId} and planned_date >= #{startDate} and planned_date <= #{endDate} group by planned_date @@ -187,7 +187,7 @@ then 1 else 0 end) as ontime_tasks from medication_task where del_flag = 0 - and member_id = #{memberId} + and person_id = #{personId} and planned_date >= #{startDate} and planned_date <= #{endDate} group by extract(hour from planned_time) From 6cff4a2e7ae20426af5f75065e09f4066baa3410 Mon Sep 17 00:00:00 2001 From: tianyongbao Date: Sat, 21 Mar 2026 22:28:06 +0800 Subject: [PATCH 7/7] =?UTF-8?q?fix:=20=E6=85=A2=E6=80=A7=E7=97=85=E7=AE=A1?= =?UTF-8?q?=E7=90=86=EF=BC=8C=E5=AE=9A=E6=97=B6=E4=BB=BB=E5=8A=A1=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=AE=8C=E5=96=84=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- intc-api/intc-api-health/pom.xml | 28 +++++++++ .../intc/api/health/RemoteHealthService.java | 40 ++++++++++++ .../factory/RemoteHealthFallbackFactory.java | 41 ++++++++++++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + intc-api/pom.xml | 1 + .../core/constant/ServiceNameConstants.java | 5 ++ .../controller/HealthJobController.java | 59 ++++++++++++++++++ .../controller/MedicationTaskController.java | 6 +- .../health/domain/ChronicDiseaseRecord.java | 3 + .../health/domain/vo/MedicationPlanVo.java | 13 ++-- .../health/domain/vo/MedicationTaskVo.java | 20 +++--- .../mapper/ChronicDiseaseRecordMapper.java | 2 + .../health/mapper/MedicationPlanMapper.java | 2 + .../health/mapper/MedicationTaskMapper.java | 13 +++- .../service/IMedicationTaskService.java | 2 +- .../impl/MedicationPlanServiceImpl.java | 11 +--- .../impl/MedicationTaskServiceImpl.java | 21 ++++++- .../intc/health/task/MedicationTaskJob.java | 62 ++++++++++++------- .../health/ChronicDiseaseRecordMapper.xml | 9 ++- .../mapper/health/MedicationPlanMapper.xml | 8 ++- .../mapper/health/MedicationTaskMapper.xml | 7 +++ intc-modules/intc-job/pom.xml | 6 ++ .../job/task/MedicationRemindJobTask.java | 36 +++++++++++ .../intc/job/task/MedicationTaskJobTask.java | 27 ++++++++ 24 files changed, 368 insertions(+), 55 deletions(-) create mode 100644 intc-api/intc-api-health/pom.xml create mode 100644 intc-api/intc-api-health/src/main/java/com/intc/api/health/RemoteHealthService.java create mode 100644 intc-api/intc-api-health/src/main/java/com/intc/api/health/factory/RemoteHealthFallbackFactory.java create mode 100644 intc-api/intc-api-health/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthJobController.java create mode 100644 intc-modules/intc-job/src/main/java/com/intc/job/task/MedicationRemindJobTask.java create mode 100644 intc-modules/intc-job/src/main/java/com/intc/job/task/MedicationTaskJobTask.java diff --git a/intc-api/intc-api-health/pom.xml b/intc-api/intc-api-health/pom.xml new file mode 100644 index 0000000..fd7279c --- /dev/null +++ b/intc-api/intc-api-health/pom.xml @@ -0,0 +1,28 @@ + + + + com.intc + intc-api + 3.6.3 + + 4.0.0 + + intc-api-health + + + intc-api-health 健康模块远程调用接口 + + + + + + + com.intc + intc-common-core + + + + + diff --git a/intc-api/intc-api-health/src/main/java/com/intc/api/health/RemoteHealthService.java b/intc-api/intc-api-health/src/main/java/com/intc/api/health/RemoteHealthService.java new file mode 100644 index 0000000..817b03a --- /dev/null +++ b/intc-api/intc-api-health/src/main/java/com/intc/api/health/RemoteHealthService.java @@ -0,0 +1,40 @@ +package com.intc.api.health; + +import com.intc.common.core.constant.ServiceNameConstants; +import com.intc.common.core.domain.R; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * 健康模块远程调用服务 + * + * @author intc + */ +@FeignClient(contextId = "remoteHealthService", value = ServiceNameConstants.INTC_HEALTH, fallbackFactory = com.intc.api.health.factory.RemoteHealthFallbackFactory.class) +public interface RemoteHealthService { + + /** + * 每日生成服药任务 + * + * @return 结果 + */ + @RequestMapping(value = "/job/generateDailyTasks", method = RequestMethod.POST) + R generateDailyTasks(); + + /** + * 扫描并发送服药提醒 + * + * @return 结果 + */ + @RequestMapping(value = "/job/scanAndSendReminders", method = RequestMethod.POST) + R scanAndSendReminders(); + + /** + * 扫描超时未服药任务 + * + * @return 结果 + */ + @RequestMapping(value = "/job/scanOverdueRecords", method = RequestMethod.POST) + R scanOverdueRecords(); +} diff --git a/intc-api/intc-api-health/src/main/java/com/intc/api/health/factory/RemoteHealthFallbackFactory.java b/intc-api/intc-api-health/src/main/java/com/intc/api/health/factory/RemoteHealthFallbackFactory.java new file mode 100644 index 0000000..935c7c4 --- /dev/null +++ b/intc-api/intc-api-health/src/main/java/com/intc/api/health/factory/RemoteHealthFallbackFactory.java @@ -0,0 +1,41 @@ +package com.intc.api.health.factory; + +import com.intc.api.health.RemoteHealthService; +import com.intc.common.core.domain.R; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.cloud.openfeign.FallbackFactory; +import org.springframework.stereotype.Component; + +/** + * 健康服务降级处理 + * + * @author intc + */ +@Component +public class RemoteHealthFallbackFactory implements FallbackFactory { + + private static final Logger log = LoggerFactory.getLogger(RemoteHealthFallbackFactory.class); + + @Override + public RemoteHealthService create(Throwable throwable) { + log.error("健康服务调用失败:{}", throwable.getMessage()); + return new RemoteHealthService() { + + @Override + public R generateDailyTasks() { + return R.fail("健康服务调用每日生成服药任务失败"); + } + + @Override + public R scanAndSendReminders() { + return R.fail("健康服务调用扫描服药提醒失败"); + } + + @Override + public R scanOverdueRecords() { + return R.fail("健康服务调用扫描超时未服药记录失败"); + } + }; + } +} diff --git a/intc-api/intc-api-health/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/intc-api/intc-api-health/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 0000000..4389ae5 --- /dev/null +++ b/intc-api/intc-api-health/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +com.intc.api.health.factory.RemoteHealthFallbackFactory \ No newline at end of file diff --git a/intc-api/pom.xml b/intc-api/pom.xml index 3395678..db3a536 100644 --- a/intc-api/pom.xml +++ b/intc-api/pom.xml @@ -11,6 +11,7 @@ intc-api-system intc-api-invest + intc-api-health intc-api pom diff --git a/intc-common/intc-common-core/src/main/java/com/intc/common/core/constant/ServiceNameConstants.java b/intc-common/intc-common-core/src/main/java/com/intc/common/core/constant/ServiceNameConstants.java index da07691..55d79d9 100644 --- a/intc-common/intc-common-core/src/main/java/com/intc/common/core/constant/ServiceNameConstants.java +++ b/intc-common/intc-common-core/src/main/java/com/intc/common/core/constant/ServiceNameConstants.java @@ -65,4 +65,9 @@ public class ServiceNameConstants * INTC_INVEST_PROD的serviceId */ public static final String INTC_INVEST_PROD ="intc-invest-prod"; + + /** + * INTC_HEALTH的serviceId + */ + public static final String INTC_HEALTH = "intc-health"; } diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthJobController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthJobController.java new file mode 100644 index 0000000..b5c8270 --- /dev/null +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/HealthJobController.java @@ -0,0 +1,59 @@ +package com.intc.health.controller; + +import com.intc.common.core.web.domain.AjaxResult; +import com.intc.health.task.MedicationRemindJob; +import com.intc.health.task.MedicationTaskJob; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * 健康模块定时任务触发接口(供 intc-job 远程调用) + * + * @author intc + */ +@RestController +@RequestMapping("/job") +@Api(tags = "健康模块定时任务接口") +public class HealthJobController { + + @Resource + private MedicationTaskJob medicationTaskJob; + + @Resource + private MedicationRemindJob medicationRemindJob; + + /** + * 每日生成服药任务 + */ + @PostMapping("/generateDailyTasks") + @ApiOperation("每日生成服药任务") + public AjaxResult generateDailyTasks() { + medicationTaskJob.generateDailyTasks(); + return AjaxResult.success(); + } + + /** + * 扫描并发送服药提醒 + */ + @PostMapping("/scanAndSendReminders") + @ApiOperation("扫描并发送服药提醒") + public AjaxResult scanAndSendReminders() { + medicationRemindJob.scanAndSendReminders(); + return AjaxResult.success(); + } + + /** + * 扫描超时未服药任务 + */ + @PostMapping("/scanOverdueRecords") + @ApiOperation("扫描超时未服药任务") + public AjaxResult scanOverdueRecords() { + medicationRemindJob.scanOverdueRecords(); + return AjaxResult.success(); + } +} diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java index 90b0fd5..15c8f8b 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/controller/MedicationTaskController.java @@ -58,8 +58,10 @@ public class MedicationTaskController extends BaseController { @ApiOperation("确认服药") @RequiresPermissions("health:medicationTask:edit") @Log(title = "服药任务", businessType = BusinessType.UPDATE) - public AjaxResult confirm(@PathVariable Long id, @RequestParam(required = false) Integer confirmType) { - return toAjax(taskService.confirm(id, confirmType)); + public AjaxResult confirm(@PathVariable Long id, + @RequestParam(required = false) Integer confirmType, + @RequestParam(required = false) String confirmTime) { + return toAjax(taskService.confirm(id, confirmType, confirmTime)); } @PutMapping("/skip/{id}") diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java index 6591fd0..a9ec46d 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/ChronicDiseaseRecord.java @@ -23,6 +23,9 @@ public class ChronicDiseaseRecord extends BaseEntity { @ApiModelProperty("关联成员ID") private Long personId; + @ApiModelProperty("关联疾病ID") + private Long diseaseId; + @ApiModelProperty("疾病名称") private String diseaseName; diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java index 91a9533..11615f8 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationPlanVo.java @@ -1,13 +1,13 @@ package com.intc.health.domain.vo; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.databind.JsonNode; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; -import java.time.LocalDate; -import java.time.LocalDateTime; +import java.util.Date; /** * 用药计划VO @@ -62,10 +62,12 @@ public class MedicationPlanVo { private JsonNode timeSlots; @ApiModelProperty("开始日期") - private LocalDate startDate; + @JsonFormat(pattern = "yyyy-MM-dd") + private Date startDate; @ApiModelProperty("结束日期") - private LocalDate endDate; + @JsonFormat(pattern = "yyyy-MM-dd") + private Date endDate; @ApiModelProperty("是否开启提醒:1-是 0-否") private Integer remindEnabled; @@ -89,5 +91,6 @@ public class MedicationPlanVo { private Integer todayCompleted; @ApiModelProperty("创建时间") - private LocalDateTime createTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java index 52d0c33..9cb2312 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/domain/vo/MedicationTaskVo.java @@ -1,13 +1,12 @@ package com.intc.health.domain.vo; +import com.fasterxml.jackson.annotation.JsonFormat; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; +import java.util.Date; /** * 服药任务VO @@ -38,16 +37,19 @@ public class MedicationTaskVo { private String medicineName; @ApiModelProperty("计划服药日期") - private LocalDate plannedDate; + @JsonFormat(pattern = "yyyy-MM-dd") + private Date plannedDate; @ApiModelProperty("计划服药时间") - private LocalTime plannedTime; + @JsonFormat(pattern = "HH:mm:ss") + private Date plannedTime; @ApiModelProperty("计划剂量") private BigDecimal plannedDosage; @ApiModelProperty("实际服药时间") - private LocalDateTime actualTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date actualTime; @ApiModelProperty("实际剂量") private BigDecimal actualDosage; @@ -68,8 +70,10 @@ public class MedicationTaskVo { private Integer remindStatus; @ApiModelProperty("提醒时间") - private LocalDateTime remindTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date remindTime; @ApiModelProperty("创建时间") - private LocalDateTime createTime; + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseRecordMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseRecordMapper.java index 224f973..8680d1b 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseRecordMapper.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/ChronicDiseaseRecordMapper.java @@ -1,5 +1,6 @@ package com.intc.health.mapper; +import com.intc.common.datascope.annotation.DataScope; import java.util.List; import com.intc.health.domain.vo.ChronicDiseaseRecordVo; import com.intc.health.domain.dto.ChronicDiseaseRecordDto; @@ -27,6 +28,7 @@ public interface ChronicDiseaseRecordMapper * @param chronicDiseaseRecordDto 慢性疾病档案 * @return 慢性疾病档案集合 */ + @DataScope(businessAlias = "a") public List selectChronicDiseaseRecordList(ChronicDiseaseRecordDto chronicDiseaseRecordDto); /** diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationPlanMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationPlanMapper.java index 407cd7c..44c56b3 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationPlanMapper.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationPlanMapper.java @@ -1,5 +1,6 @@ package com.intc.health.mapper; +import com.intc.common.datascope.annotation.DataScope; import com.intc.health.domain.MedicationPlan; import com.intc.health.domain.dto.MedicationPlanDto; import com.intc.health.domain.vo.MedicationPlanVo; @@ -23,6 +24,7 @@ public interface MedicationPlanMapper { /** * 查询用药计划列表 */ + @DataScope(businessAlias = "a") List selectList(MedicationPlanDto dto); /** diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationTaskMapper.java b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationTaskMapper.java index cfb54a8..993cdfd 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationTaskMapper.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/mapper/MedicationTaskMapper.java @@ -1,5 +1,6 @@ package com.intc.health.mapper; +import com.intc.common.datascope.annotation.DataScope; import com.intc.health.domain.MedicationTask; import com.intc.health.domain.dto.MedicationTaskDto; import com.intc.health.domain.vo.MedicationTaskVo; @@ -25,6 +26,7 @@ public interface MedicationTaskMapper { /** * 查询服药任务列表 */ + @DataScope(businessAlias = "a") List selectList(MedicationTaskDto dto); /** @@ -67,6 +69,11 @@ public interface MedicationTaskMapper { */ int countByPlanAndDate(@Param("planId") Long planId, @Param("date") LocalDate date); + /** + * 删除某计划某天的所有任务(用于重新生成时清理旧数据) + */ + int deleteByPlanAndDate(@Param("planId") Long planId, @Param("date") LocalDate date); + /** * 统计某计划某天的已服药数 */ @@ -87,21 +94,21 @@ public interface MedicationTaskMapper { /** * 获取总体统计 */ - java.util.Map getOverallStats(@Param("memberId") Long memberId, + java.util.Map getOverallStats(@Param("personId") Long personId, @Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate); /** * 获取每日统计 */ - List> getDailyStats(@Param("memberId") Long memberId, + List> getDailyStats(@Param("personId") Long personId, @Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate); /** * 获取时段统计 */ - List> getTimeSlotStats(@Param("memberId") Long memberId, + List> getTimeSlotStats(@Param("personId") Long personId, @Param("startDate") LocalDate startDate, @Param("endDate") LocalDate endDate); } \ No newline at end of file diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationTaskService.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationTaskService.java index 4354210..af445b9 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationTaskService.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/IMedicationTaskService.java @@ -42,7 +42,7 @@ public interface IMedicationTaskService { /** * 确认服药 */ - int confirm(Long id, Integer confirmType); + int confirm(Long id, Integer confirmType, String confirmTime); /** * 跳过服药 diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java index 9d426ab..8188bdb 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationPlanServiceImpl.java @@ -27,19 +27,12 @@ public class MedicationPlanServiceImpl implements IMedicationPlanService { @Override public MedicationPlanVo selectById(Long id) { - MedicationPlanVo vo = planMapper.selectById(id); - if (vo != null) { - // 统计今日任务情况 - // TODO: 添加今日任务统计 - } - return vo; + return planMapper.selectById(id); } @Override public List selectList(MedicationPlanDto dto) { - List list = planMapper.selectList(dto); - // TODO: 可以添加今日任务统计 - return list; + return planMapper.selectList(dto); } @Override diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationTaskServiceImpl.java b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationTaskServiceImpl.java index ce00e2b..db3bd6a 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationTaskServiceImpl.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/service/impl/MedicationTaskServiceImpl.java @@ -10,7 +10,9 @@ import com.intc.health.service.IMedicationTaskService; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.util.List; /** @@ -58,12 +60,27 @@ public class MedicationTaskServiceImpl implements IMedicationTaskService { } @Override - public int confirm(Long id, Integer confirmType) { + public int confirm(Long id, Integer confirmType, String confirmTime) { MedicationTask task = new MedicationTask(); task.setId(id); task.setStatus(1); // 已服药 task.setConfirmType(confirmType != null ? confirmType : 1); - task.setActualTime(LocalDateTime.now()); + // 优先使用前端传入的实际服药时间,没有则用当前时间 + if (confirmTime != null && !confirmTime.isEmpty()) { + try { + LocalTime time = LocalTime.parse(confirmTime, java.time.format.DateTimeFormatter.ofPattern("HH:mm")); + task.setActualTime(LocalDateTime.of(LocalDate.now(), time)); + } catch (Exception e1) { + try { + LocalTime time = LocalTime.parse(confirmTime, java.time.format.DateTimeFormatter.ofPattern("HH:mm:ss")); + task.setActualTime(LocalDateTime.of(LocalDate.now(), time)); + } catch (Exception e2) { + task.setActualTime(LocalDateTime.now()); + } + } + } else { + task.setActualTime(LocalDateTime.now()); + } task.setUpdateBy(SecurityUtils.getUsername()); task.setUpdateTime(DateUtils.getNowDate()); return taskMapper.update(task); diff --git a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java index efdc836..2dd3168 100644 --- a/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java +++ b/intc-modules/intc-health/src/main/java/com/intc/health/task/MedicationTaskJob.java @@ -16,9 +16,11 @@ import java.time.DayOfWeek; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; +import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.Date; import java.util.List; /** @@ -70,19 +72,26 @@ public class MedicationTaskJob { continue; } - // 检查是否已生成过任务 - int existCount = taskMapper.countByPlanAndDate(plan.getId(), date); - if (existCount > 0) { + // 先计算本次应生成的任务列表 + List tasks = generateTasksForPlan(plan, date); + if (tasks.isEmpty()) { continue; } - // 生成任务 - List tasks = generateTasksForPlan(plan, date); - if (!tasks.isEmpty()) { - taskMapper.batchInsert(tasks); - generatedCount += tasks.size(); - log.info("计划 {} 在 {} 生成了 {} 条任务", plan.getPlanName(), date, tasks.size()); + // 检查已生成的任务数,只补充未生成的部分(防止重复) + int existCount = taskMapper.countByPlanAndDate(plan.getId(), date); + if (existCount >= tasks.size()) { + // 已全量生成,跳过 + continue; } + + // 未全量生成时,删除旧的再重新全量插入(保证幂等) + if (existCount > 0) { + taskMapper.deleteByPlanAndDate(plan.getId(), date); + } + taskMapper.batchInsert(tasks); + generatedCount += tasks.size(); + log.info("计划 {} 在 {} 生成了 {} 条任务", plan.getPlanName(), date, tasks.size()); } catch (Exception e) { log.error("生成计划 {} 的任务失败: {}", plan.getId(), e.getMessage(), e); } @@ -96,10 +105,10 @@ public class MedicationTaskJob { */ private boolean shouldTakeMedicineOnDate(MedicationPlanVo plan, LocalDate date) { // 检查日期范围 - if (plan.getStartDate() != null && date.isBefore(plan.getStartDate())) { + if (plan.getStartDate() != null && date.isBefore(toLocalDate(plan.getStartDate()))) { return false; } - if (plan.getEndDate() != null && date.isAfter(plan.getEndDate())) { + if (plan.getEndDate() != null && date.isAfter(toLocalDate(plan.getEndDate()))) { return false; } @@ -152,7 +161,7 @@ public class MedicationTaskJob { * 隔天服药判断 */ private boolean shouldTakeOnAlternate(MedicationPlanVo plan, LocalDate date) { - LocalDate startDate = plan.getStartDate(); + LocalDate startDate = plan.getStartDate() != null ? toLocalDate(plan.getStartDate()) : null; if (startDate == null) { startDate = date; } @@ -182,23 +191,25 @@ public class MedicationTaskJob { List tasks = new ArrayList<>(); JsonNode timeSlots = plan.getTimeSlots(); + log.info("计划 {} timeSlots原始值={}, isArray={}, nodeType={}", + plan.getId(), timeSlots, timeSlots != null && timeSlots.isArray(), timeSlots != null ? timeSlots.getNodeType() : null); + // TextNode说明存储时被二次序列化,需要再解析一次 + if (timeSlots != null && timeSlots.isTextual()) { + try { + timeSlots = new com.fasterxml.jackson.databind.ObjectMapper().readTree(timeSlots.asText()); + } catch (Exception e) { + timeSlots = null; + } + } if (timeSlots == null || !timeSlots.isArray()) { // 如果没有配置时段,使用默认时段 timeSlots = createDefaultTimeSlots(plan); } for (JsonNode slot : timeSlots) { - if (!slot.has("enabled") || !slot.get("enabled").asBoolean(true)) { - continue; - } - - String timeStr = slot.has("time") ? slot.get("time").asText() : "08:00"; - LocalTime time = parseTime(timeStr); - + String timeStr = slot.asText(); BigDecimal dosage = plan.getDosagePerTime(); - if (slot.has("dosage")) { - dosage = new BigDecimal(slot.get("dosage").asText()); - } + LocalTime time = parseTime(timeStr); MedicationTask task = new MedicationTask(); task.setPlanId(plan.getId()); @@ -230,6 +241,13 @@ public class MedicationTaskJob { } } + /** + * Date 转 LocalDate + */ + private LocalDate toLocalDate(Date date) { + return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + } + /** * 解析时间字符串 */ 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 baadaf2..b2aac63 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 @@ -8,7 +8,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + @@ -28,7 +28,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select a.id, a.person_id, a.disease_name, a.disease_code, a.diagnosis_date, + select a.id, a.person_id,a.disease_id, a.disease_name, a.disease_code, a.diagnosis_date, a.disease_status, a.main_doctor, a.hospital, a.department, a.notes, a.is_active, a.create_by, a.create_time, a.update_by, a.update_time, a.del_flag, a.remark, p.name as person_name @@ -62,6 +62,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and a.diagnosis_date <= #{diagnosisDateEnd} + + ${params.dataScope} order by a.create_time desc @@ -81,6 +83,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" id, person_id, + disease_id, disease_name, disease_code, diagnosis_date, @@ -100,6 +103,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{id}, #{personId}, + #{diseaseId}, #{diseaseName}, #{diseaseCode}, #{diagnosisDate}, @@ -122,6 +126,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update chronic_disease_record person_id = #{personId}, + disease_id = #{diseaseId}, disease_name = #{diseaseName}, disease_code = #{diseaseCode}, diagnosis_date = #{diagnosisDate}, diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml index e11f3a2..29bb0e1 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationPlanMapper.xml @@ -24,6 +24,8 @@ + + @@ -33,7 +35,9 @@ a.medicine_name, a.specification, a.dosage_per_time, a.dosage_unit, a.frequency_type, a.frequency_config, a.time_slots, a.start_date, a.end_date, a.remind_enabled, a.remind_advance_min, a.notify_family, a.family_member_ids, - a.status, a.create_time + a.status, a.create_time, + (select count(1) from medication_task t where t.plan_id = a.id and t.del_flag = 0 and t.planned_date = current_date) as today_total, + (select count(1) from medication_task t where t.plan_id = a.id and t.del_flag = 0 and t.planned_date = current_date and t.status = 1) as today_completed from medication_plan a left join health_person p on a.person_id = p.id left join chronic_disease_record c on a.chronic_disease_id = c.id @@ -60,6 +64,8 @@ and (a.plan_name like '%' || #{keyword} || '%' or a.medicine_name like '%' || #{keyword} || '%') + + ${params.dataScope} order by a.create_time desc diff --git a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml index f143cd8..bffa40a 100644 --- a/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml +++ b/intc-modules/intc-health/src/main/resources/mapper/health/MedicationTaskMapper.xml @@ -52,6 +52,8 @@ and a.medicine_name like '%' || #{keyword} || '%' + + ${params.dataScope} order by a.planned_date desc, a.planned_time desc @@ -118,6 +120,11 @@ where del_flag = 0 and plan_id = #{planId} and planned_date = #{date} + + delete from medication_task + where plan_id = #{planId} and planned_date = #{date} and status = 0 + +