Explorar o código

feat:健康档案-历史档案

caoliqin hai 1 semana
pai
achega
c1ee566b41

+ 5 - 4
fs-admin/src/main/java/com/fs/his/controller/FsHealthRecordController.java

@@ -51,17 +51,18 @@ public class FsHealthRecordController extends BaseController
         return getDataTable(list);
     }
 
+
     /**
-     * 导出健康档案列表
+     * 导出健康档案列表(与列表一致:每人只导出最新版)
      */
     @PreAuthorize("@ss.hasPermi('his:healthRecord:export')")
     @Log(title = "健康档案", businessType = BusinessType.EXPORT)
     @GetMapping("/export")
-    public AjaxResult export(FsHealthRecord fsHealthRecord)
+    public AjaxResult export(FsHealthRecordListParam fsHealthRecord)
     {
         logger.info("tc>\n【健康档案】:{}", SecurityUtils.getUserId());
-        List<FsHealthRecord> list = fsHealthRecordService.selectFsHealthRecordList(fsHealthRecord);
-        ExcelUtil<FsHealthRecord> util = new ExcelUtil<FsHealthRecord>(FsHealthRecord.class);
+        List<FsHealthRecordListPVO> list = fsHealthRecordService.selectFsHealthRecordListVO(fsHealthRecord);
+        ExcelUtil<FsHealthRecordListPVO> util = new ExcelUtil<>(FsHealthRecordListPVO.class);
         return util.exportExcel(list, "健康档案数据");
     }
 

+ 4 - 0
fs-service/src/main/java/com/fs/his/domain/FsHealthRecord.java

@@ -62,5 +62,9 @@ public class FsHealthRecord extends BaseEntity
     @Excel(name = "家族史")
     private String familyHistory;
 
+    /** 档案版本号,用于查看历史档案 */
+    @Excel(name = "档案版本号")
+    private Integer version;
+
 
 }

+ 27 - 0
fs-service/src/main/java/com/fs/his/dto/HealthHistoryBlockDTO.java

@@ -0,0 +1,27 @@
+package com.fs.his.dto;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * 健康史模板块(health_history JSON 数组元素)
+ */
+@Data
+public class HealthHistoryBlockDTO {
+
+    private Integer id;
+
+    /** 模板名称 */
+    private String name;
+
+    private Integer sort;
+
+    private Integer type;
+
+    /** 所选值 */
+    private String value;
+
+    /** 题目列表 */
+    private List<HealthHistoryQuestionDTO> question;
+}

+ 19 - 0
fs-service/src/main/java/com/fs/his/dto/HealthHistoryQuestionDTO.java

@@ -0,0 +1,19 @@
+package com.fs.his.dto;
+
+import lombok.Data;
+
+/**
+ * 健康史模板块中的题目项
+ */
+@Data
+public class HealthHistoryQuestionDTO {
+
+    /** 题目名称 */
+    private String name;
+
+    /** 是否可填写 */
+    private Integer isWrite;
+
+    /** 填写值 */
+    private String writeVal;
+}

+ 18 - 3
fs-service/src/main/java/com/fs/his/mapper/FsHealthRecordMapper.java

@@ -62,11 +62,21 @@ public interface FsHealthRecordMapper
      */
     public int deleteFsHealthRecordByIds(Long[] ids);
 
-    @Select("select * from fs_health_record where user_id=#{userId} limit 1")
+    @Select("select * from fs_health_record where user_id=#{userId} order by version desc, id desc limit 1")
     FsHealthRecord selectFsHealthRecordByUserId(Long userId);
 
