From 53ecb9853f880ad1432fa091abf03fd8a1259518 Mon Sep 17 00:00:00 2001
From: huangjin <huangjin@lucahealthcare.com>
Date: Fri, 25 Oct 2024 16:38:54 +0800
Subject: [PATCH] =?UTF-8?q?=E4=B8=A4=E4=B8=AA=E5=BA=93=E5=90=8C=E6=97=B6?=
 =?UTF-8?q?=E6=B4=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../pilot/config/MongoEnUsTemplateConfig.java |  38 +
 .../luca/pilot/service/EnUsPlanService.java   |  10 +
 .../service/impl/EnUsPlanServiceImpl.java     | 684 ++++++++++++++++++
 .../pilot/service/impl/PlanServiceImpl.java   |  12 +-
 src/main/resources/application-hj.yml         |   3 +-
 src/main/resources/application-uat.yml        |   3 +-
 src/main/resources/application.yml            |   2 +
 .../java/com/luca/pilot/PlanTaskTest.java     |  10 +-
 8 files changed, 753 insertions(+), 9 deletions(-)
 create mode 100644 src/main/java/com/luca/pilot/config/MongoEnUsTemplateConfig.java
 create mode 100644 src/main/java/com/luca/pilot/service/EnUsPlanService.java
 create mode 100644 src/main/java/com/luca/pilot/service/impl/EnUsPlanServiceImpl.java

