陈昶聿
6 天以前 8fe7805b75fceef28f00fb0124901031a287429c
smartor/src/main/java/com/smartor/service/impl/Icd10ServiceImpl.java
@@ -1,97 +1,261 @@
package com.smartor.service.impl;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.gson.Gson;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.http.HttpUtils;
import com.smartor.domain.Icd10;
import com.smartor.mapper.Icd10Mapper;
import com.smartor.service.IIcd10Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
 * 疾病Service业务层处理
 *
 *
 * @author ruoyi
 * @date 2023-12-21
 */
@Slf4j
@Service
public class Icd10ServiceImpl implements IIcd10Service
{
public class Icd10ServiceImpl implements IIcd10Service {
    @Autowired
    private Icd10Mapper icd10Mapper;
    @Value("${sltd_pub_path}")
    private String sltdPubPath;
    @Value("${lwl_app_key}")
    private String APP_KEY;
    /**
     * 固定 orgId
     */
    private static final long ORG_ID = 20001001L;
    /**
     * 每页拉取条数(接口最大允许 1000)
     */
    private static final int PAGE_SIZE = 1000;
    /**
     * 批量写入单批最大条数
     */
    private static final int BATCH_SIZE = 500;
    /**
     * 查询疾病
     *
     *
     * @param icdid 疾病主键
     * @return 疾病
     */
    @Override
    public Icd10 selectIcd10ByIcdid(Long icdid)
    {
    public Icd10 selectIcd10ByIcdid(Long icdid) {
        return icd10Mapper.selectIcd10ByIcdid(icdid);
    }
    /**
     * 查询疾病列表
     *
     *
     * @param icd10 疾病
     * @return 疾病
     */
    @Override
    public List<Icd10> selectIcd10List(Icd10 icd10)
    {
    public List<Icd10> selectIcd10List(Icd10 icd10) {
        return icd10Mapper.selectIcd10List(icd10);
    }
    /**
     * 新增疾病
     *
     *
     * @param icd10 疾病
     * @return 结果
     */
    @Override
    public int insertIcd10(Icd10 icd10)
    {
    public int insertIcd10(Icd10 icd10) {
        icd10.setCreateTime(DateUtils.getNowDate());
        return icd10Mapper.insertIcd10(icd10);
    }
    /**
     * 修改疾病
     *
     *
     * @param icd10 疾病
     * @return 结果
     */
    @Override
    public int updateIcd10(Icd10 icd10)
    {
    public int updateIcd10(Icd10 icd10) {
        icd10.setUpdateTime(DateUtils.getNowDate());
        return icd10Mapper.updateIcd10(icd10);
    }
    /**
     * 批量删除疾病
     *
     *
     * @param icdids 需要删除的疾病主键
     * @return 结果
     */
    @Override
    public int deleteIcd10ByIcdids(Long[] icdids)
    {
    public int deleteIcd10ByIcdids(Long[] icdids) {
        return icd10Mapper.deleteIcd10ByIcdids(icdids);
    }
    /**
     * 删除疾病信息
     *
     *
     * @param icdid 疾病主键
     * @return 结果
     */
    @Override
    public int deleteIcd10ByIcdid(Long icdid)
    {
    public int deleteIcd10ByIcdid(Long icdid) {
        return icd10Mapper.deleteIcd10ByIcdid(icdid);
    }
    /**
     * 从远程接口(来未来)分页拉取并增量写入 icd10 表。
     * <p>
     * 优化要点:
     * 1. 每页最大拉取 1000 条,减少请求次数。
     * 2. 每页把当前页所有 icdcode 用一条 IN SQL 一次批量查库,避免循环 N 次单条查询。
     * 3. 将不存在的记录收集后分批(每批 500 条)批量插入。
     * </p>
     *
     * @return 本次运行新增总条数
     */
    @Override
    public int queryAddIcd10() {
        int totalInserted = 0;
        long current = 1;
        long totalPages = 1; // 首次循环前先执行一次
        log.info("[开始] 从来未来拉取 ICD10 增量数据,orgId={}", ORG_ID);
        do {
            // 构建请求体
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("orgId", ORG_ID);
            requestBody.put("searchText", "");
            requestBody.put("size", PAGE_SIZE);
            requestBody.put("current", current);
            String responseStr;
            try {
                Map<String, String> headers = buildRequestHeaders();
                responseStr = HttpUtils.sendPostByHeader(sltdPubPath + "/hbos-thirdparty-integration/standard/base/dtc/pageDiagnosisDict", new Gson().toJson(requestBody), headers);
            } catch (Exception e) {
                log.error("[第{}页] 请求来未来接口失败", current, e);
                break;
            }
            if (responseStr == null || responseStr.isEmpty()) {
                log.warn("[第{}页] 接口返回空,停止采集", current);
                break;
            }
            JSONObject resp = JSON.parseObject(responseStr);
            if (resp == null || !Boolean.TRUE.equals(resp.getBoolean("success"))) {
                log.error("[第{}页] 接口返回失败:{}", current, responseStr);
                break;
            }
            JSONObject data = resp.getJSONObject("data");
            if (data == null) {
                break;
            }
            // 计算总页数
            long total = data.getLongValue("total");
            long pageSize = data.getLongValue("size");
            if (pageSize <= 0) {
                break;
            }
            totalPages = (total + pageSize - 1) / pageSize;
            JSONArray records = data.getJSONArray("records");
            if (records == null || records.isEmpty()) {
                break;
            }
            log.info("[第{}/{}页] 获取 {} 条记录,总{}条", current, totalPages, records.size(), total);
            // 解析当前页数据
            List<String> pageNames = new ArrayList<>();
            List<Icd10> pageList = new ArrayList<>();
            for (int i = 0; i < records.size(); i++) {
                JSONObject rec = records.getJSONObject(i);
                String icdCode = rec.getString("icdCode");
                if (icdCode == null || icdCode.isEmpty()) {
                    continue;
                }
                String icdName = StringUtils.isEmpty(rec.getString("name")) ? null : rec.getString("name").trim();
                if (icdName == null || icdName.isEmpty()) {
                    continue;
                }
                pageNames.add(icdName);
                Icd10 icd10 = new Icd10();
                icd10.setIcdcode(icdCode);
                icd10.setIcdname(icdName);
                icd10.setIcdpym(rec.getString("pinyin"));
                icd10.setHisIcdid(rec.getString("his_icdid"));
                icd10.setOrgid(String.valueOf(ORG_ID));
                icd10.setDelFlag("0");
                icd10.setCreateTime(DateUtils.getNowDate());
                pageList.add(icd10);
            }
            if (pageNames.isEmpty()) {
                current++;
                continue;
            }
            // 一次 IN 查库,获取已存在的 icdname(核心去重优化点)南华附一的icdname不会重复,icd10code会重复
            Set<String> existingNames = new HashSet<>(icd10Mapper.selectExistingIcdcodes(pageNames));
            // 过滤出不存在的记录
            List<Icd10> newList = pageList.stream().filter(item -> !existingNames.contains(item.getIcdname())).collect(Collectors.toList());
            log.info("[第{}/{}页] 当前页共 {} 条,已存在 {} 条,需新入库 {} 条", current, totalPages, pageList.size(), existingNames.size(), newList.size());
            // 分批批量插入
            int inserted = batchInsert(newList);
            totalInserted += inserted;
            current++;
        } while (current <= totalPages);
        log.info("[完成] ICD10 增量采集结束,本次共新增 {} 条", totalInserted);
        return totalInserted;
    }
    /**
     * 分批批量插入,每批最大 BATCH_SIZE 条
     */
    private int batchInsert(List<Icd10> list) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        int total = 0;
        int size = list.size();
        for (int start = 0; start < size; start += BATCH_SIZE) {
            int end = Math.min(start + BATCH_SIZE, size);
            total += icd10Mapper.batchIcd10(list.subList(start, end));
        }
        return total;
    }
    private Map<String, String> buildRequestHeaders() {
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        headers.put("app-key", APP_KEY);
        return headers;
    }
}