alibct пре 2 месеци
комит
1f460854e2
100 измењених фајлова са 5740 додато и 0 уклоњено
  1. 38 0
      .gitignore
  2. 10 0
      .idea/.gitignore
  3. 5 0
      .idea/codeStyles/codeStyleConfig.xml
  4. 17 0
      .idea/dataSources.xml
  5. 33 0
      .idea/encodings.xml
  6. 10 0
      .idea/inspectionProfiles/Project_Default.xml
  7. 21 0
      .idea/misc.xml
  8. 21 0
      .idea/sqldialects.xml
  9. 6 0
      .idea/vcs.xml
  10. BIN
      .style/Java开发手册(黄山版).pdf
  11. 380 0
      .style/p3c-codestyle.xml
  12. 149 0
      pavis-common/pom.xml
  13. 201 0
      pavis-common/src/main/java/com/pavis/admin/common/config/doc/GlobalAuthenticationCustomizer.java
  14. 49 0
      pavis-common/src/main/java/com/pavis/admin/common/config/doc/GlobalDescriptionCustomizer.java
  15. 165 0
      pavis-common/src/main/java/com/pavis/admin/common/config/doc/OperationDescriptionCustomizer.java
  16. 24 0
      pavis-common/src/main/java/com/pavis/admin/common/config/excel/DictExcelProperty.java
  17. 77 0
      pavis-common/src/main/java/com/pavis/admin/common/config/excel/ExcelDictConverter.java
  18. 176 0
      pavis-common/src/main/java/com/pavis/admin/common/config/exception/GlobalExceptionHandler.java
  19. 57 0
      pavis-common/src/main/java/com/pavis/admin/common/config/exception/GlobalSaTokenExceptionHandler.java
  20. 35 0
      pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/BCryptEncryptor.java
  21. 42 0
      pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/DataPermissionMapper.java
  22. 38 0
      pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/DefaultDataPermissionUserContextProvider.java
  23. 97 0
      pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java
  24. 42 0
      pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/MybatisPlusConfiguration.java
  25. 82 0
      pavis-common/src/main/java/com/pavis/admin/common/config/properties/CaptchaProperties.java
  26. 28 0
      pavis-common/src/main/java/com/pavis/admin/common/config/properties/RsaProperties.java
  27. 29 0
      pavis-common/src/main/java/com/pavis/admin/common/config/websocket/WebSocketClientServiceImpl.java
  28. 61 0
      pavis-common/src/main/java/com/pavis/admin/common/constant/CacheConstants.java
  29. 45 0
      pavis-common/src/main/java/com/pavis/admin/common/constant/ContainerConstants.java
  30. 49 0
      pavis-common/src/main/java/com/pavis/admin/common/constant/RegexConstants.java
  31. 74 0
      pavis-common/src/main/java/com/pavis/admin/common/constant/SysConstants.java
  32. 39 0
      pavis-common/src/main/java/com/pavis/admin/common/constant/UiConstants.java
  33. 44 0
      pavis-common/src/main/java/com/pavis/admin/common/context/RoleContext.java
  34. 117 0
      pavis-common/src/main/java/com/pavis/admin/common/context/UserContext.java
  35. 168 0
      pavis-common/src/main/java/com/pavis/admin/common/context/UserContextHolder.java
  36. 62 0
      pavis-common/src/main/java/com/pavis/admin/common/context/UserExtraContext.java
  37. 52 0
      pavis-common/src/main/java/com/pavis/admin/common/controller/BaseController.java
  38. 45 0
      pavis-common/src/main/java/com/pavis/admin/common/enums/DataScopeEnum.java
  39. 32 0
      pavis-common/src/main/java/com/pavis/admin/common/enums/DisEnableStatusEnum.java
  40. 35 0
      pavis-common/src/main/java/com/pavis/admin/common/enums/GenderEnum.java
  41. 32 0
      pavis-common/src/main/java/com/pavis/admin/common/enums/SuccessFailureStatusEnum.java
  42. 39 0
      pavis-common/src/main/java/com/pavis/admin/common/model/entity/BaseCreateDO.java
  43. 51 0
      pavis-common/src/main/java/com/pavis/admin/common/model/entity/BaseDO.java
  44. 39 0
      pavis-common/src/main/java/com/pavis/admin/common/model/entity/BaseUpdateDO.java
  45. 27 0
      pavis-common/src/main/java/com/pavis/admin/common/model/req/CommonStatusUpdateReq.java
  46. 49 0
      pavis-common/src/main/java/com/pavis/admin/common/model/resp/BaseDetailResp.java
  47. 63 0
      pavis-common/src/main/java/com/pavis/admin/common/model/resp/BaseResp.java
  48. 23 0
      pavis-common/src/main/java/com/pavis/admin/common/service/CommonDictItemService.java
  49. 28 0
      pavis-common/src/main/java/com/pavis/admin/common/service/CommonUserService.java
  50. 92 0
      pavis-common/src/main/java/com/pavis/admin/common/util/SecureUtils.java
  51. 50 0
      pavis-extension/pavis-extension-schedule-server/pom.xml
  52. 44 0
      pavis-extension/pavis-extension-schedule-server/src/main/java/com/pavis/admin/extension/scheduling/ScheduleServerApplication.java
  53. 58 0
      pavis-extension/pavis-extension-schedule-server/src/main/resources/config/application-dev.yml
  54. 58 0
      pavis-extension/pavis-extension-schedule-server/src/main/resources/config/application-prod.yml
  55. 12 0
      pavis-extension/pavis-extension-schedule-server/src/main/resources/config/application.yml
  56. 5 0
      pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/db.changelog-master.yaml
  57. 14 0
      pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/mysql/snail-job_data.sql
  58. 521 0
      pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/mysql/snail-job_table.sql
  59. 14 0
      pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/postgresql/snail-job_data.sql
  60. 831 0
      pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/postgresql/snail-job_table.sql
  61. 88 0
      pavis-extension/pavis-extension-schedule-server/src/main/resources/logback-spring.xml
  62. 17 0
      pavis-extension/pom.xml
  63. 130 0
      pavis-module-aigc/pom.xml
  64. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/PavisAiAutoConfiguration.java
  65. 49 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/model/req/ChatReq.java
  66. 56 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/model/req/ImageReq.java
  67. 27 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/model/resp/ChatResp.java
  68. 29 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/model/resp/EmbeddingResp.java
  69. 30 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/utils/PromptUtil.java
  70. 74 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/utils/StreamEmitter.java
  71. 17 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/constant/EmbedConst.java
  72. 7 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/constant/ModelConst.java
  73. 57 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/constant/PromptConst.java
  74. 14 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/constant/PropConst.java
  75. 30 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/ChatErrorEnum.java
  76. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/EmbedStoreEnum.java
  77. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/ModelTypeEnum.java
  78. 23 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/ProviderEnum.java
  79. 17 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/RoleEnum.java
  80. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/event/EmbeddingRefreshEvent.java
  81. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/event/ProviderRefreshEvent.java
  82. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentExecutionMapper.java
  83. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentKnowledgeMapper.java
  84. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentMapper.java
  85. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentStepMapper.java
  86. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentToolMapper.java
  87. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AigcAppMapper.java
  88. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AigcMessageFeedbackMapper.java
  89. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AigcMessageMapper.java
  90. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AppApiMapper.java
  91. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AppKnowledgeMapper.java
  92. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/ConversationMapper.java
  93. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/DocChunkMapper.java
  94. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/DocMapper.java
  95. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/EmbedStoreMapper.java
  96. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/KnowledgeMapper.java
  97. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/ModelMapper.java
  98. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/ModelSecretMapper.java
  99. 12 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/ToolMapper.java
  100. 94 0
      pavis-module-aigc/src/main/java/com/pavis/admin/aigc/model/entity/AgentDO.java

+ 38 - 0
.gitignore

@@ -0,0 +1,38 @@
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### IntelliJ IDEA ###
+.idea/modules.xml
+.idea/jarRepositories.xml
+.idea/compiler.xml
+.idea/libraries/
+*.iws
+*.iml
+*.ipr
+
+### Eclipse ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
+
+### Mac OS ###
+.DS_Store

+ 10 - 0
.idea/.gitignore

@@ -0,0 +1,10 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# 依赖于环境的 Maven 主目录路径
+/mavenHomeManager.xml
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 5 - 0
.idea/codeStyles/codeStyleConfig.xml

@@ -0,0 +1,5 @@
+<component name="ProjectCodeStyleConfiguration">
+  <state>
+    <option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
+  </state>
+</component>

+ 17 - 0
.idea/dataSources.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="DataSourceManagerImpl" format="xml" multifile-model="true">
+    <data-source source="LOCAL" name="pavis_admin@localhost" uuid="6091b8ab-4ca9-4d4e-a8a4-f6291b091dc8">
+      <driver-ref>mysql.8</driver-ref>
+      <synchronize>true</synchronize>
+      <jdbc-driver>com.mysql.cj.jdbc.Driver</jdbc-driver>
+      <jdbc-url>jdbc:mysql://localhost:3306/pavis_admin</jdbc-url>
+      <jdbc-additional-properties>
+        <property name="com.intellij.clouds.kubernetes.db.host.port" />
+        <property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
+        <property name="com.intellij.clouds.kubernetes.db.container.port" />
+      </jdbc-additional-properties>
+      <working-dir>$ProjectFileDir$</working-dir>
+    </data-source>
+  </component>
+</project>

+ 33 - 0
.idea/encodings.xml

@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Encoding">
+    <file url="file://$PROJECT_DIR$/pavis-common/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-common/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-extension/pavis-extension-schedule-server/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-extension/pavis-extension-schedule-server/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-extension/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-extension/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-agent/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-agent/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-ai/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-ai/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-aigc/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-aigc/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-rag/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-rag/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-system/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-module-system/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-plugin/pavis-plugin-generator/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-plugin/pavis-plugin-generator/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-plugin/pavis-plugin-open/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-plugin/pavis-plugin-open/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-plugin/pavis-plugin-schedule/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-plugin/pavis-plugin-schedule/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-plugin/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-plugin/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
+  </component>
+</project>

+ 10 - 0
.idea/inspectionProfiles/Project_Default.xml

@@ -0,0 +1,10 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
+      <option name="processCode" value="true" />
+      <option name="processLiterals" value="true" />
+      <option name="processComments" value="true" />
+    </inspection_tool>
+  </profile>
+</component>

+ 21 - 0
.idea/misc.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ExternalStorageConfigurationManager" enabled="true" />
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/pom.xml" />
+      </list>
+    </option>
+    <option name="ignoredFiles">
+      <set>
+        <option value="$PROJECT_DIR$/pavis-module-agent/pom.xml" />
+        <option value="$PROJECT_DIR$/pavis-module-ai/pom.xml" />
+        <option value="$PROJECT_DIR$/pavis-module-rag/pom.xml" />
+      </set>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="homebrew-17" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>

+ 21 - 0
.idea/sqldialects.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="SqlDialectMappings">
+    <file url="file://$PROJECT_DIR$/pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/mysql/snail-job_data.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/mysql/snail-job_table.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/postgresql/snail-job_data.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/postgresql/snail-job_table.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/mysql/main_column.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/mysql/main_data.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/mysql/main_table.sql" dialect="MySQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/mysql/plugin/plugin_generator.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/mysql/plugin/plugin_open.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/mysql/plugin/plugin_schedule.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/postgresql/main_column.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/postgresql/main_data.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/postgresql/main_table.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/postgresql/plugin/plugin_generator.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/postgresql/plugin/plugin_open.sql" dialect="GenericSQL" />
+    <file url="file://$PROJECT_DIR$/pavis-webapi/src/main/resources/db/changelog/postgresql/plugin/plugin_schedule.sql" dialect="GenericSQL" />
+  </component>
+</project>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="$PROJECT_DIR$" vcs="Git" />
+  </component>
+</project>

BIN
.style/Java开发手册(黄山版).pdf


+ 380 - 0
.style/p3c-codestyle.xml

@@ -0,0 +1,380 @@
+<?xml version="1.0" encoding="utf-8"?>
+<profiles version="21">
+    <profile kind="CodeFormatterProfile" name="P3C-CodeStyle" version="21">
+        <setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="space"/>
+        <setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
+        <setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
+        <setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="end_of_line"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_preserve"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_preserve"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_preserve"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_preserve"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_preserve"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_preserve"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
+        <setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_preserve"/>
+        <setting id="org.eclipse.jdt.core.formatter.lineSplit" value="120"/>
+        <setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="1"/>
+        <setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="82"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="82"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="18"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="80"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="48"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="49"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="2"/>
+        <setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="0"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="120"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
+        <setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="true"/>
+        <setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
+        <setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
+    </profile>
+</profiles>

+ 149 - 0
pavis-common/pom.xml

@@ -0,0 +1,149 @@
+<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 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.pavis</groupId>
+        <artifactId>pavis-admin</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>pavis-common</artifactId>
+    <description>公共模块(存放公共工具类,公共配置等)</description>
+
+    <dependencies>
+        <!-- CosId(通用、灵活、高性能的分布式 ID 生成器) -->
+        <dependency>
+            <groupId>me.ahoo.cosid</groupId>
+            <artifactId>cosid-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>me.ahoo.cosid</groupId>
+            <artifactId>cosid-spring-redis</artifactId>
+        </dependency>
+
+        <!-- X File Storage(一行代码将文件存储到本地、FTP、SFTP、WebDAV、阿里云 OSS、华为云 OBS...等其它兼容 S3 协议的存储平台) -->
+        <dependency>
+            <groupId>org.dromara.x-file-storage</groupId>
+            <artifactId>x-file-storage-spring</artifactId>
+        </dependency>
+        <!-- Amazon S3(Amazon Simple Storage Service,亚马逊简单存储服务,通用存储协议 S3,兼容主流云厂商对象存储) -->
+        <dependency>
+            <groupId>com.amazonaws</groupId>
+            <artifactId>aws-java-sdk-s3</artifactId>
+        </dependency>
+
+        <!-- FreeMarker(模板引擎) -->
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+        </dependency>
+
+        <!-- MySQL Java 驱动 -->
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+        </dependency>
+
+        <!-- PostgreSQL Java 驱动 -->
+        <!--<dependency>
+            <groupId>org.postgresql</groupId>
+            <artifactId>postgresql</artifactId>
+        </dependency>-->
+
+        <!-- ContiNew Starter 扩展模块 - CURD(增删改查) -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-extension-crud-mp</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 认证模块 - SaToken -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-auth-satoken</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-web</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- ContiNew Starter 认证模块 - JustAuth -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-auth-justauth</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 缓存模块 - JetCache -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-cache-jetcache</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 数据权限模块 - MyBatis Plus -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-extension-datapermission-mp</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 消息模块 - WebSocket -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-messaging-websocket</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.springframework.boot</groupId>
+                    <artifactId>spring-boot-starter-web</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- ContiNew Starter 消息模块 - 邮件 -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-messaging-mail</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 验证码模块 - 图形验证码 -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-captcha-graphic</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 验证码模块 - 行为验证码 -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-captcha-behavior</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 限流模块 -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-ratelimiter</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 安全模块 - 加密 -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-security-crypto</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 安全模块 - 脱敏 -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-security-mask</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter 安全模块 - 密码编码器 -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-security-password</artifactId>
+        </dependency>
+
+        <!-- ContiNew Starter JSON 模块 - Jackson -->
+        <dependency>
+            <groupId>top.continew</groupId>
+            <artifactId>continew-starter-json-jackson</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 201 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/doc/GlobalAuthenticationCustomizer.java

@@ -0,0 +1,201 @@
+
+package com.pavis.admin.common.config.doc;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.hutool.core.map.MapUtil;
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.PathItem;
+import io.swagger.v3.oas.models.security.SecurityRequirement;
+import io.swagger.v3.oas.models.security.SecurityScheme;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
+import org.springframework.aop.support.AopUtils;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+import org.springframework.util.AntPathMatcher;
+import org.springframework.web.bind.annotation.*;
+import top.continew.starter.apidoc.autoconfigure.SpringDocExtensionProperties;
+import top.continew.starter.auth.satoken.autoconfigure.SaTokenExtensionProperties;
+import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
+
+import java.lang.reflect.Method;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 全局鉴权参数定制器
+ *
+ * 
+ * @since 2024/12/31 13:36
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class GlobalAuthenticationCustomizer implements GlobalOpenApiCustomizer {
+
+    private final SpringDocExtensionProperties properties;
+    private final SaTokenExtensionProperties saTokenExtensionProperties;
+    private final ApplicationContext context;
+    private final AntPathMatcher pathMatcher = new AntPathMatcher();
+
+    /**
+     * 定制 OpenAPI 文档
+     *
+     * @param openApi 当前 OpenAPI 对象
+     */
+    @Override
+    public void customise(OpenAPI openApi) {
+        if (MapUtil.isEmpty(openApi.getPaths())) {
+            return;
+        }
+
+        // 收集需要排除的路径(包括 Sa-Token 配置中的排除路径和 @SaIgnore 注解路径)
+        Set<String> excludedPaths = collectExcludedPaths();
+
+        // 遍历所有路径,为需要鉴权的路径添加安全认证配置
+        openApi.getPaths().forEach((path, pathItem) -> {
+            if (isPathExcluded(path, excludedPaths)) {
+                // 路径在排除列表中,跳过处理
+                return;
+            }
+            // 为路径添加安全认证参数
+            addAuthenticationParameters(pathItem);
+        });
+    }
+
+    /**
+     * 收集所有需要排除的路径
+     *
+     * @return 排除路径集合
+     */
+    private Set<String> collectExcludedPaths() {
+        Set<String> excludedPaths = new HashSet<>();
+        excludedPaths.addAll(Arrays.asList(saTokenExtensionProperties.getSecurity().getExcludes()));
+        excludedPaths.addAll(resolveSaIgnorePaths());
+        return excludedPaths;
+    }
+
+    /**
+     * 为路径项添加认证参数
+     *
+     * @param pathItem 当前路径项
+     */
+    private void addAuthenticationParameters(PathItem pathItem) {
+        Components components = properties.getComponents();
+        if (components == null || MapUtil.isEmpty(components.getSecuritySchemes())) {
+            return;
+        }
+        Map<String, SecurityScheme> securitySchemes = components.getSecuritySchemes();
+        List<String> schemeNames = securitySchemes.values().stream().map(SecurityScheme::getName).toList();
+        pathItem.readOperations().forEach(operation -> {
+            SecurityRequirement securityRequirement = new SecurityRequirement();
+            schemeNames.forEach(securityRequirement::addList);
+            operation.addSecurityItem(securityRequirement);
+        });
+    }
+
+    /**
+     * 解析所有带有 @SaIgnore 注解的路径
+     *
+     * @return 被忽略的路径集合
+     */
+    private Set<String> resolveSaIgnorePaths() {
+        // 获取所有标注 @RestController 的 Bean
+        Map<String, Object> controllers = context.getBeansWithAnnotation(RestController.class);
+        Set<String> ignoredPaths = new HashSet<>();
+
+        // 遍历所有控制器,解析 @SaIgnore 注解路径
+        controllers.values().forEach(controllerBean -> {
+            Class<?> controllerClass = AopUtils.getTargetClass(controllerBean);
+            List<String> classPaths = getClassPaths(controllerClass);
+
+            // 类级别的 @SaIgnore 注解
+            if (controllerClass.isAnnotationPresent(SaIgnore.class)) {
+                classPaths.forEach(classPath -> ignoredPaths.add(classPath + "/**"));
+            }
+
+            // 方法级别的 @SaIgnore 注解
+            Arrays.stream(controllerClass.getDeclaredMethods())
+                .filter(method -> method.isAnnotationPresent(SaIgnore.class))
+                .forEach(method -> ignoredPaths.addAll(combinePaths(classPaths, getMethodPaths(method))));
+        });
+
+        return ignoredPaths;
+    }
+
+    /**
+     * 获取类上的所有路径
+     *
+     * @param controller 控制器类
+     * @return 类路径列表
+     */
+    private List<String> getClassPaths(Class<?> controller) {
+        List<String> classPaths = new ArrayList<>();
+        // 处理 @RequestMapping 注解
+        if (controller.isAnnotationPresent(RequestMapping.class)) {
+            RequestMapping mapping = controller.getAnnotation(RequestMapping.class);
+            classPaths.addAll(Arrays.asList(mapping.value()));
+        }
+        // 处理 @CrudRequestMapping 注解
+        if (controller.isAnnotationPresent(CrudRequestMapping.class)) {
+            CrudRequestMapping mapping = controller.getAnnotation(CrudRequestMapping.class);
+            if (!mapping.value().isEmpty()) {
+                classPaths.add(mapping.value());
+            }
+        }
+        return classPaths;
+    }
+
+    /**
+     * 获取方法上的所有路径
+     *
+     * @param method 控制器方法
+     * @return 方法路径列表
+     */
+    private List<String> getMethodPaths(Method method) {
+        List<String> methodPaths = new ArrayList<>();
+
+        // 检查方法上的各种映射注解
+        if (method.isAnnotationPresent(GetMapping.class)) {
+            methodPaths.addAll(Arrays.asList(method.getAnnotation(GetMapping.class).value()));
+        } else if (method.isAnnotationPresent(PostMapping.class)) {
+            methodPaths.addAll(Arrays.asList(method.getAnnotation(PostMapping.class).value()));
+        } else if (method.isAnnotationPresent(PutMapping.class)) {
+            methodPaths.addAll(Arrays.asList(method.getAnnotation(PutMapping.class).value()));
+        } else if (method.isAnnotationPresent(DeleteMapping.class)) {
+            methodPaths.addAll(Arrays.asList(method.getAnnotation(DeleteMapping.class).value()));
+        } else if (method.isAnnotationPresent(RequestMapping.class)) {
+            methodPaths.addAll(Arrays.asList(method.getAnnotation(RequestMapping.class).value()));
+        } else if (method.isAnnotationPresent(PatchMapping.class)) {
+            methodPaths.addAll(Arrays.asList(method.getAnnotation(PatchMapping.class).value()));
+        }
+
+        return methodPaths;
+    }
+
+    /**
+     * 组合类路径和方法路径
+     *
+     * @param classPaths  类路径列表
+     * @param methodPaths 方法路径列表
+     * @return 完整路径集合
+     */
+    private Set<String> combinePaths(List<String> classPaths, List<String> methodPaths) {
+        return classPaths.stream()
+            .flatMap(classPath -> methodPaths.stream().map(methodPath -> classPath + methodPath))
+            .collect(Collectors.toSet());
+    }
+
+    /**
+     * 检查路径是否在排除列表中
+     *
+     * @param path          当前路径
+     * @param excludedPaths 排除路径集合,支持通配符
+     * @return 是否匹配排除规则
+     */
+    private boolean isPathExcluded(String path, Set<String> excludedPaths) {
+        return excludedPaths.stream().anyMatch(pattern -> pathMatcher.match(pattern, path));
+    }
+}

+ 49 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/doc/GlobalDescriptionCustomizer.java

@@ -0,0 +1,49 @@
+
+package com.pavis.admin.common.config.doc;
+
+import cn.hutool.core.util.StrUtil;
+import io.swagger.v3.oas.models.Operation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springdoc.core.customizers.GlobalOperationCustomizer;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 全局描述定制器 - 处理 sa-token 的注解权限码
+ *
+ * 
+ * @since 2025/1/24 14:59
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class GlobalDescriptionCustomizer implements GlobalOperationCustomizer {
+
+    @Override
+    public Operation customize(Operation operation, HandlerMethod handlerMethod) {
+        // 将 sa-token 注解数据添加到 operation 的描述中
+        // 权限
+        List<String> noteList = new ArrayList<>(new OperationDescriptionCustomizer().getPermission(handlerMethod));
+
+        // 如果注解数据列表为空,直接返回原 operation
+        if (noteList.isEmpty()) {
+            return operation;
+        }
+        // 拼接注解数据为字符串
+        String noteStr = StrUtil.join("<br/>", noteList);
+        // 获取原描述
+        String originalDescription = operation.getDescription();
+        // 根据原描述是否为空,更新描述
+        String newDescription = StrUtil.isNotEmpty(originalDescription)
+            ? originalDescription + "<br/>" + noteStr
+            : noteStr;
+
+        // 设置新描述
+        operation.setDescription(newDescription);
+        return operation;
+    }
+}

