From 840a0b1b82cfab7de0e8d7cb94153b977551cb3b Mon Sep 17 00:00:00 2001
From: huangjin <huangjin@lucahealthcare.com>
Date: Fri, 30 Aug 2024 10:06:56 +0800
Subject: [PATCH] uat

---
 .gitignore                                    |  33 +
 .idea/misc.xml                                |  10 +-
 .idea/modules.xml                             |   8 -
 mvnw                                          | 259 +++++++
 pom.xml                                       |  93 +++
 .../java/com/luca/pilot/PilotApplication.java |  16 +
 .../pilot/bizEnum/CrfQuestionTypeEnum.java    |  42 ++
 .../com/luca/pilot/bizEnum/TableEnum.java     |  54 ++
 .../java/com/luca/pilot/bo/BindDataBo.java    |  18 +
 .../com/luca/pilot/bo/CrfJsonValueBo.java     |  21 +
 .../com/luca/pilot/bo/CrfJsonValueKeyBo.java  |  22 +
 .../java/com/luca/pilot/bo/CrfProblemBo.java  |  26 +
 .../luca/pilot/bo/CrfTableJsonTopicBo.java    |  20 +
 .../config/MongoArchiveTemplateConfig.java    |  37 +
 .../pilot/config/MongoBaseTemplateConfig.java |  39 ++
 .../pilot/entity/AbstractAuditingEntity.java  |  35 +
 .../com/luca/pilot/entity/BaseModuleView.java |  63 ++
 .../pilot/entity/ClinicalTrialsEvent.java     |  92 +++
 .../com/luca/pilot/entity/CollectModule.java  |  88 +++
 src/main/java/com/luca/pilot/entity/Crf.java  |  40 ++
 .../java/com/luca/pilot/entity/CrfAnswer.java |  70 ++
 .../pilot/entity/DigitalMedicalDetails.java   |  78 +++
 .../com/luca/pilot/entity/ModuleEntity.java   |  51 ++
 .../entity/PatientScaleEvaluatingEntity.java  |  44 ++
 src/main/java/com/luca/pilot/entity/Plan.java |  91 +++
 .../com/luca/pilot/entity/PlanModule.java     |  84 +++
 .../java/com/luca/pilot/entity/PlanTask.java  | 157 +++++
 .../luca/pilot/entity/PlanTaskDetails.java    | 100 +++
 .../pilot/entity/PlanTaskDetailsModule.java   |  62 ++
 .../pilot/entity/PlanTaskModuleRelate.java    |  51 ++
 .../java/com/luca/pilot/entity/Project.java   |  95 +++
 .../com/luca/pilot/entity/Questionnaire.java  |  43 ++
 .../pilot/entity/QuestionnaireAnswer.java     |  68 ++
 .../entity/QuestionnaireAnswerOption.java     |  55 ++
 .../entity/QuestionnaireAnswerRecord.java     |  56 ++
 .../entity/ScaleModuleDetailsEntity.java      |  33 +
 .../luca/pilot/entity/ScaleModuleEntity.java  |  29 +
 src/main/java/com/luca/pilot/entity/Site.java |  89 +++
 .../luca/pilot/entity/SynchronizeTime.java    |  14 +
 .../com/luca/pilot/entity/UserArchive.java    | 207 ++++++
 .../luca/pilot/entity/UserArchiveMapping.java |  33 +
 .../pilot/service/BaseModuleViewService.java  |  10 +
 .../com/luca/pilot/service/PlanService.java   |  10 +
 .../impl/BaseModuleViewServiceImpl.java       |  57 ++
 .../pilot/service/impl/PlanServiceImpl.java   | 643 ++++++++++++++++++
 .../java/com/luca/pilot/util/CrfUtil.java     | 228 +++++++
 src/main/resources/application-dev.yml        |  11 +
 src/main/resources/application-hj.yml         |  15 +
 src/main/resources/application-uat.yml        |  13 +
 src/main/resources/application.yml            |  15 +
 .../com/luca/pilot/PilotApplicationTests.java |  13 +
 .../java/com/luca/pilot/PlanTaskTest.java     |  90 +++
 52 files changed, 3622 insertions(+), 9 deletions(-)
 create mode 100644 .gitignore
 delete mode 100644 .idea/modules.xml
 create mode 100644 mvnw
 create mode 100644 pom.xml
 create mode 100644 src/main/java/com/luca/pilot/PilotApplication.java
 create mode 100644 src/main/java/com/luca/pilot/bizEnum/CrfQuestionTypeEnum.java
 create mode 100644 src/main/java/com/luca/pilot/bizEnum/TableEnum.java
 create mode 100644 src/main/java/com/luca/pilot/bo/BindDataBo.java
 create mode 100644 src/main/java/com/luca/pilot/bo/CrfJsonValueBo.java
 create mode 100644 src/main/java/com/luca/pilot/bo/CrfJsonValueKeyBo.java
 create mode 100644 src/main/java/com/luca/pilot/bo/CrfProblemBo.java
 create mode 100644 src/main/java/com/luca/pilot/bo/CrfTableJsonTopicBo.java
 create mode 100644 src/main/java/com/luca/pilot/config/MongoArchiveTemplateConfig.java
 create mode 100644 src/main/java/com/luca/pilot/config/MongoBaseTemplateConfig.java
 create mode 100644 src/main/java/com/luca/pilot/entity/AbstractAuditingEntity.java
 create mode 100644 src/main/java/com/luca/pilot/entity/BaseModuleView.java
 create mode 100644 src/main/java/com/luca/pilot/entity/ClinicalTrialsEvent.java
 create mode 100644 src/main/java/com/luca/pilot/entity/CollectModule.java
 create mode 100644 src/main/java/com/luca/pilot/entity/Crf.java
 create mode 100644 src/main/java/com/luca/pilot/entity/CrfAnswer.java
 create mode 100644 src/main/java/com/luca/pilot/entity/DigitalMedicalDetails.java
 create mode 100644 src/main/java/com/luca/pilot/entity/ModuleEntity.java
 create mode 100644 src/main/java/com/luca/pilot/entity/PatientScaleEvaluatingEntity.java
 create mode 100644 src/main/java/com/luca/pilot/entity/Plan.java
 create mode 100644 src/main/java/com/luca/pilot/entity/PlanModule.java
 create mode 100644 src/main/java/com/luca/pilot/entity/PlanTask.java
 create mode 100644 src/main/java/com/luca/pilot/entity/PlanTaskDetails.java
 create mode 100644 src/main/java/com/luca/pilot/entity/PlanTaskDetailsModule.java
 create mode 100644 src/main/java/com/luca/pilot/entity/PlanTaskModuleRelate.java
 create mode 100644 src/main/java/com/luca/pilot/entity/Project.java
 create mode 100644 src/main/java/com/luca/pilot/entity/Questionnaire.java
 create mode 100644 src/main/java/com/luca/pilot/entity/QuestionnaireAnswer.java
 create mode 100644 src/main/java/com/luca/pilot/entity/QuestionnaireAnswerOption.java
 create mode 100644 src/main/java/com/luca/pilot/entity/QuestionnaireAnswerRecord.java
 create mode 100644 src/main/java/com/luca/pilot/entity/ScaleModuleDetailsEntity.java
 create mode 100644 src/main/java/com/luca/pilot/entity/ScaleModuleEntity.java
 create mode 100644 src/main/java/com/luca/pilot/entity/Site.java
 create mode 100644 src/main/java/com/luca/pilot/entity/SynchronizeTime.java
 create mode 100644 src/main/java/com/luca/pilot/entity/UserArchive.java
 create mode 100644 src/main/java/com/luca/pilot/entity/UserArchiveMapping.java
 create mode 100644 src/main/java/com/luca/pilot/service/BaseModuleViewService.java
 create mode 100644 src/main/java/com/luca/pilot/service/PlanService.java
 create mode 100644 src/main/java/com/luca/pilot/service/impl/BaseModuleViewServiceImpl.java
 create mode 100644 src/main/java/com/luca/pilot/service/impl/PlanServiceImpl.java
 create mode 100644 src/main/java/com/luca/pilot/util/CrfUtil.java
 create mode 100644 src/main/resources/application-dev.yml
 create mode 100644 src/main/resources/application-hj.yml
 create mode 100644 src/main/resources/application-uat.yml
 create mode 100644 src/main/resources/application.yml
 create mode 100644 src/test/java/com/luca/pilot/PilotApplicationTests.java
 create mode 100644 src/test/java/com/luca/pilot/PlanTaskTest.java

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 639900d..accd629 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,14 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
-  <component name="ProjectRootManager">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/out" />
   </component>
 </project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