+    @Select("select * from fs_health_record where user_id=#{userId} order by version desc, id desc")
+    List<FsHealthRecord> selectFsHealthRecordHistoryByUserId(Long userId);
+
+    @Select("select IFNULL(MAX(version), 1) from fs_health_record where user_id=#{userId}")
+    Integer selectMaxVersionByUserId(Long userId);
+
     @Select({"<script> " +
-            "select hr.*,u.nick_name,CONCAT(LEFT(u.phone, 3), '****', RIGHT(u.phone, 4)) AS phone from fs_health_record hr left join fs_user u on hr.user_id=u.user_id "+
+            "select hr.*,u.nick_name,CONCAT(LEFT(u.phone, 3), '****', RIGHT(u.phone, 4)) AS phone " +
+            "from fs_health_record hr " +
+            "inner join (select user_id, max(id) as max_id from fs_health_record group by user_id) latest " +
+            "on hr.id = latest.max_id " +
+            "left join fs_user u on hr.user_id=u.user_id "+
             "<where>" +
             "  <if test=\"userId != null \"> and hr.user_id = #{userId}</if>\n" +
             "  <if test=\"name != null  and name != ''\"> and hr.name like concat( #{name}, '%')</if>\n" +
@@ -75,7 +85,12 @@ public interface FsHealthRecordMapper
             "</script>"})
     List<FsHealthRecordListPVO> selectFsHealthRecordListVO(FsHealthRecordListParam fsHealthRecord);
     @Select({"<script> " +
-            "select distinct hr.*,u.nick_name,CONCAT(LEFT(u.phone, 3), '****', RIGHT(u.phone, 4)) AS phone from fs_health_record hr left join fs_user u on hr.user_id=u.user_id LEFT JOIN company_user_user cuu on hr.user_id=cuu.user_id  "+
+            "select distinct hr.*,u.nick_name,CONCAT(LEFT(u.phone, 3), '****', RIGHT(u.phone, 4)) AS phone " +
+            "from fs_health_record hr " +
+            "inner join (select user_id, max(id) as max_id from fs_health_record group by user_id) latest " +
+            "on hr.id = latest.max_id " +
+            "left join fs_user u on hr.user_id=u.user_id " +
+            "left join company_user_user cuu on hr.user_id=cuu.user_id  "+
             "<where>" +
             " <if test=\"companyUserId != null \"> and cuu.company_user_id=#{companyUserId}</if>\n" +
             "  <if test=\"companyId != null \"> and cuu.company_id=#{companyId}</if>\n" +

+ 19 - 1
fs-service/src/main/java/com/fs/his/service/IFsHealthRecordService.java

@@ -4,6 +4,7 @@ import java.util.List;
 import com.fs.his.domain.FsHealthRecord;
 import com.fs.his.param.FsHealthRecordListParam;
 import com.fs.his.vo.FsHealthRecordListPVO;
+import com.fs.his.vo.HealthRecordHistoryChangeVO;
 
 /**
  * 健康档案Service接口
@@ -61,7 +62,24 @@ public interface IFsHealthRecordService
      */
     public int deleteFsHealthRecordById(Long id);
 
-    FsHealthRecord selectFsHealthRecordByUserId(Long l);
+    FsHealthRecord selectFsHealthRecordByUserId(Long userId);
+
+    /**
+     * 查询用户全部版本的健康档案
+     */
+    List<FsHealthRecord> selectFsHealthRecordHistoryByUserId(Long userId);
+
+    /**
+     * 查询用户健康档案历史变更对比展示
+     */
+    List<HealthRecordHistoryChangeVO> selectHealthRecordHistoryChanges(Long userId);
+
+    Integer selectMaxVersionByUserId(Long userId);
+
+    /**
+     * 追加新版本健康档案(修改时插入新记录,不更新旧记录)
+     */
+    int insertFsHealthRecordNewVersion(FsHealthRecord fsHealthRecord, Long userId);
 
     List<FsHealthRecordListPVO> selectFsHealthRecordListVO(FsHealthRecordListParam fsHealthRecord);
 

+ 134 - 3
fs-service/src/main/java/com/fs/his/service/impl/FsHealthRecordServiceImpl.java

@@ -1,15 +1,27 @@
 package com.fs.his.service.impl;
 
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
 import com.fs.common.utils.DateUtils;
+import com.fs.his.domain.FsHealthRecord;
+import com.fs.his.dto.HealthHistoryBlockDTO;
+import com.fs.his.dto.HealthHistoryQuestionDTO;
+import com.fs.his.mapper.FsHealthRecordMapper;
 import com.fs.his.param.FsHealthRecordListParam;
+import com.fs.his.service.IFsHealthRecordService;
 import com.fs.his.vo.FsHealthRecordListPVO;
+import com.fs.his.vo.HealthRecordHistoryChangeVO;
+import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
-import com.fs.his.mapper.FsHealthRecordMapper;
-import com.fs.his.domain.FsHealthRecord;
-import com.fs.his.service.IFsHealthRecordService;
 
 /**
  * 健康档案Service业务层处理
@@ -17,6 +29,7 @@ import com.fs.his.service.IFsHealthRecordService;
  * @author fs
  * @date 2024-09-02
  */
+@Slf4j
 @Service
 public class FsHealthRecordServiceImpl implements IFsHealthRecordService
 {
@@ -102,6 +115,124 @@ public class FsHealthRecordServiceImpl implements IFsHealthRecordService
         return fsHealthRecordMapper.selectFsHealthRecordByUserId(userId);
     }
 
+    @Override
+    public List<FsHealthRecord> selectFsHealthRecordHistoryByUserId(Long userId) {
+        return fsHealthRecordMapper.selectFsHealthRecordHistoryByUserId(userId);
+    }
+
+    @Override
+    public List<HealthRecordHistoryChangeVO> selectHealthRecordHistoryChanges(Long userId) {
+        List<FsHealthRecord> historyList = selectFsHealthRecordHistoryByUserId(userId);
+        if (historyList == null || historyList.size() < 2) {
+            return Collections.emptyList();
+        }
+
+        // 按id升序,相邻两条做对比
+        historyList.sort(Comparator.comparing(FsHealthRecord::getId, Comparator.nullsLast(Long::compareTo)));
+
+        List<HealthRecordHistoryChangeVO> changeList = new ArrayList<>();
+
+        // 先锁定一对新旧版本
+        for (int i = 1; i < historyList.size(); i++) {
+            // 倒叙查询的,所以最大的索引是最老的数据
+            FsHealthRecord oldRecord = historyList.get(i - 1);
+            FsHealthRecord newRecord = historyList.get(i);
+
+            List<HealthHistoryBlockDTO> oldTempList = Collections.emptyList();
+            List<HealthHistoryBlockDTO> newTempList = Collections.emptyList();
+            try {
+                if (StrUtil.isNotBlank(oldRecord.getHealthHistory())) {
+                    oldTempList = JSON.parseArray(oldRecord.getHealthHistory(), HealthHistoryBlockDTO.class);
+                }
+                if (StrUtil.isNotBlank(newRecord.getHealthHistory())) {
+                    newTempList = JSON.parseArray(newRecord.getHealthHistory(), HealthHistoryBlockDTO.class);
+                }
+            } catch (Exception e) {
+                log.warn("解析 health_history 失败, recordId={}/{}: {}", oldRecord.getId(), newRecord.getId(), e.getMessage());
+                continue;
+            }
+            if (oldTempList == null || oldTempList.isEmpty() || newTempList == null || newTempList.isEmpty()) {
+                continue;
+            }
+
+            // 旧版模板:id -> 模板
+            Map<Integer, HealthHistoryBlockDTO> oldTempMap = new HashMap<>();
+            for (HealthHistoryBlockDTO oldTemp : oldTempList) {
+                if (oldTemp != null && oldTemp.getId() != null) {
+                    oldTempMap.put(oldTemp.getId(), oldTemp);
+                }
+            }
+
+            // 再按照模板对比
+            for (HealthHistoryBlockDTO newTemp : newTempList) {
+                if (newTemp == null || newTemp.getId() == null) {
+                    continue;
+                }
+                HealthHistoryBlockDTO oldTemp = oldTempMap.get(newTemp.getId());
+                if (oldTemp == null) {
+                    // 新模板,忽略
+                    continue;
+                }
+
+                // 旧版题目:name -> writeVal
+                Map<String, String> oldAnswerMap = new HashMap<>();
+                if (oldTemp.getQuestion() != null) {
+                    for (HealthHistoryQuestionDTO oldItem : oldTemp.getQuestion()) {
+                        if (oldItem != null && StrUtil.isNotBlank(oldItem.getName())) {
+                            oldAnswerMap.put(oldItem.getName(), oldItem.getWriteVal() == null ? "" : oldItem.getWriteVal());
+                        }
+                    }
+                }
+                if (newTemp.getQuestion() == null) {
+                    continue;
+                }
+
+                // 再对比具体的值,和组装数据
+                for (HealthHistoryQuestionDTO newItem : newTemp.getQuestion()) {
+                    if (newItem == null || StrUtil.isBlank(newItem.getName())) {
+                        continue;
+                    }
+                    if (!oldAnswerMap.containsKey(newItem.getName())) {
+                        // 新题目
+                        continue;
+                    }
+                    String oldValue = oldAnswerMap.get(newItem.getName());
+                    String newValue = newItem.getWriteVal() == null ? "" : newItem.getWriteVal();
+                    if (Objects.equals(oldValue, newValue)) {
+                        continue;
+                    }
+                    HealthRecordHistoryChangeVO change = new HealthRecordHistoryChangeVO();
+                    change.setId(newRecord.getId());
+                    change.setTempleName(newTemp.getName());
+                    change.setOperateTime(newRecord.getCreateTime());
+                    change.setOperateStr(newItem.getName() + "由'" + oldValue + "'修改为'" + newValue + "'");
+                    changeList.add(change);
+                }
+            }
+        }
+        // 最新变更在前
+        Collections.reverse(changeList);
+        return changeList;
+    }
+
+    @Override
+    public Integer selectMaxVersionByUserId(Long userId) {
+        return fsHealthRecordMapper.selectMaxVersionByUserId(userId);
+    }
+
+    @Override
+    public int insertFsHealthRecordNewVersion(FsHealthRecord fsHealthRecord, Long userId) {
+        FsHealthRecord existing = selectFsHealthRecordByUserId(userId);
+        if (existing == null) {
+            return 0;
+        }
+        fsHealthRecord.setId(null);
+        fsHealthRecord.setUserId(userId);
+        Integer maxVersion = selectMaxVersionByUserId(userId);
+        fsHealthRecord.setVersion(maxVersion + 1);
+        return insertFsHealthRecord(fsHealthRecord);
+    }
+
     @Override
     public List<FsHealthRecordListPVO> selectFsHealthRecordListVO(FsHealthRecordListParam fsHealthRecord) {
         return fsHealthRecordMapper.selectFsHealthRecordListVO(fsHealthRecord);

+ 2 - 0
fs-service/src/main/java/com/fs/his/vo/FsHealthRecordListPVO.java

@@ -54,6 +54,8 @@ public class FsHealthRecordListPVO {
     @Excel(name = "过敏史")
     private String allergyHistory;
     private String  familyHistory;
+    /** 档案版本号 */
+    private Integer version;
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     private Date createTime;
 }

+ 26 - 0
fs-service/src/main/java/com/fs/his/vo/HealthRecordHistoryChangeVO.java

@@ -0,0 +1,26 @@
+package com.fs.his.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 健康档案历史变更条目
+ */
+@Data
+public class HealthRecordHistoryChangeVO {
+
+    /** 档案记录id(变更后的版本) */
+    private Long id;
+
+    /** 模板标题 */
+    private String templeName;
+
+    /** 操作时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date operateTime;
+
+    /** 变更描述 */
+    private String operateStr;
+}

+ 5 - 1
fs-service/src/main/resources/mapper/his/FsHealthRecordMapper.xml

@@ -20,10 +20,11 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <result property="updateTime"    column="update_time"    />
         <result property="familyHistory"    column="family_history"    />
         <result property="age"    column="age"    />
+        <result property="version"    column="version"    />
     </resultMap>
 
     <sql id="selectFsHealthRecordVo">
-        select id, user_id,family_history,name,age, sex, weight, height, bmi, symptom_history, health_history, drug_history, allergy_history, create_time, update_time from fs_health_record
+        select id, user_id, family_history, name, age, sex, weight, height, bmi, symptom_history, health_history, drug_history, allergy_history, create_time, update_time, version from fs_health_record
     </sql>
 
     <select id="selectFsHealthRecordList" parameterType="FsHealthRecord" resultMap="FsHealthRecordResult">
@@ -65,6 +66,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="updateTime != null">update_time,</if>
             <if test="familyHistory != null">family_history,</if>
             <if test="age != null">age,</if>
+            <if test="version != null">version,</if>
          </trim>
         <trim prefix="values (" suffix=")" suffixOverrides=",">
             <if test="id != null">#{id},</if>
@@ -82,6 +84,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="updateTime != null">#{updateTime},</if>
             <if test="familyHistory != null">#{familyHistory},</if>
             <if test="age != null">#{age},</if>
+            <if test="version != null">#{version},</if>
         </trim>
     </insert>
 
@@ -102,6 +105,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             <if test="updateTime != null">update_time = #{updateTime},</if>
             <if test="familyHistory != null">family_history = #{familyHistory},</if>
             <if test="age != null">age = #{age},</if>
+            <if test="version != null">version = #{version},</if>
         </trim>
         where id = #{id}
     </update>

+ 54 - 2
fs-user-app/src/main/java/com/fs/app/controller/HealthRecordController.java

@@ -22,6 +22,8 @@ import com.fs.his.service.IFsHealthRecordService;
 import com.fs.his.vo.FsHealthDataListUVO;
 import com.fs.his.vo.FsHealthHistoryTempListUVO;
 import com.fs.his.vo.FsHealthLifeListUVO;
+import com.fs.his.vo.HealthRecordHistoryChangeVO;
+import com.github.pagehelper.Page;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
 import io.swagger.annotations.Api;
@@ -64,6 +66,47 @@ public class HealthRecordController extends AppBaseController
         return AjaxResult.success(fsHealthRecordService.selectFsHealthRecordByUserId(Long.parseLong(getUserId())));
     }
 
+    /**
+     * 查询用户健康档案历史变更对比展示
+     */
+    @Login
+    @ApiOperation("查询健康档案历史")
+    @GetMapping("/historyRecord")
+    public R historyRecord(@RequestParam("userId") Long userId,
+                           @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
+                           @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize)
+    {
+        if (userId == null) {
+            return R.error("userId不能为空");
+        }
+        List<HealthRecordHistoryChangeVO> all = fsHealthRecordService.selectHealthRecordHistoryChanges(userId);
+        int total = all.size();
+        int fromIndex = Math.max((pageNum - 1) * pageSize, 0);
+        List<HealthRecordHistoryChangeVO> pageList;
+        if (fromIndex >= total) {
+            pageList = java.util.Collections.emptyList();
+        } else {
+            int toIndex = Math.min(fromIndex + pageSize, total);
+            pageList = all.subList(fromIndex, toIndex);
+        }
+        Page<HealthRecordHistoryChangeVO> page = new Page<>(pageNum, pageSize);
+        page.setTotal(total);
+        page.addAll(pageList);
+        return R.ok().put("data", new PageInfo<>(page));
+    }
+
+    @Login
+    @ApiOperation("获取其他用户健康档案")
+    @GetMapping("/userRecord")
+    public R userRecord(Long userId)
+    {
+        FsHealthRecord fsHealthRecord = fsHealthRecordService.selectFsHealthRecordByUserId(userId);
+        if (fsHealthRecord == null) {
+            return R.ok("暂无数据").put("isExistRecord", false);
+        }
+        return R.ok().put("data", fsHealthRecord);
+    }
+
     /**
      * 新增健康档案
      */
@@ -93,20 +136,29 @@ public class HealthRecordController extends AppBaseController
 
         FsHealthRecord fsHealthRecord = BeanCopyUtils.copy(param, FsHealthRecord.class);
         fsHealthRecord.setUserId(Long.parseLong(getUserId()));
+        fsHealthRecord.setVersion(1);
         fsHealthRecordService.insertFsHealthRecord(fsHealthRecord);
         return R.ok();
     }
 
     /**
-     * 修改健康档案
+     * 修改健康档案(追加新版本,保留历史记录)
      */
     @Login
     @ApiOperation("修改健康档案")
     @PutMapping("/editRecord")
     public R edit(@RequestBody FsHealthRecordAddEditParam param)
     {
+        Long userId = Long.parseLong(getUserId());
+        FsHealthRecord existing = fsHealthRecordService.selectFsHealthRecordByUserId(userId);
+        if (existing == null) {
+            return R.error("请先新增健康档案");
+        }
         FsHealthRecord fsHealthRecord = BeanCopyUtils.copy(param, FsHealthRecord.class);
-        fsHealthRecordService.updateFsHealthRecord(fsHealthRecord);
+        int rows = fsHealthRecordService.insertFsHealthRecordNewVersion(fsHealthRecord, userId);
+        if (rows <= 0) {
+            return R.error("修改健康档案失败");
+        }
         return R.ok();
     }