+ 165 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/doc/OperationDescriptionCustomizer.java

@@ -0,0 +1,165 @@
+
+package com.pavis.admin.common.config.doc;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import cn.dev33.satoken.annotation.SaMode;
+import cn.hutool.core.text.CharSequenceUtil;
+import org.springframework.web.method.HandlerMethod;
+import top.continew.starter.core.constant.StringConstants;
+import top.continew.starter.extension.crud.annotation.CrudApi;
+import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
+import top.continew.starter.extension.crud.enums.Api;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Operation 描述定制器 处理 sa-token 鉴权标识符
+ *
+ * 
+ * @since 2024/6/14 11:18
+ */
+public class OperationDescriptionCustomizer {
+
+    /**
+     * 获取 sa-token 注解信息
+     *
+     * @param handlerMethod 处理程序方法
+     * @return 包含权限和角色校验信息的列表
+     */
+    public List<String> getPermission(HandlerMethod handlerMethod) {
+        List<String> values = new ArrayList<>();
+
+        // 获取权限校验信息
+        String permissionInfo = getAnnotationInfo(handlerMethod, SaCheckPermission.class, "权限校验:");
+        if (!permissionInfo.isEmpty()) {
+            values.add(permissionInfo);
+        }
+
+        // 获取角色校验信息
+        String roleInfo = getAnnotationInfo(handlerMethod, SaCheckRole.class, "角色校验:");
+        if (!roleInfo.isEmpty()) {
+            values.add(roleInfo);
+        }
+
+        // 处理 CrudRequestMapping 和 CrudApi 注解生成的权限信息
+        String crudPermissionInfo = getCrudPermissionInfo(handlerMethod);
+        if (!crudPermissionInfo.isEmpty()) {
+            values.add(crudPermissionInfo);
+        }
+        return values;
+    }
+
+    /**
+     * 获取类和方法上指定注解的信息
+     *
+     * @param handlerMethod   处理程序方法
+     * @param annotationClass 注解类
+     * @param title           信息标题
+     * @param <A>             注解类型
+     * @return 拼接好的注解信息字符串
+     */
+    @SuppressWarnings("unchecked")
+    private <A extends Annotation> String getAnnotationInfo(HandlerMethod handlerMethod,
+                                                            Class<A> annotationClass,
+                                                            String title) {
+        StringBuilder infoBuilder = new StringBuilder();
+
+        // 获取类上的注解
+        A classAnnotation = handlerMethod.getBeanType().getAnnotation(annotationClass);
+        if (classAnnotation != null) {
+            appendAnnotationInfo(infoBuilder, "类:", classAnnotation);
+        }
+
+        // 获取方法上的注解
+        A methodAnnotation = handlerMethod.getMethodAnnotation(annotationClass);
+        if (methodAnnotation != null) {
+            appendAnnotationInfo(infoBuilder, "方法:", methodAnnotation);
+        }
+
+        // 如果有注解信息,添加标题
+        if (!infoBuilder.isEmpty()) {
+            infoBuilder.insert(0, "<font style=\"color:red\" class=\"light-red\">" + title + "</font></br>");
+        }
+
+        return infoBuilder.toString();
+    }
+
+    /**
+     * 拼接注解信息到 StringBuilder 中
+     *
+     * @param builder    用于拼接信息的 StringBuilder
+     * @param prefix     前缀信息,如 "类:" 或 "方法:"
+     * @param annotation 注解对象
+     */
+    private void appendAnnotationInfo(StringBuilder builder, String prefix, Annotation annotation) {
+        String[] values = null;
+        SaMode mode = null;
+        String type = "";
+        String[] orRole = new String[0];
+
+        if (annotation instanceof SaCheckPermission checkPermission) {
+            values = checkPermission.value();
+            mode = checkPermission.mode();
+            type = checkPermission.type();
+            orRole = checkPermission.orRole();
+        } else if (annotation instanceof SaCheckRole checkRole) {
+            values = checkRole.value();
+            mode = checkRole.mode();
+            type = checkRole.type();
+        }
+
+        if (values != null && mode != null) {
+            builder.append("<font style=\"color:red\" class=\"light-red\">");
+            builder.append(prefix);
+            if (!type.isEmpty()) {
+                builder.append("(类型:").append(type).append(")");
+            }
+            builder.append(getAnnotationNote(values, mode));
+            if (orRole.length > 0) {
+                builder.append(" 或 角色校验(").append(getAnnotationNote(orRole, mode)).append(")");
+            }
+            builder.append("</font></br>");
+        }
+    }
+
+    /**
+     * 根据注解的模式拼接注解值
+     *
+     * @param values 注解的值数组
+     * @param mode   注解的模式(AND 或 OR)
+     * @return 拼接好的注解值字符串
+     */
+    private String getAnnotationNote(String[] values, SaMode mode) {
+        if (mode.equals(SaMode.AND)) {
+            return String.join(" 且 ", values);
+        } else {
+            return String.join(" 或 ", values);
+        }
+    }
+
+    /**
+     * 处理 CrudRequestMapping 和 CrudApi 注解生成的权限信息
+     *
+     * @param handlerMethod 处理程序方法
+     * @return 拼接好的权限信息字符串
+     */
+    private String getCrudPermissionInfo(HandlerMethod handlerMethod) {
+        CrudRequestMapping crudRequestMapping = handlerMethod.getBeanType().getAnnotation(CrudRequestMapping.class);
+        CrudApi crudApi = handlerMethod.getMethodAnnotation(CrudApi.class);
+
+        if (crudRequestMapping == null || crudApi == null) {
+            return "";
+        }
+
+        String path = crudRequestMapping.value();
+        String prefix = String.join(StringConstants.COLON, CharSequenceUtil.splitTrim(path, StringConstants.SLASH));
+        Api api = crudApi.value();
+        String apiName = Api.PAGE.equals(api) || Api.TREE.equals(api) ? Api.LIST.name() : api.name();
+        String permission = "%s:%s".formatted(prefix, apiName.toLowerCase());
+
+        return "<font style=\"color:red\" class=\"light-red\">Crud 权限校验:</font></br><font style=\"color:red\" class=\"light-red\">方法:</font><font style=\"color:red\" class=\"light-red\">" + permission + "</font>";
+    }
+}

+ 24 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/excel/DictExcelProperty.java

@@ -0,0 +1,24 @@
+
+package com.pavis.admin.common.config.excel;
+
+import java.lang.annotation.*;
+
+/**
+ * 字典字段注解
+ *
+ *
+ * @since 2025/4/9 20:25
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DictExcelProperty {
+
+    /**
+     * 字典编码
+     *
+     * @return 字典编码
+     */
+    String value();
+}

+ 77 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/excel/ExcelDictConverter.java

@@ -0,0 +1,77 @@
+
+package com.pavis.admin.common.config.excel;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.extra.spring.SpringUtil;
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import com.pavis.admin.common.service.CommonDictItemService;
+import top.continew.starter.core.constant.StringConstants;
+import top.continew.starter.extension.crud.model.resp.LabelValueResp;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Easy Excel 字典转换器
+ *
+ * 
+ * @since 2025/4/9 20:22
+ */
+public class ExcelDictConverter implements Converter<Object> {
+
+    @Override
+    public Object convertToJavaData(ReadCellData<?> cellData,
+                                    ExcelContentProperty contentProperty,
+                                    GlobalConfiguration globalConfiguration) {
+        // 获取字典项数据
+        List<LabelValueResp> dictItemList = this.getDictCode(contentProperty);
+        // 转换字典标签为字典值
+        String value = dictItemList.stream()
+            .filter(item -> Objects.equals(cellData.getStringValue(), item.getValue()))
+            .findFirst()
+            .map(LabelValueResp::getLabel)
+            .orElse(null);
+        // 转换字典值为对应类型
+        return Convert.convert(contentProperty.getField().getType(), value);
+    }
+
+    @Override
+    public WriteCellData<String> convertToExcelData(Object data,
+                                                    ExcelContentProperty contentProperty,
+                                                    GlobalConfiguration globalConfiguration) {
+        if (null == data) {
+            return new WriteCellData<>(StringConstants.EMPTY);
+        }
+        // 获取字典项数据
+        List<LabelValueResp> dictItemList = this.getDictCode(contentProperty);
+        if (CollUtil.isEmpty(dictItemList)) {
+            return new WriteCellData<>(StringConstants.EMPTY);
+        }
+        // 转换字典值为字典标签
+        return new WriteCellData<>(dictItemList.stream()
+            .filter(item -> Objects.equals(data, item.getValue()))
+            .findFirst()
+            .map(LabelValueResp::getLabel)
+            .orElse(StringConstants.EMPTY));
+    }
+
+    /**
+     * 获取字典项数据
+     *
+     * @param contentProperty Excel 内容属性
+     * @return 字典项数据
+     */
+    private List<LabelValueResp> getDictCode(ExcelContentProperty contentProperty) {
+        DictExcelProperty dictExcelProperty = contentProperty.getField().getAnnotation(DictExcelProperty.class);
+        if (null == dictExcelProperty) {
+            throw new IllegalArgumentException("Excel 字典转换器异常:请为字段添加 @DictExcelProperty 注解");
+        }
+        CommonDictItemService dictItemService = SpringUtil.getBean(CommonDictItemService.class);
+        return dictItemService.listByDictCode(dictExcelProperty.value());
+    }
+}

+ 176 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/exception/GlobalExceptionHandler.java

@@ -0,0 +1,176 @@
+
+package com.pavis.admin.common.config.exception;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import com.fasterxml.jackson.databind.exc.InvalidFormatException;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+import org.springframework.web.multipart.MultipartException;
+import org.springframework.web.servlet.NoHandlerFoundException;
+import top.continew.starter.core.exception.BadRequestException;
+import top.continew.starter.core.exception.BaseException;
+import top.continew.starter.core.exception.BusinessException;
+import top.continew.starter.core.util.ExceptionUtils;
+import top.continew.starter.web.model.R;
+
+import java.util.Objects;
+
+/**
+ * 全局异常处理器
+ *
+ * 
+ * 
+ * @since 2024/8/7 20:21
+ */
+@Slf4j
+@Order(99)
+@RestControllerAdvice
+public class GlobalExceptionHandler {
+
+    /**
+     * 自定义基类异常
+     */
+    @ExceptionHandler(BaseException.class)
+    public R handleBaseException(BaseException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        return R.fail(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), e.getMessage());
+    }
+
+    /**
+     * 业务异常
+     */
+    @ExceptionHandler(BusinessException.class)
+    public R handleBusinessException(BusinessException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        return R.fail(String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()), e.getMessage());
+    }
+
+    /**
+     * 自定义验证异常-错误请求
+     * <p>
+     * {@code ValidationUtils.throwIfXxx(xxx)}
+     * </p>
+     */
+    @ExceptionHandler(BadRequestException.class)
+    public R handleBadRequestException(BadRequestException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        return R.fail(String.valueOf(HttpStatus.BAD_REQUEST.value()), e.getMessage());
+    }
+
+    /**
+     * 方法参数缺失异常
+     * <p>
+     * {@code @RequestParam} 参数缺失
+     * </p>
+     */
+    @ExceptionHandler(MissingServletRequestParameterException.class)
+    public R handleMethodArgumentTypeMismatchException(MissingServletRequestParameterException e,
+                                                       HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        return R.fail(String.valueOf(HttpStatus.BAD_REQUEST.value()), "参数 '%s' 缺失".formatted(e.getParameterName()));
+    }
+
+    /**
+     * 方法参数无效异常
+     * <p>
+     * {@code @NotBlank}、{@code @NotNull} 等参数验证不通过
+     * </p>
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        String errorMsg = ExceptionUtils.exToNull(() -> Objects.requireNonNull(e.getBindingResult().getFieldError())
+            .getDefaultMessage());
+        return R.fail(String.valueOf(HttpStatus.BAD_REQUEST.value()), errorMsg);
+    }
+
+    /**
+     * 方法参数类型不匹配异常
+     * <p>
+     * {@code @RequestParam} 参数类型不匹配
+     * </p>
+     */
+    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+    public R handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,
+                                                       HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        return R.fail(String.valueOf(HttpStatus.BAD_REQUEST.value()), "参数 '%s' 类型不匹配".formatted(e.getName()));
+    }
+
+    /**
+     * HTTP 消息不可读异常
+     * <p>
+     * 1.@RequestBody 缺失请求体<br />
+     * 2.@RequestBody 实体内参数类型不匹配<br />
+     * 3.请求体解析格式异常<br />
+     * ...
+     * </p>
+     */
+    @ExceptionHandler(HttpMessageNotReadableException.class)
+    public R handleHttpMessageNotReadableException(HttpMessageNotReadableException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        // @RequestBody 实体内参数类型不匹配
+        if (e.getCause() instanceof InvalidFormatException invalidFormatException) {
+            return R.fail(String.valueOf(HttpStatus.BAD_REQUEST.value()), "参数 '%s' 类型不匹配"
+                .formatted(invalidFormatException.getValue()));
+        }
+        return R.fail(String.valueOf(HttpStatus.BAD_REQUEST.value()), "参数缺失或格式不正确");
+    }
+
+    /**
+     * 文件上传异常-超过上传大小限制
+     */
+    @ExceptionHandler(MultipartException.class)
+    public R handleMultipartException(MultipartException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        String msg = e.getMessage();
+        R defaultFail = R.fail(String.valueOf(HttpStatus.BAD_REQUEST.value()), msg);
+        if (CharSequenceUtil.isBlank(msg)) {
+            return defaultFail;
+        }
+        String sizeLimit;
+        Throwable cause = e.getCause();
+        if (null != cause) {
+            msg = msg.concat(cause.getMessage().toLowerCase());
+        }
+        if (msg.contains("larger than")) {
+            sizeLimit = CharSequenceUtil.subAfter(msg, "larger than ", true);
+        } else if (msg.contains("size") && msg.contains("exceed")) {
+            sizeLimit = CharSequenceUtil.subBetween(msg, "the maximum size ", " for");
+        } else {
+            return defaultFail;
+        }
+        return R.fail(String.valueOf(HttpStatus.BAD_REQUEST.value()), "请上传小于 %s 的文件".formatted(FileUtil
+            .readableFileSize(Long.parseLong(sizeLimit))));
+    }
+
+    /**
+     * 请求 URL 不存在异常
+     */
+    @ExceptionHandler(NoHandlerFoundException.class)
+    public R handleNoHandlerFoundException(NoHandlerFoundException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        return R.fail(String.valueOf(HttpStatus.NOT_FOUND.value()), "请求 URL '%s' 不存在".formatted(request
+            .getRequestURI()));
+    }
+
+    /**
+     * 不支持的 HTTP 请求方法异常
+     */
+    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+    public R handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e,
+                                                          HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        return R.fail(String.valueOf(HttpStatus.METHOD_NOT_ALLOWED.value()), "请求方式 '%s' 不支持".formatted(e.getMethod()));
+    }
+}

+ 57 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/exception/GlobalSaTokenExceptionHandler.java

@@ -0,0 +1,57 @@
+
+package com.pavis.admin.common.config.exception;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.exception.NotPermissionException;
+import cn.dev33.satoken.exception.NotRoleException;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.annotation.Order;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import top.continew.starter.web.model.R;
+
+/**
+ * 全局 SaToken 异常处理器
+ *
+ *
+ * @since 2024/8/7 20:21
+ */
+@Slf4j
+@Order(99)
+@RestControllerAdvice
+public class GlobalSaTokenExceptionHandler {
+
+    /**
+     * 认证异常-登录认证
+     */
+    @ExceptionHandler(NotLoginException.class)
+    public R handleNotLoginException(NotLoginException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        String errorMsg = switch (e.getType()) {
+            case NotLoginException.KICK_OUT -> "您已被踢下线";
+            case NotLoginException.BE_REPLACED_MESSAGE -> "您已被顶下线";
+            default -> "您的登录状态已过期,请重新登录";
+        };
+        return R.fail(String.valueOf(HttpStatus.UNAUTHORIZED.value()), errorMsg);
+    }
+
+    /**
+     * 认证异常-权限认证
+     */
+    @ExceptionHandler(NotPermissionException.class)
+    public R handleNotPermissionException(NotPermissionException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        return R.fail(String.valueOf(HttpStatus.FORBIDDEN.value()), "没有访问权限,请联系管理员授权");
+    }
+
+    /**
+     * 认证异常-角色认证
+     */
+    @ExceptionHandler(NotRoleException.class)
+    public R handleNotRoleException(NotRoleException e, HttpServletRequest request) {
+        log.error("[{}] {}", request.getMethod(), request.getRequestURI(), e);
+        return R.fail(String.valueOf(HttpStatus.FORBIDDEN.value()), "没有访问权限,请联系管理员授权");
+    }
+}

+ 35 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/BCryptEncryptor.java

@@ -0,0 +1,35 @@
+
+package com.pavis.admin.common.config.mybatis;
+
+import org.springframework.security.crypto.password.PasswordEncoder;
+import top.continew.starter.security.crypto.encryptor.IEncryptor;
+import top.continew.starter.security.password.constant.PasswordEncoderConstants;
+
+/**
+ * BCrypt 加/解密处理器(不可逆)
+ *
+ *
+ * @since 2024/2/8 22:29
+ */
+public class BCryptEncryptor implements IEncryptor {
+
+    private final PasswordEncoder passwordEncoder;
+
+    public BCryptEncryptor(PasswordEncoder passwordEncoder) {
+        this.passwordEncoder = passwordEncoder;
+    }
+
+    @Override
+    public String encrypt(String plaintext, String password, String publicKey) {
+        // 如果已经是 BCrypt 加密格式,直接返回
+        if (PasswordEncoderConstants.BCRYPT_PATTERN.matcher(plaintext).matches()) {
+            return plaintext;
+        }
+        return passwordEncoder.encode(plaintext);
+    }
+
+    @Override
+    public String decrypt(String ciphertext, String password, String privateKey) {
+        return ciphertext;
+    }
+}

+ 42 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/DataPermissionMapper.java