deleted file mode 100644
index fa1044b..0000000
--- a/.idea/modules.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project version="4">
-  <component name="ProjectModuleManager">
-    <modules>
-      <module fileurl="file://$PROJECT_DIR$/.idea/ai-chat-pilot.iml" filepath="$PROJECT_DIR$/.idea/ai-chat-pilot.iml" />
-    </modules>
-  </component>
-</project>
\ No newline at end of file
diff --git a/mvnw b/mvnw
new file mode 100644
index 0000000..d7c358e
--- /dev/null
+++ b/mvnw
@@ -0,0 +1,259 @@
+#!/bin/sh
+# ----------------------------------------------------------------------------
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#    https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+# ----------------------------------------------------------------------------
+
+# ----------------------------------------------------------------------------
+# Apache Maven Wrapper startup batch script, version 3.3.2
+#
+# Optional ENV vars
+# -----------------
+#   JAVA_HOME - location of a JDK home dir, required when download maven via java source
+#   MVNW_REPOURL - repo url base for downloading maven distribution
+#   MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven
+#   MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output
+# ----------------------------------------------------------------------------
+
+set -euf
+[ "${MVNW_VERBOSE-}" != debug ] || set -x
+
+# OS specific support.
+native_path() { printf %s\\n "$1"; }
+case "$(uname)" in
+CYGWIN* | MINGW*)
+  [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")"
+  native_path() { cygpath --path --windows "$1"; }
+  ;;
+esac
+
+# set JAVACMD and JAVACCMD
+set_java_home() {
+  # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched
+  if [ -n "${JAVA_HOME-}" ]; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ]; then
+      # IBM's JDK on AIX uses strange locations for the executables
+      JAVACMD="$JAVA_HOME/jre/sh/java"
+      JAVACCMD="$JAVA_HOME/jre/sh/javac"
+    else
+      JAVACMD="$JAVA_HOME/bin/java"
+      JAVACCMD="$JAVA_HOME/bin/javac"
+
+      if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then
+        echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2
+        echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2
+        return 1
+      fi
+    fi
+  else
+    JAVACMD="$(
+      'set' +e
+      'unset' -f command 2>/dev/null
+      'command' -v java
+    )" || :
+    JAVACCMD="$(
+      'set' +e
+      'unset' -f command 2>/dev/null
+      'command' -v javac
+    )" || :
+
+    if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then
+      echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2
+      return 1
+    fi
+  fi
+}
+
+# hash string like Java String::hashCode
+hash_string() {
+  str="${1:-}" h=0
+  while [ -n "$str" ]; do
+    char="${str%"${str#?}"}"
+    h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296))
+    str="${str#?}"
+  done
+  printf %x\\n $h
+}
+
+verbose() { :; }
+[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; }
+
+die() {
+  printf %s\\n "$1" >&2
+  exit 1
+}
+
+trim() {
+  # MWRAPPER-139:
+  #   Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds.
+  #   Needed for removing poorly interpreted newline sequences when running in more
+  #   exotic environments such as mingw bash on Windows.
+  printf "%s" "${1}" | tr -d '[:space:]'
+}
+
+# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties
+while IFS="=" read -r key value; do
+  case "${key-}" in
+  distributionUrl) distributionUrl=$(trim "${value-}") ;;
+  distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;;
+  esac
+done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties"
+[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties"
+
+case "${distributionUrl##*/}" in
+maven-mvnd-*bin.*)
+  MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/
+  case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in
+  *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;;
+  :Darwin*x86_64) distributionPlatform=darwin-amd64 ;;
+  :Darwin*arm64) distributionPlatform=darwin-aarch64 ;;
+  :Linux*x86_64*) distributionPlatform=linux-amd64 ;;
+  *)
+    echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2
+    distributionPlatform=linux-amd64
+    ;;
+  esac
+  distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip"
+  ;;
+maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;;
+*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;;
+esac
+
+# apply MVNW_REPOURL and calculate MAVEN_HOME
+# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-<version>,maven-mvnd-<version>-<platform>}/<hash>
+[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}"
+distributionUrlName="${distributionUrl##*/}"
+distributionUrlNameMain="${distributionUrlName%.*}"
+distributionUrlNameMain="${distributionUrlNameMain%-bin}"
+MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}"
+MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")"
+
+exec_maven() {
+  unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || :
+  exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD"
+}
+
+if [ -d "$MAVEN_HOME" ]; then
+  verbose "found existing MAVEN_HOME at $MAVEN_HOME"
+  exec_maven "$@"
+fi
+
+case "${distributionUrl-}" in
+*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;;
+*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;;
+esac
+
+# prepare tmp dir
+if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then
+  clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; }
+  trap clean HUP INT TERM EXIT
+else
+  die "cannot create temp dir"
+fi
+
+mkdir -p -- "${MAVEN_HOME%/*}"
+
+# Download and Install Apache Maven
+verbose "Couldn't find MAVEN_HOME, downloading and installing it ..."
+verbose "Downloading from: $distributionUrl"
+verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName"
+
+# select .zip or .tar.gz
+if ! command -v unzip >/dev/null; then
+  distributionUrl="${distributionUrl%.zip}.tar.gz"
+  distributionUrlName="${distributionUrl##*/}"
+fi
+
+# verbose opt
+__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR=''
+[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v
+
+# normalize http auth
+case "${MVNW_PASSWORD:+has-password}" in
+'') MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;;
+esac
+
+if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then
+  verbose "Found wget ... using wget"
+  wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl"
+elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then
+  verbose "Found curl ... using curl"
+  curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl"
+elif set_java_home; then
+  verbose "Falling back to use Java to download"
+  javaSource="$TMP_DOWNLOAD_DIR/Downloader.java"
+  targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName"
+  cat >"$javaSource" <<-END
+	public class Downloader extends java.net.Authenticator
+	{
+	  protected java.net.PasswordAuthentication getPasswordAuthentication()
+	  {
+	    return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() );
+	  }
+	  public static void main( String[] args ) throws Exception
+	  {
+	    setDefault( new Downloader() );
+	    java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() );
+	  }
+	}
+	END
+  # For Cygwin/MinGW, switch paths to Windows format before running javac and java
+  verbose " - Compiling Downloader.java ..."
+  "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java"
+  verbose " - Running Downloader.java ..."
+  "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")"
+fi
+
+# If specified, validate the SHA-256 sum of the Maven distribution zip file
+if [ -n "${distributionSha256Sum-}" ]; then
+  distributionSha256Result=false
+  if [ "$MVN_CMD" = mvnd.sh ]; then
+    echo "Checksum validation is not supported for maven-mvnd." >&2
+    echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+    exit 1
+  elif command -v sha256sum >/dev/null; then
+    if echo "$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then
+      distributionSha256Result=true
+    fi
+  elif command -v shasum >/dev/null; then
+    if echo "$distributionSha256Sum  $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then
+      distributionSha256Result=true
+    fi
+  else
+    echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2
+    echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2
+    exit 1
+  fi
+  if [ $distributionSha256Result = false ]; then
+    echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2
+    echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2
+    exit 1
+  fi
+fi
+
+# unzip and move
+if command -v unzip >/dev/null; then
+  unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip"
+else
+  tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar"
+fi
+printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url"
+mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME"
+
+clean || :
+exec_maven "$@"
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..53b403f
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.3.2.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+
+    <!-- Generated by https://start.springboot.io -->
+    <!-- 优质的 spring/boot/data/security/cloud 框架中文文档尽在 => https://springdoc.cn -->
+    <groupId>com.luca</groupId>
+    <artifactId>pilot</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>pilot</name>
+    <description>pilot data clean</description>
+    <url/>
+    <licenses>
+        <license/>
+    </licenses>
+    <developers>
+        <developer/>
+    </developers>
+    <scm>
+        <connection/>
+        <developerConnection/>
+        <tag/>
+        <url/>
+    </scm>
+    <properties>
+        <java.version>11</java.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.data</groupId>
+            <artifactId>spring-data-jpa</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.7.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.76</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/src/main/java/com/luca/pilot/PilotApplication.java b/src/main/java/com/luca/pilot/PilotApplication.java
new file mode 100644
index 0000000..f511a0d
--- /dev/null
+++ b/src/main/java/com/luca/pilot/PilotApplication.java
@@ -0,0 +1,16 @@
+package com.luca.pilot;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+
+@SpringBootApplication
+@EnableScheduling
+public class PilotApplication {
+
+	public static void main(String[] args) {
+		SpringApplication.run(PilotApplication.class, args);
+	}
+
+}
diff --git a/src/main/java/com/luca/pilot/bizEnum/CrfQuestionTypeEnum.java b/src/main/java/com/luca/pilot/bizEnum/CrfQuestionTypeEnum.java
new file mode 100644
index 0000000..5a17f72
--- /dev/null
+++ b/src/main/java/com/luca/pilot/bizEnum/CrfQuestionTypeEnum.java
@@ -0,0 +1,42 @@
+package com.luca.pilot.bizEnum;
+
+import cn.hutool.core.util.ObjectUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @Classname CrfQuestionTypeEnum
+ * @Description TODO
+ * @Date 2023/7/18 10:29
+ * @Created by 范宇坤
+ */
+@Getter
+@AllArgsConstructor
+public enum CrfQuestionTypeEnum {
+
+    CUSTOMIZE("CUSTOMIZE", "意外类型"),
+    TEMPLATE("TEMPLATE", "外层框架"),
+    REGULAR("REGULAR", "固定结构"),
+    TEXT("TEXT", "输入框"),
+    TEXTAREA("TEXTAREA", "多行输入框"),
+    NUMBER("NUMBER", "数值"),
+    DATE("DATE", "日期选择"),
+    SELECT("SELECT", "下拉单选"),
+    RADIO("RADIO", "点击单选"),
+    MUTISELECT("MUTISELECT", "下拉多选"),
+    CRFTABLE("CRFTABLE", "矩阵填空"),
+    CASCADER("CASCADER", "级联选择"),
+    ;
+
+    private String code;
+    private String desc;
+
+    public static CrfQuestionTypeEnum getDeviceEnum(String code) {
+        for (CrfQuestionTypeEnum value : CrfQuestionTypeEnum.values()) {
+            if (ObjectUtil.equal(value.code, code)) {
+                return value;
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/main/java/com/luca/pilot/bizEnum/TableEnum.java b/src/main/java/com/luca/pilot/bizEnum/TableEnum.java
new file mode 100644
index 0000000..b95133c
--- /dev/null
+++ b/src/main/java/com/luca/pilot/bizEnum/TableEnum.java
@@ -0,0 +1,54 @@
+package com.luca.pilot.bizEnum;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum TableEnum {
+
+    armOutstretched("armOutstretched", "clinical_trials_arm_outstretched"),
+    bodyPosturalTremorMiddle("bodyPosturalTremorMiddle", "clinical_trials_body_postural_tremor_middle"),
+    bodyPosturalTremorMiddleBlind("bodyPosturalTremorMiddleBlind", "clinical_trials_body_postural_tremor_middle_blind"),
+    seatedSteppingLeft("seatedSteppingLeft", "clinical_trials_foot_tap_seated_left"),
+    seatedSteppingRight("seatedSteppingRight", "clinical_trials_foot_tap_seated_right"),
+    gaitStability("gaitStability", "clinical_trials_gait_and_balance"),
+    gaitUTurn("gaitUTurn", "clinical_trials_gait_u_turn"),
+    handKineticTremorLeft("handKineticTremorLeft", "clinical_trials_hand_kinetic_tremor_left"),
+    handKineticTremorRight("handKineticTremorRight", "clinical_trials_hand_kinetic_tremor_right"),
+    handPosturalTremorLeft("handPosturalTremorLeft", "clinical_trials_hand_postural_tremor_left"),
+    handPosturalTremorRight("handPosturalTremorRight", "clinical_trials_hand_postural_tremor_right"),
+    handRestTremorLeft("handRestTremorLeft", "clinical_trials_hand_rest_tremor_left"),
+    handRestTremorRight("handRestTremorRight", "clinical_trials_hand_rest_tremor_right"),
+    indexFingerTappingTwoTargetLeft("indexFingerTappingTwoTargetLeft", "clinical_trials_index_finger_tap_two_target_left"),
+    indexFingerTappingTwoTargetRight("indexFingerTappingTwoTargetRight", "clinical_trials_index_finger_tap_two_target_right"),
+    indexFingerTappingOneTargetLeft("indexFingerTappingOneTargetLeft", "clinical_trials_index_finger_tapping_one_target_left"),
+    indexFingerTappingOneTargetRight("indexFingerTappingOneTargetRight", "clinical_trials_index_finger_tapping_one_target_right"),
+    legRestTremorLeft("legRestTremorLeft", "clinical_trials_leg_rest_tremor_left"),
+    legRestTremorRight("legRestTremorRight", "clinical_trials_leg_rest_tremor_right"),
+    mci("mci", "clinical_trials_mci"),
+    handPronationSupinationLeft("handPronationSupinationLeft", "clinical_trials_palm_flip_left"),
+    handPronationSupinationRight("handPronationSupinationRight", "clinical_trials_palm_flip_right"),
+    sitToStand30s("sitToStand30s", "clinical_trials_sit_to_stand_by_thirty"),
+    tremor("tremor", "clinical_trials_tremor_detection"),
+    twoFingerTappingTwoTargetLeft("twoFingerTappingTwoTargetLeft", "clinical_trials_two_finger_tapping_two_target_left"),
+    twoFingerTappingTwoTargetRight("twoFingerTappingTwoTargetRight", "clinical_trials_two_finger_tapping_two_target_right"),
+    vision("vision", "clinical_trials_vision"),
+    visionColorBlindnessType("visionColorBlindnessType", "clinical_trials_vision_color_blindness_type"),
+    visionContrastSensitivity("visionContrastSensitivity", "clinical_trials_vision_contrast_sensitivity"),
+    visionEsdmt("visionEsdmt", "clinical_trials_vision_esdmt"),
+    visionVibrationSensitivity("visionVibrationSensitivity", "clinical_trials_vision_vibration_sensitivity"),
+    ;
+
+    private final String moudleItemType;
+    private final String tableName;
+
+    public static String getTableNameByType(String type) {
+        for (TableEnum value : TableEnum.values()) {
+            if (value.getMoudleItemType().equals(type)) {
+                return value.getTableName();
+            }
+        }
+        return null;
+    }
+}
diff --git a/src/main/java/com/luca/pilot/bo/BindDataBo.java b/src/main/java/com/luca/pilot/bo/BindDataBo.java
new file mode 100644
index 0000000..7f0722d
--- /dev/null
+++ b/src/main/java/com/luca/pilot/bo/BindDataBo.java
@@ -0,0 +1,18 @@
+package com.luca.pilot.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @Classname BindDataBo
+ * @Description TODO
+ * @Date 2023/7/18 10:37
+ * @Created by 范宇坤
+ */
+@Data
+@Accessors(chain = true)
+public class BindDataBo {
+    private String dataType;
+    private String choiceField;
+    private String dataId;
+}
diff --git a/src/main/java/com/luca/pilot/bo/CrfJsonValueBo.java b/src/main/java/com/luca/pilot/bo/CrfJsonValueBo.java
new file mode 100644
index 0000000..369cbd4
--- /dev/null
+++ b/src/main/java/com/luca/pilot/bo/CrfJsonValueBo.java
@@ -0,0 +1,21 @@
+package com.luca.pilot.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @Classname CrfJsonValueBo
+ * @Description TODO
+ * @Date 2023/7/17 18:17
+ * @Created by 范宇坤
+ */
+@Data
+@Accessors(chain = true)
+public class CrfJsonValueBo {
+
+    private String key;
+    private String keyPrefix;
+    private String name;
+    private String value;
+    private String text;
+}
diff --git a/src/main/java/com/luca/pilot/bo/CrfJsonValueKeyBo.java b/src/main/java/com/luca/pilot/bo/CrfJsonValueKeyBo.java
new file mode 100644
index 0000000..e1a12b4
--- /dev/null
+++ b/src/main/java/com/luca/pilot/bo/CrfJsonValueKeyBo.java
@@ -0,0 +1,22 @@
+package com.luca.pilot.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @Classname CrfJsonValueBo
+ * @Description TODO
+ * @Date 2023/7/17 18:17
+ * @Created by 范宇坤
+ */
+@Data
+@Accessors(chain = true)
+public class CrfJsonValueKeyBo {
+
+    private String id;
+    private String keyPrefix;
+    private String title;
+    private String value;
+    private String colKey;
+    private String colName;
+}
diff --git a/src/main/java/com/luca/pilot/bo/CrfProblemBo.java b/src/main/java/com/luca/pilot/bo/CrfProblemBo.java
new file mode 100644
index 0000000..ec6c0bd
--- /dev/null
+++ b/src/main/java/com/luca/pilot/bo/CrfProblemBo.java
@@ -0,0 +1,26 @@
+package com.luca.pilot.bo;
+
+import com.luca.pilot.bizEnum.CrfQuestionTypeEnum;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @Classname CrfProblemBo
+ * @Description TODO
+ * @Date 2023/7/18 10:37
+ * @Created by 范宇坤
+ */
+@Data
+@Accessors(chain = true)
+public class CrfProblemBo {
+
+    private String title;
+
+    private String key;
+
+    private CrfQuestionTypeEnum questionType;
+
+    private BindDataBo dataBo;
+
+    private String properties;
+}
diff --git a/src/main/java/com/luca/pilot/bo/CrfTableJsonTopicBo.java b/src/main/java/com/luca/pilot/bo/CrfTableJsonTopicBo.java
new file mode 100644
index 0000000..0f491d4
--- /dev/null
+++ b/src/main/java/com/luca/pilot/bo/CrfTableJsonTopicBo.java
@@ -0,0 +1,20 @@
+package com.luca.pilot.bo;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @Classname CrfTableJsonTopicBo
+ * @Description TODO
+ * @Date 2023/7/20 13:58
+ * @Created by 范宇坤
+ */
+@Data
+@Accessors(chain = true)
+public class CrfTableJsonTopicBo {
+
+    private String id;
+    private String title;
+    private String dataIndex;
+    private String type;
+}
diff --git a/src/main/java/com/luca/pilot/config/MongoArchiveTemplateConfig.java b/src/main/java/com/luca/pilot/config/MongoArchiveTemplateConfig.java
new file mode 100644
index 0000000..18998d4
--- /dev/null
+++ b/src/main/java/com/luca/pilot/config/MongoArchiveTemplateConfig.java
@@ -0,0 +1,37 @@
+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;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+/**
+ * @author Wong
+ * @date 2024/1/6 14:17
+ */
+@Slf4j
+@Configuration
+@EnableMongoRepositories(mongoTemplateRef = "mongoArchiveTemplate")
+public class MongoArchiveTemplateConfig {
+
+    @Value("${spring.data.archive-mongodb.uri}")
+    private String uri;
+
+    @Bean(name = "mongoArchiveTemplate")
+    public MongoTemplate mongoECrfTemplate() {
+        log.info("-----------------------Backend Init MongoECrfTemplate Success-----------------------------------");
+        return new MongoTemplate(mongoECrfFactory());
+    }
+
+    @Bean
+    public MongoDatabaseFactory mongoECrfFactory() {
+        SimpleMongoClientDatabaseFactory simpleMongoClientDbFactory = new SimpleMongoClientDatabaseFactory(uri);
+        return simpleMongoClientDbFactory;
+    }
+
+}
diff --git a/src/main/java/com/luca/pilot/config/MongoBaseTemplateConfig.java b/src/main/java/com/luca/pilot/config/MongoBaseTemplateConfig.java
new file mode 100644
index 0000000..e2ff090
--- /dev/null
+++ b/src/main/java/com/luca/pilot/config/MongoBaseTemplateConfig.java
@@ -0,0 +1,39 @@
+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;
+import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
+
+/**
+ * @author Wong
+ * @date 2024/1/6 14:17
+ */
+@Slf4j
+@Configuration
+//@EnableMongoRepositories(basePackages = "com.luca.pilot.entity")
+public class MongoBaseTemplateConfig {
+
+    @Value("${spring.data.base-mongodb.uri}")
+    private String uri;
+
+    @Primary
+    @Bean(name = "mongoTemplate")
+    public MongoTemplate mongoBaseTemplate() {
+        log.info("-----------------------Backend Init MongoBaseTemplate Success -----------------------------------");
+        return new MongoTemplate(mongoBaseFactory());
+    }
+
+    @Bean
+    @Primary
+    public MongoDatabaseFactory mongoBaseFactory() {
+        SimpleMongoClientDatabaseFactory simpleMongoClientDbFactory = new SimpleMongoClientDatabaseFactory(uri);
+        return simpleMongoClientDbFactory;
+    }
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/AbstractAuditingEntity.java b/src/main/java/com/luca/pilot/entity/AbstractAuditingEntity.java
new file mode 100644
index 0000000..e13fd16
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/AbstractAuditingEntity.java
@@ -0,0 +1,35 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import org.springframework.data.mongodb.core.mapping.Field;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * Base abstract class for entities which will hold definitions for created, last modified by date.
+ */
+@Data
+public abstract class AbstractAuditingEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @Field("created_by")
+    private String createdBy;
+
+    @Field("created_at")
+    private String createdAt;
+
+    @Field("last_modified_by")
+    private String lastModifiedBy;
+
+    @Field("last_modified_at")
+    private String lastModifiedAt;
+
+    /**
+     * 删除标记(false:未删除 true:已删除)
+     */
+    private boolean deleted = false;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/BaseModuleView.java b/src/main/java/com/luca/pilot/entity/BaseModuleView.java
new file mode 100644
index 0000000..f041064
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/BaseModuleView.java
@@ -0,0 +1,63 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+@Data
+@Accessors(chain = true)
+@Document(collection = "base_module_view")
+public class BaseModuleView {
+
+    private Long id;
+
+    @Field("tenant_id")
+    private Long tenantId;
+
+    private String name;
+
+    @Field("module_item_type")
+    private String moduleItemType;
+
+    private Integer status;
+
+    @Field("module_code")
+    private String moduleCode;
+
+    @Field("module_enabled")
+    private Boolean moduleEnabled;
+
+    @Field("module_type")
+    private String moduleType;
+
+    @Field("project_code")
+    private String projectCode;
+
+    @Field("project_enabled")
+    private Boolean projectEnabled;
+
+    @Field("collect_type")
+    private String collectType;
+
+    @Field("local_algorithm")
+    private String localAlgorithm;
+
+    @Field("supplement_img_url")
+    private String supplementImgUrl;
+
+    @Field("supplement_media_url")
+    private String supplementMediaUrl;
+
+    @Field("collect_duration")
+    private String collectDuration;
+
+    @Field("description")
+    private String description;
+
+    private String deleted;
+
+    @Field("created_at")
+    private String createdAt;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/ClinicalTrialsEvent.java b/src/main/java/com/luca/pilot/entity/ClinicalTrialsEvent.java
new file mode 100644
index 0000000..66a0f9d
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/ClinicalTrialsEvent.java
@@ -0,0 +1,92 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author Wong
+ * @since 2023-11-30
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Document("clinical_trials_event")
+public class ClinicalTrialsEvent extends AbstractAuditingEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    /**
+     * 项目Code
+     */
+    private String projectCode;
+
+    /**
+     * uaa用户id
+     */
+    private Long uaaUserId;
+
+    /**
+     * DBM-事件id
+     */
+    @Field("event_id")
+    private Long eventId;
+
+    /**
+     * 计划任务id
+     */
+    @Field("plan_details_id")
+    private Long planDetailsId;
+
+    /**
+     * 关联模块分类(例如: DIGITAL_MEDICAL/COLLECT_FLOW)
+     */
+    @Field("relation_type")
+    private String relationType;
+
+    /**
+     * 关联模块id
+     */
+    @Field("relation_id")
+    private Long relationId;
+
+    /**
+     * 模块项类型 (例如: sitToStand/collect_module)
+     */
+    @Field("module_item_type")
+    private String moduleItemType;
+
+    /**
+     * 科研采集 - 采集类型
+     */
+    @Field("collect_type")
+    private String collectType;
+
+    /**
+     * 科研采集 - 本地算法
+     */
+    private String localAlgorithm;
+
+    /**
+     * 开始时间
+     */
+    private String startTime;
+
+    /**
+     * 完成时间
+     */
+    private String finishTime;
+
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/CollectModule.java b/src/main/java/com/luca/pilot/entity/CollectModule.java
new file mode 100644
index 0000000..43ecb7a
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/CollectModule.java
@@ -0,0 +1,88 @@
+package com.luca.pilot.entity;
+
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 科研采集信息表
+ * </p>
+ *
+ * @author linfeng.yang
+ * @since 2023-06-13
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Document("collect_module")
+public class CollectModule extends AbstractAuditingEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    /**
+     * 租户ID
+     */
+    private Long tenantId;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 编码
+     */
+    private String code;
+
+    /**
+     * 采集类型
+     */
+    private String collectType;
+
+    /**
+     * 采集时长
+     */
+    private Integer collectDuration;
+
+    /**
+     * 本地算法
+     */
+    private String localAlgorithm;
+
+    /**
+     * 示例媒体文件URL
+     */
+    private String mediaUrl;
+
+    /**
+     * 示例媒体文件前端使用
+     */
+    private String audioMinioPath;
+
+    /**
+     * 描述
+     */
+    private String description;
+
+    /**
+     * 图片地址
+     */
+    private String imgUrl;
+
+    /**
+     * 是否计时 0或者null 否 1 是
+     */
+    private String isTime;
+
+    /**
+     * 计时时间
+     */
+    private String time;
+
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/Crf.java b/src/main/java/com/luca/pilot/entity/Crf.java
new file mode 100644
index 0000000..7015eb9
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/Crf.java
@@ -0,0 +1,40 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author linfeng.yang
+ * @since 2021-11-24
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document("crf")
+public class Crf extends AbstractAuditingEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String name;
+
+    private String description;
+
+    private Long sourceId;
+
+    @Field("question_json")
+    private String questionJson;
+
+    @Field("crf_top_id")
+    private Long crfTopId;
+}
diff --git a/src/main/java/com/luca/pilot/entity/CrfAnswer.java b/src/main/java/com/luca/pilot/entity/CrfAnswer.java
new file mode 100644
index 0000000..b190335
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/CrfAnswer.java
@@ -0,0 +1,70 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.io.Serializable;
+
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document("crf_answer")
+public class CrfAnswer extends AbstractAuditingEntity implements Serializable {
+
+
+    private static final long serialVersionUID = 1L;
+
+
+    /**
+     * CrfAnswer表主键ID
+     */
+    private Long id;
+
+    /**
+     * crf表ID
+     */
+    @Field("crf_id")
+    private Long crfId;
+
+    /**
+     * crfTop表主键ID
+     */
+    @Field("crf_top_id")
+    private Long crfTopId;
+
+    /**
+     * 租户ID
+     */
+    private Long tenantId;
+
+
+    /**
+     * 答案的大json
+     */
+    @Field("answer_json")
+    private String answerJson;
+
+    @Field("plan_task_details_id")
+    private Long planTaskDetailsId;
+
+    /**
+     * SiteId
+     */
+    private String siteId;
+
+    /**
+     * projectCode
+     */
+    private String projectCode;
+
+    /**
+     * patientCode
+     */
+    private String patientCode;
+
+
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/DigitalMedicalDetails.java b/src/main/java/com/luca/pilot/entity/DigitalMedicalDetails.java
new file mode 100644
index 0000000..4c24066
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/DigitalMedicalDetails.java
@@ -0,0 +1,78 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+/**
+ * <p>
+ * 数字靶点子模块详细信息表
+ * </p>
+ *
+ * @since 2022-01-17
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Document(collection = "digital_medical_details")
+public class DigitalMedicalDetails extends AbstractAuditingEntity {
+
+    /**
+     * id
+     */
+    private Long id;
+
+    /**
+     * 租户id
+     */
+    private Long tenantId;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * code
+     */
+    private String code;
+
+    /**
+     * 描述
+     */
+    private String description;
+
+    /**
+     * 算法id
+     */
+    private Long algorithmId;
+
+    /**
+     * 算法名称
+     */
+    private String algorithmName;
+
+    /**
+     * 算法类型
+     * com.luca.enumeration.DbmAlgorithmType枚举
+     * 对应
+     * com.lucahealthcare.luca.common.enumerations.ModuleItemType枚举
+     */
+    private String algorithmType;
+
+    /**
+     * 算法支持设备
+     */
+    private String algorithmDevices;
+
+    /**
+     * 算法详情
+     */
+    private String algorithmDetails;
+
+    /**
+     * 数字诊疗详情下的子数字诊疗id,JSONArray,  todo:冠霖说放到算法下
+     */
+    private String subAlgorithm;
+
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/ModuleEntity.java b/src/main/java/com/luca/pilot/entity/ModuleEntity.java
new file mode 100644
index 0000000..098fb84
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/ModuleEntity.java
@@ -0,0 +1,51 @@
+package com.luca.pilot.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+/**
+ * @author jiangbangfa
+ * @date 2021/7/20 上午9:39
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document("module")
+public class ModuleEntity extends AbstractAuditingEntity {
+
+    private Long id;
+
+    /**
+     * 项目code
+     */
+    @Field("project_code")
+    private String projectCode;
+
+    /**
+     * 模块code
+     */
+    private String code;
+
+    /**
+     * 模块名称
+     */
+    private String name;
+
+    /**
+     * 模块类型
+     */
+    private String type;
+
+    /**
+     * 模块状态
+     */
+    private Boolean enabled;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/PatientScaleEvaluatingEntity.java b/src/main/java/com/luca/pilot/entity/PatientScaleEvaluatingEntity.java
new file mode 100644
index 0000000..8e00d0f
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/PatientScaleEvaluatingEntity.java
@@ -0,0 +1,44 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+/**
+ * @author linfeng.yang
+ * @date 2021/8/03 下午14:40
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document("patient_scale_evaluating")
+public class PatientScaleEvaluatingEntity extends AbstractAuditingEntity {
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+    private String code;
+
+    @Field("project_code")
+    private String projectCode;
+    private String patientCode;
+    private String siteId;
+    @Field("scale_code")
+    private String scaleCode;
+    @Field("scale_result")
+    private String scaleResult;
+    private String ruleId;
+
+    /**
+     * 量表答题总得分
+     */
+    @Field("total_score")
+    private String totalScore;
+
+    /**
+     * 患者任务详情id
+     */
+    @Field("plan_task_details_id")
+    private Long planTaskDetailsId;
+}
diff --git a/src/main/java/com/luca/pilot/entity/Plan.java b/src/main/java/com/luca/pilot/entity/Plan.java
new file mode 100644
index 0000000..8319284
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/Plan.java
@@ -0,0 +1,91 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.time.LocalDate;
+
+/**
+ * <p>
+ * 计划表
+ * </p>
+ *
+ * @author Lt
+ * @since 2021-11-08
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Document(collection="plan")
+public class Plan extends AbstractAuditingEntity {
+
+    /**
+     * id
+     */
+    private Long id;
+
+    /**
+     * 租户id
+     */
+    @Field("tenant_id")
+    private Long tenantId;
+
+    /**
+     * 项目id
+     */
+    @Field("project_id")
+    private Long projectId;
+
+    /**
+     * 计划名称
+     */
+    private String name;
+
+    /**
+     * 计划编号
+     */
+    private String number;
+
+    /**
+     * 生效日期
+     */
+    @Field("effective_date")
+    private LocalDate effectiveDate;
+
+    /**
+     * 计划天数
+     */
+    private Integer days;
+
+    /**
+     * 描述
+     */
+    private String description;
+
+    /**
+     * 是否启用(0:禁用 1:启用)
+     */
+    private Boolean enabled;
+
+    /**
+     * 计划二维码
+     */
+    @Field("plan_url")
+    private String planUrl;
+
+    /**
+     * 标签ids
+     */
+    @Field("patient_tags")
+    private String patientTags;
+
+    /**
+     * 是否需要医生审核  0 不需要  1 需要
+     */
+    @Field("doctor_audit")
+    private Integer doctorAudit;
+
+
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/PlanModule.java b/src/main/java/com/luca/pilot/entity/PlanModule.java
new file mode 100644
index 0000000..c990dea
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/PlanModule.java
@@ -0,0 +1,84 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Data
+@Document(collection="plan_module")
+public class PlanModule {
+
+    private String key;
+    /**
+     * 患者编号
+     */
+    private String subjectId;
+    /**
+     * 随机数
+     */
+    private String randomizationId;
+
+
+    /**
+     * plan
+     */
+    private String projectCode;
+    private String projectName;
+    private String siteName;
+    private Long planId;
+    private String planCode;
+    private String planEffectiveDate;
+    private Integer planDuration;
+
+    /**
+     * plan task
+     */
+    private String planTaskName;
+    private String planTaskdescription;
+    private Integer planTaskType;
+    private Integer planTaskTaskCount;
+    private Integer planTaskFinishDay;
+    private Integer planTaskLoopType;
+    private Boolean planTaskEnabled;
+    private Integer planTaskIsCirculation;
+    private Integer planTaskBeginDay;
+    private Integer planTaskCirculationDay;
+    private Integer planTaskWindowPhase;
+    private Integer planTaskEndDay;
+
+    /**
+     * plan task detail
+     */
+    private String taskStartDate;
+    private String taskEndDate;
+    private Integer taskCompleteStatus;
+    private String taskCompleteTime;
+    private Integer taskEnabled;
+    private Integer taskCompleteOrder;
+
+    /**
+     * plan module relate
+     */
+    private String moduleType;
+    private Long moduleId;
+    private String moduleName;
+
+
+
+    /**
+     * plan task detail module
+     */
+    private Integer moduleComplete;
+    private String moduleIgnoreRemark;
+    private String moduleFinishTime;
+
+    /**
+     * 组装
+     */
+    private String result;
+    private String digitalModuleTableName;
+
+    /**
+     * event
+     */
+    private Long digitalModuleEventId;
+}
diff --git a/src/main/java/com/luca/pilot/entity/PlanTask.java b/src/main/java/com/luca/pilot/entity/PlanTask.java
new file mode 100644
index 0000000..d7cff83
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/PlanTask.java
@@ -0,0 +1,157 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+/**
+ * <p>
+ * 患者任务计划
+ * </p>
+ *
+ * @author Lt
+ * @since 2021-11-08
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Document(collection="plan_task")
+public class PlanTask extends AbstractAuditingEntity {
+
+    /**
+     * id
+     */
+    private Long id;
+
+    /**
+     * 租户id
+     */
+    @Field("tenant_id")
+    private Long tenantId;
+
+    /**
+     * 项目id
+     */
+    @Field("project_id")
+    private Long projectId;
+
+    /**
+     * 计划id
+     */
+    @Field("plan_id")
+    private Long planId;
+
+    /**
+     * 任务名称
+     */
+    @Field("name")
+    private String name;
+
+    /**
+     * 任务描述
+     */
+    @Field("description")
+    private String description;
+
+    /**
+     * 循环类型(1:周 2:月 3:项目)
+     */
+    @Field("loop_type")
+    private Integer loopType;
+
+    /**
+     * 执行类型(循环类型=周 1:指定星期 2:循环周内几次;  循环类型=月 1:从当月几日开始 2:指定日期)
+     */
+    @Field("execute_type")
+    private Integer executeType;
+
+    /**
+     * 执行日期(cron表达式简化)
+     */
+    @Field("execute_cron")
+    private String executeCron;
+
+    /**
+     * 周执行频次(循环类型为周类型,循环周内几次时设值)
+     */
+    @Field("week_frequency")
+    private Integer weekFrequency;
+
+    /**
+     * 是否启用(0:禁用 1:启用)
+     */
+    @Field("enabled")
+    private Boolean enabled;
+
+    /**
+     * 计划目标id
+     */
+    @Field("target_id")
+    private Long targetId;
+    /**
+     * 窗口期
+     */
+    @Field("window_phase")
+    private Integer windowPhase;
+
+    /**
+     * 预约时间
+     */
+    @Field("reserve_time")
+    private String reserveTime;
+
+    /**
+     * 共需多少天
+     */
+    @Field("finish_day")
+    private Integer finishDay;
+
+    /**
+     * 任务类型(0:患者任务 1:医生随访)
+     */
+    @Field("task_type")
+    private Integer taskType;
+
+    /**
+     * 一日需完成次数
+     */
+    @Field("task_count")
+    private Integer taskCount;
+
+    /**
+     * 是否开启窗口期 1开启 0 未开启
+     */
+    @Field("is_window_phase")
+    private Integer isWindowPhase;
+
+    /**
+     * 是否循环 1是 0 否
+     */
+    @Field("is_circulation")
+    private Integer isCirculation;
+
+    /**
+     * 第几天循环
+     */
+    @Field("circulation_day")
+    private Integer circulationDay;
+
+    /**
+     * 第几天开始
+     */
+    @Field("begin_day")
+    private Integer beginDay;
+
+    /**
+     * 入组类型随访结束于第几天,0为至随访结束
+     */
+    @Field("end_day")
+    private Integer endDay;
+
+    /**
+     * 分组id
+     */
+    @Field("group_id")
+    private Long groupId;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/PlanTaskDetails.java b/src/main/java/com/luca/pilot/entity/PlanTaskDetails.java
new file mode 100644
index 0000000..2b2209f
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/PlanTaskDetails.java
@@ -0,0 +1,100 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 患者任务计划详情表
+ * </p>
+ *
+ * @author Lt
+ * @since 2021-11-08
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document(collection="plan_task_details")
+public class PlanTaskDetails extends AbstractAuditingEntity {
+
+    /**
+     * id
+     */
+    private Long id;
+
+    /**
+     * 计划code  //todo 临时字段
+     */
+    @Field("schedule_task_code")
+    private String scheduleTaskCode;
+
+    /**
+     * 租户id
+     */
+    @Field("tenant_id")
+    private Long tenantId;
+
+    /**
+     * 项目id
+     */
+    @Field("project_id")
+    private Long projectId;
+
+    /**
+     * 患者任务计划id
+     */
+    @Field("plan_task_id")
+    private Long planTaskId;
+
+    /**
+     * 患者code
+     */
+    @Field("patient_code")
+    private String patientCode;
+
+    /**
+     * 计划开始日期
+     */
+    @Field("start_date")
+    private String startDate;
+
+    /**
+     * 计划结束日期
+     */
+    @Field("end_date")
+    private String endDate;
+
+    /**
+     * 计划完成状态(0:未完成 1:已完成)
+     */
+    @Field("complete_status")
+    private Integer completeStatus;
+
+    /**
+     * 计划完成时间
+     */
+    @Field("complete_time")
+    private String completeTime;
+
+    /**
+     * 命中条件(若是循环周内几次1111100:标识 周一到周五做,周六周天不做; 其它类型任务:1)
+     */
+    private String hit;
+
+    /**
+     * 完成顺序
+     */
+    @Field("complete_order")
+    private Integer completeOrder;
+
+    /**
+     * 0 禁用 1 启用
+     */
+    private Integer enabled;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/PlanTaskDetailsModule.java b/src/main/java/com/luca/pilot/entity/PlanTaskDetailsModule.java
new file mode 100644
index 0000000..6a4a1e6
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/PlanTaskDetailsModule.java
@@ -0,0 +1,62 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+/**
+ * <p>
+ * 患者任务计划详情表
+ * </p>
+ *
+ * @author Lt
+ * @since 2021-11-08
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Document(collection = "plan_task_details_module")
+public class PlanTaskDetailsModule extends AbstractAuditingEntity {
+
+    /**
+     * id
+     */
+//    @TableId(type = IdType.INPUT)
+    private Long id;
+
+    /**
+     * 租户id
+     */
+    private Long tenantId;
+
+    /**
+     * 患者任务计划详情id
+     */
+    @Field("plan_task_details_id")
+    private Long planTaskDetailsId;
+
+    /**
+     * 关联项目类型
+     */
+    @Field("relation_type")
+    private String relationType;
+
+    /**
+     * 关联id
+     */
+    @Field("relation_id")
+    private Long relationId;
+
+    /**
+     * 模块任务完成状态(0:未完成 1:已完成)
+     */
+    @Field("module_complete")
+    private Integer moduleComplete;
+
+    /**
+     * 忽略备注
+     */
+    @Field("ignore_remark")
+    private String ignoreRemark;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/PlanTaskModuleRelate.java b/src/main/java/com/luca/pilot/entity/PlanTaskModuleRelate.java
new file mode 100644
index 0000000..380f87c
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/PlanTaskModuleRelate.java
@@ -0,0 +1,51 @@
+package com.luca.pilot.entity;
+
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+/**
+ * <p>
+ * 患者任务计划与模块关联表
+ * </p>
+ *
+ * @author Lt
+ * @since 2021-11-08
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Document(collection="plan_task_module_relate")
+public class PlanTaskModuleRelate extends AbstractAuditingEntity {
+
+    /**
+     * id
+     */
+    private Long id;
+
+    /**
+     * 租户id
+     */
+    @Field("tenant_id")
+    private Long tenantId;
+
+    /**
+     * 关联model类型
+     */
+    @Field("relation_type")
+    private String relationType;
+
+    /**
+     * 关联id
+     */
+    @Field("relation_id")
+    private Long relationId;
+
+    /**
+     * 患者任务计划id
+     */
+    @Field("plan_task_id")
+    private Long planTaskId;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/Project.java b/src/main/java/com/luca/pilot/entity/Project.java
new file mode 100644
index 0000000..a1363fb
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/Project.java
@@ -0,0 +1,95 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.time.LocalDate;
+
+/**
+ * @author jiangbangfa
+ * @date 2021/7/19 下午6:13
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document(collection="project")
+public class Project extends AbstractAuditingEntity {
+
+
+    private Long id;
+
+    private String code;
+
+    private String name;
+
+    @Field("app_ids")
+    private String appIds;
+
+    @Field("invite_code")
+    private String inviteCode;
+
+    private Long type;
+
+    private String number;
+
+    @Field("tenant_id")
+    private Long tenantId;
+
+    @Field("bid_unit")
+    private String bidUnit;
+
+    private String version;
+
+//    @Field("start_at")
+//    private LocalDate startAt;
+//
+//    @Field("end_at")
+//    private LocalDate endAt;
+
+    private String url;
+    @Field("dashboard_show_code")
+    private String dashboardShowCode;
+
+    @Field("dashboard_show_name")
+    private String dashboardShowName;
+
+    /**
+     * 日记使用 方案名称 非必填
+     */
+    @Field("scheme_name")
+    private String schemeName;
+
+    /**
+     * 日记使用 方案编号 非必填
+     */
+    @Field("scheme_code")
+    private String schemeCode;
+
+//    /**
+//     * 是否认证
+//     */
+//    @Field("enable_id_verification")
+//    private Boolean enableIdVerification;
+
+
+    /**
+     * 0 未锁库 1 已锁库
+     */
+    private Integer locked;
+
+    /**
+     * 研究随访时长
+     */
+    @Field("study_follow_up_time")
+    private Integer studyFollowUpTime;
+
+    /**
+     * 计划人数
+     */
+    @Field("plan_people")
+    private Long planPeople;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/Questionnaire.java b/src/main/java/com/luca/pilot/entity/Questionnaire.java
new file mode 100644
index 0000000..7a2dfa0
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/Questionnaire.java
@@ -0,0 +1,43 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author linfeng.yang
+ * @since 2021-10-21
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document("questionnaire")
+public class Questionnaire extends AbstractAuditingEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+    private Long id;
+
+    private String url;
+
+    private String name;
+
+    private String description;
+
+    private Integer status;
+
+    @Field("top_id")
+    private Long topId;
+
+    private Long sourceId;
+
+    private Long tenantId;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/QuestionnaireAnswer.java b/src/main/java/com/luca/pilot/entity/QuestionnaireAnswer.java
new file mode 100644
index 0000000..afe1219
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/QuestionnaireAnswer.java
@@ -0,0 +1,68 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author linfeng.yang
+ * @since 2021-11-02
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Document("questionnaire_answer")
+public class QuestionnaireAnswer extends AbstractAuditingEntity implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    @Field("questionnaire_id")
+    private Long questionnaireId;
+
+    @Field("questionnaire_name")
+    private String questionnaireName;
+
+    @Field("question_id")
+    private Long questionId;
+
+    @Field("question_name")
+    private String questionName;
+
+    private String type;
+
+    private Long tenantId;
+
+
+    /**
+     * 患者任务详情id
+     */
+    @Field("plan_task_details_id")
+    private Long planTaskDetailsId;
+
+    /**
+     * 睡眠问卷睡眠类型
+     */
+    private Integer sleepType;
+
+    /**
+     * site Id
+     */
+    private String siteId;
+    /**
+     * 主记录id
+     */
+    @Field("record_id")
+    private Long recordId;
+
+//    @ApiModelProperty(value = "关联schedule")
+//    private String scheduleTaskCode;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/QuestionnaireAnswerOption.java b/src/main/java/com/luca/pilot/entity/QuestionnaireAnswerOption.java
new file mode 100644
index 0000000..41e4b59
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/QuestionnaireAnswerOption.java
@@ -0,0 +1,55 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author linfeng.yang
+ * @since 2021-11-02
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Document("questionnaire_answer_option")
+public class QuestionnaireAnswerOption extends AbstractAuditingEntity implements Serializable{
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    @Field("answer_id")
+    private Long answerId;
+
+    @Field("option_id")
+    private Long optionId;
+
+    @Field("option_name")
+    private String optionName;
+
+    @Field("question_id")
+    private Long questionId;
+
+    private String content;
+
+    @Field("date_at")
+    private String dateAt;
+
+    @Field("number_answer")
+    private BigDecimal numberAnswer;
+
+    @Field("left_min")
+    private BigDecimal leftMin;
+
+    @Field("right_max")
+    private BigDecimal rightMax;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/QuestionnaireAnswerRecord.java b/src/main/java/com/luca/pilot/entity/QuestionnaireAnswerRecord.java
new file mode 100644
index 0000000..db02ed9
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/QuestionnaireAnswerRecord.java
@@ -0,0 +1,56 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author linfeng.yang
+ * @since 2021-10-21
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@Document("questionnaire_answer_record")
+public class QuestionnaireAnswerRecord extends AbstractAuditingEntity implements Serializable{
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    @Field("top_id")
+    private Long topId;
+
+    @Field("project_code")
+    private String projectCode;
+
+    @Field("site_id")
+    private String siteId;
+
+    @Field("patient_code")
+    private String patientCode;
+
+    /**
+     * 患者任务详情id
+     */
+    @Field("plan_task_details_id")
+    private Long planTaskDetailsId;
+
+    /**
+     * 计划完成时间
+     */
+    @Field("complete_time")
+    private String completeTime;
+
+
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/ScaleModuleDetailsEntity.java b/src/main/java/com/luca/pilot/entity/ScaleModuleDetailsEntity.java
new file mode 100644
index 0000000..39cf369
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/ScaleModuleDetailsEntity.java
@@ -0,0 +1,33 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.math.BigDecimal;
+
+/**
+ * @author linfeng.yang
+ * @date 2021/8/03 下午14:40
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document("scale_module_details")
+public class ScaleModuleDetailsEntity extends AbstractAuditingEntity {
+
+    private Long id;
+    private String code;
+    private String name;
+    private String description;
+    private String ruleDescription;
+    private Integer status;     //0:未发布 1:已发布 2:已下架
+    private String tags;
+    private String scaleImg;
+    private String url;
+    private String abbreviation;
+    private BigDecimal scaleScore;
+    private String ruleResult;
+    private String ruleContent;
+}
diff --git a/src/main/java/com/luca/pilot/entity/ScaleModuleEntity.java b/src/main/java/com/luca/pilot/entity/ScaleModuleEntity.java
new file mode 100644
index 0000000..0379b66
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/ScaleModuleEntity.java
@@ -0,0 +1,29 @@
+package com.luca.pilot.entity;
+
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+/**
+ * @author linfeng.yang
+ * @date 2021/8/03 下午14:40
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document("scale_module")
+public class ScaleModuleEntity extends AbstractAuditingEntity {
+
+    private Long id;
+    private String code;
+    @Field("project_code")
+    private String projectCode;
+    @Field("module_code")
+    private String moduleCode;
+    @Field("scale_code")
+    private String scaleCode;
+    private Boolean enabled;
+}
diff --git a/src/main/java/com/luca/pilot/entity/Site.java b/src/main/java/com/luca/pilot/entity/Site.java
new file mode 100644
index 0000000..22c70b6
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/Site.java
@@ -0,0 +1,89 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+@Document(collection="site")
+public class Site extends AbstractAuditingEntity {
+    /**
+     * siteId
+     */
+    private Long id;
+
+    /**
+     * 租户id
+     */
+    private Long tenantId;
+
+    /**
+     * 项目id
+     */
+    private Long projectId;
+
+    /**
+     * site名称(L:32)
+     */
+    @Field("site_name")
+    private String siteName;
+
+    /**
+     * 描述(L:128)
+     */
+    private String description;
+
+    /**
+     * logo
+     */
+    private String logoUrl;
+
+    /**
+     * 知情同意书文本
+     */
+    private String agreementText;
+
+    /**
+     * 知情同意类型  0 无 1 通用模板  2 site自定义
+     */
+    private Integer agreementType;
+
+    /**
+     * 目标患者数
+     */
+    private Long targetPatientsNum;
+
+    /**
+     * 省级id
+     */
+    private Long provinceId;
+
+    /**
+     * 市级id
+     */
+    private Long cityId;
+
+    /**
+     * 区/县级id
+     */
+    private Long areaId;
+
+    /**
+     * 省级-市级-区/县级
+     */
+    private String address;
+
+    /**
+     * 时区
+     */
+    private String timeZone;
+
+    /**
+     * 启用状态
+     */
+    private Boolean enable;
+
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/luca/pilot/entity/SynchronizeTime.java b/src/main/java/com/luca/pilot/entity/SynchronizeTime.java
new file mode 100644
index 0000000..9391f86
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/SynchronizeTime.java
@@ -0,0 +1,14 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+import java.time.LocalDateTime;
+@Data
+@Document(collection="synchronize_time")
+public class SynchronizeTime {
+
+    private String _id;
+    private LocalDateTime plan;
+
+}
diff --git a/src/main/java/com/luca/pilot/entity/UserArchive.java b/src/main/java/com/luca/pilot/entity/UserArchive.java
new file mode 100644
index 0000000..5e1579c
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/UserArchive.java
@@ -0,0 +1,207 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.mongodb.core.mapping.Document;
+
+@Data
+@Accessors(chain = true)
+@Document("user_archive")
+public class UserArchive {
+
+    @Id
+    private String id;
+    /**
+     * 名字
+     */
+    private String name;
+
+    /**
+     * 手机号
+     */
+    private String phoneNo;
+
+    /**
+     * 男|女
+     */
+    private String gender;
+
+    /**
+     * YYYY-MM-DD格式
+     */
+    private String birthday;
+
+    /**
+     * 身份证后四位
+     */
+    private String idCardLastFour;
+
+    /**
+     * 身份证号
+     */
+    private String idCard;
+
+    /**
+     * 地址
+     */
+    private String address;
+
+    /**
+     * 学历
+     */
+    private String education;
+
+    /**
+     * 职业(退休前)
+     */
+    private String job;
+
+    /**
+     * 婚姻状况
+     */
+    private String maritalStatus;
+
+    /**
+     * 居住状态
+     */
+    private String dwellStatus;
+
+    /**
+     * 身高
+     */
+    private String height;
+
+    /**
+     * 体重
+     */
+    private String weight;
+
+    /**
+     * 是否喜欢听音乐
+     */
+    private String likeMusic;
+
+    /**
+     * 每周听音乐时长
+     */
+    private String weekMusciDuration;
+
+    /**
+     * 多久入睡
+     */
+    private String fallAsleep;
+
+    /**
+     * 睡眠几小时
+     */
+    private String sleepTime;
+
+    /**
+     * 影响睡眠情况
+     */
+    private String sleepAffect;
+
+    /**
+     * 是否药物助眠
+     */
+    private String drugHelpSleep;
+
+    /**
+     * 是否听不清影响生活
+     */
+    private String hearingAffectLife;
+
+    /**
+     * 是否患有糖尿病
+     */
+    private String diabetes;
+    /**
+     * 是否患有高血压
+     */
+    private String hypertension;
+    /**
+     * 是否饮酒
+     */
+    private String drink;
+    /**
+     * 是否吸烟
+     */
+    private String smoke;
+
+    /**
+     * 规则md5
+     */
+    private String schemaMd5;
+
+    /**
+     * 民族
+     */
+    private String nation;
+
+    /**
+     * 既往病史
+     */
+    private String pastMedicalHistory;
+
+    /**
+     * 随机数
+     */
+    private String randomizationId;
+    /**
+     * 过敏史
+     */
+    private String allergyHistory;
+
+    private String nlfh;//',"健康志愿者,年龄18至75岁(包含边界值),男女不限"
+    private String brqs;//',"能够本人签署知情同意书"
+    private String yypd;//',"愿意在研究期间佩戴手环收集数据设备"
+    private String yytgdz;//',"愿意提供有效的联系地址,以接收研究设备"
+    private String ywf;//',"家中需具备Wi-Fi网络连接,网络速度100 Mbps及以上"
+    private String yysysj;//',"愿意使用配备数据套餐的手机,并采用合适的数据连接方式传输研究所收集的数据"
+    private String ysjxtbs;//',"有神经系统或精神疾病病史,或认知受损或失去行为能力的受试者"
+    private String yhgfxshsb;//',"有很高风险损坏设备或不能长时间佩戴的受试者,如经常游泳者"
+    private String gmpf;//',"对可穿戴设备过敏或有皮肤过敏史的受试者"
+    private String yzyfx;//',"由于健康状况问题,被评估为有住院风险的受试者"
+    private String wsyznsb;//',"既往从未使用过智能设备的受试者"
+    private String ssz;//',"在筛选时存在需要治疗的急性或慢性疾病的受试者(包括但不限于免疫缺陷或免疫抑制疾病、恶性肿瘤或皮肤疾病等)"
+    private String yywly;//',"有药物滥用或药物依赖病史的受试者"
+    private String cyqtsy;//',"目前参与其他药物或医疗设备临床试验的受试者"
+    private String zzbr;//',"目前正在哺乳的女性"
+    private String yjzbsh;//',"研究者认为受试者存在不适合参与试验的其他原因"
+    private String wcglx;//',"受试者在签署知情同意时或整个研究期间,无出国旅行计划"
+
+    private String screeningNum; // 筛选号
+    private String addressHome; // 家庭住址
+
+    // ------------------ 患者档案固定数据 -------------------
+    /**
+     * 患者编号 subjectId
+     */
+    private String subjectId;
+
+    /**
+     * 0禁用  1启用(默认)
+     */
+    private Integer enable = 1;
+
+    /**
+     * 是否封存 0否 1是
+     */
+    private Integer isArchive = 0;
+
+    /**
+     * 创建时间
+     */
+    private String createAt;
+
+    /**
+     * 创建人
+     */
+    private String createBy;
+
+    /**
+     * 文件url
+     */
+    private String fileUrl;
+}
diff --git a/src/main/java/com/luca/pilot/entity/UserArchiveMapping.java b/src/main/java/com/luca/pilot/entity/UserArchiveMapping.java
new file mode 100644
index 0000000..220db16
--- /dev/null
+++ b/src/main/java/com/luca/pilot/entity/UserArchiveMapping.java
@@ -0,0 +1,33 @@
+package com.luca.pilot.entity;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.data.mongodb.core.mapping.Document;
+import org.springframework.data.mongodb.core.mapping.Field;
+
+/**
+ * @author linfeng.yang
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+@Document(collection="user_archive_mapping")
+public class UserArchiveMapping extends AbstractAuditingEntity {
+    private Long id;
+    @Field("project_code")
+    private String projectCode;
+
+    @Field("site_id")
+    private Long siteId;
+
+    @Field("uaa_user_id")
+    private Long uaaUserId;
+
+    @Field("patient_code")
+    private String patientCode;
+
+    @Field("user_archive_id")
+    private String userArchiveId;
+
+}
diff --git a/src/main/java/com/luca/pilot/service/BaseModuleViewService.java b/src/main/java/com/luca/pilot/service/BaseModuleViewService.java
new file mode 100644
index 0000000..78b1388
--- /dev/null
+++ b/src/main/java/com/luca/pilot/service/BaseModuleViewService.java
@@ -0,0 +1,10 @@
+package com.luca.pilot.service;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+
+public interface BaseModuleViewService {
+
+     void synchronizeModuleView();
+}
diff --git a/src/main/java/com/luca/pilot/service/PlanService.java b/src/main/java/com/luca/pilot/service/PlanService.java
new file mode 100644
index 0000000..94be7ce
--- /dev/null
+++ b/src/main/java/com/luca/pilot/service/PlanService.java
@@ -0,0 +1,10 @@
+package com.luca.pilot.service;
+
+public interface PlanService {
+
+
+    void synchronizePlanTask();
+
+    void test();
+
+}
diff --git a/src/main/java/com/luca/pilot/service/impl/BaseModuleViewServiceImpl.java b/src/main/java/com/luca/pilot/service/impl/BaseModuleViewServiceImpl.java
new file mode 100644
index 0000000..a1ee712
--- /dev/null
+++ b/src/main/java/com/luca/pilot/service/impl/BaseModuleViewServiceImpl.java
@@ -0,0 +1,57 @@
+package com.luca.pilot.service.impl;
+
+import com.luca.pilot.entity.BaseModuleView;
+import com.luca.pilot.entity.ModuleEntity;
+import com.luca.pilot.entity.ScaleModuleDetailsEntity;
+import com.luca.pilot.entity.ScaleModuleEntity;
+import com.luca.pilot.service.BaseModuleViewService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class BaseModuleViewServiceImpl implements BaseModuleViewService {
+
+    @Resource(name = "mongoTemplate")
+    private MongoTemplate mongoTemplate;
+
+    @Override
+    public void synchronizeModuleView() {
+        queryScale();
+    }
+
+    private void queryScale() {
+        List<ScaleModuleDetailsEntity> scaleModuleDetailsList = mongoTemplate.findAll(ScaleModuleDetailsEntity.class);
+        List<ScaleModuleEntity> scaleModuleList = mongoTemplate.findAll(ScaleModuleEntity.class);
+        List<ModuleEntity> moduleList = mongoTemplate.findAll(ModuleEntity.class);
+
+        List<BaseModuleView> views = scaleModuleDetailsList.stream().map(x -> {
+            ScaleModuleEntity sm = scaleModuleList.stream().filter(y -> y.getScaleCode().equals(x.getCode())).findFirst().orElse(null);
+            if(Objects.nonNull(sm)) {
+                ModuleEntity m = moduleList.stream().filter(y -> y.getCode().equals(sm.getModuleCode())).findFirst().orElse(null);
+                BaseModuleView view = new BaseModuleView()
+                        .setId(x.getId())
+                        .setName(x.getName())
+                        .setStatus(x.getStatus())
+                        .setModuleCode(Objects.isNull(sm) ? "" : sm.getScaleCode())
+                        .setModuleEnabled(Objects.isNull(sm) ? null : sm.getEnabled())
+                        .setModuleType(Objects.isNull(m) ? "" : m.getType())
+                        .setProjectCode(Objects.isNull(m) ? "" : m.getProjectCode())
+                        .setProjectEnabled(Objects.isNull(m) ? null : m.getEnabled());
+                return view;
+            }
+            return null;
+        }).collect(Collectors.toList());
+
+        mongoTemplate.insertAll(views);
+    }
+
+}
diff --git a/src/main/java/com/luca/pilot/service/impl/PlanServiceImpl.java b/src/main/java/com/luca/pilot/service/impl/PlanServiceImpl.java
new file mode 100644
index 0000000..8e4dc42
--- /dev/null
+++ b/src/main/java/com/luca/pilot/service/impl/PlanServiceImpl.java
@@ -0,0 +1,643 @@
+package com.luca.pilot.service.impl;
+
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.json.JSONUtil;
+import com.luca.pilot.bizEnum.TableEnum;
+import com.luca.pilot.entity.*;
+import com.luca.pilot.service.PlanService;
+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.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.data.mongodb.core.query.Update;
+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.time.*;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Slf4j
+@Service
+public class PlanServiceImpl implements PlanService {
+
+    @Resource(name = "mongoTemplate")
+    private MongoTemplate mongoTemplate;
+
+    @Resource(name = "mongoArchiveTemplate")
+    private MongoTemplate mongoArchiveTemplate;
+
+    @Override
+    @Scheduled(cron ="0 0/5 * * * ?")
+    public void synchronizePlanTask() {
+        log.info("-----------synchronizePlanTask start-----------");
+        LocalDateTime now = LocalDateTime.now();
+
+        SynchronizeTime synchronizeTime = findSynchronizeTime();
+
+        LocalDateTime lastSynchronizeTime = null;
+        if (Objects.nonNull(synchronizeTime)) {
+            lastSynchronizeTime = synchronizeTime.getPlan();
+        }
+
+        Query countQuery = new Query();
+        if (Objects.nonNull(lastSynchronizeTime)) {
+            countQuery.addCriteria(Criteria.where("last_modified_at").gt(String.valueOf(lastSynchronizeTime)));
+        }
+        long totalPlanTaskDetailsCount = mongoTemplate.count(countQuery, PlanTaskDetails.class);
+        log.info("PlanTaskDetails 在大于 {} 时间内未查询到数据 {} 条", lastSynchronizeTime, totalPlanTaskDetailsCount);
+
+        if (totalPlanTaskDetailsCount == 0) {
+            return;
+        }
+
+        saveSynchronizeTime(synchronizeTime, now);
+
+        long skip = totalPlanTaskDetailsCount / 10000;
+        if (totalPlanTaskDetailsCount % 10000 > 0) {
+            skip++;
+        }
+
+        long totalPlanModuleCount = mongoTemplate.count(countQuery, 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("第{}次查询 planTaskDetails count:{}", i + 1, planTaskDetails.size());
+            // 获取对应档案,取subjectId 和 randomId
+            List<UserArchiveMapping> userArchiveMappings = queryArchiveMapping(planTaskDetails);
+            List<UserArchive> userArchives = queryArchive(userArchiveMappings);
+
+            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);
+
+            Map<Long, Map<String, String>> resultMap = queryPlanTaskDetailResult(planTaskDetails);
+
+            Map<Long, Map<Long, Long>> digitalMedicalEventMap = queryDigitalMedicalEvent(planTaskDetails);
+            Map<Long, Map<Long, String>> digitalMedicalTypeMap = queryDigitalMedicalType(planTaskDetails);
+
+            List<PlanModule> planMoudles = 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.getId().equals(planTaskDetail.getProjectId())).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());
+                    }
+
+                    if (Objects.nonNull(plan)) {
+                        planMoudle.setPlanId(plan.getId());
+                        planMoudle.setPlanCode(plan.getNumber());
+                        planMoudle.setPlanEffectiveDate(parseTimeFromDate(plan.getEffectiveDate()));
+                        planMoudle.setPlanDuration(plan.getDays());
+                    }
+
+                    if (Objects.nonNull(planTask)) {
+                        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.getProjectId()));
+                        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, String> planTaskDetailMap = resultMap.get(planTaskDetail.getId());
+
+                        if (MapUtil.isNotEmpty(planTaskDetailMap)) {
+                            String 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(Criteria.where("key").is(planMoudle.getKey()));
+                        Update update = buildUpdate(planMoudle);
+                        bulkOps.upsert(upsertQuery, update);
+                    }
+                    planMoudles.add(planMoudle);
+                }
+            }
+
+            // 是否第一次全量插入
+            if (totalPlanModuleCount > 0) {
+                bulkOps.execute();
+                log.info("bulkOps 更新或新增:{} 条", planMoudles.size());
+            } else {
+                if (!CollectionUtils.isEmpty(planMoudles)) {
+                    mongoTemplate.insert(planMoudles, PlanModule.class);
+                    log.info("mongoTemplate 直接新增:{} 条", planMoudles.size());
+                }
+            }
+
+        }
+
+        log.info("synchronizePlanTask end, 耗时:{} 秒", LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - now.toEpochSecond(ZoneOffset.of("+8")));
+
+    }
+
+    private SynchronizeTime findSynchronizeTime() {
+        Query query = new Query().limit(1);
+        return mongoTemplate.findOne(query, SynchronizeTime.class);
+    }
+
+    private void saveSynchronizeTime(SynchronizeTime synchronizeTime, LocalDateTime now) {
+        if (Objects.isNull(synchronizeTime)) {
+            SynchronizeTime time = new SynchronizeTime();
+            time.setPlan(now);
+            mongoTemplate.save(time);
+        } else {
+            Query updateQuery = new Query();
+            updateQuery.addCriteria(Criteria.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("planId", planMoudle.getPlanId())
+                .set("planCode", planMoudle.getPlanCode())
+                .set("planDuration", planMoudle.getPlanDuration())
+                .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.getTaskEndDate())
+                .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() {
+
+    }
+
+
+    private String parseTimeFromDate(LocalDate timeStr) {
+        LocalDateTime localDateTime = timeStr.atStartOfDay();
+        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        return localDateTime.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(Criteria.where("plan_task_details_id").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(Criteria.where("plan_details_id").in(planTskDetailIds).and("relation_type").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(Criteria.where("plan_details_id").in(planTskDetailIds).and("relation_type").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, String>> queryPlanTaskDetailResult(List<PlanTaskDetails> planTaskDetails) {
+        Map<Long, Map<String, String>> map = new HashMap<>();
+        Map<Long, Map<String, String>> scaleMap = queryScaleResult(planTaskDetails);
+        map.putAll(scaleMap);
+        Map<Long, Map<String, String>> 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, String>> 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, String>> 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(Criteria.where("plan_task_details_id").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(Criteria.where("id").in(crfIds)), Crf.class)
+                .stream().collect(Collectors.toMap(Crf::getId, Crf::getQuestionJson, (k1, k2) -> k2));
+
+        Map<Long, Map<String, String>> map = new HashMap<>();
+        crfAnswersMap.forEach((k, v) -> {
+            if (!CollectionUtils.isEmpty(v)) {
+                Map<String, String> innerMap = new HashMap<>();
+                v.forEach(crfAnswer -> {
+                    String questionJson = crfMap.get(crfAnswer.getCrfId());
+                    if (Objects.nonNull(questionJson) && Objects.nonNull(crfAnswer.getAnswerJson())) {
+                        try {
+                            String 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, String>> 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(Criteria.where("plan_task_details_id").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(Criteria.where("record_id").in(recordIds)), QuestionnaireAnswer.class);
+
+        Set<Long> ansowerIds = answers.stream().map(QuestionnaireAnswer::getId).collect(Collectors.toSet());
+        List<QuestionnaireAnswerOption> answerOptions = mongoTemplate.find(new Query().addCriteria(Criteria.where("answer_id").in(ansowerIds)), QuestionnaireAnswerOption.class);
+
+        Map<Long, Map<String, String>> map = new HashMap<>();
+
+        for (QuestionnaireAnswerRecord record : records) {
+
+            List<QuestionnaireAnswer> answerList = answers.stream().filter(x -> x.getRecordId().equals(record.getId())).collect(Collectors.toList());
+
+            Map<String, String> resultMap = new HashMap<>();
+            List<String> keyValueNewVos = new ArrayList<>();
+            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.add(answer.getQuestionName() + ":" + optionalAnswerOption.map(QuestionnaireAnswerOption::getOptionName).orElse("-"));
+                        break;
+                    case "SLIDE":
+                    case "DATE_SELECT":
+                    case "NUMBER":
+                        keyValueNewVos.add(answer.getQuestionName() + ":" + 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.add(answer.getQuestionName() + ":" + (optionNames.isEmpty() ? "-" : String.join(",", optionNames)));
+                        break;
+                    case "DATE":
+                        keyValueNewVos.add(answer.getQuestionName() + ":" + optionalAnswerOption.map(QuestionnaireAnswerOption::getDateAt).orElse("-"));
+                        break;
+
+                    case "SECTION_NUMBER":
+                        keyValueNewVos.add(answer.getQuestionName() + ":" + (optionalAnswerOption.map(option -> option.getLeftMin() + "-" + option.getRightMax()).orElse("-")));
+                        break;
+                    case "TEXT":
+                        keyValueNewVos.add(answer.getQuestionName() + ":" + optionalAnswerOption.map(QuestionnaireAnswerOption::getContent).orElse("-"));
+                        break;
+                }
+            }
+            resultMap.put(String.valueOf(record.getTopId()), JSONUtil.toJsonStr(keyValueNewVos));
+            map.put(record.getPlanTaskDetailsId(), resultMap);
+        }
+
+        return map;
+    }
+
+    private Map<Long, Map<String, String>> 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(Criteria.where("plan_task_details_id").in(planTskDetailIds)), PatientScaleEvaluatingEntity.class)
+                        .stream().collect(Collectors.groupingBy(PatientScaleEvaluatingEntity::getPlanTaskDetailsId));
+
+        Map<Long, Map<String, String>> map = new HashMap<>();
+
+        scaleEvaluatMap.forEach((k, v) -> {
+            if (!CollectionUtils.isEmpty(v)) {
+                Map<String, String> result = new HashMap<>();
+                v.forEach(item -> {
+                    List<String> sb = new ArrayList<>();
+                    if (Objects.nonNull(item.getScaleResult())) {
+                        sb.add("result:" + item.getScaleResult());
+                    }
+                    if (Objects.nonNull(item.getTotalScore())) {
+                        sb.add("totalScore:" + item.getTotalScore());
+                    }
+                    if (!CollectionUtils.isEmpty(sb)) {
+                        result.put(item.getScaleCode(), JSONUtil.toJsonStr(sb));
+                    }
+
+                });
+
+                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(Criteria.where("top_id").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(Criteria.where("crf_top_id").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(Criteria.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(Criteria.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(Criteria.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(Criteria.where("patient_code").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(Criteria.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(Criteria.where("id").in(siteIds)),
+                Site.class);
+    }
+
+    private List<Project> queryProjct(List<PlanTaskDetails> planTaskDetails) {
+        List<Long> projectIds = planTaskDetails.stream().map(PlanTaskDetails::getProjectId).collect(Collectors.toList());
+        return mongoTemplate.find(new Query().addCriteria(Criteria.where("id").in(projectIds)), 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(Criteria.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(Criteria.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(Criteria.where("_id").in(archiveIds)),
+                UserArchive.class);
+    }
+}
diff --git a/src/main/java/com/luca/pilot/util/CrfUtil.java b/src/main/java/com/luca/pilot/util/CrfUtil.java
new file mode 100644
index 0000000..6efcca4
--- /dev/null
+++ b/src/main/java/com/luca/pilot/util/CrfUtil.java
@@ -0,0 +1,228 @@
+package com.luca.pilot.util;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.parser.Feature;
+import com.luca.pilot.bizEnum.CrfQuestionTypeEnum;
+import com.luca.pilot.bo.*;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+public class CrfUtil {
+
+    public static String parseCrfProblemAndAnswer(String crfProblemJson, String crfAswerJson) {
+        if (Objects.isNull(crfProblemJson) || "".equals(crfProblemJson)
+                || Objects.isNull(crfAswerJson) || "".equals(crfAswerJson)) {
+            return "";
+        }
+
+        List<CrfProblemBo> crfProblemBos = crfProblemJsonAnalysisNew(crfProblemJson);
+
+        List<String> dataIds = crfProblemBos.stream().map(CrfProblemBo::getDataBo).filter(Objects::nonNull).collect(Collectors.toList())
+                .stream().map(BindDataBo::getDataId).collect(Collectors.toList());
+
+        List<CrfJsonValueBo> crfJsonValueBos = crfJsonAnalysis(crfAswerJson);
+
+        List<String> crfAswers = new ArrayList<>();
+        crfJsonValueBos.stream().filter(x -> dataIds.contains(x.getKey())).forEach(item -> {
+            if (Objects.nonNull(item.getName()) && Objects.nonNull(item.getText())) {
+                crfAswers.add(item.getName() + ":" + item.getText());
+            }
+        });
+        if (CollectionUtil.isEmpty(crfAswers)) {
+            return null;
+        }
+        return JSONUtil.toJsonStr(crfAswers);
+    }
+
+    /**
+     * crf 问题json 解析
+     */
+    public static List<CrfProblemBo> crfProblemJsonAnalysisNew(String crfProblemJson) {
+        if (Objects.isNull(crfProblemJson) || "".equals(crfProblemJson)) {
+            return Collections.emptyList();
+        }
+        var jsonObject = JSONObject.parseObject(crfProblemJson, Feature.OrderedField);
+        if (jsonObject == null) {
+            return Collections.emptyList();
+        }
+        List<JSONObject> bos = new ArrayList<>();
+        problemJsonNew(bos, jsonObject, null);
+
+        if (CollectionUtil.isEmpty(bos)) {
+            return Collections.emptyList();
+        }
+        return bos.stream().filter(item -> Objects.nonNull(item.get("questionType"))).map(item -> {
+            var crfProblemBo = new CrfProblemBo()
+                    .setTitle(String.valueOf(item.get("title")))
+                    .setProperties(JSONObject.toJSONString(item.get("properties")))
+                    .setQuestionType(CrfQuestionTypeEnum.getDeviceEnum(JSONObject.toJSONString(item.get("questionType")).replace("\"", "")));
+            var bindData = JSONObject.toJSONString(item.get("BindData"));
+            if (!"".equals(bindData)) {
+                crfProblemBo.setDataBo(
+                        new BindDataBo()
+                                .setDataId(JSONObject.parseObject(bindData).getString("dataId"))
+                                .setDataType(JSONObject.parseObject(bindData).getString("dataType"))
+                                .setChoiceField(JSONObject.parseObject(bindData).getString("choiceField"))
+                );
+            }
+            return crfProblemBo;
+        }).collect(Collectors.toList());
+    }
+
+    private static void problemJsonNew(List<JSONObject> array, JSONObject data, String prefix) {
+        if (Objects.isNull(data)) {
+            return;
+        }
+
+        var title = data.get("title");
+        if (Objects.nonNull(prefix)) {
+            title = prefix + "," + title;
+            data.put("title", title);
+
+        }
+        var properties = data.get("properties");
+        if (Objects.isNull(properties)) {
+            var columns = data.get("columns");
+            var defaultValue = data.get("defaultValue");
+            if (Objects.isNull(defaultValue)) {
+                array.add(data);
+                return;
+            }
+            try {
+                var head = JSONObject.parseObject(data.get("BindData").toString(), Feature.OrderedField).get("dataId").toString();
+                var columnsBos = JSONObject.parseArray(JSONObject.toJSONString(columns), CrfTableJsonTopicBo.class).stream()
+                        .filter(bo -> !"title".equals(bo.getDataIndex())) // 去掉最左一列 dataIndex 为 title 的列
+                        .collect(Collectors.toList());
+                var defaultValueBos = JSONObject.parseArray(JSONObject.toJSONString(defaultValue), CrfTableJsonTopicBo.class);
+                for (int i = 0; i < columnsBos.size(); i++) {
+                    for (int j = 0; j < defaultValueBos.size(); j++) {
+                        JSONObject jsonObject = new JSONObject();
+                        jsonObject.put("title", title + "," + defaultValueBos.get(j).getTitle() + "-" + columnsBos.get(i).getTitle());
+                        jsonObject.put("questionType", CrfQuestionTypeEnum.CRFTABLE.getCode());
+                        jsonObject.put("BindData",
+                                new BindDataBo()
+                                        .setChoiceField("MH")
+                                        .setDataType("CUSTOMIZE")
+                                        .setDataId(head + "-" + columnsBos.get(i).getDataIndex() + "-" + defaultValueBos.get(j).getId())
+                        );
+                        array.add(jsonObject);
+                    }
+                }
+            } catch (Exception e) {
+                array.add(data);
+                return;
+            }
+            return;
+        }
+
+        var propertiesJsonObject = JSONObject.parseObject(properties.toString(), Feature.OrderedField);
+        array.add(data);
+        var keySet = propertiesJsonObject.keySet();
+        var collect = keySet.stream().map(key -> JSONObject.parseObject(JSONObject.toJSONString(propertiesJsonObject.get(key)), Feature.OrderedField)).collect(Collectors.toList());
+        for (JSONObject item : collect) {
+            problemJsonNew(array, item, Objects.nonNull(title) ? title.toString() : null);
+        }
+    }
+
+    /**
+     * crf 答案json 解析
+     */
+    public static List<CrfJsonValueBo> crfJsonAnalysis(String crfJson) {
+        Map<String, String> map = new HashMap<>();
+        if (Objects.isNull(crfJson) || "".equals(crfJson)) {
+            return Collections.emptyList();
+        }
+        var jsonObject = JSONObject.parseObject(crfJson);
+        if (jsonObject == null) {
+            return Collections.emptyList();
+        }
+        var formStr = JSONObject.toJSONString(jsonObject.get("form"));
+        if ("".equals(formStr)) {
+            return Collections.emptyList();
+        }
+        var array = JSONObject.parseArray(formStr, CrfJsonValueBo.class);
+        if (CollectionUtil.isNotEmpty(array)) {
+            var bos = jsonArray(array);
+            if (CollectionUtil.isEmpty(bos)) {
+                return Collections.emptyList();
+            }
+            var collect = bos.stream().map(item -> {
+                try {
+                    var boList = JSONObject.parseArray(item.getText(), CrfJsonValueKeyBo.class);
+                    if (CollectionUtil.isEmpty(boList)) {
+                        return null;
+                    }
+                    List<CrfJsonValueBo> valueBos = new ArrayList<>();
+                    var colKey = JSONObject.parseArray(boList.get(0).getColKey());
+                    for (int i = 0; i < colKey.size(); i++) {
+                        for (CrfJsonValueKeyBo crfJsonValueKeyBo : boList) {
+                            var valueArray = JSONObject.parseArray(crfJsonValueKeyBo.getValue());
+                            valueBos.add(
+                                    new CrfJsonValueBo()
+                                            .setKey(item.getKey() + "-" + colKey.get(i) + "-" + crfJsonValueKeyBo.getId())
+                                            .setName(crfJsonValueKeyBo.getTitle())
+                                            .setValue(crfJsonValueKeyBo.getValue())
+                                            .setText(Objects.isNull(valueArray.get(i)) ? "-" : valueArray.get(i).toString())
+                            );
+                        }
+                    }
+                    return valueBos;
+                } catch (Exception e) {
+                    // log.info("【COPD-DATA-DOCTOR】 ★ crf json 解析异常");
+                    return null;
+                }
+            }).filter(java.util.Objects::nonNull).collect(Collectors.toList());
+            if (CollectionUtil.isNotEmpty(collect)) {
+                collect.forEach(bos::addAll);
+            }
+            return bos.stream().peek(item -> {
+                item.setKeyPrefix(item.getKey());
+            }).collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+
+
+    /**
+     * 递归解析
+     *
+     * @param array
+     * @return
+     */
+    private static List<CrfJsonValueBo> jsonArray(List<CrfJsonValueBo> array) {
+        var collect = array.stream().filter(item -> Objects.nonNull(item.getValue()) && !"".equals(item.getValue())).collect(Collectors.toList());
+        if (CollectionUtil.isEmpty(collect)) {
+            return collect;
+        }
+        List<CrfJsonValueBo> bos = new ArrayList<>();
+        for (CrfJsonValueBo item : collect) {
+            if (Objects.nonNull(item) && Objects.nonNull(item.getValue()) && !"".equals(item.getValue()) && !"null".equals(item.getValue())) {
+                try {
+                    var boList = JSONObject.parseArray(item.getValue(), CrfJsonValueBo.class).stream().filter(Objects::nonNull).collect(Collectors.toList());
+                    if (CollectionUtil.isNotEmpty(boList)) {
+                        bos.addAll(jsonArray(boList));
+                    }
+                } catch (Exception e) {
+                    continue;
+                }
+            }
+        }
+        collect.addAll(bos);
+        return collect;
+    }
+
+    public static void main(String[] args) {
+
+        String a = "{\"form\":[{\"name\":\"基本信息\",\"key\":\"baseInfo_q2OjsA\",\"value\":[{\"key\":\"patientType\",\"name\":\"组别\",\"value\":null,\"text\":null},{\"key\":\"patientName\",\"name\":\"唯一识别码\",\"value\":\"78N6A\",\"text\":\"78N6A\"},{\"key\":\"patientGender\",\"name\":\"性别\",\"value\":[\"F\"],\"text\":\"女\"},{\"key\":\"patientNation\",\"name\":\"民族\",\"value\":null,\"text\":null},{\"key\":\"patientBirthmonth\",\"name\":\"出生年月\",\"value\":\"19930509\",\"text\":\"19930509\"},{\"key\":\"patientAge\",\"name\":\"年龄\",\"value\":\"29\",\"text\":\"29 岁\"},{\"key\":\"patientHeight\",\"name\":\"身高\",\"value\":\"167\",\"text\":\"167 cm\"},{\"key\":\"patientWeight\",\"name\":\"体重\",\"value\":\"54\",\"text\":\"54 kg\"},{\"key\":\"tips\",\"name\":\"备注\",\"value\":null,\"text\":null}]},{\"name\":\"个人史\",\"key\":\"smokeHistory_2NufHa\",\"value\":[{\"key\":\"smokeHis\",\"name\":\"吸烟史\",\"value\":[\"2\"],\"text\":\"戒烟超过1年\"},{\"key\":\"ApreviousSurgical\",\"name\":\"既往手术史\",\"value\":null,\"text\":null},{\"key\":\"previousSurgical\",\"name\":\"既往手术史-名称\",\"value\":null,\"text\":null},{\"key\":\"surgicalTime\",\"name\":\"手术时间(年月)\",\"value\":null,\"text\":null},{\"key\":\"AIndtoxins\",\"name\":\"工业毒物接触史\",\"value\":[\"0\"],\"text\":\"无\"},{\"key\":\"Indtoxins\",\"name\":\"工业毒物接触时长\",\"value\":null,\"text\":null},{\"key\":\"AdustRemoval\",\"name\":\"粉尘接触\",\"value\":[\"1\"],\"text\":\"有\"},{\"key\":\"dustRemoval\",\"name\":\"粉尘接触时长\",\"value\":null,\"text\":null},{\"key\":\"Aradioactive\",\"name\":\"放射性物质接触\",\"value\":[\"0\"],\"text\":\"无\"},{\"key\":\"radioactive\",\"name\":\"放射性物质接触时长\",\"value\":null,\"text\":null},{\"key\":\"foodAllergies\",\"name\":\"食物过敏史\",\"value\":[\"no\"],\"text\":\"无\"},{\"key\":\"drugAllergies\",\"name\":\"药物过敏史\",\"value\":[\"yes\"],\"text\":\"有\"},{\"key\":\"drugAllergiesother\",\"name\":\"其他过敏史(如花粉)\",\"value\":null,\"text\":null},{\"key\":\"familyAllergies\",\"name\":\"父母/祖父母是否有过敏\",\"value\":[\"yes\"],\"text\":\"有\"},{\"key\":\"ispollutionpollution\",\"name\":\"是否曾长期(大于五年)接触空气污染?\",\"value\":[\"no\"],\"text\":\"否\"},{\"key\":\"COVID\",\"name\":\"近1个月是否新冠感染\",\"value\":[\"1\"],\"text\":\"是\"}]},{\"name\":\"现病史(呼吸系统疾病)-近两周\",\"key\":\"CM_history_45UfkY\",\"value\":[{\"key\":\"nowDiseaseTime\",\"name\":\"当前疾病诊断时间\",\"value\":null,\"text\":null},{\"key\":\"isHot\",\"name\":\"发热\",\"value\":null,\"text\":null},{\"key\":\"nasalObstruction\",\"name\":\"鼻塞\",\"value\":null,\"text\":null},{\"key\":\"runNose\",\"name\":\"流涕\",\"value\":null,\"text\":null},{\"key\":\"frequency\",\"name\":\"咳嗽(没有感冒时)\",\"value\":null,\"text\":null},{\"key\":\"expectoration\",\"name\":\"咳痰量\",\"value\":null,\"text\":null},{\"key\":\"vomicaNt\",\"name\":\"咳脓痰\",\"value\":null,\"text\":null},{\"key\":\"pant\",\"name\":\"呼吸困难\",\"value\":null,\"text\":null},{\"key\":\"isBlood\",\"name\":\"咯血\",\"value\":null,\"text\":null},{\"key\":\"chestPain\",\"name\":\"胸痛\",\"value\":null,\"text\":null},{\"key\":\"otherqtzz\",\"name\":\"其他症状\",\"value\":null,\"text\":null},{\"key\":\"everyDayBreathBad\",\"name\":\"每天都有呼吸症状,在体力活动之后喘憋加重\",\"value\":null,\"text\":null},{\"key\":\"nowWorseAir\",\"name\":\"是否遇到刺激性气体等过敏性物质,或者情绪激动时,会引发呼吸道症状,但是之后能恢复正常\",\"value\":null,\"text\":null},{\"key\":\"NDDrugNameis\",\"name\":\"是否有药物治疗\",\"value\":null,\"text\":null},{\"key\":\"XBSHDetail\",\"name\":\"治疗药物详情(药物名称/剂量/给药途径/频率)\",\"value\":null,\"text\":null}]},{\"name\":\"现病史(其他呼吸系统疾病)\",\"key\":\"CMO_history_g3RXLT\",\"value\":[{\"key\":\"isHaveOtherBreath\",\"name\":\"是否有其他呼吸系统疾病\",\"value\":null,\"text\":null},{\"key\":\"otherDiseaseTime\",\"name\":\"诊断时间\",\"value\":null,\"text\":null},{\"key\":\"otherDiseaseName\",\"name\":\"疾病名称\",\"value\":null,\"text\":null},{\"key\":\"NDOBDrugNameis\",\"name\":\"是否有药物治疗\",\"value\":null,\"text\":null},{\"key\":\"XBSOBDetail\",\"name\":\"治疗药物详情(药物名称/剂量/给药途径/频率)\",\"value\":null,\"text\":null}]},{\"name\":\"现病史(非呼吸系统疾病)\",\"key\":\"CMF_history_q4Z5Br\",\"value\":[{\"key\":\"isHaveFBreath\",\"name\":\"是否有非呼吸系统疾病\",\"value\":null,\"text\":null},{\"key\":\"FDiseaseTime\",\"name\":\"诊断时间\",\"value\":null,\"text\":null},{\"key\":\"FDiseaseName\",\"name\":\"疾病名称\",\"value\":null,\"text\":null},{\"key\":\"NDFDrugNameis\",\"name\":\"是否有药物治疗\",\"value\":null,\"text\":null},{\"key\":\"XBSFDetail\",\"name\":\"治疗药物详情(药物名称/剂量/给药途径/频率)\",\"value\":null,\"text\":null}]},{\"name\":\"COPD过去1年内急性加重情况(仅COPD患者填写)\",\"key\":\"AEstatus_j4CJXr\",\"value\":[{\"key\":\"AETimes\",\"name\":\"AE总次数\",\"value\":null,\"text\":null},{\"key\":\"MidAE\",\"name\":\"中度AE\",\"value\":null,\"text\":null},{\"key\":\"highAE\",\"name\":\"重度AE\",\"value\":null,\"text\":null}]},{\"name\":\"HRCT\",\"key\":\"lungCTcheck_qHV_iL\",\"value\":[{\"key\":\"HRCTclear\",\"name\":\"是否已完成HRCT检查\",\"value\":null,\"text\":null},{\"key\":\"HRCTtime\",\"name\":\"HRCT检查日期\",\"value\":null,\"text\":null},{\"key\":\"HRCTcheck\",\"name\":\"HRCT诊断\",\"value\":null,\"text\":null},{\"key\":\"HRCTdescribe\",\"name\":\"HRCT描述\",\"value\":null,\"text\":null}]},{\"name\":\"胸部X线\",\"key\":\"lungCTcheckLower_DPV4NP\",\"value\":[{\"key\":\"chestXDateclear\",\"name\":\"是否已完成胸部X线检查\",\"value\":null,\"text\":null},{\"key\":\"chestXDate\",\"name\":\"胸部X线检查日期\",\"value\":null,\"text\":null},{\"key\":\"chestXresult\",\"name\":\"胸部X线检查结果\",\"value\":null,\"text\":null},{\"key\":\"chestXdescribe\",\"name\":\"胸部X线检查描述\",\"value\":null,\"text\":null}]},{\"name\":\"肺功能(哮喘与COPD必填)\",\"key\":\"lungFunction_inf_PtaUZb\",\"value\":[{\"key\":\"zqgkzjEight\",\"name\":\"是否停支气管舒张剂或激素类8h以上\",\"value\":null,\"text\":null},{\"key\":\"pulResult\",\"name\":\"舒张试验\",\"value\":null,\"text\":null},{\"key\":\"sdacJl\",\"name\":\"沙丁胺醇吸入剂量\",\"value\":null,\"text\":null},{\"key\":\"before\",\"name\":\"支气管扩张剂吸入前\",\"value\":[{\"predicted\":\"--\",\"real\":\"--\",\"percent\":\"--\",\"id\":\"0\",\"title\":\"FEV1%\"},{\"predicted\":\"--\",\"real\":\"--\",\"percent\":\"--\",\"id\":\"1\",\"title\":\"FEV1\"},{\"predicted\":\"--\",\"real\":\"--\",\"percent\":\"--\",\"id\":\"2\",\"title\":\"FVC\"},{\"predicted\":\"--\",\"real\":\"--\",\"percent\":\"--\",\"id\":\"3\",\"title\":\"FEV1/FVC\"}],\"text\":[{\"title\":\"FEV1%\",\"value\":[\"--\",\"--\",\"--\"],\"colKey\":[\"predicted\",\"real\",\"percent\"],\"colName\":[\"预计值\",\"前次\",\"前/预\"],\"id\":\"0\"},{\"title\":\"FEV1\",\"value\":[\"--\",\"--\",\"--\"],\"colKey\":[\"predicted\",\"real\",\"percent\"],\"colName\":[\"预计值\",\"前次\",\"前/预\"],\"id\":\"1\"},{\"title\":\"FVC\",\"value\":[\"--\",\"--\",\"--\"],\"colKey\":[\"predicted\",\"real\",\"percent\"],\"colName\":[\"预计值\",\"前次\",\"前/预\"],\"id\":\"2\"},{\"title\":\"FEV1/FVC\",\"value\":[\"--\",\"--\",\"--\"],\"colKey\":[\"predicted\",\"real\",\"percent\"],\"colName\":[\"预计值\",\"前次\",\"前/预\"],\"id\":\"3\"}]},{\"key\":\"after\",\"name\":\"支气管扩张剂吸入后\",\"value\":[{\"real\":\"--\",\"percent\":\"--\",\"better\":\"--\",\"id\":\"0\",\"title\":\"FEV1%\"},{\"real\":\"--\",\"percent\":\"--\",\"better\":\"--\",\"id\":\"1\",\"title\":\"FEV1\"},{\"real\":\"--\",\"percent\":\"--\",\"better\":\"--\",\"id\":\"2\",\"title\":\"FVC\"},{\"real\":\"--\",\"percent\":\"--\",\"better\":\"--\",\"id\":\"3\",\"title\":\"FEV1/FVC\"}],\"text\":[{\"title\":\"FEV1%\",\"value\":[\"--\",\"--\",\"--\"],\"colKey\":[\"real\",\"percent\",\"better\"],\"colName\":[\"后次\",\"后/预\",\"改善率\"],\"id\":\"0\"},{\"title\":\"FEV1\",\"value\":[\"--\",\"--\",\"--\"],\"colKey\":[\"real\",\"percent\",\"better\"],\"colName\":[\"后次\",\"后/预\",\"改善率\"],\"id\":\"1\"},{\"title\":\"FVC\",\"value\":[\"--\",\"--\",\"--\"],\"colKey\":[\"real\",\"percent\",\"better\"],\"colName\":[\"后次\",\"后/预\",\"改善率\"],\"id\":\"2\"},{\"title\":\"FEV1/FVC\",\"value\":[\"--\",\"--\",\"--\"],\"colKey\":[\"real\",\"percent\",\"better\"],\"colName\":[\"后次\",\"后/预\",\"改善率\"],\"id\":\"3\"}]}]}],\"crfId\":\"1828353427575558144\",\"answer\":{\"patientName\":\"78N6A\",\"patientGender\":[\"F\"],\"patientPhone\":\"\",\"patientBirth\":\"\",\"patientHeight\":\"167\",\"patientWeight\":\"54\",\"patientAge\":\"29\",\"patientBirthmonth\":\"19930509\",\"smokeHis\":[\"2\"],\"AIndtoxins\":[\"0\"],\"AdustRemoval\":[\"1\"],\"Aradioactive\":[\"0\"],\"foodAllergies\":[\"no\"],\"drugAllergies\":[\"yes\"],\"familyAllergies\":[\"yes\"],\"ispollutionpollution\":[\"no\"],\"COVID\":[\"1\"],\"before\":[{\"id\":\"0\",\"title\":\"FEV1%\"},{\"id\":\"1\",\"title\":\"FEV1\"},{\"id\":\"2\",\"title\":\"FVC\"},{\"id\":\"3\",\"title\":\"FEV1/FVC\"}],\"after\":[{\"id\":\"0\",\"title\":\"FEV1%\"},{\"id\":\"1\",\"title\":\"FEV1\"},{\"id\":\"2\",\"title\":\"FVC\"},{\"id\":\"3\",\"title\":\"FEV1/FVC\"}]}}";
+        String form = "{\"displayType\":\"column\",\"code\":\"patient_inf\",\"name\":\"患者录入表单\",\"type\":\"object\",\"properties\":{\"baseInfo_q2OjsA\":{\"type\":\"object\",\"description\":\"\",\"title\":\"基本信息\",\"questionType\":\"TEMPLATE\",\"lucaBanpickDataId\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"baseInfo\"},\"properties\":{\"radio_pZJcYQ\":{\"title\":\"组别\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"patientType\"},\"options\":[{\"id\":\"0\",\"name\":\"COPD\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"支气管哮喘\",\"code\":\"2\"},{\"id\":\"2\",\"name\":\"支气管扩张\",\"code\":\"3\"},{\"id\":\"3\",\"name\":\"上呼吸道感染\",\"code\":\"4\"},{\"id\":\"4\",\"name\":\"下呼吸道感染\",\"code\":\"5\"},{\"id\":\"5\",\"name\":\"慢性支气管炎\",\"code\":\"7\"},{\"id\":\"6\",\"name\":\"咳嗽\",\"code\":\"8\"},{\"id\":\"7\",\"name\":\"健康人\",\"code\":\"6\"}],\"enum\":[\"1\",\"2\",\"3\",\"4\",\"5\",\"7\",\"8\",\"6\"],\"enumNames\":[\"COPD\",\"支气管哮喘\",\"支气管扩张\",\"上呼吸道感染\",\"下呼吸道感染\",\"慢性支气管炎\",\"咳嗽\",\"健康人\"]},\"input_eI5d5N\":{\"title\":\"唯一识别码\",\"type\":\"string\",\"questionType\":\"TEXT\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"patientName\"},\"rangeLength\":{\"min\":1,\"max\":5},\"min\":1,\"max\":5,\"show\":{\"questions\":[],\"options\":[]}},\"radio_2BZqLQ\":{\"title\":\"性别\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"patientGender\"},\"options\":[{\"id\":\"0\",\"name\":\"男\",\"code\":\"M\"},{\"id\":\"1\",\"name\":\"女\",\"code\":\"F\"}],\"enum\":[\"M\",\"F\"],\"enumNames\":[\"男\",\"女\"]},\"input_1vS3p_\":{\"title\":\"民族\",\"type\":\"string\",\"questionType\":\"TEXT\",\"required\":false,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"patientNation\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"input_BBOEYs\":{\"title\":\"出生年月\",\"type\":\"string\",\"questionType\":\"TEXT\",\"description\":\"如1990年12月,请输入199012\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"patientBirthmonth\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"number_GfRINe\":{\"title\":\"年龄\",\"type\":\"number\",\"questionType\":\"NUMBER\",\"widget\":\"CrfInputNumber\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"patientAge\"},\"range\":{\"min\":0,\"max\":0},\"unit\":\"岁\",\"min\":0,\"max\":0,\"required\":true},\"number_xhJFdf\":{\"title\":\"身高\",\"type\":\"number\",\"questionType\":\"NUMBER\",\"widget\":\"CrfInputNumber\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"patientHeight\"},\"range\":{\"min\":0,\"max\":0},\"unit\":\"cm\",\"min\":0,\"max\":0,\"required\":true},\"number_2NItPR\":{\"title\":\"体重\",\"type\":\"number\",\"questionType\":\"NUMBER\",\"widget\":\"CrfInputNumber\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"patientWeight\"},\"range\":{\"min\":0,\"max\":0},\"unit\":\"kg\",\"min\":0,\"max\":0,\"required\":true},\"textarea_InDWcs\":{\"title\":\"备注\",\"type\":\"string\",\"format\":\"textarea\",\"questionType\":\"TEXTAREA\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"tips\"},\"rangeLength\":{\"min\":0,\"max\":400},\"min\":0,\"max\":400}}},\"smokeHistory_2NufHa\":{\"type\":\"object\",\"description\":\"\",\"title\":\"个人史\",\"questionType\":\"TEMPLATE\",\"lucaBanpickDataId\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"smokeHistory\"},\"required\":true,\"properties\":{\"radio_wxrmgo\":{\"title\":\"吸烟史\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"smokeHis\"},\"options\":[{\"id\":\"0\",\"name\":\"正在吸烟/戒烟未满1年\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"戒烟超过1年\",\"code\":\"2\"},{\"id\":\"2\",\"name\":\"从不吸烟\",\"code\":\"3\"}],\"enum\":[\"1\",\"2\",\"3\"],\"enumNames\":[\"正在吸烟/戒烟未满1年\",\"戒烟超过1年\",\"从不吸烟\"]},\"radio_PjH1Z_\":{\"title\":\"既往手术史\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"ApreviousSurgical\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"0\"}],\"enum\":[\"1\",\"0\"],\"enumNames\":[\"有\",\"无\"]},\"input_ELJeHV\":{\"title\":\"既往手术史-名称\",\"type\":\"string\",\"questionType\":\"TEXT\",\"description\":\"\",\"required\":false,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"previousSurgical\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"input_meEqwd\":{\"title\":\"手术时间(年月)\",\"type\":\"string\",\"questionType\":\"TEXT\",\"description\":\"如1990年12月,请输入199012\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"surgicalTime\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"radio_Sk6gDE\":{\"title\":\"工业毒物接触史\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"AIndtoxins\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"0\"}],\"enum\":[\"1\",\"0\"],\"enumNames\":[\"有\",\"无\"]},\"number_ML7RDe\":{\"title\":\"工业毒物接触时长\",\"type\":\"number\",\"questionType\":\"NUMBER\",\"widget\":\"CrfInputNumber\",\"description\":\"\",\"required\":false,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"Indtoxins\"},\"range\":{\"min\":0,\"max\":0},\"unit\":\"年\",\"min\":0,\"max\":0},\"radio_ksSICF\":{\"title\":\"粉尘接触\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"AdustRemoval\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"0\"}],\"enum\":[\"1\",\"0\"],\"enumNames\":[\"有\",\"无\"]},\"number_0Pj-iN\":{\"title\":\"粉尘接触时长\",\"type\":\"number\",\"questionType\":\"NUMBER\",\"widget\":\"CrfInputNumber\",\"description\":\"\",\"required\":false,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"dustRemoval\"},\"range\":{\"min\":0,\"max\":0},\"unit\":\"年\",\"min\":0,\"max\":0},\"radio_IFLN4Y\":{\"title\":\"放射性物质接触\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"Aradioactive\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"0\"}],\"enum\":[\"1\",\"0\"],\"enumNames\":[\"有\",\"无\"]},\"number_xhGgoA\":{\"title\":\"放射性物质接触时长\",\"type\":\"number\",\"questionType\":\"NUMBER\",\"widget\":\"CrfInputNumber\",\"description\":\"\",\"required\":false,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"radioactive\"},\"range\":{\"min\":0,\"max\":0},\"unit\":\"年\",\"min\":0,\"max\":0},\"radio_CoFBNM\":{\"title\":\"食物过敏史\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"description\":\"\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"foodAllergies\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"radio_9lmZfk\":{\"title\":\"药物过敏史\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"drugAllergies\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"input_-LeeUZ\":{\"title\":\"其他过敏史(如花粉)\",\"type\":\"string\",\"questionType\":\"TEXT\",\"required\":false,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"drugAllergiesother\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"radio_VHyLEJ\":{\"title\":\"父母/祖父母是否有过敏\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"description\":\"过敏性鼻炎、湿疹皮肤过敏、食物过敏等\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"familyAllergies\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"radio_nnqvcY\":{\"title\":\"是否曾长期(大于五年)接触空气污染?\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"description\":\"空气污染包含粉尘、刺激气体、麻将室茶馆室二手烟,或常年工作在化工、纺织车间等有空气污染的环境\",\"required\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"ispollutionpollution\"},\"options\":[{\"id\":\"0\",\"name\":\"是\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"否\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"是\",\"否\"]},\"radio_5veO9S\":{\"title\":\"近1个月是否新冠感染\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"description\":\"鼻或咽拭子抗原/聚合酶链反应 (PCR)检测阳性\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"COVID\"},\"options\":[{\"id\":\"0\",\"name\":\"是\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"否\",\"code\":\"2\"}],\"enum\":[\"1\",\"2\"],\"enumNames\":[\"是\",\"否\"],\"required\":true}}},\"CM_history_45UfkY\":{\"type\":\"object\",\"title\":\"现病史(呼吸系统疾病)-近两周\",\"description\":\"\",\"questionType\":\"TEMPLATE\",\"lucaBanpickDataId\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"CM_history\"},\"properties\":{\"date_SZbSoa\":{\"title\":\"当前疾病诊断时间\",\"type\":\"string\",\"format\":\"date\",\"questionType\":\"DATE\",\"widget\":\"CrfDatePick\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"nowDiseaseTime\"}},\"radio_RRlBks\":{\"title\":\"发热\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"isHot\"},\"options\":[{\"id\":\"0\",\"name\":\"37.3~38℃\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"38.1~39℃\",\"code\":\"2\"},{\"id\":\"2\",\"name\":\"39.1~41℃\",\"code\":\"3\"},{\"id\":\"3\",\"name\":\"≥41℃\",\"code\":\"4\"}],\"enum\":[\"1\",\"2\",\"3\",\"4\"],\"enumNames\":[\"37.3~38℃\",\"38.1~39℃\",\"39.1~41℃\",\"≥41℃\"]},\"radio_9Wf2Pa\":{\"title\":\"鼻塞\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"nasalObstruction\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"radio_BKQTvO\":{\"title\":\"流涕\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"runNose\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"radio_3oCGKT\":{\"title\":\"咳嗽(没有感冒时)\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"VS\",\"dataId\":\"frequency\"},\"options\":[{\"id\":\"0\",\"name\":\"无明显咳嗽\",\"code\":\"neverCough\"},{\"id\":\"1\",\"name\":\"早晨居多\",\"code\":\"mornMore\"},{\"id\":\"2\",\"name\":\"夜间居多\",\"code\":\"nightMore\"},{\"id\":\"3\",\"name\":\"全天偶有咳嗽\",\"code\":\"occasionalCough\"},{\"id\":\"4\",\"name\":\"咳嗽频繁\",\"code\":\"frequentCough\"}],\"enum\":[\"neverCough\",\"mornMore\",\"nightMore\",\"occasionalCough\",\"frequentCough\"],\"enumNames\":[\"无明显咳嗽\",\"早晨居多\",\"夜间居多\",\"全天偶有咳嗽\",\"咳嗽频繁\"]},\"radio_4MD3cs\":{\"title\":\"咳痰量\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"VS\",\"dataId\":\"expectoration\"},\"options\":[{\"id\":\"0\",\"name\":\"无明显咳痰\",\"code\":\"neverExpectorate\"},{\"id\":\"1\",\"name\":\"咳痰10ml以下\",\"code\":\"belowTen\"},{\"id\":\"2\",\"name\":\"咳痰10ml以上\",\"code\":\"aboveTen\"}],\"enum\":[\"neverExpectorate\",\"belowTen\",\"aboveTen\"],\"enumNames\":[\"无明显咳痰\",\"咳痰10ml以下\",\"咳痰10ml以上\"]},\"radio_svNkPO\":{\"title\":\"咳脓痰\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"vomicaNt\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"radio_EKR86w\":{\"title\":\"呼吸困难\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"VS\",\"dataId\":\"pant\"},\"options\":[{\"id\":\"0\",\"name\":\"无\",\"code\":\"neverPant\"},{\"id\":\"1\",\"name\":\"剧烈活动时出现\",\"code\":\"occasionallyPant\"},{\"id\":\"2\",\"name\":\"日常活动时发生,休息时不发生\",\"code\":\"whenActive\"},{\"id\":\"3\",\"name\":\"喘息不能平躺,影响休息与活动\",\"code\":\"alwaysPant\"}],\"enum\":[\"neverPant\",\"occasionallyPant\",\"whenActive\",\"alwaysPant\"],\"enumNames\":[\"无\",\"剧烈活动时出现\",\"日常活动时发生,休息时不发生\",\"喘息不能平躺,影响休息与活动\"]},\"radio_H-oWj_\":{\"title\":\"咯血\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"isBlood\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"radio_iFybYL\":{\"title\":\"胸痛\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"chestPain\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"input_Tv2xuD\":{\"title\":\"其他症状\",\"type\":\"string\",\"questionType\":\"TEXT\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"otherqtzz\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"radio_pMRb1u\":{\"title\":\"每天都有呼吸症状,在体力活动之后喘憋加重\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"description\":\"喘息,咳嗽,呼吸困难,胸闷或疼痛\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"everyDayBreathBad\"},\"options\":[{\"id\":\"0\",\"name\":\"是\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"否\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"是\",\"否\"]},\"radio_6FzCNg\":{\"title\":\"是否遇到刺激性气体等过敏性物质,或者情绪激动时,会引发呼吸道症状,但是之后能恢复正常\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"description\":\"喘息,咳嗽,呼吸困难,胸闷或疼痛\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"nowWorseAir\"},\"options\":[{\"id\":\"0\",\"name\":\"是\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"否\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"是\",\"否\"]},\"radio_mN0BSK\":{\"title\":\"是否有药物治疗\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"NDDrugNameis\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"0\"}],\"enum\":[\"1\",\"0\"],\"enumNames\":[\"有\",\"无\"]},\"textarea_VcEcqT\":{\"title\":\"治疗药物详情(药物名称/剂量/给药途径/频率)\",\"type\":\"string\",\"format\":\"textarea\",\"questionType\":\"TEXTAREA\",\"description\":\"填写示例:药物1,2mg,口服,每天2次\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"XBSHDetail\"},\"rangeLength\":{\"min\":0,\"max\":400},\"min\":0,\"max\":400}}},\"CMO_history_g3RXLT\":{\"type\":\"object\",\"description\":\"\",\"title\":\"现病史(其他呼吸系统疾病)\",\"questionType\":\"TEMPLATE\",\"lucaBanpickDataId\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"CMO_history\"},\"properties\":{\"radio_gmS0wy\":{\"title\":\"是否有其他呼吸系统疾病\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"isHaveOtherBreath\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"date_SZbSoa\":{\"title\":\"诊断时间\",\"type\":\"string\",\"format\":\"date\",\"questionType\":\"DATE\",\"widget\":\"CrfDatePick\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"otherDiseaseTime\"}},\"input_sXY8NP\":{\"title\":\"疾病名称\",\"type\":\"string\",\"questionType\":\"TEXT\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"otherDiseaseName\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"radio_bsMHh_\":{\"title\":\"是否有药物治疗\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"NDOBDrugNameis\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"0\"}],\"enum\":[\"1\",\"0\"],\"enumNames\":[\"有\",\"无\"]},\"textarea_ju4cIb\":{\"title\":\"治疗药物详情(药物名称/剂量/给药途径/频率)\",\"type\":\"string\",\"format\":\"textarea\",\"questionType\":\"TEXTAREA\",\"description\":\"填写示例:药物1,2mg,口服,每天2次\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"XBSOBDetail\"},\"rangeLength\":{\"min\":0,\"max\":400},\"min\":0,\"max\":400}}},\"CMF_history_q4Z5Br\":{\"type\":\"object\",\"description\":\"\",\"title\":\"现病史(非呼吸系统疾病)\",\"questionType\":\"TEMPLATE\",\"lucaBanpickDataId\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"CMF_history\"},\"properties\":{\"radio_gmS0wy\":{\"title\":\"是否有非呼吸系统疾病\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"isHaveFBreath\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"有\",\"无\"]},\"date_SZbSoa\":{\"title\":\"诊断时间\",\"type\":\"string\",\"format\":\"date\",\"questionType\":\"DATE\",\"widget\":\"CrfDatePick\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"FDiseaseTime\"}},\"input_sXY8NP\":{\"title\":\"疾病名称\",\"type\":\"string\",\"questionType\":\"TEXT\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"FDiseaseName\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"radio_Arisrv\":{\"title\":\"是否有药物治疗\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"NDFDrugNameis\"},\"options\":[{\"id\":\"0\",\"name\":\"有\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"无\",\"code\":\"0\"}],\"enum\":[\"1\",\"0\"],\"enumNames\":[\"有\",\"无\"]},\"textarea_FrL9N0\":{\"title\":\"治疗药物详情(药物名称/剂量/给药途径/频率)\",\"type\":\"string\",\"format\":\"textarea\",\"questionType\":\"TEXTAREA\",\"description\":\"填写示例:药物1,2mg,口服,每天2次\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"XBSFDetail\"},\"rangeLength\":{\"min\":0,\"max\":400},\"min\":0,\"max\":400}}},\"AEstatus_j4CJXr\":{\"type\":\"object\",\"description\":\"\",\"title\":\"COPD过去1年内急性加重情况(仅COPD患者填写)\",\"questionType\":\"TEMPLATE\",\"lucaBanpickDataId\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"AEstatus\"},\"properties\":{\"number_d3YdWP\":{\"title\":\"AE总次数\",\"type\":\"number\",\"questionType\":\"NUMBER\",\"widget\":\"CrfInputNumber\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"AETimes\"},\"range\":{\"min\":0,\"max\":0},\"unit\":\"次\",\"min\":0,\"max\":0},\"number_s3YyoQ\":{\"title\":\"中度AE\",\"type\":\"number\",\"questionType\":\"NUMBER\",\"widget\":\"CrfInputNumber\",\"description\":\"使用短效支气管扩张剂和抗生素治疗和/或口服糖皮质激素\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"MidAE\"},\"range\":{\"min\":0,\"max\":0},\"unit\":\"次\",\"min\":0,\"max\":0},\"number_b5HNLY\":{\"title\":\"重度AE\",\"type\":\"number\",\"questionType\":\"NUMBER\",\"widget\":\"CrfInputNumber\",\"description\":\"需要住院或急诊、ICU 治疗\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"highAE\"},\"range\":{\"min\":0,\"max\":0},\"unit\":\"次\",\"min\":0,\"max\":0}}},\"lungCTcheck_qHV_iL\":{\"type\":\"object\",\"description\":\"\",\"title\":\"HRCT\",\"questionType\":\"TEMPLATE\",\"lucaBanpickDataId\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"lungCTcheck\"},\"properties\":{\"radio_eQ7i2_\":{\"title\":\"是否已完成HRCT检查\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"HRCTclear\"},\"options\":[{\"id\":\"0\",\"name\":\"是\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"否\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"是\",\"否\"]},\"date_eLLo3o\":{\"title\":\"HRCT检查日期\",\"type\":\"string\",\"format\":\"date\",\"questionType\":\"DATE\",\"widget\":\"CrfDatePick\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"HRCTtime\"}},\"input_REgSRb\":{\"title\":\"HRCT诊断\",\"type\":\"string\",\"questionType\":\"TEXT\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"HRCTcheck\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"textarea_1nJhSZ\":{\"title\":\"HRCT描述\",\"type\":\"string\",\"format\":\"textarea\",\"questionType\":\"TEXTAREA\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"HRCTdescribe\"},\"rangeLength\":{\"min\":0,\"max\":400},\"min\":0,\"max\":400}}},\"lungCTcheckLower_DPV4NP\":{\"type\":\"object\",\"description\":\"\",\"title\":\"胸部X线\",\"questionType\":\"TEMPLATE\",\"lucaBanpickDataId\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"lungCTcheckLower\"},\"properties\":{\"radio_F3h09O\":{\"title\":\"是否已完成胸部X线检查\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"chestXDateclear\"},\"options\":[{\"id\":\"0\",\"name\":\"是\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"否\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"是\",\"否\"]},\"date_OPurFU\":{\"title\":\"胸部X线检查日期\",\"type\":\"string\",\"format\":\"date\",\"questionType\":\"DATE\",\"widget\":\"CrfDatePick\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"chestXDate\"}},\"input_GhAtyb\":{\"title\":\"胸部X线检查结果\",\"type\":\"string\",\"questionType\":\"TEXT\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"chestXresult\"},\"rangeLength\":{\"min\":0,\"max\":200},\"min\":0,\"max\":200},\"textarea_V0f1S3\":{\"title\":\"胸部X线检查描述\",\"type\":\"string\",\"format\":\"textarea\",\"questionType\":\"TEXTAREA\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"chestXdescribe\"},\"rangeLength\":{\"min\":0,\"max\":400},\"min\":0,\"max\":400}}},\"lungFunction_inf_PtaUZb\":{\"type\":\"object\",\"description\":\"\",\"title\":\"肺功能(哮喘与COPD必填)\",\"questionType\":\"TEMPLATE\",\"lucaBanpickDataId\":true,\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"lungFunction_inf\"},\"properties\":{\"radio_eiDPtt\":{\"title\":\"是否停支气管舒张剂或激素类8h以上\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"zqgkzjEight\"},\"options\":[{\"id\":\"0\",\"name\":\"是\",\"code\":\"yes\"},{\"id\":\"1\",\"name\":\"否\",\"code\":\"no\"}],\"enum\":[\"yes\",\"no\"],\"enumNames\":[\"是\",\"否\"]},\"radio_TwQ-dW\":{\"title\":\"舒张试验\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"pulResult\"},\"options\":[{\"id\":\"0\",\"name\":\"阳性\",\"code\":\"positive\"},{\"id\":\"1\",\"name\":\"阴性\",\"code\":\"negative\"}],\"enum\":[\"positive\",\"negative\"],\"enumNames\":[\"阳性\",\"阴性\"]},\"radio_g2D3JC\":{\"title\":\"沙丁胺醇吸入剂量\",\"type\":\"string\",\"widget\":\"radio\",\"questionType\":\"RADIO\",\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"MH\",\"dataId\":\"sdacJl\"},\"options\":[{\"id\":\"0\",\"name\":\"100μg\",\"code\":\"1\"},{\"id\":\"1\",\"name\":\"200μg\",\"code\":\"2\"},{\"id\":\"2\",\"name\":\"400μg\",\"code\":\"3\"},{\"id\":\"3\",\"name\":\"不详\",\"code\":\"4\"}],\"enum\":[\"1\",\"2\",\"3\",\"4\"],\"enumNames\":[\"100μg\",\"200μg\",\"400μg\",\"不详\"]},\"newTabel_CeMggW\":{\"title\":\"支气管扩张剂吸入前\",\"type\":\"array\",\"questionType\":\"CRFTABLE\",\"widget\":\"CrfTable\",\"items\":{\"type\":\"object\",\"properties\":{}},\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"VS\",\"dataId\":\"before\"},\"columns\":[{\"id\":\"0\",\"title\":\"指标\",\"dataIndex\":\"title\",\"type\":\"TEXT\"},{\"id\":\"1\",\"title\":\"预计值\",\"dataIndex\":\"predicted\",\"type\":\"INPUT\"},{\"id\":\"2\",\"title\":\"前次\",\"dataIndex\":\"real\",\"type\":\"INPUT\"},{\"id\":\"3\",\"title\":\"前/预\",\"dataIndex\":\"percent\",\"type\":\"INPUT\"}],\"defaultValue\":[{\"id\":\"0\",\"title\":\"FEV1%\"},{\"id\":\"1\",\"title\":\"FEV1\"},{\"id\":\"2\",\"title\":\"FVC\"},{\"id\":\"3\",\"title\":\"FEV1/FVC\"}],\"description\":\"\"},\"newTabel_U738QJ\":{\"title\":\"支气管扩张剂吸入后\",\"type\":\"array\",\"questionType\":\"CRFTABLE\",\"widget\":\"CrfTable\",\"items\":{\"type\":\"object\",\"properties\":{}},\"BindData\":{\"dataType\":\"CUSTOMIZE\",\"choiceField\":\"DM\",\"dataId\":\"after\"},\"columns\":[{\"id\":\"0\",\"title\":\"指标\",\"dataIndex\":\"title\",\"type\":\"TEXT\"},{\"id\":\"1\",\"title\":\"后次\",\"dataIndex\":\"real\",\"type\":\"INPUT\"},{\"id\":\"2\",\"title\":\"后/预\",\"dataIndex\":\"percent\",\"type\":\"INPUT\"},{\"id\":\"3\",\"title\":\"改善率\",\"dataIndex\":\"better\",\"type\":\"INPUT\"}],\"defaultValue\":[{\"id\":\"0\",\"title\":\"FEV1%\"},{\"id\":\"1\",\"title\":\"FEV1\"},{\"id\":\"2\",\"title\":\"FVC\"},{\"id\":\"3\",\"title\":\"FEV1/FVC\"}],\"description\":\"\"}}}}}";
+
+        System.out.println(JSONUtil.toJsonStr(crfProblemJsonAnalysisNew(form)));
+        System.out.println(JSONUtil.toJsonStr(crfJsonAnalysis(a)));
+
+        System.out.println(parseCrfProblemAndAnswer(form, a));
+    }
+
+}
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..ba66105
--- /dev/null
+++ b/src/main/resources/application-dev.yml
@@ -0,0 +1,11 @@
+# server
+SERVER-PORT: 8181
+
+#MGDB
+MGDB-ADDRESS: 47.92.245.13:30606
+MGDB-NAME: root
+MGDB-PASSWORD: 123456
+MGDB-DATABASE: luca-copy-dev
+MGDB-AUTHSOURCE: admin
+
+ARCHIVE-MGDB-DATABASE: luca_dev
diff --git a/src/main/resources/application-hj.yml b/src/main/resources/application-hj.yml
new file mode 100644
index 0000000..24c2218
--- /dev/null
+++ b/src/main/resources/application-hj.yml
@@ -0,0 +1,15 @@
+# server
+SERVER-PORT: 8181
+
+#MGDB
+MGDB-ADDRESS: 47.92.245.13:30606
+MGDB-NAME: root
+MGDB-PASSWORD: 123456
+MGDB-DATABASE: luca-copy-dev
+#MGDB-DATABASE: luca-copy-uat
+MGDB-AUTHSOURCE: admin
+
+ARCHIVE-MGDB-DATABASE: luca_dev
+#ARCHIVE-MGDB-DATABASE: luca_uat
+
+
diff --git a/src/main/resources/application-uat.yml b/src/main/resources/application-uat.yml
new file mode 100644
index 0000000..830c610
--- /dev/null
+++ b/src/main/resources/application-uat.yml
@@ -0,0 +1,13 @@
+# server
+SERVER-PORT: 8181
+
+#MGDB
+MGDB-ADDRESS: 47.92.245.13:30606
+MGDB-NAME: root
+MGDB-PASSWORD: 123456
+MGDB-DATABASE: luca-copy-uat
+MGDB-AUTHSOURCE: admin
+
+ARCHIVE-MGDB-DATABASE: luca_uat
+
+
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
new file mode 100644
index 0000000..5026fde
--- /dev/null
+++ b/src/main/resources/application.yml
@@ -0,0 +1,15 @@
+server:
+  port: ${SERVER-PORT:8181}
+
+spring:
+  profiles:
+    active: ${ACTIVE-PROFILES:local}
+  application:
+    name: BACKEND
+  data:
+    base-mongodb:
+      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}
+
+
diff --git a/src/test/java/com/luca/pilot/PilotApplicationTests.java b/src/test/java/com/luca/pilot/PilotApplicationTests.java
new file mode 100644
index 0000000..9490718
--- /dev/null
+++ b/src/test/java/com/luca/pilot/PilotApplicationTests.java
@@ -0,0 +1,13 @@
+package com.luca.pilot;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class PilotApplicationTests {
+
+	@Test
+	void contextLoads() {
+	}
+
+}
diff --git a/src/test/java/com/luca/pilot/PlanTaskTest.java b/src/test/java/com/luca/pilot/PlanTaskTest.java
new file mode 100644
index 0000000..9460f7c
--- /dev/null
+++ b/src/test/java/com/luca/pilot/PlanTaskTest.java
@@ -0,0 +1,90 @@
+package com.luca.pilot;
+
+import cn.hutool.json.JSONUtil;
+import com.luca.pilot.entity.UserArchive;
+import com.luca.pilot.service.BaseModuleViewService;
+import com.luca.pilot.service.PlanService;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.test.context.ActiveProfiles;
+
+import java.util.List;
+
+@Slf4j
+@SpringBootTest
+@ActiveProfiles("hj")
+public class PlanTaskTest {
+    @Autowired
+    private MongoTemplate mongoTemplate;
+    @Autowired
+    private PlanService planService;
+    @Autowired
+    private BaseModuleViewService baseModuleViewService;
+
+
+    @Test
+    void synchronizePlanTask2() {
+        // 创建查询条件
+        Query query = new Query();
+        query.addCriteria(Criteria.where("createAt").lt("2023-12-07 14:50"));
+        long count = mongoTemplate.count(query, UserArchive.class);
+        log.info("total count:{}", count);
+
+        long skip = count / 10;
+        if (count % 10 > 0) {
+            skip++;
+        }
+
+
+        for (int i = 0; i < skip; i++) {
+            query.skip(i * 10L);
+            query.limit(10);
+            List<UserArchive> userArchives = mongoTemplate.find(query, UserArchive.class);
+            log.info("userArchives count:{}", userArchives.size());
+        }
+
+    }
+
+    @Test
+    void synchronizeModuleView() {
+        baseModuleViewService.synchronizeModuleView();
+    }
+
+
+
+    @Test
+    void synchronizePlanTask() {
+        planService.synchronizePlanTask();
+    }
+
+    @Test
+    void contextLoads() {
+        Book book = new Book();
+        book.setId(10);
+        book.setName("testMongoDB");
+        book.setType("testMongoDB");
+        book.setDescription("testMongoDB");
+        mongoTemplate.save(book);
+    }
+
+    @Test
+    void find() {
+        List<Book> all = mongoTemplate.findAll(Book.class);
+        System.out.println(all);
+    }
+
+    @Data
+    class Book {
+        private int id;
+        private String name;
+        private String type;
+        private String description;
+    }
+}
+
-- 
GitLab