diff --git a/src/main/java/com/luca/pilot/config/MongoEnUsTemplateConfig.java b/src/main/java/com/luca/pilot/config/MongoEnUsTemplateConfig.java
new file mode 100644
index 0000000..5bd091a
--- /dev/null
+++ b/src/main/java/com/luca/pilot/config/MongoEnUsTemplateConfig.java
@@ -0,0 +1,38 @@
+package com.luca.pilot.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.data.mongodb.MongoDatabaseFactory;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory;
+
+/**
+ * @author Wong
+ * @date 2024/1/6 14:17
+ */
+@Slf4j
+@Configuration
+//@EnableMongoRepositories(basePackages = "com.luca.pilot.entity")
+public class MongoEnUsTemplateConfig {
+
+    @Value("${spring.data.en-us-mongodb.uri}")
+    private String uri;
+
+//    @Primary
+    @Bean(name = "enUsMmongoTemplate")
+    public MongoTemplate enUsMmongoTemplate() {
+        log.info("-----------------------Backend Init MongoBaseTemplate Success -----------------------------------");
+        return new MongoTemplate(enUsMmongoFactory());
+    }
+
+    @Bean
+//    @Primary
+    public MongoDatabaseFactory enUsMmongoFactory() {
+        SimpleMongoClientDatabaseFactory simpleMongoClientDbFactory = new SimpleMongoClientDatabaseFactory(uri);
+        return simpleMongoClientDbFactory;
+    }
+
+}
diff --git a/src/main/java/com/luca/pilot/service/EnUsPlanService.java b/src/main/java/com/luca/pilot/service/EnUsPlanService.java
new file mode 100644
index 0000000..503a4a6
--- /dev/null
+++ b/src/main/java/com/luca/pilot/service/EnUsPlanService.java
@@ -0,0 +1,10 @@
+package com.luca.pilot.service;
+
+public interface EnUsPlanService {
+
+
+    void synchronizePlanTask();
+
+    void test();
+
+}
diff --git a/src/main/java/com/luca/pilot/service/impl/EnUsPlanServiceImpl.java b/src/main/java/com/luca/pilot/service/impl/EnUsPlanServiceImpl.java
new file mode 100644
index 0000000..99da0ed
--- /dev/null
+++ b/src/main/java/com/luca/pilot/service/impl/EnUsPlanServiceImpl.java
@@ -0,0 +1,684 @@
+package com.luca.pilot.service.impl;
+
+
+import cn.hutool.core.map.MapUtil;
+import com.luca.pilot.bizEnum.TableEnum;
+import com.luca.pilot.entity.*;
+import com.luca.pilot.service.EnUsPlanService;
+import com.luca.pilot.util.CrfUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.mongodb.core.BulkOperations;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+import org.springframework.data.util.Pair;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.springframework.data.mongodb.core.query.Criteria.where;
+
+@Slf4j
+@Service
+public class EnUsPlanServiceImpl implements EnUsPlanService {
+
+    @Resource(name = "enUsMmongoTemplate")
+    private MongoTemplate mongoTemplate;
+
+    @Resource(name = "mongoArchiveTemplate")
+    private MongoTemplate mongoArchiveTemplate;
+
+    @Override
+    @Scheduled(cron ="0 0/1 * * * ?")
+    public void synchronizePlanTask() {
+        log.info("-------------- en-US synchronizePlanTask start----------");
+        String nowTime = parseTimeFromDateTime (LocalDateTime.now());
+
+        SynchronizeTime synchronizeTime = findSynchronizeTime();
+
+        String lastSynchronizeTime = null;
+        if (Objects.nonNull(synchronizeTime)) {
+            lastSynchronizeTime =  synchronizeTime.getPlan();
+        }
+
+        Query countQuery = new Query();
+        if (Objects.nonNull(lastSynchronizeTime)) {
+            countQuery.addCriteria(where("lastModifiedAt").gt(lastSynchronizeTime));
+        }
+        long totalPlanTaskDetailsCount = mongoTemplate.count(countQuery, PlanTaskDetails.class);
+        log.info(" en-US PlanTaskDetails 鍦ㄥぇ浜� {} 鏃堕棿鍐呮湭鏌ヨ鍒版暟鎹� {} 鏉�", lastSynchronizeTime, totalPlanTaskDetailsCount);
+
+        if (totalPlanTaskDetailsCount == 0) {
+            return;
+        }
+
+        saveSynchronizeTime(synchronizeTime, nowTime);
+
+        long skip = totalPlanTaskDetailsCount / 10000;
+        if (totalPlanTaskDetailsCount % 10000 > 0) {
+            skip++;
+        }
+
+        long totalPlanModuleCount = mongoTemplate.count(new Query(), PlanModule.class);
+
+        BulkOperations bulkOps = mongoTemplate.bulkOps(BulkOperations.BulkMode.UNORDERED, PlanModule.class);
+
+        for (int i = 0; i < skip; i++) {
+            countQuery.skip(i * 10000L);
+            countQuery.limit(10000);
+            List<PlanTaskDetails> planTaskDetails = mongoTemplate.find(countQuery, PlanTaskDetails.class);
+            log.info(" en-US 绗瑊}娆℃煡璇� planTaskDetails count:{}", i + 1, planTaskDetails.size());
+            // 鑾峰彇瀵瑰簲妗f锛屽彇subjectId 鍜� randomId
+            List<UserArchiveMapping> userArchiveMappings = queryArchiveMapping(planTaskDetails);
+            List<UserArchive> userArchives = queryArchive(userArchiveMappings);
+            // 鑾峰彇椤圭洰鍜宻ite
+            List<Project> projects = queryProjct(planTaskDetails);
+            List<Site> sites = querySites(userArchiveMappings);
+            // 鑾峰彇璁″垝鐩稿叧鐨勬暟鎹�
+            List<PlanTask> planTasks = queryPlanTasks(planTaskDetails);
+            List<Plan> plans = queryPlans(planTasks);
+            List<PlanTaskModuleRelate> planMoudleRelates = queryPlanMoudleRelates(planTasks);
+            List<PlanTaskDetailsModule> planTaskDetailsModules = queryPlanTaskDetaiMoudles(planTaskDetails);
+
+            // 鑾峰彇妯″潡鍚嶇О
+            Map<Long, String> relationNameMap = queryRelateMoudleName(planMoudleRelates);
+
+            // 鑾峰彇result,鏂规硶涓垎鍒煡浜哠cale锛孮uestionaire,CRF
+            Map<Long, Map<String, Object>> resultMap = queryPlanTaskDetailResult(planTaskDetails);
+
+            // 鏁板瓧闈剁偣鐩稿叧鐨勬暟鎹紝杩欓儴鍒嗕笉闇€瑕佺粍瑁呯粨鏋滐紝鍙渶瑕佸啓鍏ョ洰鏍囪〃鍜孌igital id
+            Map<Long, Map<Long, Long>> digitalMedicalEventMap = queryDigitalMedicalEvent(planTaskDetails);
+            Map<Long, Map<Long, String>> digitalMedicalTypeMap = queryDigitalMedicalType(planTaskDetails);
+
+            List<PlanModule> planMoudles = new ArrayList<>();
+            List<Pair<Query, Update>> pairs = new ArrayList<>();
+
+            //浠� planTaskDetail 鍜� planMoudleRelate 涓哄熀鍑�
+            // 涓€涓� planTaskDetail 鑳藉搴斿涓� planMoudleRelate锛屽嵆涓€娆′换鍔¢厤缃簡澶氬皯涓ā鍧楋紙闂嵎锛岄噺琛紝鏁板瓧闈剁偣锛�
+            for (PlanTaskDetails planTaskDetail : planTaskDetails) {
+                UserArchiveMapping userArchiveMapping = userArchiveMappings.stream().filter(x -> x.getPatientCode().equals(planTaskDetail.getPatientCode())).findFirst().orElse(null);
+
+                UserArchive userArchive = userArchives.stream().filter(x -> Objects.nonNull(userArchiveMapping) && x.getId().equals(userArchiveMapping.getUserArchiveId())).findFirst().orElse(null);
+
+                Project project = projects.stream().filter(x -> x.getCode().equals(planTaskDetail.getProjectCode())).findFirst().orElse(null);
+
+                Site site = sites.stream().filter(x -> Objects.nonNull(userArchiveMapping) && x.getId().equals(userArchiveMapping.getSiteId())).findFirst().orElse(null);
+
+                PlanTask planTask = planTasks.stream().filter(x -> x.getId().equals(planTaskDetail.getPlanTaskId())).findFirst().orElse(null);
+
+                Plan plan = plans.stream().filter(x -> Objects.nonNull(planTask) && x.getId().equals(planTask.getPlanId())).findFirst().orElse(null);
+
+                List<PlanTaskModuleRelate> relates = planMoudleRelates.stream().filter(x -> Objects.nonNull(planTask) && x.getPlanTaskId().equals(planTask.getId())).collect(Collectors.toList());
+
+                List<PlanTaskDetailsModule> modules = planTaskDetailsModules.stream().filter(x -> Objects.nonNull(planTaskDetail) && x.getPlanTaskDetailsId().equals(planTaskDetail.getId())).collect(Collectors.toList());
+
+                for (PlanTaskModuleRelate relate : relates) {
+                    PlanModule planMoudle = new PlanModule();
+
+                    planMoudle.setKey(planTaskDetail.getId() + String.valueOf(relate.getId()));
+
+                    if (Objects.nonNull(userArchive)) {
+                        planMoudle.setSubjectId(userArchive.getSubjectId());
+                        planMoudle.setRandomizationId(userArchive.getRandomizationId());
+                    }
+
+                    if (Objects.nonNull(project)) {
+
+                        planMoudle.setProjectName(project.getName());
+                    }
+                    if (Objects.nonNull(site)) {
+                        planMoudle.setSiteName(site.getSiteName());
+                        planMoudle.setSiteId(site.getId());
+                    }
+
+                    if (Objects.nonNull(plan)) {
+                        planMoudle.setPlanId(plan.getId());
+                        planMoudle.setPlanCode(plan.getNumber());
+                        planMoudle.setPlanEffectiveDate(plan.getEffectiveDate().atStartOfDay());
+                        planMoudle.setPlanDuration(plan.getDays());
+                    }
+
+                    if (Objects.nonNull(planTask)) {
+                        planMoudle.setPlanTaskId(planTask.getId());
+                        planMoudle.setPlanTaskName(planTask.getName());
+                        planMoudle.setPlanTaskdescription(planTask.getDescription());
+                        planMoudle.setPlanTaskType(planTask.getTaskType());
+                        planMoudle.setPlanTaskTaskCount(planTask.getTaskCount());
+                        planMoudle.setPlanTaskFinishDay(planTask.getFinishDay());
+                        planMoudle.setPlanTaskLoopType(planTask.getLoopType());
+                        planMoudle.setPlanTaskEnabled(planTask.getEnabled());
+                        planMoudle.setPlanTaskIsCirculation(planTask.getIsCirculation());
+                        planMoudle.setPlanTaskBeginDay(planTask.getBeginDay());
+                        planMoudle.setPlanTaskCirculationDay(planTask.getCirculationDay());
+                        planMoudle.setPlanTaskWindowPhase(planTask.getWindowPhase());
+                        planMoudle.setPlanTaskEndDay(planTask.getEndDay());
+                    }
+
+                    if (Objects.nonNull(planTaskDetail)) {
+                        planMoudle.setProjectCode(String.valueOf(planTaskDetail.getProjectCode()));
+                        planMoudle.setTaskStartDate(planTaskDetail.getStartDate());
+                        planMoudle.setTaskEndDate(planTaskDetail.getEndDate());
+                        planMoudle.setTaskCompleteStatus(planTaskDetail.getCompleteStatus());
+                        planMoudle.setTaskCompleteTime(planTaskDetail.getCompleteTime());
+                        planMoudle.setTaskEnabled(planTaskDetail.getEnabled());
+                        planMoudle.setTaskCompleteOrder(planTaskDetail.getCompleteOrder());
+                    }
+
+                    if (Objects.nonNull(relate)) {
+                        planMoudle.setModuleType(relate.getRelationType());
+                        planMoudle.setModuleId(relate.getRelationId());
+                    }
+
+                    if (MapUtil.isNotEmpty(relationNameMap) && Objects.nonNull(relationNameMap.get(relate.getRelationId()))) {
+                        planMoudle.setModuleName(relationNameMap.get(relate.getRelationId()));
+                    }
+
+                    if (MapUtil.isNotEmpty(resultMap)) {
+                        Map<String, Object> planTaskDetailMap = resultMap.get(planTaskDetail.getId());
+
+                        if (MapUtil.isNotEmpty(planTaskDetailMap)) {
+                            Object result = planTaskDetailMap.get(String.valueOf(relate.getRelationId()));
+                            if (!StringUtils.isEmpty(result)) {
+                                planMoudle.setResult(result);
+                            }
+                        }
+                    }
+
+                    if (relate.getRelationType().equals("DIGITAL_MEDICAL")) {
+                        if (MapUtil.isNotEmpty(digitalMedicalEventMap)) {
+                            Map<Long, Long> eventMap = digitalMedicalEventMap.get(planTaskDetail.getId());
+                            if (MapUtil.isNotEmpty(eventMap)) {
+                                Long eventId = eventMap.get(relate.getRelationId());
+                                if (Objects.nonNull(eventId)) {
+                                    planMoudle.setDigitalModuleEventId(eventId);
+                                }
+                            }
+                        }
+                        if (MapUtil.isNotEmpty(digitalMedicalTypeMap)) {
+                            Map<Long, String> typeMap = digitalMedicalTypeMap.get(planTaskDetail.getId());
+                            if (MapUtil.isNotEmpty(typeMap)) {
+                                String eventType = typeMap.get(relate.getRelationId());
+                                if (Objects.nonNull(eventType)) {
+                                    String tableName = TableEnum.getTableNameByType(eventType);
+                                    if (Objects.nonNull(tableName)) {
+                                        planMoudle.setDigitalModuleTableName(tableName);
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    PlanTaskDetailsModule module = modules.stream().filter(x -> x.getRelationId().equals(relate.getRelationId())).findFirst().orElse(null);
+                    if (Objects.nonNull(module)) {
+                        planMoudle.setModuleComplete(module.getModuleComplete());
+                        planMoudle.setModuleIgnoreRemark(module.getIgnoreRemark());
+                        if (Objects.nonNull(module.getModuleComplete()) && module.getModuleComplete().equals(1)) {
+                            planMoudle.setModuleFinishTime(module.getLastModifiedAt());
+                        }
+                    } else {
+                        planMoudle.setModuleComplete(0);
+                    }
+
+                    // 鏄惁绗竴娆″叏閲忔彃鍏�
+                    if (totalPlanModuleCount > 0) {
+                        Query upsertQuery = new Query(where("key").is(planMoudle.getKey()));
+                        Update update = buildUpdate(planMoudle);
+                        bulkOps.upsert(upsertQuery, update);
+                        Pair<Query, Update> pair = Pair.of(upsertQuery, update);
+                        pairs.add(pair);
+                    }else {
+                        planMoudles.add(planMoudle);
+                    }
+                }
+            }
+
+
+            // 鏄惁绗竴娆″叏閲忔彃鍏�
+            if (totalPlanModuleCount > 0) {
+//                CompletableFuture.runAsync(() -> {
+                    bulkOps.upsert(pairs);
+                    bulkOps.execute();
+                    log.info(" en-US bulkOps 鏇存柊鎴栨彃鍏� {}  鏉℃暟鎹�", pairs.size());
+//                });
+            } else {
+                if (!CollectionUtils.isEmpty(planMoudles)) {
+                    mongoTemplate.insert(planMoudles, PlanModule.class);
+                    log.info(" en-US mongoTemplate insert {} 鏉℃暟鎹� ", planMoudles.size());
+                }
+            }
+
+        }
+
+        log.info(" en-US synchronizePlanTask end, 鑰楁椂:{} 绉�", LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) -
+                LocalDateTime.parse(nowTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toEpochSecond(ZoneOffset.of("+8")));
+
+    }
+
+    private SynchronizeTime findSynchronizeTime() {
+        Query query = new Query().limit(1);
+        return mongoTemplate.findOne(query, SynchronizeTime.class);
+    }
+
+    private void saveSynchronizeTime(SynchronizeTime synchronizeTime, String now) {
+        if (Objects.isNull(synchronizeTime)) {
+            SynchronizeTime time = new SynchronizeTime();
+            time.setPlan(now);
+            mongoTemplate.save(time);
+        } else {
+            Query updateQuery = new Query();
+            updateQuery.addCriteria(where("_id").is(synchronizeTime.get_id()));
+            Update update = new Update();
+            update.set("plan", now);
+            mongoTemplate.updateFirst(updateQuery, update, SynchronizeTime.class);
+        }
+    }
+
+    private Update buildUpdate(PlanModule planMoudle) {
+        return new Update()
+                .set("key", planMoudle.getKey())
+                .set("subjectId", planMoudle.getSubjectId())
+                .set("randomizationId", planMoudle.getRandomizationId())
+                .set("projectCode", planMoudle.getProjectCode())
+                .set("projectName", planMoudle.getProjectName())
+                .set("siteName", planMoudle.getSiteName())
+                .set("siteId", planMoudle.getSiteId())
+                .set("planId", planMoudle.getPlanId())
+                .set("planCode", planMoudle.getPlanCode())
+                .set("planDuration", planMoudle.getPlanDuration())
+                .set("planTaskId", planMoudle.getPlanTaskId())
+                .set("planTaskName", planMoudle.getPlanTaskName())
+                .set("planTaskdescription", planMoudle.getPlanTaskdescription())
+                .set("planTaskType", planMoudle.getPlanTaskType())
+                .set("planTaskTaskCount", planMoudle.getPlanTaskTaskCount())
+                .set("planTaskFinishDay", planMoudle.getPlanTaskFinishDay())
+                .set("planTaskLoopType", planMoudle.getPlanTaskLoopType())
+                .set("planTaskEnabled", planMoudle.getPlanTaskEnabled())
+                .set("planTaskIsCirculation", planMoudle.getPlanTaskIsCirculation())
+                .set("planTaskBeginDay", planMoudle.getPlanTaskBeginDay())
+                .set("planTaskCirculationDay", planMoudle.getPlanTaskCirculationDay())
+                .set("planTaskWindowPhase", planMoudle.getPlanTaskWindowPhase())
+                .set("planTaskEndDay", planMoudle.getPlanTaskEndDay())
+                .set("taskStartDate", planMoudle.getTaskStartDate())
+                .set("taskEndDate", planMoudle.getTaskEndDate())
+                .set("taskCompleteStatus", planMoudle.getTaskCompleteStatus())
+                .set("taskCompleteTime", planMoudle.getTaskCompleteTime())
+                .set("taskEnabled", planMoudle.getTaskEnabled())
+                .set("taskCompleteOrder", planMoudle.getTaskCompleteOrder())
+                .set("moduleType", planMoudle.getModuleType())
+                .set("moduleId", planMoudle.getModuleId())
+                .set("moduleName", planMoudle.getModuleName())
+                .set("moduleComplete", planMoudle.getModuleComplete())
+                .set("moduleIgnoreRemark", planMoudle.getModuleIgnoreRemark())
+                .set("moduleFinishTime", planMoudle.getModuleFinishTime())
+                .set("result", planMoudle.getResult())
+                .set("digitalModuleTableName", planMoudle.getDigitalModuleTableName())
+                .set("digitalModuleEventId", planMoudle.getDigitalModuleEventId())
+                .set("planEffectiveDate", planMoudle.getPlanEffectiveDate());
+    }
+
+    @Override
+    public void test() {
+
+    }
+
+
+    public static void main(String[] args) {
+        String yim ="2024-08-30 10:14:45";
+        System.out.println(LocalDateTime.parse(yim, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    }
+
+    private String parseTimeFromDate(LocalDate timeStr) {
+        LocalDateTime localDateTime = timeStr.atStartOfDay();
+        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        return localDateTime.format(fmt);
+    }
+    private String parseTimeFromDateTime(LocalDateTime timeStr) {
+        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        return timeStr.format(fmt);
+    }
+
+    private List<PlanTaskDetailsModule> queryPlanTaskDetaiMoudles(List<PlanTaskDetails> planTaskDetails) {
+
+        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
+        if (CollectionUtils.isEmpty(planTskDetailIds)) {
+            return new ArrayList<>();
+        }
+        return mongoTemplate.find(new Query().addCriteria(where("planTaskDetailsId").in(planTskDetailIds)), PlanTaskDetailsModule.class);
+
+    }
+
+    private Map<Long, Map<Long, String>> queryDigitalMedicalType(List<PlanTaskDetails> planTaskDetails) {
+        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
+        if (CollectionUtils.isEmpty(planTskDetailIds)) {
+            return new HashMap<>();
+        }
+
+        Map<Long, List<ClinicalTrialsEvent>> eventMap = mongoTemplate.find(new Query().addCriteria(where("planDetailsId").in(planTskDetailIds).and("relationType").is("DIGITAL_MEDICAL")), ClinicalTrialsEvent.class)
+                .stream().collect(Collectors.groupingBy(ClinicalTrialsEvent::getPlanDetailsId));
+
+        Map<Long, Map<Long, String>> map = new HashMap<>();
+        eventMap.forEach((k, v) -> {
+            Map<Long, String> innerMap = new HashMap<>();
+            if (!CollectionUtils.isEmpty(v)) {
+                v.forEach(event -> {
+                    innerMap.put(event.getRelationId(), event.getModuleItemType());
+                });
+                map.put(k, innerMap);
+            }
+        });
+
+        return map;
+    }
+
+    private Map<Long, Map<Long, Long>> queryDigitalMedicalEvent(List<PlanTaskDetails> planTaskDetails) {
+        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
+        if (CollectionUtils.isEmpty(planTskDetailIds)) {
+            return new HashMap<>();
+        }
+
+        Map<Long, List<ClinicalTrialsEvent>> eventMap = mongoTemplate.find(new Query().addCriteria(where("planDetailsId").in(planTskDetailIds).and("relationType").is("DIGITAL_MEDICAL")), ClinicalTrialsEvent.class)
+                .stream().collect(Collectors.groupingBy(ClinicalTrialsEvent::getPlanDetailsId));
+
+        Map<Long, Map<Long, Long>> map = new HashMap<>();
+        eventMap.forEach((k, v) -> {
+            Map<Long, Long> innerMap = new HashMap<>();
+            if (!CollectionUtils.isEmpty(v)) {
+                v.forEach(event -> {
+                    innerMap.put(event.getRelationId(), event.getEventId());
+                });
+                map.put(k, innerMap);
+            }
+        });
+
+        return map;
+    }
+
+    private Map<Long, Map<String, Object>> queryPlanTaskDetailResult(List<PlanTaskDetails> planTaskDetails) {
+        Map<Long, Map<String, Object>> map = new HashMap<>();
+        Map<Long, Map<String, Object>> scaleMap = queryScaleResult(planTaskDetails);
+        map.putAll(scaleMap);
+        Map<Long, Map<String, Object>> questonaireMap = queryQuestionaireResult(planTaskDetails);
+
+        questonaireMap.forEach((k, v) -> {
+            if (map.containsKey(k)) {
+                map.get(k).putAll(v);
+            } else {
+                map.put(k, v);
+            }
+        });
+
+        Map<Long, Map<String, Object>> crfMap = queryCrfResult(planTaskDetails);
+        crfMap.forEach((k, v) -> {
+            if (map.containsKey(k)) {
+                map.get(k).putAll(v);
+            } else {
+                map.put(k, v);
+            }
+        });
+
+        return map;
+    }
+
+    private Map<Long, Map<String, Object>> queryCrfResult(List<PlanTaskDetails> planTaskDetails) {
+        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
+        if (CollectionUtils.isEmpty(planTskDetailIds)) {
+            return new HashMap<>();
+        }
+
+        List<CrfAnswer> crfAnswers = mongoTemplate.find(new Query().addCriteria(where("planTaskDetailsId").in(planTskDetailIds)), CrfAnswer.class);
+
+        Map<Long, List<CrfAnswer>> crfAnswersMap = crfAnswers.stream().collect(Collectors.groupingBy(CrfAnswer::getPlanTaskDetailsId));
+
+        Set<Long> crfIds = crfAnswers.stream().map(CrfAnswer::getCrfId).collect(Collectors.toSet());
+        Map<Long, String> crfMap = mongoTemplate.find(new Query().addCriteria(where("id").in(crfIds)), Crf.class)
+                .stream().collect(Collectors.toMap(Crf::getId, Crf::getQuestionJson, (k1, k2) -> k2));
+
+        Map<Long, Map<String, Object>> map = new HashMap<>();
+        crfAnswersMap.forEach((k, v) -> {
+            if (!CollectionUtils.isEmpty(v)) {
+                Map<String, Object> innerMap = new HashMap<>();
+                v.forEach(crfAnswer -> {
+                    String questionJson = crfMap.get(crfAnswer.getCrfId());
+                    if (Objects.nonNull(questionJson) && Objects.nonNull(crfAnswer.getAnswerJson())) {
+                        try {
+                            Map<String, Object> result = CrfUtil.parseCrfProblemAndAnswer(questionJson, crfAnswer.getAnswerJson());
+                            if (Objects.nonNull(result)) {
+                                innerMap.put(crfAnswer.getCrfTopId().toString(), result);
+                            }
+                        } catch (Exception e) {
+                            e.printStackTrace();
+
+                        }
+                    }
+                });
+                map.put(k, innerMap);
+            }
+        });
+
+        return map;
+    }
+
+    private Map<Long, Map<String, Object>> queryQuestionaireResult(List<PlanTaskDetails> planTaskDetails) {
+        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
+        if (CollectionUtils.isEmpty(planTskDetailIds)) {
+            return new HashMap<>();
+        }
+
+        List<QuestionnaireAnswerRecord> records = mongoTemplate.find(new Query().addCriteria(where("planTaskDetailsId").in(planTskDetailIds)), QuestionnaireAnswerRecord.class);
+
+        if (CollectionUtils.isEmpty(records)) {
+            return new HashMap<>();
+        }
+
+        Set<Long> recordIds = records.stream().map(QuestionnaireAnswerRecord::getId).collect(Collectors.toSet());
+        List<QuestionnaireAnswer> answers = mongoTemplate.find(new Query().addCriteria(where("recordId").in(recordIds)), QuestionnaireAnswer.class);
+
+        Set<Long> ansowerIds = answers.stream().map(QuestionnaireAnswer::getId).collect(Collectors.toSet());
+        List<QuestionnaireAnswerOption> answerOptions = mongoTemplate.find(new Query().addCriteria(where("answerId").in(ansowerIds)), QuestionnaireAnswerOption.class);
+
+        Map<Long, Map<String, Object>> map = new HashMap<>();
+
+        for (QuestionnaireAnswerRecord record : records) {
+
+            List<QuestionnaireAnswer> answerList = answers.stream().filter(x -> x.getRecordId().equals(record.getId())).collect(Collectors.toList());
+
+            Map<String, Object> resultMap = new HashMap<>();
+//            List<String> keyValueNewVos = new ArrayList<>();
+            Map<String,Object> keyValueNewVos = new HashMap<>();
+            for (QuestionnaireAnswer answer : answerList) {
+                Stream<QuestionnaireAnswerOption> questionnaireAnswerOptionStream = answerOptions.stream().filter(x -> x.getAnswerId().equals(answer.getId()) && x.getQuestionId().equals(answer.getQuestionId()));
+                Optional<QuestionnaireAnswerOption> optionalAnswerOption = questionnaireAnswerOptionStream.findAny();
+
+                switch (answer.getType()) {
+                    case "CHOICE":
+                        keyValueNewVos.put(answer.getQuestionName().replaceAll("\\.", ""), optionalAnswerOption.map(QuestionnaireAnswerOption::getOptionName).orElse("-"));
+                        break;
+                    case "SLIDE":
+                    case "DATE_SELECT":
+                    case "NUMBER":
+                        keyValueNewVos.put(answer.getQuestionName().replaceAll("\\.", ""), optionalAnswerOption.map(option -> String.valueOf(option.getNumberAnswer())).orElse("-"));
+                        break;
+                    case "MULTIPLE_CHOICE":
+                        List<String> optionNames = answerOptions.stream()
+                                .filter(x -> x.getAnswerId().equals(answer.getId()) && x.getQuestionId().equals(answer.getQuestionId()))
+                                .map(QuestionnaireAnswerOption::getOptionName)
+                                .collect(Collectors.toList());
+                        keyValueNewVos.put(answer.getQuestionName().replaceAll("\\.", ""), (optionNames.isEmpty() ? "-" : String.join(",", optionNames)));
+                        break;
+                    case "DATE":
+                        keyValueNewVos.put(answer.getQuestionName().replaceAll("\\.", ""), optionalAnswerOption.map(QuestionnaireAnswerOption::getDateAt).orElse("-"));
+                        break;
+
+                    case "SECTION_NUMBER":
+                        keyValueNewVos.put(answer.getQuestionName().replaceAll("\\.", ""), (optionalAnswerOption.map(option -> option.getLeftMin() + "-" + option.getRightMax()).orElse("-")));
+                        break;
+                    case "TEXT":
+                        keyValueNewVos.put(answer.getQuestionName().replaceAll("\\.", ""), optionalAnswerOption.map(QuestionnaireAnswerOption::getContent).orElse("-"));
+                        break;
+                }
+            }
+            resultMap.put(String.valueOf(record.getTopId()), keyValueNewVos);
+            map.put(record.getPlanTaskDetailsId(), resultMap);
+        }
+
+        return map;
+    }
+
+    private Map<Long, Map<String, Object>> queryScaleResult(List<PlanTaskDetails> planTaskDetails) {
+        Set<Long> planTskDetailIds = planTaskDetails.stream().map(PlanTaskDetails::getId).collect(Collectors.toSet());
+        if (CollectionUtils.isEmpty(planTskDetailIds)) {
+            return new HashMap<>();
+        }
+
+        Map<Long, List<PatientScaleEvaluatingEntity>> scaleEvaluatMap =
+                mongoTemplate.find(new Query().addCriteria(where("planTaskDetailsId").in(planTskDetailIds)), PatientScaleEvaluatingEntity.class)
+                        .stream().collect(Collectors.groupingBy(PatientScaleEvaluatingEntity::getPlanTaskDetailsId));
+
+        Map<Long, Map<String, Object>> map = new HashMap<>();
+
+        scaleEvaluatMap.forEach((k, v) -> {
+            if (!CollectionUtils.isEmpty(v)) {
+                Map<String, Object> result = new HashMap<>();
+                v.forEach(item -> {
+//                    List<String> sb = new ArrayList<>();
+                    Map<String,Object> resultMap = new HashMap<>();
+                    if (Objects.nonNull(item.getScaleResult())) {
+//                        sb.add("result:" + item.getScaleResult());
+                        resultMap.put("evaluation",item.getScaleResult());
+                    }
+                    if (Objects.nonNull(item.getTotalScore())) {
+//                        sb.add("totalScore:" + item.getTotalScore());
+                        resultMap.put("score",item.getTotalScore());
+                    }
+
+                    if(!StringUtils.isEmpty(item.getScaleCode())) {
+                        List<ScaleQuestionEntity> questions = mongoTemplate.find(new Query().addCriteria(where("scaleCode").is(item.getScaleCode())), ScaleQuestionEntity.class);
+                        BigDecimal totalScore = questions.stream().map(ScaleQuestionEntity::getScore).reduce(BigDecimal.ZERO, BigDecimal::add);
+                        resultMap.put("totalScore", totalScore);
+                    }
+
+
+                    if (!MapUtil.isEmpty(resultMap)) {
+                        result.put(item.getScaleCode(), resultMap);
+                    }
+
+                });
+
+                map.put(k, result);
+            }
+        });
+
+        return map;
+    }
+
+    private Map<Long, String> queryRelateMoudleName(List<PlanTaskModuleRelate> planMoudleRelates) {
+        /**
+         * QUESTIONNAIRE 1
+         * SCALE 1
+         * DIGITAL_MEDICAL
+         * CRF 1
+         * COLLECT_FLOW
+         *
+         * INTELLIGENT_DEVICE
+         * EXERCISE_MODULE
+         *
+         * E_DIARY
+         */
+        Map<Long, String> map = new HashMap<>();
+        List<Long> questionnaireIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("QUESTIONNAIRE")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
+        Map<Long, String> questionaireMap = mongoTemplate.find(new Query().addCriteria(where("topId").in(questionnaireIds)), Questionnaire.class)
+                .stream().collect(Collectors.toMap(Questionnaire::getTopId, Questionnaire::getName, (k1, k2) -> k2));
+        if (MapUtil.isNotEmpty(questionaireMap)) {
+            map.putAll(questionaireMap);
+        }
+
+        List<Long> crfTopIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("CRF")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
+        Map<Long, String> crfMap = mongoTemplate.find(new Query().addCriteria(where("crfTopId").in(crfTopIds)), Crf.class)
+                .stream().collect(Collectors.toMap(Crf::getCrfTopId, Crf::getName, (k1, k2) -> k2));
+        if (MapUtil.isNotEmpty(crfMap)) {
+            map.putAll(crfMap);
+        }
+
+        List<Long> scaleIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("SCALE")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
+        Map<Long, String> scaleMap = mongoTemplate.find(new Query().addCriteria(where("id").in(scaleIds)), ScaleModuleDetailsEntity.class)
+                .stream().collect(Collectors.toMap(ScaleModuleDetailsEntity::getId, ScaleModuleDetailsEntity::getName, (k1, k2) -> k2));
+        if (MapUtil.isNotEmpty(scaleMap)) {
+            map.putAll(scaleMap);
+        }
+
+        List<Long> digitalMedicalIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("DIGITAL_MEDICAL")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
+        Map<Long, String> digitalMedicalMap = mongoTemplate.find(new Query().addCriteria(where("id").in(digitalMedicalIds)), DigitalMedicalDetails.class)
+                .stream().collect(Collectors.toMap(DigitalMedicalDetails::getId, DigitalMedicalDetails::getName, (k1, k2) -> k2));
+        if (MapUtil.isNotEmpty(digitalMedicalMap)) {
+            map.putAll(digitalMedicalMap);
+        }
+
+        List<Long> collectMoudleIds = planMoudleRelates.stream().filter(relate -> relate.getRelationType().equals("COLLECT_FLOW")).map(PlanTaskModuleRelate::getRelationId).collect(Collectors.toList());
+        Map<Long, String> collectMoudleMap = mongoTemplate.find(new Query().addCriteria(where("id").in(collectMoudleIds)), CollectModule.class)
+                .stream().collect(Collectors.toMap(CollectModule::getId, CollectModule::getName, (k1, k2) -> k2));
+        if (MapUtil.isNotEmpty(collectMoudleMap)) {
+            map.putAll(collectMoudleMap);
+        }
+
+        return map;
+    }
+
+    private List<UserArchiveMapping> queryArchiveMapping(List<PlanTaskDetails> planTaskDetails) {
+        List<String> patientCodes = planTaskDetails.stream().map(PlanTaskDetails::getPatientCode).collect(Collectors.toList());
+        Query archiveMappingquery = new Query();
+        archiveMappingquery.addCriteria(where("patientCode").in(patientCodes));
+        return mongoTemplate.find(archiveMappingquery, UserArchiveMapping.class);
+    }
+
+    private List<PlanTaskModuleRelate> queryPlanMoudleRelates(List<PlanTask> planTasks) {
+        List<Long> planTaskIds = planTasks.stream().map(PlanTask::getId).collect(Collectors.toList());
+        return mongoTemplate.find(new Query().addCriteria(where("planTaskId").in(planTaskIds)), PlanTaskModuleRelate.class);
+    }
+
+    private List<Site> querySites(List<UserArchiveMapping> userArchiveMappings) {
+        List<Long> siteIds = userArchiveMappings.stream().map(UserArchiveMapping::getSiteId).collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(siteIds)) {
+            return new ArrayList<>();
+        }
+        return mongoTemplate.find(new Query().addCriteria(where("id").in(siteIds)),
+                Site.class);
+    }
+
+    private List<Project> queryProjct(List<PlanTaskDetails> planTaskDetails) {
+        List<String> projectCodes = planTaskDetails.stream().map(PlanTaskDetails::getProjectCode).collect(Collectors.toList());
+        return mongoTemplate.find(new Query().addCriteria(where("code").in(projectCodes)), Project.class);
+    }
+
+    private List<Plan> queryPlans(List<PlanTask> planTasks) {
+        List<Long> planIds = planTasks.stream().map(PlanTask::getPlanId).collect(Collectors.toList());
+        return mongoTemplate.find(new Query().addCriteria(where("id").in(planIds)),
+                Plan.class);
+    }
+
+    private List<PlanTask> queryPlanTasks(List<PlanTaskDetails> planTaskDetails) {
+        List<Long> planTaskIds = planTaskDetails.stream().map(PlanTaskDetails::getPlanTaskId).collect(Collectors.toList());
+        return mongoTemplate.find(new Query().addCriteria(where("id").in(planTaskIds)),
+                PlanTask.class);
+    }
+
+    private List<UserArchive> queryArchive(List<UserArchiveMapping> userArchiveMappings) {
+        List<String> archiveIds = userArchiveMappings
+                .stream().map(UserArchiveMapping::getUserArchiveId).collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(archiveIds)) {
+            return new ArrayList<>();
+        }
+        return mongoArchiveTemplate.find(new Query().addCriteria(where("_id").in(archiveIds)),
+                UserArchive.class);
+    }
+}
diff --git a/src/main/java/com/luca/pilot/service/impl/PlanServiceImpl.java b/src/main/java/com/luca/pilot/service/impl/PlanServiceImpl.java
index 1691b66..2120ffb 100644
--- a/src/main/java/com/luca/pilot/service/impl/PlanServiceImpl.java
+++ b/src/main/java/com/luca/pilot/service/impl/PlanServiceImpl.java
@@ -49,7 +49,7 @@ public class PlanServiceImpl implements PlanService {
     @Override
     @Scheduled(cron ="0 0/1 * * * ?")
     public void synchronizePlanTask() {
-        log.info("--------------synchronizePlanTask start----------");
+        log.info("--------------zh-CN synchronizePlanTask start----------");
         String nowTime = parseTimeFromDateTime (LocalDateTime.now());
 
         SynchronizeTime synchronizeTime = findSynchronizeTime();
@@ -64,7 +64,7 @@ public class PlanServiceImpl implements PlanService {
             countQuery.addCriteria(where("lastModifiedAt").gt(lastSynchronizeTime));
         }
         long totalPlanTaskDetailsCount = mongoTemplate.count(countQuery, PlanTaskDetails.class);
-        log.info("PlanTaskDetails 鍦ㄥぇ浜� {} 鏃堕棿鍐呮湭鏌ヨ鍒版暟鎹� {} 鏉�", lastSynchronizeTime, totalPlanTaskDetailsCount);
+        log.info("zh-CN PlanTaskDetails 鍦ㄥぇ浜� {} 鏃堕棿鍐呮湭鏌ヨ鍒版暟鎹� {} 鏉�", lastSynchronizeTime, totalPlanTaskDetailsCount);
 
         if (totalPlanTaskDetailsCount == 0) {
             return;
@@ -85,7 +85,7 @@ public class PlanServiceImpl implements PlanService {
             countQuery.skip(i * 10000L);
             countQuery.limit(10000);
             List<PlanTaskDetails> planTaskDetails = mongoTemplate.find(countQuery, PlanTaskDetails.class);
-            log.info("绗瑊}娆℃煡璇� planTaskDetails count:{}", i + 1, planTaskDetails.size());
+            log.info("zh-CN 绗瑊}娆℃煡璇� planTaskDetails count:{}", i + 1, planTaskDetails.size());
             // 鑾峰彇瀵瑰簲妗f锛屽彇subjectId 鍜� randomId
             List<UserArchiveMapping> userArchiveMappings = queryArchiveMapping(planTaskDetails);
             List<UserArchive> userArchives = queryArchive(userArchiveMappings);
@@ -256,18 +256,18 @@ public class PlanServiceImpl implements PlanService {
 //                CompletableFuture.runAsync(() -> {
                     bulkOps.upsert(pairs);
                     bulkOps.execute();
-                    log.info("bulkOps 鏇存柊鎴栨彃鍏� {}  鏉℃暟鎹�", pairs.size());
+                    log.info("zh-CN bulkOps 鏇存柊鎴栨彃鍏� {}  鏉℃暟鎹�", pairs.size());
 //                });
             } else {
                 if (!CollectionUtils.isEmpty(planMoudles)) {
                     mongoTemplate.insert(planMoudles, PlanModule.class);
-                    log.info("mongoTemplate insert {} 鏉℃暟鎹� ", planMoudles.size());
+                    log.info("zh-CN mongoTemplate insert {} 鏉℃暟鎹� ", planMoudles.size());
                 }
             }
 
         }
 
-        log.info("synchronizePlanTask end, 鑰楁椂:{} 绉�", LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) -
+        log.info("zh-CN synchronizePlanTask end, 鑰楁椂:{} 绉�", LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) -
                 LocalDateTime.parse(nowTime, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")).toEpochSecond(ZoneOffset.of("+8")));
 
     }
diff --git a/src/main/resources/application-hj.yml b/src/main/resources/application-hj.yml
index afb4d3e..f1ac565 100644
--- a/src/main/resources/application-hj.yml
+++ b/src/main/resources/application-hj.yml
@@ -5,7 +5,8 @@ SERVER-PORT: 8181
 MGDB-ADDRESS: 47.92.245.13:30606
 MGDB-NAME: root
 MGDB-PASSWORD: 123456
-MGDB-DATABASE: luca-mysql-copy-en-US
+MGDB-DATABASE: luca-mysql-copy-zh-CN
+ENUS-MGDB-DATABASE: luca-mysql-copy-en-US
 #MGDB-DATABASE: luca-copy-uat
 MGDB-AUTHSOURCE: admin
 
diff --git a/src/main/resources/application-uat.yml b/src/main/resources/application-uat.yml
index c984d1b..5a5b84c 100644
--- a/src/main/resources/application-uat.yml
+++ b/src/main/resources/application-uat.yml
@@ -5,7 +5,8 @@ SERVER-PORT: 8181
 MGDB-ADDRESS: mongo.luca-common:27017
 MGDB-NAME: root
 MGDB-PASSWORD: 123456
-MGDB-DATABASE: luca-mysql-copy-en-US
+MGDB-DATABASE: luca-mysql-copy-zh-CN
+ENUS-MGDB-DATABASE: luca-mysql-copy-en-US
 MGDB-AUTHSOURCE: admin
 
 ARCHIVE-MGDB-DATABASE: luca_uat
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 5026fde..ddc1fcb 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -11,5 +11,7 @@ spring:
       uri: mongodb://${MGDB-NAME}:${MGDB-PASSWORD}@${MGDB-ADDRESS}/${MGDB-DATABASE}?authSource=${MGDB-AUTHSOURCE}
     archive-mongodb:
       uri: mongodb://${MGDB-NAME}:${MGDB-PASSWORD}@${MGDB-ADDRESS}/${ARCHIVE-MGDB-DATABASE}?authSource=${MGDB-AUTHSOURCE}
+    en-us-mongodb:
+      uri: mongodb://${MGDB-NAME}:${MGDB-PASSWORD}@${MGDB-ADDRESS}/${ENUS-MGDB-DATABASE}?authSource=${MGDB-AUTHSOURCE}
 
 
diff --git a/src/test/java/com/luca/pilot/PlanTaskTest.java b/src/test/java/com/luca/pilot/PlanTaskTest.java
index f2b58c9..4341fc1 100644
--- a/src/test/java/com/luca/pilot/PlanTaskTest.java
+++ b/src/test/java/com/luca/pilot/PlanTaskTest.java
@@ -1,6 +1,7 @@
 package com.luca.pilot;
 
 import com.luca.pilot.entity.UserArchive;
+import com.luca.pilot.service.EnUsPlanService;
 import com.luca.pilot.service.PlanService;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
@@ -23,6 +24,9 @@ public class PlanTaskTest {
     @Autowired
     private PlanService planService;
 
+    @Autowired
+    private EnUsPlanService enUsPlanService;
+
 
     @Test
     void synchronizePlanTask2() {
@@ -50,9 +54,13 @@ public class PlanTaskTest {
 
 
     @Test
-    void synchronizePlanTask() {
+    void synchronizePlanTaskZhCn() {
         planService.synchronizePlanTask();
     }
+    @Test
+    void synchronizePlanTaskEnUs() {
+        enUsPlanService.synchronizePlanTask();
+    }
 
     @Test
     void contextLoads() {
-- 
GitLab