@@ -0,0 +1,42 @@
+
+package com.pavis.admin.common.config.mybatis;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.apache.ibatis.annotations.Param;
+import top.continew.starter.data.mp.base.BaseMapper;
+import top.continew.starter.extension.datapermission.annotation.DataPermission;
+
+import java.util.List;
+
+/**
+ * 数据权限 Mapper 基类
+ *
+ * @param <T> 实体类
+ *
+ * @since 2023/9/3 21:50
+ */
+public interface DataPermissionMapper<T> extends BaseMapper<T> {
+
+    /**
+     * 根据 entity 条件,查询全部记录
+     *
+     * @param queryWrapper 实体对象封装操作类(可以为 null)
+     * @return 全部记录
+     */
+    @Override
+    @DataPermission
+    List<T> selectList(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
+
+    /**
+     * 根据 entity 条件,查询全部记录(并翻页)
+     *
+     * @param page         分页查询条件
+     * @param queryWrapper 实体对象封装操作类(可以为 null)
+     * @return 全部记录(并翻页)
+     */
+    @Override
+    @DataPermission
+    List<T> selectList(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
+}

+ 38 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/DefaultDataPermissionUserContextProvider.java

@@ -0,0 +1,38 @@
+
+package com.pavis.admin.common.config.mybatis;
+
+import cn.hutool.core.convert.Convert;
+import com.pavis.admin.common.context.UserContextHolder;
+import top.continew.starter.extension.datapermission.enums.DataScope;
+import top.continew.starter.extension.datapermission.filter.DataPermissionUserContextProvider;
+import top.continew.starter.extension.datapermission.model.RoleContext;
+import top.continew.starter.extension.datapermission.model.UserContext;
+
+import java.util.stream.Collectors;
+
+/**
+ * 数据权限用户上下文提供者
+ *
+ * 
+ * @since 2023/12/21 21:19
+ */
+public class DefaultDataPermissionUserContextProvider implements DataPermissionUserContextProvider {
+
+    @Override
+    public boolean isFilter() {
+        return !UserContextHolder.isAdmin();
+    }
+
+    @Override
+    public UserContext getUserContext() {
+        com.pavis.admin.common.context.UserContext context = UserContextHolder.getContext();
+        UserContext userContext = new UserContext();
+        userContext.setUserId(Convert.toStr(context.getId()));
+        userContext.setDeptId(Convert.toStr(context.getDeptId()));
+        userContext.setRoles(context.getRoles()
+            .stream()
+            .map(r -> new RoleContext(Convert.toStr(r.getId()), DataScope.valueOf(r.getDataScope().name())))
+            .collect(Collectors.toSet()));
+        return userContext;
+    }
+}

+ 97 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/MyBatisPlusMetaObjectHandler.java

@@ -0,0 +1,97 @@
+
+package com.pavis.admin.common.config.mybatis;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+import com.pavis.admin.common.context.UserContextHolder;
+import com.pavis.admin.common.model.entity.BaseDO;
+
+import java.time.LocalDateTime;
+
+/**
+ * MyBatis Plus 元对象处理器配置(插入或修改时自动填充)
+ *
+ *
+ * @since 2022/12/22 19:52
+ */
+public class MyBatisPlusMetaObjectHandler implements MetaObjectHandler {
+
+    /**
+     * 创建人
+     */
+    private static final String CREATE_USER = "createUser";
+    /**
+     * 创建时间
+     */
+    private static final String CREATE_TIME = "createTime";
+    /**
+     * 修改人
+     */
+    private static final String UPDATE_USER = "updateUser";
+    /**
+     * 修改时间
+     */
+    private static final String UPDATE_TIME = "updateTime";
+
+    /**
+     * 插入数据时填充
+     *
+     * @param metaObject 元对象
+     */
+    @Override
+    public void insertFill(MetaObject metaObject) {
+        if (null == metaObject) {
+            return;
+        }
+        Long createUser = UserContextHolder.getUserId();
+        LocalDateTime createTime = LocalDateTime.now();
+        if (metaObject.getOriginalObject() instanceof BaseDO baseDO) {
+            // 继承了 BaseDO 的类,填充创建信息字段
+            baseDO.setCreateUser(ObjectUtil.defaultIfNull(baseDO.getCreateUser(), createUser));
+            baseDO.setCreateTime(ObjectUtil.defaultIfNull(baseDO.getCreateTime(), createTime));
+        } else {
+            // 未继承 BaseDO 的类,如存在创建信息字段则进行填充
+            this.fillFieldValue(metaObject, CREATE_USER, createUser, false);
+            this.fillFieldValue(metaObject, CREATE_TIME, createTime, false);
+        }
+    }
+
+    /**
+     * 修改数据时填充
+     *
+     * @param metaObject 元对象
+     */
+    @Override
+    public void updateFill(MetaObject metaObject) {
+        if (null == metaObject) {
+            return;
+        }
+        Long updateUser = UserContextHolder.getUserId();
+        LocalDateTime updateTime = LocalDateTime.now();
+        if (metaObject.getOriginalObject() instanceof BaseDO baseDO) {
+            // 继承了 BaseDO 的类,填充修改信息
+            baseDO.setUpdateUser(updateUser);
+            baseDO.setUpdateTime(updateTime);
+        } else {
+            // 未继承 BaseDO 的类,根据类中拥有的修改信息字段进行填充,不存在修改信息字段不进行填充
+            this.fillFieldValue(metaObject, UPDATE_USER, updateUser, true);
+            this.fillFieldValue(metaObject, UPDATE_TIME, updateTime, true);
+        }
+    }
+
+    /**
+     * 填充字段值
+     *
+     * @param metaObject     元数据对象
+     * @param fieldName      要填充的字段名
+     * @param fillFieldValue 要填充的字段值
+     * @param isOverride     如果字段值不为空,是否覆盖(true:覆盖;false:不覆盖)
+     */
+    private void fillFieldValue(MetaObject metaObject, String fieldName, Object fillFieldValue, boolean isOverride) {
+        if (metaObject.hasSetter(fieldName)) {
+            Object fieldValue = metaObject.getValue(fieldName);
+            setFieldValByName(fieldName, null != fieldValue && !isOverride ? fieldValue : fillFieldValue, metaObject);
+        }
+    }
+}

+ 42 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/mybatis/MybatisPlusConfiguration.java

@@ -0,0 +1,42 @@
+
+package com.pavis.admin.common.config.mybatis;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import top.continew.starter.extension.datapermission.filter.DataPermissionUserContextProvider;
+
+/**
+ * MyBatis Plus 配置
+ *
+ *
+ * @since 2022/12/22 19:51
+ */
+@Configuration
+public class MybatisPlusConfiguration {
+
+    /**
+     * 元对象处理器配置(插入或修改时自动填充)
+     */
+    @Bean
+    public MetaObjectHandler metaObjectHandler() {
+        return new MyBatisPlusMetaObjectHandler();
+    }
+
+    /**
+     * 数据权限用户上下文提供者
+     */
+    @Bean
+    public DataPermissionUserContextProvider dataPermissionUserContextProvider() {
+        return new DefaultDataPermissionUserContextProvider();
+    }
+
+    /**
+     * BCrypt 加/解密处理器
+     */
+    @Bean
+    public BCryptEncryptor bCryptEncryptor(PasswordEncoder passwordEncoder) {
+        return new BCryptEncryptor(passwordEncoder);
+    }
+}

+ 82 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/properties/CaptchaProperties.java

@@ -0,0 +1,82 @@
+
+package com.pavis.admin.common.config.properties;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 验证码配置属性
+ *
+ * 
+ * @since 2022/12/11 13:35
+ */
+@Data
+@Component
+@ConfigurationProperties(prefix = "captcha")
+public class CaptchaProperties {
+
+    /**
+     * 图形验证码过期时间
+     */
+    @Value("${continew-starter.captcha.graphic.expirationInMinutes}")
+    private long expirationInMinutes;
+
+    /**
+     * 邮箱验证码配置
+     */
+    private CaptchaMail mail;
+
+    /**
+     * 短信验证码配置
+     */
+    private CaptchaSms sms;
+
+    /**
+     * 邮箱验证码配置
+     */
+    @Data
+    public static class CaptchaMail {
+        /**
+         * 内容长度
+         */
+        private int length;
+
+        /**
+         * 过期时间
+         */
+        private long expirationInMinutes;
+
+        /**
+         * 模板路径
+         */
+        private String templatePath;
+    }
+
+    /**
+     * 短信验证码配置
+     */
+    @Data
+    public static class CaptchaSms {
+        /**
+         * 内容长度
+         */
+        private int length;
+
+        /**
+         * 过期时间
+         */
+        private long expirationInMinutes;
+
+        /**
+         * 验证码字段模板键名
+         */
+        private String codeKey = "code";
+
+        /**
+         * 失效时间字段模板键名
+         */
+        private String timeKey = "expirationInMinutes";
+    }
+}

+ 28 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/properties/RsaProperties.java

@@ -0,0 +1,28 @@
+
+package com.pavis.admin.common.config.properties;
+
+import cn.hutool.extra.spring.SpringUtil;
+
+/**
+ * RSA 配置属性
+ *
+ *
+ * 
+ * @since 2022/12/21 20:21
+ */
+public class RsaProperties {
+
+    /**
+     * 私钥
+     */
+    public static final String PRIVATE_KEY;
+    public static final String PUBLIC_KEY;
+
+    static {
+        PRIVATE_KEY = SpringUtil.getProperty("continew-starter.security.crypto.private-key");
+        PUBLIC_KEY = SpringUtil.getProperty("continew-starter.security.crypto.public-key");
+    }
+
+    private RsaProperties() {
+    }
+}

+ 29 - 0
pavis-common/src/main/java/com/pavis/admin/common/config/websocket/WebSocketClientServiceImpl.java

@@ -0,0 +1,29 @@
+
+package com.pavis.admin.common.config.websocket;
+
+import cn.dev33.satoken.stp.StpUtil;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.http.server.ServletServerHttpRequest;
+import org.springframework.stereotype.Component;
+import top.continew.starter.core.exception.BusinessException;
+import top.continew.starter.messaging.websocket.core.WebSocketClientService;
+
+/**
+ * 当前登录用户 Provider
+ *
+ *
+ * @since 2024/6/4 22:13
+ */
+@Component
+public class WebSocketClientServiceImpl implements WebSocketClientService {
+
+    @Override
+    public String getClientId(ServletServerHttpRequest request) {
+        HttpServletRequest servletRequest = request.getServletRequest();
+        String token = servletRequest.getParameter("token");
+        if (null == StpUtil.getLoginIdByToken(token)) {
+            throw new BusinessException("登录已过期,请重新登录");
+        }
+        return token;
+    }
+}

+ 61 - 0
pavis-common/src/main/java/com/pavis/admin/common/constant/CacheConstants.java

@@ -0,0 +1,61 @@
+
+package com.pavis.admin.common.constant;
+
+import top.continew.starter.core.constant.StringConstants;
+
+/**
+ * 缓存相关常量
+ *
+ * 
+ * @since 2022/12/22 19:30
+ */
+public class CacheConstants {
+
+    /**
+     * 分隔符
+     */
+    public static final String DELIMITER = StringConstants.COLON;
+
+    /**
+     * 验证码键前缀
+     */
+    public static final String CAPTCHA_KEY_PREFIX = "CAPTCHA" + DELIMITER;
+
+    /**
+     * 用户缓存键前缀
+     */
+    public static final String USER_KEY_PREFIX = "USER" + DELIMITER;
+
+    /**
+     * 角色菜单缓存键前缀
+     */
+    public static final String ROLE_MENU_KEY_PREFIX = "ROLE_MENU" + DELIMITER;
+
+    /**
+     * 字典缓存键前缀
+     */
+    public static final String DICT_KEY_PREFIX = "DICT" + DELIMITER;
+
+    /**
+     * 参数缓存键前缀
+     */
+    public static final String OPTION_KEY_PREFIX = "OPTION" + DELIMITER;
+
+    /**
+     * 仪表盘缓存键前缀
+     */
+    public static final String DASHBOARD_KEY_PREFIX = "DASHBOARD" + DELIMITER;
+
+    /**
+     * 用户密码错误次数缓存键前缀
+     */
+    public static final String USER_PASSWORD_ERROR_KEY_PREFIX = USER_KEY_PREFIX + "PASSWORD_ERROR" + DELIMITER;
+
+    /**
+     * 数据导入临时会话key
+     */
+    public static final String DATA_IMPORT_KEY = "SYSTEM" + DELIMITER + "DATA_IMPORT" + DELIMITER;
+
+    private CacheConstants() {
+    }
+}

+ 45 - 0
pavis-common/src/main/java/com/pavis/admin/common/constant/ContainerConstants.java

@@ -0,0 +1,45 @@
+
+package com.pavis.admin.common.constant;
+
+/**
+ * 数据源容器相关常量(Crane4j 数据填充组件使用)
+ *
+ *
+ * @since 2024/1/20 12:33
+ */
+public class ContainerConstants {
+
+    /**
+     * 用户昵称
+     */
+    public static final String USER_NICKNAME = "UserNickname";
+
+    /**
+     * 用户角色 ID 列表
+     */
+    public static final String USER_ROLE_ID_LIST = "UserRoleIdList";
+
+    /**
+     * 用户角色名称列表
+     */
+    public static final String USER_ROLE_NAME_LIST = "UserRoleNameList";
+
+    /**
+     * 应用知识库 ID 列表
+     */
+    public static final String APP_KNOWLEDGE_ID_LIST = "AppKnowledgeIdList";
+
+
+    /**
+     * 智能体工具 ID 列表
+     */
+    public static final String AGENT_TOOL_ID_LIST = "AgentToolIdList";
+
+    /**
+     * 智能体工具 Key 列表
+     */
+    public static final String AGENT_TOOL_KEY_LIST = "AgentToolKeyList";
+
+    private ContainerConstants() {
+    }
+}

+ 49 - 0
pavis-common/src/main/java/com/pavis/admin/common/constant/RegexConstants.java

@@ -0,0 +1,49 @@
+
+package com.pavis.admin.common.constant;
+
+/**
+ * 正则相关常量
+ *
+ * 
+ * @since 2023/1/10 20:06
+ */
+public class RegexConstants {
+
+    /**
+     * 用户名正则(用户名长度为 4-64 个字符,支持大小写字母、数字、下划线,以字母开头)
+     */
+    public static final String USERNAME = "^[a-zA-Z][a-zA-Z0-9_]{3,64}$";
+
+    /**
+     * 密码正则模板(密码长度为 min-max 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字)
+     */
+    public static final String PASSWORD_TEMPLATE = "^(?=.*\\d)(?=.*[a-z]).{%s,%s}$";
+
+    /**
+     * 密码正则(密码长度为 8-32 个字符,支持大小写字母、数字、特殊字符,至少包含字母和数字)
+     */
+    public static final String PASSWORD = "^(?=.*\\d)(?=.*[a-z]).{8,32}$";
+
+    /**
+     * 特殊字符正则
+     */
+    public static final String SPECIAL_CHARACTER = "[-_`~!@#$%^&*()+=|{}':;',\\\\[\\\\].<>/?~!@#¥%……&*()——+|{}【】‘;:”“’。,、?]|\\n|\\r|\\t";
+
+    /**
+     * 通用编码正则(长度为 2-30 个字符,支持大小写字母、数字、下划线,以字母开头)
+     */
+    public static final String GENERAL_CODE = "^[a-zA-Z][a-zA-Z0-9_]{1,29}$";
+
+    /**
+     * 通用名称正则(长度为 2-30 个字符,支持中文、字母、数字、下划线,短横线)
+     */
+    public static final String GENERAL_NAME = "^[\\u4e00-\\u9fa5a-zA-Z0-9_-]{2,30}$";
+
+    /**
+     * 包名正则(可以包含大小写字母、数字、下划线,每一级包名不能以数字开头)
+     */
+    public static final String PACKAGE_NAME = "^(?:[a-zA-Z_][a-zA-Z0-9_]*\\.)*[a-zA-Z_][a-zA-Z0-9_]*$";
+
+    private RegexConstants() {
+    }
+}

+ 74 - 0
pavis-common/src/main/java/com/pavis/admin/common/constant/SysConstants.java

@@ -0,0 +1,74 @@
+
+package com.pavis.admin.common.constant;
+
+/**
+ * 系统相关常量
+ *
+ *
+ * @since 2023/2/9 22:11
+ */
+public class SysConstants {
+
+    /**
+     * 否
+     */
+    public static final Integer NO = 0;
+
+    /**
+     * 是
+     */
+    public static final Integer YES = 1;
+
+    /**
+     * 超管用户 ID
+     */
+    public static final Long SUPER_USER_ID = 1L;
+
+    /**
+     * 顶级部门 ID
+     */
+    public static final Long SUPER_DEPT_ID = 1L;
+
+    /**
+     * 顶级父 ID
+     */
+    public static final Long SUPER_PARENT_ID = 0L;
+
+    /**
+     * 超管角色编码
+     */
+    public static final String SUPER_ROLE_CODE = "admin";
+
+    /**
+     * 普通用户角色编码
+     */
+    public static final String GENERAL_ROLE_CODE = "general";
+
+    /**
+     * 超管角色 ID
+     */
+    public static final Long SUPER_ROLE_ID = 1L;
+
+    /**
+     * 普通用户角色 ID
+     */
+    public static final Long GENERAL_ROLE_ID = 2L;
+
+    /**
+     * 全部权限标识
+     */
+    public static final String ALL_PERMISSION = "*:*:*";
+
+    /**
+     * 登录 URI
+     */
+    public static final String LOGIN_URI = "/auth/login";
+
+    /**
+     * 登出 URI
+     */
+    public static final String LOGOUT_URI = "/auth/logout";
+
+    private SysConstants() {
+    }
+}

+ 39 - 0
pavis-common/src/main/java/com/pavis/admin/common/constant/UiConstants.java

@@ -0,0 +1,39 @@
+
+package com.pavis.admin.common.constant;
+
+/**
+ * UI 相关常量
+ *
+ * 
+ * @since 2023/9/17 14:12
+ */
+public class UiConstants {
+
+    /**
+     * 主要色(极致蓝)
+     */
+    public static final String COLOR_PRIMARY = "primary";
+
+    /**
+     * 成功色(仙野绿)
+     */
+    public static final String COLOR_SUCCESS = "success";
+
+    /**
+     * 警告色(活力橙)
+     */
+    public static final String COLOR_WARNING = "warning";
+
+    /**
+     * 错误色(浪漫红)
+     */
+    public static final String COLOR_ERROR = "error";
+
+    /**
+     * 默认色(中性灰)
+     */
+    public static final String COLOR_DEFAULT = "default";
+
+    private UiConstants() {
+    }
+}

+ 44 - 0
pavis-common/src/main/java/com/pavis/admin/common/context/RoleContext.java

@@ -0,0 +1,44 @@
+
+package com.pavis.admin.common.context;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import com.pavis.admin.common.enums.DataScopeEnum;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 角色上下文
+ *
+ *
+ * @since 2023/3/7 22:08
+ */
+@Data
+@NoArgsConstructor
+public class RoleContext implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ID
+     */
+    private Long id;
+
+    /**
+     * 角色编码
+     */
+    private String code;
+
+    /**
+     * 数据权限
+     */
+    private DataScopeEnum dataScope;
+
+    public RoleContext(Long id, String code, DataScopeEnum dataScope) {
+        this.id = id;
+        this.code = code;
+        this.dataScope = dataScope;
+    }
+}

+ 117 - 0
pavis-common/src/main/java/com/pavis/admin/common/context/UserContext.java

@@ -0,0 +1,117 @@
+
+package com.pavis.admin.common.context;
+
+import cn.hutool.core.collection.CollUtil;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import com.pavis.admin.common.constant.SysConstants;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 用户上下文
+ *
+ *
+ * @since 2024/10/9 20:29
+ */
+@Data
+@NoArgsConstructor
+public class UserContext implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ID
+     */
+    private Long id;
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 部门 ID
+     */
+    private Long deptId;
+
+    /**
+     * 最后一次修改密码时间
+     */
+    private LocalDateTime pwdResetTime;
+
+    /**
+     * 登录时系统设置的密码过期天数
+     */
+    private Integer passwordExpirationDays;
+
+    /**
+     * 权限码集合
+     */
+    private Set<String> permissions;
+
+    /**
+     * 角色编码集合
+     */
+    private Set<String> roleCodes;
+
+    /**
+     * 角色集合
+     */
+    private Set<RoleContext> roles;
+
+    /**
+     * 客户端类型
+     */
+    private String clientType;
+
+    /**
+     * 客户端 ID
+     */
+    private String clientId;
+
+    public UserContext(Set<String> permissions, Set<RoleContext> roles, Integer passwordExpirationDays) {
+        this.permissions = permissions;
+        this.setRoles(roles);
+        this.passwordExpirationDays = passwordExpirationDays;
+    }
+
+    public void setRoles(Set<RoleContext> roles) {
+        this.roles = roles;
+        this.roleCodes = roles.stream().map(RoleContext::getCode).collect(Collectors.toSet());
+    }
+
+    /**
+     * 是否为管理员
+     *
+     * @return true:是;false:否
+     */
+    public boolean isAdmin() {
+        if (CollUtil.isEmpty(roleCodes)) {
+            return false;
+        }
+        return roleCodes.contains(SysConstants.SUPER_ROLE_CODE);
+    }
+
+    /**
+     * 密码是否已过期
+     *
+     * @return 是否过期
+     */
+    public boolean isPasswordExpired() {
+        // 永久有效
+        if (this.passwordExpirationDays == null || this.passwordExpirationDays <= SysConstants.NO) {
+            return false;
+        }
+        // 初始密码(第三方登录用户)暂不提示修改
+        if (this.pwdResetTime == null) {
+            return false;
+        }
+        return this.pwdResetTime.plusDays(this.passwordExpirationDays).isBefore(LocalDateTime.now());
+    }
+}

+ 168 - 0
pavis-common/src/main/java/com/pavis/admin/common/context/UserContextHolder.java

@@ -0,0 +1,168 @@
+
+package com.pavis.admin.common.context;
+
+import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.extra.spring.SpringUtil;
+import com.pavis.admin.common.service.CommonUserService;
+import top.continew.starter.core.util.ExceptionUtils;
+
+/**
+ * 用户上下文 Holder
+ *
+ *
+ * @since 2022/12/24 12:58
+ */
+public class UserContextHolder {
+
+    private static final ThreadLocal<UserContext> CONTEXT_HOLDER = new ThreadLocal<>();
+    private static final ThreadLocal<UserExtraContext> EXTRA_CONTEXT_HOLDER = new ThreadLocal<>();
+
+    private UserContextHolder() {
+    }
+
+    /**
+     * 设置上下文
+     *
+     * @param context 上下文
+     */
+    public static void setContext(UserContext context) {
+        setContext(context, true);
+    }
+
+    /**
+     * 设置上下文
+     *
+     * @param context  上下文
+     * @param isUpdate 是否更新
+     */
+    public static void setContext(UserContext context, boolean isUpdate) {
+        CONTEXT_HOLDER.set(context);
+        if (isUpdate) {
+            StpUtil.getSessionByLoginId(context.getId()).set(SaSession.USER, context);
+        }
+    }
+
+    /**
+     * 获取上下文
+     *
+     * @return 上下文
+     */
+    public static UserContext getContext() {
+        UserContext context = CONTEXT_HOLDER.get();
+        if (null == context) {
+            context = StpUtil.getSession().getModel(SaSession.USER, UserContext.class);
+            CONTEXT_HOLDER.set(context);
+        }
+        return context;
+    }
+
+    /**
+     * 获取指定用户的上下文
+     *
+     * @param userId 用户 ID
+     * @return 上下文
+     */
+    public static UserContext getContext(Long userId) {
+        SaSession session = StpUtil.getSessionByLoginId(userId, false);
+        if (null == session) {
+            return null;
+        }
+        return session.getModel(SaSession.USER, UserContext.class);
+    }
+
+    /**
+     * 设置额外上下文
+     *
+     * @param context 额外上下文
+     */
+    public static void setExtraContext(UserExtraContext context) {
+        EXTRA_CONTEXT_HOLDER.set(context);
+    }
+
+    /**
+     * 获取额外上下文
+     *
+     * @return 额外上下文
+     */
+    public static UserExtraContext getExtraContext() {
+        UserExtraContext context = EXTRA_CONTEXT_HOLDER.get();
+        if (null == context) {
+            context = getExtraContext(StpUtil.getTokenValue());
+            EXTRA_CONTEXT_HOLDER.set(context);
+        }
+        return context;
+    }
+
+    /**
+     * 获取额外上下文
+     *
+     * @param token 令牌
+     * @return 额外上下文
+     */
+    public static UserExtraContext getExtraContext(String token) {
+        UserExtraContext context = new UserExtraContext();
+        context.setIp(Convert.toStr(StpUtil.getExtra(token, "ip")));
+        context.setAddress(Convert.toStr(StpUtil.getExtra(token, "address")));
+        context.setBrowser(Convert.toStr(StpUtil.getExtra(token, "browser")));
+        context.setOs(Convert.toStr(StpUtil.getExtra(token, "os")));
+        context.setLoginTime(Convert.toLocalDateTime(StpUtil.getExtra(token, "loginTime")));
+        return context;
+    }
+
+    /**
+     * 清除上下文
+     */
+    public static void clearContext() {
+        CONTEXT_HOLDER.remove();
+        EXTRA_CONTEXT_HOLDER.remove();
+    }
+
+    /**
+     * 获取用户 ID
+     *
+     * @return 用户 ID
+     */
+    public static Long getUserId() {
+        return ExceptionUtils.exToNull(() -> getContext().getId());
+    }
+
+    /**
+     * 获取用户名
+     *
+     * @return 用户名
+     */
+    public static String getUsername() {
+        return ExceptionUtils.exToNull(() -> getContext().getUsername());
+    }
+
+    /**
+     * 获取用户昵称
+     *
+     * @return 用户昵称
+     */
+    public static String getNickname() {
+        return getNickname(getUserId());
+    }
+
+    /**
+     * 获取用户昵称
+     *
+     * @param userId 登录用户 ID
+     * @return 用户昵称
+     */
+    public static String getNickname(Long userId) {
+        return ExceptionUtils.exToNull(() -> SpringUtil.getBean(CommonUserService.class).getNicknameById(userId));
+    }
+
+    /**
+     * 是否为管理员
+     *
+     * @return 是否为管理员
+     */
+    public static boolean isAdmin() {
+        StpUtil.checkLogin();
+        return getContext().isAdmin();
+    }
+}

+ 62 - 0
pavis-common/src/main/java/com/pavis/admin/common/context/UserExtraContext.java

@@ -0,0 +1,62 @@
+
+package com.pavis.admin.common.context;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.servlet.JakartaServletUtil;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import top.continew.starter.core.util.ExceptionUtils;
+import top.continew.starter.core.util.IpUtils;
+import top.continew.starter.web.util.ServletUtils;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 用户额外上下文
+ *
+ *
+ * @since 2024/10/9 20:29
+ */
+@Data
+@NoArgsConstructor
+public class UserExtraContext implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * IP
+     */
+    private String ip;
+
+    /**
+     * IP 归属地
+     */
+    private String address;
+
+    /**
+     * 浏览器
+     */
+    private String browser;
+
+    /**
+     * 操作系统
+     */
+    private String os;
+
+    /**
+     * 登录时间
+     */
+    private LocalDateTime loginTime;
+
+    public UserExtraContext(HttpServletRequest request) {
+        this.ip = JakartaServletUtil.getClientIP(request);
+        this.address = ExceptionUtils.exToNull(() -> IpUtils.getIpv4Address(this.ip));
+        this.setBrowser(ServletUtils.getBrowser(request));
+        this.setLoginTime(LocalDateTime.now());
+        this.setOs(StrUtil.subBefore(ServletUtils.getOs(request), " or", false));
+    }
+}

+ 52 - 0
pavis-common/src/main/java/com/pavis/admin/common/controller/BaseController.java

@@ -0,0 +1,52 @@
+
+package com.pavis.admin.common.controller;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.context.model.SaRequest;
+import cn.dev33.satoken.sign.SaSignTemplate;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import top.continew.starter.core.constant.StringConstants;
+import top.continew.starter.extension.crud.annotation.CrudApi;
+import top.continew.starter.extension.crud.annotation.CrudRequestMapping;
+import top.continew.starter.extension.crud.controller.AbstractBaseController;
+import top.continew.starter.extension.crud.enums.Api;
+import top.continew.starter.extension.crud.service.BaseService;
+
+import java.lang.reflect.Method;
+import java.util.Collection;
+
+/**
+ * 控制器基类
+ *
+ * @param <S> 业务接口
+ * @param <L> 列表类型
+ * @param <D> 详情类型
+ * @param <Q> 查询条件
+ * @param <C> 创建或修改参数类型
+ * 
+ * @since 2024/12/6 20:30
+ */
+public class BaseController<S extends BaseService<L, D, Q, C>, L, D, Q, C> extends AbstractBaseController<S, L, D, Q, C> {
+
+    @Override
+    public void preHandle(CrudApi crudApi, Object[] args, Method targetMethod, Class<?> targetClass) throws Exception {
+        SaRequest saRequest = SaHolder.getRequest();
+        Collection<String> paramNames = saRequest.getParamNames();
+        if (paramNames.stream().anyMatch(SaSignTemplate.sign::equals)) {
+            return;
+        }
+        if (AnnotationUtil.hasAnnotation(targetMethod, SaIgnore.class) || AnnotationUtil
+            .hasAnnotation(targetClass, SaIgnore.class)) {
+            return;
+        }
+        CrudRequestMapping crudRequestMapping = targetClass.getDeclaredAnnotation(CrudRequestMapping.class);
+        String path = crudRequestMapping.value();
+        String prefix = String.join(StringConstants.COLON, CharSequenceUtil.splitTrim(path, StringConstants.SLASH));
+        Api api = crudApi.value();
+        String apiName = Api.PAGE.equals(api) || Api.TREE.equals(api) ? Api.LIST.name() : api.name();
+        StpUtil.checkPermission("%s:%s".formatted(prefix, apiName.toLowerCase()));
+    }
+}

+ 45 - 0
pavis-common/src/main/java/com/pavis/admin/common/enums/DataScopeEnum.java

@@ -0,0 +1,45 @@
+
+package com.pavis.admin.common.enums;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import top.continew.starter.core.enums.BaseEnum;
+
+/**
+ * 数据权限枚举
+ *
+ *
+ * @since 2023/2/8 22:58
+ */
+@Getter
+@RequiredArgsConstructor
+public enum DataScopeEnum implements BaseEnum<Integer> {
+
+    /**
+     * 全部数据权限
+     */
+    ALL(1, "全部数据权限"),
+
+    /**
+     * 本部门及以下数据权限
+     */
+    DEPT_AND_CHILD(2, "本部门及以下数据权限"),
+
+    /**
+     * 本部门数据权限
+     */
+    DEPT(3, "本部门数据权限"),
+
+    /**
+     * 仅本人数据权限
+     */
+    SELF(4, "仅本人数据权限"),
+
+    /**
+     * 自定义数据权限
+     */
+    CUSTOM(5, "自定义数据权限"),;
+
+    private final Integer value;
+    private final String description;
+}

+ 32 - 0
pavis-common/src/main/java/com/pavis/admin/common/enums/DisEnableStatusEnum.java

@@ -0,0 +1,32 @@
+
+package com.pavis.admin.common.enums;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import com.pavis.admin.common.constant.UiConstants;
+import top.continew.starter.core.enums.BaseEnum;
+
+/**
+ * 启用/禁用状态枚举
+ *
+ *
+ * @since 2022/12/29 22:38
+ */
+@Getter
+@RequiredArgsConstructor
+public enum DisEnableStatusEnum implements BaseEnum<Integer> {
+
+    /**
+     * 启用
+     */
+    ENABLE(1, "启用", UiConstants.COLOR_SUCCESS),
+
+    /**
+     * 禁用
+     */
+    DISABLE(2, "禁用", UiConstants.COLOR_ERROR),;
+
+    private final Integer value;
+    private final String description;
+    private final String color;
+}

+ 35 - 0
pavis-common/src/main/java/com/pavis/admin/common/enums/GenderEnum.java

@@ -0,0 +1,35 @@
+
+package com.pavis.admin.common.enums;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import top.continew.starter.core.enums.BaseEnum;
+
+/**
+ * 性别枚举
+ *
+ *
+ * @since 2022/12/29 21:59
+ */
+@Getter
+@RequiredArgsConstructor
+public enum GenderEnum implements BaseEnum<Integer> {
+
+    /**
+     * 未知
+     */
+    UNKNOWN(0, "未知"),
+
+    /**
+     * 男
+     */
+    MALE(1, "男"),
+
+    /**
+     * 女
+     */
+    FEMALE(2, "女"),;
+
+    private final Integer value;
+    private final String description;
+}

+ 32 - 0
pavis-common/src/main/java/com/pavis/admin/common/enums/SuccessFailureStatusEnum.java

@@ -0,0 +1,32 @@
+
+package com.pavis.admin.common.enums;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import com.pavis.admin.common.constant.UiConstants;
+import top.continew.starter.core.enums.BaseEnum;
+
+/**
+ * 成功/失败状态枚举
+ *
+ *
+ * @since 2023/2/26 21:35
+ */
+@Getter
+@RequiredArgsConstructor
+public enum SuccessFailureStatusEnum implements BaseEnum<Integer> {
+
+    /**
+     * 成功
+     */
+    SUCCESS(1, "成功", UiConstants.COLOR_SUCCESS),
+
+    /**
+     * 失败
+     */
+    FAILURE(2, "失败", UiConstants.COLOR_ERROR),;
+
+    private final Integer value;
+    private final String description;
+    private final String color;
+}

+ 39 - 0
pavis-common/src/main/java/com/pavis/admin/common/model/entity/BaseCreateDO.java

@@ -0,0 +1,39 @@
+
+package com.pavis.admin.common.model.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+import top.continew.starter.extension.crud.model.entity.BaseIdDO;
+
+import java.io.Serial;
+import java.time.LocalDateTime;
+
+/**
+ * 实体类基类
+ *
+ * <p>
+ * 通用字段:ID、创建人、创建时间
+ * </p>
+ *
+ *
+ * @since 2025/1/12 23:00
+ */
+@Data
+public class BaseCreateDO extends BaseIdDO {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 创建人
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUser;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+}

+ 51 - 0
pavis-common/src/main/java/com/pavis/admin/common/model/entity/BaseDO.java

@@ -0,0 +1,51 @@
+
+package com.pavis.admin.common.model.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+import top.continew.starter.extension.crud.model.entity.BaseIdDO;
+
+import java.io.Serial;
+import java.time.LocalDateTime;
+
+/**
+ * 实体类基类
+ *
+ * <p>
+ * 通用字段:ID、创建人、创建时间、修改人、修改时间
+ * </p>
+ *
+ *
+ * @since 2025/1/12 23:00
+ */
+@Data
+public class BaseDO extends BaseIdDO {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 创建人
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private Long createUser;
+
+    /**
+     * 创建时间
+     */
+    @TableField(fill = FieldFill.INSERT)
+    private LocalDateTime createTime;
+
+    /**
+     * 修改人
+     */
+    @TableField(fill = FieldFill.UPDATE)
+    private Long updateUser;
+
+    /**
+     * 修改时间
+     */
+    @TableField(fill = FieldFill.UPDATE)
+    private LocalDateTime updateTime;
+}

+ 39 - 0
pavis-common/src/main/java/com/pavis/admin/common/model/entity/BaseUpdateDO.java

@@ -0,0 +1,39 @@
+
+package com.pavis.admin.common.model.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.TableField;
+import lombok.Data;
+import top.continew.starter.extension.crud.model.entity.BaseIdDO;
+
+import java.io.Serial;
+import java.time.LocalDateTime;
+
+/**
+ * 实体类基类
+ *
+ * <p>
+ * 通用字段:ID、修改人、修改时间
+ * </p>
+ *
+ *
+ * @since 2025/1/12 23:00
+ */
+@Data
+public class BaseUpdateDO extends BaseIdDO {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 修改人
+     */
+    @TableField(fill = FieldFill.UPDATE)
+    private Long updateUser;
+
+    /**
+     * 修改时间
+     */
+    @TableField(fill = FieldFill.UPDATE)
+    private LocalDateTime updateTime;
+}

+ 27 - 0
pavis-common/src/main/java/com/pavis/admin/common/model/req/CommonStatusUpdateReq.java

@@ -0,0 +1,27 @@
+
+package com.pavis.admin.common.model.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import com.pavis.admin.common.enums.DisEnableStatusEnum;
+
+import java.io.Serializable;
+
+/**
+ * 状态修改请求参数
+ *
+ *
+ * @since 2025/3/4 20:09
+ */
+@Data
+@Schema(description = "状态修改请求参数")
+public class CommonStatusUpdateReq implements Serializable {
+
+    /**
+     * 状态
+     */
+    @Schema(description = "状态", example = "1")
+    @NotNull(message = "状态无效")
+    private DisEnableStatusEnum status;
+}

+ 49 - 0
pavis-common/src/main/java/com/pavis/admin/common/model/resp/BaseDetailResp.java

@@ -0,0 +1,49 @@
+
+package com.pavis.admin.common.model.resp;
+
+import cn.crane4j.annotation.Assemble;
+import cn.crane4j.annotation.Mapping;
+import cn.crane4j.annotation.condition.ConditionOnPropertyNotNull;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.pavis.admin.common.constant.ContainerConstants;
+
+import java.io.Serial;
+import java.time.LocalDateTime;
+
+/**
+ * 详情响应参数基类
+ *
+ *
+ * @since 2024/12/27 20:32
+ */
+@Data
+public class BaseDetailResp extends BaseResp {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 修改人
+     */
+    @JsonIgnore
+    @ConditionOnPropertyNotNull
+    @Assemble(container = ContainerConstants.USER_NICKNAME, props = @Mapping(ref = "updateUserString"))
+    private Long updateUser;
+
+    /**
+     * 修改人
+     */
+    @Schema(description = "修改人", example = "李四")
+    @ExcelProperty(value = "修改人", order = Integer.MAX_VALUE - 2)
+    private String updateUserString;
+
+    /**
+     * 修改时间
+     */
+    @Schema(description = "修改时间", example = "2023-08-08 08:08:08", type = "string")
+    @ExcelProperty(value = "修改时间", order = Integer.MAX_VALUE - 1)
+    private LocalDateTime updateTime;
+}

+ 63 - 0
pavis-common/src/main/java/com/pavis/admin/common/model/resp/BaseResp.java

@@ -0,0 +1,63 @@
+
+package com.pavis.admin.common.model.resp;
+
+import cn.crane4j.annotation.Assemble;
+import cn.crane4j.annotation.Mapping;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import com.pavis.admin.common.constant.ContainerConstants;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 响应参数基类
+ *
+ *
+ * @since 2024/12/27 20:32
+ */
+@Data
+public class BaseResp implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ID
+     */
+    @Schema(description = "ID", example = "1")
+    @ExcelProperty(value = "ID", order = 1)
+    private Long id;
+
+    /**
+     * 创建人
+     */
+    @JsonIgnore
+    @Assemble(container = ContainerConstants.USER_NICKNAME, props = @Mapping(ref = "createUserString"))
+    private Long createUser;
+
+    /**
+     * 创建人
+     */
+    @Schema(description = "创建人", example = "超级管理员")
+    @ExcelProperty(value = "创建人", order = Integer.MAX_VALUE - 4)
+    private String createUserString;
+
+    /**
+     * 创建时间
+     */
+    @Schema(description = "创建时间", example = "2023-08-08 08:08:08", type = "string")
+    @ExcelProperty(value = "创建时间", order = Integer.MAX_VALUE - 3)
+    private LocalDateTime createTime;
+
+    /**
+     * 是否禁用修改
+     */
+    @Schema(description = "是否禁用修改", example = "true")
+    @JsonInclude(JsonInclude.Include.NON_NULL)
+    private Boolean disabled;
+}

+ 23 - 0
pavis-common/src/main/java/com/pavis/admin/common/service/CommonDictItemService.java

@@ -0,0 +1,23 @@
+
+package com.pavis.admin.common.service;
+
+import top.continew.starter.extension.crud.model.resp.LabelValueResp;
+
+import java.util.List;
+
+/**
+ * 公共字典项业务接口
+ *
+ *
+ * @since 2025/4/9 20:17
+ */
+public interface CommonDictItemService {
+
+    /**
+     * 根据字典编码查询
+     *
+     * @param dictCode 字典编码
+     * @return 字典项列表
+     */
+    List<LabelValueResp> listByDictCode(String dictCode);
+}

+ 28 - 0
pavis-common/src/main/java/com/pavis/admin/common/service/CommonUserService.java

@@ -0,0 +1,28 @@
+
+package com.pavis.admin.common.service;
+
+import cn.crane4j.annotation.ContainerMethod;
+import cn.crane4j.annotation.MappingType;
+import com.pavis.admin.common.constant.ContainerConstants;
+
+/**
+ * 公共用户业务接口
+ *
+ *
+ * @since 2025/1/9 20:17
+ */
+public interface CommonUserService {
+
+    /**
+     * 根据 ID 查询昵称
+     *
+     * <p>
+     * 数据填充容器 {@link ContainerConstants#USER_NICKNAME}
+     * </p>
+     *
+     * @param id ID
+     * @return 昵称
+     */
+    @ContainerMethod(namespace = ContainerConstants.USER_NICKNAME, type = MappingType.ORDER_OF_KEYS)
+    String getNicknameById(Long id);
+}

+ 92 - 0
pavis-common/src/main/java/com/pavis/admin/common/util/SecureUtils.java

@@ -0,0 +1,92 @@
+
+package com.pavis.admin.common.util;
+
+import cn.hutool.core.codec.Base64;
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.extra.spring.SpringUtil;
+import com.pavis.admin.common.config.properties.RsaProperties;
+import top.continew.starter.core.exception.BusinessException;
+import top.continew.starter.core.validation.ValidationUtils;
+import top.continew.starter.security.crypto.autoconfigure.CryptoProperties;
+import top.continew.starter.security.crypto.encryptor.AesEncryptor;
+import top.continew.starter.security.crypto.encryptor.IEncryptor;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 加密/解密工具类
+ *
+ * 
+ * @since 2022/12/21 21:41
+ */
+public class SecureUtils {
+
+    private SecureUtils() {
+    }
+
+    /**
+     * 公钥加密
+     *
+     * @param data 要加密的内容
+     * @return 加密后的内容
+     */
+    public static String encryptByRsaPublicKey(String data) {
+        String publicKey = RsaProperties.PUBLIC_KEY;
+        ValidationUtils.throwIfBlank(publicKey, "请配置 RSA 公钥");
+        return encryptByRsaPublicKey(data, publicKey);
+    }
+
+    /**
+     * 私钥解密
+     *
+     * @param data 要解密的内容(Base64 加密过)
+     * @return 解密后的内容
+     */
+    public static String decryptByRsaPrivateKey(String data) {
+        String privateKey = RsaProperties.PRIVATE_KEY;
+        ValidationUtils.throwIfBlank(privateKey, "请配置 RSA 私钥");
+        return decryptByRsaPrivateKey(data, privateKey);
+    }
+
+    /**
+     * 公钥加密
+     *
+     * @param data      要加密的内容
+     * @param publicKey 公钥
+     * @return 加密后的内容
+     */
+    public static String encryptByRsaPublicKey(String data, String publicKey) {
+        return new String(SecureUtil.rsa(null, publicKey).encrypt(data, KeyType.PublicKey));
+    }
+
+    /**
+     * 私钥解密
+     *
+     * @param data       要解密的内容(Base64 加密过)
+     * @param privateKey 私钥
+     * @return 解密后的内容
+     */
+    public static String decryptByRsaPrivateKey(String data, String privateKey) {
+        return new String(SecureUtil.rsa(privateKey, null).decrypt(Base64.decode(data), KeyType.PrivateKey));
+    }
+
+    /**
+     * 对普通加密字段列表进行AES加密,优化starter加密模块后优化这个方法
+     *
+     * @param values 待加密内容
+     * @return 加密后内容
+     */
+    public static List<String> encryptFieldByAes(List<String> values) {
+        IEncryptor encryptor = new AesEncryptor();
+        CryptoProperties properties = SpringUtil.getBean(CryptoProperties.class);
+        return values.stream().map(value -> {
+            try {
+                return encryptor.encrypt(value, properties.getPassword(), properties.getPublicKey());
+            } catch (Exception e) {
+                throw new BusinessException("字段加密异常");
+            }
+        }).collect(Collectors.toList());
+    }
+}

+ 50 - 0
pavis-extension/pavis-extension-schedule-server/pom.xml

@@ -0,0 +1,50 @@
+<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 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.pavis</groupId>
+        <artifactId>pavis-extension</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>pavis-extension-schedule-server</artifactId>
+    <description>任务调度服务端</description>
+
+    <properties>
+        <!-- SnailJob 服务端 -->
+        <snail-job.version>1.4.0</snail-job.version>
+    </properties>
+
+    <dependencies>
+        <!-- SnailJob(灵活,可靠和快速的分布式任务重试和分布式任务调度平台) -->
+        <dependency>
+            <groupId>com.aizuda</groupId>
+            <artifactId>snail-job-server-starter</artifactId>
+            <version>${snail-job.version}</version>
+        </dependency>
+
+        <!-- Liquibase(用于管理数据库版本,跟踪、管理和应用数据库变化) -->
+        <dependency>
+            <groupId>org.liquibase</groupId>
+            <artifactId>liquibase-core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <!-- 设置构建的 jar 包名 -->
+        <finalName>${project.artifactId}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 44 - 0
pavis-extension/pavis-extension-schedule-server/src/main/java/com/pavis/admin/extension/scheduling/ScheduleServerApplication.java

@@ -0,0 +1,44 @@
+
+package com.pavis.admin.extension.scheduling;
+
+import cn.hutool.core.net.NetUtil;
+import cn.hutool.core.util.URLUtil;
+import cn.hutool.extra.spring.SpringUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+
+/**
+ * 任务调度服务端启动程序
+ *
+ * 
+ * @since 2024/6/25 22:24
+ */
+@Slf4j
+@SpringBootApplication
+@RequiredArgsConstructor
+public class ScheduleServerApplication extends com.aizuda.snailjob.server.SnailJobServerApplication implements ApplicationRunner {
+
+    private final ServerProperties serverProperties;
+
+    public static void main(String[] args) {
+        SpringApplication.run(ScheduleServerApplication.class, args);
+    }
+
+    @Override
+    public void run(ApplicationArguments args) {
+        String hostAddress = NetUtil.getLocalhostStr();
+        Integer port = serverProperties.getPort();
+        String contextPath = serverProperties.getServlet().getContextPath();
+        String baseUrl = URLUtil.normalize("%s:%s%s".formatted(hostAddress, port, contextPath));
+        log.info("----------------------------------------------");
+        log.info("{} service started successfully.", SpringUtil.getApplicationName());
+        log.info("访问地址:{}", baseUrl);
+        log.info("在线文档:https://snailjob.opensnail.com");
+        log.info("----------------------------------------------");
+    }
+}

+ 58 - 0
pavis-extension/pavis-extension-schedule-server/src/main/resources/config/application-dev.yml

@@ -0,0 +1,58 @@
+server:
+  port: 8001
+
+--- ### 数据源配置
+spring.datasource:
+  url: jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:pavis_admin_job}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+  username: ${DB_USER:root}
+  password: ${DB_PWD:Semi.1001}
+  driver-class-name: com.mysql.cj.jdbc.Driver
+#  # PostgreSQL 配置
+#  url: jdbc:postgresql://${DB_HOST:127.0.0.1}:${DB_PORT:5432}/${DB_NAME:pavis_admin_job}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&stringtype=unspecified
+#  username: ${DB_USER:root}
+#  password: ${DB_PWD:123456}
+#  driver-class-name: org.postgresql.Driver
+## Liquibase 配置
+spring.liquibase:
+  # 是否启用
+  enabled: true
+  # 配置文件路径
+  change-log: classpath:/db/changelog/db.changelog-master.yaml
+
+--- ### Snail Job 服务端配置
+snail-job:
+  # Netty 端口
+  netty-port: 1788
+  # 合并日志默认保存天数
+  merge-Log-days: 1
+  # 合并日志默认的条数
+  merge-Log-num: 500
+  # 配置日志保存时间(单位:天)
+  log-storage: 90
+  # 配置每批次拉取重试数据的大小
+  retry-pull-page-size: 100
+  # 配置一个客户端每秒最多接收的重试数量指令
+  limiter: 10
+  # 配置号段模式下的步长
+  step: 100
+  # bucket 的总数量
+  bucket-total: 128
+  # Dashboard 任务容错天数
+  summary-day: 7
+  # 配置负载均衡周期时间
+  load-balance-cycle-time: 10
+  ## 回调配置
+  callback:
+    # 回调 uniqueId 前缀
+    prefix: CB
+    # 配置回调的最大执行次数
+    max-count: 288
+    # 配置回调触发的间隔时间
+    trigger-interval: 900
+
+--- ### 日志配置
+logging:
+  level:
+    com.aizuda.snailjob: DEBUG
+  file:
+    path: ./logs

+ 58 - 0
pavis-extension/pavis-extension-schedule-server/src/main/resources/config/application-prod.yml

@@ -0,0 +1,58 @@
+server:
+  port: 18001
+
+--- ### 数据源配置
+spring.datasource:
+  url: jdbc:mysql://${DB_HOST:127.0.0.1}:${DB_PORT:3306}/${DB_NAME:pavis_admin_job}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
+  username: ${DB_USER:root}
+  password: ${DB_PWD:Semi.1001}
+  driver-class-name: com.mysql.cj.jdbc.Driver
+#  # PostgreSQL 配置
+#  url: jdbc:postgresql://${DB_HOST:127.0.0.1}:${DB_PORT:5432}/${DB_NAME:pavis_admin_job}?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&autoReconnect=true&stringtype=unspecified
+#  username: ${DB_USER:root}
+#  password: ${DB_PWD:123456}
+#  driver-class-name: org.postgresql.Driver
+## Liquibase 配置
+spring.liquibase:
+  # 是否启用
+  enabled: true
+  # 配置文件路径
+  change-log: classpath:/db/changelog/db.changelog-master.yaml
+
+--- ### Snail Job 服务端配置
+snail-job:
+  # Netty 端口
+  netty-port: 1788
+  # 合并日志默认保存天数
+  merge-Log-days: 1
+  # 合并日志默认的条数
+  merge-Log-num: 500
+  # 配置日志保存时间(单位:天)
+  log-storage: 90
+  # 配置每批次拉取重试数据的大小
+  retry-pull-page-size: 100
+  # 配置一个客户端每秒最多接收的重试数量指令
+  limiter: 10
+  # 配置号段模式下的步长
+  step: 100
+  # bucket 的总数量
+  bucket-total: 128
+  # Dashboard 任务容错天数
+  summary-day: 7
+  # 配置负载均衡周期时间
+  load-balance-cycle-time: 10
+  ## 回调配置
+  callback:
+    # 回调 uniqueId 前缀
+    prefix: CB
+    # 配置回调的最大执行次数
+    max-count: 288
+    # 配置回调触发的间隔时间
+    trigger-interval: 900
+
+--- ### 日志配置
+logging:
+  level:
+    com.aizuda.snailjob: INFO
+  file:
+    path: ../logs

+ 12 - 0
pavis-extension/pavis-extension-schedule-server/src/main/resources/config/application.yml

@@ -0,0 +1,12 @@
+--- ### Spring 配置
+spring:
+  application:
+    name: pavis-admin-schedule-server
+  ## 环境配置
+  profiles:
+    # 启用的环境
+    active: dev
+
+--- ### 日志配置
+logging:
+  config: classpath:logback-spring.xml

+ 5 - 0
pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/db.changelog-master.yaml

@@ -0,0 +1,5 @@
+databaseChangeLog:
+  - include:
+      file: db/changelog/mysql/snail-job_table.sql
+  - include:
+      file: db/changelog/mysql/snail-job_data.sql

+ 14 - 0
pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/mysql/snail-job_data.sql

@@ -0,0 +1,14 @@
+-- liquibase formatted sql
+
+-- changeset snail-job-server:1.1.0
+-- 默认命名空间:Default
+INSERT INTO `sj_namespace` (`id`, `name`, `unique_id`, `create_dt`, `update_dt`, `deleted`)
+VALUES (1, 'Default', '764d604ec6fc45f68cd92514c40e9e1a', NOW(), NOW(), 0);
+
+-- 默认用户:admin/admin
+INSERT INTO `sj_system_user` (username, password, role)
+VALUES ('admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2);
+
+-- 默认分组:continew-admin
+INSERT INTO `sj_group_config` (`id`, `namespace_id`, `group_name`, `description`, `token`, `group_status`, `version`, `group_partition`, `id_generator_mode`, `init_scene`, `create_dt`, `update_dt`)
+VALUES (1, '764d604ec6fc45f68cd92514c40e9e1a', 'continew-admin', '默认分组', 'SJ_Wyz3dmsdbDOkDujOTSSoBjGQP1BMsVnj', 1, 1, 0, 2, 1, NOW(), NOW());

+ 521 - 0
pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/mysql/snail-job_table.sql

@@ -0,0 +1,521 @@
+-- liquibase formatted sql
+
+-- changeset snail-job-server:1.1.0
+SET NAMES utf8mb4;
+
+CREATE TABLE `sj_namespace`
+(
+    `id`          bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `name`        varchar(64)         NOT NULL COMMENT '名称',
+    `unique_id`   varchar(64)         NOT NULL COMMENT '唯一id',
+    `description` varchar(256)        NOT NULL DEFAULT '' COMMENT '描述',
+    `deleted`     tinyint(4)          NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除',
+    `create_dt`   datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`   datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_name` (`name`),
+    UNIQUE KEY `uk_unique_id` (`unique_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='命名空间';
+
+CREATE TABLE `sj_group_config`
+(
+    `id`                bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`      varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`        varchar(64)         NOT NULL DEFAULT '' COMMENT '组名称',
+    `description`       varchar(256)        NOT NULL DEFAULT '' COMMENT '组描述',
+    `token`             varchar(64)         NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT' COMMENT 'token',
+    `group_status`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '组状态 0、未启用 1、启用',
+    `version`           int(11)             NOT NULL COMMENT '版本号',
+    `group_partition`   int(11)             NOT NULL COMMENT '分区',
+    `id_generator_mode` tinyint(4)          NOT NULL DEFAULT 1 COMMENT '唯一id生成模式 默认号段模式',
+    `init_scene`        tinyint(4)          NOT NULL DEFAULT 0 COMMENT '是否初始化场景 0:否 1:是',
+    `create_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='组配置'
+;
+
+CREATE TABLE `sj_notify_config`
+(
+    `id`                     bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`           varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`             varchar(64)         NOT NULL COMMENT '组名称',
+    `notify_name`            varchar(64)         NOT NULL DEFAULT '' COMMENT '通知名称',
+    `system_task_type`       tinyint(4)          NOT NULL DEFAULT 3 COMMENT '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务',
+    `notify_status`          tinyint(4)          NOT NULL DEFAULT 0 COMMENT '通知状态 0、未启用 1、启用',
+    `recipient_ids`          varchar(128)        NOT NULL COMMENT '接收人id列表',
+    `notify_threshold`       int(11)             NOT NULL DEFAULT 0 COMMENT '通知阈值',
+    `notify_scene`           tinyint(4)          NOT NULL DEFAULT 0 COMMENT '通知场景',
+    `rate_limiter_status`    tinyint(4)          NOT NULL DEFAULT 0 COMMENT '限流状态 0、未启用 1、启用',
+    `rate_limiter_threshold` int(11)             NOT NULL DEFAULT 0 COMMENT '每秒限流阈值',
+    `description`            varchar(256)        NOT NULL DEFAULT '' COMMENT '描述',
+    `create_dt`              datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`              datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='通知配置'
+;
+
+CREATE TABLE `sj_notify_recipient`
+(
+    `id`               bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`     varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `recipient_name`   varchar(64)         NOT NULL COMMENT '接收人名称',
+    `notify_type`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook',
+    `notify_attribute` varchar(512)        NOT NULL COMMENT '配置属性',
+    `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '描述',
+    `create_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id` (`namespace_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='告警通知接收人'
+;
+
+CREATE TABLE `sj_retry_dead_letter`
+(
+    `id`            bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`  varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`    varchar(64)         NOT NULL COMMENT '组名称',
+    `scene_name`    varchar(64)         NOT NULL COMMENT '场景名称',
+    `idempotent_id` varchar(64)         NOT NULL COMMENT '幂等id',
+    `biz_no`        varchar(64)         NOT NULL DEFAULT '' COMMENT '业务编号',
+    `executor_name` varchar(512)        NOT NULL DEFAULT '' COMMENT '执行器名称',
+    `args_str`      text                NOT NULL COMMENT '执行方法参数',
+    `ext_attrs`     text                NOT NULL COMMENT '扩展字段',
+    `create_dt`     datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`),
+    KEY `idx_idempotent_id` (`idempotent_id`),
+    KEY `idx_biz_no` (`biz_no`),
+    KEY `idx_create_dt` (`create_dt`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='死信队列表'
+;
+
+CREATE TABLE `sj_retry`
+(
+    `id`              bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`    varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`      varchar(64)         NOT NULL COMMENT '组名称',
+    `scene_name`      varchar(64)         NOT NULL COMMENT '场景名称',
+    `idempotent_id`   varchar(64)         NOT NULL COMMENT '幂等id',
+    `biz_no`          varchar(64)         NOT NULL DEFAULT '' COMMENT '业务编号',
+    `executor_name`   varchar(512)        NOT NULL DEFAULT '' COMMENT '执行器名称',
+    `args_str`        text                NOT NULL COMMENT '执行方法参数',
+    `ext_attrs`       text                NOT NULL COMMENT '扩展字段',
+    `next_trigger_at` bigint(13)          NOT NULL COMMENT '下次触发时间',
+    `retry_count`     int(11)             NOT NULL DEFAULT 0 COMMENT '重试次数',
+    `retry_status`    tinyint(4)          NOT NULL DEFAULT 0 COMMENT '重试状态 0、重试中 1、成功 2、最大重试次数',
+    `task_type`       tinyint(4)          NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据',
+    `bucket_index`    int(11)             NOT NULL DEFAULT 0 COMMENT 'bucket',
+    `parent_id`       bigint(20)          NOT NULL DEFAULT 0 COMMENT '父节点id',
+    `deleted`         bigint(20)          NOT NULL DEFAULT 0 COMMENT '逻辑删除',
+    `create_dt`       datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`       datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`),
+    KEY `idx_namespace_id_group_name_retry_status` (`namespace_id`, `group_name`, `retry_status`),
+    KEY `idx_idempotent_id` (`idempotent_id`),
+    KEY `idx_biz_no` (`biz_no`),
+    KEY `idx_parent_id` (`parent_id`),
+    KEY `idx_create_dt` (`create_dt`),
+    UNIQUE KEY `uk_name_task_type_idempotent_id_deleted` (`namespace_id`, `group_name`, `task_type`, `idempotent_id`, `deleted`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='重试信息表'
+;
+
+CREATE TABLE `sj_retry_task`
+(
+    `id`               bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`     varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`       varchar(64)         NOT NULL COMMENT '组名称',
+    `scene_name`       varchar(64)         NOT NULL COMMENT '场景名称',
+    `retry_id`         bigint(20)          NOT NULL COMMENT '重试信息Id',
+    `ext_attrs`        text                NOT NULL COMMENT '扩展字段',
+    `task_status`      tinyint(4)          NOT NULL DEFAULT 1 COMMENT '重试状态',
+    `task_type`        tinyint(4)          NOT NULL DEFAULT 1 COMMENT '任务类型 1、重试数据 2、回调数据',
+    `operation_reason` tinyint(4)          NOT NULL DEFAULT 0 COMMENT '操作原因',
+    `client_info`      varchar(128)        DEFAULT NULL COMMENT '客户端地址 clientId#ip:port',
+    `create_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`),
+    KEY `task_status` (`task_status`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_retry_id` (`retry_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='重试任务表'
+;
+
+CREATE TABLE `sj_retry_task_log_message`
+(
+    `id`            bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`  varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`    varchar(64)         NOT NULL COMMENT '组名称',
+    `retry_id`      bigint(20)          NOT NULL COMMENT '重试信息Id',
+    `retry_task_id` bigint(20)          NOT NULL COMMENT '重试任务Id',
+    `message`       longtext            NOT NULL COMMENT '异常信息',
+    `log_num`       int(11)             NOT NULL DEFAULT 1 COMMENT '日志数量',
+    `real_time`     bigint(13)          NOT NULL DEFAULT 0 COMMENT '上报时间',
+    `create_dt`     datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_retry_task_id` (`namespace_id`, `group_name`, `retry_task_id`),
+    KEY `idx_create_dt` (`create_dt`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='任务调度日志信息记录表'
+;
+
+CREATE TABLE `sj_retry_scene_config`
+(
+    `id`                  bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`        varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `scene_name`          varchar(64)         NOT NULL COMMENT '场景名称',
+    `group_name`          varchar(64)         NOT NULL COMMENT '组名称',
+    `scene_status`        tinyint(4)          NOT NULL DEFAULT 0 COMMENT '组状态 0、未启用 1、启用',
+    `max_retry_count`     int(11)             NOT NULL DEFAULT 5 COMMENT '最大重试次数',
+    `back_off`            tinyint(4)          NOT NULL DEFAULT 1 COMMENT '1、默认等级 2、固定间隔时间 3、CRON 表达式',
+    `trigger_interval`    varchar(16)         NOT NULL DEFAULT '' COMMENT '间隔时长',
+    `notify_ids`          varchar(128)        NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表',
+    `deadline_request`    bigint(20) unsigned NOT NULL DEFAULT 60000 COMMENT 'Deadline Request 调用链超时 单位毫秒',
+    `executor_timeout`    int(11) unsigned    NOT NULL DEFAULT 5 COMMENT '任务执行超时时间,单位秒',
+    `route_key`           tinyint(4)          NOT NULL DEFAULT 4 COMMENT '路由策略',
+    `block_strategy`      tinyint(4)          NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行',
+    `cb_status`           tinyint(4)          NOT NULL DEFAULT 0 COMMENT '回调状态 0、不开启 1、开启',
+    `cb_trigger_type`     tinyint(4)          NOT NULL DEFAULT 1 COMMENT '1、默认等级 2、固定间隔时间 3、CRON 表达式',
+    `cb_max_count`        int(11)             NOT NULL DEFAULT 16 COMMENT '回调的最大执行次数',
+    `cb_trigger_interval` varchar(16)         NOT NULL DEFAULT '' COMMENT '回调的最大执行次数',
+    `description`         varchar(256)        NOT NULL DEFAULT '' COMMENT '描述',
+    `create_dt`           datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`           datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_namespace_id_group_name_scene_name` (`namespace_id`, `group_name`, `scene_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='场景配置'
+;
+
+CREATE TABLE `sj_server_node`
+(
+    `id`           bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id` varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`   varchar(64)         NOT NULL COMMENT '组名称',
+    `host_id`      varchar(64)         NOT NULL COMMENT '主机id',
+    `host_ip`      varchar(64)         NOT NULL COMMENT '机器ip',
+    `host_port`    int(16)             NOT NULL COMMENT '机器端口',
+    `expire_at`    datetime            NOT NULL COMMENT '过期时间',
+    `node_type`    tinyint(4)          NOT NULL COMMENT '节点类型 1、客户端 2、是服务端',
+    `ext_attrs`    varchar(256)        NULL     DEFAULT '' COMMENT '扩展字段',
+    `create_dt`    datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`    datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`),
+    KEY `idx_expire_at_node_type` (`expire_at`, `node_type`),
+    UNIQUE KEY `uk_host_id_host_ip` (`host_id`, `host_ip`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='服务器节点'
+;
+
+CREATE TABLE `sj_distributed_lock`
+(
+    `name`       varchar(64)         NOT NULL COMMENT '锁名称',
+    `lock_until` timestamp(3)        NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '锁定时长',
+    `locked_at`  timestamp(3)        NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '锁定时间',
+    `locked_by`  varchar(255)        NOT NULL COMMENT '锁定者',
+    `create_dt`  datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`  datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='锁定表'
+;
+
+CREATE TABLE `sj_system_user`
+(
+    `id`        bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `username`  varchar(64)         NOT NULL COMMENT '账号',
+    `password`  varchar(128)        NOT NULL COMMENT '密码',
+    `role`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '角色:1-普通用户、2-管理员',
+    `create_dt` datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt` datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_username` (`username`) USING BTREE
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户表';
+
+CREATE TABLE `sj_system_user_permission`
+(
+    `id`             bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `group_name`     varchar(64)         NOT NULL COMMENT '组名称',
+    `namespace_id`   varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `system_user_id` bigint(20)          NOT NULL COMMENT '系统用户id',
+    `create_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_namespace_id_group_name_system_user_id` (`namespace_id`, `group_name`, `system_user_id`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='系统用户权限表';
+
+CREATE TABLE `sj_sequence_alloc`
+(
+    `id`           bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id` varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`   varchar(64)         NOT NULL DEFAULT '' COMMENT '组名称',
+    `max_id`       bigint(20)          NOT NULL DEFAULT 1 COMMENT '最大id',
+    `step`         int(11)             NOT NULL DEFAULT 100 COMMENT '步长',
+    `update_dt`    datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4 COMMENT ='号段模式序号ID分配表';
+
+-- 分布式调度DDL
+CREATE TABLE `sj_job`
+(
+    `id`               bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`     varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`       varchar(64)         NOT NULL COMMENT '组名称',
+    `job_name`         varchar(64)         NOT NULL COMMENT '名称',
+    `args_str`         text                         DEFAULT NULL COMMENT '执行方法参数',
+    `args_type`        tinyint(4)          NOT NULL DEFAULT 1 COMMENT '参数类型 ',
+    `next_trigger_at`  bigint(13)          NOT NULL COMMENT '下次触发时间',
+    `job_status`       tinyint(4)          NOT NULL DEFAULT 1 COMMENT '任务状态 0、关闭、1、开启',
+    `task_type`        tinyint(4)          NOT NULL DEFAULT 1 COMMENT '任务类型 1、集群 2、广播 3、切片',
+    `route_key`        tinyint(4)          NOT NULL DEFAULT 4 COMMENT '路由策略',
+    `executor_type`    tinyint(4)          NOT NULL DEFAULT 1 COMMENT '执行器类型',
+    `executor_info`    varchar(255)                 DEFAULT NULL COMMENT '执行器名称',
+    `trigger_type`     tinyint(4)          NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间',
+    `trigger_interval` varchar(255)        NOT NULL COMMENT '间隔时长',
+    `block_strategy`   tinyint(4)          NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行 4、恢复',
+    `executor_timeout` int(11)             NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒',
+    `max_retry_times`  int(11)             NOT NULL DEFAULT 0 COMMENT '最大重试次数',
+    `parallel_num`     int(11)             NOT NULL DEFAULT 1 COMMENT '并行数',
+    `retry_interval`   int(11)             NOT NULL DEFAULT 0 COMMENT '重试间隔(s)',
+    `bucket_index`     int(11)             NOT NULL DEFAULT 0 COMMENT 'bucket',
+    `resident`         tinyint(4)          NOT NULL DEFAULT 0 COMMENT '是否是常驻任务',
+    `notify_ids`       varchar(128)        NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表',
+    `owner_id`         bigint(20)          NULL                 COMMENT '负责人id',
+    `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '描述',
+    `ext_attrs`        varchar(256)        NULL     DEFAULT '' COMMENT '扩展字段',
+    `deleted`          tinyint(4)          NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除',
+    `create_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`),
+    KEY `idx_job_status_bucket_index` (`job_status`, `bucket_index`),
+    KEY `idx_create_dt` (`create_dt`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='任务信息';
+
+CREATE TABLE `sj_job_log_message`
+(
+    `id`            bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`  varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`    varchar(64)         NOT NULL COMMENT '组名称',
+    `job_id`        bigint(20)          NOT NULL COMMENT '任务信息id',
+    `task_batch_id` bigint(20)          NOT NULL COMMENT '任务批次id',
+    `task_id`       bigint(20)          NOT NULL COMMENT '调度任务id',
+    `message`       longtext            NOT NULL COMMENT '调度信息',
+    `log_num`       int(11)             NOT NULL DEFAULT 1 COMMENT '日志数量',
+    `real_time`     bigint(13)          NOT NULL DEFAULT 0 COMMENT '上报时间',
+    `ext_attrs`     varchar(256)        NULL     DEFAULT '' COMMENT '扩展字段',
+    `create_dt`     datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_task_batch_id_task_id` (`task_batch_id`, `task_id`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='调度日志';
+
+CREATE TABLE `sj_job_task`
+(
+    `id`             bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`   varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`     varchar(64)         NOT NULL COMMENT '组名称',
+    `job_id`         bigint(20)          NOT NULL COMMENT '任务信息id',
+    `task_batch_id`  bigint(20)          NOT NULL COMMENT '调度任务id',
+    `parent_id`      bigint(20)          NOT NULL DEFAULT 0 COMMENT '父执行器id',
+    `task_status`    tinyint             NOT NULL DEFAULT 0 COMMENT '执行的状态 0、失败 1、成功',
+    `retry_count`    int(11)             NOT NULL DEFAULT 0 COMMENT '重试次数',
+    `mr_stage`       tinyint                      DEFAULT NULL COMMENT '动态分片所处阶段 1:map 2:reduce 3:mergeReduce',
+    `leaf`           tinyint             NOT NULL DEFAULT '1' COMMENT '叶子节点',
+    `task_name`      varchar(255)        NOT NULL DEFAULT '' COMMENT '任务名称',
+    `client_info`    varchar(128)                 DEFAULT NULL COMMENT '客户端地址 clientId#ip:port',
+    `wf_context`     text                         DEFAULT NULL COMMENT '工作流全局上下文',
+    `result_message` text                NOT NULL COMMENT '执行结果',
+    `args_str`       text                         DEFAULT NULL COMMENT '执行方法参数',
+    `args_type`      tinyint             NOT NULL DEFAULT 1 COMMENT '参数类型 ',
+    `ext_attrs`      varchar(256)        NULL     DEFAULT '' COMMENT '扩展字段',
+    `create_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`      datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_task_batch_id_task_status` (`task_batch_id`, `task_status`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='任务实例';
+
+CREATE TABLE `sj_job_task_batch`
+(
+    `id`                      bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`            varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`              varchar(64)         NOT NULL COMMENT '组名称',
+    `job_id`                  bigint(20)          NOT NULL COMMENT '任务id',
+    `workflow_node_id`        bigint(20)          NOT NULL DEFAULT 0 COMMENT '工作流节点id',
+    `parent_workflow_node_id` bigint(20)          NOT NULL DEFAULT 0 COMMENT '工作流任务父批次id',
+    `workflow_task_batch_id`  bigint(20)          NOT NULL DEFAULT 0 COMMENT '工作流任务批次id',
+    `task_batch_status`       tinyint(4)          NOT NULL DEFAULT 0 COMMENT '任务批次状态 0、失败 1、成功',
+    `operation_reason`        tinyint(4)          NOT NULL DEFAULT 0 COMMENT '操作原因',
+    `execution_at`            bigint(13)          NOT NULL DEFAULT 0 COMMENT '任务执行时间',
+    `system_task_type`        tinyint(4)          NOT NULL DEFAULT 3 COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务',
+    `parent_id`               varchar(64)         NOT NULL DEFAULT '' COMMENT '父节点',
+    `ext_attrs`               varchar(256)        NULL     DEFAULT '' COMMENT '扩展字段',
+    `deleted`                 tinyint(4)          NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除',
+    `create_dt`               datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`               datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_job_id_task_batch_status` (`job_id`, `task_batch_status`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`),
+    KEY `idx_workflow_task_batch_id_workflow_node_id` (`workflow_task_batch_id`, `workflow_node_id`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='任务批次';
+
+CREATE TABLE `sj_job_summary`
+(
+    `id`               bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`     VARCHAR(64)     NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`       VARCHAR(64)     NOT NULL DEFAULT '' COMMENT '组名称',
+    `business_id`      bigint          NOT NULL COMMENT '业务id (job_id或workflow_id)',
+    `system_task_type` tinyint(4)      NOT NULL DEFAULT 3 COMMENT '任务类型 3、JOB任务 4、WORKFLOW任务',
+    `trigger_at`       datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间',
+    `success_num`      int             NOT NULL DEFAULT 0 COMMENT '执行成功-日志数量',
+    `fail_num`         int             NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量',
+    `fail_reason`      varchar(512)    NOT NULL DEFAULT '' COMMENT '失败原因',
+    `stop_num`         int             NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量',
+    `stop_reason`      varchar(512)    NOT NULL DEFAULT '' COMMENT '失败原因',
+    `cancel_num`       int             NOT NULL DEFAULT 0 COMMENT '执行失败-日志数量',
+    `cancel_reason`    varchar(512)    NOT NULL DEFAULT '' COMMENT '失败原因',
+    `create_dt`        datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`        datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_namespace_id_group_name_business_id` (`namespace_id`, `group_name`, business_id),
+    UNIQUE KEY `uk_trigger_at_system_task_type_business_id` (`trigger_at`, `system_task_type`, `business_id`) USING BTREE
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Job';
+
+CREATE TABLE `sj_retry_summary`
+(
+    `id`            bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`  VARCHAR(64)     NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`    VARCHAR(64)     NOT NULL DEFAULT '' COMMENT '组名称',
+    `scene_name`    VARCHAR(50)     NOT NULL DEFAULT '' COMMENT '场景名称',
+    `trigger_at`    datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '统计时间',
+    `running_num`   int             NOT NULL DEFAULT 0 COMMENT '重试中-日志数量',
+    `finish_num`    int             NOT NULL DEFAULT 0 COMMENT '重试完成-日志数量',
+    `max_count_num` int             NOT NULL DEFAULT 0 COMMENT '重试到达最大次数-日志数量',
+    `suspend_num`   int             NOT NULL DEFAULT 0 COMMENT '暂停重试-日志数量',
+    `create_dt`     datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`     datetime        NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_trigger_at` (`trigger_at`),
+    UNIQUE KEY `uk_scene_name_trigger_at` (`namespace_id`, `group_name`, `scene_name`, `trigger_at`) USING BTREE
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8mb4 COMMENT ='DashBoard_Retry';
+
+CREATE TABLE `sj_workflow`
+(
+    `id`               bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `workflow_name`    varchar(64)         NOT NULL COMMENT '工作流名称',
+    `namespace_id`     varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`       varchar(64)         NOT NULL COMMENT '组名称',
+    `workflow_status`  tinyint(4)          NOT NULL DEFAULT 1 COMMENT '工作流状态 0、关闭、1、开启',
+    `trigger_type`     tinyint(4)          NOT NULL COMMENT '触发类型 1.CRON 表达式 2. 固定时间',
+    `trigger_interval` varchar(255)        NOT NULL COMMENT '间隔时长',
+    `next_trigger_at`  bigint              NOT NULL COMMENT '下次触发时间',
+    `block_strategy`   tinyint(4)          NOT NULL DEFAULT 1 COMMENT '阻塞策略 1、丢弃 2、覆盖 3、并行',
+    `executor_timeout` int(11)             NOT NULL DEFAULT 0 COMMENT '任务执行超时时间,单位秒',
+    `description`      varchar(256)        NOT NULL DEFAULT '' COMMENT '描述',
+    `flow_info`        text                         DEFAULT NULL COMMENT '流程信息',
+    `wf_context`       text                         DEFAULT NULL COMMENT '上下文',
+    `notify_ids`       varchar(128)        NOT NULL DEFAULT '' COMMENT '通知告警场景配置id列表',
+    `bucket_index`     int(11)             NOT NULL DEFAULT 0 COMMENT 'bucket',
+    `version`          int(11)             NOT NULL COMMENT '版本号',
+    `ext_attrs`        varchar(256)        NULL     DEFAULT '' COMMENT '扩展字段',
+    `deleted`          tinyint(4)          NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除',
+    `create_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`        datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='工作流';
+
+CREATE TABLE `sj_workflow_node`
+(
+    `id`                   bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`         varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `node_name`            varchar(64)         NOT NULL COMMENT '节点名称',
+    `group_name`           varchar(64)         NOT NULL COMMENT '组名称',
+    `job_id`               bigint(20)          NOT NULL COMMENT '任务信息id',
+    `workflow_id`          bigint(20)          NOT NULL COMMENT '工作流ID',
+    `node_type`            tinyint(4)          NOT NULL DEFAULT 1 COMMENT '1、任务节点 2、条件节点',
+    `expression_type`      tinyint(4)          NOT NULL DEFAULT 0 COMMENT '1、SpEl、2、Aviator 3、QL',
+    `fail_strategy`        tinyint(4)          NOT NULL DEFAULT 1 COMMENT '失败策略 1、跳过 2、阻塞',
+    `workflow_node_status` tinyint(4)          NOT NULL DEFAULT 1 COMMENT '工作流节点状态 0、关闭、1、开启',
+    `priority_level`       int(11)             NOT NULL DEFAULT 1 COMMENT '优先级',
+    `node_info`            text                         DEFAULT NULL COMMENT '节点信息 ',
+    `version`              int(11)             NOT NULL COMMENT '版本号',
+    `ext_attrs`            varchar(256)        NULL     DEFAULT '' COMMENT '扩展字段',
+    `deleted`              tinyint(4)          NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除',
+    `create_dt`            datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`            datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='工作流节点';
+
+CREATE TABLE `sj_workflow_task_batch`
+(
+    `id`                bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
+    `namespace_id`      varchar(64)         NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
+    `group_name`        varchar(64)         NOT NULL COMMENT '组名称',
+    `workflow_id`       bigint(20)          NOT NULL COMMENT '工作流任务id',
+    `task_batch_status` tinyint(4)          NOT NULL DEFAULT 0 COMMENT '任务批次状态 0、失败 1、成功',
+    `operation_reason`  tinyint(4)          NOT NULL DEFAULT 0 COMMENT '操作原因',
+    `flow_info`         text                         DEFAULT NULL COMMENT '流程信息',
+    `wf_context`        text                         DEFAULT NULL COMMENT '全局上下文',
+    `execution_at`      bigint(13)          NOT NULL DEFAULT 0 COMMENT '任务执行时间',
+    `ext_attrs`         varchar(256)        NULL     DEFAULT '' COMMENT '扩展字段',
+    `version`           int(11)              NOT NULL DEFAULT 1 COMMENT '版本号',
+    `deleted`           tinyint(4)          NOT NULL DEFAULT 0 COMMENT '逻辑删除 1、删除',
+    `create_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_dt`         datetime            NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_job_id_task_batch_status` (`workflow_id`, `task_batch_status`),
+    KEY `idx_create_dt` (`create_dt`),
+    KEY `idx_namespace_id_group_name` (`namespace_id`, `group_name`)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 0
+  DEFAULT CHARSET = utf8mb4 COMMENT ='工作流批次';

+ 14 - 0
pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/postgresql/snail-job_data.sql

@@ -0,0 +1,14 @@
+-- liquibase formatted sql
+
+-- changeset snail-job-server:1.1.0
+-- 默认命名空间:Default
+INSERT INTO sj_namespace (id, name, unique_id, create_dt, update_dt, deleted)
+VALUES (1, 'Default', '764d604ec6fc45f68cd92514c40e9e1a', NOW(), NOW(), 0);
+
+-- 默认用户:admin/admin
+INSERT INTO sj_system_user (username, password, role)
+VALUES ('admin', '465c194afb65670f38322df087f0a9bb225cc257e43eb4ac5a0c98ef5b3173ac', 2);
+
+-- 默认分组:continew-admin
+INSERT INTO sj_group_config (id, namespace_id, group_name, description, token, group_status, version, group_partition, id_generator_mode, init_scene, create_dt, update_dt)
+VALUES (1, '764d604ec6fc45f68cd92514c40e9e1a', 'continew-admin', '默认分组', 'SJ_Wyz3dmsdbDOkDujOTSSoBjGQP1BMsVnj', 1, 1, 0, 2, 1, NOW(), NOW());

+ 831 - 0
pavis-extension/pavis-extension-schedule-server/src/main/resources/db/changelog/postgresql/snail-job_table.sql

@@ -0,0 +1,831 @@
+-- liquibase formatted sql
+
+-- changeset snail-job-server:1.1.0
+-- sj_namespace
+CREATE TABLE sj_namespace
+(
+    id          bigserial PRIMARY KEY,
+    name        varchar(64)  NOT NULL,
+    unique_id   varchar(64)  NOT NULL,
+    description varchar(256) NOT NULL DEFAULT '',
+    deleted     smallint     NOT NULL DEFAULT 0,
+    create_dt   timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt   timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_namespace_01 ON sj_namespace (name);
+
+COMMENT ON COLUMN sj_namespace.id IS '主键';
+COMMENT ON COLUMN sj_namespace.name IS '名称';
+COMMENT ON COLUMN sj_namespace.unique_id IS '唯一id';
+COMMENT ON COLUMN sj_namespace.description IS '描述';
+COMMENT ON COLUMN sj_namespace.deleted IS '逻辑删除 1、删除';
+COMMENT ON COLUMN sj_namespace.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_namespace.update_dt IS '修改时间';
+COMMENT ON TABLE sj_namespace IS '命名空间';
+
+-- sj_group_config
+CREATE TABLE sj_group_config
+(
+    id                bigserial PRIMARY KEY,
+    namespace_id      varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name        varchar(64)  NOT NULL DEFAULT '',
+    description       varchar(256) NOT NULL DEFAULT '',
+    token             varchar(64)  NOT NULL DEFAULT 'SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT',
+    group_status      smallint     NOT NULL DEFAULT 0,
+    version           int          NOT NULL,
+    group_partition   int          NOT NULL,
+    id_generator_mode smallint     NOT NULL DEFAULT 1,
+    init_scene        smallint     NOT NULL DEFAULT 0,
+    create_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_group_config_01 ON sj_group_config (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_group_config.id IS '主键';
+COMMENT ON COLUMN sj_group_config.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_group_config.group_name IS '组名称';
+COMMENT ON COLUMN sj_group_config.description IS '组描述';
+COMMENT ON COLUMN sj_group_config.token IS 'token';
+COMMENT ON COLUMN sj_group_config.group_status IS '组状态 0、未启用 1、启用';
+COMMENT ON COLUMN sj_group_config.version IS '版本号';
+COMMENT ON COLUMN sj_group_config.group_partition IS '分区';
+COMMENT ON COLUMN sj_group_config.id_generator_mode IS '唯一id生成模式 默认号段模式';
+COMMENT ON COLUMN sj_group_config.init_scene IS '是否初始化场景 0:否 1:是';
+COMMENT ON COLUMN sj_group_config.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_group_config.update_dt IS '修改时间';
+COMMENT ON TABLE sj_group_config IS '组配置';
+
+-- sj_notify_config
+CREATE TABLE sj_notify_config
+(
+    id                     bigserial PRIMARY KEY,
+    namespace_id           varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name             varchar(64)  NOT NULL,
+    notify_name            varchar(64)  NOT NULL DEFAULT '',
+    system_task_type       smallint     NOT NULL DEFAULT 3,
+    notify_status          smallint     NOT NULL DEFAULT 0,
+    recipient_ids          varchar(128) NOT NULL,
+    notify_threshold       int          NOT NULL DEFAULT 0,
+    notify_scene           smallint     NOT NULL DEFAULT 0,
+    rate_limiter_status    smallint     NOT NULL DEFAULT 0,
+    rate_limiter_threshold int          NOT NULL DEFAULT 0,
+    description            varchar(256) NOT NULL DEFAULT '',
+    create_dt              timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt              timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_notify_config_01 ON sj_notify_config (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_notify_config.id IS '主键';
+COMMENT ON COLUMN sj_notify_config.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_notify_config.group_name IS '组名称';
+COMMENT ON COLUMN sj_notify_config.notify_name IS '通知名称';
+COMMENT ON COLUMN sj_notify_config.system_task_type IS '任务类型 1. 重试任务 2. 重试回调 3、JOB任务 4、WORKFLOW任务';
+COMMENT ON COLUMN sj_notify_config.notify_status IS '通知状态 0、未启用 1、启用';
+COMMENT ON COLUMN sj_notify_config.recipient_ids IS '接收人id列表';
+COMMENT ON COLUMN sj_notify_config.notify_threshold IS '通知阈值';
+COMMENT ON COLUMN sj_notify_config.notify_scene IS '通知场景';
+COMMENT ON COLUMN sj_notify_config.rate_limiter_status IS '限流状态 0、未启用 1、启用';
+COMMENT ON COLUMN sj_notify_config.rate_limiter_threshold IS '每秒限流阈值';
+COMMENT ON COLUMN sj_notify_config.description IS '描述';
+COMMENT ON COLUMN sj_notify_config.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_notify_config.update_dt IS '修改时间';
+COMMENT ON TABLE sj_notify_config IS '通知配置';
+
+-- sj_notify_recipient
+CREATE TABLE sj_notify_recipient
+(
+    id               bigserial PRIMARY KEY,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    recipient_name   varchar(64)  NOT NULL,
+    notify_type      smallint     NOT NULL DEFAULT 0,
+    notify_attribute varchar(512) NOT NULL,
+    description      varchar(256) NOT NULL DEFAULT '',
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_notify_recipient_01 ON sj_notify_recipient (namespace_id);
+
+COMMENT ON COLUMN sj_notify_recipient.id IS '主键';
+COMMENT ON COLUMN sj_notify_recipient.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_notify_recipient.recipient_name IS '接收人名称';
+COMMENT ON COLUMN sj_notify_recipient.notify_type IS '通知类型 1、钉钉 2、邮件 3、企业微信 4 飞书 5 webhook';
+COMMENT ON COLUMN sj_notify_recipient.notify_attribute IS '配置属性';
+COMMENT ON COLUMN sj_notify_recipient.description IS '描述';
+COMMENT ON COLUMN sj_notify_recipient.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_notify_recipient.update_dt IS '修改时间';
+COMMENT ON TABLE sj_notify_recipient IS '告警通知接收人';
+
+-- sj_retry_dead_letter
+CREATE TABLE sj_retry_dead_letter
+(
+    id            bigserial PRIMARY KEY,
+    namespace_id  varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name    varchar(64)  NOT NULL,
+    scene_name    varchar(64)  NOT NULL,
+    idempotent_id varchar(64)  NOT NULL,
+    biz_no        varchar(64)  NOT NULL DEFAULT '',
+    executor_name varchar(512) NOT NULL DEFAULT '',
+    args_str      text         NOT NULL,
+    ext_attrs     text         NOT NULL,
+    create_dt     timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_retry_dead_letter_01 ON sj_retry_dead_letter (namespace_id, group_name, scene_name);
+CREATE INDEX idx_sj_retry_dead_letter_02 ON sj_retry_dead_letter (idempotent_id);
+CREATE INDEX idx_sj_retry_dead_letter_03 ON sj_retry_dead_letter (biz_no);
+CREATE INDEX idx_sj_retry_dead_letter_04 ON sj_retry_dead_letter (create_dt);
+
+COMMENT ON COLUMN sj_retry_dead_letter.id IS '主键';
+COMMENT ON COLUMN sj_retry_dead_letter.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_retry_dead_letter.group_name IS '组名称';
+COMMENT ON COLUMN sj_retry_dead_letter.scene_name IS '场景名称';
+COMMENT ON COLUMN sj_retry_dead_letter.idempotent_id IS '幂等id';
+COMMENT ON COLUMN sj_retry_dead_letter.biz_no IS '业务编号';
+COMMENT ON COLUMN sj_retry_dead_letter.executor_name IS '执行器名称';
+COMMENT ON COLUMN sj_retry_dead_letter.args_str IS '执行方法参数';
+COMMENT ON COLUMN sj_retry_dead_letter.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_retry_dead_letter.create_dt IS '创建时间';
+COMMENT ON TABLE sj_retry_dead_letter IS '死信队列表';
+
+-- sj_retry
+CREATE TABLE sj_retry
+(
+    id              bigserial PRIMARY KEY,
+    namespace_id    varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name      varchar(64)  NOT NULL,
+    scene_name      varchar(64)  NOT NULL,
+    idempotent_id   varchar(64)  NOT NULL,
+    biz_no          varchar(64)  NOT NULL DEFAULT '',
+    executor_name   varchar(512) NOT NULL DEFAULT '',
+    args_str        text         NOT NULL,
+    ext_attrs       text         NOT NULL,
+    next_trigger_at bigint       NOT NULL,
+    retry_count     int          NOT NULL DEFAULT 0,
+    retry_status    smallint     NOT NULL DEFAULT 0,
+    task_type       smallint     NOT NULL DEFAULT 1,
+    bucket_index    int          NOT NULL DEFAULT 0,
+    parent_id       bigint       NOT NULL DEFAULT 0,
+    deleted         bigint       NOT NULL DEFAULT 0,
+    create_dt       timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt       timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_retry_01 ON sj_retry (namespace_id, group_name, task_type, idempotent_id, deleted);
+
+CREATE INDEX idx_sj_retry_01 ON sj_retry (namespace_id, group_name, scene_name);
+CREATE INDEX idx_sj_retry_02 ON sj_retry (namespace_id, group_name, retry_status);
+CREATE INDEX idx_sj_retry_03 ON sj_retry (idempotent_id);
+CREATE INDEX idx_sj_retry_04 ON sj_retry (biz_no);
+CREATE INDEX idx_sj_retry_05 ON sj_retry (parent_id);
+CREATE INDEX idx_sj_retry_06 ON sj_retry (create_dt);
+
+COMMENT ON COLUMN sj_retry.id IS '主键';
+COMMENT ON COLUMN sj_retry.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_retry.group_name IS '组名称';
+COMMENT ON COLUMN sj_retry.scene_name IS '场景名称';
+COMMENT ON COLUMN sj_retry.idempotent_id IS '幂等id';
+COMMENT ON COLUMN sj_retry.biz_no IS '业务编号';
+COMMENT ON COLUMN sj_retry.executor_name IS '执行器名称';
+COMMENT ON COLUMN sj_retry.args_str IS '执行方法参数';
+COMMENT ON COLUMN sj_retry.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_retry.next_trigger_at IS '下次触发时间';
+COMMENT ON COLUMN sj_retry.retry_count IS '重试次数';
+COMMENT ON COLUMN sj_retry.retry_status IS '重试状态 0、重试中 1、成功 2、最大重试次数';
+COMMENT ON COLUMN sj_retry.task_type IS '任务类型 1、重试数据 2、回调数据';
+COMMENT ON COLUMN sj_retry.bucket_index IS 'bucket';
+COMMENT ON COLUMN sj_retry.parent_id IS '父节点id';
+COMMENT ON COLUMN sj_retry.deleted IS '逻辑删除';
+COMMENT ON COLUMN sj_retry.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_retry.update_dt IS '修改时间';
+COMMENT ON TABLE sj_retry IS '重试信息表';
+
+-- sj_retry_task
+CREATE TABLE sj_retry_task
+(
+    id               bigserial PRIMARY KEY,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       varchar(64)  NOT NULL,
+    scene_name       varchar(64)  NOT NULL,
+    retry_id         bigint       NOT NULL,
+    ext_attrs        text         NOT NULL,
+    task_status      smallint     NOT NULL DEFAULT 1,
+    task_type        smallint     NOT NULL DEFAULT 1,
+    operation_reason smallint     NOT NULL DEFAULT 0,
+    client_info      varchar(128) NULL     DEFAULT NULL,
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_retry_task_01 ON sj_retry_task (namespace_id, group_name, scene_name);
+CREATE INDEX idx_sj_retry_task_02 ON sj_retry_task (task_status);
+CREATE INDEX idx_sj_retry_task_03 ON sj_retry_task (create_dt);
+CREATE INDEX idx_sj_retry_task_04 ON sj_retry_task (retry_id);
+
+COMMENT ON COLUMN sj_retry_task.id IS '主键';
+COMMENT ON COLUMN sj_retry_task.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_retry_task.group_name IS '组名称';
+COMMENT ON COLUMN sj_retry_task.scene_name IS '场景名称';
+COMMENT ON COLUMN sj_retry_task.retry_id IS '重试信息Id';
+COMMENT ON COLUMN sj_retry_task.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_retry_task.task_status IS '重试状态';
+COMMENT ON COLUMN sj_retry_task.task_type IS '任务类型 1、重试数据 2、回调数据';
+COMMENT ON COLUMN sj_retry_task.operation_reason IS '操作原因';
+COMMENT ON COLUMN sj_retry_task.client_info IS '客户端地址 clientId#ip:port';
+COMMENT ON COLUMN sj_retry_task.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_retry_task.update_dt IS '修改时间';
+COMMENT ON TABLE sj_retry_task IS '重试任务表';
+
+-- sj_retry_task_log_message
+CREATE TABLE sj_retry_task_log_message
+(
+    id            bigserial PRIMARY KEY,
+    namespace_id  varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name    varchar(64) NOT NULL,
+    retry_id      bigint      NOT NULL,
+    retry_task_id bigint      NOT NULL,
+    message       text        NOT NULL,
+    log_num       int         NOT NULL DEFAULT 1,
+    real_time     bigint      NOT NULL DEFAULT 0,
+    create_dt     timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_retry_task_log_message_01 ON sj_retry_task_log_message (namespace_id, group_name, retry_task_id);
+CREATE INDEX idx_sj_retry_task_log_message_02 ON sj_retry_task_log_message (create_dt);
+
+COMMENT ON COLUMN sj_retry_task_log_message.id IS '主键';
+COMMENT ON COLUMN sj_retry_task_log_message.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_retry_task_log_message.group_name IS '组名称';
+COMMENT ON COLUMN sj_retry_task_log_message.retry_id IS '重试信息Id';
+COMMENT ON COLUMN sj_retry_task_log_message.retry_task_id IS '重试任务Id';
+COMMENT ON COLUMN sj_retry_task_log_message.message IS '异常信息';
+COMMENT ON COLUMN sj_retry_task_log_message.log_num IS '日志数量';
+COMMENT ON COLUMN sj_retry_task_log_message.real_time IS '上报时间';
+COMMENT ON COLUMN sj_retry_task_log_message.create_dt IS '创建时间';
+COMMENT ON TABLE sj_retry_task_log_message IS '任务调度日志信息记录表';
+
+-- sj_retry_scene_config
+CREATE TABLE sj_retry_scene_config
+(
+    id                  bigserial PRIMARY KEY,
+    namespace_id        varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    scene_name          varchar(64)  NOT NULL,
+    group_name          varchar(64)  NOT NULL,
+    scene_status        smallint     NOT NULL DEFAULT 0,
+    max_retry_count     int          NOT NULL DEFAULT 5,
+    back_off            smallint     NOT NULL DEFAULT 1,
+    trigger_interval    varchar(16)  NOT NULL DEFAULT '',
+    notify_ids          varchar(128) NOT NULL DEFAULT '',
+    deadline_request    bigint       NOT NULL DEFAULT 60000,
+    executor_timeout    int          NOT NULL DEFAULT 5,
+    route_key           smallint     NOT NULL DEFAULT 4,
+    block_strategy      smallint     NOT NULL DEFAULT 1,
+    cb_status           smallint     NOT NULL DEFAULT 0,
+    cb_trigger_type     smallint     NOT NULL DEFAULT 1,
+    cb_max_count        int          NOT NULL DEFAULT 16,
+    cb_trigger_interval varchar(16)  NOT NULL DEFAULT '',
+    description         varchar(256) NOT NULL DEFAULT '',
+    create_dt           timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt           timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_retry_scene_config_01 ON sj_retry_scene_config (namespace_id, group_name, scene_name);
+
+COMMENT ON COLUMN sj_retry_scene_config.id IS '主键';
+COMMENT ON COLUMN sj_retry_scene_config.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_retry_scene_config.scene_name IS '场景名称';
+COMMENT ON COLUMN sj_retry_scene_config.group_name IS '组名称';
+COMMENT ON COLUMN sj_retry_scene_config.scene_status IS '组状态 0、未启用 1、启用';
+COMMENT ON COLUMN sj_retry_scene_config.max_retry_count IS '最大重试次数';
+COMMENT ON COLUMN sj_retry_scene_config.back_off IS '1、默认等级 2、固定间隔时间 3、CRON 表达式';
+COMMENT ON COLUMN sj_retry_scene_config.trigger_interval IS '间隔时长';
+COMMENT ON COLUMN sj_retry_scene_config.notify_ids IS '通知告警场景配置id列表';
+COMMENT ON COLUMN sj_retry_scene_config.deadline_request IS 'Deadline Request 调用链超时 单位毫秒';
+COMMENT ON COLUMN sj_retry_scene_config.executor_timeout IS '任务执行超时时间,单位秒';
+COMMENT ON COLUMN sj_retry_scene_config.route_key IS '路由策略';
+COMMENT ON COLUMN sj_retry_scene_config.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行';
+COMMENT ON COLUMN sj_retry_scene_config.cb_status IS '回调状态 0、不开启 1、开启';
+COMMENT ON COLUMN sj_retry_scene_config.cb_trigger_type IS '1、默认等级 2、固定间隔时间 3、CRON 表达式';
+COMMENT ON COLUMN sj_retry_scene_config.cb_max_count IS '回调的最大执行次数';
+COMMENT ON COLUMN sj_retry_scene_config.cb_trigger_interval IS '回调的最大执行次数';
+COMMENT ON COLUMN sj_retry_scene_config.description IS '描述';
+COMMENT ON COLUMN sj_retry_scene_config.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_retry_scene_config.update_dt IS '修改时间';
+COMMENT ON TABLE sj_retry_scene_config IS '场景配置';
+
+-- sj_server_node
+CREATE TABLE sj_server_node
+(
+    id           bigserial PRIMARY KEY,
+    namespace_id varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name   varchar(64)  NOT NULL,
+    host_id      varchar(64)  NOT NULL,
+    host_ip      varchar(64)  NOT NULL,
+    host_port    int          NOT NULL,
+    expire_at    timestamp    NOT NULL,
+    node_type    smallint     NOT NULL,
+    ext_attrs    varchar(256) NULL     DEFAULT '',
+    create_dt    timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt    timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_server_node_01 ON sj_server_node (host_id, host_ip);
+
+CREATE INDEX idx_sj_server_node_01 ON sj_server_node (namespace_id, group_name);
+CREATE INDEX idx_sj_server_node_02 ON sj_server_node (expire_at, node_type);
+
+COMMENT ON COLUMN sj_server_node.id IS '主键';
+COMMENT ON COLUMN sj_server_node.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_server_node.group_name IS '组名称';
+COMMENT ON COLUMN sj_server_node.host_id IS '主机id';
+COMMENT ON COLUMN sj_server_node.host_ip IS '机器ip';
+COMMENT ON COLUMN sj_server_node.host_port IS '机器端口';
+COMMENT ON COLUMN sj_server_node.expire_at IS '过期时间';
+COMMENT ON COLUMN sj_server_node.node_type IS '节点类型 1、客户端 2、是服务端';
+COMMENT ON COLUMN sj_server_node.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_server_node.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_server_node.update_dt IS '修改时间';
+COMMENT ON TABLE sj_server_node IS '服务器节点';
+
+-- sj_distributed_lock
+CREATE TABLE sj_distributed_lock
+(
+    name       varchar(64)  NOT NULL,
+    lock_until timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+    locked_at  timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
+    locked_by  varchar(255) NOT NULL,
+    create_dt  timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt  timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+COMMENT ON COLUMN sj_distributed_lock.name IS '锁名称';
+COMMENT ON COLUMN sj_distributed_lock.lock_until IS '锁定时长';
+COMMENT ON COLUMN sj_distributed_lock.locked_at IS '锁定时间';
+COMMENT ON COLUMN sj_distributed_lock.locked_by IS '锁定者';
+COMMENT ON COLUMN sj_distributed_lock.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_distributed_lock.update_dt IS '修改时间';
+COMMENT ON TABLE sj_distributed_lock IS '锁定表';
+
+-- sj_system_user
+CREATE TABLE sj_system_user
+(
+    id        bigserial PRIMARY KEY,
+    username  varchar(64)  NOT NULL,
+    password  varchar(128) NOT NULL,
+    role      smallint     NOT NULL DEFAULT 0,
+    create_dt timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+COMMENT ON COLUMN sj_system_user.id IS '主键';
+COMMENT ON COLUMN sj_system_user.username IS '账号';
+COMMENT ON COLUMN sj_system_user.password IS '密码';
+COMMENT ON COLUMN sj_system_user.role IS '角色:1-普通用户、2-管理员';
+COMMENT ON COLUMN sj_system_user.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_system_user.update_dt IS '修改时间';
+COMMENT ON TABLE sj_system_user IS '系统用户表';
+
+-- sj_system_user_permission
+CREATE TABLE sj_system_user_permission
+(
+    id             bigserial PRIMARY KEY,
+    group_name     varchar(64) NOT NULL,
+    namespace_id   varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    system_user_id bigint      NOT NULL,
+    create_dt      timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt      timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_system_user_permission_01 ON sj_system_user_permission (namespace_id, group_name, system_user_id);
+
+COMMENT ON COLUMN sj_system_user_permission.id IS '主键';
+COMMENT ON COLUMN sj_system_user_permission.group_name IS '组名称';
+COMMENT ON COLUMN sj_system_user_permission.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_system_user_permission.system_user_id IS '系统用户id';
+COMMENT ON COLUMN sj_system_user_permission.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_system_user_permission.update_dt IS '修改时间';
+COMMENT ON TABLE sj_system_user_permission IS '系统用户权限表';
+
+-- sj_sequence_alloc
+CREATE TABLE sj_sequence_alloc
+(
+    id           bigserial PRIMARY KEY,
+    namespace_id varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name   varchar(64) NOT NULL DEFAULT '',
+    max_id       bigint      NOT NULL DEFAULT 1,
+    step         int         NOT NULL DEFAULT 100,
+    update_dt    timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_sequence_alloc_01 ON sj_sequence_alloc (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_sequence_alloc.id IS '主键';
+COMMENT ON COLUMN sj_sequence_alloc.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_sequence_alloc.group_name IS '组名称';
+COMMENT ON COLUMN sj_sequence_alloc.max_id IS '最大id';
+COMMENT ON COLUMN sj_sequence_alloc.step IS '步长';
+COMMENT ON COLUMN sj_sequence_alloc.update_dt IS '更新时间';
+COMMENT ON TABLE sj_sequence_alloc IS '号段模式序号ID分配表';
+
+-- sj_job
+CREATE TABLE sj_job
+(
+    id               bigserial PRIMARY KEY,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       varchar(64)  NOT NULL,
+    job_name         varchar(64)  NOT NULL,
+    args_str         text         NULL     DEFAULT NULL,
+    args_type        smallint     NOT NULL DEFAULT 1,
+    next_trigger_at  bigint       NOT NULL,
+    job_status       smallint     NOT NULL DEFAULT 1,
+    task_type        smallint     NOT NULL DEFAULT 1,
+    route_key        smallint     NOT NULL DEFAULT 4,
+    executor_type    smallint     NOT NULL DEFAULT 1,
+    executor_info    varchar(255) NULL     DEFAULT NULL,
+    trigger_type     smallint     NOT NULL,
+    trigger_interval varchar(255) NOT NULL,
+    block_strategy   smallint     NOT NULL DEFAULT 1,
+    executor_timeout int          NOT NULL DEFAULT 0,
+    max_retry_times  int          NOT NULL DEFAULT 0,
+    parallel_num     int          NOT NULL DEFAULT 1,
+    retry_interval   int          NOT NULL DEFAULT 0,
+    bucket_index     int          NOT NULL DEFAULT 0,
+    resident         smallint     NOT NULL DEFAULT 0,
+    notify_ids       varchar(128) NOT NULL DEFAULT '',
+    owner_id         bigint       NULL,
+    description      varchar(256) NOT NULL DEFAULT '',
+    ext_attrs        varchar(256) NULL     DEFAULT '',
+    deleted          smallint     NOT NULL DEFAULT 0,
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_job_01 ON sj_job (namespace_id, group_name);
+CREATE INDEX idx_sj_job_02 ON sj_job (job_status, bucket_index);
+CREATE INDEX idx_sj_job_03 ON sj_job (create_dt);
+
+COMMENT ON COLUMN sj_job.id IS '主键';
+COMMENT ON COLUMN sj_job.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_job.group_name IS '组名称';
+COMMENT ON COLUMN sj_job.job_name IS '名称';
+COMMENT ON COLUMN sj_job.args_str IS '执行方法参数';
+COMMENT ON COLUMN sj_job.args_type IS '参数类型 ';
+COMMENT ON COLUMN sj_job.next_trigger_at IS '下次触发时间';
+COMMENT ON COLUMN sj_job.job_status IS '任务状态 0、关闭、1、开启';
+COMMENT ON COLUMN sj_job.task_type IS '任务类型 1、集群 2、广播 3、切片';
+COMMENT ON COLUMN sj_job.route_key IS '路由策略';
+COMMENT ON COLUMN sj_job.executor_type IS '执行器类型';
+COMMENT ON COLUMN sj_job.executor_info IS '执行器名称';
+COMMENT ON COLUMN sj_job.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间';
+COMMENT ON COLUMN sj_job.trigger_interval IS '间隔时长';
+COMMENT ON COLUMN sj_job.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行 4、恢复';
+COMMENT ON COLUMN sj_job.executor_timeout IS '任务执行超时时间,单位秒';
+COMMENT ON COLUMN sj_job.max_retry_times IS '最大重试次数';
+COMMENT ON COLUMN sj_job.parallel_num IS '并行数';
+COMMENT ON COLUMN sj_job.retry_interval IS '重试间隔 ( s)';
+COMMENT ON COLUMN sj_job.bucket_index IS 'bucket';
+COMMENT ON COLUMN sj_job.resident IS '是否是常驻任务';
+COMMENT ON COLUMN sj_job.notify_ids IS '通知告警场景配置id列表';
+COMMENT ON COLUMN sj_job.owner_id IS '负责人id';
+COMMENT ON COLUMN sj_job.description IS '描述';
+COMMENT ON COLUMN sj_job.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_job.deleted IS '逻辑删除 1、删除';
+COMMENT ON COLUMN sj_job.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_job.update_dt IS '修改时间';
+COMMENT ON TABLE sj_job IS '任务信息';
+
+-- sj_job_log_message
+CREATE TABLE sj_job_log_message
+(
+    id            bigserial PRIMARY KEY,
+    namespace_id  varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name    varchar(64)  NOT NULL,
+    job_id        bigint       NOT NULL,
+    task_batch_id bigint       NOT NULL,
+    task_id       bigint       NOT NULL,
+    message       text         NOT NULL,
+    log_num       int          NOT NULL DEFAULT 1,
+    real_time     bigint       NOT NULL DEFAULT 0,
+    ext_attrs     varchar(256) NULL     DEFAULT '',
+    create_dt     timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_job_log_message_01 ON sj_job_log_message (task_batch_id, task_id);
+CREATE INDEX idx_sj_job_log_message_02 ON sj_job_log_message (create_dt);
+CREATE INDEX idx_sj_job_log_message_03 ON sj_job_log_message (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_job_log_message.id IS '主键';
+COMMENT ON COLUMN sj_job_log_message.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_job_log_message.group_name IS '组名称';
+COMMENT ON COLUMN sj_job_log_message.job_id IS '任务信息id';
+COMMENT ON COLUMN sj_job_log_message.task_batch_id IS '任务批次id';
+COMMENT ON COLUMN sj_job_log_message.task_id IS '调度任务id';
+COMMENT ON COLUMN sj_job_log_message.message IS '调度信息';
+COMMENT ON COLUMN sj_job_log_message.log_num IS '日志数量';
+COMMENT ON COLUMN sj_job_log_message.real_time IS '上报时间';
+COMMENT ON COLUMN sj_job_log_message.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_job_log_message.create_dt IS '创建时间';
+COMMENT ON TABLE sj_job_log_message IS '调度日志';
+
+-- sj_job_task
+CREATE TABLE sj_job_task
+(
+    id             bigserial PRIMARY KEY,
+    namespace_id   varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name     varchar(64)  NOT NULL,
+    job_id         bigint       NOT NULL,
+    task_batch_id  bigint       NOT NULL,
+    parent_id      bigint       NOT NULL DEFAULT 0,
+    task_status    smallint     NOT NULL DEFAULT 0,
+    retry_count    int          NOT NULL DEFAULT 0,
+    mr_stage       smallint     NULL     DEFAULT NULL,
+    leaf           smallint     NOT NULL DEFAULT '1',
+    task_name      varchar(255) NOT NULL DEFAULT '',
+    client_info    varchar(128) NULL     DEFAULT NULL,
+    wf_context     text         NULL     DEFAULT NULL,
+    result_message text         NOT NULL,
+    args_str       text         NULL     DEFAULT NULL,
+    args_type      smallint     NOT NULL DEFAULT 1,
+    ext_attrs      varchar(256) NULL     DEFAULT '',
+    create_dt      timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt      timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_job_task_01 ON sj_job_task (task_batch_id, task_status);
+CREATE INDEX idx_sj_job_task_02 ON sj_job_task (create_dt);
+CREATE INDEX idx_sj_job_task_03 ON sj_job_task (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_job_task.id IS '主键';
+COMMENT ON COLUMN sj_job_task.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_job_task.group_name IS '组名称';
+COMMENT ON COLUMN sj_job_task.job_id IS '任务信息id';
+COMMENT ON COLUMN sj_job_task.task_batch_id IS '调度任务id';
+COMMENT ON COLUMN sj_job_task.parent_id IS '父执行器id';
+COMMENT ON COLUMN sj_job_task.task_status IS '执行的状态 0、失败 1、成功';
+COMMENT ON COLUMN sj_job_task.retry_count IS '重试次数';
+COMMENT ON COLUMN sj_job_task.mr_stage IS '动态分片所处阶段 1:map 2:reduce 3:mergeReduce';
+COMMENT ON COLUMN sj_job_task.leaf IS '叶子节点';
+COMMENT ON COLUMN sj_job_task.task_name IS '任务名称';
+COMMENT ON COLUMN sj_job_task.client_info IS '客户端地址 clientId#ip:port';
+COMMENT ON COLUMN sj_job_task.wf_context IS '工作流全局上下文';
+COMMENT ON COLUMN sj_job_task.result_message IS '执行结果';
+COMMENT ON COLUMN sj_job_task.args_str IS '执行方法参数';
+COMMENT ON COLUMN sj_job_task.args_type IS '参数类型 ';
+COMMENT ON COLUMN sj_job_task.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_job_task.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_job_task.update_dt IS '修改时间';
+COMMENT ON TABLE sj_job_task IS '任务实例';
+
+-- sj_job_task_batch
+CREATE TABLE sj_job_task_batch
+(
+    id                      bigserial PRIMARY KEY,
+    namespace_id            varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name              varchar(64)  NOT NULL,
+    job_id                  bigint       NOT NULL,
+    workflow_node_id        bigint       NOT NULL DEFAULT 0,
+    parent_workflow_node_id bigint       NOT NULL DEFAULT 0,
+    workflow_task_batch_id  bigint       NOT NULL DEFAULT 0,
+    task_batch_status       smallint     NOT NULL DEFAULT 0,
+    operation_reason        smallint     NOT NULL DEFAULT 0,
+    execution_at            bigint       NOT NULL DEFAULT 0,
+    system_task_type        smallint     NOT NULL DEFAULT 3,
+    parent_id               varchar(64)  NOT NULL DEFAULT '',
+    ext_attrs               varchar(256) NULL     DEFAULT '',
+    deleted                 smallint     NOT NULL DEFAULT 0,
+    create_dt               timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt               timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_job_task_batch_01 ON sj_job_task_batch (job_id, task_batch_status);
+CREATE INDEX idx_sj_job_task_batch_02 ON sj_job_task_batch (create_dt);
+CREATE INDEX idx_sj_job_task_batch_03 ON sj_job_task_batch (namespace_id, group_name);
+CREATE INDEX idx_sj_job_task_batch_04 ON sj_job_task_batch (workflow_task_batch_id, workflow_node_id);
+
+COMMENT ON COLUMN sj_job_task_batch.id IS '主键';
+COMMENT ON COLUMN sj_job_task_batch.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_job_task_batch.group_name IS '组名称';
+COMMENT ON COLUMN sj_job_task_batch.job_id IS '任务id';
+COMMENT ON COLUMN sj_job_task_batch.workflow_node_id IS '工作流节点id';
+COMMENT ON COLUMN sj_job_task_batch.parent_workflow_node_id IS '工作流任务父批次id';
+COMMENT ON COLUMN sj_job_task_batch.workflow_task_batch_id IS '工作流任务批次id';
+COMMENT ON COLUMN sj_job_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功';
+COMMENT ON COLUMN sj_job_task_batch.operation_reason IS '操作原因';
+COMMENT ON COLUMN sj_job_task_batch.execution_at IS '任务执行时间';
+COMMENT ON COLUMN sj_job_task_batch.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务';
+COMMENT ON COLUMN sj_job_task_batch.parent_id IS '父节点';
+COMMENT ON COLUMN sj_job_task_batch.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_job_task_batch.deleted IS '逻辑删除 1、删除';
+COMMENT ON COLUMN sj_job_task_batch.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_job_task_batch.update_dt IS '修改时间';
+COMMENT ON TABLE sj_job_task_batch IS '任务批次';
+
+-- sj_job_summary
+CREATE TABLE sj_job_summary
+(
+    id               bigserial PRIMARY KEY,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       varchar(64)  NOT NULL DEFAULT '',
+    business_id      bigint       NOT NULL,
+    system_task_type smallint     NOT NULL DEFAULT 3,
+    trigger_at       timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    success_num      int          NOT NULL DEFAULT 0,
+    fail_num         int          NOT NULL DEFAULT 0,
+    fail_reason      varchar(512) NOT NULL DEFAULT '',
+    stop_num         int          NOT NULL DEFAULT 0,
+    stop_reason      varchar(512) NOT NULL DEFAULT '',
+    cancel_num       int          NOT NULL DEFAULT 0,
+    cancel_reason    varchar(512) NOT NULL DEFAULT '',
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_job_summary_01 ON sj_job_summary (trigger_at, system_task_type, business_id);
+
+CREATE INDEX idx_sj_job_summary_01 ON sj_job_summary (namespace_id, group_name, business_id);
+
+COMMENT ON COLUMN sj_job_summary.id IS '主键';
+COMMENT ON COLUMN sj_job_summary.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_job_summary.group_name IS '组名称';
+COMMENT ON COLUMN sj_job_summary.business_id IS '业务id  ( job_id或workflow_id)';
+COMMENT ON COLUMN sj_job_summary.system_task_type IS '任务类型 3、JOB任务 4、WORKFLOW任务';
+COMMENT ON COLUMN sj_job_summary.trigger_at IS '统计时间';
+COMMENT ON COLUMN sj_job_summary.success_num IS '执行成功-日志数量';
+COMMENT ON COLUMN sj_job_summary.fail_num IS '执行失败-日志数量';
+COMMENT ON COLUMN sj_job_summary.fail_reason IS '失败原因';
+COMMENT ON COLUMN sj_job_summary.stop_num IS '执行失败-日志数量';
+COMMENT ON COLUMN sj_job_summary.stop_reason IS '失败原因';
+COMMENT ON COLUMN sj_job_summary.cancel_num IS '执行失败-日志数量';
+COMMENT ON COLUMN sj_job_summary.cancel_reason IS '失败原因';
+COMMENT ON COLUMN sj_job_summary.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_job_summary.update_dt IS '修改时间';
+COMMENT ON TABLE sj_job_summary IS 'DashBoard_Job';
+
+-- sj_retry_summary
+CREATE TABLE sj_retry_summary
+(
+    id            bigserial PRIMARY KEY,
+    namespace_id  varchar(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name    varchar(64) NOT NULL DEFAULT '',
+    scene_name    varchar(50) NOT NULL DEFAULT '',
+    trigger_at    timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    running_num   int         NOT NULL DEFAULT 0,
+    finish_num    int         NOT NULL DEFAULT 0,
+    max_count_num int         NOT NULL DEFAULT 0,
+    suspend_num   int         NOT NULL DEFAULT 0,
+    create_dt     timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt     timestamp   NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE UNIQUE INDEX uk_sj_retry_summary_01 ON sj_retry_summary (namespace_id, group_name, scene_name, trigger_at);
+
+CREATE INDEX idx_sj_retry_summary_01 ON sj_retry_summary (trigger_at);
+
+COMMENT ON COLUMN sj_retry_summary.id IS '主键';
+COMMENT ON COLUMN sj_retry_summary.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_retry_summary.group_name IS '组名称';
+COMMENT ON COLUMN sj_retry_summary.scene_name IS '场景名称';
+COMMENT ON COLUMN sj_retry_summary.trigger_at IS '统计时间';
+COMMENT ON COLUMN sj_retry_summary.running_num IS '重试中-日志数量';
+COMMENT ON COLUMN sj_retry_summary.finish_num IS '重试完成-日志数量';
+COMMENT ON COLUMN sj_retry_summary.max_count_num IS '重试到达最大次数-日志数量';
+COMMENT ON COLUMN sj_retry_summary.suspend_num IS '暂停重试-日志数量';
+COMMENT ON COLUMN sj_retry_summary.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_retry_summary.update_dt IS '修改时间';
+COMMENT ON TABLE sj_retry_summary IS 'DashBoard_Retry';
+
+-- sj_workflow
+CREATE TABLE sj_workflow
+(
+    id               bigserial PRIMARY KEY,
+    workflow_name    varchar(64)  NOT NULL,
+    namespace_id     varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name       varchar(64)  NOT NULL,
+    workflow_status  smallint     NOT NULL DEFAULT 1,
+    trigger_type     smallint     NOT NULL,
+    trigger_interval varchar(255) NOT NULL,
+    next_trigger_at  bigint       NOT NULL,
+    block_strategy   smallint     NOT NULL DEFAULT 1,
+    executor_timeout int          NOT NULL DEFAULT 0,
+    description      varchar(256) NOT NULL DEFAULT '',
+    flow_info        text         NULL     DEFAULT NULL,
+    wf_context       text         NULL     DEFAULT NULL,
+    notify_ids       varchar(128) NOT NULL DEFAULT '',
+    bucket_index     int          NOT NULL DEFAULT 0,
+    version          int          NOT NULL,
+    ext_attrs        varchar(256) NULL     DEFAULT '',
+    deleted          smallint     NOT NULL DEFAULT 0,
+    create_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt        timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_workflow_01 ON sj_workflow (create_dt);
+CREATE INDEX idx_sj_workflow_02 ON sj_workflow (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_workflow.id IS '主键';
+COMMENT ON COLUMN sj_workflow.workflow_name IS '工作流名称';
+COMMENT ON COLUMN sj_workflow.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_workflow.group_name IS '组名称';
+COMMENT ON COLUMN sj_workflow.workflow_status IS '工作流状态 0、关闭、1、开启';
+COMMENT ON COLUMN sj_workflow.trigger_type IS '触发类型 1.CRON 表达式 2. 固定时间';
+COMMENT ON COLUMN sj_workflow.trigger_interval IS '间隔时长';
+COMMENT ON COLUMN sj_workflow.next_trigger_at IS '下次触发时间';
+COMMENT ON COLUMN sj_workflow.block_strategy IS '阻塞策略 1、丢弃 2、覆盖 3、并行';
+COMMENT ON COLUMN sj_workflow.executor_timeout IS '任务执行超时时间,单位秒';
+COMMENT ON COLUMN sj_workflow.description IS '描述';
+COMMENT ON COLUMN sj_workflow.flow_info IS '流程信息';
+COMMENT ON COLUMN sj_workflow.wf_context IS '上下文';
+COMMENT ON COLUMN sj_workflow.notify_ids IS '通知告警场景配置id列表';
+COMMENT ON COLUMN sj_workflow.bucket_index IS 'bucket';
+COMMENT ON COLUMN sj_workflow.version IS '版本号';
+COMMENT ON COLUMN sj_workflow.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_workflow.deleted IS '逻辑删除 1、删除';
+COMMENT ON COLUMN sj_workflow.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_workflow.update_dt IS '修改时间';
+COMMENT ON TABLE sj_workflow IS '工作流';
+
+-- sj_workflow_node
+CREATE TABLE sj_workflow_node
+(
+    id                   bigserial PRIMARY KEY,
+    namespace_id         varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    node_name            varchar(64)  NOT NULL,
+    group_name           varchar(64)  NOT NULL,
+    job_id               bigint       NOT NULL,
+    workflow_id          bigint       NOT NULL,
+    node_type            smallint     NOT NULL DEFAULT 1,
+    expression_type      smallint     NOT NULL DEFAULT 0,
+    fail_strategy        smallint     NOT NULL DEFAULT 1,
+    workflow_node_status smallint     NOT NULL DEFAULT 1,
+    priority_level       int          NOT NULL DEFAULT 1,
+    node_info            text         NULL     DEFAULT NULL,
+    version              int          NOT NULL,
+    ext_attrs            varchar(256) NULL     DEFAULT '',
+    deleted              smallint     NOT NULL DEFAULT 0,
+    create_dt            timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt            timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_workflow_node_01 ON sj_workflow_node (create_dt);
+CREATE INDEX idx_sj_workflow_node_02 ON sj_workflow_node (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_workflow_node.id IS '主键';
+COMMENT ON COLUMN sj_workflow_node.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_workflow_node.node_name IS '节点名称';
+COMMENT ON COLUMN sj_workflow_node.group_name IS '组名称';
+COMMENT ON COLUMN sj_workflow_node.job_id IS '任务信息id';
+COMMENT ON COLUMN sj_workflow_node.workflow_id IS '工作流ID';
+COMMENT ON COLUMN sj_workflow_node.node_type IS '1、任务节点 2、条件节点';
+COMMENT ON COLUMN sj_workflow_node.expression_type IS '1、SpEl、2、Aviator 3、QL';
+COMMENT ON COLUMN sj_workflow_node.fail_strategy IS '失败策略 1、跳过 2、阻塞';
+COMMENT ON COLUMN sj_workflow_node.workflow_node_status IS '工作流节点状态 0、关闭、1、开启';
+COMMENT ON COLUMN sj_workflow_node.priority_level IS '优先级';
+COMMENT ON COLUMN sj_workflow_node.node_info IS '节点信息 ';
+COMMENT ON COLUMN sj_workflow_node.version IS '版本号';
+COMMENT ON COLUMN sj_workflow_node.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_workflow_node.deleted IS '逻辑删除 1、删除';
+COMMENT ON COLUMN sj_workflow_node.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_workflow_node.update_dt IS '修改时间';
+COMMENT ON TABLE sj_workflow_node IS '工作流节点';
+
+-- sj_workflow_task_batch
+CREATE TABLE sj_workflow_task_batch
+(
+    id                bigserial PRIMARY KEY,
+    namespace_id      varchar(64)  NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a',
+    group_name        varchar(64)  NOT NULL,
+    workflow_id       bigint       NOT NULL,
+    task_batch_status smallint     NOT NULL DEFAULT 0,
+    operation_reason  smallint     NOT NULL DEFAULT 0,
+    flow_info         text         NULL     DEFAULT NULL,
+    wf_context        text         NULL     DEFAULT NULL,
+    execution_at      bigint       NOT NULL DEFAULT 0,
+    ext_attrs         varchar(256) NULL     DEFAULT '',
+    version           int          NOT NULL DEFAULT 1,
+    deleted           smallint     NOT NULL DEFAULT 0,
+    create_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP,
+    update_dt         timestamp    NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE INDEX idx_sj_workflow_task_batch_01 ON sj_workflow_task_batch (workflow_id, task_batch_status);
+CREATE INDEX idx_sj_workflow_task_batch_02 ON sj_workflow_task_batch (create_dt);
+CREATE INDEX idx_sj_workflow_task_batch_03 ON sj_workflow_task_batch (namespace_id, group_name);
+
+COMMENT ON COLUMN sj_workflow_task_batch.id IS '主键';
+COMMENT ON COLUMN sj_workflow_task_batch.namespace_id IS '命名空间id';
+COMMENT ON COLUMN sj_workflow_task_batch.group_name IS '组名称';
+COMMENT ON COLUMN sj_workflow_task_batch.workflow_id IS '工作流任务id';
+COMMENT ON COLUMN sj_workflow_task_batch.task_batch_status IS '任务批次状态 0、失败 1、成功';
+COMMENT ON COLUMN sj_workflow_task_batch.operation_reason IS '操作原因';
+COMMENT ON COLUMN sj_workflow_task_batch.flow_info IS '流程信息';
+COMMENT ON COLUMN sj_workflow_task_batch.wf_context IS '全局上下文';
+COMMENT ON COLUMN sj_workflow_task_batch.execution_at IS '任务执行时间';
+COMMENT ON COLUMN sj_workflow_task_batch.ext_attrs IS '扩展字段';
+COMMENT ON COLUMN sj_workflow_task_batch.version IS '版本号';
+COMMENT ON COLUMN sj_workflow_task_batch.deleted IS '逻辑删除 1、删除';
+COMMENT ON COLUMN sj_workflow_task_batch.create_dt IS '创建时间';
+COMMENT ON COLUMN sj_workflow_task_batch.update_dt IS '修改时间';
+COMMENT ON TABLE sj_workflow_task_batch IS '工作流批次';

+ 88 - 0
pavis-extension/pavis-extension-schedule-server/src/main/resources/logback-spring.xml

@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration debug="false" scan="true" scanPeriod="30 seconds">
+
+    <!-- 关闭 Logback 的状态监听器(通过更换默认状态监听器实现) -->
+    <statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
+
+    <!-- 应用名 -->
+    <springProperty name="APP_NAME" source="spring.application.name" scope="context"/>
+    <!-- 保存路径 -->
+    <property name="LOG_PATH" value="${LOG_PATH:-./logs/job-server}"/>
+    <!-- 字符集 -->
+    <property name="LOG_CHARSET" value="utf-8"/>
+    <!-- 格式化输出:%d 表示日期;%thread 表示线程名;%-5level:级别从左显示 5 个字符宽度;%msg:日志消息;%n 是换行符 -->
+    <!-- 控制台输出格式(带颜色) -->
+    <property name="CONSOLE_LOG_PATTERN" value="%red(%d{yyyy-MM-dd HH:mm:ss}) %highlight(%-5level) %green([%thread]) %boldMagenta(%logger{50}) - %msg%n"/>
+    <!-- 文件输出格式 -->
+    <property name="FILE_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss} %-5level [%thread] %logger{50} - %msg%n"/>
+    <!-- 单个日志文件大小上限 -->
+    <property name="FILE_MAX_SIZE" value="20MB"/>
+
+    <!-- 输出日志到控制台 -->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${CONSOLE_LOG_PATTERN}</pattern>
+            <charset>${LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+
+    <!-- 输出日志到控制台(不带颜色) -->
+    <appender name="CONSOLE_PROD" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>${FILE_LOG_PATTERN}</pattern>
+            <charset>${LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+
+    <!-- 输出日志到文件 -->
+    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/${APP_NAME}.log</file>
+        <!-- 滚动策略:基于文件大小和时间归档日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- 日志文件的路径及文件名 -->
+            <fileNamePattern>${LOG_PATH}/%d{yyyy-MM-dd}/${APP_NAME}.%d{yyyy-MM-dd}.%i.log.gz</fileNamePattern>
+            <!-- 日志文件大小(超过指定大小后,会切分新文件,从索引 0 开始计数,例如:app.2024-01-01.1.log.gz ) -->
+            <maxFileSize>${FILE_MAX_SIZE}</maxFileSize>
+            <!-- 日志保留天数 -->
+            <maxHistory>${FILE_MAX_HISTORY}</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${FILE_LOG_PATTERN}</pattern>
+            <charset>${LOG_CHARSET}</charset>
+        </encoder>
+    </appender>
+
+    <!-- 输出日志到文件(异步) -->
+    <appender name="ASYNC_FILE" class="ch.qos.logback.classic.AsyncAppender">
+        <!-- 不丢失日志,默认:如果队列的 80% 已满,则会丢弃 TRACT、DEBUG、INFO 级别的日志 -->
+        <discardingThreshold>0</discardingThreshold>
+        <!-- 更改默认的队列的深度,该值会影响性能,默认:256 -->
+        <queueSize>512</queueSize>
+        <!-- 添加附加的 appender,最多只能添加一个 -->
+        <appender-ref ref="FILE"/>
+    </appender>
+
+    <!-- Snail Job Server -->
+    <appender name="JOB_SERVER" class="com.aizuda.snailjob.server.common.appender.SnailJobServerLogbackAppender" />
+
+    <!-- 开发环境:只打印到控制台 -->
+    <springProfile name="dev">
+        <!-- 如果配置的日志等级,和 application.yml 中的日志等级配置重叠,application.yml 配置优先级高 -->
+        <root level="INFO">
+            <appender-ref ref="CONSOLE"/>
+            <appender-ref ref="JOB_SERVER"/>
+        </root>
+    </springProfile>
+
+    <!-- 生产环境:打印到控制台并输出到文件 -->
+    <springProfile name="prod">
+        <root level="INFO">
+            <appender-ref ref="CONSOLE_PROD"/>
+            <appender-ref ref="ASYNC_FILE"/>
+            <appender-ref ref="JOB_SERVER"/>
+        </root>
+        <!-- 日志保留天数(根据国家法律,网络运行状态、网络安全事件、个人敏感信息操作等相关记录,留存的日志不少于六个月,并且进行网络多机备份。) -->
+        <property name="FILE_MAX_HISTORY" value="180"/>
+    </springProfile>
+</configuration>

+ 17 - 0
pavis-extension/pom.xml

@@ -0,0 +1,17 @@
+<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 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.pavis</groupId>
+        <artifactId>pavis-admin</artifactId>
+        <version>${revision}</version>
+    </parent>
+
+    <artifactId>pavis-extension</artifactId>
+    <packaging>pom</packaging>
+    <description>扩展模块(存放其他扩展模块)</description>
+
+    <modules>
+        <module>pavis-extension-schedule-server</module>
+    </modules>
+</project>

+ 130 - 0
pavis-module-aigc/pom.xml

@@ -0,0 +1,130 @@
+<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 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.pavis</groupId>
+        <artifactId>pavis-admin</artifactId>
+        <version>${revision}</version>
+    </parent>
+    
+    <artifactId>pavis-module-aigc</artifactId>
+    <description>智能管理模块(存放智能管理相关业务功能,例如:知识库、增强检索、智能体等)</description>
+    
+    <properties>
+        <spring-ai.version>1.0.0-M8</spring-ai.version>
+        <langchain4j-core.version>1.0.1</langchain4j-core.version>
+        <langchain4j-community.version>1.0.1-beta6</langchain4j-community.version>
+    </properties>
+    
+    <dependencies>
+        <!-- 公共模块 -->
+        <dependency>
+            <groupId>com.pavis</groupId>
+            <artifactId>pavis-common</artifactId>
+        </dependency>
+        
+        <!-- Spring AI 框架 -->
+        <dependency>
+            <groupId>org.springframework.ai</groupId>
+            <artifactId>spring-ai-starter-model-openai</artifactId>
+            <version>${spring-ai.version}</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.springframework.ai</groupId>
+            <artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
+            <version>${spring-ai.version}</version>
+        </dependency>
+        
+        <!-- HttpClient 核心库 -->
+        <dependency>
+            <groupId>org.apache.httpcomponents.client5</groupId>
+            <artifactId>httpclient5</artifactId>
+        </dependency>
+        
+        <!-- 如果需要使用 HttpClient 连接池管理 -->
+        <dependency>
+            <groupId>org.apache.httpcomponents.core5</groupId>
+            <artifactId>httpcore5</artifactId>
+        </dependency>
+        
+        <!-- langchain4j 核心库 -->
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j</artifactId>
+            <version>${langchain4j-core.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-core</artifactId>
+            <version>${langchain4j-core.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-open-ai</artifactId>
+            <version>${langchain4j-core.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-ollama</artifactId>
+            <version>${langchain4j-community.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-community-qianfan</artifactId>
+            <version>${langchain4j-community.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-community-dashscope</artifactId>
+            <version>${langchain4j-community.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.slf4j</groupId>
+                    <artifactId>slf4j-simple</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-community-zhipu-ai</artifactId>
+            <version>${langchain4j-community.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-embeddings</artifactId>
+            <version>${langchain4j-community.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-community-redis</artifactId>
+            <version>${langchain4j-community.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-pgvector</artifactId>
+            <version>${langchain4j-community.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-milvus</artifactId>
+            <version>${langchain4j-community.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-embedding-store-filter-parser-sql</artifactId>
+            <version>${langchain4j-community.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.github.jsqlparser</groupId>
+                    <artifactId>jsqlparser</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>dev.langchain4j</groupId>
+            <artifactId>langchain4j-document-parser-apache-tika</artifactId>
+            <version>${langchain4j-community.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/PavisAiAutoConfiguration.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc;
+
+import com.pavis.admin.aigc.properties.ChatProps;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties({
+        ChatProps.class,
+})
+public class PavisAiAutoConfiguration {
+}

+ 49 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/model/req/ChatReq.java

@@ -0,0 +1,49 @@
+package com.pavis.admin.aigc.common.model.req;
+
+import com.pavis.admin.aigc.common.utils.StreamEmitter;
+import dev.langchain4j.model.input.Prompt;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+
+@Data
+@Accessors(chain = true)
+public class ChatReq {
+
+    private String appId;
+    private String modelId;
+    private String modelName;
+    private String modelProvider;
+
+    private String message;
+
+    private String conversationId;
+
+    private String userId;
+
+    private String username;
+
+    private String chatId;
+
+    private String promptText;
+
+    private String docsName;
+
+    private String knowledgeId;
+    private List<String> knowledgeIds = new ArrayList<>();
+
+    private String docsId;
+
+    private String url;
+
+    private String role;
+
+    private Prompt prompt;
+
+    private StreamEmitter emitter;
+    private Executor executor;
+}

+ 56 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/model/req/ImageReq.java

@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
+ *
+ * Licensed under the GNU Affero General Public License, Version 3 (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.gnu.org/licenses/agpl-3.0.html
+ *
+ * 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.
+ */
+
+package com.pavis.admin.aigc.common.model.req;
+
+import dev.langchain4j.model.input.Prompt;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+/**
+ * @author tycoding
+ * @since 2024/1/6
+ */
+@Data
+@Accessors(chain = true)
+public class ImageReq {
+
+    private String modelId;
+    private String modelName;
+    private String modelProvider;
+
+    private Prompt prompt;
+
+    /**
+     * 内容
+     */
+    private String message;
+
+    /**
+     * 质量
+     */
+    private String quality;
+
+    /**
+     * 尺寸
+     */
+    private String size;
+
+    /**
+     * 风格
+     */
+    private String style;
+}

+ 27 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/model/resp/ChatResp.java

@@ -0,0 +1,27 @@
+package com.pavis.admin.aigc.common.model.resp;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(chain = true)
+public class ChatResp {
+
+    private boolean isDone = false;
+
+    private String message;
+
+    private Integer usedToken;
+
+    private long time;
+
+    public ChatResp(String message) {
+        this.message = message;
+    }
+
+    public ChatResp(Integer usedToken, long startTime) {
+        this.isDone = true;
+        this.usedToken = usedToken;
+        this.time = System.currentTimeMillis() - startTime;
+    }
+}

+ 29 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/model/resp/EmbeddingResp.java

@@ -0,0 +1,29 @@
+package com.pavis.admin.aigc.common.model.resp;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+@Data
+@Accessors(chain = true)
+public class EmbeddingResp {
+
+    /**
+     * 写入到vector store的ID
+     */
+    private String vectorId;
+
+    /**
+     * 文档ID
+     */
+    private String docsId;
+
+    /**
+     * 知识库ID
+     */
+    private String knowledgeId;
+
+    /**
+     * Embedding后切片的文本
+     */
+    private String text;
+}

+ 30 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/utils/PromptUtil.java

@@ -0,0 +1,30 @@
+package com.pavis.admin.aigc.common.utils;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.pavis.admin.aigc.constant.PromptConst;
+import dev.langchain4j.model.input.Prompt;
+import dev.langchain4j.model.input.PromptTemplate;
+
+import java.util.Map;
+
+
+public class PromptUtil {
+
+    public static Prompt build(String message) {
+        return new Prompt(message);
+    }
+
+    public static Prompt build(String message, String promptText) {
+        return new PromptTemplate(promptText + PromptConst.EMPTY).apply(Map.of(PromptConst.QUESTION, message));
+    }
+
+    public static Prompt build(String message, String promptText, Object param) {
+        Map<String, Object> params = BeanUtil.beanToMap(param, false, true);
+        params.put(PromptConst.QUESTION, message);
+        return new PromptTemplate(promptText).apply(params);
+    }
+
+    public static Prompt buildDocs(String message) {
+        return new PromptTemplate(PromptConst.DOCUMENT).apply(Map.of(PromptConst.QUESTION, message));
+    }
+}

+ 74 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/common/utils/StreamEmitter.java

@@ -0,0 +1,74 @@
+package com.pavis.admin.aigc.common.utils;
+
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+
+public class StreamEmitter {
+
+    private final SseEmitter emitter;
+
+    public StreamEmitter() {
+        emitter = new SseEmitter(5 * 60 * 1000L);
+    }
+
+    public SseEmitter get() {
+        return emitter;
+    }
+
+    public SseEmitter streaming(final ExecutorService executor, Runnable func) {
+//        ExecutorService executor = Executors.newSingleThreadExecutor();
+
+        emitter.onCompletion(() -> {
+            System.out.println("SseEmitter 完成");
+            executor.shutdownNow();
+        });
+
+        emitter.onError((e) -> {
+            System.out.println("SseEmitter 出现错误: " + e.getMessage());
+            executor.shutdownNow();
+        });
+
+        emitter.onTimeout(() -> {
+            System.out.println("SseEmitter 超时");
+            emitter.complete();
+            executor.shutdownNow();
+        });
+        executor.execute(() -> {
+            try {
+                func.run();
+            } catch (Exception e) {
+                System.out.println("捕获到异常: " + e.getMessage());
+                emitter.completeWithError(e);
+                Thread.currentThread().interrupt();
+            } finally {
+                if (!executor.isShutdown()) {
+                    executor.shutdownNow();
+                }
+            }
+        });
+        return emitter;
+    }
+
+    public void send(Object obj) {
+        try {
+            emitter.send(obj);
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    public void complete() {
+        emitter.complete();
+    }
+
+    public void error(String message) {
+        try {
+            emitter.send("Error: " + message);
+            emitter.complete();
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+}

+ 17 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/constant/EmbedConst.java

@@ -0,0 +1,17 @@
+package com.pavis.admin.aigc.constant;
+
+
+public interface EmbedConst {
+
+    String ORIGIN_TYPE_INPUT = "INPUT";
+    String ORIGIN_TYPE_UPLOAD = "UPLOAD";
+
+    String KNOWLEDGE = "knowledgeId";
+    String FILENAME = "docsName";
+
+    String CLAZZ_NAME_OPENAI = "OpenAiEmbeddingModel";
+    String CLAZZ_NAME_QIANFAN = "QianfanEmbeddingModel";
+    String CLAZZ_NAME_QIANWEN = "QwenEmbeddingModel";
+    String CLAZZ_NAME_ZHIPU = "ZhipuAiEmbeddingModel";
+    String CLAZZ_NAME_OLLAMA = "OllamaEmbeddingModel";
+}

+ 7 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/constant/ModelConst.java

@@ -0,0 +1,7 @@
+package com.pavis.admin.aigc.constant;
+
+public interface ModelConst {
+
+    String TEXT_SUFFIX = "_text";
+    String IMAGE_SUFFIX = "_image";
+}

+ 57 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/constant/PromptConst.java

@@ -0,0 +1,57 @@
+package com.pavis.admin.aigc.constant;
+
+public interface PromptConst {
+
+    String QUESTION = "question";
+
+    String EMPTY = """
+            
+            ------
+            {{question}}
+            ------
+            """;
+
+    String DOCUMENT = "You are good at analyzing documents. Please analyze my questions according to the following documents, question: [{{question}}], [docs]";
+
+    String MINDMAP = """
+            # Role
+            You are a Markdown outline format engineer who focuses on answering user questions. You can quickly and accurately convert user questions into refined Markdown outline titles, and refine the specific details of each title.
+            
+            ## Skills
+            ### Skill 1: Identify user question intent
+            - Accurately understand the specific content and needs of user questions.
+            ### Skill 2: Convert to Markdown outline
+            - Simplify user questions into Markdown outline-style titles.
+            ### Skill 3: Return to user
+            - Return the optimized outline to the user.
+            
+            ## Constraints
+            - Only return the organized Markdown format content, without other explanation information
+            - Answer the question in the language used by the user.
+            - Return the answer in Markdown style, keep the main title as concise as possible; and refine the specific step information of each main title in the subtitle.
+            """;
+
+    String WRITE = """
+            # 角色
+            你是一名专业文案撰写师。你擅长运用行业领域相关知识,以专业的视角为用户生成Markdown文档。
+            
+            ## 技能
+            ### 技能 1: 写作
+            - 提取用户输入的主题和关键信息。
+            
+            ### 技能 2: 专业知识应用
+            - 了解相关行业的相关知识。
+            - 在撰写内容时,运用专业的语言和视角。
+            
+             ### 技能 3: 遵循Markdown格式
+            - 拆分文档内容,以Markdown大纲格式分段内容,更易于用户阅读
+            
+            ## 限制
+            - 只讨论写作相关的话题,不要返回其他任何内容和解释。
+            - 始终以用户输入的信息为主题,撰写内容。
+            """;
+
+    String IMAGE = """
+            Please generate the corresponding pictures according to the following requirements.
+            """;
+}

+ 14 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/constant/PropConst.java

@@ -0,0 +1,14 @@
+package com.pavis.admin.aigc.constant;
+
+public interface PropConst {
+
+    String OPENAI_CON = "langchat.openai.api-key";
+
+    String GEMINI_CON = "langchat.gemini.project";
+
+    String AZUREOPENAI_CON = "langchat.azureopenai.api-key";
+
+    String GOOGLE_CON = "langchat.web-search.google.api-key";
+
+    String TAVILY_CON = "langchat.web-search.tavily.api-key";
+}

+ 30 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/ChatErrorEnum.java

@@ -0,0 +1,30 @@
+package com.pavis.admin.aigc.enums;
+
+import lombok.AllArgsConstructor;
+
+
+@AllArgsConstructor
+public enum ChatErrorEnum {
+    API_KEY_IS_NULL(1000, "模型 %s %s api key 为空,请检查配置"),
+    BASE_URL_IS_NULL(1003, "模型 %s %s base url 为空,请检查配置"),
+    SECRET_KEY_IS_NULL(1005, "模型 %s %s base secret Key 为空,请检查配置"),
+    ;
+
+    /**
+     * 错误码
+     */
+    private int errorCode;
+    /**
+     * 错误描述,用于展示给用户
+     */
+    private String errorDesc;
+
+    public int getErrorCode() {
+        return this.errorCode;
+    }
+
+    public String getErrorDesc(String modelName, String type) {
+        return this.errorDesc.formatted(modelName, type);
+    }
+
+}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/EmbedStoreEnum.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum EmbedStoreEnum {
+
+    REDIS,
+    PGVECTOR,
+    MILVUS,
+    ;
+}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/ModelTypeEnum.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum ModelTypeEnum {
+
+    CHAT,
+    EMBEDDING,
+    TEXT_IMAGE,
+    WEB_SEARCH;
+}

+ 23 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/ProviderEnum.java

@@ -0,0 +1,23 @@
+package com.pavis.admin.aigc.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum ProviderEnum {
+
+    OPENAI,
+    AZURE_OPENAI,
+    GEMINI,
+    OLLAMA,
+    CLAUDE,
+    Q_FAN,
+    Q_WEN,
+    ZHIPU,
+    YI,
+    DOUYIN,
+    DEEPSEEK,
+    SILICON,
+    SPARK,
+    ;
+
+}

+ 17 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/enums/RoleEnum.java

@@ -0,0 +1,17 @@
+package com.pavis.admin.aigc.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum RoleEnum {
+    USER("user"),
+    ASSISTANT("assistant"),
+    SYSTEM("system"),
+    ;
+
+    private final String name;
+
+    RoleEnum(String name) {
+        this.name = name;
+    }
+}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/event/EmbeddingRefreshEvent.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.event;
+
+import org.springframework.context.ApplicationEvent;
+
+public class EmbeddingRefreshEvent extends ApplicationEvent {
+
+    private static final long serialVersionUID = 4109980679877560773L;
+
+    public EmbeddingRefreshEvent(Object source) {
+        super(source);
+    }
+}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/event/ProviderRefreshEvent.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.event;
+
+import org.springframework.context.ApplicationEvent;
+
+public class ProviderRefreshEvent extends ApplicationEvent {
+
+    private static final long serialVersionUID = 4109980679877560773L;
+
+    public ProviderRefreshEvent(Object source) {
+        super(source);
+    }
+}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentExecutionMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AgentExecutionDO;
+
+/**
+* 智能体执行记录 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AgentExecutionMapper extends BaseMapper<AgentExecutionDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentKnowledgeMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AgentKnowledgeDO;
+
+/**
+* 智能体和知识库关联 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AgentKnowledgeMapper extends BaseMapper<AgentKnowledgeDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AgentDO;
+
+/**
+* 智能体 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AgentMapper extends BaseMapper<AgentDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentStepMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AgentStepDO;
+
+/**
+* 智能体执行步骤 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AgentStepMapper extends BaseMapper<AgentStepDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AgentToolMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AgentToolDO;
+
+/**
+* 智能体和工具关联 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AgentToolMapper extends BaseMapper<AgentToolDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AigcAppMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AigcAppDO;
+
+/**
+* AIGC应用配置 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AigcAppMapper extends BaseMapper<AigcAppDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AigcMessageFeedbackMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AigcMessageFeedbackDO;
+
+/**
+* 消息反馈 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AigcMessageFeedbackMapper extends BaseMapper<AigcMessageFeedbackDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AigcMessageMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AigcMessageDO;
+
+/**
+* 智能对话消息 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AigcMessageMapper extends BaseMapper<AigcMessageDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AppApiMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AppApiDO;
+
+/**
+* 应用API密钥 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AppApiMapper extends BaseMapper<AppApiDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/AppKnowledgeMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.AppKnowledgeDO;
+
+/**
+* 应用和知识库关联 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface AppKnowledgeMapper extends BaseMapper<AppKnowledgeDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/ConversationMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.ConversationDO;
+
+/**
+* 智能对话会话 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface ConversationMapper extends BaseMapper<ConversationDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/DocChunkMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.DocChunkDO;
+
+/**
+* 文档切片 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface DocChunkMapper extends BaseMapper<DocChunkDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/DocMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.DocDO;
+
+/**
+* 智能文档 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface DocMapper extends BaseMapper<DocDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/EmbedStoreMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.EmbedStoreDO;
+
+/**
+* 向量存储配置 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface EmbedStoreMapper extends BaseMapper<EmbedStoreDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/KnowledgeMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.KnowledgeDO;
+
+/**
+* AIGC知识库 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface KnowledgeMapper extends BaseMapper<KnowledgeDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/ModelMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.ModelDO;
+
+/**
+* AIGC模型配置 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface ModelMapper extends BaseMapper<ModelDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/ModelSecretMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.ModelSecretDO;
+
+/**
+* 模型安全配置 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface ModelSecretMapper extends BaseMapper<ModelSecretDO> {}

+ 12 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/mapper/ToolMapper.java

@@ -0,0 +1,12 @@
+package com.pavis.admin.aigc.mapper;
+
+import top.continew.starter.data.mp.base.BaseMapper;
+import com.pavis.admin.aigc.model.entity.ToolDO;
+
+/**
+* 工具 Mapper
+*
+* @author semi
+* @since 2025/05/26 17:28
+*/
+public interface ToolMapper extends BaseMapper<ToolDO> {}

+ 94 - 0
pavis-module-aigc/src/main/java/com/pavis/admin/aigc/model/entity/AgentDO.java

@@ -0,0 +1,94 @@
+package com.pavis.admin.aigc.model.entity;
+
+import lombok.Data;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import com.pavis.admin.common.model.entity.BaseDO;
+
+
+import java.io.Serial;
+
+/**
+ * 智能体实体
+ *
+ * @author semi
+ * @since 2025/05/26 17:28
+ */
+@Data
+@TableName("aigc_agent")
+public class AgentDO extends BaseDO {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 智能体名称
+     */
+    private String name;
+
+    /**
+     * 智能体唯一标识码
+     */
+    private String code;
+
+    /**
+     * 智能体类型:assistant/task/workflow
+     */
+    private String agentType;
+
+    /**
+     * 智能体描述
+     */
+    private String description;
+
+    /**
+     * 智能体提示词
+     */
+    private String systemPrompt;
+
+    /**
+     * 智能体执行下一步任务的提示词
+     */
+    private String nextStepPrompt;
+
+    /**
+     * 关联模型ID
+     */
+    private Long modelId;
+
+    /**
+     * 对应的类
+     */
+    private String className;
+
+    /**
+     * 图标URL
+     */
+    private String icon;
+
+    /**
+     * 配置参数
+     */
+    private String config;
+
+    /**
+     * 最大步骤数
+     */
+    private Integer maxSteps;
+
+    /**
+     * 执行超时时间(秒)
+     */
+    private Integer timeout;
+
+    /**
+     * 状态(1:启用;2:禁用)
+     */
+    private Integer status;
+
+    /**
+     * 版本号
+     */
+    private String version;
+}

Неке датотеке нису приказане због велике количине промена