From 805c4053c1e14cb2753d59ab6f8911b98f264073 Mon Sep 17 00:00:00 2001
From: zhangdaiscott <zhangdaiscott@163.com>
Date: Wed, 23 Feb 2022 23:34:04 +0800
Subject: [PATCH] JeecgBoot 3.1.0 版本发布,基于代码生成器的企业级低代码平台

---
 jeecg-boot/README.md                                                                                                                                                                     |   2 +-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml                                                                                                            |   2 +-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java                                                         |  89 -----------------------------------------------------------------------------------------
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java                                   |  18 ------------------
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java                                         |  42 ------------------------------------------
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java                                                   |   3 ++-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml                                                                                                            |   2 +-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java                                                         |  55 -------------------------------------------------------
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml                                                                                                                                   |   2 +-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml                                                                                                                                  |   2 +-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java                                                                                        |   2 ++
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java                                                                                 |   2 +-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java                                                                                    |  11 ++++++++---
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java                                                                          |  20 +++++++++++++++++---
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/UrlMatchEnum.java                                                                                  |  10 ++++++----
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoDict.java                                                                           |  23 +++++++++++++++++++++++
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoLowApp.java                                                                         |  33 +++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java                                                                              |  18 ++++++++++++++++--
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java                                                                            |  69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java                                                                         |  22 ++++++++++++++++++++++
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java                                                                   |  33 ++++++++++++++-------------------
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java                                                               |  11 +++++++++--
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java                                                                          |  66 ++++++++++++++++++++++++++++++++++++++++++++++++++----------------
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java                                                                                  |   5 ++---
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModel.java                                                                                  |   6 ++++++
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java                                                                                     |  36 ++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java                                                                                       |   5 ++++-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java                                                                                |   2 +-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java                                                                          |   2 +-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java                                                                                 |  46 +++++++++++++++++++++++++++++++++++++---------
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/AutoPoiDictConfig.java                                                                                    |  22 +++++++++++++++++-----
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeeccgBaseConfig.java                                                                                     |  26 ++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java                                                                                         |  10 +++++-----
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java                                                                                    |  21 ++++++++++++++++-----
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java                                                                                     |   5 ++++-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java                                                                                   |   7 ++++---
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Shiro.java                                                                                             |  18 ++++++++++++++++++
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml                                                                                                                                 |   2 +-
 jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java                                                                              |   4 ++++
 jeecg-boot/jeecg-boot-base/pom.xml                                                                                                                                                       |   2 +-
 jeecg-boot/jeecg-boot-module-demo/pom.xml                                                                                                                                                |   2 +-
 jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/mock/MockController.java                                                                                          |   2 +-
 jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/online/OnlCgformDemoController.java                                                                               | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java                                                                          |   9 +++++++--
 jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderErpMainController.java                                                                  | 256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderMainController.java                                                                     |   2 +-
 jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderTabMainController.java                                                                  | 267 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 jeecg-boot/jeecg-boot-module-system/Dockerfile                                                                                                                                           |   4 ++--
 jeecg-boot/jeecg-boot-module-system/pom.xml                                                                                                                                              |   8 ++++----
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/JeecgSystemApplication.java                                                                                                  |   8 ++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/jimureport/JimuReportTokenService.java                                                                                |  15 ++++++++++++---
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/aop/LogRecordAspect.java                                                                                     |  92 ++++++++++++++++++++++++++++++++++++++++++++++----------------------------------------------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/controller/NgAlainController.java                                                                            | 172 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------------------------------------------------------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java                                                                           |  18 ++++++++++++------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/job/SampleJob.java                                                                                            |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java                                                                      |   9 +++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java                                                                               |  82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/MockVue3Controller.java                                                                            |  19 -------------------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java                                                                     |  38 ++++++++++++++++++++++----------------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java                                                                 |   6 ++++++
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java                                                                         |  49 +++++++++++++++++++++++++++++++++++++------------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java                                                                        |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java                                                                       |   2 ++
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java                                                                           |  11 +++++++++--
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java                                                                 |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java                                                                       |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java                                                                             |  19 +++++++++++++++----
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java                                                                         |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java                                                                       |  67 ++++++++++++++++++++++++++++++++++++++++++-------------------------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java                                                                         |   5 ++++-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java                                                                           |  38 +++++++++++++++++++++++++++++++++-----
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java                                                                             |  50 ++++++++++++++++++++++++++++++++++++++++++--------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java                                                                       |  29 +++++++++++++++++++++--------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java                                                                            |  16 ++++++++++++----
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepart.java                                                                                         |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysPosition.java                                                                                       |   2 --
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java                                                                                   |  20 +++++++++++++++++++-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java                                                                                     |  11 +++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml                                                                                  |  36 +++++++++++++++++++++++++++---------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserDepartMapper.xml                                                                            |  12 ++++++++----
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/AnnouncementSendModel.java                                                                              |   9 +++------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/rule/CategoryCodeRule.java                                                                                    |   3 +++
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java                                                                                |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java                                                                                |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/IThirdAppService.java                                                                                 |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java                                                                              |   4 +++-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartPermissionServiceImpl.java                                                              |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java                                                                        |  14 ++++++++++----
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java                                                                          |  38 ++++++++++++++++++++++++++++++++------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java                                                                        |   6 +++---
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java                                                                  |   3 +++
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java                                                                    |  21 +++++++++++----------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java                                                                          |   1 +
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java                                                                 |  78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java                                                         |  20 ++++++++++++++++----
 jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml                                                                                                              |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt                                                                                                                        |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/utils.ftl                                                                                       |   4 ++--
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai             |  20 ++++++++++----------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei                   |   4 ++--
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                          | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                          |  61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi                         | 354 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei              |  58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai       |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei             |  17 ++---------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei                     |  15 +--------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai            |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                         | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                         |  82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi                        | 354 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei             |  87 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai           |   4 ++--
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei                         |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/[1-n]List.vuei                                 |  15 ++-------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                        | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                        | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi                       | 601 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei                                | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei            |  58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Modal.vuei                    |  66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai   |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei                 |   4 +---
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei         |  17 ++---------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei                 |  15 +--------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                | 244 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                |  80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi               | 763 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei    | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei             |  64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/subTables/[1-n]SubTable.vuei          |  69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei                |  17 ++---------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei                        |  15 +--------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                       | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                       |  72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi                      | 700 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei           | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei                    |  64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai           |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei                 |  21 ++++++---------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei                         |  15 +--------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                        | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                        |  72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi                       | 700 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei            | 183 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei                     |  64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai                            |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}Form.vuei                                      |  93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}List.vuei                                      |  44 ++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                                         | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                                         |  61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi                                        |  56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei                                |  56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/controller/${entityPackage}/${entityName}Controller.javai          | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/entity/${entityPackage}/${entityName}.javai                        |  49 +++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/${entityName}Mapper.javai                  |  17 +++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml                |   5 +++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/I${entityName}Service.javai               |  14 ++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai       |  19 +++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/${entityName}List.vuei                        | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei               | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei | 162 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                                        | 153 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                                        |  61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi                                       |  56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei                               |  56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/controller/${entityPackage}/${entityName}Controller.javai                           | 170 --------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/entity/${entityPackage}/${entityName}.javai                                         |  49 -------------------------------------------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/${entityName}Mapper.javai                                   |  17 -----------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml                                 |   5 -----
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/I${entityName}Service.javai                                |  14 --------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai                        |  19 -------------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/${entityName}List.vuei                                         | 173 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei                                | 156 ------------------------------------------------------------------------------------------------------------------------------------------------------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei                  | 162 ------------------------------------------------------------------------------------------------------------------------------------------------------------------
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai                      |   2 +-
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                                   | 152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                                   |  72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi                                  |  95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei                          | 119 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai                     |   4 ++--
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei                                  | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi                                  | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi                                 | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei                                          | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei                         |  56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/[1-n]Modal.vuei                                 |  64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-module-system/src/main/resources/templates/announcement/showContent.ftl                                                                                            |   2 +-
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml                                                                                                                           |   2 +-
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/resources/bootstrap.yml                                                                                                  |   4 ++--
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml                                                                                                                             |   2 +-
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml                                                                                                                            |   2 +-
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/src/main/java/org/jeecg/boot/starter/lock/aspect/DistributedLockHandler.java                                                       |   6 +++---
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml                                                                                                                        |   2 +-
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-seata/pom.xml                                                                                                                           |  27 +++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/pom.xml                                                                                                                  |  28 ++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/java/org/jeecg/boot/shardingsphere/config/DataSourceConfiguration.java                                          |  78 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/resources/application.yml                                                                                       |   3 +++
 jeecg-boot/jeecg-boot-starter/pom.xml                                                                                                                                                    |  93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile                                                                                                                             |   4 ++--
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml                                                                                                                                |   2 +-
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml                                                                                                     |   2 +-
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml                                                                                                                                |   2 +-
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile                                                                                                                               |   4 ++--
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml                                                                                                                                  |   2 +-
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml                                                                                                                               |   2 +-
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile                                                                                                                        |   4 ++--
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml                                                                                                                           |   2 +-
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/pom.xml                                                                                                            |  22 ++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/controller/SeataOrderController.java                                    |  59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/PlaceOrderRequest.java                                              |  28 ++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceBalanceRequest.java                                           |  21 +++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceStockRequest.java                                             |  21 +++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataAccount.java                                                |  30 ++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataOrder.java                                                  |  44 ++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataProduct.java                                                |  33 +++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/enums/OrderStatus.java                                                  |  22 ++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataAccountMapper.java                                          |  16 ++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataOrderMapper.java                                            |  17 +++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataProductMapper.java                                          |  15 +++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataAccountService.java                                        |  15 +++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataOrderService.java                                          |  18 ++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataProductService.java                                        |  18 ++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataAccountServiceImpl.java                               |  52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataOrderServiceImpl.java                                 |  67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataProductServiceImpl.java                               |  57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/application-seata.yml                                                                           |  38 ++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-account.sql                                                                          |  29 +++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-order.sql                                                                            |  32 ++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-product.sql                                                                          |  31 +++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/seata.sql                                                                                   |  79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/undo_log.sql                                                                                |  12 ++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/doc/db.sql                                                                                                |  46 ++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/pom.xml                                                                                                   |  22 ++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/algorithm/StandardModTableShardAlgorithm.java               |  86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/controller/JeecgShardingDemoController.java                 |  49 +++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/entity/ShardingSysLog.java                                  | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/ShardingSysLogMapper.java                            |  15 +++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/xml/ShardingSysLogMapper.xml                         |   5 +++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/IShardingSysLogService.java                         |  14 ++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/impl/ShardingSysLogServiceImpl.java                 |  19 +++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/resources/application-sharding.yml                                                               |  42 ++++++++++++++++++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/pom.xml                                                                                                                                   |  26 ++++++++++++++++++++++++++
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile                                                                                                                              |   4 ++--
 jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml                                                                                                                                 |   2 +-
 jeecg-boot/jeecg-cloud-module/pom.xml                                                                                                                                                    |   3 ++-
 jeecg-boot/pom.xml                                                                                                                                                                       |  20 ++++++++++++++++----
 247 files changed, 12328 insertions(+), 1858 deletions(-)
 delete mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java
 delete mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java
 delete mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java
 delete mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java
 create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoDict.java
 create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoLowApp.java
 create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java
 create mode 100644 jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Shiro.java
 create mode 100644 jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/online/OnlCgformDemoController.java
 create mode 100644 jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderErpMainController.java
 delete mode 100644 jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderTabMainController.java
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/MockVue3Controller.java
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/subTables/[1-n]SubTable.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}Form.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/controller/${entityPackage}/${entityName}Controller.javai
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/entity/${entityPackage}/${entityName}.javai
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/${entityName}Mapper.javai
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/I${entityName}Service.javai
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/controller/${entityPackage}/${entityName}Controller.javai
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/entity/${entityPackage}/${entityName}.javai
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/${entityName}Mapper.javai
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/I${entityName}Service.javai
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/${entityName}List.vuei
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei
 delete mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/[1-n]Modal.vuei
 create mode 100644 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-seata/pom.xml
 create mode 100644 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/pom.xml
 create mode 100644 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/java/org/jeecg/boot/shardingsphere/config/DataSourceConfiguration.java
 create mode 100644 jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/resources/application.yml
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/pom.xml
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/controller/SeataOrderController.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/PlaceOrderRequest.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceBalanceRequest.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceStockRequest.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataAccount.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataOrder.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataProduct.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/enums/OrderStatus.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataAccountMapper.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataOrderMapper.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataProductMapper.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataAccountService.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataOrderService.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataProductService.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataAccountServiceImpl.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataOrderServiceImpl.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataProductServiceImpl.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/application-seata.yml
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-account.sql
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-order.sql
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-product.sql
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/seata.sql
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/undo_log.sql
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/doc/db.sql
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/pom.xml
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/algorithm/StandardModTableShardAlgorithm.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/controller/JeecgShardingDemoController.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/entity/ShardingSysLog.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/ShardingSysLogMapper.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/xml/ShardingSysLogMapper.xml
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/IShardingSysLogService.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/impl/ShardingSysLogServiceImpl.java
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/resources/application-sharding.yml
 create mode 100644 jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/pom.xml

diff --git a/jeecg-boot/README.md b/jeecg-boot/README.md
index 2960702..fbf773c 100644
--- a/jeecg-boot/README.md
+++ b/jeecg-boot/README.md
@@ -1,7 +1,7 @@
 Jeecg-Boot 低代码开发平台
 ===============
 
-当前最新版本: 3.0(发布日期:2021-11-01)
+当前最新版本: 3.1.0(发布日期:20220301)
 
 
 ## 后端技术架构
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml
index 75e7e82..4fed55c 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-base-api</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java
deleted file mode 100644
index e951bd6..0000000
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java
+++ /dev/null
@@ -1,89 +0,0 @@
-package org.jeecg.common.bpm.api;
-
-import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.constant.ServiceNameConstants;
-import org.jeecg.common.online.api.factory.OnlineBaseExtAPIFallbackFactory;
-import org.springframework.cloud.openfeign.FeignClient;
-import org.springframework.stereotype.Component;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-
-/**
- * 流程接口
- *
- * @author scott
- */
-@Component
-@FeignClient(contextId = "bpmBaseRemoteApi", value = ServiceNameConstants.SYSTEM_SERVICE,
-    fallbackFactory = OnlineBaseExtAPIFallbackFactory.class)
-public interface IBpmBaseExtAPI {
-    /**
-     * 23. 流程提交接口(online,自定义开发)
-     *
-     * @param flowCode
-     *            流程业务关联 例如:joa_leave_01
-     * @param id
-     *            表单业务数据data id
-     * @param formUrl
-     *            流程审批时附件页面默认展示的PC端表单组件(地址)
-     * @param formUrlMobile
-     *            流程审批时附件页面默认展示的移动端表单组件(地址)
-     * @param username
-     *            流程发起人账号
-     * @param jsonData
-     *            Json串,额外扩展的流程变量值 【非必填】
-     * @return
-     * @throws Exception
-     */
-    @PostMapping(value = "/act/process/extActProcess/startMutilProcess")
-    Result<String> startMutilProcess(@RequestParam("flowCode") String flowCode, @RequestParam("id") String id,
-        @RequestParam("formUrl") String formUrl, @RequestParam("formUrlMobile") String formUrlMobile,
-        @RequestParam("username") String username, @RequestParam("jsonData") String jsonData) throws Exception;
-
-    /**
-     * 24. 流程提交接口(自定义表单设计器)
-     *
-     * @param flowCode
-     *            流程业务关联 例如:joa_leave_01
-     * @param id
-     *            表单业务数据data id
-     * @param formUrl
-     *            流程审批时附件页面默认展示的PC端表单组件(地址)
-     * @param formUrlMobile
-     *            流程审批时附件页面默认展示的移动端表单组件(地址)
-     * @param username
-     *            流程发起人账号
-     * @param jsonData
-     *            Json串,额外扩展的流程变量值 【非必填】
-     * @return
-     * @throws Exception
-     */
-    @PostMapping(value = "/act/process/extActProcess/startDesFormMutilProcess")
-    Result<String> startDesFormMutilProcess(@RequestParam("flowCode") String flowCode, @RequestParam("id") String id,
-        @RequestParam("formUrl") String formUrl, @RequestParam("formUrlMobile") String formUrlMobile,
-        @RequestParam("username") String username, @RequestParam("jsonData") String jsonData) throws Exception;
-
-    /**
-     * 25. 保存流程草稿箱接口(自定义开发表单、online表单)
-     *
-     * @param flowCode
-     *            流程业务关联 例如:joa_leave_01
-     * @param id
-     *            表单业务数据data id
-     * @param formUrl
-     *            流程审批时附件页面默认展示的PC端表单组件(地址) 【非必填】
-     * @param formUrlMobile
-     *            流程审批时附件页面默认展示的移动端表单组件(地址) 【非必填】
-     * @param username
-     *            流程发起人账号
-     * @param jsonData
-     *            Json串,额外扩展的流程变量值 【非必填】
-     * @return
-     * @throws Exception
-     */
-    @PostMapping(value = "/act/process/extActProcess/saveMutilProcessDraft")
-    Result<String> saveMutilProcessDraft(@RequestParam("flowCode") String flowCode, @RequestParam("id") String id,
-        @RequestParam("formUrl") String formUrl, @RequestParam("formUrlMobile") String formUrlMobile,
-        @RequestParam("username") String username, @RequestParam("jsonData") String jsonData) throws Exception;
-
-}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java
deleted file mode 100644
index 6546be5..0000000
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/factory/BpmBaseExtAPIFallbackFactory.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.jeecg.common.bpm.api.factory;
-
-import org.jeecg.common.bpm.api.IBpmBaseExtAPI;
-import org.jeecg.common.bpm.api.fallback.BpmBaseExtAPIFallback;
-import org.springframework.stereotype.Component;
-
-import feign.hystrix.FallbackFactory;
-
-@Component
-public class BpmBaseExtAPIFallbackFactory implements FallbackFactory<IBpmBaseExtAPI> {
-
-    @Override
-    public IBpmBaseExtAPI create(Throwable throwable) {
-        BpmBaseExtAPIFallback fallback = new BpmBaseExtAPIFallback();
-        fallback.setCause(throwable);
-        return fallback;
-    }
-}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java
deleted file mode 100644
index b0ddadc..0000000
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/bpm/api/fallback/BpmBaseExtAPIFallback.java
+++ /dev/null
@@ -1,42 +0,0 @@
-package org.jeecg.common.bpm.api.fallback;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.bpm.api.IBpmBaseExtAPI;
-import org.jeecg.common.online.api.IOnlineBaseExtAPI;
-import org.jeecg.common.system.vo.DictModel;
-
-import com.alibaba.fastjson.JSONObject;
-
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * 进入fallback的方法 检查是否token未设置
- */
-@Slf4j
-public class BpmBaseExtAPIFallback implements IBpmBaseExtAPI {
-
-    @Setter
-    private Throwable cause;
-
-    @Override
-    public Result<String> startMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile,
-        String username, String jsonData) throws Exception {
-        return null;
-    }
-
-    @Override
-    public Result<String> startDesFormMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile,
-        String username, String jsonData) throws Exception {
-        return null;
-    }
-
-    @Override
-    public Result<String> saveMutilProcessDraft(String flowCode, String id, String formUrl, String formUrlMobile,
-        String username, String jsonData) throws Exception {
-        return null;
-    }
-}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java
index f3e0751..6627bb3 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-cloud-api/src/main/java/org/jeecg/common/online/api/IOnlineBaseExtAPI.java
@@ -15,7 +15,8 @@ import java.util.Map;
  * 【Online】Feign API接口
  */
 @Component
-@FeignClient(contextId = "onlineBaseRemoteApi", value = ServiceNameConstants.SYSTEM_ONLINE, fallbackFactory = OnlineBaseExtAPIFallbackFactory.class)
+@FeignClient(contextId = "onlineBaseRemoteApi", value = ServiceNameConstants.SYSTEM_SERVICE, fallbackFactory = OnlineBaseExtAPIFallbackFactory.class)
+//@FeignClient(contextId = "onlineBaseRemoteApi", value = ServiceNameConstants.SYSTEM_ONLINE, fallbackFactory = OnlineBaseExtAPIFallbackFactory.class)
 public interface IOnlineBaseExtAPI {
 
     /**
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml
index 4b9210c..89c8d3f 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-base-api</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java
deleted file mode 100644
index c1db8ae..0000000
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/jeecg-system-local-api/src/main/java/org/jeecg/common/bpm/api/IBpmBaseExtAPI.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package org.jeecg.common.bpm.api;
-
-import java.util.List;
-import java.util.Map;
-
-import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.system.vo.DictModel;
-
-import com.alibaba.fastjson.JSONObject;
-
-/**
- * 流程接口
- *
- * @author scott
- */
-public interface IBpmBaseExtAPI {
-    /**
-     *  23. 流程提交接口(online,自定义开发)
-     * @param flowCode 流程业务关联 例如:joa_leave_01
-     * @param id 表单业务数据data id
-     * @param formUrl 	流程审批时附件页面默认展示的PC端表单组件(地址)
-     * @param formUrlMobile  流程审批时附件页面默认展示的移动端表单组件(地址)
-     * @param username  流程发起人账号
-     * @param jsonData  Json串,额外扩展的流程变量值  【非必填】
-     * @return
-     * @throws Exception
-     */
-    Result<String> startMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile,String username, String jsonData) throws Exception;
-
-    /**
-     *  24. 流程提交接口(自定义表单设计器)
-     * @param flowCode 流程业务关联 例如:joa_leave_01
-     * @param id 表单业务数据data id
-     * @param formUrl 	流程审批时附件页面默认展示的PC端表单组件(地址)
-     * @param formUrlMobile  流程审批时附件页面默认展示的移动端表单组件(地址)
-     * @param username  流程发起人账号
-     * @param jsonData  Json串,额外扩展的流程变量值  【非必填】
-     * @return
-     * @throws Exception
-     */
-    Result<String> startDesFormMutilProcess(String flowCode, String id, String formUrl, String formUrlMobile,String username,String jsonData) throws Exception;
-    /**
-     * 25. 保存流程草稿箱接口(自定义开发表单、online表单)
-     * @param flowCode 流程业务关联 例如:joa_leave_01
-     * @param id 表单业务数据data id
-     * @param formUrl 	流程审批时附件页面默认展示的PC端表单组件(地址) 【非必填】
-     * @param formUrlMobile  流程审批时附件页面默认展示的移动端表单组件(地址)  【非必填】
-     * @param username  流程发起人账号
-     * @param jsonData  Json串,额外扩展的流程变量值  【非必填】
-     * @return
-     * @throws Exception
-     */
-    Result<String> saveMutilProcessDraft(String flowCode, String id, String formUrl, String formUrlMobile,String username,String jsonData) throws Exception;
-
-}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml
index a6f3df9..9218f19 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-api/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-base</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml
index 1599982..15c9936 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/pom.xml
@@ -4,7 +4,7 @@
 	<parent>
 		<groupId>org.jeecgframework.boot</groupId>
 		<artifactId>jeecg-boot-base</artifactId>
-		<version>3.0</version>
+		<version>3.1.0</version>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
 
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java
index 59f4813..a679baf 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/api/vo/Result.java
@@ -103,6 +103,7 @@ public class Result<T> implements Serializable {
 		return r;
 	}
 
+	@Deprecated
 	public static<T> Result<T> OK(String msg) {
 		Result<T> r = new Result<T>();
 		r.setSuccess(true);
@@ -157,6 +158,7 @@ public class Result<T> implements Serializable {
 		this.success = false;
 		return this;
 	}
+
 	/**
 	 * 无权限访问返回结果
 	 */
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java
index bcca2d7..2357607 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/AutoLogAspect.java
@@ -88,7 +88,7 @@ public class AutoLogAspect {
 
 
         //设置操作类型
-        if (dto.getLogType() == CommonConstant.LOG_TYPE_2) {
+        if (CommonConstant.LOG_TYPE_2 == dto.getLogType()) {
             dto.setOperateType(getOperateType(methodName, syslog.operateType()));
         }
 
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java
index c3175cc..abe49f1 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/DictAspect.java
@@ -2,6 +2,7 @@ package org.jeecg.common.aspect;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.parser.Feature;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.fasterxml.jackson.annotation.JsonFormat;
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -18,6 +19,7 @@ import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.vo.DictModel;
 import org.jeecg.common.util.oConvertUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.util.StringUtils;
@@ -38,14 +40,14 @@ import java.util.stream.Collectors;
 @Component
 @Slf4j
 public class DictAspect {
-
+    @Lazy
     @Autowired
     private CommonAPI commonAPI;
     @Autowired
     public RedisTemplate redisTemplate;
 
     // 定义切点Pointcut
-    @Pointcut("execution(public * org.jeecg.modules..*.*Controller.*(..))")
+    @Pointcut("execution(public * org.jeecg.modules..*.*Controller.*(..)) || @annotation(org.jeecg.common.aspect.annotation.AutoDict)")
     public void excudeService() {
     }
 
@@ -103,7 +105,10 @@ public class DictAspect {
                     } catch (JsonProcessingException e) {
                         log.error("json解析失败"+e.getMessage(),e);
                     }
-                    JSONObject item = JSONObject.parseObject(json);
+                    //update-begin--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
+                    JSONObject item = JSONObject.parseObject(json, Feature.OrderedField);
+                    //update-end--Author:scott -- Date:20211223 ----for:【issues/3303】restcontroller返回json数据后key顺序错乱 -----
+
                     //update-begin--Author:scott -- Date:20190603 ----for:解决继承实体字段无法翻译问题------
                     //for (Field field : record.getClass().getDeclaredFields()) {
                     // 遍历所有字段,把字典Code取出来,放到 map 里
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java
index 2ba5122..34687f7 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/PermissionDataAspect.java
@@ -8,6 +8,7 @@ import org.aspectj.lang.annotation.Pointcut;
 import org.aspectj.lang.reflect.MethodSignature;
 import org.jeecg.common.api.CommonAPI;
 import org.jeecg.common.aspect.annotation.PermissionData;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.util.JeecgDataAutorUtils;
 import org.jeecg.common.system.util.JwtUtil;
 import org.jeecg.common.system.vo.SysPermissionDataRuleModel;
@@ -15,6 +16,7 @@ import org.jeecg.common.system.vo.SysUserCacheInfo;
 import org.jeecg.common.util.SpringContextUtils;
 import org.jeecg.common.util.oConvertUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Component;
 
 import javax.servlet.http.HttpServletRequest;
@@ -31,7 +33,7 @@ import java.util.List;
 @Component
 @Slf4j
 public class PermissionDataAspect {
-
+    @Lazy
     @Autowired
     private CommonAPI commonAPI;
 
@@ -47,11 +49,21 @@ public class PermissionDataAspect {
         Method method = signature.getMethod();
         PermissionData pd = method.getAnnotation(PermissionData.class);
         String component = pd.pageComponent();
-
         String requestMethod = request.getMethod();
         String requestPath = request.getRequestURI().substring(request.getContextPath().length());
         requestPath = filterUrl(requestPath);
-        log.debug("拦截请求 >> "+requestPath+";请求类型 >> "+requestMethod);
+        //update-begin-author:taoyan date:20211027 for:JTC-132【online报表权限】online报表带参数的菜单配置数据权限无效
+        //先判断是否online报表请求
+        // TODO 参数顺序调整有隐患
+        if(requestPath.indexOf(UrlMatchEnum.CGREPORT_DATA.getMatch_url())>=0){
+            // 获取地址栏参数
+            String urlParamString = request.getParameter(CommonConstant.ONL_REP_URL_PARAM_STR);
+            if(oConvertUtils.isNotEmpty(urlParamString)){
+                requestPath+="?"+urlParamString;
+            }
+        }
+        //update-end-author:taoyan date:20211027 for:JTC-132【online报表权限】online报表带参数的菜单配置数据权限无效
+        log.info("拦截请求 >> {} ; 请求类型 >> {} . ", requestPath, requestMethod);
         String username = JwtUtil.getUserNameByToken(request);
         //查询数据权限信息
         //TODO 微服务情况下也得支持缓存机制
@@ -86,6 +98,7 @@ public class PermissionDataAspect {
      * @param request
      * @return
      */
+    @Deprecated
     private String getJgAuthRequsetPath(HttpServletRequest request) {
         String queryString = request.getQueryString();
         String requestPath = request.getRequestURI();
@@ -106,6 +119,7 @@ public class PermissionDataAspect {
         return filterUrl(requestPath);
     }
 
+    @Deprecated
     private boolean moHuContain(List<String> list,String key){
         for(String str : list){
             if(key.contains(str)){
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/UrlMatchEnum.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/UrlMatchEnum.java
index 8e3c211..4407fce 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/UrlMatchEnum.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/UrlMatchEnum.java
@@ -10,8 +10,8 @@ public enum UrlMatchEnum {
     CGFORM_EXCEL_DATA("/online/cgform/api/exportXls/", "/online/cgformList/"),
     CGFORM_TREE_DATA("/online/cgform/api/getTreeData/", "/online/cgformList/"),
     CGREPORT_DATA("/online/cgreport/api/getColumnsAndData/", "/online/cgreport/"),
-    CGREPORT_EXCEL_DATA("/online/cgreport/api/exportXls/", "/online/cgreport/");
-
+    CGREPORT_EXCEL_DATA("/online/cgreport/api/exportXls/", "/online/cgreport/"),
+    CGREPORT_EXCEL_DATA2("/online/cgreport/api/exportManySheetXls/", "/online/cgreport/");
 
     UrlMatchEnum(String url, String match_url) {
         this.url = url;
@@ -47,8 +47,10 @@ public enum UrlMatchEnum {
         return null;
     }
 
-
-//    public static void main(String[] args) {
+    public String getMatch_url() {
+        return match_url;
+    }
+    //    public static void main(String[] args) {
 //        /**
 //         * 比如request真实请求URL: /online/cgform/api/getData/81fcf7d8922d45069b0d5ba983612d3a
 //         * 转换匹配路由URL后(对应配置的菜单路径):/online/cgformList/81fcf7d8922d45069b0d5ba983612d3a
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoDict.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoDict.java
new file mode 100644
index 0000000..a6537cb
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoDict.java
@@ -0,0 +1,23 @@
+package org.jeecg.common.aspect.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 通过此注解声明的接口,自动实现字典翻译
+ * 
+ * @Author scott
+ * @email jeecgos@163.com
+ * @Date 2022年01月05日
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface AutoDict {
+
+	/**
+	 * 暂时无用
+	 * @return
+	 */
+	String value() default "";
+
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoLowApp.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoLowApp.java
new file mode 100644
index 0000000..2b3ded9
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/aspect/annotation/AutoLowApp.java
@@ -0,0 +1,33 @@
+package org.jeecg.common.aspect.annotation;
+
+import java.lang.annotation.*;
+
+import org.jeecg.common.constant.enums.LowAppAopEnum;
+
+/**
+ * 自动注入low_app_id
+ * 
+ * @Author scott
+ * @email jeecgos@163.com
+ * @Date 2022年01月05日
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface AutoLowApp {
+
+	/**
+	 * 切面类型(add、delete、db_import等其他操作)
+	 *
+	 * @return
+	 */
+	LowAppAopEnum action();
+
+	/**
+	 * 业务类型(cgform等)
+	 *
+	 * @return
+	 */
+	String bizType();
+
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
index f0805a2..a53929c 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/CommonConstant.java
@@ -77,7 +77,13 @@ public interface CommonConstant {
     public static final String PREFIX_USER_TOKEN  = "prefix_user_token_";
     /** Token缓存时间:3600秒即一小时 */
     public static final int  TOKEN_EXPIRE_TIME  = 3600;
-    
+
+    /** 登录二维码 */
+    public static final String  LOGIN_QRCODE_PRE  = "QRCODELOGIN:";
+    public static final String  LOGIN_QRCODE  = "LQ:";
+    /** 登录二维码token */
+    public static final String  LOGIN_QRCODE_TOKEN  = "LQT:";
+
 
     /**
      *  0:一级菜单
@@ -91,7 +97,7 @@ public interface CommonConstant {
      *  2:按钮权限
      */
     public static final Integer MENU_TYPE_2  = 2;
-    
+
     /**通告对象类型(USER:指定用户,ALL:全体用户)*/
     public static final String MSG_TYPE_UESR  = "USER";
     public static final String MSG_TYPE_ALL  = "ALL";
@@ -229,6 +235,9 @@ public interface CommonConstant {
     public static final String SQL_INDEX_UNIQ_SYS_USER_WORK_NO = "uniq_sys_user_work_no";
     /** sys_user 表 phone 唯一键索引 */
     public static final String SQL_INDEX_UNIQ_SYS_USER_PHONE = "uniq_sys_user_phone";
+    /** 达梦数据库升提示。违反表[SYS_USER]唯一性约束 */
+    public static final String SQL_INDEX_UNIQ_SYS_USER = "唯一性约束";
+
     /** sys_user 表 email 唯一键索引 */
     public static final String SQL_INDEX_UNIQ_SYS_USER_EMAIL = "uniq_sys_user_email";
     /** sys_quartz_job 表 job_class_name 唯一键索引 */
@@ -239,6 +248,8 @@ public interface CommonConstant {
     public static final String SQL_INDEX_UNIQ_SYS_ROLE_CODE = "uniq_sys_role_role_code";
     /** sys_depart 表 code 唯一键索引 */
     public static final String SQL_INDEX_UNIQ_DEPART_ORG_CODE = "uniq_depart_org_code";
+    /** sys_category 表 code 唯一键索引 */
+    public static final String SQL_INDEX_UNIQ_CATEGORY_CODE = "idx_sc_code";
     /**
      * 在线聊天 是否为默认分组
      */
@@ -325,4 +336,7 @@ public interface CommonConstant {
     /** 系统通告消息状态:2=已撤销 */
     String ANNOUNCEMENT_SEND_STATUS_2 = "2";
 
+    /**ONLINE 报表权限用 从request中获取地址栏后的参数*/
+    String ONL_REP_URL_PARAM_STR="onlRepUrlParamStr";
+
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java
index b4d7bc2..44fe009 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/ProvinceCityArea.java
@@ -29,7 +29,7 @@ public class ProvinceCityArea {
 
     public String getCode(String text){
         this.initAreaList();
-        if(areaList!=null || areaList.size()>0){
+        if(areaList!=null && areaList.size()>0){
             for(int i=areaList.size()-1;i>=0;i--){
                 if(text.indexOf(areaList.get(i).getText())>=0){
                     return areaList.get(i).getId();
@@ -39,6 +39,73 @@ public class ProvinceCityArea {
         return null;
     }
 
+    // update-begin-author:sunjianlei date:20220121 for:【JTC-704】数据导入错误 省市区组件,文件中为北京市,导入后,导为了山西省
+    /**
+     * 获取省市区code,精准匹配
+     * @param texts 文本数组,省,市,区
+     * @return 返回 省市区的code
+     */
+    public String[] getCode(String[] texts) {
+        if (texts == null || texts.length == 0) {
+            return null;
+        }
+        this.initAreaList();
+        if (areaList == null || areaList.size() == 0) {
+            return null;
+        }
+        String[] codes = new String[texts.length];
+        String code = null;
+        for (int i = 0; i < texts.length; i++) {
+            String text = texts[i];
+            Area area;
+            if (code == null) {
+                area = getAreaByText(text);
+            } else {
+                area = getAreaByPidAndText(code, text);
+            }
+            if (area != null) {
+                code = area.id;
+                codes[i] = code;
+            } else {
+                return null;
+            }
+        }
+        return codes;
+    }
+
+    /**
+     * 根据text获取area
+     * @param text
+     * @return
+     */
+    public Area getAreaByText(String text) {
+        for (Area area : areaList) {
+            if (text.equals(area.getText())) {
+                return area;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 通过pid获取 area 对象
+     * @param pCode 父级编码
+     * @param text
+     * @return
+     */
+    public Area getAreaByPidAndText(String pCode, String text) {
+        this.initAreaList();
+        if (this.areaList != null && this.areaList.size() > 0) {
+            for (Area area : this.areaList) {
+                if (area.getPid().equals(pCode) && area.getText().equals(text)) {
+                    return area;
+                }
+            }
+        }
+        return null;
+    }
+    // update-end-author:sunjianlei date:20220121 for:【JTC-704】数据导入错误 省市区组件,文件中为北京市,导入后,导为了山西省
+
     public void getAreaByCode(String code,List<String> ls){
         for(Area area: areaList){
             if(area.getId().equals(code)){
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java
new file mode 100644
index 0000000..638c80b
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/LowAppAopEnum.java
@@ -0,0 +1,22 @@
+package org.jeecg.common.constant.enums;
+
+/**
+ * LowApp 切面注解枚举
+ * @date 2022-1-5
+ */
+public enum LowAppAopEnum {
+
+    /**
+     * 新增方法
+     */
+    ADD,
+    /**
+     * 删除方法(包含单个和批量删除)
+     */
+    DELETE,
+
+    /**
+     * Online表单专用:数据库表转Online表单
+     */
+    CGFORM_DB_IMPORT
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java
index 6d12c4b..dbb6548 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/constant/enums/RoleIndexConfigEnum.java
@@ -1,24 +1,20 @@
 package org.jeecg.common.constant.enums;
 
+import org.jeecg.common.util.oConvertUtils;
+
 import java.util.List;
 
 /**
  * 首页自定义
  * 通过角色编码与首页组件路径配置
+ * 枚举的顺序有权限高低权重作用(也就是配置多个角色,在前面的角色首页,会优先生效)
  */
 public enum RoleIndexConfigEnum {
-    /**
-     * 管理员
-     */
-    ADMIN("admin1", "dashboard/Analysis2"),
-    /**
-     * 测试
-     */
-    TEST("test",  "dashboard/Analysis"),
-    /**
-     * hr
-     */
-    HR("hr", "dashboard/Analysis1");
+
+    ADMIN("admin", "dashboard/Analysis"),
+    //TEST("test",  "dashboard/IndexChart"),
+    HR("hr", "dashboard/IndexBdc");
+    //DM("dm", "dashboard/IndexTask"),
 
     /**
      * 角色编码
@@ -44,7 +40,7 @@ public enum RoleIndexConfigEnum {
      * @param roleCode 角色编码
      * @return
      */
-    public static RoleIndexConfigEnum getEnumByCode(String roleCode) {
+    private static RoleIndexConfigEnum getEnumByCode(String roleCode) {
         for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) {
             if (e.roleCode.equals(roleCode)) {
                 return e;
@@ -57,7 +53,7 @@ public enum RoleIndexConfigEnum {
      * @param roleCode 角色编码
      * @return
      */
-    public static String getIndexByCode(String roleCode) {
+    private static String getIndexByCode(String roleCode) {
         for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) {
             if (e.roleCode.equals(roleCode)) {
                 return e.componentUrl;
@@ -67,11 +63,10 @@ public enum RoleIndexConfigEnum {
     }
 
     public static String getIndexByRoles(List<String> roles) {
-        for (String role : roles) {
-            for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) {
-                if (e.roleCode.equals(role)) {
-                    return e.componentUrl;
-                }
+        String[] rolesArray = roles.toArray(new String[roles.size()]);
+        for (RoleIndexConfigEnum e : RoleIndexConfigEnum.values()) {
+            if (oConvertUtils.isIn(e.roleCode,rolesArray)){
+                return e.componentUrl;
             }
         }
         return null;
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java
index 897fe77..cff9a26 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/base/controller/JeecgController.java
@@ -180,8 +180,15 @@ public class JeecgController<T, S extends IService<T>> {
                 //update-end-author:taoyan date:20190528 for:批量插入数据
                 return Result.ok("文件导入成功!数据行数:" + list.size());
             } catch (Exception e) {
-                log.error(e.getMessage(), e);
-                return Result.error("文件导入失败:" + e.getMessage());
+                //update-begin-author:taoyan date:20211124 for: 导入数据重复增加提示
+                String msg = e.getMessage();
+                log.error(msg, e);
+                if(msg!=null && msg.indexOf("Duplicate entry")>=0){
+                    return Result.error("文件导入失败:有重复数据!");
+                }else{
+                    return Result.error("文件导入失败:" + e.getMessage());
+                }
+                //update-end-author:taoyan date:20211124 for: 导入数据重复增加提示
             } finally {
                 try {
                     file.getInputStream().close();
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
index ac722af..8ff0a9f 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/query/QueryGenerator.java
@@ -25,7 +25,6 @@ import org.jeecg.common.util.oConvertUtils;
 import org.springframework.util.NumberUtils;
 
 import com.alibaba.fastjson.JSON;
-import com.baomidou.mybatisplus.annotation.DbType;
 import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 
@@ -145,20 +144,23 @@ public class QueryGenerator {
 				//区间查询
 				doIntervalQuery(queryWrapper, parameterMap, type, name, column);
 				//判断单值  参数带不同标识字符串 走不同的查询
-				//TODO 这种前后带逗号的支持分割后模糊查询需要否 使多选字段的查询生效
+				//TODO 这种前后带逗号的支持分割后模糊查询(多选字段查询生效) 示例:,1,3,
 				if (null != value && value.toString().startsWith(COMMA) && value.toString().endsWith(COMMA)) {
 					String multiLikeval = value.toString().replace(",,", COMMA);
 					String[] vals = multiLikeval.substring(1, multiLikeval.length()).split(COMMA);
 					final String field = oConvertUtils.camelToUnderline(column);
 					if(vals.length>1) {
 						queryWrapper.and(j -> {
+                            log.info("---查询过滤器,Query规则---field:{}, rule:{}, value:{}", field, "like", vals[0]);
 							j = j.like(field,vals[0]);
 							for (int k=1;k<vals.length;k++) {
 								j = j.or().like(field,vals[k]);
+								log.info("---查询过滤器,Query规则 .or()---field:{}, rule:{}, value:{}", field, "like", vals[k]);
 							}
 							//return j;
 						});
 					}else {
+						log.info("---查询过滤器,Query规则---field:{}, rule:{}, value:{}", field, "like", vals[0]);
 						queryWrapper.and(j -> j.like(field,vals[0]));
 					}
 				}else {
@@ -224,7 +226,7 @@ public class QueryGenerator {
 		if(parameterMap!=null&& parameterMap.containsKey(ORDER_TYPE)) {
 			order = parameterMap.get(ORDER_TYPE)[0];
 		}
-        log.info("排序规则>>列:" + column + ",排序方式:" + order);
+        log.debug("排序规则>>列:" + column + ",排序方式:" + order);
 		if (oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) {
 			//字典字段,去掉字典翻译文本后缀
 			if(column.endsWith(CommonConstant.DICT_TEXT_SUFFIX)) {
@@ -270,10 +272,21 @@ public class QueryGenerator {
                 if (conditions == null || conditions.size() == 0) {
                     return;
                 }
-                log.info("---高级查询参数-->" + conditions.toString());
+				// update-begin-author:sunjianlei date:20220119 for: 【JTC-573】 过滤空条件查询,防止 sql 拼接多余的 and
+				List<QueryCondition> filterConditions = conditions.stream().filter(
+						rule -> oConvertUtils.isNotEmpty(rule.getField())
+								&& oConvertUtils.isNotEmpty(rule.getRule())
+								&& oConvertUtils.isNotEmpty(rule.getVal())
+				).collect(Collectors.toList());
+				if (filterConditions.size() == 0) {
+					return;
+				}
+				// update-end-author:sunjianlei date:20220119 for: 【JTC-573】 过滤空条件查询,防止 sql 拼接多余的 and
+                log.info("---高级查询参数-->" + filterConditions);
+
                 queryWrapper.and(andWrapper -> {
-                    for (int i = 0; i < conditions.size(); i++) {
-                        QueryCondition rule = conditions.get(i);
+                    for (int i = 0; i < filterConditions.size(); i++) {
+                        QueryCondition rule = filterConditions.get(i);
                         if (oConvertUtils.isNotEmpty(rule.getField())
                                 && oConvertUtils.isNotEmpty(rule.getRule())
                                 && oConvertUtils.isNotEmpty(rule.getVal())) {
@@ -324,7 +337,7 @@ public class QueryGenerator {
 							//update-end-author:taoyan date:20201228 for: 【高级查询】 oracle 日期等于查询报错
 
                             // 如果拼接方式是OR,就拼接OR
-                            if (MatchTypeEnum.OR == matchType && i < (conditions.size() - 1)) {
+                            if (MatchTypeEnum.OR == matchType && i < (filterConditions.size() - 1)) {
                                 andWrapper.or();
                             }
                         }
@@ -457,15 +470,37 @@ public class QueryGenerator {
 	
 	private static void addQueryByRule(QueryWrapper<?> queryWrapper,String name,String type,String value,QueryRuleEnum rule) throws ParseException {
 		if(oConvertUtils.isNotEmpty(value)) {
-			Object temp;
+			//update-begin--Author:sunjianlei  Date:20220104 for:【JTC-409】修复逗号分割情况下没有转换类型,导致类型严格的数据库查询报错 -------------------
 			// 针对数字类型字段,多值查询
-			if(value.indexOf(COMMA)!=-1){
-				temp = value;
+			if(value.contains(COMMA)){
+				Object[] temp = Arrays.stream(value.split(COMMA)).map(v -> {
+					try {
+						return QueryGenerator.parseByType(v, type, rule);
+					} catch (ParseException e) {
+						e.printStackTrace();
+						return v;
+					}
+				}).toArray();
 				addEasyQuery(queryWrapper, name, rule, temp);
 				return;
 			}
+			Object temp = QueryGenerator.parseByType(value, type, rule);
+			addEasyQuery(queryWrapper, name, rule, temp);
+			//update-end--Author:sunjianlei  Date:20220104 for:【JTC-409】修复逗号分割情况下没有转换类型,导致类型严格的数据库查询报错 -------------------
+		}
+	}
 
-			switch (type) {
+	/**
+	 * 根据类型转换给定的值
+	 * @param value
+	 * @param type
+	 * @param rule
+	 * @return
+	 * @throws ParseException
+	 */
+	private static Object parseByType(String value, String type, QueryRuleEnum rule) throws ParseException {
+		Object temp;
+		switch (type) {
 			case "class java.lang.Integer":
 				temp =  Integer.parseInt(value);
 				break;
@@ -490,9 +525,8 @@ public class QueryGenerator {
 			default:
 				temp = value;
 				break;
-			}
-			addEasyQuery(queryWrapper, name, rule, temp);
 		}
+		return temp;
 	}
 	
 	/**
@@ -527,12 +561,12 @@ public class QueryGenerator {
 	 * @param rule         查询规则
 	 * @param value        查询条件值
 	 */
-	private static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {
+	public static void addEasyQuery(QueryWrapper<?> queryWrapper, String name, QueryRuleEnum rule, Object value) {
 		if (value == null || rule == null || oConvertUtils.isEmpty(value)) {
 			return;
 		}
 		name = oConvertUtils.camelToUnderline(name);
-		log.info("--查询规则-->"+name+" "+rule.getValue()+" "+value);
+		log.info("---查询过滤器,Query规则---field:{}, rule:{}, value:{}",name,rule.getValue(),value);
 		switch (rule) {
 		case GT:
 			queryWrapper.gt(name, value);
@@ -555,7 +589,7 @@ public class QueryGenerator {
 			break;
 		case IN:
 			if(value instanceof String) {
-				queryWrapper.in(name, (Object[])value.toString().split(","));
+				queryWrapper.in(name, (Object[])value.toString().split(COMMA));
 			}else if(value instanceof String[]) {
 				queryWrapper.in(name, (Object[]) value);
 			}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java
index 3daabcf..f6247d8 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/util/JwtUtil.java
@@ -34,8 +34,8 @@ import org.jeecg.common.util.oConvertUtils;
  **/
 public class JwtUtil {
 
-	// Token过期时间30分钟(用户登录过期时间是此时间的两倍,以token在reids缓存时间为准)
-	public static final long EXPIRE_TIME = 30 * 60 * 1000;
+	// Token过期时间2小时(用户登录过期时间是此时间的两倍,以token在reids缓存时间为准)
+	public static final long EXPIRE_TIME = 2 * 60 * 60 * 1000;
 
     /**
      *
@@ -155,7 +155,6 @@ public class JwtUtil {
 	 * @param user
 	 * @return
 	 */
-	//TODO 急待改造 sckjkdsjsfjdk
 	public static String getUserSystemData(String key,SysUserCacheInfo user) {
 		if(user==null) {
 			user = JeecgDataAutorUtils.loadUserInfo();
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModel.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModel.java
index 453cbe0..f0936cb 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModel.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/DictModel.java
@@ -39,5 +39,11 @@ public class DictModel implements Serializable{
 	public String getTitle() {
 		return this.text;
 	}
+	/**
+	 * 特殊用途: vue3 Select组件
+	 */
+	public String getLabel() {
+		return this.text;
+	}
 
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java
index 71c298a..c9aab4e 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/CommonUtils.java
@@ -14,6 +14,7 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource;
 import org.springframework.util.FileCopyUtils;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletRequest;
 import javax.sql.DataSource;
 import java.io.ByteArrayInputStream;
 import java.io.File;
@@ -282,4 +283,39 @@ public class CommonUtils {
         return DB_TYPE;
 
     }
+    /**
+     * 获取服务器地址
+     *
+     * @param request
+     * @return
+     */
+    public static String getBaseUrl(HttpServletRequest request) {
+        //1.【兼容】兼容微服务下的 base path-------
+        String x_gateway_base_path = request.getHeader("X_GATEWAY_BASE_PATH");
+        if(oConvertUtils.isNotEmpty(x_gateway_base_path)){
+            log.info("x_gateway_base_path = "+ x_gateway_base_path);
+            return  x_gateway_base_path;
+        }
+        //2.【兼容】SSL认证之后,request.getScheme()获取不到https的问题
+        // https://blog.csdn.net/weixin_34376986/article/details/89767950
+        String scheme = request.getHeader("X-Forwarded-Scheme");
+        if(oConvertUtils.isEmpty(scheme)){
+            scheme = request.getScheme();
+        }
+
+        //3.常规操作
+        String serverName = request.getServerName();
+        int serverPort = request.getServerPort();
+        String contextPath = request.getContextPath();
+
+        //返回 host domain
+        String baseDomainPath = null;
+        if(80 == serverPort){
+            baseDomainPath = scheme + "://" + serverName  + contextPath ;
+        }else{
+            baseDomainPath = scheme + "://" + serverName + ":" + serverPort + contextPath ;
+        }
+        log.info("-----Common getBaseUrl----- : " + baseDomainPath);
+        return baseDomainPath;
+    }
 }
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java
index e1aeac4..e96fa21 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/MinioUtil.java
@@ -1,6 +1,7 @@
 package org.jeecg.common.util;
 
 import io.minio.*;
+import io.minio.http.Method;
 import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.util.filter.FileTypeFilter;
 import org.jeecg.common.util.filter.StrAttackFilter;
@@ -158,9 +159,11 @@ public class MinioUtil {
     public static String getObjectURL(String bucketName, String objectName, Integer expires) {
         initMinio(minioUrl, minioName,minioPass);
         try{
+            //update-begin---author:liusq  Date:20220121  for:获取文件外链报错提示method不能为空,导致文件下载和预览失败----
             GetPresignedObjectUrlArgs objectArgs = GetPresignedObjectUrlArgs.builder().object(objectName)
                     .bucket(bucketName)
-                    .expiry(expires).build();
+                    .expiry(expires).method(Method.GET).build();
+            //update-begin---author:liusq  Date:20220121  for:获取文件外链报错提示method不能为空,导致文件下载和预览失败----
             String url = minioClient.getPresignedObjectUrl(objectArgs);
             return URLDecoder.decode(url,"UTF-8");
         }catch (Exception e){
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
index e4ae69a..38e2606 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/SqlInjectionUtil.java
@@ -17,7 +17,7 @@ public class SqlInjectionUtil {
 	 * (上线修改值 20200501,同步修改前端的盐值)
 	 */
 	private final static String TABLE_DICT_SIGN_SALT = "20200501";
-	private final static String xssStr = "'|and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+";
+	private final static String xssStr = "and |exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |;|or |+|user()";
 
 	/*
 	* 针对表字典进行额外的sign签名校验(增加安全机制)
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java
index 728fd82..453bc0a 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/dynamic/db/DbTypeUtils.java
@@ -25,7 +25,7 @@ public class DbTypeUtils {
         dialectMap.put("postgresql", "org.hibernate.dialect.PostgreSQLDialect"); //1  --
         dialectMap.put("sqlserver2005", "org.hibernate.dialect.SQLServer2005Dialect");
         dialectMap.put("sqlserver", "org.hibernate.dialect.SQLServerDialect"); //1
-        dialectMap.put("dm", "org.hibernate.dialect.OracleDialect");//达梦数据库 [国产] 1--
+        dialectMap.put("dm", "org.hibernate.dialect.DmDialect");//达梦数据库 [国产] 1--
         dialectMap.put("xugu", "org.hibernate.dialect.HSQLDialect"); //虚谷数据库
         dialectMap.put("kingbasees", "org.hibernate.dialect.PostgreSQLDialect");  //人大金仓 [国产] 1
         dialectMap.put("phoenix", "org.hibernate.dialect.HSQLDialect"); // Phoenix HBase数据库
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java
index 45a2fc7..f57d00f 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/common/util/oss/OssBootUtil.java
@@ -258,6 +258,9 @@ public class OssBootUtil {
                 newBucket = bucket;
             }
             initOSS(endPoint, accessKeyId, accessKeySecret);
+            //update-begin---author:liusq  Date:20220120  for:替换objectName前缀,防止key不一致导致获取不到文件----
+            objectName = OssBootUtil.replacePrefix(objectName,bucket);
+            //update-end---author:liusq  Date:20220120  for:替换objectName前缀,防止key不一致导致获取不到文件----
             OSSObject ossObject = ossClient.getObject(newBucket,objectName);
             inputStream = new BufferedInputStream(ossObject.getObjectContent());
         }catch (Exception e){
@@ -266,14 +269,14 @@ public class OssBootUtil {
         return inputStream;
     }
 
-    /**
-     * 获取文件流
-     * @param objectName
-     * @return
-     */
-    public static InputStream getOssFile(String objectName){
-        return getOssFile(objectName,null);
-    }
+    ///**
+    // * 获取文件流
+    // * @param objectName
+    // * @return
+    // */
+    //public static InputStream getOssFile(String objectName){
+    //    return getOssFile(objectName,null);
+    //}
 
     /**
      * 获取文件外链
@@ -285,6 +288,9 @@ public class OssBootUtil {
     public static String getObjectURL(String bucketName, String objectName, Date expires) {
         initOSS(endPoint, accessKeyId, accessKeySecret);
         try{
+            //update-begin---author:liusq  Date:20220120  for:替换objectName前缀,防止key不一致导致获取不到文件----
+            objectName = OssBootUtil.replacePrefix(objectName,bucketName);
+            //update-end---author:liusq  Date:20220120  for:替换objectName前缀,防止key不一致导致获取不到文件----
             if(ossClient.doesObjectExist(bucketName,objectName)){
                 URL url = ossClient.generatePresignedUrl(bucketName,objectName,expires);
                 return URLDecoder.decode(url.toString(),"UTF-8");
@@ -334,5 +340,27 @@ public class OssBootUtil {
         return FILE_URL;
     }
 
-
+    /**
+     * 替换前缀,防止key不一致导致获取不到文件
+     * @param objectName 文件上传路径 key
+     * @param customBucket 自定义桶
+     * @date 2022-01-20
+     * @author lsq
+     * @return
+     */
+    private static String replacePrefix(String objectName,String customBucket){
+        log.info("------replacePrefix---替换前---objectName:{}",objectName);
+        if(oConvertUtils.isNotEmpty(staticDomain)){
+            objectName= objectName.replace(staticDomain+"/","");
+        }else{
+            String newBucket = bucketName;
+            if(oConvertUtils.isNotEmpty(customBucket)){
+                newBucket = customBucket;
+            }
+            String path ="https://" + newBucket + "." + endPoint + "/";
+            objectName = objectName.replace(path,"");
+        }
+        log.info("------replacePrefix---替换后---objectName:{}",objectName);
+        return objectName;
+    }
 }
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/AutoPoiDictConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/AutoPoiDictConfig.java
index d56f7b4..14eaeb9 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/AutoPoiDictConfig.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/AutoPoiDictConfig.java
@@ -1,6 +1,10 @@
 package org.jeecg.config;
 
-import lombok.extern.slf4j.Slf4j;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.annotation.Resource;
+
 import org.jeecg.common.api.CommonAPI;
 import org.jeecg.common.system.vo.DictModel;
 import org.jeecg.common.util.oConvertUtils;
@@ -8,9 +12,7 @@ import org.jeecgframework.dict.service.AutoPoiDictServiceI;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.Resource;
-import java.util.ArrayList;
-import java.util.List;
+import lombok.extern.slf4j.Slf4j;
 
 /**
  * 描述:AutoPoi Excel注解支持字典参数设置
@@ -25,6 +27,9 @@ import java.util.List;
 @Slf4j
 @Service
 public class AutoPoiDictConfig implements AutoPoiDictServiceI {
+	final static String EXCEL_SPLIT_TAG = "_";
+	final static String TEMP_EXCEL_SPLIT_TAG = "---";
+
 	@Lazy
 	@Resource
 	private CommonAPI commonAPI;
@@ -53,7 +58,14 @@ public class AutoPoiDictConfig implements AutoPoiDictServiceI {
 		}
 		for (DictModel t : dictList) {
 			if(t!=null){
-				dictReplaces.add(t.getText() + "_" + t.getValue());
+				//update-begin---author:scott   Date:20211220  for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析---
+				if(t.getValue().contains(EXCEL_SPLIT_TAG)){
+					String val = t.getValue().replace(EXCEL_SPLIT_TAG,TEMP_EXCEL_SPLIT_TAG);
+					dictReplaces.add(t.getText() + EXCEL_SPLIT_TAG + val);
+				}else{
+					dictReplaces.add(t.getText() + EXCEL_SPLIT_TAG + t.getValue());
+				}
+				//update-end---author:20211220     Date:20211220  for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析---
 			}
 		}
 		if (dictReplaces != null && dictReplaces.size() != 0) {
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeeccgBaseConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeeccgBaseConfig.java
index f1fb951..adecdd3 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeeccgBaseConfig.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/JeeccgBaseConfig.java
@@ -1,5 +1,6 @@
 package org.jeecg.config;
 
+import org.jeecg.config.vo.Shiro;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 
@@ -14,6 +15,15 @@ public class JeeccgBaseConfig {
      * 是否启用安全模式
      */
     private Boolean safeMode = false;
+    /**
+     * shiro拦截排除
+     */
+    private Shiro shiro;
+    /**
+     * 签名密钥串(字典等敏感接口)
+     * @TODO 降低使用成本加的默认值,实际以 yml配置 为准
+     */
+    private String signatureSecret = "dd05f1c54d63749eda95f9fa6d49v442a";
 
     public Boolean getSafeMode() {
         return safeMode;
@@ -22,4 +32,20 @@ public class JeeccgBaseConfig {
     public void setSafeMode(Boolean safeMode) {
         this.safeMode = safeMode;
     }
+
+    public String getSignatureSecret() {
+        return signatureSecret;
+    }
+
+    public void setSignatureSecret(String signatureSecret) {
+        this.signatureSecret = signatureSecret;
+    }
+
+    public Shiro getShiro() {
+        return shiro;
+    }
+
+    public void setShiro(Shiro shiro) {
+        this.shiro = shiro;
+    }
 }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java
index ba1a475..b6e7b0c 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/StaticConfig.java
@@ -20,11 +20,11 @@ public class StaticConfig {
     @Value(value = "${spring.mail.username}")
     private String emailFrom;
 
-    /**
-     * 签名密钥串
-     */
-    @Value(value = "${jeecg.signatureSecret}")
-    private String signatureSecret;
+//    /**
+//     * 签名密钥串
+//     */
+//    @Value(value = "${jeecg.signatureSecret}")
+//    private String signatureSecret;
 
 
     /*@Bean
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
index 468cc2d..c49b753 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroConfig.java
@@ -1,3 +1,4 @@
+
 package org.jeecg.config.shiro;
 
 import lombok.extern.slf4j.Slf4j;
@@ -15,6 +16,7 @@ import org.crazycake.shiro.RedisClusterManager;
 import org.crazycake.shiro.RedisManager;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.util.oConvertUtils;
+import org.jeecg.config.JeeccgBaseConfig;
 import org.jeecg.config.shiro.filters.CustomShiroFilterFactoryBean;
 import org.jeecg.config.shiro.filters.JwtFilter;
 import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
@@ -43,13 +45,12 @@ import java.util.*;
 @Configuration
 public class ShiroConfig {
 
-    @Value("${jeecg.shiro.excludeUrls}")
-    private String excludeUrls;
     @Resource
     LettuceConnectionFactory lettuceConnectionFactory;
     @Autowired
     private Environment env;
-
+    @Autowired
+    JeeccgBaseConfig jeeccgBaseConfig;
 
     /**
      * Filter Chain定义说明
@@ -64,8 +65,9 @@ public class ShiroConfig {
         shiroFilterFactoryBean.setSecurityManager(securityManager);
         // 拦截器
         Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
-        if(oConvertUtils.isNotEmpty(excludeUrls)){
-            String[] permissionUrl = excludeUrls.split(",");
+        String shiroExcludeUrls = jeeccgBaseConfig.getShiro().getExcludeUrls();
+        if(oConvertUtils.isNotEmpty(shiroExcludeUrls)){
+            String[] permissionUrl = shiroExcludeUrls.split(",");
             for(String url : permissionUrl){
                 filterChainDefinitionMap.put(url,"anon");
             }
@@ -89,6 +91,12 @@ public class ShiroConfig {
         filterChainDefinitionMap.put("/sys/common/static/**", "anon");//图片预览 &下载文件不限制token
         filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");//pdf预览
         filterChainDefinitionMap.put("/generic/**", "anon");//pdf预览需要文件
+
+        filterChainDefinitionMap.put("/sys/getLoginQrcode/**", "anon"); //登录二维码
+        filterChainDefinitionMap.put("/sys/getQrcodeToken/**", "anon"); //监听扫码
+        filterChainDefinitionMap.put("/sys/checkAuth", "anon"); //授权接口排除
+
+
         filterChainDefinitionMap.put("/", "anon");
         filterChainDefinitionMap.put("/doc.html", "anon");
         filterChainDefinitionMap.put("/**/*.js", "anon");
@@ -130,6 +138,9 @@ public class ShiroConfig {
         filterChainDefinitionMap.put("/newsWebsocket/**", "anon");//CMS模块
         filterChainDefinitionMap.put("/vxeSocket/**", "anon");//JVxeTable无痕刷新示例
 
+        //wps
+        filterChainDefinitionMap.put("/v1/**","anon");
+
         //性能监控  TODO 存在安全漏洞泄露TOEKN(durid连接池也有)
         filterChainDefinitionMap.put("/actuator/**", "anon");
 
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
index 01cd937..6ae2094 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/shiro/ShiroRealm.java
@@ -137,9 +137,12 @@ public class ShiroRealm extends AuthorizingRealm {
         if(oConvertUtils.isNotEmpty(userTenantIds)){
             String contextTenantId = TenantContext.getTenant();
             if(oConvertUtils.isNotEmpty(contextTenantId) && !"0".equals(contextTenantId)){
-                if(String.join(",",userTenantIds).indexOf(contextTenantId)<0){
+                //update-begin-author:taoyan date:20211227 for: /issues/I4O14W 用户租户信息变更判断漏洞
+                String[] arr = userTenantIds.split(",");
+                if(!oConvertUtils.isIn(contextTenantId, arr)){
                     throw new AuthenticationException("用户租户信息变更,请重新登陆!");
                 }
+                //update-end-author:taoyan date:20211227 for: /issues/I4O14W 用户租户信息变更判断漏洞
             }
         }
         //update-end-author:taoyan date:20210609 for:校验用户的tenant_id和前端传过来的是否一致
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
index 5b4b170..16097d6 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/sign/util/SignUtil.java
@@ -5,7 +5,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.exception.JeecgBootException;
 import org.jeecg.common.util.SpringContextUtils;
 import org.jeecg.common.util.oConvertUtils;
-import org.jeecg.config.StaticConfig;
+import org.jeecg.config.JeeccgBaseConfig;
 import org.springframework.util.DigestUtils;
 import org.springframework.util.StringUtils;
 
@@ -46,8 +46,9 @@ public class SignUtil {
         params.remove("_t");
         String paramsJsonStr = JSONObject.toJSONString(params);
         log.info("Param paramsJsonStr : {}", paramsJsonStr);
-        StaticConfig staticConfig = SpringContextUtils.getBean(StaticConfig.class);
-        String signatureSecret = staticConfig.getSignatureSecret();
+        //设置签名秘钥
+        JeeccgBaseConfig jeeccgBaseConfig = SpringContextUtils.getBean(JeeccgBaseConfig.class);
+        String signatureSecret = jeeccgBaseConfig.getSignatureSecret();
         if(oConvertUtils.isEmpty(signatureSecret) || signatureSecret.contains("${")){
             throw new JeecgBootException("签名密钥 ${jeecg.signatureSecret} 缺少配置 !!");
         }
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Shiro.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Shiro.java
new file mode 100644
index 0000000..bcb8710
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-core/src/main/java/org/jeecg/config/vo/Shiro.java
@@ -0,0 +1,18 @@
+package org.jeecg.config.vo;
+
+/**
+ * @Description: TODO
+ * @author: scott
+ * @date: 2022年01月21日 14:23
+ */
+public class Shiro {
+    private String excludeUrls = "";
+
+    public String getExcludeUrls() {
+        return excludeUrls;
+    }
+
+    public void setExcludeUrls(String excludeUrls) {
+        this.excludeUrls = excludeUrls;
+    }
+}
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml
index fcd8479..446b212 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/pom.xml
@@ -4,7 +4,7 @@
     <parent>
         <groupId>org.jeecgframework.boot</groupId>
         <artifactId>jeecg-boot-base</artifactId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <description>公共模块</description>
diff --git a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java
index 1926062..ab11545 100644
--- a/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java
+++ b/jeecg-boot/jeecg-boot-base/jeecg-boot-base-tools/src/main/java/org/jeecg/common/constant/CacheConstant.java
@@ -96,4 +96,8 @@ public interface CacheConstant {
 	 * online图表
 	 */
 	public static final String ONLINE_GRAPH = "sys:cache:online:graph";
+	/**
+	 * 拖拽页面信息缓存
+	 */
+	public static final String DRAG_PAGE_CACHE = "drag:cache:page";
 }
diff --git a/jeecg-boot/jeecg-boot-base/pom.xml b/jeecg-boot/jeecg-boot-base/pom.xml
index b8e031c..5768ee1 100644
--- a/jeecg-boot/jeecg-boot-base/pom.xml
+++ b/jeecg-boot/jeecg-boot-base/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-parent</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/jeecg-boot/jeecg-boot-module-demo/pom.xml b/jeecg-boot/jeecg-boot-module-demo/pom.xml
index 05aa954..37affda 100644
--- a/jeecg-boot/jeecg-boot-module-demo/pom.xml
+++ b/jeecg-boot/jeecg-boot-module-demo/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-parent</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/mock/MockController.java b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/mock/MockController.java
index b5bf0ed..668b49f 100644
--- a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/mock/MockController.java
+++ b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/mock/MockController.java
@@ -31,7 +31,7 @@ public class MockController {
 	 * @return
 	 */
 	@RequestMapping(value = "/json/{filename}", method = RequestMethod.GET)
-	public String getJsonData(@PathVariable String filename) {
+	public String getJsonData(@PathVariable("filename") String filename) {
 		String jsonpath = "classpath:org/jeecg/modules/demo/mock/json/"+filename+".json";
 		return readJson(jsonpath);
 	}
diff --git a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/online/OnlCgformDemoController.java b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/online/OnlCgformDemoController.java
new file mode 100644
index 0000000..fe2dd68
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/online/OnlCgformDemoController.java
@@ -0,0 +1,117 @@
+package org.jeecg.modules.demo.online;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.vo.DictModel;
+import org.jeecg.common.util.oConvertUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Online表单开发 demo 示例
+ *
+ * @author sunjianlei
+ * @date 2021-12-16
+ */
+@Slf4j
+@RestController("onlCgformDemoController")
+@RequestMapping("/demo/online/cgform")
+public class OnlCgformDemoController {
+
+    /**
+     * Online表单 http 增强,list增强示例
+     * @param params
+     * @return
+     */
+    @PostMapping("/enhanceJavaListHttp")
+    public Result<?> enhanceJavaListHttp(@RequestBody JSONObject params) {
+        log.info(" --- params:" + params.toJSONString());
+        JSONArray dataList = params.getJSONArray("dataList");
+        List<DictModel> dict = virtualDictData();
+        for (int i = 0; i < dataList.size(); i++) {
+            JSONObject record = dataList.getJSONObject(i);
+            String province = record.getString("province");
+            if (province == null) {
+                continue;
+            }
+            String text = dict.stream()
+                    .filter(p -> province.equals(p.getValue()))
+                    .map(DictModel::getText)
+                    .findAny()
+                    .orElse(province);
+            record.put("province", text);
+        }
+        Result<?> res = Result.OK(dataList);
+        res.setCode(1);
+        return res;
+    }
+
+    /**
+     * 模拟字典数据
+     *
+     * @return
+     */
+    private List<DictModel> virtualDictData() {
+        List<DictModel> dict = new ArrayList<>();
+        dict.add(new DictModel("bj", "北京"));
+        dict.add(new DictModel("sd", "山东"));
+        dict.add(new DictModel("ah", "安徽"));
+        return dict;
+    }
+
+
+    /**
+     * Online表单 http 增强,add、edit增强示例
+     * @param params
+     * @return
+     */
+    @PostMapping("/enhanceJavaHttp")
+    public Result<?> enhanceJavaHttp(@RequestBody JSONObject params) {
+        log.info(" --- params:" + params.toJSONString());
+        String tableName = params.getString("tableName");
+        JSONObject record = params.getJSONObject("record");
+        /*
+         * 业务场景一: 获取提交表单数据,进行其他业务关联操作
+         * (比如:根据入库单,同步更改库存)
+         */
+        log.info(" --- tableName:" + tableName);
+        log.info(" --- 行数据:" + record.toJSONString());
+        /*
+         * 业务场景二: 保存数据之前进行数据的校验
+         * 直接返回错误状态即可
+         */
+        String phone = record.getString("phone");
+        if (oConvertUtils.isEmpty(phone)) {
+            return Result.error("手机号不能为空!");
+        }
+        /*
+         * 业务场景三: 保存数据之对数据的处理
+         * 直接操作 record 即可
+         */
+        record.put("phone", "010-" + phone);
+
+        /* 其他业务场景自行实现 */
+
+        // 返回场景一: 不对 record 做任何修改的情况下,可以直接返回 code,
+        // 返回 0 = 丢弃当前数据
+        // 返回 1 = 新增当前数据
+        // 返回 2 = 修改当前数据 TODO(?)存疑
+//		 return Result.OK(1);
+
+        // 返回场景二: 需要对 record 做修改的情况下,需要返回一个JSONObject对象(或者Map也行)
+        JSONObject res = new JSONObject();
+        res.put("code", 1);
+        // 将 record 返回以进行修改
+        res.put("record", record);
+        // TODO 不要 code 的概念
+        return Result.OK(res);
+    }
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java
index 5a1877e..cde438c 100644
--- a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java
+++ b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgDemoController.java
@@ -62,6 +62,7 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
     public Result<?> list(JeecgDemo jeecgDemo, @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo, @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
                           HttpServletRequest req) {
         QueryWrapper<JeecgDemo> queryWrapper = QueryGenerator.initQueryWrapper(jeecgDemo, req.getParameterMap());
+        queryWrapper.orderByDesc("create_time");
         Page<JeecgDemo> page = new Page<JeecgDemo>(pageNo, pageSize);
 
         IPage<JeecgDemo> pageList = jeecgDemoService.page(page, queryWrapper);
@@ -92,9 +93,9 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
      * @param jeecgDemo
      * @return
      */
-    @PutMapping(value = "/edit")
-    @ApiOperation(value = "编辑DEMO", notes = "编辑DEMO")
     @AutoLog(value = "编辑DEMO", operateType = CommonConstant.OPERATE_TYPE_3)
+    @ApiOperation(value = "编辑DEMO", notes = "编辑DEMO")
+    @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
     public Result<?> edit(@RequestBody JeecgDemo jeecgDemo) {
         jeecgDemoService.updateById(jeecgDemo);
         return Result.OK("更新成功!");
@@ -316,5 +317,9 @@ public class JeecgDemoController extends JeecgController<JeecgDemo, IJeecgDemoSe
         return Result.OK("1");
     }
 
+    @GetMapping(value = "/hello")
+    public String hello(HttpServletRequest req) {
+        return "hello world!";
+    }
 
 }
diff --git a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderErpMainController.java b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderErpMainController.java
new file mode 100644
index 0000000..9b02a9a
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderErpMainController.java
@@ -0,0 +1,256 @@
+package org.jeecg.modules.demo.test.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.modules.demo.test.entity.JeecgOrderCustomer;
+import org.jeecg.modules.demo.test.entity.JeecgOrderMain;
+import org.jeecg.modules.demo.test.entity.JeecgOrderTicket;
+import org.jeecg.modules.demo.test.service.IJeecgOrderCustomerService;
+import org.jeecg.modules.demo.test.service.IJeecgOrderMainService;
+import org.jeecg.modules.demo.test.service.IJeecgOrderTicketService;
+import org.jeecg.modules.demo.test.vo.JeecgOrderMainPage;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.Arrays;
+
+/**
+ * @Description: 一对多示例(ERP TAB风格)
+ * @Author: ZhiLin
+ * @Date: 2019-02-20
+ * @Version: v2.0
+ */
+@Slf4j
+@RestController
+@RequestMapping("/test/order")
+public class JeecgOrderErpMainController {
+
+    @Autowired
+    private IJeecgOrderMainService jeecgOrderMainService;
+    @Autowired
+    private IJeecgOrderCustomerService jeecgOrderCustomerService;
+    @Autowired
+    private IJeecgOrderTicketService jeecgOrderTicketService;
+
+    /**
+     * 分页列表查询
+     *
+     * @param jeecgOrderMain
+     * @param pageNo
+     * @param pageSize
+     * @param req
+     * @return
+     */
+    @GetMapping(value = "/orderList")
+    public Result<?> respondePagedData(JeecgOrderMain jeecgOrderMain,
+                                       @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                       @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                       HttpServletRequest req) {
+        QueryWrapper<JeecgOrderMain> queryWrapper = QueryGenerator.initQueryWrapper(jeecgOrderMain, req.getParameterMap());
+        Page<JeecgOrderMain> page = new Page<JeecgOrderMain>(pageNo, pageSize);
+        IPage<JeecgOrderMain> pageList = jeecgOrderMainService.page(page, queryWrapper);
+        return Result.ok(pageList);
+    }
+
+    /**
+     * 添加
+     *
+     * @param jeecgOrderMainPage
+     * @return
+     */
+    @PostMapping(value = "/add")
+    public Result<?> add(@RequestBody JeecgOrderMainPage jeecgOrderMainPage) {
+        JeecgOrderMain jeecgOrderMain = new JeecgOrderMain();
+        BeanUtils.copyProperties(jeecgOrderMainPage, jeecgOrderMain);
+        jeecgOrderMainService.save(jeecgOrderMain);
+        return Result.ok("添加成功!");
+    }
+
+    /**
+     * 编辑
+     *
+     * @param jeecgOrderMainPage
+     * @return
+     */
+    @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
+    public Result<?> edit(@RequestBody JeecgOrderMainPage jeecgOrderMainPage) {
+        JeecgOrderMain jeecgOrderMain = new JeecgOrderMain();
+        BeanUtils.copyProperties(jeecgOrderMainPage, jeecgOrderMain);
+        jeecgOrderMainService.updateById(jeecgOrderMain);
+        return Result.ok("编辑成功!");
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @DeleteMapping(value = "/delete")
+    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
+        jeecgOrderMainService.delMain(id);
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @DeleteMapping(value = "/deleteBatch")
+    public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+        this.jeecgOrderMainService.removeByIds(Arrays.asList(ids.split(",")));
+        return Result.ok("批量删除成功!");
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param id
+     * @return
+     */
+    @GetMapping(value = "/queryById")
+    public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
+        JeecgOrderMain jeecgOrderMain = jeecgOrderMainService.getById(id);
+        return Result.ok(jeecgOrderMain);
+    }
+
+
+    /**
+     * 通过id查询
+     *
+     * @param jeecgOrderCustomer
+     * @return
+     */
+    @GetMapping(value = "/listOrderCustomerByMainId")
+    public Result<?> queryOrderCustomerListByMainId(JeecgOrderCustomer jeecgOrderCustomer,
+                                                    @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                    @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                    HttpServletRequest req) {
+        QueryWrapper<JeecgOrderCustomer> queryWrapper = QueryGenerator.initQueryWrapper(jeecgOrderCustomer, req.getParameterMap());
+        Page<JeecgOrderCustomer> page = new Page<JeecgOrderCustomer>(pageNo, pageSize);
+        IPage<JeecgOrderCustomer> pageList = jeecgOrderCustomerService.page(page, queryWrapper);
+        return Result.ok(pageList);
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param jeecgOrderTicket
+     * @return
+     */
+    @GetMapping(value = "/listOrderTicketByMainId")
+    public Result<?> queryOrderTicketListByMainId(JeecgOrderTicket jeecgOrderTicket,
+                                                  @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                                  @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                                  HttpServletRequest req) {
+        QueryWrapper<JeecgOrderTicket> queryWrapper = QueryGenerator.initQueryWrapper(jeecgOrderTicket, req.getParameterMap());
+        Page<JeecgOrderTicket> page = new Page<JeecgOrderTicket>(pageNo, pageSize);
+        IPage<JeecgOrderTicket> pageList = jeecgOrderTicketService.page(page, queryWrapper);
+        return Result.ok(pageList);
+    }
+
+    /**
+     * 添加
+     *
+     * @param jeecgOrderCustomer
+     * @return
+     */
+    @PostMapping(value = "/addCustomer")
+    public Result<?> addCustomer(@RequestBody JeecgOrderCustomer jeecgOrderCustomer) {
+        jeecgOrderCustomerService.save(jeecgOrderCustomer);
+        return Result.ok("添加成功!");
+    }
+
+    /**
+     * 编辑
+     *
+     * @param jeecgOrderCustomer
+     * @return
+     */
+    @RequestMapping(value = "/editCustomer", method = {RequestMethod.PUT,RequestMethod.POST})
+    public Result<?> editCustomer(@RequestBody JeecgOrderCustomer jeecgOrderCustomer) {
+        jeecgOrderCustomerService.updateById(jeecgOrderCustomer);
+        return Result.ok("添加成功!");
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @DeleteMapping(value = "/deleteCustomer")
+    public Result<?> deleteCustomer(@RequestParam(name = "id", required = true) String id) {
+        jeecgOrderCustomerService.removeById(id);
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @DeleteMapping(value = "/deleteBatchCustomer")
+    public Result<?> deleteBatchCustomer(@RequestParam(name = "ids", required = true) String ids) {
+        this.jeecgOrderCustomerService.removeByIds(Arrays.asList(ids.split(",")));
+        return Result.ok("批量删除成功!");
+    }
+
+    /**
+     * 添加
+     *
+     * @param jeecgOrderTicket
+     * @return
+     */
+    @PostMapping(value = "/addTicket")
+    public Result<?> addTicket(@RequestBody JeecgOrderTicket jeecgOrderTicket) {
+        jeecgOrderTicketService.save(jeecgOrderTicket);
+        return Result.ok("添加成功!");
+    }
+
+    /**
+     * 编辑
+     *
+     * @param jeecgOrderTicket
+     * @return
+     */
+    @RequestMapping(value = "/editTicket", method = {RequestMethod.PUT,RequestMethod.POST})
+    public Result<?> editTicket(@RequestBody JeecgOrderTicket jeecgOrderTicket) {
+        jeecgOrderTicketService.updateById(jeecgOrderTicket);
+        return Result.ok("编辑成功!");
+    }
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @DeleteMapping(value = "/deleteTicket")
+    public Result<?> deleteTicket(@RequestParam(name = "id", required = true) String id) {
+        jeecgOrderTicketService.removeById(id);
+        return Result.ok("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @DeleteMapping(value = "/deleteBatchTicket")
+    public Result<?> deleteBatchTicket(@RequestParam(name = "ids", required = true) String ids) {
+        this.jeecgOrderTicketService.removeByIds(Arrays.asList(ids.split(",")));
+        return Result.ok("批量删除成功!");
+    }
+
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderMainController.java b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderMainController.java
index e6020aa..129115e 100644
--- a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderMainController.java
+++ b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderMainController.java
@@ -104,7 +104,7 @@ public class JeecgOrderMainController extends JeecgController<JeecgOrderMain, IJ
      * @param jeecgOrderMainPage
      * @return
      */
-    @PutMapping(value = "/edit")
+    @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
     public Result<?> eidt(@RequestBody JeecgOrderMainPage jeecgOrderMainPage) {
         JeecgOrderMain jeecgOrderMain = new JeecgOrderMain();
         BeanUtils.copyProperties(jeecgOrderMainPage, jeecgOrderMain);
diff --git a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderTabMainController.java b/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderTabMainController.java
deleted file mode 100644
index f5ce4c7..0000000
--- a/jeecg-boot/jeecg-boot-module-demo/src/main/java/org/jeecg/modules/demo/test/controller/JeecgOrderTabMainController.java
+++ /dev/null
@@ -1,267 +0,0 @@
-package org.jeecg.modules.demo.test.controller;
-
-import java.util.Arrays;
-import java.util.List;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.system.query.QueryGenerator;
-import org.jeecg.modules.demo.test.entity.JeecgOrderCustomer;
-import org.jeecg.modules.demo.test.entity.JeecgOrderMain;
-import org.jeecg.modules.demo.test.entity.JeecgOrderTicket;
-import org.jeecg.modules.demo.test.service.IJeecgOrderCustomerService;
-import org.jeecg.modules.demo.test.service.IJeecgOrderMainService;
-import org.jeecg.modules.demo.test.service.IJeecgOrderTicketService;
-import org.jeecg.modules.demo.test.vo.JeecgOrderMainPage;
-import org.springframework.beans.BeanUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.PutMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-
-import lombok.extern.slf4j.Slf4j;
-
-/**
- * @Description: 一对多示例(ERP TAB风格)
- * @Author: ZhiLin
- * @Date: 2019-02-20
- * @Version: v2.0
- */
-@Slf4j
-@RestController
-@RequestMapping("/test/order")
-public class JeecgOrderTabMainController {
-
-    @Autowired
-    private IJeecgOrderMainService jeecgOrderMainService;
-    @Autowired
-    private IJeecgOrderCustomerService jeecgOrderCustomerService;
-    @Autowired
-    private IJeecgOrderTicketService jeecgOrderTicketService;
-
-    /**
-     * 分页列表查询
-     *
-     * @param jeecgOrderMain
-     * @param pageNo
-     * @param pageSize
-     * @param req
-     * @return
-     */
-    @GetMapping(value = "/orderList")
-    public Result<?> respondePagedData(JeecgOrderMain jeecgOrderMain,
-                                       @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
-                                       @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
-                                       HttpServletRequest req) {
-        QueryWrapper<JeecgOrderMain> queryWrapper = QueryGenerator.initQueryWrapper(jeecgOrderMain, req.getParameterMap());
-        Page<JeecgOrderMain> page = new Page<JeecgOrderMain>(pageNo, pageSize);
-        IPage<JeecgOrderMain> pageList = jeecgOrderMainService.page(page, queryWrapper);
-        return Result.ok(pageList);
-    }
-
-    /**
-     * 添加
-     *
-     * @param jeecgOrderMainPage
-     * @return
-     */
-    @PostMapping(value = "/add")
-    public Result<?> add(@RequestBody JeecgOrderMainPage jeecgOrderMainPage) {
-        JeecgOrderMain jeecgOrderMain = new JeecgOrderMain();
-        BeanUtils.copyProperties(jeecgOrderMainPage, jeecgOrderMain);
-        jeecgOrderMainService.save(jeecgOrderMain);
-        return Result.ok("添加成功!");
-    }
-
-    /**
-     * 编辑
-     *
-     * @param jeecgOrderMainPage
-     * @return
-     */
-    @PutMapping("/edit")
-    public Result<?> edit(@RequestBody JeecgOrderMainPage jeecgOrderMainPage) {
-        JeecgOrderMain jeecgOrderMain = new JeecgOrderMain();
-        BeanUtils.copyProperties(jeecgOrderMainPage, jeecgOrderMain);
-        jeecgOrderMainService.updateById(jeecgOrderMain);
-        return Result.ok("编辑成功!");
-    }
-
-    /**
-     * 通过id删除
-     *
-     * @param id
-     * @return
-     */
-    @DeleteMapping(value = "/delete")
-    public Result<?> delete(@RequestParam(name = "id", required = true) String id) {
-        jeecgOrderMainService.delMain(id);
-        return Result.ok("删除成功!");
-    }
-
-    /**
-     * 批量删除
-     *
-     * @param ids
-     * @return
-     */
-    @DeleteMapping(value = "/deleteBatch")
-    public Result<?> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
-        this.jeecgOrderMainService.removeByIds(Arrays.asList(ids.split(",")));
-        return Result.ok("批量删除成功!");
-    }
-
-    /**
-     * 通过id查询
-     *
-     * @param id
-     * @return
-     */
-    @GetMapping(value = "/queryById")
-    public Result<?> queryById(@RequestParam(name = "id", required = true) String id) {
-        JeecgOrderMain jeecgOrderMain = jeecgOrderMainService.getById(id);
-        return Result.ok(jeecgOrderMain);
-    }
-
-
-    /**
-     * 通过id查询
-     *
-     * @param jeecgOrderCustomer
-     * @return
-     */
-    @GetMapping(value = "/listOrderCustomerByMainId")
-    public Result<?> queryOrderCustomerListByMainId(JeecgOrderCustomer jeecgOrderCustomer,
-                                                    @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
-                                                    @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
-                                                    HttpServletRequest req) {
-        QueryWrapper<JeecgOrderCustomer> queryWrapper = QueryGenerator.initQueryWrapper(jeecgOrderCustomer, req.getParameterMap());
-        Page<JeecgOrderCustomer> page = new Page<JeecgOrderCustomer>(pageNo, pageSize);
-        IPage<JeecgOrderCustomer> pageList = jeecgOrderCustomerService.page(page, queryWrapper);
-        return Result.ok(pageList);
-    }
-
-    /**
-     * 通过id查询
-     *
-     * @param jeecgOrderTicket
-     * @return
-     */
-    @GetMapping(value = "/listOrderTicketByMainId")
-    public Result<?> queryOrderTicketListByMainId(JeecgOrderTicket jeecgOrderTicket,
-                                                  @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
-                                                  @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
-                                                  HttpServletRequest req) {
-        QueryWrapper<JeecgOrderTicket> queryWrapper = QueryGenerator.initQueryWrapper(jeecgOrderTicket, req.getParameterMap());
-        Page<JeecgOrderTicket> page = new Page<JeecgOrderTicket>(pageNo, pageSize);
-        IPage<JeecgOrderTicket> pageList = jeecgOrderTicketService.page(page, queryWrapper);
-        return Result.ok(pageList);
-    }
-
-    /**
-     * 添加
-     *
-     * @param jeecgOrderCustomer
-     * @return
-     */
-    @PostMapping(value = "/addCustomer")
-    public Result<?> addCustomer(@RequestBody JeecgOrderCustomer jeecgOrderCustomer) {
-        jeecgOrderCustomerService.save(jeecgOrderCustomer);
-        return Result.ok("添加成功!");
-    }
-
-    /**
-     * 编辑
-     *
-     * @param jeecgOrderCustomer
-     * @return
-     */
-    @PutMapping("/editCustomer")
-    public Result<?> editCustomer(@RequestBody JeecgOrderCustomer jeecgOrderCustomer) {
-        jeecgOrderCustomerService.updateById(jeecgOrderCustomer);
-        return Result.ok("添加成功!");
-    }
-
-    /**
-     * 通过id删除
-     *
-     * @param id
-     * @return
-     */
-    @DeleteMapping(value = "/deleteCustomer")
-    public Result<?> deleteCustomer(@RequestParam(name = "id", required = true) String id) {
-        jeecgOrderCustomerService.removeById(id);
-        return Result.ok("删除成功!");
-    }
-
-    /**
-     * 批量删除
-     *
-     * @param ids
-     * @return
-     */
-    @DeleteMapping(value = "/deleteBatchCustomer")
-    public Result<?> deleteBatchCustomer(@RequestParam(name = "ids", required = true) String ids) {
-        this.jeecgOrderCustomerService.removeByIds(Arrays.asList(ids.split(",")));
-        return Result.ok("批量删除成功!");
-    }
-
-    /**
-     * 添加
-     *
-     * @param jeecgOrderTicket
-     * @return
-     */
-    @PostMapping(value = "/addTicket")
-    public Result<?> addTicket(@RequestBody JeecgOrderTicket jeecgOrderTicket) {
-        jeecgOrderTicketService.save(jeecgOrderTicket);
-        return Result.ok("添加成功!");
-    }
-
-    /**
-     * 编辑
-     *
-     * @param jeecgOrderTicket
-     * @return
-     */
-    @PutMapping("/editTicket")
-    public Result<?> editTicket(@RequestBody JeecgOrderTicket jeecgOrderTicket) {
-        jeecgOrderTicketService.updateById(jeecgOrderTicket);
-        return Result.ok("编辑成功!");
-    }
-
-    /**
-     * 通过id删除
-     *
-     * @param id
-     * @return
-     */
-    @DeleteMapping(value = "/deleteTicket")
-    public Result<?> deleteTicket(@RequestParam(name = "id", required = true) String id) {
-        jeecgOrderTicketService.removeById(id);
-        return Result.ok("删除成功!");
-    }
-
-    /**
-     * 批量删除
-     *
-     * @param ids
-     * @return
-     */
-    @DeleteMapping(value = "/deleteBatchTicket")
-    public Result<?> deleteBatchTicket(@RequestParam(name = "ids", required = true) String ids) {
-        this.jeecgOrderTicketService.removeByIds(Arrays.asList(ids.split(",")));
-        return Result.ok("批量删除成功!");
-    }
-
-}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/Dockerfile b/jeecg-boot/jeecg-boot-module-system/Dockerfile
index 72e5a11..5fa43c3 100644
--- a/jeecg-boot/jeecg-boot-module-system/Dockerfile
+++ b/jeecg-boot/jeecg-boot-module-system/Dockerfile
@@ -11,6 +11,6 @@ WORKDIR /jeecg-boot
 EXPOSE 8080
 
 ADD ./src/main/resources/jeecg ./config/jeecg
-ADD ./target/jeecg-boot-module-system-3.0.jar ./
+ADD ./target/jeecg-boot-module-system-3.1.0.jar ./
 
-CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-3.0.jar
\ No newline at end of file
+CMD sleep 60;java -Djava.security.egd=file:/dev/./urandom -jar jeecg-boot-module-system-3.1.0.jar
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/pom.xml b/jeecg-boot/jeecg-boot-module-system/pom.xml
index d4ba2cf..513991a 100644
--- a/jeecg-boot/jeecg-boot-module-system/pom.xml
+++ b/jeecg-boot/jeecg-boot-module-system/pom.xml
@@ -4,7 +4,7 @@
 	<parent>
 		<groupId>org.jeecgframework.boot</groupId>
 		<artifactId>jeecg-boot-parent</artifactId>
-		<version>3.0</version>
+		<version>3.1.0</version>
 	</parent>
 	<modelVersion>4.0.0</modelVersion>
 
@@ -38,7 +38,7 @@
 		<dependency>
 			<groupId>org.jeecgframework</groupId>
 			<artifactId>jeewx-api</artifactId>
-			<version>1.4.6</version>
+			<version>1.4.7</version>
 			<exclusions>
 				<exclusion>
 					<artifactId>commons-beanutils</artifactId>
@@ -54,7 +54,7 @@
 		<dependency>
 			<groupId>org.jeecgframework.jimureport</groupId>
 			<artifactId>jimureport-spring-boot-starter</artifactId>
-			<version>1.4.0</version>
+			<version>1.4.2</version>
 		</dependency>
 
 
@@ -62,7 +62,7 @@
 		<dependency>
 			<groupId>org.jeecgframework.boot</groupId>
 			<artifactId>jeecg-boot-module-demo</artifactId>
-			<version>3.0</version>
+			<version>3.1.0</version>
 		</dependency>
 
 	</dependencies>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/JeecgSystemApplication.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/JeecgSystemApplication.java
index a4e9588..f709911 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/JeecgSystemApplication.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/JeecgSystemApplication.java
@@ -1,12 +1,19 @@
 package org.jeecg;
 
 import lombok.extern.slf4j.Slf4j;
+import org.apache.catalina.Context;
+import org.apache.tomcat.util.scan.StandardJarScanner;
 import org.jeecg.common.util.oConvertUtils;
 import org.springframework.boot.SpringApplication;
+//import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
 import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.Bean;
 import org.springframework.core.env.Environment;
 
 import java.net.InetAddress;
@@ -17,6 +24,7 @@ import java.net.UnknownHostException;
 */
 @Slf4j
 @SpringBootApplication
+@EnableAutoConfiguration(exclude={MongoAutoConfiguration.class})
 public class JeecgSystemApplication extends SpringBootServletInitializer {
 
     @Override
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/jimureport/JimuReportTokenService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/jimureport/JimuReportTokenService.java
index a2fdc7f..4d9f0e4 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/jimureport/JimuReportTokenService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/config/jimureport/JimuReportTokenService.java
@@ -1,6 +1,6 @@
 package org.jeecg.config.jimureport;
 
-import org.jeecg.common.constant.DataBaseConstant;
+import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.system.api.ISysBaseAPI;
 import org.jeecg.common.system.util.JwtUtil;
 import org.jeecg.common.system.vo.SysUserCacheInfo;
@@ -20,6 +20,9 @@ import java.util.Map;
  *  * 1.自定义获取登录token
  *  * 2.自定义获取登录用户
  */
+
+
+@Slf4j
 @Component
 public class JimuReportTokenService implements JmReportTokenServiceI {
     @Autowired
@@ -45,10 +48,16 @@ public class JimuReportTokenService implements JmReportTokenServiceI {
 
     @Override
     public Map<String, Object> getUserInfo(String token) {
+        Map<String, Object> map = new HashMap<String, Object>();
         String username = JwtUtil.getUsername(token);
         //此处通过token只能拿到一个信息 用户账号  后面的就是根据账号获取其他信息 查询数据或是走redis 用户根据自身业务可自定义
-        SysUserCacheInfo userInfo = sysBaseAPI.getCacheUser(username);
-        Map<String, Object> map = new HashMap<String, Object>();
+        SysUserCacheInfo userInfo = null;
+        try {
+            userInfo = sysBaseAPI.getCacheUser(username);
+        } catch (Exception e) {
+            log.error("获取用户信息异常:"+ e.getMessage());
+            return map;
+        }
         //设置账号名
         map.put(SYS_USER_CODE, userInfo.getSysUserCode());
         //设置部门编码
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/aop/LogRecordAspect.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/aop/LogRecordAspect.java
index ceb0476..c625318 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/aop/LogRecordAspect.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/aop/LogRecordAspect.java
@@ -1,46 +1,46 @@
-package org.jeecg.modules.ngalain.aop;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.aspectj.lang.ProceedingJoinPoint;
-import org.aspectj.lang.annotation.Around;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Pointcut;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.context.request.RequestAttributes;
-import org.springframework.web.context.request.RequestContextHolder;
-import org.springframework.web.context.request.ServletRequestAttributes;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;;
-
-
-// 暂时注释掉,提高系统性能
-//@Aspect   //定义一个切面
-//@Configuration
-public class LogRecordAspect {
-private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class);
-
-    // 定义切点Pointcut
-    @Pointcut("execution(public * org.jeecg.modules.*.*.*Controller.*(..))")
-    public void excudeService() {
-    }
-
-    @Around("excudeService()")
-    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
-        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
-        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
-        HttpServletRequest request = sra.getRequest();
-
-        String url = request.getRequestURL().toString();
-        String method = request.getMethod();
-        String uri = request.getRequestURI();
-        String queryString = request.getQueryString();
-        logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, queryString);
-
-        // result的值就是被拦截方法的返回值
-        Object result = pjp.proceed();
-
-        logger.info("请求结束,controller的返回值是 " + result);
-        return result;
-    }
-}
\ No newline at end of file
+//package org.jeecg.modules.ngalain.aop;
+//
+//import javax.servlet.http.HttpServletRequest;
+//
+//import org.aspectj.lang.ProceedingJoinPoint;
+//import org.aspectj.lang.annotation.Around;
+//import org.aspectj.lang.annotation.Aspect;
+//import org.aspectj.lang.annotation.Pointcut;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.web.context.request.RequestAttributes;
+//import org.springframework.web.context.request.RequestContextHolder;
+//import org.springframework.web.context.request.ServletRequestAttributes;
+//import org.slf4j.Logger;
+//import org.slf4j.LoggerFactory;;
+//
+//
+//// 暂时注释掉,提高系统性能
+////@Aspect   //定义一个切面
+////@Configuration
+//public class LogRecordAspect {
+//private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class);
+//
+//    // 定义切点Pointcut
+//    @Pointcut("execution(public * org.jeecg.modules.*.*.*Controller.*(..))")
+//    public void excudeService() {
+//    }
+//
+//    @Around("excudeService()")
+//    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
+//        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
+//        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
+//        HttpServletRequest request = sra.getRequest();
+//
+//        String url = request.getRequestURL().toString();
+//        String method = request.getMethod();
+//        String uri = request.getRequestURI();
+//        String queryString = request.getQueryString();
+//        logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, queryString);
+//
+//        // result的值就是被拦截方法的返回值
+//        Object result = pjp.proceed();
+//
+//        logger.info("请求结束,controller的返回值是 " + result);
+//        return result;
+//    }
+//}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/controller/NgAlainController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/controller/NgAlainController.java
index bca04aa..1930b97 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/controller/NgAlainController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/ngalain/controller/NgAlainController.java
@@ -1,86 +1,86 @@
-package org.jeecg.modules.ngalain.controller;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-
-import org.apache.shiro.SecurityUtils;
-import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.system.vo.DictModel;
-import org.jeecg.common.system.vo.LoginUser;
-import org.jeecg.modules.ngalain.service.NgAlainService;
-import org.jeecg.modules.system.service.ISysDictService;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.ResponseBody;
-import org.springframework.web.bind.annotation.RestController;
-
-import com.alibaba.fastjson.JSONObject;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-@RestController
-@RequestMapping("/sys/ng-alain")
-public class NgAlainController {
-    @Autowired
-    private NgAlainService ngAlainService;
-    @Autowired
-    private ISysDictService sysDictService;
-
-    @RequestMapping(value = "/getAppData")
-    @ResponseBody
-    public JSONObject getAppData(HttpServletRequest request) throws Exception {
-       String token=request.getHeader("X-Access-Token");
-        JSONObject j = new JSONObject();
-        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-        JSONObject userObjcet = new JSONObject();
-        userObjcet.put("name", user.getUsername());
-        userObjcet.put("avatar", user.getAvatar());
-        userObjcet.put("email", user.getEmail());
-        userObjcet.put("token", token);
-        j.put("user", userObjcet);
-        j.put("menu",ngAlainService.getMenu(user.getUsername()));
-        JSONObject app = new JSONObject();
-        app.put("name", "jeecg-boot-angular");
-        app.put("description", "jeecg+ng-alain整合版本");
-        j.put("app", app);
-        return j;
-    }
-
-    @RequestMapping(value = "/getDictItems/{dictCode}", method = RequestMethod.GET)
-    public Object getDictItems(@PathVariable String dictCode) {
-        log.info(" dictCode : "+ dictCode);
-        Result<List<DictModel>> result = new Result<List<DictModel>>();
-        List<DictModel> ls = null;
-        try {
-            ls = sysDictService.queryDictItemsByCode(dictCode);
-            result.setSuccess(true);
-            result.setResult(ls);
-        } catch (Exception e) {
-            log.error(e.getMessage(),e);
-            result.error500("操作失败");
-            return result;
-        }
-        List<JSONObject> dictlist=new ArrayList<>();
-        for (DictModel l : ls) {
-            JSONObject dict=new JSONObject();
-                try {
-                    dict.put("value",Integer.parseInt(l.getValue()));
-                } catch (NumberFormatException e) {
-                    dict.put("value",l.getValue());
-                }
-            dict.put("label",l.getText());
-            dictlist.add(dict);
-        }
-        return dictlist;
-    }
-    @RequestMapping(value = "/getDictItemsByTable/{table}/{key}/{value}", method = RequestMethod.GET)
-    public Object getDictItemsByTable(@PathVariable String table,@PathVariable String key,@PathVariable String value) {
-        return this.ngAlainService.getDictByTable(table,key,value);
-    }
-}
+//package org.jeecg.modules.ngalain.controller;
+//
+//import java.util.ArrayList;
+//import java.util.List;
+//import java.util.Map;
+//
+//import javax.servlet.http.HttpServletRequest;
+//
+//import org.apache.shiro.SecurityUtils;
+//import org.jeecg.common.api.vo.Result;
+//import org.jeecg.common.system.vo.DictModel;
+//import org.jeecg.common.system.vo.LoginUser;
+//import org.jeecg.modules.ngalain.service.NgAlainService;
+//import org.jeecg.modules.system.service.ISysDictService;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.web.bind.annotation.PathVariable;
+//import org.springframework.web.bind.annotation.RequestMapping;
+//import org.springframework.web.bind.annotation.RequestMethod;
+//import org.springframework.web.bind.annotation.ResponseBody;
+//import org.springframework.web.bind.annotation.RestController;
+//
+//import com.alibaba.fastjson.JSONObject;
+//
+//import lombok.extern.slf4j.Slf4j;
+//
+//@Slf4j
+//@RestController
+//@RequestMapping("/sys/ng-alain")
+//public class NgAlainController {
+//    @Autowired
+//    private NgAlainService ngAlainService;
+//    @Autowired
+//    private ISysDictService sysDictService;
+//
+//    @RequestMapping(value = "/getAppData")
+//    @ResponseBody
+//    public JSONObject getAppData(HttpServletRequest request) throws Exception {
+//       String token=request.getHeader("X-Access-Token");
+//        JSONObject j = new JSONObject();
+//        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+//        JSONObject userObjcet = new JSONObject();
+//        userObjcet.put("name", user.getUsername());
+//        userObjcet.put("avatar", user.getAvatar());
+//        userObjcet.put("email", user.getEmail());
+//        userObjcet.put("token", token);
+//        j.put("user", userObjcet);
+//        j.put("menu",ngAlainService.getMenu(user.getUsername()));
+//        JSONObject app = new JSONObject();
+//        app.put("name", "jeecg-boot-angular");
+//        app.put("description", "jeecg+ng-alain整合版本");
+//        j.put("app", app);
+//        return j;
+//    }
+//
+//    @RequestMapping(value = "/getDictItems/{dictCode}", method = RequestMethod.GET)
+//    public Object getDictItems(@PathVariable String dictCode) {
+//        log.info(" dictCode : "+ dictCode);
+//        Result<List<DictModel>> result = new Result<List<DictModel>>();
+//        List<DictModel> ls = null;
+//        try {
+//            ls = sysDictService.queryDictItemsByCode(dictCode);
+//            result.setSuccess(true);
+//            result.setResult(ls);
+//        } catch (Exception e) {
+//            log.error(e.getMessage(),e);
+//            result.error500("操作失败");
+//            return result;
+//        }
+//        List<JSONObject> dictlist=new ArrayList<>();
+//        for (DictModel l : ls) {
+//            JSONObject dict=new JSONObject();
+//                try {
+//                    dict.put("value",Integer.parseInt(l.getValue()));
+//                } catch (NumberFormatException e) {
+//                    dict.put("value",l.getValue());
+//                }
+//            dict.put("label",l.getText());
+//            dictlist.add(dict);
+//        }
+//        return dictlist;
+//    }
+//    @RequestMapping(value = "/getDictItemsByTable/{table}/{key}/{value}", method = RequestMethod.GET)
+//    public Object getDictItemsByTable(@PathVariable String table,@PathVariable String key,@PathVariable String value) {
+//        return this.ngAlainService.getDictByTable(table,key,value);
+//    }
+//}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java
index 5f9a733..d2e6d54 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/controller/QuartzJobController.java
@@ -6,10 +6,12 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.authz.annotation.RequiresRoles;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.ImportExcelUtil;
 import org.jeecg.modules.quartz.entity.QuartzJob;
 import org.jeecg.modules.quartz.service.IQuartzJobService;
@@ -145,14 +147,14 @@ public class QuartzJobController {
 	 */
 	//@RequiresRoles("admin")
 	@GetMapping(value = "/pause")
-	@ApiOperation(value = "暂停定时任务")
+	@ApiOperation(value = "停止定时任务")
 	public Result<Object> pauseJob(@RequestParam(name = "id") String id) {
 		QuartzJob job = quartzJobService.getById(id);
 		if (job == null) {
 			return Result.error("定时任务不存在!");
 		}
 		quartzJobService.pause(job);
-		return Result.ok("暂停定时任务成功");
+		return Result.ok("停止定时任务成功");
 	}
 
 	/**
@@ -163,7 +165,7 @@ public class QuartzJobController {
 	 */
 	//@RequiresRoles("admin")
 	@GetMapping(value = "/resume")
-	@ApiOperation(value = "恢复定时任务")
+	@ApiOperation(value = "启动定时任务")
 	public Result<Object> resumeJob(@RequestParam(name = "id") String id) {
 		QuartzJob job = quartzJobService.getById(id);
 		if (job == null) {
@@ -171,7 +173,7 @@ public class QuartzJobController {
 		}
 		quartzJobService.resumeJob(job);
 		//scheduler.resumeJob(JobKey.jobKey(job.getJobClassName().trim()));
-		return Result.ok("恢复定时任务成功");
+		return Result.ok("启动定时任务成功");
 	}
 
 	/**
@@ -202,8 +204,12 @@ public class QuartzJobController {
 		// 导出文件名称
 		mv.addObject(NormalExcelConstants.FILE_NAME, "定时任务列表");
 		mv.addObject(NormalExcelConstants.CLASS, QuartzJob.class);
-		mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:Jeecg", "导出信息"));
-		mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
+        //获取当前登录用户
+        //update-begin---author:wangshuai ---date:20211227  for:[JTC-116]导出人写死了------------
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+		mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("定时任务列表数据", "导出人:"+user.getRealname(), "导出信息"));
+        //update-end---author:wangshuai ---date:20211227  for:[JTC-116]导出人写死了------------
+        mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
 		return mv;
 	}
 
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/job/SampleJob.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/job/SampleJob.java
index 0ea62e9..db37777 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/job/SampleJob.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/quartz/job/SampleJob.java
@@ -17,7 +17,7 @@ public class SampleJob implements Job {
 
 	@Override
 	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
-
+		log.info(" Job Execution key:"+jobExecutionContext.getJobDetail().getKey());
 		log.info(String.format(" Jeecg-Boot 普通定时任务 SampleJob !  时间:" + DateUtils.getTimestamp()));
 	}
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java
index db5f8f5..dc38911 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/DuplicateCheckController.java
@@ -47,6 +47,15 @@ public class DuplicateCheckController {
 		//SQL注入校验(只限制非法串改数据库)
 		final String[] sqlInjCheck = {duplicateCheckVo.getTableName(),duplicateCheckVo.getFieldName()};
 		SqlInjectionUtil.filterContent(sqlInjCheck);
+		// update-begin-author:taoyan date:20211227 for: JTC-25 【online报表】oracle 操作问题 录入弹框啥都不填直接保存 ①编码不是应该提示必填么?②报错也应该是具体文字提示,不是后台错误日志
+		if(StringUtils.isEmpty(duplicateCheckVo.getFieldVal())){
+			Result rs = new Result();
+			rs.setCode(500);
+			rs.setSuccess(true);
+			rs.setMessage("数据为空,不作处理!");
+			return rs;
+		}
+		// update-end-author:taoyan date:20211227 for: JTC-25 【online报表】oracle 操作问题 录入弹框啥都不填直接保存 ①编码不是应该提示必填么?②报错也应该是具体文字提示,不是后台错误日志
 		if (StringUtils.isNotBlank(duplicateCheckVo.getDataId())) {
 			// [2].编辑页面校验
 			num = sysDictMapper.duplicateCheckCountSql(duplicateCheckVo);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java
index bdf71d5..67e7f0a 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/LoginController.java
@@ -4,6 +4,7 @@ import cn.hutool.core.util.RandomUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.aliyuncs.exceptions.ClientException;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
@@ -58,8 +59,6 @@ public class LoginController {
 	@Resource
 	private BaseCommonService baseCommonService;
 
-	private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
-
 	@ApiOperation("登录接口")
 	@RequestMapping(value = "/login", method = RequestMethod.POST)
 	public Result<JSONObject> login(@RequestBody SysLoginModel sysLoginModel){
@@ -82,6 +81,7 @@ public class LoginController {
 		Object checkCode = redisUtil.get(realKey);
 		//当进入登录页时,有一定几率出现验证码错误 #1714
 		if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
+            log.warn("验证码错误,key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
 			result.error500("验证码错误");
 			return result;
 		}
@@ -402,7 +402,10 @@ public class LoginController {
 		// update-begin--Author:sunjianlei Date:20210802 for:获取用户租户信息
 		String tenantIds = sysUser.getRelTenantIds();
 		if (oConvertUtils.isNotEmpty(tenantIds)) {
-			List<String> tenantIdList = Arrays.asList(tenantIds.split(","));
+			List<Integer> tenantIdList = new ArrayList<>();
+			for(String id: tenantIds.split(",")){
+				tenantIdList.add(Integer.valueOf(id));
+			}
 			// 该方法仅查询有效的租户,如果返回0个就说明所有的租户均无效。
 			List<SysTenant> tenantList = sysTenantService.queryEffectiveTenant(tenantIdList);
 			if (tenantList.size() == 0) {
@@ -450,10 +453,17 @@ public class LoginController {
 	public Result<String> randomImage(HttpServletResponse response,@PathVariable String key){
 		Result<String> res = new Result<String>();
 		try {
+			//生成验证码
+			final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
 			String code = RandomUtil.randomString(BASE_CHECK_CODES,4);
+
+			//存到redis中
 			String lowerCaseCode = code.toLowerCase();
 			String realKey = MD5Util.MD5Encode(lowerCaseCode+key, "utf-8");
+            log.info("获取验证码,Redis checkCode = {},key = {}", code, key);
 			redisUtil.set(realKey, lowerCaseCode, 60);
+
+			//返回前端
 			String base64 = RandImageUtil.generate(code);
 			res.setSuccess(true);
 			res.setResult(base64);
@@ -495,13 +505,16 @@ public class LoginController {
 		if(oConvertUtils.isEmpty(orgCode)) {
 			//如果当前用户无选择部门 查看部门关联信息
 			List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
+			//update-begin-author:taoyan date:20220117 for: JTC-1068【app】新建用户,没有设置部门及角色,点击登录提示暂未归属部,一直在登录页面 使用手机号登录 可正常
 			if (departs == null || departs.size() == 0) {
-				result.error500("用户暂未归属部门,不可登录!");
-				return result;
+				/*result.error500("用户暂未归属部门,不可登录!");
+				return result;*/
+			}else{
+				orgCode = departs.get(0).getOrgCode();
+				sysUser.setOrgCode(orgCode);
+				this.sysUserService.updateUserDepart(username, orgCode);
 			}
-			orgCode = departs.get(0).getOrgCode();
-			sysUser.setOrgCode(orgCode);
-			this.sysUserService.updateUserDepart(username, orgCode);
+			//update-end-author:taoyan date:20220117 for: JTC-1068【app】新建用户,没有设置部门及角色,点击登录提示暂未归属部,一直在登录页面 使用手机号登录 可正常
 		}
 		JSONObject obj = new JSONObject();
 		//用户登录信息
@@ -542,5 +555,58 @@ public class LoginController {
 		}
 		return Result.ok();
 	}
+	/**
+	 * 登录二维码
+	 */
+	@ApiOperation(value = "登录二维码", notes = "登录二维码")
+	@GetMapping("/getLoginQrcode")
+	public Result<?>  getLoginQrcode() {
+		String qrcodeId = CommonConstant.LOGIN_QRCODE_PRE+IdWorker.getIdStr();
+		//定义二维码参数
+		Map params = new HashMap(5);
+		params.put("qrcodeId", qrcodeId);
+		//存放二维码唯一标识30秒有效
+		redisUtil.set(CommonConstant.LOGIN_QRCODE + qrcodeId, qrcodeId, 30);
+		return Result.OK(params);
+	}
+	/**
+	 * 扫码二维码
+	 */
+	@ApiOperation(value = "扫码登录二维码", notes = "扫码登录二维码")
+	@PostMapping("/scanLoginQrcode")
+	public Result<?> scanLoginQrcode(@RequestParam String qrcodeId, @RequestParam String token) {
+		Object check = redisUtil.get(CommonConstant.LOGIN_QRCODE + qrcodeId);
+		if (oConvertUtils.isNotEmpty(check)) {
+			//存放token给前台读取
+			redisUtil.set(CommonConstant.LOGIN_QRCODE_TOKEN+qrcodeId, token, 60);
+		} else {
+			return Result.error("二维码已过期,请刷新后重试");
+		}
+		return Result.OK("扫码成功");
+	}
+
+
+	/**
+	 * 获取用户扫码后保存的token
+	 */
+	@ApiOperation(value = "获取用户扫码后保存的token", notes = "获取用户扫码后保存的token")
+	@GetMapping("/getQrcodeToken")
+	public Result getQrcodeToken(@RequestParam String qrcodeId) {
+		Object token = redisUtil.get(CommonConstant.LOGIN_QRCODE_TOKEN + qrcodeId);
+		Map result = new HashMap();
+		Object qrcodeIdExpire = redisUtil.get(CommonConstant.LOGIN_QRCODE + qrcodeId);
+		if (oConvertUtils.isEmpty(qrcodeIdExpire)) {
+			//二维码过期通知前台刷新
+			result.put("token", "-2");
+			return Result.OK(result);
+		}
+		if (oConvertUtils.isNotEmpty(token)) {
+			result.put("success", true);
+			result.put("token", token);
+		} else {
+			result.put("token", "-1");
+		}
+		return Result.OK(result);
+	}
 
 }
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/MockVue3Controller.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/MockVue3Controller.java
deleted file mode 100644
index 193b1a0..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/MockVue3Controller.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package org.jeecg.modules.system.controller;
-
-import lombok.extern.slf4j.Slf4j;
-import org.jeecg.common.api.vo.Result;
-import org.jeecg.modules.system.entity.SysUser;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * vue3前端临时接口
- */
-@RestController
-@RequestMapping("/")
-@Slf4j
-public class MockVue3Controller {
-
-
-}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java
index da3714f..0891101 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementController.java
@@ -14,6 +14,7 @@ import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.CommonSendStatus;
 import org.jeecg.common.constant.WebsocketConst;
 import org.jeecg.common.system.api.ISysBaseAPI;
+import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.util.JwtUtil;
 import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.RedisUtil;
@@ -93,18 +94,21 @@ public class SysAnnouncementController {
 									  HttpServletRequest req) {
 		Result<IPage<SysAnnouncement>> result = new Result<IPage<SysAnnouncement>>();
 		sysAnnouncement.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
-		QueryWrapper<SysAnnouncement> queryWrapper = new QueryWrapper<SysAnnouncement>(sysAnnouncement);
+		QueryWrapper<SysAnnouncement> queryWrapper = QueryGenerator.initQueryWrapper(sysAnnouncement, req.getParameterMap());
 		Page<SysAnnouncement> page = new Page<SysAnnouncement>(pageNo,pageSize);
+
+		//update-begin-author:lvdandan date:20211229 for: sqlserver mssql-jdbc 8.2.2.jre8版本下系统公告列表查询报错 查询SQL中生成了两个create_time DESC;故注释此段代码
 		//排序逻辑 处理
-		String column = req.getParameter("column");
-		String order = req.getParameter("order");
-		if(oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) {
-			if("asc".equals(order)) {
-				queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column));
-			}else {
-				queryWrapper.orderByDesc(oConvertUtils.camelToUnderline(column));
-			}
-		}
+//		String column = req.getParameter("column");
+//		String order = req.getParameter("order");
+//		if(oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) {
+//			if("asc".equals(order)) {
+//				queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column));
+//			}else {
+//				queryWrapper.orderByDesc(oConvertUtils.camelToUnderline(column));
+//			}
+//		}
+		//update-end-author:lvdandan date:20211229 for: sqlserver mssql-jdbc 8.2.2.jre8版本下系统公告列表查询报错 查询SQL中生成了两个create_time DESC;故注释此段代码
 		IPage<SysAnnouncement> pageList = sysAnnouncementService.page(page, queryWrapper);
 		result.setSuccess(true);
 		result.setResult(pageList);
@@ -337,11 +341,13 @@ public class SysAnnouncementController {
 				query.eq(SysAnnouncementSend::getUserId,userId);
 				SysAnnouncementSend one = sysAnnouncementSendService.getOne(query);
 				if(null==one){
-				SysAnnouncementSend announcementSend = new SysAnnouncementSend();
-				announcementSend.setAnntId(announcements.get(i).getId());
-				announcementSend.setUserId(userId);
-				announcementSend.setReadFlag(CommonConstant.NO_READ_FLAG);
-				sysAnnouncementSendService.save(announcementSend);
+					log.info("listByUser接口新增了SysAnnouncementSend:pageSize{}:"+pageSize);
+					SysAnnouncementSend announcementSend = new SysAnnouncementSend();
+					announcementSend.setAnntId(announcements.get(i).getId());
+					announcementSend.setUserId(userId);
+					announcementSend.setReadFlag(CommonConstant.NO_READ_FLAG);
+					sysAnnouncementSendService.save(announcementSend);
+					log.info("announcementSend.toString()",announcementSend.toString());
 				}
 				//update-end--Author:wangshuai  Date:20200803  for: 通知公告消息重复LOWCOD-759------------
 			}
@@ -373,7 +379,7 @@ public class SysAnnouncementController {
         LambdaQueryWrapper<SysAnnouncement> queryWrapper = new LambdaQueryWrapper<SysAnnouncement>(sysAnnouncement);
         //Step.2 AutoPoi 导出Excel
         ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
-		queryWrapper.eq(SysAnnouncement::getDelFlag,CommonConstant.DEL_FLAG_0);
+		queryWrapper.eq(SysAnnouncement::getDelFlag,CommonConstant.DEL_FLAG_0.toString());
         List<SysAnnouncement> pageList = sysAnnouncementService.list(queryWrapper);
         //导出文件名称
         mv.addObject(NormalExcelConstants.FILE_NAME, "系统通告列表");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java
index 635e695..ac2087c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysAnnouncementSendController.java
@@ -10,6 +10,7 @@ import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.constant.WebsocketConst;
 import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.SqlInjectionUtil;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.message.websocket.WebSocket;
 import org.jeecg.modules.system.entity.SysAnnouncementSend;
@@ -69,6 +70,11 @@ public class SysAnnouncementSendController {
 		//排序逻辑 处理
 		String column = req.getParameter("column");
 		String order = req.getParameter("order");
+
+		//issues/3331 SQL injection vulnerability
+		SqlInjectionUtil.filterContent(column);
+		SqlInjectionUtil.filterContent(order);
+
 		if(oConvertUtils.isNotEmpty(column) && oConvertUtils.isNotEmpty(order)) {
 			if("asc".equals(order)) {
 				queryWrapper.orderByAsc(oConvertUtils.camelToUnderline(column));
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java
index 4c5759d..60bada8 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCategoryController.java
@@ -9,9 +9,11 @@ import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.query.QueryGenerator;
 import org.jeecg.common.system.vo.DictModel;
 import org.jeecg.common.system.vo.LoginUser;
+import org.jeecg.common.util.ImportExcelUtil;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.system.entity.SysCategory;
 import org.jeecg.modules.system.model.TreeSelectModel;
@@ -65,10 +67,16 @@ public class SysCategoryController {
 		Result<IPage<SysCategory>> result = new Result<IPage<SysCategory>>();
 		
 		//--author:os_chengtgen---date:20190804 -----for: 分类字典页面显示错误,issues:377--------start
-		//QueryWrapper<SysCategory> queryWrapper = QueryGenerator.initQueryWrapper(sysCategory, req.getParameterMap());
-		QueryWrapper<SysCategory> queryWrapper = new QueryWrapper<SysCategory>();
-		queryWrapper.eq("pid", sysCategory.getPid());
-		//--author:os_chengtgen---date:20190804 -----for: 分类字典页面显示错误,issues:377--------end
+		//--author:liusq---date:20211119 -----for: 【vue3】分类字典页面查询条件配置--------start
+		QueryWrapper<SysCategory> queryWrapper = QueryGenerator.initQueryWrapper(sysCategory, req.getParameterMap());
+		String name = sysCategory.getName();
+		String code = sysCategory.getCode();
+		//QueryWrapper<SysCategory> queryWrapper = new QueryWrapper<SysCategory>();
+		if(StringUtils.isBlank(name)&&StringUtils.isBlank(code)){
+			queryWrapper.eq("pid", sysCategory.getPid());
+		}
+		//--author:liusq---date:20211119 -----for: 分类字典页面查询条件配置--------end
+		//--author:os_chengtgen---date:20190804 -----for:【vue3】 分类字典页面显示错误,issues:377--------end
 
 		Page<SysCategory> page = new Page<SysCategory>(pageNo, pageSize);
 		IPage<SysCategory> pageList = sysCategoryService.page(page, queryWrapper);
@@ -215,10 +223,13 @@ public class SysCategoryController {
    * @return
    */
   @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
-  public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+  public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) throws IOException{
       MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
       Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
-      for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
+	  // 错误信息
+	  List<String> errorMessage = new ArrayList<>();
+	  int successLines = 0, errorLines = 0;
+	  for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
           MultipartFile file = entity.getValue();// 获取上传文件对象
           ImportParams params = new ImportParams();
           params.setTitleRows(2);
@@ -229,7 +240,8 @@ public class SysCategoryController {
 			 //按照编码长度排序
               Collections.sort(listSysCategorys);
 			  log.info("排序后的list====>",listSysCategorys);
-              for (SysCategory sysCategoryExcel : listSysCategorys) {
+              for (int i = 0; i < listSysCategorys.size(); i++) {
+				  SysCategory sysCategoryExcel = listSysCategorys.get(i);
 				  String code = sysCategoryExcel.getCode();
 				  if(code.length()>3){
 					  String pCode = sysCategoryExcel.getCode().substring(0,code.length()-3);
@@ -242,12 +254,25 @@ public class SysCategoryController {
 				  }else{
 					  sysCategoryExcel.setPid("0");
 				  }
-                  sysCategoryService.save(sysCategoryExcel);
+				  try {
+					  sysCategoryService.save(sysCategoryExcel);
+					  successLines++;
+				  } catch (Exception e) {
+					  errorLines++;
+					  String message = e.getMessage().toLowerCase();
+					  int lineNumber = i + 1;
+					  // 通过索引名判断出错信息
+					  if (message.contains(CommonConstant.SQL_INDEX_UNIQ_CATEGORY_CODE)) {
+						  errorMessage.add("第 " + lineNumber + " 行:分类编码已经存在,忽略导入。");
+					  }  else {
+						  errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入");
+						  log.error(e.getMessage(), e);
+					  }
+				  }
               }
-              return Result.ok("文件导入成功!数据行数:" + listSysCategorys.size());
           } catch (Exception e) {
-              log.error(e.getMessage(), e);
-              return Result.error("文件导入失败:"+e.getMessage());
+			  errorMessage.add("发生异常:" + e.getMessage());
+			  log.error(e.getMessage(), e);
           } finally {
               try {
                   file.getInputStream().close();
@@ -256,7 +281,7 @@ public class SysCategoryController {
               }
           }
       }
-      return Result.error("文件导入失败!");
+      return ImportExcelUtil.imporReturnRes(errorLines,successLines,errorMessage);
   }
   
   
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java
index 01e54b4..c7e7584 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysCheckRuleController.java
@@ -112,7 +112,7 @@ public class SysCheckRuleController extends JeecgController<SysCheckRule, ISysCh
      */
     @AutoLog(value = "编码校验规则-编辑")
     @ApiOperation(value = "编码校验规则-编辑", notes = "编码校验规则-编辑")
-    @PutMapping(value = "/edit")
+    @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
     public Result edit(@RequestBody SysCheckRule sysCheckRule) {
         sysCheckRuleService.updateById(sysCheckRule);
         return Result.ok("编辑成功!");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java
index 268eb92..98417c1 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDataSourceController.java
@@ -14,6 +14,7 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
+import org.apache.shiro.authz.annotation.RequiresRoles;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.aspect.annotation.AutoLog;
 import org.jeecg.common.system.base.controller.JeecgController;
@@ -57,6 +58,7 @@ public class SysDataSourceController extends JeecgController<SysDataSource, ISys
      */
     @AutoLog(value = "多数据源管理-分页列表查询")
     @ApiOperation(value = "多数据源管理-分页列表查询", notes = "多数据源管理-分页列表查询")
+    //@RequiresRoles("admin")
     @GetMapping(value = "/list")
     public Result<?> queryPageList(
             SysDataSource sysDataSource,
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
index dfd17c5..3df03e7 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartController.java
@@ -198,7 +198,7 @@ public class SysDepartController {
 	 * @return
 	 */
 	//@RequiresRoles({"admin"})
-	@RequestMapping(value = "/edit", method = RequestMethod.PUT)
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	@CacheEvict(value= {CacheConstant.SYS_DEPARTS_CACHE,CacheConstant.SYS_DEPART_IDS_CACHE}, allEntries=true)
 	public Result<SysDepart> edit(@RequestBody SysDepart sysDepart, HttpServletRequest request) {
 		String username = JwtUtil.getUserNameByToken(request);
@@ -322,7 +322,7 @@ public class SysDepartController {
 		if(oConvertUtils.isNotEmpty(user.getUserIdentity()) && user.getUserIdentity().equals( CommonConstant.USER_IDENTITY_2 )){
 			departIds = user.getDepartIds();
 		}
-		List<SysDepartTreeModel> treeList = this.sysDepartService.searhBy(keyWord,myDeptSearch,departIds);
+		List<SysDepartTreeModel> treeList = this.sysDepartService.searchByKeyWord(keyWord,myDeptSearch,departIds);
 		if (treeList == null || treeList.size() == 0) {
 			result.setSuccess(false);
 			result.setMessage("未查询匹配数据!");
@@ -363,6 +363,8 @@ public class SysDepartController {
 
     /**
      * 通过excel导入数据
+	 * 部门导入方案1: 通过机构编码来计算出部门的父级ID,维护上下级关系;
+	 * 部门导入方案2: 你也可以改造下程序,机构编码直接导入,先不设置父ID;全部导入后,写一个sql,补下父ID;
      *
      * @param request
      * @param response
@@ -418,6 +420,11 @@ public class SysDepartController {
 					sysDepart.setOrgType(sysDepart.getOrgCode().length()/codeLength+"");
                     //update-end---author:liusq   Date:20210223  for:批量导入部门以后,不能追加下一级部门 #2245------------
 					sysDepart.setDelFlag(CommonConstant.DEL_FLAG_0.toString());
+                    //update-begin---author:wangshuai ---date:20220105  for:[JTC-363]部门导入 机构类别没有时导入失败,赋默认值------------
+					if(oConvertUtils.isEmpty(sysDepart.getOrgCategory())){
+					    sysDepart.setOrgCategory("1");
+                    }
+                    //update-end---author:wangshuai ---date:20220105  for:[JTC-363]部门导入 机构类别没有时导入失败,赋默认值------------
 					ImportExcelUtil.importDateSaveOne(sysDepart, ISysDepartService.class, errorMessageList, num, CommonConstant.SQL_INDEX_UNIQ_DEPART_ORG_CODE);
 					num++;
                 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java
index 1af0986..7ca751f 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartPermissionController.java
@@ -97,7 +97,7 @@ public class SysDepartPermissionController extends JeecgController<SysDepartPerm
 	 * @return
 	 */
 	@ApiOperation(value="部门权限表-编辑", notes="部门权限表-编辑")
-	@PutMapping(value = "/edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit(@RequestBody SysDepartPermission sysDepartPermission) {
 		sysDepartPermissionService.updateById(sysDepartPermission);
 		return Result.ok("编辑成功!");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java
index 4ac0f2c..383d027 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDepartRoleController.java
@@ -114,7 +114,7 @@ public class SysDepartRoleController extends JeecgController<SysDepartRole, ISys
 	 */
 	//@RequiresRoles({"admin"})
 	@ApiOperation(value="部门角色-编辑", notes="部门角色-编辑")
-	@PutMapping(value = "/edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit(@RequestBody SysDepartRole sysDepartRole) {
 		sysDepartRoleService.updateById(sysDepartRole);
 		return Result.ok("编辑成功!");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
index 7c4acad..5e21130 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysDictController.java
@@ -496,7 +496,7 @@ public class SysDictController {
 			try {
 				//导入Excel格式校验,看匹配的字段文本概率
 				Boolean t = ExcelImportCheckUtil.check(file.getInputStream(), SysDictPage.class, params);
-				if(!t){
+				if(t!=null && !t){
 					throw new RuntimeException("导入Excel校验失败 !");
 				}
 				List<SysDictPage> list = ExcelImportUtil.importExcel(file.getInputStream(), SysDictPage.class, params);
@@ -511,11 +511,22 @@ public class SysDictController {
 						Integer integer = sysDictService.saveMain(po, list.get(i).getSysDictItemList());
 						if(integer>0){
 							successLines++;
-						}else{
+                        //update-begin---author:wangshuai ---date:20220211  for:[JTC-1168]如果字典项值为空,则字典项忽略导入------------
+						}else if(integer == -1){
+                            errorLines++;
+                            errorMessage.add("字典名称:" + po.getDictName() + ",对应字典列表的字典项值不能为空,忽略导入。");
+                        }else{
+                        //update-end---author:wangshuai ---date:20220211  for:[JTC-1168]如果字典项值为空,则字典项忽略导入------------
 							errorLines++;
 							int lineNumber = i + 1;
-							errorMessage.add("第 " + lineNumber + " 行:字典编码已经存在,忽略导入。");
-						}
+                            //update-begin---author:wangshuai ---date:20220209  for:[JTC-1168]字典编号不能为空------------
+                            if(oConvertUtils.isEmpty(po.getDictCode())){
+                                errorMessage.add("第 " + lineNumber + " 行:字典编码不能为空,忽略导入。");
+                            }else{
+                                errorMessage.add("第 " + lineNumber + " 行:字典编码已经存在,忽略导入。");
+                            }
+                            //update-end---author:wangshuai ---date:20220209  for:[JTC-1168]字典编号不能为空------------
+                        }
 					}  catch (Exception e) {
 						errorLines++;
 						int lineNumber = i + 1;
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java
index f0c1340..29354fb 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysFillRuleController.java
@@ -93,7 +93,7 @@ public class SysFillRuleController extends JeecgController<SysFillRule, ISysFill
      */
     @AutoLog(value = "填值规则-编辑")
     @ApiOperation(value = "填值规则-编辑", notes = "填值规则-编辑")
-    @PutMapping(value = "/edit")
+    @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
     public Result<?> edit(@RequestBody SysFillRule sysFillRule) {
         sysFillRuleService.updateById(sysFillRule);
         return Result.ok("编辑成功!");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
index e473ddc..e4d5b4e 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPermissionController.java
@@ -59,7 +59,7 @@ public class SysPermissionController {
 
 	/**
 	 * 加载数据节点
-	 * 
+	 *
 	 * @return
 	 */
 	@RequestMapping(value = "/list", method = RequestMethod.GET)
@@ -200,7 +200,7 @@ public class SysPermissionController {
 
 	/**
 	 * 查询用户拥有的菜单权限和按钮权限
-	 * 
+	 *
 	 * @return
 	 */
 	@RequestMapping(value = "/getUserPermissionByToken", method = RequestMethod.GET)
@@ -261,32 +261,49 @@ public class SysPermissionController {
 	}
 
 	/**
-	 * 【vue3专用】查询用户拥有的按钮/表单访问权限
-	 * @return
+	 * 【vue3专用】获取
+	 * 1、查询用户拥有的按钮/表单访问权限
+	 * 2、所有权限 (菜单权限配置)
+	 * 3、系统安全模式 (开启则online报表的数据源必填)
 	 */
 	@RequestMapping(value = "/getPermCode", method = RequestMethod.GET)
 	public Result<?> getPermCode() {
-		Result<List<String>> result = new Result<List<String>>();
 		try {
-			//直接获取当前用户
+			// 直接获取当前用户
 			LoginUser loginUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
-			//获取当前用户的权限集合
+			if (oConvertUtils.isEmpty(loginUser)) {
+				return Result.error("请登录系统!");
+			}
+			// 获取当前用户的权限集合
 			List<SysPermission> metaList = sysPermissionService.queryByUser(loginUser.getUsername());
+            // 按钮权限(用户拥有的权限集合)
+            List<String> codeList = metaList.stream()
+                    .filter((permission) -> CommonConstant.MENU_TYPE_2.equals(permission.getMenuType()) && CommonConstant.STATUS_1.equals(permission.getStatus()))
+                    .collect(ArrayList::new, (list, permission) -> list.add(permission.getPerms()), ArrayList::addAll);
+            //
+			JSONArray authArray = new JSONArray();
+			this.getAuthJsonArray(authArray, metaList);
+			// 查询所有的权限
+			LambdaQueryWrapper<SysPermission> query = new LambdaQueryWrapper<>();
+			query.eq(SysPermission::getDelFlag, CommonConstant.DEL_FLAG_0);
+			query.eq(SysPermission::getMenuType, CommonConstant.MENU_TYPE_2);
+			List<SysPermission> allAuthList = sysPermissionService.list(query);
+			JSONArray allAuthArray = new JSONArray();
+			this.getAllAuthJsonArray(allAuthArray, allAuthList);
+			JSONObject result = new JSONObject();
+            // 所拥有的权限编码
+			result.put("codeList", codeList);
 			//按钮权限(用户拥有的权限集合)
-			List<String> authList = metaList.stream()
-					.filter((permission) -> permission.getMenuType().equals(CommonConstant.MENU_TYPE_2)
-                            && CommonConstant.STATUS_1.equals(permission.getStatus())
-                    )
-					.collect(() -> new ArrayList<String>(),
-							(list, permission) -> list.add(permission.getPerms()),
-							(list1, list2) -> list1.addAll(list2)
-					);
-			result.setResult(authList);
+			result.put("auth", authArray);
+			//全部权限配置集合(按钮权限,访问权限)
+			result.put("allAuth", allAuthArray);
+            // 系统安全模式
+			result.put("sysSafeMode", jeeccgBaseConfig.getSafeMode());
+            return Result.OK(result);
 		} catch (Exception e) {
-			result.error500("查询失败:" + e.getMessage());
 			log.error(e.getMessage(), e);
+            return Result.error("查询失败:" + e.getMessage());
 		}
-		return result;
 	}
 
 	/**
@@ -374,7 +391,7 @@ public class SysPermissionController {
 
 	/**
 	 * 获取全部的权限树
-	 * 
+	 *
 	 * @return
 	 */
 	@RequestMapping(value = "/queryTreeList", method = RequestMethod.GET)
@@ -720,7 +737,7 @@ public class SysPermissionController {
 	/**
 	 * 判断是否外网URL 例如: http://localhost:8080/jeecg-boot/swagger-ui.html#/ 支持特殊格式: {{
 	 * window._CONFIG['domianURL'] }}/druid/ {{ JS代码片段 }},前台解析会自动执行JS代码片段
-	 * 
+	 *
 	 * @return
 	 */
 	private boolean isWWWHttpUrl(String url) {
@@ -733,7 +750,7 @@ public class SysPermissionController {
 	/**
 	 * 通过URL生成路由name(去掉URL前缀斜杠,替换内容中的斜杠‘/’为-) 举例: URL = /isystem/role RouteName =
 	 * isystem-role
-	 * 
+	 *
 	 * @return
 	 */
 	private String urlToRouteName(String url) {
@@ -753,7 +770,7 @@ public class SysPermissionController {
 
 	/**
 	 * 根据菜单id来获取其对应的权限数据
-	 * 
+	 *
 	 * @param sysPermissionDataRule
 	 * @return
 	 */
@@ -768,7 +785,7 @@ public class SysPermissionController {
 
 	/**
 	 * 添加菜单权限数据
-	 * 
+	 *
 	 * @param sysPermissionDataRule
 	 * @return
 	 */
@@ -803,7 +820,7 @@ public class SysPermissionController {
 
 	/**
 	 * 删除菜单权限数据
-	 * 
+	 *
 	 * @param id
 	 * @return
 	 */
@@ -823,7 +840,7 @@ public class SysPermissionController {
 
 	/**
 	 * 查询菜单权限数据
-	 * 
+	 *
 	 * @param sysPermissionDataRule
 	 * @return
 	 */
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java
index cccd034..8315423 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysPositionController.java
@@ -8,10 +8,12 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.poi.ss.formula.functions.T;
+import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.aspect.annotation.AutoLog;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.ImportExcelUtil;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.quartz.service.IQuartzJobService;
@@ -208,10 +210,11 @@ public class SysPositionController {
         //Step.2 AutoPoi 导出Excel
         ModelAndView mv = new ModelAndView(new JeecgEntityExcelView());
         List<SysPosition> pageList = sysPositionService.list(queryWrapper);
+        LoginUser user = (LoginUser) SecurityUtils.getSubject().getPrincipal();
         //导出文件名称
         mv.addObject(NormalExcelConstants.FILE_NAME, "职务表列表");
         mv.addObject(NormalExcelConstants.CLASS, SysPosition.class);
-        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("职务表列表数据", "导出人:Jeecg", "导出信息"));
+        mv.addObject(NormalExcelConstants.PARAMS, new ExportParams("职务表列表数据", "导出人:"+user.getRealname(),"导出信息"));
         mv.addObject(NormalExcelConstants.DATA_LIST, pageList);
         return mv;
     }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java
index 533408a..82b73b7 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysTenantController.java
@@ -6,9 +6,11 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
 import org.jeecg.common.aspect.annotation.PermissionData;
 import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.vo.LoginUser;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.system.entity.SysTenant;
 import org.jeecg.modules.system.service.ISysTenantService;
@@ -16,9 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 
 /**
  * 租户配置信息
@@ -132,11 +132,11 @@ public class SysTenantController {
         }else {
             String[] ls = ids.split(",");
             // 过滤掉已被引用的租户
-            List<String> idList = new ArrayList<>();
+            List<Integer> idList = new ArrayList<>();
             for (String id : ls) {
                 int userCount = sysTenantService.countUserLinkTenant(id);
                 if (userCount == 0) {
-                    idList.add(id);
+                    idList.add(Integer.parseInt(id));
                 }
             }
             if (idList.size() > 0) {
@@ -190,4 +190,32 @@ public class SysTenantController {
         result.setResult(ls);
         return result;
     }
+    /**
+     *  查询当前用户的所有有效租户 【当前用于vue3版本】
+     * @return
+     */
+    @RequestMapping(value = "/getCurrentUserTenant", method = RequestMethod.GET)
+    public Result<Map<String,Object>> getCurrentUserTenant() {
+        Result<Map<String,Object>> result = new Result<Map<String,Object>>();
+        try {
+            LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
+            String tenantIds = sysUser.getRelTenantIds();
+            Map<String,Object> map = new HashMap<String,Object>();
+            if (oConvertUtils.isNotEmpty(tenantIds)) {
+                List<Integer> tenantIdList = new ArrayList<>();
+                for(String id: tenantIds.split(",")){
+                    tenantIdList.add(Integer.valueOf(id));
+                }
+                // 该方法仅查询有效的租户,如果返回0个就说明所有的租户均无效。
+                List<SysTenant> tenantList = sysTenantService.queryEffectiveTenant(tenantIdList);
+                map.put("list", tenantList);
+            }
+            result.setSuccess(true);
+            result.setResult(map);
+        }catch(Exception e) {
+            log.error(e.getMessage(), e);
+            result.error500("查询失败!");
+        }
+        return result;
+    }
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
index 68728ed..a6a12de 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserController.java
@@ -108,12 +108,38 @@ public class SysUserController {
 									  @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,HttpServletRequest req) {
 		Result<IPage<SysUser>> result = new Result<IPage<SysUser>>();
 		QueryWrapper<SysUser> queryWrapper = QueryGenerator.initQueryWrapper(user, req.getParameterMap());
-    	//TODO 外部模拟登陆临时账号,列表不显示
+        
+        //update-begin-Author:wangshuai--Date:20211119--for:【vue3】通过部门id查询用户,通过code查询id
+        //部门ID
+        String departId = req.getParameter("departId");
+        if(oConvertUtils.isNotEmpty(departId)){
+            LambdaQueryWrapper<SysUserDepart> query = new LambdaQueryWrapper<>();
+            query.eq(SysUserDepart::getDepId,departId);
+            List<SysUserDepart> list = sysUserDepartService.list(query);
+            List<String> userIds = list.stream().map(SysUserDepart::getUserId).collect(Collectors.toList());
+            queryWrapper.in("id",userIds);
+        }
+        //用户ID
+        String code = req.getParameter("code");
+        if(oConvertUtils.isNotEmpty(code)){
+            queryWrapper.in("id",Arrays.asList(code.split(",")));
+            pageSize = code.split(",").length;
+        }
+        //update-end-Author:wangshuai--Date:20211119--for:【vue3】通过部门id查询用户,通过code查询id
+
+        //update-begin-author:taoyan--date:20220104--for: JTC-372 【用户冻结问题】 online授权、用户组件,选择用户都能看到被冻结的用户
+        String status = req.getParameter("status");
+        if(oConvertUtils.isNotEmpty(status)){
+            queryWrapper.eq("status", Integer.parseInt(status));
+        }
+        //update-end-author:taoyan--date:20220104--for: JTC-372 【用户冻结问题】 online授权、用户组件,选择用户都能看到被冻结的用户
+
+        //TODO 外部模拟登陆临时账号,列表不显示
         queryWrapper.ne("username","_reserve_user_external");
 		Page<SysUser> page = new Page<SysUser>(pageNo, pageSize);
 		IPage<SysUser> pageList = sysUserService.page(page, queryWrapper);
 
-		//批量查询用户的所属部门
+        //批量查询用户的所属部门
         //step.1 先拿到全部的 useids
         //step.2 通过 useids,一次性查询用户的所属部门名字
         List<String> userIds = pageList.getRecords().stream().map(SysUser::getId).collect(Collectors.toList());
@@ -492,6 +518,8 @@ public class SysUserController {
                             errorMessage.add("第 " + lineNumber + " 行:手机号已经存在,忽略导入。");
                         } else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER_EMAIL)) {
                             errorMessage.add("第 " + lineNumber + " 行:电子邮件已经存在,忽略导入。");
+                        }  else if (message.contains(CommonConstant.SQL_INDEX_UNIQ_SYS_USER)) {
+                            errorMessage.add("第 " + lineNumber + " 行:违反表唯一性约束。");
                         } else {
                             errorMessage.add("第 " + lineNumber + " 行:未知错误,忽略导入");
                             log.error(e.getMessage(), e);
@@ -1187,7 +1215,7 @@ public class SysUserController {
      * @param jsonObject
      * @return
      */
-    @RequestMapping(value = "/appEdit", method = RequestMethod.PUT)
+    @RequestMapping(value = "/appEdit", method = {RequestMethod.PUT,RequestMethod.POST})
     public Result<SysUser> appEdit(HttpServletRequest request,@RequestBody JSONObject jsonObject) {
         Result<SysUser> result = new Result<SysUser>();
         try {
@@ -1305,7 +1333,9 @@ public class SysUserController {
      * @return
      */
     @GetMapping("/appQueryUser")
-    public Result<List<SysUser>> appQueryUser(@RequestParam(name = "keyword", required = false) String keyword) {
+    public Result<List<SysUser>> appQueryUser(@RequestParam(name = "keyword", required = false) String keyword,
+                                              @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+                                              @RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
         Result<List<SysUser>> result = new Result<List<SysUser>>();
         LambdaQueryWrapper<SysUser> queryWrapper =new LambdaQueryWrapper<SysUser>();
         //TODO 外部模拟登陆临时账号,列表不显示
@@ -1313,18 +1343,19 @@ public class SysUserController {
         if(StringUtils.isNotBlank(keyword)){
             queryWrapper.and(i -> i.like(SysUser::getUsername, keyword).or().like(SysUser::getRealname, keyword));
         }
-        List<SysUser> list = sysUserService.list(queryWrapper);
+        Page<SysUser> page = new Page<>(pageNo, pageSize);
+        IPage<SysUser> pageList = this.sysUserService.page(page, queryWrapper);
         //批量查询用户的所属部门
         //step.1 先拿到全部的 useids
         //step.2 通过 useids,一次性查询用户的所属部门名字
-        List<String> userIds = list.stream().map(SysUser::getId).collect(Collectors.toList());
+        List<String> userIds = pageList.getRecords().stream().map(SysUser::getId).collect(Collectors.toList());
         if(userIds!=null && userIds.size()>0){
             Map<String,String>  useDepNames = sysUserService.getDepNamesByUserIds(userIds);
-            list.forEach(item->{
+            pageList.getRecords().forEach(item->{
                 item.setOrgCodeTxt(useDepNames.get(item.getId()));
             });
         }
-        result.setResult(list);
+        result.setResult(pageList.getRecords());
         return result;
     }
 
@@ -1374,6 +1405,9 @@ public class SysUserController {
     @GetMapping("/getMultiUser")
     public List<SysUser> getMultiUser(SysUser sysUser){
         QueryWrapper<SysUser> queryWrapper = QueryGenerator.initQueryWrapper(sysUser, null);
+        //update-begin---author:wangshuai ---date:20220104  for:[JTC-297]已冻结用户仍可设置为代理人------------
+        queryWrapper.eq("status",Integer.parseInt(CommonConstant.STATUS_1));
+        //update-end---author:wangshuai ---date:20220104  for:[JTC-297]已冻结用户仍可设置为代理人------------
         List<SysUser> ls = this.sysUserService.list(queryWrapper);
         for(SysUser user: ls){
             user.setPassword(null);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java
index 4377f1a..576c9fd 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/SysUserOnlineController.java
@@ -1,8 +1,7 @@
 package org.jeecg.modules.system.controller;
 
-import java.util.*;
-
-import javax.annotation.Resource;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang.StringUtils;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
@@ -21,9 +20,11 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.web.bind.annotation.*;
 
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-
-import lombok.extern.slf4j.Slf4j;
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * @Description: 在线用户
@@ -63,8 +64,20 @@ public class SysUserOnlineController {
                 online.setToken(token);
                 //TODO 改成一次性查询
                 LoginUser loginUser = sysBaseAPI.getUserByName(JwtUtil.getUsername(token));
-                BeanUtils.copyProperties(loginUser, online);
-                onlineList.add(online);
+                if (loginUser != null) {
+                    //update-begin---author:wangshuai ---date:20220104  for:[JTC-382]在线用户查询无效------------
+                    //验证用户名是否与传过来的用户名相同
+                    boolean isMatchUsername=true;
+                    //判断用户名是否为空,并且当前循环的用户不包含传过来的用户名,那么就设成false
+                    if(oConvertUtils.isNotEmpty(username) && !loginUser.getUsername().contains(username)){
+                        isMatchUsername = false;
+                    }
+                    if(isMatchUsername){
+                        BeanUtils.copyProperties(loginUser, online);
+                        onlineList.add(online);
+                    }
+                    //update-end---author:wangshuai ---date:20220104  for:[JTC-382]在线用户查询无效------------
+                }
             }
         }
         Collections.reverse(onlineList);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java
index bff60e7..7363d55 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/controller/ThirdAppController.java
@@ -91,8 +91,12 @@ public class ThirdAppController {
     @GetMapping("/sync/wechatEnterprise/depart/toApp")
     public Result syncWechatEnterpriseDepartToApp(@RequestParam(value = "ids", required = false) String ids) {
         if (thirdAppConfig.isWechatEnterpriseEnabled()) {
-            boolean flag = wechatEnterpriseService.syncLocalDepartmentToThirdApp(ids);
-            return flag ? Result.OK("同步成功", null) : Result.error("同步失败");
+            SyncInfoVo syncInfo = wechatEnterpriseService.syncLocalDepartmentToThirdApp(ids);
+            if (syncInfo.getFailInfo().size() == 0) {
+                return Result.OK("同步成功", null);
+            } else {
+                return Result.error("同步失败", syncInfo);
+            }
         }
         return Result.error("企业微信同步功能已禁用");
     }
@@ -125,8 +129,12 @@ public class ThirdAppController {
     @GetMapping("/sync/dingtalk/depart/toApp")
     public Result syncDingtalkDepartToApp(@RequestParam(value = "ids", required = false) String ids) {
         if (thirdAppConfig.isDingtalkEnabled()) {
-            boolean flag = dingtalkService.syncLocalDepartmentToThirdApp(ids);
-            return flag ? Result.OK("同步成功", null) : Result.error("同步失败");
+            SyncInfoVo syncInfo = dingtalkService.syncLocalDepartmentToThirdApp(ids);
+            if (syncInfo.getFailInfo().size() == 0) {
+                return Result.OK("同步成功", null);
+            } else {
+                return Result.error("同步失败", syncInfo);
+            }
         }
         return Result.error("钉钉同步功能已禁用");
     }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepart.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepart.java
index b84181e..c0a9481 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepart.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysDepart.java
@@ -45,7 +45,7 @@ public class SysDepart implements Serializable {
 	/**描述*/
 	@Excel(name="描述",width=15)
 	private String description;
-	/**机构类别 1公司,2组织机构,2岗位*/
+	/**机构类别 1=公司,2=组织机构,3=岗位*/
 	@Excel(name="机构类别",width=15,dicCode="org_category")
 	private String orgCategory;
 	/**机构类型*/
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysPosition.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysPosition.java
index f7a3f12..ad113ab 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysPosition.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysPosition.java
@@ -54,7 +54,6 @@ public class SysPosition {
     /**
      * 公司id
      */
-    @Excel(name = "公司id", width = 15)
     @ApiModelProperty(value = "公司id")
     private java.lang.String companyId;
     /**
@@ -84,7 +83,6 @@ public class SysPosition {
     /**
      * 组织机构编码
      */
-    @Excel(name = "组织机构编码", width = 15)
     @ApiModelProperty(value = "组织机构编码")
     private java.lang.String sysOrgCode;
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java
index 22f0574..d9a0ca1 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/entity/SysThirdAccount.java
@@ -3,12 +3,14 @@ package org.jeecg.modules.system.entity;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.experimental.Accessors;
 import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
 
 /**
  * @Description: 第三方登录账号表
@@ -25,7 +27,7 @@ public class SysThirdAccount {
  
 	/**编号*/
 	@TableId(type = IdType.ASSIGN_ID)
-  @ApiModelProperty(value = "编号")
+    @ApiModelProperty(value = "编号")
 	private java.lang.String id;
 	/**第三方登录id*/
 	@Excel(name = "第三方登录id", width = 15)
@@ -59,4 +61,20 @@ public class SysThirdAccount {
 	@Excel(name = "第三方用户账号", width = 15)
 	@ApiModelProperty(value = "第三方用户账号")
 	private java.lang.String thirdUserId;
+    /**创建人*/
+    @Excel(name = "创建人", width = 15)
+    private java.lang.String createBy;
+    /**创建日期*/
+    @Excel(name = "创建日期", width = 20, format = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private java.util.Date createTime;
+    /**修改人*/
+    @Excel(name = "修改人", width = 15)
+    private java.lang.String updateBy;
+    /**修改日期*/
+    @Excel(name = "修改日期", width = 20, format = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    private java.util.Date updateTime;
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
index 1753b41..d569857 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/SysDictMapper.java
@@ -193,4 +193,15 @@ public interface SysDictMapper extends BaseMapper<SysDict> {
 	 */
 	@Deprecated
 	List<DictModel> queryAllTableDictItems(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql);
+
+	/**
+	 * 查询字典表的数据
+	 * @param table 表名
+	 * @param text   显示字段名
+	 * @param code   存储字段名
+	 * @param filterSql 条件sql
+	 * @param codeValues 存储字段值 作为查询条件in
+	 * @return
+	 */
+	List<DictModel> queryTableDictByKeysAndFilterSql(@Param("table") String table, @Param("text") String text, @Param("code") String code, @Param("filterSql") String filterSql,  @Param("codeValues") List<String> codeValues);
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
index 58539d3..7a4b388 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysDictMapper.xml
@@ -134,19 +134,24 @@
 			   ${pidField} as parentId
 			   from ${table}
 			   where
-			   <choose>
-				   <when test="pid != null and pid != ''">
-					   ${pidField} = #{pid}
-				   </when>
-				   <otherwise>
-					   (${pidField} = '' OR ${pidField} IS NULL)
-				   </otherwise>
-			   </choose>
+			   <!-- udapte-begin-author:sunjianlei date:20220110 for: 【JTC-597】自定义树查询条件查不出数据 -->
+			   <if test="query == null">
+				   <choose>
+					   <when test="pid != null and pid != ''">
+						   ${pidField} = #{pid}
+					   </when>
+					   <otherwise>
+						   (${pidField} = '' OR ${pidField} IS NULL)
+					   </otherwise>
+				   </choose>
+			   </if>
 			   <if test="query!= null">
+			       1 = 1
 				   <foreach collection="query.entrySet()" item="value"  index="key" >
-				   	and ${key} = #{value}
+				   	and ${key} LIKE #{value}
 				   </foreach>
 			   </if>
+			   <!-- udapte-end-author:sunjianlei date:20220110 for: 【JTC-597】自定义树查询条件查不出数据 -->
 	</select>
 
 
@@ -179,5 +184,18 @@
 	</select>
 
 
+	<!-- 查询字典表的数据 支持设置过滤条件、设置存储值作为in查询条件 -->
+	<select id="queryTableDictByKeysAndFilterSql" parameterType="String" resultType="org.jeecg.common.system.vo.DictModel">
+		select ${text} as "text", ${code} as "value" from ${table} where ${code} IN (
+		<foreach item="key" collection="codeValues" separator=",">
+			#{key}
+		</foreach>
+		)
+		<if test="filterSql != null and filterSql != ''">
+			and ${filterSql}
+		</if>
+	</select>
+
+
 
 </mapper>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserDepartMapper.xml b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserDepartMapper.xml
index c403eaa..92da725 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserDepartMapper.xml
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/mapper/xml/SysUserDepartMapper.xml
@@ -14,7 +14,9 @@
 		join sys_depart c on b.dep_id = c.id
 		where a.del_flag = 0 and c.org_code like '${orgCode}%'
 		<if test="realname!=null and realname!=''">
-			and a.realname like '%${realname}%'
+			<!-- update by sunjianlei 20220119【#3348】SQL injection exists in /sys/user/queryUserByDepId;  -->
+			<bind name="bindRealname" value="'%'+realname+'%'"/>
+			and a.realname like #{bindRealname}
 		</if>
 	</select>
 
@@ -23,12 +25,14 @@
 		select a.*, c.depart_name as org_code_txt from sys_user a
 		join sys_user_depart b on b.user_id = a.id
 		join sys_depart c on b.dep_id = c.id
-		where a.del_flag = 0 and c.org_code like '${orgCode}%'
+		where a.del_flag = 0 and a.status = 1 and c.org_code like '${orgCode}%'
 		<if test="username!=null and username!=''">
-			and a.username like '%${username}%'
+			<bind name="bindUsername" value="'%'+username+'%'"/>
+			and a.username like #{bindUsername}
 		</if>
 		<if test="realname!=null and realname!=''">
-			and a.realname like '%${realname}%'
+		    <bind name="bindRealname" value="'%'+realname+'%'"/>
+			and a.realname like #{bindRealname}
 		</if>
 	</select>
 </mapper>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/AnnouncementSendModel.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/AnnouncementSendModel.java
index 3c8e996..5437ec3 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/AnnouncementSendModel.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/model/AnnouncementSendModel.java
@@ -1,15 +1,12 @@
 package org.jeecg.modules.system.model;
 
-import java.io.Serializable;
-
-import org.springframework.format.annotation.DateTimeFormat;
-
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
-
 import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
 
 /**
  * @Description: 用户通告阅读标记表
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/rule/CategoryCodeRule.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/rule/CategoryCodeRule.java
index 91d3a17..29ed03c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/rule/CategoryCodeRule.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/rule/CategoryCodeRule.java
@@ -2,6 +2,7 @@ package org.jeecg.modules.system.rule;
 
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.handler.IFillRuleHandler;
 import org.jeecg.common.util.SpringContextUtils;
 import org.jeecg.common.util.YouBianCodeUtil;
@@ -16,12 +17,14 @@ import java.util.List;
  * @Date 2019/12/9 11:32
  * @Description: 分类字典编码生成规则
  */
+@Slf4j
 public class CategoryCodeRule implements IFillRuleHandler {
 
     public static final String ROOT_PID_VALUE = "0";
 
     @Override
     public Object execute(JSONObject params, JSONObject formData) {
+        log.info("系统自定义编码规则[category_code_rule],params:{} ,formData: {}", params, formData);
 
         String categoryPid = ROOT_PID_VALUE;
         String categoryCode = null;
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
index 8f5edfd..d389da2 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysDepartService.java
@@ -67,7 +67,7 @@ public interface ISysDepartService extends IService<SysDepart>{
      * @param keyWord
      * @return
      */
-    List<SysDepartTreeModel> searhBy(String keyWord,String myDeptSearch,String departIds);
+    List<SysDepartTreeModel> searchByKeyWord(String keyWord,String myDeptSearch,String departIds);
     
     /**
      * 根据部门id删除并删除其可能存在的子级部门
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java
index 80350a1..4142585 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/ISysTenantService.java
@@ -14,7 +14,7 @@ public interface ISysTenantService extends IService<SysTenant> {
      * @param idList
      * @return
      */
-    List<SysTenant> queryEffectiveTenant(Collection<String> idList);
+    List<SysTenant> queryEffectiveTenant(Collection<Integer> idList);
 
     /**
      * 返回某个租户被多少个用户引用了
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/IThirdAppService.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/IThirdAppService.java
index 84ae6fe..4116142 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/IThirdAppService.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/IThirdAppService.java
@@ -21,7 +21,7 @@ public interface IThirdAppService {
      *
      * @return 成功返回true
      */
-    boolean syncLocalDepartmentToThirdApp(String ids);
+    SyncInfoVo syncLocalDepartmentToThirdApp(String ids);
 
     /**
      * 将第三方App部门同步到本地<br>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java
index fe9335c..4c30eea 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysBaseApiImpl.java
@@ -146,7 +146,9 @@ public class SysBaseApiImpl implements ISysBaseAPI {
 				//通过自定义URL匹配规则 获取菜单(实现通过菜单配置数据权限规则,实际上针对获取数据接口进行数据规则控制)
 				String userMatchUrl = UrlMatchEnum.getMatchResultByUrl(requestPath);
 				LambdaQueryWrapper<SysPermission> queryQserMatch = new LambdaQueryWrapper<SysPermission>();
-				queryQserMatch.eq(SysPermission::getMenuType, 1);
+				// update-begin-author:taoyan date:20211027 for: online菜单如果配置成一级菜单 权限查询不到 取消menuType = 1
+				//queryQserMatch.eq(SysPermission::getMenuType, 1);
+				// update-end-author:taoyan date:20211027 for: online菜单如果配置成一级菜单 权限查询不到 取消menuType = 1
 				queryQserMatch.eq(SysPermission::getDelFlag, 0);
 				queryQserMatch.eq(SysPermission::getUrl, userMatchUrl);
 				if(oConvertUtils.isNotEmpty(userMatchUrl)){
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartPermissionServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartPermissionServiceImpl.java
index 9d6faf2..b9e72f1 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartPermissionServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartPermissionServiceImpl.java
@@ -69,7 +69,7 @@ public class SysDepartPermissionServiceImpl extends ServiceImpl<SysDepartPermiss
     @Override
     public List<SysPermissionDataRule> getPermRuleListByDeptIdAndPermId(String departId, String permissionId) {
         SysDepartPermission departPermission = this.getOne(new QueryWrapper<SysDepartPermission>().lambda().eq(SysDepartPermission::getDepartId, departId).eq(SysDepartPermission::getPermissionId, permissionId));
-        if(departPermission != null){
+        if(departPermission != null && oConvertUtils.isNotEmpty(departPermission.getDataRuleIds())){
             LambdaQueryWrapper<SysPermissionDataRule> query = new LambdaQueryWrapper<SysPermissionDataRule>();
             query.in(SysPermissionDataRule::getId, Arrays.asList(departPermission.getDataRuleIds().split(",")));
             query.orderByDesc(SysPermissionDataRule::getCreateTime);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
index 1293845..f1e55be 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDepartServiceImpl.java
@@ -300,7 +300,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 	 * </p>
 	 */
 	@Override
-	public List<SysDepartTreeModel> searhBy(String keyWord,String myDeptSearch,String departIds) {
+	public List<SysDepartTreeModel> searchByKeyWord(String keyWord,String myDeptSearch,String departIds) {
 		LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>();
 		List<SysDepartTreeModel> newList = new ArrayList<>();
 		//myDeptSearch不为空时为我的部门搜索,只搜索所负责部门
@@ -311,9 +311,15 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 			}
 			//根据部门id获取所负责部门
 			String[] codeArr = this.getMyDeptParentOrgCode(departIds);
-			for(int i=0;i<codeArr.length;i++){
-				query.or().likeRight(SysDepart::getOrgCode,codeArr[i]);
+			//update-begin-author:taoyan date:20220104 for:/issues/3311 当用户属于两个部门的时候,且这两个部门没有上下级关系,我的部门-部门名称查询条件模糊搜索失效!
+			if (codeArr != null && codeArr.length > 0) {
+				query.nested(i -> {
+					for (String s : codeArr) {
+						i.or().likeRight(SysDepart::getOrgCode, s);
+					}
+				});
 			}
+			//update-end-author:taoyan date:20220104 for:/issues/3311 当用户属于两个部门的时候,且这两个部门没有上下级关系,我的部门-部门名称查询条件模糊搜索失效!
 			query.eq(SysDepart::getDelFlag, CommonConstant.DEL_FLAG_0.toString());
 		}
 		query.like(SysDepart::getDepartName, keyWord);
@@ -499,7 +505,7 @@ public class SysDepartServiceImpl extends ServiceImpl<SysDepartMapper, SysDepart
 			}
 		};
 		LambdaQueryWrapper<SysDepart> lqw=new LambdaQueryWrapper();
-		lqw.eq(true,SysDepart::getDelFlag,CommonConstant.DEL_FLAG_0);
+		lqw.eq(true,SysDepart::getDelFlag,CommonConstant.DEL_FLAG_0.toString());
 		lqw.func(square);
 		lqw.orderByDesc(SysDepart::getDepartOrder);
 		List<SysDepart> list = list(lqw);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
index 3621d96..3382fb9 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysDictServiceImpl.java
@@ -163,7 +163,15 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 
 	@Override
 	public List<DictModel> queryTableDictTextByKeys(String table, String text, String code, List<String> keys) {
-		return sysDictMapper.queryTableDictTextByKeys(table, text, code, keys);
+		//update-begin-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件
+		String filterSql = null;
+		if(table.toLowerCase().indexOf("where")>0){
+			String[] arr = table.split(" (?i)where ");
+			table = arr[0];
+			filterSql = arr[1];
+		}
+		return sysDictMapper.queryTableDictByKeysAndFilterSql(table, text, code, filterSql, keys);
+		//update-end-author:taoyan date:20220113 for: @dict注解支持 dicttable 设置where条件
 	}
 
 	@Override
@@ -225,6 +233,11 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 			 insert = sysDictMapper.insert(sysDict);
 			if (sysDictItemList != null) {
 				for (SysDictItem entity : sysDictItemList) {
+                    //update-begin---author:wangshuai ---date:20220211  for:[JTC-1168]如果字典项值为空,则字典项忽略导入------------
+				    if(oConvertUtils.isEmpty(entity.getItemValue())){
+				        return -1;
+                    }
+                    //update-end---author:wangshuai ---date:20220211  for:[JTC-1168]如果字典项值为空,则字典项忽略导入------------
 					entity.setDictId(sysDict.getId());
 					entity.setStatus(1);
 					sysDictItemMapper.insert(entity);
@@ -255,7 +268,7 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 	public List<DictModel> queryLittleTableDictItems(String table, String text, String code, String condition, String keyword, int pageSize) {
     	Page<DictModel> page = new Page<DictModel>(1, pageSize);
 		page.setSearchCount(false);
-		String filterSql = getFilterSql(text, code, condition, keyword);
+		String filterSql = getFilterSql(table, text, code, condition, keyword);
 		IPage<DictModel> pageList = baseMapper.queryTableDictWithFilter(page, table, text, code, filterSql);
 		return pageList.getRecords();
 	}
@@ -268,12 +281,19 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 	 * @param keyword
 	 * @return
 	 */
-	private String getFilterSql(String text, String code, String condition, String keyword){
+	private String getFilterSql(String table, String text, String code, String condition, String keyword){
 		String keywordSql = null, filterSql = "", sql_where = " where ";
+		// update-begin-author:sunjianlei date:20220112 for: 【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错
+		if (table.toLowerCase().contains(" where ")) {
+			sql_where = " and ";
+		}
+		// update-end-author:sunjianlei date:20220112 for: 【JTC-631】判断如果 table 携带了 where 条件,那么就使用 and 查询,防止报错
 		if(oConvertUtils.isNotEmpty(keyword)){
 			// 判断是否是多选
 			if (keyword.contains(",")) {
-				String inKeywords = "\"" + keyword.replaceAll(",", "\",\"") + "\"";
+                //update-begin--author:scott--date:20220105--for:JTC-529【表单设计器】 编辑页面报错,in参数采用双引号导致 ----
+				String inKeywords = "'" + String.join("','", keyword.split(",")) + "'";
+                //update-end--author:scott--date:20220105--for:JTC-529【表单设计器】 编辑页面报错,in参数采用双引号导致----
 				keywordSql = "(" + text + " in (" + inKeywords + ") or " + code + " in (" + inKeywords + "))";
 			} else {
 				keywordSql = "("+text + " like '%"+keyword+"%' or "+ code + " like '%"+keyword+"%')";
@@ -290,14 +310,20 @@ public class SysDictServiceImpl extends ServiceImpl<SysDictMapper, SysDict> impl
 	}
 	@Override
 	public List<DictModel> queryAllTableDictItems(String table, String text, String code, String condition, String keyword) {
-		String filterSql = getFilterSql(text, code, condition, keyword);
+		String filterSql = getFilterSql(table, text, code, condition, keyword);
 		List<DictModel> ls = baseMapper.queryAllTableDictItems(table, text, code, filterSql);
     	return ls;
 	}
 
 	@Override
 	public List<TreeSelectModel> queryTreeList(Map<String, String> query,String table, String text, String code, String pidField,String pid,String hasChildField) {
-		return baseMapper.queryTreeList(query,table, text, code, pidField, pid,hasChildField);
+		List<TreeSelectModel> result = baseMapper.queryTreeList(query, table, text, code, pidField, pid, hasChildField);
+		// udapte-begin-author:sunjianlei date:20220110 for: 【JTC-597】如果 query 有值,就不允许展开子节点
+		if (query != null) {
+			result.forEach(r -> r.setLeaf(true));
+		}
+		return result;
+		// udapte-end-author:sunjianlei date:20220110 for: 【JTC-597】如果 query 有值,就不允许展开子节点
 	}
 
 	@Override
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java
index f545802..a4c4e85 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysTenantServiceImpl.java
@@ -24,10 +24,10 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
     ISysUserService userService;
 
     @Override
-    public List<SysTenant> queryEffectiveTenant(Collection<String> idList) {
+    public List<SysTenant> queryEffectiveTenant(Collection<Integer> idList) {
         LambdaQueryWrapper<SysTenant> queryWrapper = new LambdaQueryWrapper<>();
         queryWrapper.in(SysTenant::getId, idList);
-        queryWrapper.eq(SysTenant::getStatus, CommonConstant.STATUS_1);
+        queryWrapper.eq(SysTenant::getStatus, Integer.valueOf(CommonConstant.STATUS_1));
         //此处查询忽略时间条件
         return super.list(queryWrapper);
     }
@@ -50,7 +50,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
         if (userCount > 0) {
             throw new JeecgBootException("该租户已被引用,无法删除!");
         }
-        return super.removeById(id);
+        return super.removeById(Integer.parseInt(id));
     }
 
 }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java
index fde06dc..8d2345c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysThirdAccountServiceImpl.java
@@ -2,6 +2,7 @@ package org.jeecg.modules.system.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.extern.slf4j.Slf4j;
 import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.util.DateUtils;
 import org.jeecg.common.util.PasswordUtil;
@@ -30,6 +31,7 @@ import java.util.List;
  * @Version: V1.0
  */
 @Service
+@Slf4j
 public class SysThirdAccountServiceImpl extends ServiceImpl<SysThirdAccountMapper, SysThirdAccount> implements ISysThirdAccountService {
     
     @Autowired
@@ -116,6 +118,7 @@ public class SysThirdAccountServiceImpl extends ServiceImpl<SysThirdAccountMappe
     @Override
     public SysThirdAccount getOneBySysUserId(String sysUserId, String thirdType) {
         LambdaQueryWrapper<SysThirdAccount> queryWrapper = new LambdaQueryWrapper<>();
+        log.info("getSysUserId: {} ,getThirdType: {}",sysUserId,thirdType);
         queryWrapper.eq(SysThirdAccount::getSysUserId, sysUserId);
         queryWrapper.eq(SysThirdAccount::getThirdType, thirdType);
         return super.getOne(queryWrapper);
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java
index 018926e..143df8f 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserDepartServiceImpl.java
@@ -1,15 +1,10 @@
 package org.jeecg.modules.system.service.impl;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import java.util.stream.Collectors;
-
-import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.common.constant.CommonConstant;
 import org.jeecg.common.util.oConvertUtils;
 import org.jeecg.modules.system.entity.SysDepart;
 import org.jeecg.modules.system.entity.SysUser;
@@ -22,8 +17,11 @@ import org.jeecg.modules.system.service.ISysUserService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 /**
  * <P>
@@ -128,6 +126,9 @@ public class SysUserDepartServiceImpl extends ServiceImpl<SysUserDepartMapper, S
 		Page<SysUser> page = new Page<SysUser>(pageNo, pageSize);
 		if(oConvertUtils.isEmpty(departId)){
 			LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
+            //update-begin---author:wangshuai ---date:20220104  for:[JTC-297]已冻结用户仍可设置为代理人------------
+            query.eq(SysUser::getStatus,Integer.parseInt(CommonConstant.STATUS_1));
+            //update-end---author:wangshuai ---date:20220104  for:[JTC-297]已冻结用户仍可设置为代理人------------
 			if(oConvertUtils.isNotEmpty(username)){
 				query.like(SysUser::getUsername, username);
 			}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
index 7fab50e..cbb4eae 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/SysUserServiceImpl.java
@@ -399,6 +399,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
 	}
 
 	@Override
+	@CacheEvict(value={CacheConstant.SYS_USERS_CACHE}, allEntries=true)
 	public boolean revertLogicDeleted(List<String> userIds, SysUser updateEntity) {
 		String ids = String.format("'%s'", String.join("','", userIds));
 		return userMapper.revertLogicDeleted(ids, updateEntity) > 0;
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java
index 0e4b9e0..e596e14 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppDingtalkServiceImpl.java
@@ -85,18 +85,31 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
         return null;
     }
 
+    // update:2022-1-21,updateBy:sunjianlei; for 【JTC-704】【钉钉】部门同步成功,实际没成,后台提示ip白名单
     @Override
-    public boolean syncLocalDepartmentToThirdApp(String ids) {
+    public SyncInfoVo syncLocalDepartmentToThirdApp(String ids) {
+        SyncInfoVo syncInfo = new SyncInfoVo();
         String accessToken = this.getAccessToken();
         if (accessToken == null) {
-            return false;
+            syncInfo.addFailInfo("accessToken获取失败!");
+            return syncInfo;
         }
         // 获取【钉钉】所有的部门
-        List<Department> departments = JdtDepartmentAPI.listAll(accessToken);
+        List<Response<Department>> departments = JdtDepartmentAPI.listAllResponse(accessToken);
         // 删除钉钉有但本地没有的部门(以本地部门数据为主)(钉钉不能创建同名部门,只能先删除)
         List<SysDepart> sysDepartList = sysDepartService.list();
         for1:
-        for (Department department : departments) {
+        for (Response<Department> departmentRes : departments) {
+            // 判断部门是否查询成功
+            if (!departmentRes.isSuccess()) {
+                syncInfo.addFailInfo(departmentRes.getErrmsg());
+                // 88 是 ip 不在白名单的错误码,如果遇到此错误码,后面的操作都可以不用进行了,因为肯定都是失败的
+                if (new Integer(88).equals(departmentRes.getErrcode())) {
+                    return syncInfo;
+                }
+                continue;
+            }
+            Department department = departmentRes.getResult();
             for (SysDepart depart : sysDepartList) {
                 // id相同,代表已存在,不删除
                 String sourceIdentifier = department.getSource_identifier();
@@ -124,24 +137,34 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
         Department parent = new Department();
         parent.setDept_id(1);
         // 递归同步部门
-        departments = JdtDepartmentAPI.listAll(accessToken);
-        this.syncDepartmentRecursion(sysDepartsTree, departments, parent, accessToken);
-        return true;
+        departments = JdtDepartmentAPI.listAllResponse(accessToken);
+        this.syncDepartmentRecursion(sysDepartsTree, departments, parent, accessToken, syncInfo);
+        return syncInfo;
     }
 
     // 递归同步部门到本地
-    public void syncDepartmentRecursion(List<SysDepartTreeModel> sysDepartsTree, List<Department> departments, Department parent, String accessToken) {
+    public void syncDepartmentRecursion(List<SysDepartTreeModel> sysDepartsTree, List<Response<Department>> departments, Department parent, String accessToken, SyncInfoVo syncInfo) {
         if (sysDepartsTree != null && sysDepartsTree.size() != 0) {
             for1:
             for (SysDepartTreeModel depart : sysDepartsTree) {
-                for (Department department : departments) {
+                for (Response<Department> departmentRes : departments) {
+                    // 判断部门是否查询成功
+                    if (!departmentRes.isSuccess()) {
+                        syncInfo.addFailInfo(departmentRes.getErrmsg());
+                        continue;
+                    }
+                    Department department = departmentRes.getResult();
                     // id相同,代表已存在,执行修改操作
                     String sourceIdentifier = department.getSource_identifier();
                     if (sourceIdentifier != null && sourceIdentifier.equals(depart.getId())) {
                         this.sysDepartToDtDepartment(depart, department, parent.getDept_id());
-                        JdtDepartmentAPI.update(department, accessToken);
-                        // 紧接着同步子级
-                        this.syncDepartmentRecursion(depart.getChildren(), departments, department, accessToken);
+                        Response<JSONObject> response = JdtDepartmentAPI.update(department, accessToken);
+                        if (response.isSuccess()) {
+                            // 紧接着同步子级
+                            this.syncDepartmentRecursion(depart.getChildren(), departments, department, accessToken, syncInfo);
+                        }
+                        // 收集错误信息
+                        this.syncDepartCollectErrInfo(response, depart, syncInfo);
                         // 跳出外部循环
                         continue for1;
                     }
@@ -154,10 +177,10 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
                     Department newParent = new Department();
                     newParent.setDept_id(response.getResult());
                     // 紧接着同步子级
-                    this.syncDepartmentRecursion(depart.getChildren(), departments, newParent, accessToken);
+                    this.syncDepartmentRecursion(depart.getChildren(), departments, newParent, accessToken, syncInfo);
                 }
                 // 收集错误信息
-//                this.syncUserCollectErrInfo(errCode, sysUser, errInfo);
+                this.syncDepartCollectErrInfo(response, depart, syncInfo);
             }
         }
     }
@@ -209,6 +232,11 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
                     SysDepart newSysDepart = this.dtDepartmentToSysDepart(departmentTree, null);
                     if (sysParentId != null) {
                         newSysDepart.setParentId(sysParentId);
+                        // 2 = 组织机构
+                        newSysDepart.setOrgCategory("2");
+                    } else {
+                        // 1 = 公司
+                        newSysDepart.setOrgCategory("1");
                     }
                     try {
                         sysDepartService.saveDepartData(newSysDepart, username);
@@ -246,6 +274,20 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
         return false;
     }
 
+    /**
+     * 【同步部门】收集同步过程中的错误信息
+     */
+    private boolean syncDepartCollectErrInfo(Response<?> response, SysDepartTreeModel depart, SyncInfoVo syncInfo) {
+        if (!response.isSuccess()) {
+            String str = String.format("部门 %s(%s) 同步失败!错误码:%s——%s", depart.getDepartName(), depart.getOrgCode(), response.getErrcode(), response.getErrmsg());
+            syncInfo.addFailInfo(str);
+            return false;
+        } else {
+            String str = String.format("部门户 %s(%s) 同步成功!", depart.getDepartName(), depart.getOrgCode());
+            syncInfo.addSuccessInfo(str);
+            return true;
+        }
+    }
 
     @Override
     public SyncInfoVo syncLocalUserToThirdApp(String ids) {
@@ -279,7 +321,7 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
             /*
              * 判断是否同步过的逻辑:
              * 1. 查询 sys_third_account(第三方账号表)是否有数据,如果有代表已同步
-             * 2. 本地表里没有,就先用手机号判断,不通过再用username判断。
+             * 2. 本地表里没有,就先用手机号判断,不通过再用username(用户账号)判断。
              */
             SysThirdAccount sysThirdAccount = sysThirdAccountService.getOneBySysUserId(sysUser.getId(), THIRD_TYPE);
             if (sysThirdAccount != null && oConvertUtils.isNotEmpty(sysThirdAccount.getThirdUserId())) {
@@ -528,6 +570,12 @@ public class ThirdAppDingtalkServiceImpl implements IThirdAppService {
         // update-begin--Author:liusq Date:20210713 for:钉钉同步到本地的人员没有状态,导致同步之后无法登录 #I3ZC2L
         sysUser.setStatus(1);
         // update-end--Author:liusq Date:20210713 for:钉钉同步到本地的人员没有状态,导致同步之后无法登录 #I3ZC2L
+        // 设置工号,如果工号为空,则使用username
+        if (oConvertUtils.isEmpty(dtUser.getJob_number())) {
+            sysUser.setWorkNo(dtUser.getUserid());
+        } else {
+            sysUser.setWorkNo(dtUser.getJob_number());
+        }
         return this.dtUserToSysUser(dtUser, sysUser);
     }
 
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java
index 4796d32..c6f1b96 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/java/org/jeecg/modules/system/service/impl/ThirdAppWechatEnterpriseServiceImpl.java
@@ -96,15 +96,18 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
     }
 
     @Override
-    public boolean syncLocalDepartmentToThirdApp(String ids) {
+    public SyncInfoVo syncLocalDepartmentToThirdApp(String ids) {
+        SyncInfoVo syncInfo = new SyncInfoVo();
         String accessToken = this.getAccessToken();
         if (accessToken == null) {
-            return false;
+            syncInfo.addFailInfo("accessToken获取失败!");
+            return syncInfo;
         }
         // 获取企业微信所有的部门
         List<Department> departments = JwDepartmentAPI.getAllDepartment(accessToken);
         if (departments == null) {
-            return false;
+            syncInfo.addFailInfo("获取企业微信所有部门失败!");
+            return syncInfo;
         }
         // 删除企业微信有但本地没有的部门(以本地部门数据为主)(以为企业微信不能创建同名部门,所以只能先删除)
         List<JwDepartmentTreeVo> departmentTreeList = JwDepartmentTreeVo.listToTree(departments);
@@ -117,7 +120,7 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
         // 递归同步部门
         departments = JwDepartmentAPI.getAllDepartment(accessToken);
         this.syncDepartmentRecursion(sysDepartsTree, departments, parent, accessToken);
-        return true;
+        return syncInfo;
     }
 
     // 递归删除部门以及子部门,由于企业微信不允许删除带有成员和子部门的部门,所以需要递归删除下子部门,然后把部门成员移动端根部门下
@@ -250,6 +253,11 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
                     SysDepart newSysDepart = this.qwDepartmentToSysDepart(departmentTree, null);
                     if (sysParentId != null) {
                         newSysDepart.setParentId(sysParentId);
+                        // 2 = 组织机构
+                        newSysDepart.setOrgCategory("2");
+                    } else {
+                        // 1 = 公司
+                        newSysDepart.setOrgCategory("1");
                     }
                     try {
                         sysDepartService.saveDepartData(newSysDepart, username);
@@ -604,6 +612,10 @@ public class ThirdAppWechatEnterpriseServiceImpl implements IThirdAppService {
         BeanUtils.copyProperties(oldSysUser, sysUser);
         sysUser.setRealname(qwUser.getName());
         sysUser.setPost(qwUser.getPosition());
+        // 设置工号,由于企业微信没有工号的概念,所以只能用 userId 代替
+        if (oConvertUtils.isEmpty(sysUser.getWorkNo())) {
+            sysUser.setWorkNo(qwUser.getUserid());
+        }
         try {
             sysUser.setSex(Integer.parseInt(qwUser.getGender()));
         } catch (NumberFormatException ignored) {
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml
index 28b8d1c..e185687 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/application-prod.yml
@@ -197,7 +197,7 @@ jeecg :
   # ElasticSearch 设置
   elasticsearch:
     cluster-name: jeecg-ES
-    cluster-nodes: 81.70.47.128:9200
+    cluster-nodes: 127.0.0.1:9200
     check-enabled: true
   # 表单设计器配置
   desform:
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt b/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt
index 89959e6..75c70b1 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/banner.txt
@@ -9,6 +9,6 @@ ${AnsiColor.BRIGHT_BLUE}
 
 
 ${AnsiColor.BRIGHT_GREEN}
-Jeecg  Boot Version: 3.0
+Jeecg  Boot Version: 3.1.0
 Spring Boot Version: ${spring-boot.version}${spring-boot.formatted-version}
 ${AnsiColor.BLACK}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/utils.ftl b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/utils.ftl
index a801731..0acf2d5 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/utils.ftl
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/common/utils.ftl
@@ -115,9 +115,9 @@
       <#return "{type:'${po.classType}',value:'${po.fieldName}',text:'${po.filedComment}'}">
   <#else>
       <#if po.classType=="sel_search" || po.classType=="list_multi">
-          <#return "{type:'${po.classType}',value:'${po.fieldName}',text:'${po.filedComment}',dictTable:'${superQuery_dictTable}', dictText:'${superQuery_dictText}', dictCode:'${po.dictField}'}">
+          <#return "{type:'${po.classType}',value:'${po.fieldName}',text:'${po.filedComment}',dictTable:\"${superQuery_dictTable}\", dictText:'${superQuery_dictText}', dictCode:'${po.dictField}'}">
       <#elseif po.dictTable?? && po.dictTable!="" && po.classType!="sel_tree" && po.classType!="cat_tree" && po.classType!="link_down">
-          <#return "{type:'${po.fieldDbType}',value:'${po.fieldName}',text:'${po.filedComment}',dictCode:'${po.dictTable},${po.dictText},${po.dictField}'}">
+          <#return "{type:'${po.fieldDbType}',value:'${po.fieldName}',text:'${po.filedComment}',dictCode:\"${po.dictTable},${po.dictText},${po.dictField}\"}">
       <#elseif po.dictField?? && po.classType!="sel_tree" && po.classType!="cat_tree" && po.classType!="link_down">
           <#return "{type:'${po.fieldDbType}',value:'${po.fieldName}',text:'${po.filedComment}',dictCode:'${po.dictField}'}">
       <#elseif po.fieldDbType=="Text">
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index d28024b..9880823 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -65,10 +65,10 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 * @param req
 	 * @return
 	 */
-	@AutoLog(value = "${tableVo.ftlDescription}-分页列表查询")
+	//@AutoLog(value = "${tableVo.ftlDescription}-分页列表查询")
 	@ApiOperation(value="${tableVo.ftlDescription}-分页列表查询", notes="${tableVo.ftlDescription}-分页列表查询")
 	@GetMapping(value = "/list")
-	public Result<?> queryPageList(${entityName} ${entityName?uncap_first},
+	public Result<IPage<${entityName}>> queryPageList(${entityName} ${entityName?uncap_first},
 								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
 								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
 								   HttpServletRequest req) {
@@ -87,7 +87,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	@AutoLog(value = "${tableVo.ftlDescription}-添加")
 	@ApiOperation(value="${tableVo.ftlDescription}-添加", notes="${tableVo.ftlDescription}-添加")
 	@PostMapping(value = "/add")
-	public Result<?> add(@RequestBody ${entityName} ${entityName?uncap_first}) {
+	public Result<String> add(@RequestBody ${entityName} ${entityName?uncap_first}) {
 	    <#if bpm_flag>
         ${entityName?uncap_first}.setBpmStatus("1");
 	    </#if>
@@ -103,8 +103,8 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
 	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
-	@PutMapping(value = "/edit")
-	public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
+	public Result<String> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
 		${entityName?uncap_first}Service.updateById(${entityName?uncap_first});
 		return Result.OK("编辑成功!");
 	}
@@ -118,7 +118,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	@AutoLog(value = "${tableVo.ftlDescription}-通过id删除")
 	@ApiOperation(value="${tableVo.ftlDescription}-通过id删除", notes="${tableVo.ftlDescription}-通过id删除")
 	@DeleteMapping(value = "/delete")
-	public Result<?> delete(@RequestParam(name="id",required=true) String id) {
+	public Result<String> delete(@RequestParam(name="id",required=true) String id) {
 		${entityName?uncap_first}Service.removeById(id);
 		return Result.OK("删除成功!");
 	}
@@ -132,7 +132,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	@AutoLog(value = "${tableVo.ftlDescription}-批量删除")
 	@ApiOperation(value="${tableVo.ftlDescription}-批量删除", notes="${tableVo.ftlDescription}-批量删除")
 	@DeleteMapping(value = "/deleteBatch")
-	public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+	public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
 		this.${entityName?uncap_first}Service.removeByIds(Arrays.asList(ids.split(",")));
 		return Result.OK("批量删除成功!");
 	}
@@ -143,13 +143,13 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 * @param id
 	 * @return
 	 */
-	@AutoLog(value = "${tableVo.ftlDescription}-通过id查询")
+	//@AutoLog(value = "${tableVo.ftlDescription}-通过id查询")
 	@ApiOperation(value="${tableVo.ftlDescription}-通过id查询", notes="${tableVo.ftlDescription}-通过id查询")
 	@GetMapping(value = "/queryById")
-	public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
+	public Result<${entityName}> queryById(@RequestParam(name="id",required=true) String id) {
 		${entityName} ${entityName?uncap_first} = ${entityName?uncap_first}Service.getById(id);
 		if(${entityName?uncap_first}==null) {
-			return Result.error("未找到对应数据");
+			return Result.error("未找到对应数据",null);
 		}
 		return Result.OK(${entityName?uncap_first});
 	}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
index f26a79f..c0b44d9 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
@@ -108,8 +108,8 @@
 </#if>
 </#list>
       <#if bpm_flag>
-          <a-col v-if="showFlowSubmitButton" :span="24" style="text-align: center">
-            <a-button @click="submitForm">提 交</a-button>
+          <a-col v-if="showFlowSubmitButton" :span="24" style="width: 100%;text-align: center;">
+            <a-button icon="check" style="width: 126px" type="primary" @click="submitForm">提 交</a-button>
           </a-col>
      </#if>
         </a-row>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..8d02c15
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,218 @@
+<template>
+  <div>
+<#assign list_need_category=false>
+<#assign list_need_pca=false>
+<#assign bpm_flag=false>
+
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
+<#assign list_need_category=true>
+</#if>
+<#if po.classType=='pca'>
+<#assign list_need_pca=true>
+</#if>
+</#list>
+<#-- 结束循环 -->
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--插槽:table标题-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+          <a-dropdown v-if="checkedKeys.length > 0">
+              <template #overlay>
+                <a-menu>
+                  <a-menu-item key="1" @click="batchHandleDelete">
+                    <Icon icon="ant-design:delete-outlined"></Icon>
+                    删除
+                  </a-menu-item>
+                </a-menu>
+              </template>
+              <a-button>批量操作
+                <Icon icon="mdi:chevron-down"></Icon>
+              </a-button>
+        </a-dropdown>
+      </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+      <!--字段回显插槽-->
+      <template #htmlSlot="{text}">
+         <div v-html="text"></div>
+      </template>
+      <template #fileSlot="{text}">
+         <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
+         <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
+      </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
+  </div>
+</template>
+
+<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup>
+  import {ref, computed, unref} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import {useModal} from '/@/components/Modal';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import ${entityName}Modal from './components/${entityName}Modal.vue'
+  import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
+  <#if list_need_category>
+  import { loadCategoryData } from '/@/api/common/api'
+  import { getAuthCache, setAuthCache } from '/@/utils/auth';
+  import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
+  </#if>
+  const checkedKeys = ref<Array<string | number>>([]);
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+  //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+      tableProps:{
+           title: '${tableVo.ftlDescription}',
+           api: list,
+           columns,
+           canResize:false,
+           formConfig: {
+              labelWidth: 120,
+              schemas: searchFormSchema,
+              autoSubmitOnEnter:true,
+              showAdvancedButton:true,
+              fieldMapToTime: [
+              <#list columns as po>
+              <#if po.isQuery=='Y'>
+              <#if po.queryMode!='single'>
+              <#if po.classType=='date'>
+                 ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'],
+              <#elseif po.classType=='datetime'>
+                 ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'],
+              </#if>
+              </#if>
+              </#if>
+              </#list>
+              ],
+            },
+           actionColumn: {
+               width: 120,
+            },
+      },
+       exportConfig: {
+            name:"${tableVo.ftlDescription}",
+            url: getExportUrl,
+          },
+          importConfig: {
+            url: getImportUrl
+          },
+  })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+   /**
+    * 新增事件
+    */
+  function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+  }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+  async function handleDelete(record) {
+     await deleteOne({id: record.id}, reload);
+   }
+   /**
+    * 批量删除事件
+    */
+  async function batchHandleDelete() {
+     await batchDelete({ids: checkedKeys.value}, reload);
+   }
+   /**
+    * 成功回调
+    */
+  function handleSuccess() {
+      reload();
+   }
+   /**
+      * 操作栏
+      */
+  function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+   }
+     /**
+        * 下拉操作栏
+        */
+  function getDropDownAction(record){
+      return [
+           {
+             label: '详情',
+             onClick: handleDetail.bind(null, record),
+           }, {
+             label: '删除',
+             popConfirm: {
+               title: '是否确认删除',
+               confirm: handleDelete.bind(null, record),
+             }
+           }
+      ]
+   }
+    <#if list_need_category>
+   /**
+    * 初始化字典配置
+   */
+    function initDictConfig(){
+     <#list columns as po>
+     <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
+       <#if po.classType=='cat_tree' && list_need_category==true>
+       loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
+         if (res) {
+             let allDictDate = getAuthCache(DB_DICT_DATA_KEY);
+             if(!allDictDate['${po.dictField?default("")}']){
+               Object.assign(allDictDate,{'${po.dictField?default("")}':res})
+             }
+             setAuthCache(DB_DICT_DATA_KEY,allDictDate)
+         }
+       })
+       </#if>
+     </#if>
+     </#list>
+   }
+   initDictConfig();
+    </#if>
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..c579f91
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,61 @@
+import {defHttp} from '/@/utils/http/axios';
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/list',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..79551ce
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,354 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+//列表数据
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.isShowList =='Y' && po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.sort=='Y'>
+    sorter: true,
+   </#if>
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+    <#elseif po.fieldDbType=='Blob'>
+    dataIndex: '${po.fieldName}String'
+    <#elseif po.classType=='umeditor'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'htmlSlot' },
+    <#elseif po.classType=='pca'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'pcaSlot' },//TODO 未翻译
+   <#elseif po.classType=='file'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'fileSlot' },
+   <#elseif po.classType=='image'>
+    dataIndex: '${po.fieldName}',
+    customRender:render.renderAvatar,
+   <#elseif po.classType=='switch'>
+    dataIndex: '${po.fieldName}',
+<#assign switch_extend_arr=['Y','N']>
+<#if po.dictField?default("")?contains("[")>
+<#assign switch_extend_arr=po.dictField?eval>
+</#if>
+<#list switch_extend_arr as a>
+<#if a_index == 0>
+<#assign switch_extend_arr1=a>
+<#else>
+<#assign switch_extend_arr2=a>
+</#if>
+</#list>
+    customRender:({text}) => {
+       return  render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
+     },
+   <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
+    dataIndex: '${po.fieldName}_dictText'
+   <#elseif po.classType=='cat_tree'>
+    dataIndex: '${po.fieldName}',
+    <#if po.dictText?default("")?trim?length == 0>
+    customRender:({text}) => {
+       return  render.renderCategoryTree(text,'${po.dictField?default("")}')
+   },
+   <#else>
+    customRender: (text, record) => (text ? record['${po.dictText}'] : '')
+   </#if>
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isQuery=='Y'>
+<#assign query_flag=true>
+	<#assign query_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1>
+	    <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+    <#elseif po.dictField?default("")?trim?length gt 1>
+        <#assign query_field_dictCode="${po.dictField}">
+    </#if>
+<#if po.queryMode=='single'>
+	{
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='sel_search'>
+      component: 'JSearchSelect',
+      componentProps:{
+         dict:"${po.dictTable},${po.dictText},${po.dictField}"
+      },
+<#elseif po.classType=='sel_user'>
+      component: 'JSelectUserByDept',
+<#elseif po.classType=='switch'>
+      component: 'JSwitch',
+      componentProps:{
+           <#if po.dictField != 'is_open'>
+           options:"${po.dictField}"
+           </#if>
+       },
+ <#elseif po.classType=='sel_depart'>
+      component: 'JSelectDept',
+ <#elseif po.classType=='list_multi'>
+      component: 'JMultiSelectTag',//暂无该组件
+      componentProps:{
+          dictCode:"query_field_dictCode?default("")"
+      },
+ <#elseif po.classType=='cat_tree'>
+      component: 'JCategorySelect',
+      componentProps:{
+          pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题
+      },
+<#elseif po.classType=='date'>
+      component: 'DatePicker',
+<#elseif po.classType=='datetime'>
+      component: 'DatePicker',
+      componentProps: {
+         showTime:true
+       },
+<#elseif po.classType=='pca'>
+      component: 'JAreaLinkage',
+<#elseif po.classType=='popup'>
+      component: 'JPopup',
+      componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:"${po.dictField}",
+             multi:${po.extendParams.popupMulti?c},
+         }
+     },
+<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
+<#--  ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
+      component: 'JDictSelectTag',
+      componentProps:{
+       <#if po.dictTable?default("")?trim?length gt 1>
+          dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
+       <#elseif po.dictField?default("")?trim?length gt 1>
+          dictCode:"${po.dictField}"
+        </#if>
+      },
+<#else>
+      component: 'Input',
+</#if>
+      colProps: {span: 6},
+ 	},
+<#else>
+     {
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='date'>
+      component: 'RangePicker',
+<#elseif po.classType=='datetime'>
+      component: 'RangePicker',
+      componentProps: {
+          showTime:true
+      },
+<#else>
+      component: 'Input', //TODO 范围查询
+</#if>
+      colProps: {span: 6},
+	},
+</#if>
+</#if>
+</#list>
+<#-- 结束循环 -->
+];
+//表单数据
+export const formSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list columns as po><#rt/>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
new file mode 100644
index 0000000..8b6d314
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/one/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
@@ -0,0 +1,58 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit">
+      <BasicForm @register="registerForm"/>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {formSchema} from '../${entityName?uncap_first}.data';
+    import {saveOrUpdate} from '../${entityName?uncap_first}.api';
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    //表单配置
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+    });
+    //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await resetFields();
+        setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+        }
+        // 隐藏底部时禁用整个表单
+       setProps({ disabled: !data?.showFooter })
+    });
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+    //表单提交事件
+    async function handleSubmit(v) {
+        try {
+            let values = await validate();
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index 2772d2f..2fd8e2c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -119,7 +119,7 @@ public class ${entityName}Controller {
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
 	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
-	@PutMapping(value = "/edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) {
 		${entityName} ${entityName?uncap_first} = new ${entityName}();
 		BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first});
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
index f483d6a..5cd51c9 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
@@ -28,13 +28,8 @@
 	<#elseif po.dictField?default("")?trim?length gt 1>
 		<#assign form_field_dictCode="${po.dictField}">
 	</#if>
-	<#if po.classType =='textarea'>
-          <a-col :span="24">
-            <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}">
-	<#else>
           <a-col :span="${form_span}" >
             <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}">
-	</#if>
 	<#if po.classType =='date'>
               <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
 	<#elseif po.classType =='datetime'>
@@ -140,7 +135,7 @@
 </#list>
     </a-tabs>
     <#if bpm_flag>
-    <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button @click="handleOk">提 交</a-button></a-row>
+    <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button icon="check" style="width: 126px" type="primary" @click="handleOk">提 交</a-button></a-row>
      </#if>
   </a-spin>
 </template>
@@ -171,20 +166,12 @@
       return {
         labelCol: {
           xs: { span: 24 },
-          sm: { span: 6 },
+          sm: { span: 5 },
         },
         wrapperCol: {
           xs: { span: 24 },
           sm: { span: 16 },
         },
-        labelCol2: {
-          xs: { span: 24 },
-          sm: { span: 3 },
-        },
-        wrapperCol2: {
-          xs: { span: 24 },
-          sm: { span: 20 },
-        },
         model:{
         <#include "/common/init/initValue.ftl">
         },
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
index 3eb17a2..80dc0f7 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
@@ -25,13 +25,8 @@
 	<#elseif po.dictField?default("")?trim?length gt 1>
 		<#assign form_field_dictCode="${po.dictField}">
 	</#if>
-	<#if po.classType =='textarea'>
-          <a-col :span="24">
-            <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}">
-	<#else>
           <a-col :span="${form_span}">
             <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}">
-	</#if>
 	<#if po.classType =='date'>
               <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%"/>
 	<#elseif po.classType =='datetime'>
@@ -117,20 +112,12 @@
         },
         labelCol: {
           xs: { span: 24 },
-          sm: { span: 6 },
+          sm: { span: 5 },
         },
         wrapperCol: {
           xs: { span: 24 },
           sm: { span: 16 },
         },
-        labelCol2: {
-          xs: { span: 24 },
-          sm: { span: 3 },
-        },
-        wrapperCol2: {
-          xs: { span: 24 },
-          sm: { span: 20 },
-        },
         <#include "/common/validatorRulesTemplate/sub.ftl">
         confirmLoading: false,
       }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index 020d3f8..4c4d28c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -158,7 +158,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
 	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
-	@PutMapping(value = "/edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
 		${entityName?uncap_first}Service.update${entityName}(${entityName?uncap_first});
 		return Result.OK("编辑成功!");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..4db54d3
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,272 @@
+<template>
+  <div class="p-4">
+    <!--引用表格-->
+    <BasicTable @register="registerTable" :rowSelection="rowSelection" :expandedRowKeys="expandedRowKeys" @expand="handleExpand" @fetch-success="onFetchSuccess">
+      <!--插槽:table标题-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleCreate" preIcon="ant-design:plus-outlined"> 新增</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+
+          <a-dropdown v-if="selectedRowKeys.length > 0">
+          <template #overlay>
+            <a-menu>
+              <a-menu-item key="1" @click="batchHandleDelete">
+                <Icon icon="ant-design:delete-outlined"></Icon>
+                删除
+              </a-menu-item>
+            </a-menu>
+          </template>
+          <a-button>批量操作
+            <Icon icon="ant-design:down-outlined"></Icon>
+          </a-button>
+        </a-dropdown>
+      </template>
+      <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)"/>
+      </template>
+    </BasicTable>
+    <!--字典弹窗-->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"/>
+  </div>
+</template>
+
+<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup>
+  //ts语法
+  import {ref, computed, unref, toRaw, nextTick} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/src/components/Table';
+  import {useModal} from '/src/components/Modal';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import ${entityName}Modal from './components/${entityName}Modal.vue';
+  import {columns} from './${entityName}.data';
+  import {list, delete${entityName}, batchDelete${entityName}, getExportUrl,getImportUrl, getChildList,getChildListBatch} from './${entityName}.api';
+
+  const expandedRowKeys = ref([]);
+  //字典model
+  const [registerModal, {openModal}] = useModal();
+   //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+    tableProps:{
+         title: '${tableVo.ftlDescription}',
+         columns,
+         canResize:false,
+         actionColumn: {
+             width: 120,
+          },
+    },
+     exportConfig: {
+          name:"${tableVo.ftlDescription}",
+          url: getExportUrl,
+        },
+        importConfig: {
+          url: getImportUrl,
+          success:importSuccess
+        },
+    })
+
+  const [registerTable, {reload, collapseAll, updateTableDataRecord, findTableDataRecord,getDataSource},{ rowSelection, selectedRowKeys }] = tableContext
+
+  /**
+   * 新增事件
+   */
+  function handleCreate() {
+    openModal(true, {
+      isUpdate: false,
+    });
+  }
+
+  /**
+   * 编辑事件
+   */
+  async function handleEdit(record) {
+    openModal(true, {
+      record,
+      isUpdate: true,
+    });
+  }
+
+  /**
+   * 详情
+   */
+  async function handleDetail(record) {
+    openModal(true, {
+      record,
+      isUpdate: true,
+      hideFooter: true,
+    });
+  }
+
+  /**
+   * 删除事件
+   */
+  async function handleDelete(record) {
+    await delete${entityName}({id: record.id}, importSuccess);
+  }
+
+  /**
+   * 批量删除事件
+   */
+  async function batchHandleDelete() {
+    const ids = selectedRowKeys.value.filter(item => !item.includes('loading'))
+    await batchDelete${entityName}({ids: ids}, importSuccess);
+  }
+  /**
+   * 导入
+   */
+   function importSuccess() {
+    reload() && (expandedRowKeys.value = []);
+  }
+  /**
+   * 添加下级
+   */
+  function handleAddSub(record) {
+    openModal(true, {
+      record,
+      isUpdate: false,
+    });
+  }
+  /**
+   * 成功回调
+   */
+  async function handleSuccess({isUpdate, values, expandedArr}) {
+    if (isUpdate) {
+      //编辑回调
+      updateTableDataRecord(values.id, values);
+    } else {
+        if(!values['pid']){
+            //新增根节点
+            reload();
+        }else{
+            //新增子集
+            expandedRowKeys.value = [];
+            for (let key of unref(expandedArr)) {
+                await expandTreeNode(key)
+            }
+        }
+    }
+  }
+
+  /**
+   * 接口请求成功后回调
+   */
+  function onFetchSuccess(result) {
+      getDataByResult(result.items)&&loadDataByExpandedRows();
+  }
+  /**
+   * 根据已展开的行查询数据(用于保存后刷新时异步加载子级的数据)
+   */
+  async function loadDataByExpandedRows() {
+      if (unref(expandedRowKeys).length > 0) {
+          const res = await getChildListBatch({ parentIds: unref(expandedRowKeys).join(',')});
+          if (res.success && res.result.records.length>0) {
+              //已展开的数据批量子节点
+              let records = res.result.records
+              const listMap = new Map();
+              for (let item of records) {
+                  let pid = item['pid'];
+                  if (unref(expandedRowKeys).includes(pid)) {
+                      let mapList = listMap.get(pid);
+                      if (mapList == null) {
+                          mapList = [];
+                      }
+                      mapList.push(item);
+                      listMap.set(pid, mapList);
+                  }
+              }
+              let childrenMap = listMap;
+              let fn = (list) => {
+                  if(list) {
+                      list.forEach(data => {
+                          if (unref(expandedRowKeys).includes(data.id)) {
+                              data.children = getDataByResult(childrenMap.get(data.id))
+                              fn(data.children)
+                          }
+                      })
+                  }
+              };
+              fn(getDataSource())
+          }
+      }
+  }
+  /**
+   * 处理数据集
+   */
+  function getDataByResult(result){
+      if(result && result.length>0){
+          return result.map(item=>{
+              //判断是否标记了带有子节点
+              if(item["hasChild"]=='1'){
+                  let loadChild = { id: item.id+'_loadChild', name: 'loading...', isLoading: true }
+                  item.children = [loadChild]
+              }
+              return item
+          })
+      }
+  }
+  /**
+   *树节点展开合并
+   * */
+  async function handleExpand(expanded, record) {
+    // 判断是否是展开状态,展开状态(expanded)并且存在子集(children)并且未加载过(isLoading)的就去查询子节点数据
+    if (expanded) {
+       expandedRowKeys.value.push(record.id)
+      if (record.children.length > 0 && !!record.children[0].isLoading) {
+        let result = await getChildList({pid: record.id});
+        result=result.records?result.records:result;
+        if (result && result.length > 0) {
+          record.children = getDataByResult(result);
+        } else {
+          record.children = null
+          record.hasChild = '0'
+        }
+      }
+    } else {
+      let keyIndex = expandedRowKeys.value.indexOf(record.id)
+      if (keyIndex >= 0) {
+        expandedRowKeys.value.splice(keyIndex, 1);
+      }
+    }
+  }
+  /**
+   *操作表格后处理树节点展开合并
+   * */
+  async function expandTreeNode(key) {
+    let record = findTableDataRecord(key)
+    expandedRowKeys.value.push(key);
+      let result = await getChildList({pid: key});
+      if (result && result.length > 0) {
+          record.children = getDataByResult(result);
+      } else {
+          record.children = null
+          record.hasChild = '0'
+      }
+      updateTableDataRecord(key, record);
+  }
+  /**
+   * 操作栏
+   */
+  function getTableAction(record) {
+    return [
+      {
+        label: '编辑',
+        onClick: handleEdit.bind(null, record),
+      },
+      {
+        label: '删除',
+        popConfirm: {
+          title: '确定删除吗?',
+          confirm: handleDelete.bind(null, record),
+        },
+      },
+      {
+        label: '添加下级',
+        onClick: handleAddSub.bind(null, {pid: record.id}),
+      }
+    ]
+  }
+</script>
+
+<style scoped>
+
+</style>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..df69b12
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,82 @@
+import {defHttp} from "/@/utils/http/axios";
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/rootList',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  delete${entityName} = '/sys/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+  loadTreeData = '/${entityPackage}/${entityName?uncap_first}/loadTreeRoot',
+  getChildList = '/${entityPackage}/${entityName?uncap_first}/childList',
+  getChildListBatch = '/${entityPackage}/${entityName?uncap_first}/getChildListBatch',
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+/**
+ * 导入api
+ * @param params
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+/**
+ * 删除
+ */
+export const delete${entityName} = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.delete${entityName}, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete${entityName} = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdateDict = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
+/**
+ * 查询全部树形节点数据
+ * @param params
+ */
+export const loadTreeData = (params) =>
+  defHttp.get({url: Api.loadTreeData,params});
+/**
+ * 查询子节点数据
+ * @param params
+ */
+export const getChildList = (params) =>
+  defHttp.get({url: Api.getChildList, params});
+/**
+ * 批量查询子节点数据
+ * @param params
+ */
+export const getChildListBatch = (params) =>
+  defHttp.get({url: Api.getChildListBatch, params},{isTransformResponse:false});
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..4595cb2
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,354 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+//列表数据
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.isShowList =='Y' && po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.sort=='Y'>
+    sorter: true,
+   </#if>
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+    <#elseif po.fieldDbType=='Blob'>
+    dataIndex: '${po.fieldName}String'
+    <#elseif po.classType=='umeditor'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'htmlSlot' },
+    <#elseif po.classType=='pca'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'pcaSlot' },//TODO 未翻译
+   <#elseif po.classType=='file'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'fileSlot' },
+   <#elseif po.classType=='image'>
+    dataIndex: '${po.fieldName}',
+    customRender:render.renderAvatar,
+   <#elseif po.classType=='switch'>
+    dataIndex: '${po.fieldName}',
+<#assign switch_extend_arr=['Y','N']>
+<#if po.dictField?default("")?contains("[")>
+<#assign switch_extend_arr=po.dictField?eval>
+</#if>
+<#list switch_extend_arr as a>
+<#if a_index == 0>
+<#assign switch_extend_arr1=a>
+<#else>
+<#assign switch_extend_arr2=a>
+</#if>
+</#list>
+    customRender:({text}) => {
+       return  render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
+     },
+   <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
+    dataIndex: '${po.fieldName}_dictText'
+   <#elseif po.classType=='cat_tree'>
+    dataIndex: '${po.fieldName}',
+    <#if po.dictText?default("")?trim?length == 0>
+    customRender:({text}) => {
+       return  render.renderCategoryTree(text,'${po.dictField?default("")}')
+   },
+   <#else>
+    customRender: (text, record) => (text ? record['${po.dictText}'] : '')
+   </#if>
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isQuery=='Y'>
+<#assign query_flag=true>
+	<#assign query_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1>
+	    <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+    <#elseif po.dictField?default("")?trim?length gt 1>
+        <#assign query_field_dictCode="${po.dictField}">
+    </#if>
+<#if po.queryMode=='single'>
+	{
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='sel_search'>
+      component: 'JSearchSelect',
+      componentProps:{
+         dict:"${po.dictTable},${po.dictText},${po.dictField}"
+      },
+<#elseif po.classType=='sel_user'>
+      component: 'JSelectUserByDept',
+<#elseif po.classType=='switch'>
+      component: 'JSwitch',
+      componentProps:{
+           <#if po.dictField != 'is_open'>
+           options:"${po.dictField}"
+           </#if>
+       },
+ <#elseif po.classType=='sel_depart'>
+      component: 'JSelectDept',
+ <#elseif po.classType=='list_multi'>
+      component: 'JMultiSelectTag',//暂无该组件
+      componentProps:{
+          dictCode:"query_field_dictCode?default("")"
+      },
+ <#elseif po.classType=='cat_tree'>
+      component: 'JCategorySelect',
+      componentProps:{
+          pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题
+      },
+<#elseif po.classType=='date'>
+      component: 'DatePicker',
+<#elseif po.classType=='datetime'>
+      component: 'DatePicker',
+      componentProps: {
+         showTime:true
+       },
+<#elseif po.classType=='pca'>
+      component: 'JAreaLinkage',
+<#elseif po.classType=='popup'>
+      component: 'JPopup',
+      componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:"${po.dictField}",
+             multi:${po.extendParams.popupMulti?c},
+         }
+     },
+<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
+<#--  ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
+      component: 'JDictSelectTag',
+      componentProps:{
+       <#if po.dictTable?default("")?trim?length gt 1>
+          dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
+       <#elseif po.dictField?default("")?trim?length gt 1>
+          dictCode:"${po.dictField}"
+        </#if>
+      },
+<#else>
+      component: 'Input',
+</#if>
+      colProps: {span: 6},
+     },
+<#else>
+     {
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='date'>
+      component: 'RangePicker',
+<#elseif po.classType=='datetime'>
+      component: 'RangePicker',
+      componentProps: {
+          showTime:true
+      },
+<#else>
+      component: 'Input', //TODO 范围查询
+</#if>
+      colProps: {span: 6},
+	},
+</#if>
+</#if>
+</#list>
+<#-- 结束循环 -->
+];
+//表单数据
+export const formSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list columns as po><#rt/>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
new file mode 100644
index 0000000..2360e9b
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/default/tree/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
@@ -0,0 +1,87 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="getTitle" @ok="handleSubmit">
+    <BasicForm @register="registerForm"/>
+  </BasicModal>
+</template>
+<script lang="ts" setup>
+  import {ref, computed, unref} from 'vue';
+  import {BasicModal, useModalInner} from '/src/components/Modal';
+  import {BasicForm, useForm} from '/src/components/Form';
+  import {formSchema} from '../${entityName?uncap_first}.data';
+  import {loadTreeData, saveOrUpdateDict} from '../${entityName?uncap_first}.api';
+  // 获取emit
+  const emit = defineEmits(['register', 'success']);
+  const isUpdate = ref(true);
+  const expandedRowKeys = ref([]);
+  const treeData = ref([]);
+  //表单配置
+  const [registerForm, {resetFields, setFieldsValue, validate, updateSchema}] = useForm({
+    schemas: formSchema,
+    showActionButtonGroup: false,
+    labelCol: {
+      xs: { span: 24 },
+      sm: { span: 4 },
+    },
+    wrapperCol: {
+      xs: { span: 24 },
+      sm: { span: 18 },
+    },
+  });
+  //表单赋值
+  const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+    //重置表单
+    await resetFields();
+    expandedRowKeys.value = [];
+    setModalProps({confirmLoading: false, minHeight: 80});
+    isUpdate.value = !!data?.isUpdate;
+    if (data?.record) {
+      //表单赋值
+      await setFieldsValue({
+        ...data.record,
+      });
+    }
+    //父级节点树信息
+    treeData.value = await loadTreeData({'async': false,'pcode':''});
+    updateSchema({
+      field: 'pid',
+      componentProps: {treeData},
+    });
+  });
+  //设置标题
+  const getTitle = computed(() => (!unref(isUpdate) ? '新增字典' : '编辑字典'));
+
+  /**
+   * 根据pid获取展开的节点
+   * @param pid
+   * @param arr
+   */
+  function getExpandKeysByPid(pid,arr){
+    if(pid && arr && arr.length>0){
+      for(let i=0;i<arr.length;i++){
+        if(arr[i].key==pid && unref(expandedRowKeys).indexOf(pid)<0){
+          expandedRowKeys.value.push(arr[i].key);
+          getExpandKeysByPid(arr[i]['parentId'],unref(treeData))
+        }else{
+          getExpandKeysByPid(pid,arr[i].children)
+        }
+      }
+    }
+  }
+  //表单提交事件
+  async function handleSubmit() {
+    try {
+      let values = await validate();
+      setModalProps({confirmLoading: true});
+      //提交表单
+      await saveOrUpdateDict(values, isUpdate.value);
+      //关闭弹窗
+      closeModal();
+      //展开的节点信息
+      await getExpandKeysByPid(values['pid'],unref(treeData))
+      //刷新列表(isUpdate:是否编辑;values:表单信息;expandedArr:展开的节点信息)
+      emit('success', {isUpdate: unref(isUpdate), values:{...values},expandedArr: unref(expandedRowKeys).reverse()});
+    } finally {
+      setModalProps({confirmLoading: false});
+    }
+  }
+</script>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index 10fab4a..1c0e3a6 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -103,7 +103,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
      */
     @AutoLog(value = "${tableVo.ftlDescription}-编辑")
     @ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
-    @PutMapping(value = "/edit")
+    @RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
     public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
         ${entityName?uncap_first}Service.updateById(${entityName?uncap_first});
         return Result.OK("编辑成功!");
@@ -194,7 +194,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 */
 	@AutoLog(value = "${sub.ftlDescription}-编辑")
 	@ApiOperation(value="${sub.ftlDescription}-编辑", notes="${sub.ftlDescription}-编辑")
-	@PutMapping(value = "/edit${sub.entityName}")
+	@RequestMapping(value = "/edit${sub.entityName}", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit${sub.entityName}(@RequestBody ${sub.entityName} ${sub.entityName?uncap_first}) {
 		${sub.entityName?uncap_first}Service.updateById(${sub.entityName?uncap_first});
 		return Result.OK("编辑成功!");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
index 7bab3da..c59a905 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
@@ -371,7 +371,7 @@
             this.$set(this.dictOptions, '${po.fieldName}', res.result)
           }
         })
-        <#elseif po.classType=='sel_search' || po.classType=='list_multi' || po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
+        <#elseif po.classType=='radio' || po.classType=='checkbox'>
         	<#assign list_field_dictCode="">
 	        <#if po.dictTable?default("")?trim?length gt 1>
 				<#assign list_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/[1-n]List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/[1-n]List.vuei
index 8226d37..557e0a5 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/[1-n]List.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue/[1-n]List.vuei
@@ -15,8 +15,6 @@
         @change="handleImportExcel">
           <a-button type="primary" icon="import">导入</a-button>
       </a-upload>
-      <!-- 高级查询区域 -->
-      <j-super-query :fieldList="superFieldList" ref="superQueryModal" @handleSuperQuery="handleSuperQuery"></j-super-query>
       <a-dropdown v-if="selectedRowKeys.length > 0">
         <a-menu slot="overlay">
           <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item>
@@ -192,12 +190,10 @@
          </#if>
          </#if>
          </#list>
-        },
-        superFieldList:[],
+        }
       }
     },
     created() {
-      this.getSuperFieldList();
     },
     computed: {
       importExcelUrl(){
@@ -209,15 +205,8 @@
         this.dataSource=[]
         this.selectedRowKeys=[]
         this.ipagination.current = 1
-      },
-      getSuperFieldList(){
-        <#include "/common/utils.ftl">
-        let fieldList=[];
-         <#list columns as po>
-        fieldList.push(${superQueryFieldList(po)})
-         </#list>
-        this.superFieldList = fieldList
       }
+
     }
   }
 </script>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..85debf1
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,236 @@
+<template>
+  <div>
+<#assign list_need_category=false>
+<#assign list_need_pca=false>
+<#assign bpm_flag=false>
+
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
+<#assign list_need_category=true>
+</#if>
+<#if po.classType=='pca'>
+<#assign list_need_pca=true>
+</#if>
+</#list>
+<#-- 结束循环 -->
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--插槽:table标题-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+          <a-dropdown v-if="selectedRowKeys.length > 0">
+              <template #overlay>
+                <a-menu>
+                  <a-menu-item key="1" @click="batchHandleDelete">
+                    <Icon icon="ant-design:delete-outlined"></Icon>
+                    删除
+                  </a-menu-item>
+                </a-menu>
+              </template>
+              <a-button>批量操作
+                <Icon icon="mdi:chevron-down"></Icon>
+              </a-button>
+        </a-dropdown>
+      </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+      <!--字段回显插槽-->
+      <template #htmlSlot="{text}">
+         <div v-html="text"></div>
+      </template>
+      <template #fileSlot="{text}">
+         <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
+         <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
+      </template>
+    </BasicTable>
+   <!--子表表格tab-->
+    <a-tabs defaultActiveKey="1">
+        <#assign sub_seq=1>
+        <#list subTables as sub>
+        <a-tab-pane tab="${sub.ftlDescription}" key="${sub_seq}" <#if sub_seq gt 1>forceRender</#if>>
+           <${sub.entityName}List/>
+        </a-tab-pane>
+        <#assign sub_seq=sub_seq+1>
+        </#list>
+     </a-tabs>
+    <!-- 表单区域 -->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
+  </div>
+</template>
+
+<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup>
+  import {ref, computed, unref,provide} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {useModal} from '/@/components/Modal';
+  import ${entityName}Modal from './components/${entityName}Modal.vue'
+<#list subTables as sub>
+  import ${sub.entityName}List from './${sub.entityName}List.vue'
+</#list>
+  import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
+  <#if list_need_category>
+  import { loadCategoryData } from '/@/api/common/api'
+  import { getAuthCache, setAuthCache } from '/@/utils/auth';
+  import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
+  </#if>
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+   //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+      tableProps:{
+           title: '${tableVo.ftlDescription}',
+           api: list,
+           columns,
+           canResize:false,
+           rowSelection: {type: 'radio'},
+           formConfig: {
+                schemas: searchFormSchema,
+                fieldMapToTime: [
+                <#list columns as po>
+                <#if po.isQuery=='Y'>
+                <#if po.queryMode!='single'>
+                <#if po.classType=='date'>
+                   ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'],
+                <#elseif po.classType=='datetime'>
+                   ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'],
+                </#if>
+                </#if>
+                </#if>
+                </#list>
+                ],
+            },
+            actionColumn: {
+               width: 120,
+            },
+            pagination:{
+                current: 1,
+                pageSize: 5,
+                pageSizeOptions: ['5', '10', '20'],
+            }
+        },
+        exportConfig: {
+            name:"${tableVo.ftlDescription}",
+            url: getExportUrl,
+        },
+        importConfig: {
+            url: getImportUrl
+        },
+    })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+  const mainId = computed(() => (unref(selectedRowKeys).length > 0 ? unref(selectedRowKeys)[0] : ''));
+  //下发 mainId,子组件接收
+  provide('mainId', mainId);
+   /**
+    * 新增事件
+    */
+  function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+  }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+  async function handleDelete(record) {
+     await deleteOne({id: record.id}, reload);
+   }
+   /**
+    * 批量删除事件
+    */
+  async function batchHandleDelete() {
+     await batchDelete({ids: selectedRowKeys.value}, reload);
+   }
+   /**
+    * 成功回调
+    */
+  function handleSuccess() {
+      reload();
+   }
+   /**
+      * 操作栏
+      */
+  function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+   }
+     /**
+        * 下拉操作栏
+        */
+  function getDropDownAction(record){
+      return [
+           {
+             label: '详情',
+             onClick: handleDetail.bind(null, record),
+           }, {
+             label: '删除',
+             popConfirm: {
+               title: '是否确认删除',
+               confirm: handleDelete.bind(null, record),
+             }
+           }
+      ]
+   }
+    <#if list_need_category>
+   /**
+    * 初始化字典配置
+   */
+    function initDictConfig(){
+     <#list columns as po>
+     <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
+       <#if po.classType=='cat_tree' && list_need_category==true>
+       loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
+         if (res) {
+             let allDictDate = getAuthCache(DB_DICT_DATA_KEY);
+             if(!allDictDate['${po.dictField?default("")}']){
+               Object.assign(allDictDate,{'${po.dictField?default("")}':res})
+             }
+             setAuthCache(DB_DICT_DATA_KEY,allDictDate)
+         }
+       })
+       </#if>
+     </#if>
+     </#list>
+   }
+   initDictConfig();
+    </#if>
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..c94300a
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,113 @@
+import {defHttp} from '/@/utils/http/axios';
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/list',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+<#list subTables as sub><#rt/>
+  ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/list${sub.entityName}ByMainId',
+  ${sub.entityName?uncap_first}Save='/${entityPackage}/${entityName?uncap_first}/add${sub.entityName}',
+  ${sub.entityName?uncap_first}Edit='/${entityPackage}/${entityName?uncap_first}/edit${sub.entityName}',
+  ${sub.entityName?uncap_first}Delete = '/${entityPackage}/${entityName?uncap_first}/delete${sub.entityName}',
+  ${sub.entityName?uncap_first}DeleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch${sub.entityName}',
+  ${sub.entityName?uncap_first}ExportXlsUrl = '/${entityPackage}/${entityName?uncap_first}/export${sub.entityName}',
+  ${sub.entityName?uncap_first}ImportUrl = '/${entityPackage}/${entityName?uncap_first}/import${sub.entityName}',
+</#list>
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
+<#list subTables as sub><#rt/>
+/**
+ * 列表接口
+ * @param params
+ */
+export const ${sub.entityName?uncap_first}List = (params) =>
+  defHttp.get({url: Api.${sub.entityName?uncap_first}List, params});
+
+/**
+ * 删除单个
+ */
+export const ${sub.entityName?uncap_first}Delete = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.${sub.entityName?uncap_first}Delete, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const ${sub.entityName?uncap_first}DeleteBatch = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.${sub.entityName?uncap_first}DeleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const  ${sub.entityName?uncap_first}SaveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.${sub.entityName?uncap_first}Edit : Api.${sub.entityName?uncap_first}Save;
+  return defHttp.post({url: url, params});
+}
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..51c81c7
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,601 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+//列表数据
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.isShowList =='Y' && po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.sort=='Y'>
+    sorter: true,
+   </#if>
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+    <#elseif po.fieldDbType=='Blob'>
+    dataIndex: '${po.fieldName}String'
+    <#elseif po.classType=='umeditor'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'htmlSlot' },
+    <#elseif po.classType=='pca'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'pcaSlot' },//TODO 未翻译
+   <#elseif po.classType=='file'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'fileSlot' },
+   <#elseif po.classType=='image'>
+    dataIndex: '${po.fieldName}',
+    customRender:render.renderAvatar,
+   <#elseif po.classType=='switch'>
+    dataIndex: '${po.fieldName}',
+<#assign switch_extend_arr=['Y','N']>
+<#if po.dictField?default("")?contains("[")>
+<#assign switch_extend_arr=po.dictField?eval>
+</#if>
+<#list switch_extend_arr as a>
+<#if a_index == 0>
+<#assign switch_extend_arr1=a>
+<#else>
+<#assign switch_extend_arr2=a>
+</#if>
+</#list>
+    customRender:({text}) => {
+       return  render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
+     },
+   <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
+    dataIndex: '${po.fieldName}_dictText'
+   <#elseif po.classType=='cat_tree'>
+    dataIndex: '${po.fieldName}',
+    <#if po.dictText?default("")?trim?length == 0>
+    customRender:({text}) => {
+       return  render.renderCategoryTree(text,'${po.dictField?default("")}')
+   },
+   <#else>
+    customRender: (text, record) => (text ? record['${po.dictText}'] : '')
+   </#if>
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.isQuery=='Y'>
+<#assign query_flag=true>
+	<#assign query_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1>
+	    <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+    <#elseif po.dictField?default("")?trim?length gt 1>
+        <#assign query_field_dictCode="${po.dictField}">
+    </#if>
+<#if po.queryMode=='single'>
+	{
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='sel_search'>
+      component: 'JSearchSelect',
+      componentProps:{
+         dict:"${po.dictTable},${po.dictText},${po.dictField}"
+      },
+<#elseif po.classType=='sel_user'>
+      component: 'JSelectUserByDept',
+<#elseif po.classType=='switch'>
+      component: 'JSwitch',
+      componentProps:{
+           <#if po.dictField != 'is_open'>
+           options:"${po.dictField}"
+           </#if>
+       },
+ <#elseif po.classType=='sel_depart'>
+      component: 'JSelectDept',
+ <#elseif po.classType=='list_multi'>
+      component: 'JMultiSelectTag',//暂无该组件
+      componentProps:{
+          dictCode:"query_field_dictCode?default("")"
+      },
+ <#elseif po.classType=='cat_tree'>
+      component: 'JCategorySelect',
+      componentProps:{
+          pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题
+      },
+<#elseif po.classType=='date'>
+      component: 'DatePicker',
+<#elseif po.classType=='datetime'>
+      component: 'DatePicker',
+      componentProps: {
+         showTime:true
+       },
+<#elseif po.classType=='pca'>
+      component: 'JAreaLinkage',
+<#elseif po.classType=='popup'>
+      component: 'JPopup',
+      componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:"${po.dictField}",
+             multi:${po.extendParams.popupMulti?c},
+         }
+     },
+<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
+<#--  ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
+      component: 'JDictSelectTag',
+      componentProps:{
+       <#if po.dictTable?default("")?trim?length gt 1>
+          dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
+       <#elseif po.dictField?default("")?trim?length gt 1>
+          dictCode:"${po.dictField}"
+        </#if>
+      },
+<#else>
+      component: 'Input',
+</#if>
+      colProps: {span: 6},
+ 	},
+<#else>
+     {
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='date'>
+      component: 'RangePicker',
+<#elseif po.classType=='datetime'>
+      component: 'RangePicker',
+      componentProps: {
+          showTime:true
+      },
+<#else>
+      component: 'Input', //TODO 范围查询
+</#if>
+      colProps: {span: 6},
+	},
+</#if>
+</#if>
+</#list>
+<#-- 结束循环 -->
+];
+
+//表单数据
+export const formSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list columns as po><#rt/>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
+
+<#list subTables as sub>
+//子表列表数据
+export const ${sub.entityName?uncap_first}Columns: BasicColumn[] = [
+ <#list sub.originalColumns as po>
+   <#if po.isShowList =='Y' && po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.sort=='Y'>
+    sorter: true,
+   </#if>
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+    <#elseif po.fieldDbType=='Blob'>
+    dataIndex: '${po.fieldName}String'
+    <#elseif po.classType=='umeditor'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'htmlSlot' },
+    <#elseif po.classType=='pca'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'pcaSlot' },//TODO 未翻译
+   <#elseif po.classType=='file'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'fileSlot' },
+   <#elseif po.classType=='image'>
+    dataIndex: '${po.fieldName}',
+    customRender:render.renderAvatar,
+   <#elseif po.classType=='switch'>
+    dataIndex: '${po.fieldName}',
+<#assign switch_extend_arr=['Y','N']>
+<#if po.dictField?default("")?contains("[")>
+<#assign switch_extend_arr=po.dictField?eval>
+</#if>
+<#list switch_extend_arr as a>
+<#if a_index == 0>
+<#assign switch_extend_arr1=a>
+<#else>
+<#assign switch_extend_arr2=a>
+</#if>
+</#list>
+    customRender:({text}) => {
+       return  render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
+     },
+   <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
+    dataIndex: '${po.fieldName}_dictText'
+   <#elseif po.classType=='cat_tree'>
+    dataIndex: '${po.fieldName}',
+    <#if po.dictText?default("")?trim?length == 0>
+    customRender:({text}) => {
+       return  render.renderCategoryTree(text,'${po.dictField?default("")}')
+   },
+   <#else>
+    customRender: (text, record) => (text ? record['${po.dictText}'] : '')
+   </#if>
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+//子表表单数据
+export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list sub.originalColumns as po><#rt/>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei
new file mode 100644
index 0000000..f44239a
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei
@@ -0,0 +1,157 @@
+<#list subTables as sub>
+#segment#${sub.entityName}List.vue
+<template>
+ <div>
+     <!--引用表格-->
+    <BasicTable @register="registerTable" :rowSelection="rowSelection" :searchInfo="searchInfo">
+      <!--插槽:table标题-->
+       <template #tableTitle>
+           <a-button type="primary" @click="handleCreate" preIcon="ant-design:plus-outlined"> 新增</a-button>
+           <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+           <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+           <a-dropdown v-if="selectedRowKeys.length > 0">
+               <template #overlay>
+                 <a-menu>
+                   <a-menu-item key="1" @click="batchHandleDelete">
+                     <Icon icon="ant-design:delete-outlined"></Icon>
+                     删除
+                   </a-menu-item>
+                 </a-menu>
+               </template>
+               <a-button>批量操作
+                 <Icon icon="mdi:chevron-down"></Icon>
+               </a-button>
+         </a-dropdown>
+       </template>
+        <!--操作栏-->
+       <template #action="{ record }">
+         <TableAction :actions="getTableAction(record)"/>
+       </template>
+       <!--字段回显插槽-->
+       <template #htmlSlot="{text}">
+          <div v-html="text"></div>
+       </template>
+       <template #fileSlot="{text}">
+          <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
+          <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
+       </template>
+     </BasicTable>
+
+      <${sub.entityName}Modal @register="registerModal" @success="handleSuccess"/>
+   </div>
+</template>
+
+<script lang="ts" setup>
+  import {ref, computed, unref,inject,watch} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {useModal} from '/@/components/Modal';
+  import ${sub.entityName}Modal from './components/${sub.entityName}Modal.vue'
+  import {${sub.entityName?uncap_first}Columns} from './${entityName}.data';
+  import {${sub.entityName?uncap_first}List, ${sub.entityName?uncap_first}Delete, ${sub.entityName?uncap_first}DeleteBatch} from './${entityName}.api';
+  import {isEmpty} from "/@/utils/is";
+  import {useMessage} from '/@/hooks/web/useMessage';
+
+    //接收主表id
+    const mainId = inject('mainId') || '';
+    //提示弹窗
+    const $message = useMessage()
+    //弹窗model
+    const [registerModal, {openModal}] = useModal();
+    const searchInfo = {};
+    // 列表页面公共参数、方法
+    const {prefixCls, tableContext} = useListPage({
+        tableProps: {
+            api: ${sub.entityName?uncap_first}List,
+            columns: ${sub.entityName?uncap_first}Columns,
+            canResize: false,
+            useSearchForm: false,
+            actionColumn: {
+                width: 180,
+            },
+            pagination:{
+                current: 1,
+                pageSize: 5,
+                pageSizeOptions: ['5', '10', '20'],
+            }
+        },
+    });
+
+    //注册table数据
+    const [registerTable, {reload}, {rowSelection, selectedRowKeys}] = tableContext;
+
+    watch(mainId, () => {
+     <#list sub.foreignKeys as key>
+         searchInfo['${key?uncap_first}'] = unref(mainId);
+     </#list>
+         reload();
+      }
+    );
+
+    /**
+     * 新增事件
+     */
+    function handleCreate() {
+        if (isEmpty(unref(mainId))) {
+            $message.createMessage.warning('请选择一个主表信息')
+            return;
+        }
+        openModal(true, {
+            isUpdate: false,
+            showFooter: true,
+        });
+    }
+
+    /**
+     * 编辑事件
+     */
+    async function handleEdit(record: Recordable) {
+        openModal(true, {
+            record,
+            isUpdate: true,
+            showFooter: true,
+        });
+    }
+
+    /**
+     * 删除事件
+     */
+    async function handleDelete(record) {
+        await ${sub.entityName?uncap_first}Delete({id: record.id}, reload);
+    }
+
+    /**
+     * 批量删除事件
+     */
+    async function batchHandleDelete() {
+        await ${sub.entityName?uncap_first}DeleteBatch({ids: selectedRowKeys.value}, () => {
+            reload()
+        })
+    }
+
+    /**
+     * 成功回调
+     */
+    function handleSuccess() {
+        reload();
+    }
+
+    /**
+     * 操作栏
+     */
+    function getTableAction(record) {
+        return [
+            {
+                label: '编辑',
+                onClick: handleEdit.bind(null, record),
+            }, {
+                label: '删除',
+                popConfirm: {
+                    title: '是否确认删除',
+                    confirm: handleDelete.bind(null, record),
+                },
+            }
+        ]
+    }
+</script>
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
new file mode 100644
index 0000000..8b6d314
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
@@ -0,0 +1,58 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit">
+      <BasicForm @register="registerForm"/>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {formSchema} from '../${entityName?uncap_first}.data';
+    import {saveOrUpdate} from '../${entityName?uncap_first}.api';
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    //表单配置
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+    });
+    //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await resetFields();
+        setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+        }
+        // 隐藏底部时禁用整个表单
+       setProps({ disabled: !data?.showFooter })
+    });
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+    //表单提交事件
+    async function handleSubmit(v) {
+        try {
+            let values = await validate();
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Modal.vuei
new file mode 100644
index 0000000..ac33a8b
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/erp/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Modal.vuei
@@ -0,0 +1,66 @@
+<#include "/common/utils.ftl">
+<#list subTables as sub>
+#segment#${sub.entityName}Modal.vue
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit">
+      <BasicForm @register="registerForm"/>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref,inject} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {${sub.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data';
+    import {${sub.entityName?uncap_first}SaveOrUpdate} from '../${entityName?uncap_first}.api';
+
+    //接收主表id
+    const mainId = inject('mainId');
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    //表单配置
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: ${sub.entityName?uncap_first}FormSchema,
+        showActionButtonGroup: false,
+    });
+    //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await resetFields();
+        setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+        }
+        // 隐藏底部时禁用整个表单
+       setProps({ disabled: !data?.showFooter })
+    });
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+    //表单提交事件
+    async function handleSubmit(v) {
+        try {
+            let values = await validate();
+            setModalProps({confirmLoading: true});
+            if (unref(mainId)) {
+             <#list sub.foreignKeys as key>
+                values['${key?uncap_first}'] = unref(mainId);
+             </#list>
+             }
+            //提交表单
+            await ${sub.entityName?uncap_first}SaveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index 76a94ec..547a8d6 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -110,7 +110,7 @@ public class ${entityName}Controller {
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
 	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
-	@PutMapping(value = "/edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) {
 		${entityName} ${entityName?uncap_first} = new ${entityName}();
 		BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first});
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
index 9014b1c..2f2800a 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/${entityName}List.vuei
@@ -266,9 +266,7 @@
           <a @click="handleEdit(record)">编辑</a>
           <a-divider type="vertical"/>
           <a-dropdown>
-            <a class="ant-dropdown-link">
-              <span>更多 <a-icon type="down"/></span>
-            </a>
+            <a class="ant-dropdown-link">更多 <a-icon type="down" /></a>
             <a-menu slot="overlay">
               <a-menu-item>
                 <a-popconfirm title="确定删除吗?" @confirm="handleDelete(record.id)">
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
index 0cf77d2..ad814c0 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
@@ -21,13 +21,8 @@
 	<#elseif po.dictField?default("")?trim?length gt 1>
 		<#assign form_field_dictCode="${po.dictField}">
 	</#if>
-	<#if po.classType =='textarea'>
-          <a-col :span="24">
-            <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}">
-	<#else>
           <a-col :xs="24" :sm="12">
             <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}">
-	</#if>
 	<#if po.classType =='date'>
               <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
 	<#elseif po.classType =='datetime'>
@@ -131,7 +126,7 @@
 </#list>
       </a-tabs>
        <#if bpm_flag>
-       <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button @click="handleOk">提 交</a-button></a-row>
+       <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button icon="check" style="width: 126px" type="primary" @click="handleOk">提 交</a-button></a-row>
        </#if>
     </a-spin>
 </template>
@@ -161,20 +156,12 @@
       return {
         labelCol: {
           xs: { span: 24 },
-          sm: { span: 6 },
+          sm: { span: 5 },
         },
         wrapperCol: {
           xs: { span: 24 },
           sm: { span: 16 },
         },
-        labelCol2: {
-          xs: { span: 24 },
-          sm: { span: 3 },
-        },
-        wrapperCol2: {
-          xs: { span: 24 },
-          sm: { span: 20 },
-        },
         model:{
         <#include "/common/init/initValue.ftl">
         },
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
index fe2cd6c..4252c92 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
@@ -15,13 +15,8 @@
 	<#elseif po.dictField?default("")?trim?length gt 1>
 		<#assign form_field_dictCode="${po.dictField}">
 	</#if>
-	<#if po.classType =='textarea'>
-        <a-col :span="24">
-          <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}">
-	<#else>
         <a-col :xs="24" :sm="12">
           <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}">
-	</#if>
 	<#if po.classType =='date'>
             <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%"/>
 	<#elseif po.classType =='datetime'>
@@ -90,20 +85,12 @@
         },
         labelCol: {
           xs: { span: 24 },
-          sm: { span: 6 },
+          sm: { span: 5 },
         },
         wrapperCol: {
           xs: { span: 24 },
           sm: { span: 16 },
         },
-        labelCol2: {
-          xs: { span: 24 },
-          sm: { span: 3 },
-        },
-        wrapperCol2: {
-          xs: { span: 24 },
-          sm: { span: 20 },
-        },
         <#include "/common/validatorRulesTemplate/sub.ftl">
         confirmLoading: false,
       }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..952afd9
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,244 @@
+<#-- ** 引入全局工具方法 ** -->
+<#--<#include "/common/utils.ftl">-->
+<#include "../../../../../../common/utils.ftl">
+<template>
+  <div>
+<#assign list_need_category=false>
+<#assign list_need_pca=false>
+<#assign bpm_flag=false>
+
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
+<#assign list_need_category=true>
+</#if>
+<#if po.classType=='pca'>
+<#assign list_need_pca=true>
+</#if>
+</#list>
+<#-- 结束循环 -->
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection" :expandedRowKeys="expandedRowKeys"  @expand="handleExpand">
+      <!-- 内嵌table区域 begin -->
+           <template #expandedRowRender="{record}">
+             <a-tabs tabPosition="top">
+   <#list subTables as sub>
+               <a-tab-pane tab="${sub.ftlDescription}" key="${sub.entityName?uncap_first}" forceRender>
+                  <${sub.entityName?uncap_first}SubTable :id="expandedRowKeys[0]"/>
+               </a-tab-pane>
+   </#list>
+             </a-tabs>
+           </template>
+     <!-- 内嵌table区域 end -->
+     <!--插槽:table标题-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+          <a-dropdown v-if="selectedRowKeys.length > 0">
+              <template #overlay>
+                <a-menu>
+                  <a-menu-item key="1" @click="batchHandleDelete">
+                    <Icon icon="ant-design:delete-outlined"></Icon>
+                    删除
+                  </a-menu-item>
+                </a-menu>
+              </template>
+              <a-button>批量操作
+                <Icon icon="mdi:chevron-down"></Icon>
+              </a-button>
+        </a-dropdown>
+      </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+      <!--字段回显插槽-->
+      <template #htmlSlot="{text}">
+         <div v-html="text"></div>
+      </template>
+      <template #fileSlot="{text}">
+         <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
+         <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
+      </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
+  </div>
+</template>
+
+<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup>
+  import {ref, computed, unref} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {useModal} from '/@/components/Modal';
+  import ${entityName}Modal from './components/${entityName}Modal.vue'
+  <#list subTables as sub>
+  import ${sub.entityName}SubTable from './subTables/${sub.entityName}SubTable.vue'
+  </#list>
+  import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
+  <#if list_need_category>
+  import { loadCategoryData } from '/@/api/common/api'
+  import { getAuthCache, setAuthCache } from '/@/utils/auth';
+  import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
+  </#if>
+   // 展开key
+  const expandedRowKeys = ref<any[]>([]);
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+   //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+      tableProps:{
+           title: '${tableVo.ftlDescription}',
+           api: list,
+           columns,
+           canResize:false,
+           formConfig: {
+                labelWidth: 120,
+                schemas: searchFormSchema,
+                autoSubmitOnEnter:true,
+                showAdvancedButton:true,
+                fieldMapToTime: [
+                <#list columns as po>
+                <#if po.isQuery=='Y'>
+                <#if po.queryMode!='single'>
+                <#if po.classType=='date'>
+                   ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'],
+                <#elseif po.classType=='datetime'>
+                   ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'],
+                </#if>
+                </#if>
+                </#if>
+                </#list>
+                ],
+            },
+            actionColumn: {
+               width: 120,
+            },
+        },
+        exportConfig: {
+            name:"${tableVo.ftlDescription}",
+            url: getExportUrl,
+        },
+        importConfig: {
+            url: getImportUrl
+        },
+    })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+   /**
+     * 展开事件
+     * */
+   function handleExpand(expanded, record){
+        expandedRowKeys.value=[];
+        if (expanded === true) {
+           expandedRowKeys.value.push(record.id)
+        }
+    }
+   /**
+    * 新增事件
+    */
+  function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+  }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+  async function handleDelete(record) {
+     await deleteOne({id: record.id}, reload);
+   }
+   /**
+    * 批量删除事件
+    */
+  async function batchHandleDelete() {
+     await batchDelete({ids: selectedRowKeys.value}, reload);
+   }
+   /**
+    * 成功回调
+    */
+  function handleSuccess() {
+      reload();
+   }
+   /**
+      * 操作栏
+      */
+  function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+   }
+     /**
+        * 下拉操作栏
+        */
+  function getDropDownAction(record){
+      return [
+           {
+             label: '详情',
+             onClick: handleDetail.bind(null, record),
+           }, {
+             label: '删除',
+             popConfirm: {
+               title: '是否确认删除',
+               confirm: handleDelete.bind(null, record),
+             }
+           }
+      ]
+   }
+    <#if list_need_category>
+   /**
+    * 初始化字典配置
+   */
+    function initDictConfig(){
+     <#list columns as po>
+     <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
+       <#if po.classType=='cat_tree' && list_need_category==true>
+       loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
+         if (res) {
+             let allDictDate = getAuthCache(DB_DICT_DATA_KEY);
+             if(!allDictDate['${po.dictField?default("")}']){
+               Object.assign(allDictDate,{'${po.dictField?default("")}':res})
+             }
+             setAuthCache(DB_DICT_DATA_KEY,allDictDate)
+         }
+       })
+       </#if>
+     </#if>
+     </#list>
+   }
+   initDictConfig();
+    </#if>
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..916c714
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,80 @@
+import {defHttp} from '/@/utils/http/axios';
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/list',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+<#list subTables as sub><#rt/>
+  ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/query${sub.entityName}ByMainId',
+</#list>
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+<#list subTables as sub><#rt/>
+/**
+ * 子表单查询接口
+ * @param params
+ */
+export const query${sub.entityName} = Api.${sub.entityName?uncap_first}List
+</#list>
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
+<#list subTables as sub><#rt/>
+/**
+ * 子表列表接口
+ * @param params
+ */
+export const ${sub.entityName?uncap_first}List = (params) =>
+  defHttp.get({url: Api.${sub.entityName?uncap_first}List, params},{isTransformResponse:false});
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..a1865f7
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,763 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types'
+//列表数据
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.isShowList =='Y' && po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.sort=='Y'>
+    sorter: true,
+   </#if>
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+    <#elseif po.fieldDbType=='Blob'>
+    dataIndex: '${po.fieldName}String'
+    <#elseif po.classType=='umeditor'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'htmlSlot' },
+    <#elseif po.classType=='pca'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'pcaSlot' },//TODO 未翻译
+   <#elseif po.classType=='file'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'fileSlot' },
+   <#elseif po.classType=='image'>
+    dataIndex: '${po.fieldName}',
+    customRender:render.renderAvatar,
+   <#elseif po.classType=='switch'>
+    dataIndex: '${po.fieldName}',
+<#assign switch_extend_arr=['Y','N']>
+<#if po.dictField?default("")?contains("[")>
+<#assign switch_extend_arr=po.dictField?eval>
+</#if>
+<#list switch_extend_arr as a>
+<#if a_index == 0>
+<#assign switch_extend_arr1=a>
+<#else>
+<#assign switch_extend_arr2=a>
+</#if>
+</#list>
+    customRender:({text}) => {
+       return  render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
+     },
+   <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
+    dataIndex: '${po.fieldName}_dictText'
+   <#elseif po.classType=='cat_tree'>
+    dataIndex: '${po.fieldName}',
+    <#if po.dictText?default("")?trim?length == 0>
+    customRender:({text}) => {
+       return  render.renderCategoryTree(text,'${po.dictField?default("")}')
+   },
+   <#else>
+    customRender: (text, record) => (text ? record['${po.dictText}'] : '')
+   </#if>
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isQuery=='Y'>
+<#assign query_flag=true>
+	<#assign query_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1>
+	    <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+    <#elseif po.dictField?default("")?trim?length gt 1>
+        <#assign query_field_dictCode="${po.dictField}">
+    </#if>
+<#if po.queryMode=='single'>
+	{
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='sel_search'>
+      component: 'JSearchSelect',
+      componentProps:{
+         dict:"${po.dictTable},${po.dictText},${po.dictField}"
+      },
+<#elseif po.classType=='sel_user'>
+      component: 'JSelectUserByDept',
+<#elseif po.classType=='switch'>
+      component: 'JSwitch',
+      componentProps:{
+           <#if po.dictField != 'is_open'>
+           options:"${po.dictField}"
+           </#if>
+       },
+ <#elseif po.classType=='sel_depart'>
+      component: 'JSelectDept',
+ <#elseif po.classType=='list_multi'>
+      component: 'JMultiSelectTag',//暂无该组件
+      componentProps:{
+          dictCode:"query_field_dictCode?default("")"
+      },
+ <#elseif po.classType=='cat_tree'>
+      component: 'JCategorySelect',
+      componentProps:{
+          pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题
+      },
+<#elseif po.classType=='date'>
+      component: 'DatePicker',
+<#elseif po.classType=='datetime'>
+      component: 'DatePicker',
+      componentProps: {
+         showTime:true
+       },
+<#elseif po.classType=='pca'>
+      component: 'JAreaLinkage',
+<#elseif po.classType=='popup'>
+      component: 'JPopup',
+      componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:"${po.dictField}",
+             multi:${po.extendParams.popupMulti?c},
+         }
+     },
+<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
+<#--  ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
+      component: 'JDictSelectTag',
+      componentProps:{
+       <#if po.dictTable?default("")?trim?length gt 1>
+          dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
+       <#elseif po.dictField?default("")?trim?length gt 1>
+          dictCode:"${po.dictField}"
+        </#if>
+      },
+<#else>
+      component: 'Input',
+</#if>
+      colProps: {span: 6},
+ 	},
+<#else>
+     {
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='date'>
+      component: 'RangePicker',
+<#elseif po.classType=='datetime'>
+      component: 'RangePicker',
+      componentProps: {
+          showTime:true
+      },
+<#else>
+      component: 'Input', //TODO 范围查询
+</#if>
+      colProps: {span: 6},
+	},
+</#if>
+</#if>
+</#list>
+<#-- 结束循环 -->
+];
+//表单数据
+export const formSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list columns as po><#rt/>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
+//子表单数据
+<#list subTables as sub>
+//子表列表数据
+export const ${sub.entityName?uncap_first}Columns: BasicColumn[] = [
+ <#list sub.originalColumns as po>
+   <#if po.isShowList =='Y' && po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.sort=='Y'>
+    sorter: true,
+   </#if>
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+    <#elseif po.fieldDbType=='Blob'>
+    dataIndex: '${po.fieldName}String'
+    <#elseif po.classType=='umeditor'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'htmlSlot' },
+    <#elseif po.classType=='pca'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'pcaSlot' },//TODO 未翻译
+   <#elseif po.classType=='file'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'fileSlot' },
+   <#elseif po.classType=='image'>
+    dataIndex: '${po.fieldName}',
+    customRender:render.renderAvatar,
+   <#elseif po.classType=='switch'>
+    dataIndex: '${po.fieldName}',
+<#assign switch_extend_arr=['Y','N']>
+<#if po.dictField?default("")?contains("[")>
+<#assign switch_extend_arr=po.dictField?eval>
+</#if>
+<#list switch_extend_arr as a>
+<#if a_index == 0>
+<#assign switch_extend_arr1=a>
+<#else>
+<#assign switch_extend_arr2=a>
+</#if>
+</#list>
+    customRender:({text}) => {
+       return  render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
+     },
+   <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
+    dataIndex: '${po.fieldName}_dictText'
+   <#elseif po.classType=='cat_tree'>
+    dataIndex: '${po.fieldName}',
+    <#if po.dictText?default("")?trim?length == 0>
+    customRender:({text}) => {
+       return  render.renderCategoryTree(text,'${po.dictField?default("")}')
+   },
+   <#else>
+    customRender: (text, record) => (text ? record['${po.dictText}'] : '')
+   </#if>
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+<#if sub.foreignRelationType =='1'>
+export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list sub.colums as po><#rt/>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
+</#if>
+</#list>
+//子表表格配置
+<#list subTables as sub>
+<#if sub.foreignRelationType =='0'>
+export const ${sub.entityName?uncap_first}JVxeColumns: JVxeColumn[] = [
+<#assign popupBackFields = "">
+
+<#-- 循环子表的列 开始 -->
+<#list sub.colums as col><#rt/>
+<#if col.isShow =='Y'>
+<#if col.filedComment !='外键' >
+    {
+      title: '${col.filedComment}',
+      key: '${autoStringSuffixForModel(col)}',
+<#if col.classType =='date'>
+      type: JVxeTypes.date,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='datetime'>
+      type: JVxeTypes.datetime,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='textarea'>
+      type: JVxeTypes.textarea,
+       <#if col.readonly=='Y'>
+      disabled:true,
+       </#if>
+<#elseif "int,decimal,double,"?contains(col.classType)>
+      type: JVxeTypes.inputNumber,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='list' || col.classType =='radio'>
+      type: JVxeTypes.select,
+      options:[],
+      <#if col.dictTable?default("")?trim?length gt 1>
+      dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
+      <#else>
+      dictCode:"${col.dictField}",
+      </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='list_multi' || col.classType =='checkbox'>
+      type: JVxeTypes.selectMultiple,
+      options:[],
+      <#if col.dictTable?default("")?trim?length gt 1>
+      dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
+      <#else>
+      dictCode:"${col.dictField}",
+      </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='sel_search'>
+      type: JVxeTypes.selectSearch,
+      <#if col.dictTable?default("")?trim?length gt 1>
+      dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
+      <#else>
+      dictCode:"${col.dictField}",
+      </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='image'>
+      type: JVxeTypes.image,
+      token:true,
+      responseName:"message",
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+      <#if col.uploadnum??>
+      number: ${col.uploadnum},
+      </#if>
+<#elseif col.classType =='file'>
+      type: JVxeTypes.file,
+      token:true,
+      responseName:"message",
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+      <#if col.uploadnum??>
+      number: ${col.uploadnum},
+      </#if>
+<#elseif col.classType =='switch'>
+      type: JVxeTypes.checkbox,
+       <#if col.dictField == 'is_open'>
+        customValue: ['Y', 'N'],
+        <#else>
+        customValue: ${col.dictField},
+        </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='popup'>
+<#if popupBackFields?length gt 0>
+    <#assign popupBackFields = "${popupBackFields}"+","+"${col.dictText}">
+<#else>
+    <#assign popupBackFields = "${col.dictText}">
+</#if>
+      type: JVxeTypes.popup,
+      popupCode:"${col.dictTable}",
+      field:"${col.dictField}",
+      orgFields:"${col.dictField}",
+      destFields:"${Format.underlineToHump(col.dictText)}",
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#else>
+       type: JVxeTypes.input,
+       <#if col.readonly=='Y'>
+       disabled:true,
+       </#if>
+</#if>
+<#if col.classType =='list_multi' || col.classType =='checkbox'>
+      width:"250px",
+<#else>
+      width:"200px",
+</#if>
+<#if col.classType =='file'>
+      placeholder: '请选择文件',
+<#else>
+      placeholder: '请输入${'$'}{title}',
+</#if>
+<#if col.defaultVal??>
+<#if col.fieldDbType=="BigDecimal" || col.fieldDbType=="double" || col.fieldDbType=="int">
+      defaultValue:${col.defaultVal},
+      <#else>
+      defaultValue:"${col.defaultVal}",
+</#if>
+<#else>
+      defaultValue:'',
+</#if>
+<#-- 子表的校验 -->
+<#assign subFieldValidType = col.fieldValidType!''>
+<#-- 非空校验 -->
+<#if col.nullable == 'N' || subFieldValidType == '*'>
+      validateRules: [{ required: true, message: '${'$'}{title}不能为空' }],
+<#-- 其他情况下,只要有值就被认为是正则校验 -->
+<#elseif subFieldValidType?length gt 0>
+<#assign subMessage = '格式不正确'>
+<#if subFieldValidType == 'only' >
+  <#assign subMessage = '不能重复'>
+</#if>
+      validateRules: [{ pattern: "${subFieldValidType}", message: "${'$'}{title}${subMessage}" }],
+</#if>
+    },
+</#if>
+</#if>
+</#list>
+<#-- 循环子表的列 结束 -->
+  ]
+</#if>
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
new file mode 100644
index 0000000..5b3918c
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
@@ -0,0 +1,179 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit">
+      <BasicForm @register="registerForm" ref="formRef"/>
+  <!-- 子表单区域 -->
+    <a-tabs v-model:activeKey="activeKey" @change="handleChangeTabs">
+<#list subTables as sub><#rt/>
+  <#if sub.foreignRelationType =='1'>
+      <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true">
+        <${sub.entityName}Form ref="${sub.entityName?uncap_first}Form"></${sub.entityName}Form>
+      </a-tab-pane>
+
+  <#else>
+      <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true">
+        <JVxeTable
+          keep-source
+          resizable
+          :ref="refKeys[${sub_index}]"
+          :loading="${sub.entityName?uncap_first}Table.loading"
+          :columns="${sub.entityName?uncap_first}Table.columns"
+          :dataSource="${sub.entityName?uncap_first}Table.dataSource"
+          :maxHeight="300"
+          :rowNumber="true"
+          :rowSelection="true"
+          :toolbar="true"
+          />
+      </a-tab-pane>
+  </#if>
+</#list>
+    </a-tabs>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref,reactive} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import { JVxeTable } from '/@/components/jeecg/JVxeTable'
+    import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts'
+    <#list subTables as sub>
+      <#if sub.foreignRelationType =='1'>
+    import ${sub.entityName}Form from './${sub.entityName}Form.vue'
+      </#if>
+    </#list>
+    import {formSchema<#list subTables as sub><#if sub.foreignRelationType =='0'>,${sub.entityName?uncap_first}JVxeColumns</#if></#list>} from '../${entityName?uncap_first}.data';
+    import {saveOrUpdate<#list subTables as sub>,query${sub.entityName}</#list>} from '../${entityName?uncap_first}.api';
+    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    const refKeys = ref([<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]);
+    <#assign hasOne2Many = false>
+    <#assign hasOne2One = false>
+    const activeKey = ref('${subTables[0].entityName?uncap_first}');
+<#list subTables as sub>
+<#if sub.foreignRelationType =='0'>
+ <#assign hasOne2Many = true>
+    const ${sub.entityName?uncap_first} = ref();
+</#if>
+<#if sub.foreignRelationType =='1'>
+ <#assign hasOne2One = true>
+    const ${sub.entityName?uncap_first}Form = ref();
+</#if>
+</#list>
+    const tableRefs = {<#list subTables as sub><#if sub.foreignRelationType =='0'>${sub.entityName?uncap_first}, <#assign hasOne2Many = true></#if></#list>};
+   <#list subTables as sub>
+   <#if sub.foreignRelationType =='0'>
+    const ${sub.entityName?uncap_first}Table = reactive({
+          loading: false,
+          dataSource: [],
+          columns:${sub.entityName?uncap_first}JVxeColumns
+    })
+    </#if>
+   </#list>
+    //表单配置
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+    });
+     //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await reset();
+        setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+            <#list subTables as sub><#rt/>
+            <#if sub.foreignRelationType =='1'>
+             ${sub.entityName?uncap_first}Form.value.initFormData(query${sub.entityName},data?.record?.id)
+            </#if>
+            </#list>
+            <#list subTables as sub><#rt/>
+            <#if sub.foreignRelationType =='0'>
+             requestSubTableData(query${sub.entityName}, {id:data?.record?.id}, ${sub.entityName?uncap_first}Table)
+            </#if>
+            </#list>
+        }
+        // 隐藏底部时禁用整个表单
+       setProps({ disabled: !data?.showFooter })
+    });
+    //方法配置
+    const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys<#if hasOne2One==true>,validateSubForm</#if>);
+
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+
+    async function reset(){
+      await resetFields();
+      activeKey.value = ref('${subTables[0].entityName?uncap_first}');
+      <#list subTables as sub>
+        <#if sub.foreignRelationType =='0'>
+      ${sub.entityName?uncap_first}Table.dataSource = [];
+        </#if>
+        <#if sub.foreignRelationType =='1'>
+      ${sub.entityName?uncap_first}Form.value.resetFields();
+        </#if>
+      </#list>
+    }
+    function classifyIntoFormData(allValues) {
+         let main = Object.assign({}, allValues.formValue)
+         return {
+           ...main, // 展开
+ <#assign subManyIndex = 0>
+ <#list subTables as sub><#rt/>
+ <#if sub.foreignRelationType =='0'>
+           ${sub.entityName?uncap_first}List: allValues.tablesValue[${subManyIndex}].tableData,
+           <#assign subManyIndex = subManyIndex+1>
+ <#else>
+           ${sub.entityName?uncap_first}List: ${sub.entityName?uncap_first}Form.value.getFormData(),
+ </#if>
+ </#list>
+         }
+       }
+      <#if hasOne2One==true>
+     //校验所有一对一子表表单
+     function validateSubForm(allValues){
+         return new Promise((resolve,reject)=>{
+             Promise.all([
+             <#list subTables as sub><#rt/>
+            <#if sub.foreignRelationType =='1'>
+                  ${sub.entityName?uncap_first}Form.value.validateForm(${sub_index}),
+            </#if>
+          </#list>
+             ]).then(() => {
+                 resolve(allValues)
+             }).catch(e => {
+                 if (e.error === VALIDATE_FAILED) {
+                     // 如果有未通过表单验证的子表,就自动跳转到它所在的tab
+                     activeKey.value = e.index == null ? unref(activeKey) : refKeys.value[e.index]
+                 } else {
+                     console.error(e)
+                 }
+             })
+         })
+     }
+    </#if>
+    //表单提交事件
+    async function requestAddOrEdit(values) {
+        try {
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
new file mode 100644
index 0000000..5a14f8d
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
@@ -0,0 +1,64 @@
+<#list subTables as sub>
+<#if sub.foreignRelationType=='1'>
+#segment#${sub.entityName}Form.vue
+<template>
+    <BasicForm @register="registerForm"/>
+</template>
+<script lang="ts">
+    import {defineComponent} from 'vue';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {${sub.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data';
+    import {defHttp} from '/@/utils/http/axios';
+    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+
+    export default defineComponent({
+        name:"${sub.entityName}Form",
+        components: {BasicForm},
+        emits:['register'],
+        setup(_,{emit}) {
+            const [registerForm, {resetFields, setFieldsValue,getFieldsValue,validate}] = useForm({
+                labelWidth: 150,
+                schemas: ${sub.entityName?uncap_first}FormSchema,
+                showActionButtonGroup: false,
+            });
+            /**
+            *初始化加载数据
+            */
+            function initFormData(url,id){
+                if(id){
+                     defHttp.get({url,params:{id}},{isTransformResponse:false}).then(res=>{
+                       res.success && setFieldsValue({...res.result.records[0]});
+                    })
+                }
+            }
+           /**
+            *获取表单数据
+            */
+            function getFormData(){
+               return [getFieldsValue()];
+            }
+            /**
+            *表单校验
+            */
+            function validateForm(index){
+                return new Promise((resolve, reject) => {
+                    // 验证子表表单
+                    validate().then(()=>{
+                        return resolve()
+                    }).catch(()=> {
+                        return reject({ error: VALIDATE_FAILED ,index})
+                    })
+                })
+            }
+            return {
+                registerForm,
+                resetFields,
+                initFormData,
+                getFormData,
+                validateForm
+            }
+        }
+    })
+</script>
+</#if>
+</#list>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/subTables/[1-n]SubTable.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/subTables/[1-n]SubTable.vuei
new file mode 100644
index 0000000..59c845f
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/inner-table/onetomany/java/${bussiPackage}/${entityPackage}/vue3/subTables/[1-n]SubTable.vuei
@@ -0,0 +1,69 @@
+<#--noinspection JSDuplicatedDeclaration-->
+<#list subTables as sub>
+#segment#${sub.entityName}SubTable.vue
+<template>
+  <div>
+  <#assign list_need_category=false>
+  <#assign list_need_pca=false>
+  <#assign bpm_flag=false>
+
+  <#-- 开始循环 -->
+  <#list columns as po>
+  <#if po.fieldDbName=='bpm_status'>
+    <#assign bpm_flag=true>
+  </#if>
+  <#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
+  <#assign list_need_category=true>
+  </#if>
+  <#if po.classType=='pca'>
+  <#assign list_need_pca=true>
+  </#if>
+  </#list>
+  <#-- 结束循环 -->
+      <!--引用表格-->
+     <BasicTable bordered size="middle" :loading="loading" rowKey="id" :canResize="false" :columns="${sub.entityName?uncap_first}Columns" :dataSource="dataSource" :pagination="false">
+        <!--字段回显插槽-->
+        <template #htmlSlot="{text}">
+           <div v-html="text"></div>
+        </template>
+        <template #fileSlot="{text}">
+           <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
+           <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
+        </template>
+      </BasicTable>
+    </div>
+</template>
+
+<script lang="ts" setup>
+  import {ref,watchEffect} from 'vue';
+  import {BasicTable} from '/@/components/Table';
+  import {${sub.entityName?uncap_first}Columns} from '../${entityName}.data';
+  import {${sub.entityName?uncap_first}List} from '../${entityName}.api';
+
+  const props = defineProps({
+    id: {
+       type: String,
+       default: '',
+     },
+  })
+
+  const loading = ref(false);
+  const dataSource = ref([]);
+
+  watchEffect(() => {
+      props.id && loadData(props.id);
+   });
+
+   function loadData(id) {
+         dataSource.value = []
+         loading.value = true
+          ${sub.entityName?uncap_first}List({id}).then((res) => {
+           if (res.success) {
+              dataSource.value = res.result.records
+           }
+         }).finally(() => {
+           loading.value = false
+         })
+    }
+</script>
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
index 98e0aa8..f387f76 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
@@ -28,13 +28,8 @@
 	<#elseif po.dictField?default("")?trim?length gt 1>
 		<#assign form_field_dictCode="${po.dictField}">
 	</#if>
-	<#if po.classType =='textarea'>
-          <a-col :span="24">
-            <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}">
-	<#else>
           <a-col :span="${form_span}" >
             <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}">
-	</#if>
 	<#if po.classType =='date'>
               <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
 	<#elseif po.classType =='datetime'>
@@ -140,7 +135,7 @@
 </#list>
     </a-tabs>
     <#if bpm_flag>
-    <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button @click="handleOk">提 交</a-button></a-row>
+    <a-row v-if="showFlowSubmitButton" style="text-align: center;width: 100%;margin-top: 16px;"><a-button icon="check" style="width: 126px" type="primary" @click="handleOk">提 交</a-button></a-row>
     </#if>
   </a-spin>
 </template>
@@ -174,20 +169,12 @@
       return {
         labelCol: {
           xs: { span: 24 },
-          sm: { span: 6 },
+          sm: { span: 5 },
         },
         wrapperCol: {
           xs: { span: 24 },
           sm: { span: 16 },
         },
-        labelCol2: {
-          xs: { span: 24 },
-          sm: { span: 3 },
-        },
-        wrapperCol2: {
-          xs: { span: 24 },
-          sm: { span: 20 },
-        },
         model:{
            <#include "/common/init/initValue.ftl">
          },
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
index 2fabc76..96cfc11 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
@@ -25,13 +25,8 @@
 	<#elseif po.dictField?default("")?trim?length gt 1>
 		<#assign form_field_dictCode="${po.dictField}">
 	</#if>
-	<#if po.classType =='textarea'>
-          <a-col :span="24">
-            <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}">
-	<#else>
           <a-col :span="${form_span}">
             <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}">
-	</#if>
 	<#if po.classType =='date'>
               <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}"  style="width: 100%"/>
 	<#elseif po.classType =='datetime'>
@@ -117,20 +112,12 @@
         },
         labelCol: {
           xs: { span: 24 },
-          sm: { span: 6 },
+          sm: { span: 5 },
         },
         wrapperCol: {
           xs: { span: 24 },
           sm: { span: 16 },
         },
-        labelCol2: {
-          xs: { span: 24 },
-          sm: { span: 3 },
-        },
-        wrapperCol2: {
-          xs: { span: 24 },
-          sm: { span: 20 },
-        },
         <#include "/common/validatorRulesTemplate/sub.ftl">
         confirmLoading: false,
       }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..d87e3b4
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,218 @@
+<template>
+  <div>
+<#assign list_need_category=false>
+<#assign list_need_pca=false>
+<#assign bpm_flag=false>
+
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
+<#assign list_need_category=true>
+</#if>
+<#if po.classType=='pca'>
+<#assign list_need_pca=true>
+</#if>
+</#list>
+<#-- 结束循环 -->
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--插槽:table标题-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+          <a-dropdown v-if="checkedKeys.length > 0">
+              <template #overlay>
+                <a-menu>
+                  <a-menu-item key="1" @click="batchHandleDelete">
+                    <Icon icon="ant-design:delete-outlined"></Icon>
+                    删除
+                  </a-menu-item>
+                </a-menu>
+              </template>
+              <a-button>批量操作
+                <Icon icon="mdi:chevron-down"></Icon>
+              </a-button>
+        </a-dropdown>
+      </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+      <!--字段回显插槽-->
+      <template #htmlSlot="{text}">
+         <div v-html="text"></div>
+      </template>
+      <template #fileSlot="{text}">
+         <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
+         <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
+      </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
+  </div>
+</template>
+
+<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup>
+  import {ref, computed, unref} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {useModal} from '/@/components/Modal';
+  import ${entityName}Modal from './components/${entityName}Modal.vue'
+  import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
+  <#if list_need_category>
+  import { loadCategoryData } from '/@/api/common/api'
+  import { getAuthCache, setAuthCache } from '/@/utils/auth';
+  import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
+  </#if>
+  const checkedKeys = ref<Array<string | number>>([]);
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+   //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+      tableProps:{
+           title: '${tableVo.ftlDescription}',
+           api: list,
+           columns,
+           canResize:false,
+           formConfig: {
+                labelWidth: 120,
+                schemas: searchFormSchema,
+                autoSubmitOnEnter:true,
+                showAdvancedButton:true,
+                fieldMapToTime: [
+                <#list columns as po>
+                <#if po.isQuery=='Y'>
+                <#if po.queryMode!='single'>
+                <#if po.classType=='date'>
+                   ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'],
+                <#elseif po.classType=='datetime'>
+                   ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'],
+                </#if>
+                </#if>
+                </#if>
+                </#list>
+                ],
+            },
+            actionColumn: {
+               width: 120,
+            },
+        },
+        exportConfig: {
+            name:"${tableVo.ftlDescription}",
+            url: getExportUrl,
+        },
+        importConfig: {
+            url: getImportUrl
+        },
+    })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+   /**
+    * 新增事件
+    */
+  function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+  }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+  async function handleDelete(record) {
+     await deleteOne({id: record.id}, reload);
+   }
+   /**
+    * 批量删除事件
+    */
+  async function batchHandleDelete() {
+     await batchDelete({ids: checkedKeys.value}, reload);
+   }
+   /**
+    * 成功回调
+    */
+  function handleSuccess() {
+      reload();
+   }
+   /**
+      * 操作栏
+      */
+  function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+   }
+     /**
+        * 下拉操作栏
+        */
+  function getDropDownAction(record){
+      return [
+           {
+             label: '详情',
+             onClick: handleDetail.bind(null, record),
+           }, {
+             label: '删除',
+             popConfirm: {
+               title: '是否确认删除',
+               confirm: handleDelete.bind(null, record),
+             }
+           }
+      ]
+   }
+    <#if list_need_category>
+   /**
+    * 初始化字典配置
+   */
+    function initDictConfig(){
+     <#list columns as po>
+     <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
+       <#if po.classType=='cat_tree' && list_need_category==true>
+       loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
+         if (res) {
+             let allDictDate = getAuthCache(DB_DICT_DATA_KEY);
+             if(!allDictDate['${po.dictField?default("")}']){
+               Object.assign(allDictDate,{'${po.dictField?default("")}':res})
+             }
+             setAuthCache(DB_DICT_DATA_KEY,allDictDate)
+         }
+       })
+       </#if>
+     </#if>
+     </#list>
+   }
+   initDictConfig();
+    </#if>
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..3b9ce59
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,72 @@
+import {defHttp} from '/@/utils/http/axios';
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/list',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+<#list subTables as sub><#rt/>
+  ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/query${sub.entityName}ByMainId',
+</#list>
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+<#list subTables as sub><#rt/>
+/**
+ * 查询子表数据
+ * @param params
+ */
+export const ${sub.entityName?uncap_first}List = Api.${sub.entityName?uncap_first}List;
+</#list>
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..b07e0d7
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,700 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types'
+//列表数据
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.isShowList =='Y' && po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.sort=='Y'>
+    sorter: true,
+   </#if>
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+    <#elseif po.fieldDbType=='Blob'>
+    dataIndex: '${po.fieldName}String'
+    <#elseif po.classType=='umeditor'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'htmlSlot' },
+    <#elseif po.classType=='pca'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'pcaSlot' },//TODO 未翻译
+   <#elseif po.classType=='file'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'fileSlot' },
+   <#elseif po.classType=='image'>
+    dataIndex: '${po.fieldName}',
+    customRender:render.renderAvatar,
+   <#elseif po.classType=='switch'>
+    dataIndex: '${po.fieldName}',
+<#assign switch_extend_arr=['Y','N']>
+<#if po.dictField?default("")?contains("[")>
+<#assign switch_extend_arr=po.dictField?eval>
+</#if>
+<#list switch_extend_arr as a>
+<#if a_index == 0>
+<#assign switch_extend_arr1=a>
+<#else>
+<#assign switch_extend_arr2=a>
+</#if>
+</#list>
+    customRender:({text}) => {
+       return  render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
+     },
+   <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
+    dataIndex: '${po.fieldName}_dictText'
+   <#elseif po.classType=='cat_tree'>
+    dataIndex: '${po.fieldName}',
+    <#if po.dictText?default("")?trim?length == 0>
+    customRender:({text}) => {
+       return  render.renderCategoryTree(text,'${po.dictField?default("")}')
+   },
+   <#else>
+    customRender: (text, record) => (text ? record['${po.dictText}'] : '')
+   </#if>
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isQuery=='Y'>
+<#assign query_flag=true>
+	<#assign query_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1>
+	    <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+    <#elseif po.dictField?default("")?trim?length gt 1>
+        <#assign query_field_dictCode="${po.dictField}">
+    </#if>
+<#if po.queryMode=='single'>
+	{
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='sel_search'>
+      component: 'JSearchSelect',
+      componentProps:{
+         dict:"${po.dictTable},${po.dictText},${po.dictField}"
+      },
+<#elseif po.classType=='sel_user'>
+      component: 'JSelectUserByDept',
+<#elseif po.classType=='switch'>
+      component: 'JSwitch',
+      componentProps:{
+           <#if po.dictField != 'is_open'>
+           options:"${po.dictField}"
+           </#if>
+       },
+ <#elseif po.classType=='sel_depart'>
+      component: 'JSelectDept',
+ <#elseif po.classType=='list_multi'>
+      component: 'JMultiSelectTag',//暂无该组件
+      componentProps:{
+          dictCode:"query_field_dictCode?default("")"
+      },
+ <#elseif po.classType=='cat_tree'>
+      component: 'JCategorySelect',
+      componentProps:{
+          pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题
+      },
+<#elseif po.classType=='date'>
+      component: 'DatePicker',
+<#elseif po.classType=='datetime'>
+      component: 'DatePicker',
+      componentProps: {
+         showTime:true
+       },
+<#elseif po.classType=='pca'>
+      component: 'JAreaLinkage',
+<#elseif po.classType=='popup'>
+      component: 'JPopup',
+      componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:"${po.dictField}",
+             multi:${po.extendParams.popupMulti?c},
+         }
+     },
+<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
+<#--  ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
+      component: 'JDictSelectTag',
+      componentProps:{
+       <#if po.dictTable?default("")?trim?length gt 1>
+          dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
+       <#elseif po.dictField?default("")?trim?length gt 1>
+          dictCode:"${po.dictField}"
+        </#if>
+      },
+<#else>
+      component: 'Input',
+</#if>
+      colProps: {span: 6},
+ 	},
+<#else>
+     {
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='date'>
+      component: 'RangePicker',
+<#elseif po.classType=='datetime'>
+      component: 'RangePicker',
+      componentProps: {
+          showTime:true
+      },
+<#else>
+      component: 'Input', //TODO 范围查询
+</#if>
+      colProps: {span: 6},
+	},
+</#if>
+</#if>
+</#list>
+<#-- 结束循环 -->
+];
+//表单数据
+export const formSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list columns as po><#rt/>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
+//子表单数据
+<#list subTables as sub>
+<#if sub.foreignRelationType =='1'>
+export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list sub.colums as po><#rt/>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
+</#if>
+</#list>
+//子表表格配置
+<#list subTables as sub>
+<#if sub.foreignRelationType =='0'>
+export const ${sub.entityName?uncap_first}Columns: JVxeColumn[] = [
+<#assign popupBackFields = "">
+
+<#-- 循环子表的列 开始 -->
+<#list sub.colums as col><#rt/>
+<#if col.isShow =='Y'>
+<#if col.filedComment !='外键' >
+    {
+      title: '${col.filedComment}',
+      key: '${autoStringSuffixForModel(col)}',
+<#if col.classType =='date'>
+      type: JVxeTypes.date,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='datetime'>
+      type: JVxeTypes.datetime,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='textarea'>
+      type: JVxeTypes.textarea,
+       <#if col.readonly=='Y'>
+      disabled:true,
+       </#if>
+<#elseif "int,decimal,double,"?contains(col.classType)>
+      type: JVxeTypes.inputNumber,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='list' || col.classType =='radio'>
+      type: JVxeTypes.select,
+      options:[],
+      <#if col.dictTable?default("")?trim?length gt 1>
+      dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
+      <#else>
+      dictCode:"${col.dictField}",
+      </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='list_multi' || col.classType =='checkbox'>
+      type: JVxeTypes.selectMultiple,
+      options:[],
+      <#if col.dictTable?default("")?trim?length gt 1>
+      dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
+      <#else>
+      dictCode:"${col.dictField}",
+      </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='sel_search'>
+      type: JVxeTypes.selectSearch,
+      <#if col.dictTable?default("")?trim?length gt 1>
+      dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
+      <#else>
+      dictCode:"${col.dictField}",
+      </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='image'>
+      type: JVxeTypes.image,
+      token:true,
+      responseName:"message",
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+      <#if col.uploadnum??>
+      number: ${col.uploadnum},
+      </#if>
+<#elseif col.classType =='file'>
+      type: JVxeTypes.file,
+      token:true,
+      responseName:"message",
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+      <#if col.uploadnum??>
+      number: ${col.uploadnum},
+      </#if>
+<#elseif col.classType =='switch'>
+      type: JVxeTypes.checkbox,
+       <#if col.dictField == 'is_open'>
+        customValue: ['Y', 'N'],
+        <#else>
+        customValue: ${col.dictField},
+        </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='popup'>
+<#if popupBackFields?length gt 0>
+    <#assign popupBackFields = "${popupBackFields}"+","+"${col.dictText}">
+<#else>
+    <#assign popupBackFields = "${col.dictText}">
+</#if>
+      type: JVxeTypes.popup,
+      popupCode:"${col.dictTable}",
+      field:"${col.dictField}",
+      orgFields:"${col.dictField}",
+      destFields:"${Format.underlineToHump(col.dictText)}",
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#else>
+       type: JVxeTypes.input,
+       <#if col.readonly=='Y'>
+       disabled:true,
+       </#if>
+</#if>
+<#if col.classType =='list_multi' || col.classType =='checkbox'>
+      width:"250px",
+<#else>
+      width:"200px",
+</#if>
+<#if col.classType =='file'>
+      placeholder: '请选择文件',
+<#else>
+      placeholder: '请输入${'$'}{title}',
+</#if>
+<#if col.defaultVal??>
+<#if col.fieldDbType=="BigDecimal" || col.fieldDbType=="double" || col.fieldDbType=="int">
+      defaultValue:${col.defaultVal},
+      <#else>
+      defaultValue:"${col.defaultVal}",
+</#if>
+<#else>
+      defaultValue:'',
+</#if>
+<#-- 子表的校验 -->
+<#assign subFieldValidType = col.fieldValidType!''>
+<#-- 非空校验 -->
+<#if col.nullable == 'N' || subFieldValidType == '*'>
+      validateRules: [{ required: true, message: '${'$'}{title}不能为空' }],
+<#-- 其他情况下,只要有值就被认为是正则校验 -->
+<#elseif subFieldValidType?length gt 0>
+<#assign subMessage = '格式不正确'>
+<#if subFieldValidType == 'only' >
+  <#assign subMessage = '不能重复'>
+</#if>
+      validateRules: [{ pattern: "${subFieldValidType}", message: "${'$'}{title}${subMessage}" }],
+</#if>
+    },
+</#if>
+</#if>
+</#list>
+<#-- 循环子表的列 结束 -->
+  ]
+</#if>
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
new file mode 100644
index 0000000..590d2eb
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
@@ -0,0 +1,179 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit">
+      <BasicForm @register="registerForm" ref="formRef"/>
+  <!-- 子表单区域 -->
+    <a-tabs v-model:activeKey="activeKey" @change="handleChangeTabs">
+<#list subTables as sub><#rt/>
+  <#if sub.foreignRelationType =='1'>
+      <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true">
+        <${sub.entityName}Form ref="${sub.entityName?uncap_first}Form"></${sub.entityName}Form>
+      </a-tab-pane>
+
+  <#else>
+      <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true">
+        <JVxeTable
+          keep-source
+          resizable
+          :ref="refKeys[${sub_index}]"
+          :loading="${sub.entityName?uncap_first}Table.loading"
+          :columns="${sub.entityName?uncap_first}Table.columns"
+          :dataSource="${sub.entityName?uncap_first}Table.dataSource"
+          :maxHeight="300"
+          :rowNumber="true"
+          :rowSelection="true"
+          :toolbar="true"
+          />
+      </a-tab-pane>
+  </#if>
+</#list>
+    </a-tabs>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref,reactive} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import { JVxeTable } from '/@/components/jeecg/JVxeTable'
+    import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts'
+    <#list subTables as sub>
+      <#if sub.foreignRelationType =='1'>
+    import ${sub.entityName}Form from './${sub.entityName}Form.vue'
+      </#if>
+    </#list>
+    import {formSchema<#list subTables as sub><#if sub.foreignRelationType =='0'>,${sub.entityName?uncap_first}Columns</#if></#list>} from '../${entityName?uncap_first}.data';
+    import {saveOrUpdate<#list subTables as sub>,${sub.entityName?uncap_first}List</#list>} from '../${entityName?uncap_first}.api';
+    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    const refKeys = ref([<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]);
+    <#assign hasOne2Many = false>
+    <#assign hasOne2One = false>
+    const activeKey = ref('${subTables[0].entityName?uncap_first}');
+<#list subTables as sub>
+<#if sub.foreignRelationType =='0'>
+ <#assign hasOne2Many = true>
+    const ${sub.entityName?uncap_first} = ref();
+</#if>
+<#if sub.foreignRelationType =='1'>
+ <#assign hasOne2One = true>
+    const ${sub.entityName?uncap_first}Form = ref();
+</#if>
+</#list>
+    const tableRefs = {<#list subTables as sub><#if sub.foreignRelationType =='0'>${sub.entityName?uncap_first}, <#assign hasOne2Many = true></#if></#list>};
+   <#list subTables as sub>
+   <#if sub.foreignRelationType =='0'>
+    const ${sub.entityName?uncap_first}Table = reactive({
+          loading: false,
+          dataSource: [],
+          columns:${sub.entityName?uncap_first}Columns
+    })
+    </#if>
+   </#list>
+    //表单配置
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+    });
+     //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await reset();
+        setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+            <#list subTables as sub><#rt/>
+            <#if sub.foreignRelationType =='1'>
+             ${sub.entityName?uncap_first}Form.value.initFormData(${sub.entityName?uncap_first}List,data?.record?.id)
+            </#if>
+            </#list>
+            <#list subTables as sub><#rt/>
+            <#if sub.foreignRelationType =='0'>
+             requestSubTableData(${sub.entityName?uncap_first}List, {id:data?.record?.id}, ${sub.entityName?uncap_first}Table)
+            </#if>
+            </#list>
+        }
+        // 隐藏底部时禁用整个表单
+       setProps({ disabled: !data?.showFooter })
+    });
+    //方法配置
+    const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys<#if hasOne2One==true>,validateSubForm</#if>);
+
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+
+    async function reset(){
+      await resetFields();
+      activeKey.value = ref('${subTables[0].entityName?uncap_first}');
+      <#list subTables as sub>
+        <#if sub.foreignRelationType =='0'>
+      ${sub.entityName?uncap_first}Table.dataSource = [];
+        </#if>
+        <#if sub.foreignRelationType =='1'>
+      ${sub.entityName?uncap_first}Form.value.resetFields();
+        </#if>
+      </#list>
+    }
+    function classifyIntoFormData(allValues) {
+         let main = Object.assign({}, allValues.formValue)
+         return {
+           ...main, // 展开
+ <#assign subManyIndex = 0>
+ <#list subTables as sub><#rt/>
+ <#if sub.foreignRelationType =='0'>
+           ${sub.entityName?uncap_first}List: allValues.tablesValue[${subManyIndex}].tableData,
+           <#assign subManyIndex = subManyIndex+1>
+ <#else>
+           ${sub.entityName?uncap_first}List: ${sub.entityName?uncap_first}Form.value.getFormData(),
+ </#if>
+ </#list>
+         }
+       }
+      <#if hasOne2One==true>
+     //校验所有一对一子表表单
+     function validateSubForm(allValues){
+         return new Promise((resolve,reject)=>{
+             Promise.all([
+             <#list subTables as sub><#rt/>
+            <#if sub.foreignRelationType =='1'>
+                  ${sub.entityName?uncap_first}Form.value.validateForm(${sub_index}),
+            </#if>
+          </#list>
+             ]).then(() => {
+                 resolve(allValues)
+             }).catch(e => {
+                 if (e.error === VALIDATE_FAILED) {
+                     // 如果有未通过表单验证的子表,就自动跳转到它所在的tab
+                     activeKey.value = e.index == null ? unref(activeKey) : refKeys.value[e.index]
+                 } else {
+                     console.error(e)
+                 }
+             })
+         })
+     }
+    </#if>
+    //表单提交事件
+    async function requestAddOrEdit(values) {
+        try {
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
new file mode 100644
index 0000000..afa4e7b
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/jvxe/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
@@ -0,0 +1,64 @@
+<#list subTables as sub>
+<#if sub.foreignRelationType=='1'>
+#segment#${sub.entityName}Form.vue
+<template>
+    <BasicForm @register="registerForm"/>
+</template>
+<script lang="ts">
+    import {defineComponent} from 'vue';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {${sub.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data';
+    import {defHttp} from '/@/utils/http/axios';
+    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+
+    export default defineComponent({
+        name:"${sub.entityName}Form",
+        components: {BasicForm},
+        emits:['register'],
+        setup(_,{emit}) {
+            const [registerForm, {resetFields, setFieldsValue,getFieldsValue,validate}] = useForm({
+                labelWidth: 150,
+                schemas: ${sub.entityName?uncap_first}FormSchema,
+                showActionButtonGroup: false,
+            });
+            /**
+            *初始化加载数据
+            */
+            function initFormData(url,id){
+                if(id){
+                     defHttp.get({url,params:{id}},{isTransformResponse:false}).then(res=>{
+                       res.success && setFieldsValue({...res.result[0]});
+                    })
+                }
+            }
+           /**
+            *获取表单数据
+            */
+            function getFormData(){
+               return [getFieldsValue()];
+            }
+            /**
+            *表单校验
+            */
+            function validateForm(index){
+                return new Promise((resolve, reject) => {
+                    // 验证子表表单
+                    validate().then(()=>{
+                        return resolve()
+                    }).catch(()=> {
+                        return reject({ error: VALIDATE_FAILED ,index})
+                    })
+                })
+            }
+            return {
+                registerForm,
+                resetFields,
+                initFormData,
+                getFormData,
+                validateForm
+            }
+        }
+    })
+</script>
+</#if>
+</#list>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index 49dad0f..58c3b8b 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -110,7 +110,7 @@ public class ${entityName}Controller {
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
 	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
-	@PutMapping(value = "/edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) {
 		${entityName} ${entityName?uncap_first} = new ${entityName}();
 		BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first});
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
index 87cd55d..0a7ae06 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/${entityName}Form.vuei
@@ -8,7 +8,7 @@
 
    <a-tabs v-model="activeKey" @change="handleChangeTabs">
    <!--主表区域 -->
-    <a-tab-pane tab="${tableVo.ftlDescription}" :key="refKeys[0]" :forceRender="true">
+    <a-tab-pane tab="${tableVo.ftlDescription}" :key="refKeys[0]" :forceRender="true" :class="'jeecg-tabs-top'" :animated="false">
          <a-form-model ref="form" :model="model" :rules="validatorRules">
            <a-row>
         <#list columns as po>
@@ -19,13 +19,8 @@
             <#elseif po.dictField?default("")?trim?length gt 1>
                 <#assign form_field_dictCode="${po.dictField}">
             </#if>
-            <#if po.classType =='textarea'>
-                  <a-col :span="24">
-                    <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}">
-            <#else>
                   <a-col :xs="24" :sm="12">
                     <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}">
-            </#if>
             <#if po.classType =='date'>
                       <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%" <#if po.readonly=='Y'>disabled</#if>/>
             <#elseif po.classType =='datetime'>
@@ -160,20 +155,12 @@ export default {
    return {
      labelCol: {
        xs: { span: 24 },
-       sm: { span: 6 },
+       sm: { span: 5 },
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 },
      },
-     labelCol2: {
-       xs: { span: 24 },
-       sm: { span: 3 },
-     },
-     wrapperCol2: {
-       xs: { span: 24 },
-       sm: { span: 20 },
-     },
      // 新增时子表默认添加几行空数据
      addDefaultRowNum: 1,
      model:{
@@ -516,4 +503,8 @@ export default {
 </script>
 
 <style scoped>
+    /** tab panel 中有下拉框/日期 这类带下拉效果的,需要加此样式 */
+    /deep/ .jeecg-tabs-top {
+        overflow: visible;
+    }
 </style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
index b071f71..ca111ff 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue/modules/[1-n]Form.vuei
@@ -25,13 +25,8 @@
 	<#elseif po.dictField?default("")?trim?length gt 1>
 		<#assign form_field_dictCode="${po.dictField}">
 	</#if>
-	<#if po.classType =='textarea'>
-          <a-col :span="24">
-            <a-form-model-item label="${po.filedComment}" :labelCol="labelCol2" :wrapperCol="wrapperCol2" prop="${autoStringSuffixForModel(po)}">
-	<#else>
           <a-col :span="${form_span}">
             <a-form-model-item label="${po.filedComment}" :labelCol="labelCol" :wrapperCol="wrapperCol" prop="${autoStringSuffixForModel(po)}">
-	</#if>
 	<#if po.classType =='date'>
               <j-date placeholder="请选择${po.filedComment}" v-model="model.${po.fieldName}" style="width: 100%"/>
 	<#elseif po.classType =='datetime'>
@@ -118,20 +113,12 @@
         },
         labelCol: {
           xs: { span: 24 },
-          sm: { span: 6 },
+          sm: { span: 5 },
         },
         wrapperCol: {
           xs: { span: 24 },
           sm: { span: 16 },
         },
-        labelCol2: {
-          xs: { span: 24 },
-          sm: { span: 3 },
-        },
-        wrapperCol2: {
-          xs: { span: 24 },
-          sm: { span: 20 },
-        },
         <#include "/common/validatorRulesTemplate/sub.ftl">
         confirmLoading: false,
       }
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..d87e3b4
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,218 @@
+<template>
+  <div>
+<#assign list_need_category=false>
+<#assign list_need_pca=false>
+<#assign bpm_flag=false>
+
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.classType=='cat_tree' && po.dictText?default("")?trim?length == 0>
+<#assign list_need_category=true>
+</#if>
+<#if po.classType=='pca'>
+<#assign list_need_pca=true>
+</#if>
+</#list>
+<#-- 结束循环 -->
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--插槽:table标题-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+          <a-dropdown v-if="checkedKeys.length > 0">
+              <template #overlay>
+                <a-menu>
+                  <a-menu-item key="1" @click="batchHandleDelete">
+                    <Icon icon="ant-design:delete-outlined"></Icon>
+                    删除
+                  </a-menu-item>
+                </a-menu>
+              </template>
+              <a-button>批量操作
+                <Icon icon="mdi:chevron-down"></Icon>
+              </a-button>
+        </a-dropdown>
+      </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+      <!--字段回显插槽-->
+      <template #htmlSlot="{text}">
+         <div v-html="text"></div>
+      </template>
+      <template #fileSlot="{text}">
+         <span v-if="!text" style="font-size: 12px;font-style: italic;">无文件</span>
+         <a-button v-else :ghost="true" type="primary" preIcon="ant-design:download-outlined" size="small" @click="downloadFile(text)">下载</a-button>
+      </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
+  </div>
+</template>
+
+<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup>
+  import {ref, computed, unref} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {useModal} from '/@/components/Modal';
+  import ${entityName}Modal from './components/${entityName}Modal.vue'
+  import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
+  <#if list_need_category>
+  import { loadCategoryData } from '/@/api/common/api'
+  import { getAuthCache, setAuthCache } from '/@/utils/auth';
+  import { DB_DICT_DATA_KEY } from '/@/enums/cacheEnum';
+  </#if>
+  const checkedKeys = ref<Array<string | number>>([]);
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+   //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+      tableProps:{
+           title: '${tableVo.ftlDescription}',
+           api: list,
+           columns,
+           canResize:false,
+           formConfig: {
+                labelWidth: 120,
+                schemas: searchFormSchema,
+                autoSubmitOnEnter:true,
+                showAdvancedButton:true,
+                fieldMapToTime: [
+                <#list columns as po>
+                <#if po.isQuery=='Y'>
+                <#if po.queryMode!='single'>
+                <#if po.classType=='date'>
+                   ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD'],
+                <#elseif po.classType=='datetime'>
+                   ['${po.fieldName}', ['${po.fieldName}_begin', '${po.fieldName}_end'], 'YYYY-MM-DD HH:mm:ss'],
+                </#if>
+                </#if>
+                </#if>
+                </#list>
+                ],
+            },
+            actionColumn: {
+               width: 120,
+            },
+        },
+        exportConfig: {
+            name:"${tableVo.ftlDescription}",
+            url: getExportUrl,
+        },
+        importConfig: {
+            url: getImportUrl
+        },
+    })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+   /**
+    * 新增事件
+    */
+  function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+  }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+  async function handleDelete(record) {
+     await deleteOne({id: record.id}, reload);
+   }
+   /**
+    * 批量删除事件
+    */
+  async function batchHandleDelete() {
+     await batchDelete({ids: checkedKeys.value}, reload);
+   }
+   /**
+    * 成功回调
+    */
+  function handleSuccess() {
+      reload();
+   }
+   /**
+      * 操作栏
+      */
+  function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+   }
+     /**
+        * 下拉操作栏
+        */
+  function getDropDownAction(record){
+      return [
+           {
+             label: '详情',
+             onClick: handleDetail.bind(null, record),
+           }, {
+             label: '删除',
+             popConfirm: {
+               title: '是否确认删除',
+               confirm: handleDelete.bind(null, record),
+             }
+           }
+      ]
+   }
+    <#if list_need_category>
+   /**
+    * 初始化字典配置
+   */
+    function initDictConfig(){
+     <#list columns as po>
+     <#if (po.isQuery=='Y' || po.isShowList=='Y') && po.classType!='popup'>
+       <#if po.classType=='cat_tree' && list_need_category==true>
+       loadCategoryData({code:'${po.dictField?default("")}'}).then((res) => {
+         if (res) {
+             let allDictDate = getAuthCache(DB_DICT_DATA_KEY);
+             if(!allDictDate['${po.dictField?default("")}']){
+               Object.assign(allDictDate,{'${po.dictField?default("")}':res})
+             }
+             setAuthCache(DB_DICT_DATA_KEY,allDictDate)
+         }
+       })
+       </#if>
+     </#if>
+     </#list>
+   }
+   initDictConfig();
+    </#if>
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..3b9ce59
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,72 @@
+import {defHttp} from '/@/utils/http/axios';
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/list',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+<#list subTables as sub><#rt/>
+  ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/query${sub.entityName}ByMainId',
+</#list>
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+<#list subTables as sub><#rt/>
+/**
+ * 查询子表数据
+ * @param params
+ */
+export const ${sub.entityName?uncap_first}List = Api.${sub.entityName?uncap_first}List;
+</#list>
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..96cb6e8
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,700 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types'
+//列表数据
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.isShowList =='Y' && po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.sort=='Y'>
+    sorter: true,
+   </#if>
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+    <#elseif po.fieldDbType=='Blob'>
+    dataIndex: '${po.fieldName}String'
+    <#elseif po.classType=='umeditor'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'htmlSlot' },
+    <#elseif po.classType=='pca'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'pcaSlot' },//TODO 未翻译
+   <#elseif po.classType=='file'>
+    dataIndex: '${po.fieldName}',
+    slots: { customRender: 'fileSlot' },
+   <#elseif po.classType=='image'>
+    dataIndex: '${po.fieldName}',
+    customRender:render.renderAvatar,
+   <#elseif po.classType=='switch'>
+    dataIndex: '${po.fieldName}',
+<#assign switch_extend_arr=['Y','N']>
+<#if po.dictField?default("")?contains("[")>
+<#assign switch_extend_arr=po.dictField?eval>
+</#if>
+<#list switch_extend_arr as a>
+<#if a_index == 0>
+<#assign switch_extend_arr1=a>
+<#else>
+<#assign switch_extend_arr2=a>
+</#if>
+</#list>
+    customRender:({text}) => {
+       return  render.renderSwitch(text, [{text:'是',value:'${switch_extend_arr1}'},{text:'否',value:'${switch_extend_arr2}'}])
+     },
+   <#elseif po.classType == 'sel_tree' || po.classType=='list' || po.classType=='list_multi' || po.classType=='sel_search' || po.classType=='radio' || po.classType=='checkbox' || po.classType=='sel_depart' || po.classType=='sel_user'>
+    dataIndex: '${po.fieldName}_dictText'
+   <#elseif po.classType=='cat_tree'>
+    dataIndex: '${po.fieldName}',
+    <#if po.dictText?default("")?trim?length == 0>
+    customRender:({text}) => {
+       return  render.renderCategoryTree(text,'${po.dictField?default("")}')
+   },
+   <#else>
+    customRender: (text, record) => (text ? record['${po.dictText}'] : '')
+   </#if>
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+<#-- 开始循环 -->
+<#list columns as po>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isQuery=='Y'>
+<#assign query_flag=true>
+	<#assign query_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1>
+	    <#assign query_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+    <#elseif po.dictField?default("")?trim?length gt 1>
+        <#assign query_field_dictCode="${po.dictField}">
+    </#if>
+<#if po.queryMode=='single'>
+	{
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='sel_search'>
+      component: 'JSearchSelect',
+      componentProps:{
+         dict:"${po.dictTable},${po.dictText},${po.dictField}"
+      },
+<#elseif po.classType=='sel_user'>
+      component: 'JSelectUserByDept',
+<#elseif po.classType=='switch'>
+      component: 'JSwitch',
+      componentProps:{
+           <#if po.dictField != 'is_open'>
+           options:"${po.dictField}"
+           </#if>
+       },
+ <#elseif po.classType=='sel_depart'>
+      component: 'JSelectDept',
+ <#elseif po.classType=='list_multi'>
+      component: 'JMultiSelectTag',//暂无该组件
+      componentProps:{
+          dictCode:"query_field_dictCode?default("")"
+      },
+ <#elseif po.classType=='cat_tree'>
+      component: 'JCategorySelect',
+      componentProps:{
+          pcode:"${po.dictField?default("")}",//back和事件未添加,暂时有问题
+      },
+<#elseif po.classType=='date'>
+      component: 'DatePicker',
+<#elseif po.classType=='datetime'>
+      component: 'DatePicker',
+      componentProps: {
+         showTime:true
+       },
+<#elseif po.classType=='pca'>
+      component: 'JAreaLinkage',
+<#elseif po.classType=='popup'>
+      component: 'JPopup',
+      componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:"${po.dictField}",
+             multi:${po.extendParams.popupMulti?c},
+         }
+     },
+<#elseif po.classType=='list' || po.classType=='radio' || po.classType=='checkbox'>
+<#--  ---------------------------下拉或是单选 判断数据字典是表字典还是普通字典------------------------------- -->
+      component: 'JDictSelectTag',
+      componentProps:{
+       <#if po.dictTable?default("")?trim?length gt 1>
+          dictCode:"${po.dictTable},${po.dictText},${po.dictField}"
+       <#elseif po.dictField?default("")?trim?length gt 1>
+          dictCode:"${po.dictField}"
+        </#if>
+      },
+<#else>
+      component: 'Input',
+</#if>
+      colProps: {span: 6},
+ 	},
+<#else>
+     {
+      label: "${po.filedComment}",
+      field: "${po.fieldName}",
+<#if po.classType=='date'>
+      component: 'RangePicker',
+<#elseif po.classType=='datetime'>
+      component: 'RangePicker',
+      componentProps: {
+          showTime:true
+      },
+<#else>
+      component: 'Input', //TODO 范围查询
+</#if>
+      colProps: {span: 6},
+	},
+</#if>
+</#if>
+</#list>
+<#-- 结束循环 -->
+];
+//表单数据
+export const formSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list columns as po><#rt/>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
+//子表单数据
+<#list subTables as sub>
+<#if sub.foreignRelationType =='1'>
+export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [
+<#assign form_cat_tree = false>
+<#assign form_cat_back = "">
+<#assign bpm_flag=false>
+<#list sub.colums as po><#rt/>
+<#if po.fieldDbName=='bpm_status'>
+  <#assign bpm_flag=true>
+</#if>
+<#if po.isShow =='Y'>
+<#assign form_field_dictCode="">
+	<#if po.dictTable?default("")?trim?length gt 1 && po.dictText?default("")?trim?length gt 1 && po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictTable},${po.dictText},${po.dictField}">
+	<#elseif po.dictField?default("")?trim?length gt 1>
+		<#assign form_field_dictCode="${po.dictField}">
+	</#if>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+    <#if po.classType =='date'>
+    component: 'DatePicker',
+     <#elseif po.fieldType =='datetime'>
+    component: 'DatePicker',
+    componentProps: {
+       showTime:true
+     },
+     <#elseif po.fieldType =='time'>
+    component: 'TimePicker',
+    <#elseif po.classType =='popup'>
+    component: 'JPopup',
+    componentProps: ({ formActionType }) => {
+         const {setFieldsValue} = formActionType;
+         return{
+             setFieldsValue:setFieldsValue,
+             code:"${po.dictTable}",
+             fieldConfig:${po.dictField},
+             multi:${po.extendParams.popupMulti?c},
+         }
+     }
+     <#elseif po.classType =='sel_depart'>
+     component: 'JSelectDept',
+     <#elseif po.classType =='switch'>
+     component: 'JSwitch',
+     componentProps:{
+         <#if po.dictField != 'is_open'>
+         options:${po.dictField}
+         </#if>
+     }
+     <#elseif po.classType =='pca'>
+    component: 'JAreaLinkage',
+    <#elseif po.classType =='markdown'>
+    component: 'JMarkdownEditor',//注意string转换问题
+     <#elseif po.classType =='password'>
+    component: 'InputPassword',
+     <#elseif po.classType =='sel_user'>
+    component: 'JSelectUserByDept',
+    componentProps:{
+        labelKey:'realname',
+     }
+    <#elseif po.classType =='textarea'>
+    component: 'InputTextArea',//TODO 注意string转换问题
+    <#elseif po.classType=='list' || po.classType=='radio'>
+    component: 'JDictSelectTag',
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='list_multi' || po.classType=='checkbox'>
+    component: 'JMultiSelectTag',//TODO  暂无该组件
+    componentProps:{
+        dictCode:"${form_field_dictCode}"
+     }
+    <#elseif po.classType=='sel_search'>
+    component: 'JSearchSelect',
+    componentProps:{
+       dict:"${form_field_dictCode}"
+    }
+<#elseif po.classType=='cat_tree'>
+    <#assign form_cat_tree = true>
+    component: 'JCategorySelect',
+    componentProps:{
+       pcode:"${po.dictField?default("")}", //TODO back和事件未添加,暂时有问题
+    }
+    <#if po.dictText?default("")?trim?length gt 1>
+    <#assign form_cat_back = "${po.dictText}">
+    </#if>
+    <#elseif po.fieldDbType=='int' || po.fieldDbType=='double' || po.fieldDbType=='BigDecimal'>
+    component: 'InputNumber',
+    <#elseif po.classType=='file'>
+    component: 'JUpload',
+    componentProps:{
+    <#if po.uploadnum??>
+       maxCount:${po.uploadnum}
+   </#if>
+     }
+ <#elseif po.classType=='image'>
+     component: 'JImageUpload',
+     componentProps:{
+     <#if po.uploadnum??>
+        fileMax:${po.uploadnum}
+    </#if>
+      }
+  <#elseif po.classType=='umeditor'>
+    component: 'JCodeEditor', //TODO String后缀暂未添加
+  <#elseif po.classType == 'sel_tree'>
+    component: 'JTreeSelect',
+    componentProps:{
+        <#if po.dictText??>
+        <#if po.dictText?split(',')[2]?? && po.dictText?split(',')[0]??>
+        dict:"${po.dictTable},${po.dictText?split(',')[2]},${po.dictText?split(',')[0]}",
+        <#elseif po.dictText?split(',')[1]??>
+        pidField:"${po.dictText?split(',')[1]}",
+        <#elseif po.dictText?split(',')[3]??>
+        hasChildField:"${po.dictText?split(',')[3]}",
+        </#if>
+        </#if>
+        pidValue:"${po.dictField}",
+    }
+   <#else>
+    component: 'Input',
+    </#if>
+     <#include "/common/utils.ftl">
+    <#if po.isShow == 'Y' && poHasCheck(po)>
+    dynamicRules: ({model,schema}) => {
+    <#if po.fieldName != 'id'>
+    <#assign fieldValidType = po.fieldValidType!''>
+          return [
+            <#-- 非空校验 -->
+           <#if po.nullable == 'N' || fieldValidType == '*'>
+                 { required: true, message: '请输入${po.filedComment}!'},
+           <#elseif fieldValidType!=''>
+                 { required: false},
+           </#if>
+       <#-- 唯一校验 -->
+           <#if fieldValidType == 'only'>
+                 {...rules.duplicateCheckRule(<#if sub?default("")?trim?length gt 1>'${sub.tableName}'<#else>'${tableName}'</#if>, '${po.fieldDbName}',model,schema,true)[0]},
+           <#-- 6到16位数字 -->
+           <#elseif fieldValidType == 'n6-16'>
+                 { pattern: /^\d{6,16}$/, message: '请输入6到16位数字!'},
+           <#-- 6到16位任意字符 -->
+           <#elseif fieldValidType == '*6-16'>
+                 { pattern: /^.{6,16}$/, message: '请输入6到16位任意字符!'},
+           <#-- 6到18位字符串 -->
+           <#elseif fieldValidType == 's6-18'>
+                 { pattern: /^.{6,18}$/, message: '请输入6到18位任意字符!'},
+           <#-- 网址 -->
+           <#elseif fieldValidType == 'url'>
+                 { pattern: /^((ht|f)tps?):\/\/[\w\-]+(\.[\w\-]+)+([\w\-.,@?^=%&:\/~+#]*[\w\-@?^=%&\/~+#])?$/, message: '请输入正确的网址!'},
+           <#-- 电子邮件 -->
+           <#elseif fieldValidType == 'e'>
+                 { pattern: /^([\w]+\.*)([\w]+)@[\w]+\.\w{3}(\.\w{2}|)$/, message: '请输入正确的电子邮件!'},
+           <#-- 手机号码 -->
+           <#elseif fieldValidType == 'm'>
+                 { pattern: /^1[3456789]\d{9}$/, message: '请输入正确的手机号码!'},
+           <#-- 邮政编码 -->
+           <#elseif fieldValidType == 'p'>
+                 { pattern: /^[1-9]\d{5}$/, message: '请输入正确的邮政编码!'},
+           <#-- 字母 -->
+           <#elseif fieldValidType == 's'>
+                 { pattern: /^[A-Z|a-z]+$/, message: '请输入字母!'},
+           <#-- 数字 -->
+           <#elseif fieldValidType == 'n'>
+                 { pattern: /^-?\d+\.?\d*$/, message: '请输入数字!'},
+           <#-- 整数 -->
+           <#elseif fieldValidType == 'z'>
+                 { pattern: /^-?\d+$/, message: '请输入整数!'},
+           <#-- 金额 -->
+           <#elseif fieldValidType == 'money'>
+                 { pattern: /^(([1-9][0-9]*)|([0]\.\d{0,2}|[1-9][0-9]*\.\d{0,2}))$/, message: '请输入正确的金额!'},
+           <#-- 正则校验 -->
+           <#elseif fieldValidType != '' && fieldValidType != '*'>
+                 { pattern: '${fieldValidType}', message: '不符合校验规则!'},
+           <#-- 无校验 -->
+           <#else>
+               <#t>
+           </#if>
+          ];
+     </#if>
+     },
+    </#if>
+    <#if po.readonly=='Y'>
+    dynamicDisabled:true
+    </#if>
+  },
+</#if>
+</#list>
+];
+</#if>
+</#list>
+//子表表格配置
+<#list subTables as sub>
+<#if sub.foreignRelationType =='0'>
+export const ${sub.entityName?uncap_first}Columns: JVxeColumn[] = [
+<#assign popupBackFields = "">
+
+<#-- 循环子表的列 开始 -->
+<#list sub.colums as col><#rt/>
+<#if col.isShow =='Y'>
+<#if col.filedComment !='外键' >
+    {
+      title: '${col.filedComment}',
+      key: '${autoStringSuffixForModel(col)}',
+<#if col.classType =='date'>
+      type: JVxeTypes.date,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='datetime'>
+      type: JVxeTypes.datetime,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='textarea'>
+      type: JVxeTypes.textarea,
+       <#if col.readonly=='Y'>
+      disabled:true,
+       </#if>
+<#elseif "int,decimal,double,"?contains(col.classType)>
+      type: JVxeTypes.inputNumber,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='list' || col.classType =='radio'>
+      type: JVxeTypes.select,
+      options:[],
+      <#if col.dictTable?default("")?trim?length gt 1>
+      dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
+      <#else>
+      dictCode:"${col.dictField}",
+      </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='list_multi' || col.classType =='checkbox'>
+      type: JVxeTypes.selectMultiple,
+      options:[],
+      <#if col.dictTable?default("")?trim?length gt 1>
+      dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
+      <#else>
+      dictCode:"${col.dictField}",
+      </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='sel_search'>
+      type: JVxeTypes.selectSearch,
+      <#if col.dictTable?default("")?trim?length gt 1>
+      dictCode:"${col.dictTable},${col.dictText},${col.dictField}",
+      <#else>
+      dictCode:"${col.dictField}",
+      </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='image'>
+      type: JVxeTypes.image,
+      token:true,
+      responseName:"message",
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+      <#if col.uploadnum??>
+      number: ${col.uploadnum},
+      </#if>
+<#elseif col.classType =='file'>
+      type: JVxeTypes.file,
+      token:true,
+      responseName:"message",
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+      <#if col.uploadnum??>
+      number: ${col.uploadnum},
+      </#if>
+<#elseif col.classType =='switch'>
+      type: JVxeTypes.checkbox,
+       <#if col.dictField == 'is_open'>
+        customValue: ['Y', 'N'],
+        <#else>
+        customValue: ${col.dictField},
+        </#if>
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#elseif col.classType =='popup'>
+<#if popupBackFields?length gt 0>
+    <#assign popupBackFields = "${popupBackFields}"+","+"${col.dictText}">
+<#else>
+    <#assign popupBackFields = "${col.dictText}">
+</#if>
+      type: JVxeTypes.popup,
+      popupCode:"${col.dictTable}",
+      field:"${col.dictField}",
+      orgFields:"${col.dictField}",
+      destFields:"${Format.underlineToHump(col.dictText)}",
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+<#else>
+      type: JVxeTypes.input,
+      <#if col.readonly=='Y'>
+      disabled:true,
+      </#if>
+</#if>
+<#if col.classType =='list_multi' || col.classType =='checkbox'>
+      width:"250px",
+<#else>
+      width:"200px",
+</#if>
+<#if col.classType =='file'>
+      placeholder: '请选择文件',
+<#else>
+      placeholder: '请输入${'$'}{title}',
+</#if>
+<#if col.defaultVal??>
+<#if col.fieldDbType=="BigDecimal" || col.fieldDbType=="double" || col.fieldDbType=="int">
+      defaultValue:${col.defaultVal},
+      <#else>
+      defaultValue:"${col.defaultVal}",
+</#if>
+<#else>
+      defaultValue:'',
+</#if>
+<#-- 子表的校验 -->
+<#assign subFieldValidType = col.fieldValidType!''>
+<#-- 非空校验 -->
+<#if col.nullable == 'N' || subFieldValidType == '*'>
+      validateRules: [{ required: true, message: '${'$'}{title}不能为空' }],
+<#-- 其他情况下,只要有值就被认为是正则校验 -->
+<#elseif subFieldValidType?length gt 0>
+<#assign subMessage = '格式不正确'>
+<#if subFieldValidType == 'only' >
+  <#assign subMessage = '不能重复'>
+</#if>
+      validateRules: [{ pattern: "${subFieldValidType}", message: "${'$'}{title}${subMessage}" }],
+</#if>
+    },
+</#if>
+</#if>
+</#list>
+<#-- 循环子表的列 结束 -->
+  ]
+</#if>
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
new file mode 100644
index 0000000..2dc5206
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/${entityName}Modal.vuei
@@ -0,0 +1,183 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit">
+  <!-- 子表单区域 -->
+    <a-tabs v-model:activeKey="activeKey" @change="handleChangeTabs">
+     <!--主表区域 -->
+     <a-tab-pane tab="${tableVo.ftlDescription}" :key="refKeys[0]" :forceRender="true">
+       <BasicForm @register="registerForm" ref="formRef"/>
+     </a-tab-pane>
+  <!--子表单区域 -->
+<#list subTables as sub><#rt/>
+  <#if sub.foreignRelationType =='1'>
+      <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index+1}]" :forceRender="true">
+        <${sub.entityName}Form ref="${sub.entityName?uncap_first}Form"></${sub.entityName}Form>
+      </a-tab-pane>
+
+  <#else>
+      <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index+1}]" :forceRender="true">
+        <JVxeTable
+          keep-source
+          resizable
+          :ref="refKeys[${sub_index+1}]"
+          :loading="${sub.entityName?uncap_first}Table.loading"
+          :columns="${sub.entityName?uncap_first}Table.columns"
+          :dataSource="${sub.entityName?uncap_first}Table.dataSource"
+          :maxHeight="300"
+          :rowNumber="true"
+          :rowSelection="true"
+          :toolbar="true"
+          />
+      </a-tab-pane>
+  </#if>
+</#list>
+    </a-tabs>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref,reactive} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import { JVxeTable } from '/@/components/jeecg/JVxeTable'
+    import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts'
+    <#list subTables as sub>
+      <#if sub.foreignRelationType =='1'>
+    import ${sub.entityName}Form from './${sub.entityName}Form.vue'
+      </#if>
+    </#list>
+    import {formSchema<#list subTables as sub><#if sub.foreignRelationType =='0'>,${sub.entityName?uncap_first}Columns</#if></#list>} from '../${entityName?uncap_first}.data';
+    import {saveOrUpdate<#list subTables as sub>,${sub.entityName?uncap_first}List</#list>} from '../${entityName?uncap_first}.api';
+    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    const refKeys = ref(['${tableVo.entityName?uncap_first}',<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]);
+    <#assign hasOne2Many = false>
+    <#assign hasOne2One = false>
+    const activeKey = ref('${tableVo.entityName?uncap_first}');
+<#list subTables as sub>
+<#if sub.foreignRelationType =='0'>
+ <#assign hasOne2Many = true>
+    const ${sub.entityName?uncap_first} = ref();
+</#if>
+<#if sub.foreignRelationType =='1'>
+ <#assign hasOne2One = true>
+    const ${sub.entityName?uncap_first}Form = ref();
+</#if>
+</#list>
+    const tableRefs = {<#list subTables as sub><#if sub.foreignRelationType =='0'>${sub.entityName?uncap_first}, <#assign hasOne2Many = true></#if></#list>};
+   <#list subTables as sub>
+   <#if sub.foreignRelationType =='0'>
+    const ${sub.entityName?uncap_first}Table = reactive({
+          loading: false,
+          dataSource: [],
+          columns:${sub.entityName?uncap_first}Columns
+    })
+    </#if>
+   </#list>
+    //表单配置
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+    });
+     //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await reset();
+        setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+            <#list subTables as sub><#rt/>
+            <#if sub.foreignRelationType =='1'>
+             ${sub.entityName?uncap_first}Form.value.initFormData(${sub.entityName?uncap_first}List,data?.record?.id)
+            </#if>
+            </#list>
+            <#list subTables as sub><#rt/>
+            <#if sub.foreignRelationType =='0'>
+             requestSubTableData(${sub.entityName?uncap_first}List, {id:data?.record?.id}, ${sub.entityName?uncap_first}Table)
+            </#if>
+            </#list>
+        }
+        // 隐藏底部时禁用整个表单
+       setProps({ disabled: !data?.showFooter })
+    });
+    //方法配置
+    const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys<#if hasOne2One==true>,validateSubForm</#if>);
+
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+
+    async function reset(){
+      await resetFields();
+      activeKey.value = ref('${tableVo.entityName?uncap_first}');
+      <#list subTables as sub>
+        <#if sub.foreignRelationType =='0'>
+      ${sub.entityName?uncap_first}Table.dataSource = [];
+        </#if>
+        <#if sub.foreignRelationType =='1'>
+      ${sub.entityName?uncap_first}Form.value.resetFields();
+        </#if>
+      </#list>
+    }
+    function classifyIntoFormData(allValues) {
+         let main = Object.assign({}, allValues.formValue)
+         return {
+           ...main, // 展开
+ <#assign subManyIndex = 0>
+ <#list subTables as sub><#rt/>
+ <#if sub.foreignRelationType =='0'>
+           ${sub.entityName?uncap_first}List: allValues.tablesValue[${subManyIndex}].tableData,
+           <#assign subManyIndex = subManyIndex+1>
+ <#else>
+           ${sub.entityName?uncap_first}List: ${sub.entityName?uncap_first}Form.value.getFormData(),
+ </#if>
+ </#list>
+         }
+       }
+      <#if hasOne2One==true>
+     //校验所有一对一子表表单
+     function validateSubForm(allValues){
+         return new Promise((resolve,reject)=>{
+             Promise.all([
+             <#list subTables as sub><#rt/>
+            <#if sub.foreignRelationType =='1'>
+                  ${sub.entityName?uncap_first}Form.value.validateForm(${sub_index+1}),
+            </#if>
+          </#list>
+             ]).then(() => {
+                 resolve(allValues)
+             }).catch(e => {
+                 if (e.error === VALIDATE_FAILED) {
+                     // 如果有未通过表单验证的子表,就自动跳转到它所在的tab
+                     activeKey.value = e.index == null ? unref(activeKey) : refKeys.value[e.index]
+                 } else {
+                     console.error(e)
+                 }
+             })
+         })
+     }
+    </#if>
+    //表单提交事件
+    async function requestAddOrEdit(values) {
+        try {
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
new file mode 100644
index 0000000..afa4e7b
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template-online/tab/onetomany/java/${bussiPackage}/${entityPackage}/vue3/components/[1-n]Form.vuei
@@ -0,0 +1,64 @@
+<#list subTables as sub>
+<#if sub.foreignRelationType=='1'>
+#segment#${sub.entityName}Form.vue
+<template>
+    <BasicForm @register="registerForm"/>
+</template>
+<script lang="ts">
+    import {defineComponent} from 'vue';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {${sub.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data';
+    import {defHttp} from '/@/utils/http/axios';
+    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+
+    export default defineComponent({
+        name:"${sub.entityName}Form",
+        components: {BasicForm},
+        emits:['register'],
+        setup(_,{emit}) {
+            const [registerForm, {resetFields, setFieldsValue,getFieldsValue,validate}] = useForm({
+                labelWidth: 150,
+                schemas: ${sub.entityName?uncap_first}FormSchema,
+                showActionButtonGroup: false,
+            });
+            /**
+            *初始化加载数据
+            */
+            function initFormData(url,id){
+                if(id){
+                     defHttp.get({url,params:{id}},{isTransformResponse:false}).then(res=>{
+                       res.success && setFieldsValue({...res.result[0]});
+                    })
+                }
+            }
+           /**
+            *获取表单数据
+            */
+            function getFormData(){
+               return [getFieldsValue()];
+            }
+            /**
+            *表单校验
+            */
+            function validateForm(index){
+                return new Promise((resolve, reject) => {
+                    // 验证子表表单
+                    validate().then(()=>{
+                        return resolve()
+                    }).catch(()=> {
+                        return reject({ error: VALIDATE_FAILED ,index})
+                    })
+                })
+            }
+            return {
+                registerForm,
+                resetFields,
+                initFormData,
+                getFormData,
+                validateForm
+            }
+        }
+    })
+</script>
+</#if>
+</#list>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index 0319320..60900d2 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -93,7 +93,7 @@ public class ${entityName}Controller extends JeecgController<${entityName}, I${e
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
 	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
-	@PutMapping(value = "/edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
 		${entityName?uncap_first}Service.updateById(${entityName?uncap_first});
 		return Result.OK("编辑成功!");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}Form.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}Form.vuei
new file mode 100644
index 0000000..7d7a57c
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}Form.vuei
@@ -0,0 +1,93 @@
+<template>
+    <view>
+        <!--标题和返回-->
+		<cu-custom :bgColor="NavBarColor" isBack :backRouterName="backRouteName">
+			<block slot="backText">返回</block>
+			<block slot="content">${tableVo.ftlDescription}</block>
+		</cu-custom>
+		 <!--表单区域-->
+		<view>
+			<form>
+    <#list columns as po><#rt/>
+    <#if po.fieldName !='id'><#rt/>
+         <#if po.fieldType =='date'>
+              <my-date label="${po.filedComment}:" fields="day" v-model="model.${po.fieldName}" placeholder="请输入${po.filedComment}"></my-date>
+         <#elseif po.fieldType =='datetime'>
+              <my-date label="${po.filedComment}:" v-model="model.${po.fieldName}" placeholder="请输入${po.filedComment}"></my-date>
+         <#else>
+              <view class="cu-form-group">
+                <view class="flex align-center">
+                  <view class="title"><text space="ensp">${po.filedComment}:</text></view>
+                  <input <#if "int,decimal,double,"?contains(po.fieldType)>type="number"</#if> placeholder="请输入${po.filedComment}" v-model="model.${po.fieldName}"/>
+                </view>
+              </view>
+        </#if>
+    </#if>
+    </#list>
+				<view class="padding">
+					<button class="cu-btn block bg-blue margin-tb-sm lg" @click="onSubmit">
+						<text v-if="loading" class="cuIcon-loading2 cuIconfont-spin"></text>提交
+					</button>
+				</view>
+			</form>
+		</view>
+    </view>
+</template>
+
+<script>
+    import myDate from '@/components/my-componets/my-date.vue'
+
+    export default {
+        name: "${entityName}Form",
+        components:{myDate},
+        props:{
+          formData:{
+              type:Object,
+              default:()=>{},
+              required:false
+          }
+        },
+        data(){
+            return {
+				CustomBar: this.CustomBar,
+				NavBarColor: this.NavBarColor,
+				loading:false,
+                model: {},
+                backRouteName:'index',
+                url: {
+                  queryById: "/${entityPackage}/${entityName?uncap_first}/queryById",
+                  add: "/${entityPackage}/${entityName?uncap_first}/add",
+                  edit: "/${entityPackage}/${entityName?uncap_first}/edit",
+                },
+            }
+        },
+        created(){
+             this.initFormData();
+        },
+        methods:{
+           initFormData(){
+               if(this.formData){
+                    let dataId = this.formData.dataId;
+                    this.$http.get(this.url.queryById,{params:{id:dataId}}).then((res)=>{
+                        if(res.data.success){
+                            console.log("表单数据",res);
+                            this.model = res.data.result;
+                        }
+                    })
+                }
+            },
+            onSubmit() {
+                let myForm = {...this.model};
+                this.loading = true;
+                let url = myForm.id?this.url.edit:this.url.add;
+				this.$http.post(url,myForm).then(res=>{
+				   console.log("res",res)
+				   this.loading = false
+				   this.$Router.push({name:this.backRouteName})
+				}).catch(()=>{
+					this.loading = false
+				});
+            }
+        }
+    }
+</script>
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}List.vuei
new file mode 100644
index 0000000..4e499af
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue-app/${entityName}List.vuei
@@ -0,0 +1,44 @@
+<template>
+	<view>
+	   <!--标题和返回-->
+		<cu-custom :bgColor="NavBarColor" isBack>
+			<block slot="backText">返回</block>
+			<block slot="content">${tableVo.ftlDescription}</block>
+		</cu-custom>
+		<!--滚动加载列表-->
+		<mescroll-body ref="mescrollRef" bottom="88"  @init="mescrollInit" :up="upOption" :down="downOption" @down="downCallback" @up="upCallback">
+		    <view class="cu-list menu">
+				<view class="cu-item" v-for="(item,index) in list" :key="index" @click="goHome">
+					<view class="flex" style="width:100%">
+                        <text class="text-lg" style="color: #000;">
+                             {{ item.createBy}}
+                        </text>
+					</view>
+				</view>
+			</view>
+		</mescroll-body>
+	</view>
+</template>
+
+<script>
+	import MescrollMixin from "@/components/mescroll-uni/mescroll-mixins.js";
+	import Mixin from "@/common/mixin/Mixin.js";
+
+	export default {
+		name: '${tableVo.ftlDescription}',
+		mixins: [MescrollMixin,Mixin],
+		data() {
+			return {
+				CustomBar:this.CustomBar,
+				NavBarColor:this.NavBarColor,
+				url: "/${entityPackage}/${entityName?uncap_first}/list",
+			};
+		},
+		methods: {
+			goHome(){
+                this.$Router.push({name: "index"})
+			}
+		}
+	}
+</script>
+
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..ed2cd44
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,153 @@
+<template>
+  <div>
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--插槽:table标题-->
+          <template #tableTitle>
+             <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+             <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+             <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+             <a-dropdown v-if="checkedKeys.length > 0">
+                 <template #overlay>
+                    <a-menu>
+                      <a-menu-item key="1" @click="batchHandleDelete">
+                        <Icon icon="ant-design:delete-outlined"></Icon>
+                        删除
+                      </a-menu-item>
+                    </a-menu>
+                  </template>
+                  <a-button>批量操作
+                    <Icon icon="mdi:chevron-down"></Icon>
+                  </a-button>
+            </a-dropdown>
+          </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+    </BasicTable>
+
+    <!-- 表单区域 -->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import {ref, computed, unref} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import {useModal} from '/@/components/Modal';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import ${entityName}Modal from './modules/${entityName}Modal.vue'
+  import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
+
+  const checkedKeys = ref<Array<string | number>>([]);
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+  //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+       tableProps:{
+            title: '${tableVo.ftlDescription}',
+            api: list,
+            columns,
+            canResize:false,
+            formConfig: {
+               labelWidth: 120,
+               schemas: searchFormSchema,
+               autoSubmitOnEnter:true,
+               showAdvancedButton:true,
+             },
+            actionColumn: {
+                width: 120,
+             },
+        },
+        exportConfig: {
+             name:"${tableVo.ftlDescription}",
+             url: getExportUrl,
+           },
+           importConfig: {
+             url: getImportUrl
+           },
+   })
+
+   const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+   /**
+    * 新增事件
+    */
+   function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+   }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+   async function handleDelete(record) {
+     await deleteOne({id: record.id}, reload);
+   }
+   /**
+    * 批量删除事件
+    */
+   async function batchHandleDelete() {
+     await batchDelete({ids: checkedKeys.value}, reload);
+   }
+   /**
+    * 成功回调
+    */
+   function handleSuccess({isUpdate, values}) {
+      reload();
+   }
+   /**
+      * 操作栏
+      */
+   function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+     }
+     /**
+       * 下拉操作栏
+       */
+    function getDropDownAction(record){
+      return [
+           {
+             label: '详情',
+             onClick: handleDetail.bind(null, record),
+           }, {
+             label: '删除',
+             popConfirm: {
+               title: '是否确认删除',
+               confirm: handleDelete.bind(null, record),
+             }
+           }
+      ]
+    }
+</script>
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..c579f91
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,61 @@
+import {defHttp} from '/@/utils/http/axios';
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/list',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..8034d5b
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,56 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    dataIndex: '${po.fieldName}'
+   },
+   </#if>
+ </#list>
+];
+
+export const searchFormSchema: FormSchema[] = [
+<#list columns as po>
+<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum>
+ {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+     <#if po.fieldType =='date'>
+    component: 'DatePicker'
+     <#elseif po.fieldType =='datetime'>
+    component: 'TimePicker'
+     <#elseif "int,decimal,double,"?contains(po.fieldType)>
+    component: 'InputNumber'
+     <#else>
+    component: 'Input'
+    </#if>
+  },
+</#if>
+</#list>
+];
+
+export const formSchema: FormSchema[] = [
+<#list columns as po><#rt/>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+     <#if po.fieldType =='date'>
+    component: 'DatePicker'
+     <#elseif po.fieldType =='datetime'>
+    component: 'TimePicker'
+     <#elseif "int,decimal,double,"?contains(po.fieldType)>
+    component: 'InputNumber'
+     <#else>
+    component: 'Input'
+    </#if>
+    <#if po.fieldName =='id'><#rt/>
+    show:false
+    </#if>
+  },
+</#list>
+];
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
new file mode 100644
index 0000000..a6cdaec
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
@@ -0,0 +1,56 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="40%">
+         <BasicForm @register="registerForm"/>
+     </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {formSchema} from '../${entityName?uncap_first}.data';
+    import {saveOrUpdate} from '../${entityName?uncap_first}.api';
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    //表单配置
+    const [registerForm, {resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+    });
+    //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await resetFields();
+        setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+        }
+    });
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+    //表单提交事件
+    async function handleSubmit(v) {
+        try {
+            let values = await validate();
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/controller/${entityPackage}/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/controller/${entityPackage}/${entityName}Controller.javai
new file mode 100644
index 0000000..57b69be
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/controller/${entityPackage}/${entityName}Controller.javai
@@ -0,0 +1,170 @@
+package ${bussiPackage}.controller.${entityPackage};
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.util.oConvertUtils;
+import ${bussiPackage}.entity.${entityPackage}.${entityName};
+import ${bussiPackage}.service.${entityPackage}.I${entityName}Service;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.MultipartHttpServletRequest;
+import org.springframework.web.servlet.ModelAndView;
+
+import org.jeecgframework.poi.excel.ExcelImportUtil;
+import org.jeecgframework.poi.excel.def.NormalExcelConstants;
+import org.jeecgframework.poi.excel.entity.ExportParams;
+import org.jeecgframework.poi.excel.entity.ImportParams;
+import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+import lombok.extern.slf4j.Slf4j;
+
+import com.alibaba.fastjson.JSON;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.jeecg.common.aspect.annotation.AutoLog;
+
+ /**
+ * @Description: ${tableVo.ftlDescription}
+ * @Author: jeecg-boot
+ * @Date:   ${.now?string["yyyy-MM-dd"]}
+ * @Version: V1.0
+ */
+@Api(tags="${tableVo.ftlDescription}")
+@RestController
+@RequestMapping("/${entityPackage}/${entityName?uncap_first}")
+@Slf4j
+public class ${entityName}Controller extends JeecgController<${entityName}, I${entityName}Service> {
+	@Autowired
+	private I${entityName}Service ${entityName?uncap_first}Service;
+	
+	/**
+	 * 分页列表查询
+	 *
+	 * @param ${entityName?uncap_first}
+	 * @param pageNo
+	 * @param pageSize
+	 * @param req
+	 * @return
+	 */
+	@AutoLog(value = "${tableVo.ftlDescription}-分页列表查询")
+	@ApiOperation(value="${tableVo.ftlDescription}-分页列表查询", notes="${tableVo.ftlDescription}-分页列表查询")
+	@GetMapping(value = "/list")
+	public Result<?> queryPageList(${entityName} ${entityName?uncap_first},
+								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+							       @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+								   HttpServletRequest req) {
+		QueryWrapper<${entityName}> queryWrapper = QueryGenerator.initQueryWrapper(${entityName?uncap_first}, req.getParameterMap());
+		Page<${entityName}> page = new Page<${entityName}>(pageNo, pageSize);
+		IPage<${entityName}> pageList = ${entityName?uncap_first}Service.page(page, queryWrapper);
+		return Result.OK(pageList);
+
+	}
+	
+	/**
+	 *   添加
+	 * @param ${entityName?uncap_first}
+	 * @return
+	 */
+	@AutoLog(value = "${tableVo.ftlDescription}-添加")
+	@ApiOperation(value="${tableVo.ftlDescription}-添加", notes="${tableVo.ftlDescription}-添加")
+	@PostMapping(value = "/add")
+	public Result<?> add(@RequestBody ${entityName} ${entityName?uncap_first}) {
+		${entityName?uncap_first}Service.save(${entityName?uncap_first});
+		return Result.OK("添加成功!");
+	}
+	
+	/**
+	 *  编辑
+	 *
+	 * @param ${entityName?uncap_first}
+	 * @return
+	 */
+	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
+	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
+	public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
+		${entityName?uncap_first}Service.updateById(${entityName?uncap_first});
+		return Result.OK("编辑成功!");
+	}
+	
+	/**
+	 *  通过id删除
+	 * @param id
+	 * @return
+	 */
+	@AutoLog(value = "${tableVo.ftlDescription}-通过id删除")
+	@ApiOperation(value="${tableVo.ftlDescription}-通过id删除", notes="${tableVo.ftlDescription}-通过id删除")
+	@DeleteMapping(value = "/delete")
+	public Result<?> delete(@RequestParam(name="id",required=true) String id) {
+		${entityName?uncap_first}Service.removeById(id);
+		return Result.OK("删除成功!");
+	}
+	
+	/**
+	 *  批量删除
+	 *
+	 * @param ids
+	 * @return
+	 */
+	@AutoLog(value = "${tableVo.ftlDescription}-批量删除")
+	@ApiOperation(value="${tableVo.ftlDescription}-批量删除", notes="${tableVo.ftlDescription}-批量删除")
+	@DeleteMapping(value = "/deleteBatch")
+	public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+		this.${entityName?uncap_first}Service.removeByIds(Arrays.asList(ids.split(",")));
+		return Result.OK("批量删除成功!");
+	}
+	
+	/**
+	 * 通过id查询
+     *
+	 * @param id
+	 * @return
+	 */
+	@AutoLog(value = "${tableVo.ftlDescription}-通过id查询")
+	@ApiOperation(value="${tableVo.ftlDescription}-通过id查询", notes="${tableVo.ftlDescription}-通过id查询")
+	@GetMapping(value = "/queryById")
+	public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
+		${entityName} ${entityName?uncap_first} = ${entityName?uncap_first}Service.getById(id);
+		return Result.OK(${entityName?uncap_first});
+	}
+
+	/**
+     * 导出excel
+     *
+     * @param request
+     * @param ${entityName?uncap_first}
+     */
+    @RequestMapping(value = "/exportXls")
+    public ModelAndView exportXls(HttpServletRequest request, ${entityName} ${entityName?uncap_first}) {
+        return super.exportXls(request, ${entityName?uncap_first}, ${entityName}.class, "${tableVo.ftlDescription}");
+    }
+
+    /**
+     * 通过excel导入数据
+     *
+     * @param request
+     * @param response
+     * @return
+     */
+    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
+    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
+        return super.importExcel(request, response, ${entityName}.class);
+    }
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/entity/${entityPackage}/${entityName}.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/entity/${entityPackage}/${entityName}.javai
new file mode 100644
index 0000000..faf00a8
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/entity/${entityPackage}/${entityName}.javai
@@ -0,0 +1,49 @@
+package ${bussiPackage}.entity.${entityPackage};
+
+import java.io.Serializable;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import org.springframework.format.annotation.DateTimeFormat;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * @Description: ${tableVo.ftlDescription}
+ * @Author: jeecg-boot
+ * @Date:   ${.now?string["yyyy-MM-dd"]}
+ * @Version: V1.0
+ */
+@Data
+@TableName("${tableName}")
+@ApiModel(value="${tableName}对象", description="${tableVo.ftlDescription}")
+public class ${entityName} implements Serializable {
+    private static final long serialVersionUID = 1L;
+    
+    <#list originalColumns as po>
+	/**${po.filedComment}*/
+	<#if po.fieldName == primaryKeyField>
+	@TableId(type = IdType.ASSIGN_ID)
+	<#else>
+    <#if po.fieldType =='java.util.Date'>
+      <#if po.fieldDbType =='date'>
+    @Excel(name = "${po.filedComment}", width = 15, format = "yyyy-MM-dd")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
+    @DateTimeFormat(pattern="yyyy-MM-dd")
+      <#elseif po.fieldDbType =='datetime'>
+    @Excel(name = "${po.filedComment}", width = 20, format = "yyyy-MM-dd HH:mm:ss")
+    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+      </#if>
+    <#else>
+    @Excel(name = "${po.filedComment}", width = 15)
+    </#if>
+  </#if>
+	@ApiModelProperty(value = "${po.filedComment}")
+	private <#if po.fieldType=='java.sql.Blob'>byte[]<#else>${po.fieldType}</#if> ${po.fieldName};
+	</#list>
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/${entityName}Mapper.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/${entityName}Mapper.javai
new file mode 100644
index 0000000..4705b6c
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/${entityName}Mapper.javai
@@ -0,0 +1,17 @@
+package ${bussiPackage}.mapper.${entityPackage};
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+import ${bussiPackage}.entity.${entityPackage}.${entityName};
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+/**
+ * @Description: ${tableVo.ftlDescription}
+ * @Author: jeecg-boot
+ * @Date:   ${.now?string["yyyy-MM-dd"]}
+ * @Version: V1.0
+ */
+public interface ${entityName}Mapper extends BaseMapper<${entityName}> {
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml
new file mode 100644
index 0000000..fb6f712
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="${bussiPackage}.mapper.${entityPackage}.${entityName}Mapper">
+
+</mapper>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/I${entityName}Service.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/I${entityName}Service.javai
new file mode 100644
index 0000000..8fdad41
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/I${entityName}Service.javai
@@ -0,0 +1,14 @@
+package ${bussiPackage}.service.${entityPackage};
+
+import ${bussiPackage}.entity.${entityPackage}.${entityName};
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * @Description: ${tableVo.ftlDescription}
+ * @Author: jeecg-boot
+ * @Date:   ${.now?string["yyyy-MM-dd"]}
+ * @Version: V1.0
+ */
+public interface I${entityName}Service extends IService<${entityName}> {
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai
new file mode 100644
index 0000000..4b09157
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai
@@ -0,0 +1,19 @@
+package ${bussiPackage}.service.${entityPackage}.impl;
+
+import ${bussiPackage}.entity.${entityPackage}.${entityName};
+import ${bussiPackage}.mapper.${entityPackage}.${entityName}Mapper;
+import ${bussiPackage}.service.${entityPackage}.I${entityName}Service;
+import org.springframework.stereotype.Service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+/**
+ * @Description: ${tableVo.ftlDescription}
+ * @Author: jeecg-boot
+ * @Date:   ${.now?string["yyyy-MM-dd"]}
+ * @Version: V1.0
+ */
+@Service
+public class ${entityName}ServiceImpl extends ServiceImpl<${entityName}Mapper, ${entityName}> implements I${entityName}Service {
+
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/${entityName}List.vuei
new file mode 100644
index 0000000..106943b
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/${entityName}List.vuei
@@ -0,0 +1,173 @@
+<template>
+  <a-card :bordered="false">
+
+    <!-- 查询区域 -->
+    <div class="table-page-search-wrapper">
+      <a-form layout="inline" @keyup.enter.native="searchQuery">
+        <a-row :gutter="24">
+
+<#list columns as po>
+<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum>
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-form-item label="${po.filedComment}">
+              <a-input placeholder="请输入${po.filedComment}" v-model="queryParam.${po.fieldName}"></a-input>
+            </a-form-item>
+          </a-col>
+<#elseif po_index == 2>
+        <template v-if="toggleSearchStatus">
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-form-item label="${po.filedComment}">
+              <a-input placeholder="请输入${po.filedComment}" v-model="queryParam.${po.fieldName}"></a-input>
+            </a-form-item>
+          </a-col>
+<#elseif po.fieldName !='id' && po_index< 5>
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <a-form-item label="${po.filedComment}">
+              <a-input placeholder="请输入${po.filedComment}" v-model="queryParam.${po.fieldName}"></a-input>
+            </a-form-item>
+          </a-col>
+<#else>
+</#if>
+</#list>
+        <#if (columns?size>1) >
+          </template>
+        </#if>
+          <a-col :xl="6" :lg="7" :md="8" :sm="24">
+            <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
+              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
+              <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
+              <a @click="handleToggleSearch" style="margin-left: 8px">
+                {{ toggleSearchStatus ? '收起' : '展开' }}
+                <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
+              </a>
+            </span>
+          </a-col>
+
+        </a-row>
+      </a-form>
+    </div>
+
+    <!-- 操作按钮区域 -->
+    <div class="table-operator">
+      <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
+      <a-button type="primary" icon="download" @click="handleExportXls('${tableVo.ftlDescription}')">导出</a-button>
+      <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
+        <a-button type="primary" icon="import">导入</a-button>
+      </a-upload>
+      <a-dropdown v-if="selectedRowKeys.length > 0">
+        <a-menu slot="overlay">
+          <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item>
+        </a-menu>
+        <a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button>
+      </a-dropdown>
+    </div>
+
+    <!-- table区域-begin -->
+    <div>
+      <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
+        <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项
+        <a style="margin-left: 24px" @click="onClearSelected">清空</a>
+      </div>
+
+      <a-table
+        ref="table"
+        size="middle"
+        bordered
+        rowKey="id"
+        :columns="columns"
+        :dataSource="dataSource"
+        :pagination="ipagination"
+        :loading="loading"
+        class="j-table-force-nowrap"
+        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
+        @change="handleTableChange">
+
+        <span slot="action" slot-scope="text, record">
+          <a @click="handleEdit(record)">编辑</a>
+
+          <a-divider type="vertical" />
+          <a-dropdown>
+            <a class="ant-dropdown-link">更多 <a-icon type="down" /></a>
+            <a-menu slot="overlay">
+              <a-menu-item>
+                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
+                  <a>删除</a>
+                </a-popconfirm>
+              </a-menu-item>
+            </a-menu>
+          </a-dropdown>
+        </span>
+
+      </a-table>
+    </div>
+    <!-- table区域-end -->
+
+    <!-- 表单区域 -->
+    <${entityName?uncap_first}-modal ref="modalForm" @ok="modalFormOk"></${entityName?uncap_first}-modal>
+  </a-card>
+</template>
+
+<script>
+  import '@/assets/less/TableExpand.less'
+  import ${entityName}Modal from './modules/${entityName}Modal'
+  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
+
+  export default {
+    name: "${entityName}List",
+    mixins:[JeecgListMixin],
+    components: {
+      ${entityName}Modal
+    },
+    data () {
+      return {
+        description: '${tableVo.ftlDescription}管理页面',
+        // 表头
+        columns: [
+          {
+            title: '#',
+            dataIndex: '',
+            key:'rowIndex',
+            width:60,
+            align:"center",
+            customRender:function (t,r,index) {
+              return parseInt(index)+1;
+            }
+           },
+          <#list columns as po>
+           <#if po.fieldName !='id'>
+		   {
+            title: '${po.filedComment}',
+            align:"center",
+            dataIndex: '${po.fieldName}'
+           },
+		   </#if>
+		  </#list>
+          {
+            title: '操作',
+            dataIndex: 'action',
+            align:"center",
+            scopedSlots: { customRender: 'action' },
+          }
+        ],
+		url: {
+          list: "/${entityPackage}/${entityName?uncap_first}/list",
+          delete: "/${entityPackage}/${entityName?uncap_first}/delete",
+          deleteBatch: "/${entityPackage}/${entityName?uncap_first}/deleteBatch",
+          exportXlsUrl: "${entityPackage}/${entityName?uncap_first}/exportXls",
+          importExcelUrl: "${entityPackage}/${entityName?uncap_first}/importExcel",
+       },
+    }
+  },
+  computed: {
+    importExcelUrl: function(){
+      <#noparse>return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;</#noparse>
+    }
+  },
+    methods: {
+
+    }
+  }
+</script>
+<style scoped>
+  @import '~@assets/less/common.less';
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei
new file mode 100644
index 0000000..ff934f1
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei
@@ -0,0 +1,156 @@
+<template>
+  <j-modal
+    :title="title"
+    :width="800"
+    :visible="visible"
+    :confirmLoading="confirmLoading"
+    switchFullscreen
+    @ok="handleOk"
+    @cancel="handleCancel"
+    cancelText="关闭">
+
+    <a-spin :spinning="confirmLoading">
+      <a-form :form="form">
+
+<#list columns as po><#rt/>
+<#if po.fieldName !='id'><#rt/>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="${po.filedComment}">
+          <#if po.fieldType =='date'>
+          <a-date-picker v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
+          <#elseif po.fieldType =='datetime'>
+          <a-date-picker showTime format='YYYY-MM-DD HH:mm:ss' v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
+          <#elseif "int,decimal,double,"?contains(po.fieldType)>
+          <a-input-number v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
+          <#else>
+          <a-input placeholder="请输入${po.filedComment}" v-decorator="['${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
+          </#if>
+        </a-form-item>
+</#if>
+</#list>
+
+      </a-form>
+    </a-spin>
+  </j-modal>
+</template>
+
+<script>
+  import { httpAction } from '@/api/manage'
+  import pick from 'lodash.pick'
+  import moment from "moment"
+
+  export default {
+    name: "${entityName}Modal",
+    data () {
+      return {
+        title:"操作",
+        visible: false,
+        model: {},
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 5 },
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 16 },
+        },
+
+        confirmLoading: false,
+        form: this.$form.createForm(this),
+        validatorRules:{
+        <#list columns as po>
+        <#if po.fieldName !='id'>
+        <#if po.nullable =='N'>
+        ${po.fieldName}:{rules: [{ required: true, message: '请输入${po.filedComment}!' }]},
+        </#if>
+        </#if>
+	    </#list>
+        },
+        url: {
+          add: "/${entityPackage}/${entityName?uncap_first}/add",
+          edit: "/${entityPackage}/${entityName?uncap_first}/edit",
+        },
+      }
+    },
+    created () {
+    },
+    methods: {
+      add () {
+        this.edit({});
+      },
+      edit (record) {
+        this.form.resetFields();
+        this.model = Object.assign({}, record);
+        this.visible = true;
+        this.$nextTick(() => {
+          this.form.setFieldsValue(pick(this.model<#list columns as po><#if po.fieldName !='id' && po.fieldType?index_of("date")==-1>,'${po.fieldName}'</#if></#list>))
+		  //时间格式化
+          <#list columns as po>
+          <#if po.fieldName !='id' && po.fieldType?index_of("date")!=-1>
+          this.form.setFieldsValue({${po.fieldName}:this.model.${po.fieldName}?moment(this.model.${po.fieldName}):null})
+          </#if>
+          </#list>
+        });
+
+      },
+      close () {
+        this.$emit('close');
+        this.visible = false;
+      },
+      handleOk () {
+        const that = this;
+        // 触发表单验证
+        this.form.validateFields((err, values) => {
+          if (!err) {
+            that.confirmLoading = true;
+            let httpurl = '';
+            let method = '';
+            if(!this.model.id){
+              httpurl+=this.url.add;
+              method = 'post';
+            }else{
+              httpurl+=this.url.edit;
+               method = 'put';
+            }
+            let formData = Object.assign(this.model, values);
+            //时间格式化
+            <#list columns as po>
+            <#if po.fieldName !='id' && po.fieldType =='date'>
+            formData.${po.fieldName} = formData.${po.fieldName}?formData.${po.fieldName}.format():null;
+            <#elseif po.fieldName !='id' && po.fieldType =='datetime'>
+            formData.${po.fieldName} = formData.${po.fieldName}?formData.${po.fieldName}.format('YYYY-MM-DD HH:mm:ss'):null;
+            </#if>
+            </#list>
+
+            console.log(formData)
+            httpAction(httpurl,formData,method).then((res)=>{
+              if(res.success){
+                that.$message.success(res.message);
+                that.$emit('ok');
+              }else{
+                that.$message.warning(res.message);
+              }
+            }).finally(() => {
+              that.confirmLoading = false;
+              that.close();
+            })
+
+
+
+          }
+        })
+      },
+      handleCancel () {
+        this.close()
+      },
+
+
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei
new file mode 100644
index 0000000..4446ba6
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei
@@ -0,0 +1,162 @@
+<template>
+  <a-drawer
+      :title="title"
+      :width="800"
+      placement="right"
+      :closable="false"
+      @close="close"
+      :visible="visible"
+  >
+
+    <a-spin :spinning="confirmLoading">
+      <a-form :form="form">
+      
+<#list columns as po><#rt/>
+<#if po.fieldName !='id'><#rt/>
+        <a-form-item
+          :labelCol="labelCol"
+          :wrapperCol="wrapperCol"
+          label="${po.filedComment}">
+          <#if po.fieldType =='date'>
+          <a-date-picker v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
+          <#elseif po.fieldType =='datetime'>
+          <a-date-picker showTime format='YYYY-MM-DD HH:mm:ss' v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
+          <#elseif "int,decimal,double,"?contains(po.fieldType)>
+          <a-input-number v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
+          <#else>
+          <a-input placeholder="请输入${po.filedComment}" v-decorator="['${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
+          </#if>
+        </a-form-item>
+</#if>
+</#list>
+		
+      </a-form>
+    </a-spin>
+    <a-button type="primary" @click="handleOk">确定</a-button>
+    <a-button type="primary" @click="handleCancel">取消</a-button>
+  </a-drawer>
+</template>
+
+<script>
+  import { httpAction } from '@/api/manage'
+  import pick from 'lodash.pick'
+  import moment from "moment"
+
+  export default {
+    name: "${entityName}Modal",
+    data () {
+      return {
+        title:"操作",
+        visible: false,
+        model: {},
+        labelCol: {
+          xs: { span: 24 },
+          sm: { span: 5 },
+        },
+        wrapperCol: {
+          xs: { span: 24 },
+          sm: { span: 16 },
+        },
+
+        confirmLoading: false,
+        form: this.$form.createForm(this),
+        validatorRules:{
+        <#list columns as po>
+        <#if po.fieldName !='id'>
+        <#if po.nullable =='N'>
+        ${po.fieldName}:{rules: [{ required: true, message: '请输入${po.filedComment}!' }]},
+        </#if>
+        </#if>
+	    </#list>
+        },
+        url: {
+          add: "/${entityPackage}/${entityName?uncap_first}/add",
+          edit: "/${entityPackage}/${entityName?uncap_first}/edit",
+        },
+      }
+    },
+    created () {
+    },
+    methods: {
+      add () {
+        this.edit({});
+      },
+      edit (record) {
+        this.form.resetFields();
+        this.model = Object.assign({}, record);
+        this.visible = true;
+        this.$nextTick(() => {
+          this.form.setFieldsValue(pick(this.model<#list columns as po><#if po.fieldName !='id' && po.fieldType?index_of("date")==-1>,'${po.fieldName}'</#if></#list>))
+		  //时间格式化
+          <#list columns as po>
+          <#if po.fieldName !='id' && po.fieldType?index_of("date")!=-1>
+          this.form.setFieldsValue({${po.fieldName}:this.model.${po.fieldName}?moment(this.model.${po.fieldName}):null})
+          </#if>
+          </#list>
+        });
+
+      },
+      close () {
+        this.$emit('close');
+        this.visible = false;
+      },
+      handleOk () {
+        const that = this;
+        // 触发表单验证
+        this.form.validateFields((err, values) => {
+          if (!err) {
+            that.confirmLoading = true;
+            let httpurl = '';
+            let method = '';
+            if(!this.model.id){
+              httpurl+=this.url.add;
+              method = 'post';
+            }else{
+              httpurl+=this.url.edit;
+               method = 'put';
+            }
+            let formData = Object.assign(this.model, values);
+            //时间格式化
+            <#list columns as po>
+            <#if po.fieldName !='id' && po.fieldType =='date'>
+            formData.${po.fieldName} = formData.${po.fieldName}?formData.${po.fieldName}.format():null;
+            <#elseif po.fieldName !='id' && po.fieldType =='datetime'>
+            formData.${po.fieldName} = formData.${po.fieldName}?formData.${po.fieldName}.format('YYYY-MM-DD HH:mm:ss'):null;
+            </#if>
+            </#list>
+            
+            console.log(formData)
+            httpAction(httpurl,formData,method).then((res)=>{
+              if(res.success){
+                that.$message.success(res.message);
+                that.$emit('ok');
+              }else{
+                that.$message.warning(res.message);
+              }
+            }).finally(() => {
+              that.confirmLoading = false;
+              that.close();
+            })
+
+
+
+          }
+        })
+      },
+      handleCancel () {
+        this.close()
+      },
+
+
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+/** Button按钮间距 */
+  .ant-btn {
+    margin-left: 30px;
+    margin-bottom: 30px;
+    float: right;
+  }
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..298e5b9
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,153 @@
+<template>
+  <div>
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--插槽:table标题-->
+          <template #tableTitle>
+             <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+             <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+             <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+             <a-dropdown v-if="checkedKeys.length > 0">
+                 <template #overlay>
+                    <a-menu>
+                      <a-menu-item key="1" @click="batchHandleDelete">
+                        <Icon icon="ant-design:delete-outlined"></Icon>
+                        删除
+                      </a-menu-item>
+                    </a-menu>
+                  </template>
+                  <a-button>批量操作
+                    <Icon icon="mdi:chevron-down"></Icon>
+                  </a-button>
+            </a-dropdown>
+          </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+    </BasicTable>
+
+    <!-- 表单区域 -->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
+  </div>
+</template>
+
+<script lang="ts" name="${entityPackage}-${entityName?uncap_first}" setup>
+  import {ref, computed, unref} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import {useModal} from '/@/components/Modal';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import ${entityName}Modal from './modules/${entityName}Modal.vue'
+  import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
+
+  const checkedKeys = ref<Array<string | number>>([]);
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+  //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+       tableProps:{
+            title: '${tableVo.ftlDescription}',
+            api: list,
+            columns,
+            canResize:false,
+            formConfig: {
+               labelWidth: 120,
+               schemas: searchFormSchema,
+               autoSubmitOnEnter:true,
+               showAdvancedButton:true,
+             },
+            actionColumn: {
+                width: 120,
+             },
+        },
+        exportConfig: {
+             name:"${tableVo.ftlDescription}",
+             url: getExportUrl,
+           },
+           importConfig: {
+             url: getImportUrl
+           },
+   })
+
+   const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+   /**
+    * 新增事件
+    */
+   function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+   }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+   async function handleDelete(record) {
+     await deleteOne({id: record.id}, reload);
+   }
+   /**
+    * 批量删除事件
+    */
+   async function batchHandleDelete() {
+     await batchDelete({ids: checkedKeys.value}, reload);
+   }
+   /**
+    * 成功回调
+    */
+   function handleSuccess({isUpdate, values}) {
+      reload();
+   }
+   /**
+      * 操作栏
+      */
+   function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+     }
+     /**
+       * 下拉操作栏
+       */
+    function getDropDownAction(record){
+      return [
+           {
+             label: '详情',
+             onClick: handleDetail.bind(null, record),
+           }, {
+             label: '删除',
+             popConfirm: {
+               title: '是否确认删除',
+               confirm: handleDelete.bind(null, record),
+             }
+           }
+      ]
+    }
+</script>
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..c579f91
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,61 @@
+import {defHttp} from '/@/utils/http/axios';
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/list',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..8034d5b
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,56 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    dataIndex: '${po.fieldName}'
+   },
+   </#if>
+ </#list>
+];
+
+export const searchFormSchema: FormSchema[] = [
+<#list columns as po>
+<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum>
+ {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+     <#if po.fieldType =='date'>
+    component: 'DatePicker'
+     <#elseif po.fieldType =='datetime'>
+    component: 'TimePicker'
+     <#elseif "int,decimal,double,"?contains(po.fieldType)>
+    component: 'InputNumber'
+     <#else>
+    component: 'Input'
+    </#if>
+  },
+</#if>
+</#list>
+];
+
+export const formSchema: FormSchema[] = [
+<#list columns as po><#rt/>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+     <#if po.fieldType =='date'>
+    component: 'DatePicker'
+     <#elseif po.fieldType =='datetime'>
+    component: 'TimePicker'
+     <#elseif "int,decimal,double,"?contains(po.fieldType)>
+    component: 'InputNumber'
+     <#else>
+    component: 'Input'
+    </#if>
+    <#if po.fieldName =='id'><#rt/>
+    show:false
+    </#if>
+  },
+</#list>
+];
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
new file mode 100644
index 0000000..a6cdaec
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
@@ -0,0 +1,56 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="40%">
+         <BasicForm @register="registerForm"/>
+     </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {formSchema} from '../${entityName?uncap_first}.data';
+    import {saveOrUpdate} from '../${entityName?uncap_first}.api';
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    //表单配置
+    const [registerForm, {resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+    });
+    //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await resetFields();
+        setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+        }
+    });
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+    //表单提交事件
+    async function handleSubmit(v) {
+        try {
+            let values = await validate();
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/controller/${entityPackage}/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/controller/${entityPackage}/${entityName}Controller.javai
deleted file mode 100644
index 87d5ed8..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/controller/${entityPackage}/${entityName}Controller.javai
+++ /dev/null
@@ -1,170 +0,0 @@
-package ${bussiPackage}.controller.${entityPackage};
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.jeecg.common.api.vo.Result;
-import org.jeecg.common.system.query.QueryGenerator;
-import org.jeecg.common.util.oConvertUtils;
-import ${bussiPackage}.entity.${entityPackage}.${entityName};
-import ${bussiPackage}.service.${entityPackage}.I${entityName}Service;
-import org.jeecg.common.system.base.controller.JeecgController;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
-import org.springframework.web.multipart.MultipartFile;
-import org.springframework.web.multipart.MultipartHttpServletRequest;
-import org.springframework.web.servlet.ModelAndView;
-
-import org.jeecgframework.poi.excel.ExcelImportUtil;
-import org.jeecgframework.poi.excel.def.NormalExcelConstants;
-import org.jeecgframework.poi.excel.entity.ExportParams;
-import org.jeecgframework.poi.excel.entity.ImportParams;
-import org.jeecgframework.poi.excel.view.JeecgEntityExcelView;
-
-import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
-import com.baomidou.mybatisplus.core.metadata.IPage;
-import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-
-import lombok.extern.slf4j.Slf4j;
-
-import com.alibaba.fastjson.JSON;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import org.jeecg.common.aspect.annotation.AutoLog;
-
- /**
- * @Description: ${tableVo.ftlDescription}
- * @Author: jeecg-boot
- * @Date:   ${.now?string["yyyy-MM-dd"]}
- * @Version: V1.0
- */
-@Api(tags="${tableVo.ftlDescription}")
-@RestController
-@RequestMapping("/${entityPackage}/${entityName?uncap_first}")
-@Slf4j
-public class ${entityName}Controller extends JeecgController<${entityName}, I${entityName}Service> {
-	@Autowired
-	private I${entityName}Service ${entityName?uncap_first}Service;
-	
-	/**
-	 * 分页列表查询
-	 *
-	 * @param ${entityName?uncap_first}
-	 * @param pageNo
-	 * @param pageSize
-	 * @param req
-	 * @return
-	 */
-	@AutoLog(value = "${tableVo.ftlDescription}-分页列表查询")
-	@ApiOperation(value="${tableVo.ftlDescription}-分页列表查询", notes="${tableVo.ftlDescription}-分页列表查询")
-	@GetMapping(value = "/list")
-	public Result<?> queryPageList(${entityName} ${entityName?uncap_first},
-								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
-							       @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
-								   HttpServletRequest req) {
-		QueryWrapper<${entityName}> queryWrapper = QueryGenerator.initQueryWrapper(${entityName?uncap_first}, req.getParameterMap());
-		Page<${entityName}> page = new Page<${entityName}>(pageNo, pageSize);
-		IPage<${entityName}> pageList = ${entityName?uncap_first}Service.page(page, queryWrapper);
-		return Result.OK(pageList);
-
-	}
-	
-	/**
-	 *   添加
-	 * @param ${entityName?uncap_first}
-	 * @return
-	 */
-	@AutoLog(value = "${tableVo.ftlDescription}-添加")
-	@ApiOperation(value="${tableVo.ftlDescription}-添加", notes="${tableVo.ftlDescription}-添加")
-	@PostMapping(value = "/add")
-	public Result<?> add(@RequestBody ${entityName} ${entityName?uncap_first}) {
-		${entityName?uncap_first}Service.save(${entityName?uncap_first});
-		return Result.OK("添加成功!");
-	}
-	
-	/**
-	 *  编辑
-	 *
-	 * @param ${entityName?uncap_first}
-	 * @return
-	 */
-	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
-	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
-	@PutMapping(value = "/edit")
-	public Result<?> edit(@RequestBody ${entityName} ${entityName?uncap_first}) {
-		${entityName?uncap_first}Service.updateById(${entityName?uncap_first});
-		return Result.OK("编辑成功!");
-	}
-	
-	/**
-	 *  通过id删除
-	 * @param id
-	 * @return
-	 */
-	@AutoLog(value = "${tableVo.ftlDescription}-通过id删除")
-	@ApiOperation(value="${tableVo.ftlDescription}-通过id删除", notes="${tableVo.ftlDescription}-通过id删除")
-	@DeleteMapping(value = "/delete")
-	public Result<?> delete(@RequestParam(name="id",required=true) String id) {
-		${entityName?uncap_first}Service.removeById(id);
-		return Result.OK("删除成功!");
-	}
-	
-	/**
-	 *  批量删除
-	 *
-	 * @param ids
-	 * @return
-	 */
-	@AutoLog(value = "${tableVo.ftlDescription}-批量删除")
-	@ApiOperation(value="${tableVo.ftlDescription}-批量删除", notes="${tableVo.ftlDescription}-批量删除")
-	@DeleteMapping(value = "/deleteBatch")
-	public Result<?> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
-		this.${entityName?uncap_first}Service.removeByIds(Arrays.asList(ids.split(",")));
-		return Result.OK("批量删除成功!");
-	}
-	
-	/**
-	 * 通过id查询
-     *
-	 * @param id
-	 * @return
-	 */
-	@AutoLog(value = "${tableVo.ftlDescription}-通过id查询")
-	@ApiOperation(value="${tableVo.ftlDescription}-通过id查询", notes="${tableVo.ftlDescription}-通过id查询")
-	@GetMapping(value = "/queryById")
-	public Result<?> queryById(@RequestParam(name="id",required=true) String id) {
-		${entityName} ${entityName?uncap_first} = ${entityName?uncap_first}Service.getById(id);
-		return Result.OK(${entityName?uncap_first});
-	}
-
-	/**
-     * 导出excel
-     *
-     * @param request
-     * @param ${entityName?uncap_first}
-     */
-    @RequestMapping(value = "/exportXls")
-    public ModelAndView exportXls(HttpServletRequest request, ${entityName} ${entityName?uncap_first}) {
-        return super.exportXls(request, ${entityName?uncap_first}, ${entityName}.class, "${tableVo.ftlDescription}");
-    }
-
-    /**
-     * 通过excel导入数据
-     *
-     * @param request
-     * @param response
-     * @return
-     */
-    @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
-    public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
-        return super.importExcel(request, response, ${entityName}.class);
-    }
-
-}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/entity/${entityPackage}/${entityName}.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/entity/${entityPackage}/${entityName}.javai
deleted file mode 100644
index faf00a8..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/entity/${entityPackage}/${entityName}.javai
+++ /dev/null
@@ -1,49 +0,0 @@
-package ${bussiPackage}.entity.${entityPackage};
-
-import java.io.Serializable;
-import com.baomidou.mybatisplus.annotation.IdType;
-import com.baomidou.mybatisplus.annotation.TableId;
-import com.baomidou.mybatisplus.annotation.TableName;
-import lombok.Data;
-import java.util.Date;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import org.springframework.format.annotation.DateTimeFormat;
-import org.jeecgframework.poi.excel.annotation.Excel;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-
-/**
- * @Description: ${tableVo.ftlDescription}
- * @Author: jeecg-boot
- * @Date:   ${.now?string["yyyy-MM-dd"]}
- * @Version: V1.0
- */
-@Data
-@TableName("${tableName}")
-@ApiModel(value="${tableName}对象", description="${tableVo.ftlDescription}")
-public class ${entityName} implements Serializable {
-    private static final long serialVersionUID = 1L;
-    
-    <#list originalColumns as po>
-	/**${po.filedComment}*/
-	<#if po.fieldName == primaryKeyField>
-	@TableId(type = IdType.ASSIGN_ID)
-	<#else>
-    <#if po.fieldType =='java.util.Date'>
-      <#if po.fieldDbType =='date'>
-    @Excel(name = "${po.filedComment}", width = 15, format = "yyyy-MM-dd")
-    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd")
-    @DateTimeFormat(pattern="yyyy-MM-dd")
-      <#elseif po.fieldDbType =='datetime'>
-    @Excel(name = "${po.filedComment}", width = 20, format = "yyyy-MM-dd HH:mm:ss")
-    @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
-      </#if>
-    <#else>
-    @Excel(name = "${po.filedComment}", width = 15)
-    </#if>
-  </#if>
-	@ApiModelProperty(value = "${po.filedComment}")
-	private <#if po.fieldType=='java.sql.Blob'>byte[]<#else>${po.fieldType}</#if> ${po.fieldName};
-	</#list>
-}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/${entityName}Mapper.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/${entityName}Mapper.javai
deleted file mode 100644
index 4705b6c..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/${entityName}Mapper.javai
+++ /dev/null
@@ -1,17 +0,0 @@
-package ${bussiPackage}.mapper.${entityPackage};
-
-import java.util.List;
-
-import org.apache.ibatis.annotations.Param;
-import ${bussiPackage}.entity.${entityPackage}.${entityName};
-import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-
-/**
- * @Description: ${tableVo.ftlDescription}
- * @Author: jeecg-boot
- * @Date:   ${.now?string["yyyy-MM-dd"]}
- * @Version: V1.0
- */
-public interface ${entityName}Mapper extends BaseMapper<${entityName}> {
-
-}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml
deleted file mode 100644
index fb6f712..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/mapper/${entityPackage}/xml/${entityName}Mapper.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="${bussiPackage}.mapper.${entityPackage}.${entityName}Mapper">
-
-</mapper>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/I${entityName}Service.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/I${entityName}Service.javai
deleted file mode 100644
index 8fdad41..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/I${entityName}Service.javai
+++ /dev/null
@@ -1,14 +0,0 @@
-package ${bussiPackage}.service.${entityPackage};
-
-import ${bussiPackage}.entity.${entityPackage}.${entityName};
-import com.baomidou.mybatisplus.extension.service.IService;
-
-/**
- * @Description: ${tableVo.ftlDescription}
- * @Author: jeecg-boot
- * @Date:   ${.now?string["yyyy-MM-dd"]}
- * @Version: V1.0
- */
-public interface I${entityName}Service extends IService<${entityName}> {
-
-}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai
deleted file mode 100644
index 4b09157..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/service/${entityPackage}/impl/${entityName}ServiceImpl.javai
+++ /dev/null
@@ -1,19 +0,0 @@
-package ${bussiPackage}.service.${entityPackage}.impl;
-
-import ${bussiPackage}.entity.${entityPackage}.${entityName};
-import ${bussiPackage}.mapper.${entityPackage}.${entityName}Mapper;
-import ${bussiPackage}.service.${entityPackage}.I${entityName}Service;
-import org.springframework.stereotype.Service;
-
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-
-/**
- * @Description: ${tableVo.ftlDescription}
- * @Author: jeecg-boot
- * @Date:   ${.now?string["yyyy-MM-dd"]}
- * @Version: V1.0
- */
-@Service
-public class ${entityName}ServiceImpl extends ServiceImpl<${entityName}Mapper, ${entityName}> implements I${entityName}Service {
-
-}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/${entityName}List.vuei
deleted file mode 100644
index 106943b..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/${entityName}List.vuei
+++ /dev/null
@@ -1,173 +0,0 @@
-<template>
-  <a-card :bordered="false">
-
-    <!-- 查询区域 -->
-    <div class="table-page-search-wrapper">
-      <a-form layout="inline" @keyup.enter.native="searchQuery">
-        <a-row :gutter="24">
-
-<#list columns as po>
-<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum>
-          <a-col :xl="6" :lg="7" :md="8" :sm="24">
-            <a-form-item label="${po.filedComment}">
-              <a-input placeholder="请输入${po.filedComment}" v-model="queryParam.${po.fieldName}"></a-input>
-            </a-form-item>
-          </a-col>
-<#elseif po_index == 2>
-        <template v-if="toggleSearchStatus">
-          <a-col :xl="6" :lg="7" :md="8" :sm="24">
-            <a-form-item label="${po.filedComment}">
-              <a-input placeholder="请输入${po.filedComment}" v-model="queryParam.${po.fieldName}"></a-input>
-            </a-form-item>
-          </a-col>
-<#elseif po.fieldName !='id' && po_index< 5>
-          <a-col :xl="6" :lg="7" :md="8" :sm="24">
-            <a-form-item label="${po.filedComment}">
-              <a-input placeholder="请输入${po.filedComment}" v-model="queryParam.${po.fieldName}"></a-input>
-            </a-form-item>
-          </a-col>
-<#else>
-</#if>
-</#list>
-        <#if (columns?size>1) >
-          </template>
-        </#if>
-          <a-col :xl="6" :lg="7" :md="8" :sm="24">
-            <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
-              <a-button type="primary" @click="searchQuery" icon="search">查询</a-button>
-              <a-button type="primary" @click="searchReset" icon="reload" style="margin-left: 8px">重置</a-button>
-              <a @click="handleToggleSearch" style="margin-left: 8px">
-                {{ toggleSearchStatus ? '收起' : '展开' }}
-                <a-icon :type="toggleSearchStatus ? 'up' : 'down'"/>
-              </a>
-            </span>
-          </a-col>
-
-        </a-row>
-      </a-form>
-    </div>
-
-    <!-- 操作按钮区域 -->
-    <div class="table-operator">
-      <a-button @click="handleAdd" type="primary" icon="plus">新增</a-button>
-      <a-button type="primary" icon="download" @click="handleExportXls('${tableVo.ftlDescription}')">导出</a-button>
-      <a-upload name="file" :showUploadList="false" :multiple="false" :headers="tokenHeader" :action="importExcelUrl" @change="handleImportExcel">
-        <a-button type="primary" icon="import">导入</a-button>
-      </a-upload>
-      <a-dropdown v-if="selectedRowKeys.length > 0">
-        <a-menu slot="overlay">
-          <a-menu-item key="1" @click="batchDel"><a-icon type="delete"/>删除</a-menu-item>
-        </a-menu>
-        <a-button style="margin-left: 8px"> 批量操作 <a-icon type="down" /></a-button>
-      </a-dropdown>
-    </div>
-
-    <!-- table区域-begin -->
-    <div>
-      <div class="ant-alert ant-alert-info" style="margin-bottom: 16px;">
-        <i class="anticon anticon-info-circle ant-alert-icon"></i> 已选择 <a style="font-weight: 600">{{ selectedRowKeys.length }}</a>项
-        <a style="margin-left: 24px" @click="onClearSelected">清空</a>
-      </div>
-
-      <a-table
-        ref="table"
-        size="middle"
-        bordered
-        rowKey="id"
-        :columns="columns"
-        :dataSource="dataSource"
-        :pagination="ipagination"
-        :loading="loading"
-        class="j-table-force-nowrap"
-        :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
-        @change="handleTableChange">
-
-        <span slot="action" slot-scope="text, record">
-          <a @click="handleEdit(record)">编辑</a>
-
-          <a-divider type="vertical" />
-          <a-dropdown>
-            <a class="ant-dropdown-link">更多 <a-icon type="down" /></a>
-            <a-menu slot="overlay">
-              <a-menu-item>
-                <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
-                  <a>删除</a>
-                </a-popconfirm>
-              </a-menu-item>
-            </a-menu>
-          </a-dropdown>
-        </span>
-
-      </a-table>
-    </div>
-    <!-- table区域-end -->
-
-    <!-- 表单区域 -->
-    <${entityName?uncap_first}-modal ref="modalForm" @ok="modalFormOk"></${entityName?uncap_first}-modal>
-  </a-card>
-</template>
-
-<script>
-  import '@/assets/less/TableExpand.less'
-  import ${entityName}Modal from './modules/${entityName}Modal'
-  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
-
-  export default {
-    name: "${entityName}List",
-    mixins:[JeecgListMixin],
-    components: {
-      ${entityName}Modal
-    },
-    data () {
-      return {
-        description: '${tableVo.ftlDescription}管理页面',
-        // 表头
-        columns: [
-          {
-            title: '#',
-            dataIndex: '',
-            key:'rowIndex',
-            width:60,
-            align:"center",
-            customRender:function (t,r,index) {
-              return parseInt(index)+1;
-            }
-           },
-          <#list columns as po>
-           <#if po.fieldName !='id'>
-		   {
-            title: '${po.filedComment}',
-            align:"center",
-            dataIndex: '${po.fieldName}'
-           },
-		   </#if>
-		  </#list>
-          {
-            title: '操作',
-            dataIndex: 'action',
-            align:"center",
-            scopedSlots: { customRender: 'action' },
-          }
-        ],
-		url: {
-          list: "/${entityPackage}/${entityName?uncap_first}/list",
-          delete: "/${entityPackage}/${entityName?uncap_first}/delete",
-          deleteBatch: "/${entityPackage}/${entityName?uncap_first}/deleteBatch",
-          exportXlsUrl: "${entityPackage}/${entityName?uncap_first}/exportXls",
-          importExcelUrl: "${entityPackage}/${entityName?uncap_first}/importExcel",
-       },
-    }
-  },
-  computed: {
-    importExcelUrl: function(){
-      <#noparse>return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;</#noparse>
-    }
-  },
-    methods: {
-
-    }
-  }
-</script>
-<style scoped>
-  @import '~@assets/less/common.less';
-</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei
deleted file mode 100644
index ff934f1..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal.vuei
+++ /dev/null
@@ -1,156 +0,0 @@
-<template>
-  <j-modal
-    :title="title"
-    :width="800"
-    :visible="visible"
-    :confirmLoading="confirmLoading"
-    switchFullscreen
-    @ok="handleOk"
-    @cancel="handleCancel"
-    cancelText="关闭">
-
-    <a-spin :spinning="confirmLoading">
-      <a-form :form="form">
-
-<#list columns as po><#rt/>
-<#if po.fieldName !='id'><#rt/>
-        <a-form-item
-          :labelCol="labelCol"
-          :wrapperCol="wrapperCol"
-          label="${po.filedComment}">
-          <#if po.fieldType =='date'>
-          <a-date-picker v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
-          <#elseif po.fieldType =='datetime'>
-          <a-date-picker showTime format='YYYY-MM-DD HH:mm:ss' v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
-          <#elseif "int,decimal,double,"?contains(po.fieldType)>
-          <a-input-number v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
-          <#else>
-          <a-input placeholder="请输入${po.filedComment}" v-decorator="['${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
-          </#if>
-        </a-form-item>
-</#if>
-</#list>
-
-      </a-form>
-    </a-spin>
-  </j-modal>
-</template>
-
-<script>
-  import { httpAction } from '@/api/manage'
-  import pick from 'lodash.pick'
-  import moment from "moment"
-
-  export default {
-    name: "${entityName}Modal",
-    data () {
-      return {
-        title:"操作",
-        visible: false,
-        model: {},
-        labelCol: {
-          xs: { span: 24 },
-          sm: { span: 5 },
-        },
-        wrapperCol: {
-          xs: { span: 24 },
-          sm: { span: 16 },
-        },
-
-        confirmLoading: false,
-        form: this.$form.createForm(this),
-        validatorRules:{
-        <#list columns as po>
-        <#if po.fieldName !='id'>
-        <#if po.nullable =='N'>
-        ${po.fieldName}:{rules: [{ required: true, message: '请输入${po.filedComment}!' }]},
-        </#if>
-        </#if>
-	    </#list>
-        },
-        url: {
-          add: "/${entityPackage}/${entityName?uncap_first}/add",
-          edit: "/${entityPackage}/${entityName?uncap_first}/edit",
-        },
-      }
-    },
-    created () {
-    },
-    methods: {
-      add () {
-        this.edit({});
-      },
-      edit (record) {
-        this.form.resetFields();
-        this.model = Object.assign({}, record);
-        this.visible = true;
-        this.$nextTick(() => {
-          this.form.setFieldsValue(pick(this.model<#list columns as po><#if po.fieldName !='id' && po.fieldType?index_of("date")==-1>,'${po.fieldName}'</#if></#list>))
-		  //时间格式化
-          <#list columns as po>
-          <#if po.fieldName !='id' && po.fieldType?index_of("date")!=-1>
-          this.form.setFieldsValue({${po.fieldName}:this.model.${po.fieldName}?moment(this.model.${po.fieldName}):null})
-          </#if>
-          </#list>
-        });
-
-      },
-      close () {
-        this.$emit('close');
-        this.visible = false;
-      },
-      handleOk () {
-        const that = this;
-        // 触发表单验证
-        this.form.validateFields((err, values) => {
-          if (!err) {
-            that.confirmLoading = true;
-            let httpurl = '';
-            let method = '';
-            if(!this.model.id){
-              httpurl+=this.url.add;
-              method = 'post';
-            }else{
-              httpurl+=this.url.edit;
-               method = 'put';
-            }
-            let formData = Object.assign(this.model, values);
-            //时间格式化
-            <#list columns as po>
-            <#if po.fieldName !='id' && po.fieldType =='date'>
-            formData.${po.fieldName} = formData.${po.fieldName}?formData.${po.fieldName}.format():null;
-            <#elseif po.fieldName !='id' && po.fieldType =='datetime'>
-            formData.${po.fieldName} = formData.${po.fieldName}?formData.${po.fieldName}.format('YYYY-MM-DD HH:mm:ss'):null;
-            </#if>
-            </#list>
-
-            console.log(formData)
-            httpAction(httpurl,formData,method).then((res)=>{
-              if(res.success){
-                that.$message.success(res.message);
-                that.$emit('ok');
-              }else{
-                that.$message.warning(res.message);
-              }
-            }).finally(() => {
-              that.confirmLoading = false;
-              that.close();
-            })
-
-
-
-          }
-        })
-      },
-      handleCancel () {
-        this.close()
-      },
-
-
-    }
-  }
-</script>
-
-<style lang="less" scoped>
-
-</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei
deleted file mode 100644
index 4446ba6..0000000
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/one2/java/${bussiPackage}/vue/${entityPackage}/modules/${entityName}Modal__Style#Drawer.vuei
+++ /dev/null
@@ -1,162 +0,0 @@
-<template>
-  <a-drawer
-      :title="title"
-      :width="800"
-      placement="right"
-      :closable="false"
-      @close="close"
-      :visible="visible"
-  >
-
-    <a-spin :spinning="confirmLoading">
-      <a-form :form="form">
-      
-<#list columns as po><#rt/>
-<#if po.fieldName !='id'><#rt/>
-        <a-form-item
-          :labelCol="labelCol"
-          :wrapperCol="wrapperCol"
-          label="${po.filedComment}">
-          <#if po.fieldType =='date'>
-          <a-date-picker v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
-          <#elseif po.fieldType =='datetime'>
-          <a-date-picker showTime format='YYYY-MM-DD HH:mm:ss' v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
-          <#elseif "int,decimal,double,"?contains(po.fieldType)>
-          <a-input-number v-decorator="[ '${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
-          <#else>
-          <a-input placeholder="请输入${po.filedComment}" v-decorator="['${po.fieldName}', <#if po.nullable =='N'>validatorRules.${po.fieldName} <#else>{}</#if>]" />
-          </#if>
-        </a-form-item>
-</#if>
-</#list>
-		
-      </a-form>
-    </a-spin>
-    <a-button type="primary" @click="handleOk">确定</a-button>
-    <a-button type="primary" @click="handleCancel">取消</a-button>
-  </a-drawer>
-</template>
-
-<script>
-  import { httpAction } from '@/api/manage'
-  import pick from 'lodash.pick'
-  import moment from "moment"
-
-  export default {
-    name: "${entityName}Modal",
-    data () {
-      return {
-        title:"操作",
-        visible: false,
-        model: {},
-        labelCol: {
-          xs: { span: 24 },
-          sm: { span: 5 },
-        },
-        wrapperCol: {
-          xs: { span: 24 },
-          sm: { span: 16 },
-        },
-
-        confirmLoading: false,
-        form: this.$form.createForm(this),
-        validatorRules:{
-        <#list columns as po>
-        <#if po.fieldName !='id'>
-        <#if po.nullable =='N'>
-        ${po.fieldName}:{rules: [{ required: true, message: '请输入${po.filedComment}!' }]},
-        </#if>
-        </#if>
-	    </#list>
-        },
-        url: {
-          add: "/${entityPackage}/${entityName?uncap_first}/add",
-          edit: "/${entityPackage}/${entityName?uncap_first}/edit",
-        },
-      }
-    },
-    created () {
-    },
-    methods: {
-      add () {
-        this.edit({});
-      },
-      edit (record) {
-        this.form.resetFields();
-        this.model = Object.assign({}, record);
-        this.visible = true;
-        this.$nextTick(() => {
-          this.form.setFieldsValue(pick(this.model<#list columns as po><#if po.fieldName !='id' && po.fieldType?index_of("date")==-1>,'${po.fieldName}'</#if></#list>))
-		  //时间格式化
-          <#list columns as po>
-          <#if po.fieldName !='id' && po.fieldType?index_of("date")!=-1>
-          this.form.setFieldsValue({${po.fieldName}:this.model.${po.fieldName}?moment(this.model.${po.fieldName}):null})
-          </#if>
-          </#list>
-        });
-
-      },
-      close () {
-        this.$emit('close');
-        this.visible = false;
-      },
-      handleOk () {
-        const that = this;
-        // 触发表单验证
-        this.form.validateFields((err, values) => {
-          if (!err) {
-            that.confirmLoading = true;
-            let httpurl = '';
-            let method = '';
-            if(!this.model.id){
-              httpurl+=this.url.add;
-              method = 'post';
-            }else{
-              httpurl+=this.url.edit;
-               method = 'put';
-            }
-            let formData = Object.assign(this.model, values);
-            //时间格式化
-            <#list columns as po>
-            <#if po.fieldName !='id' && po.fieldType =='date'>
-            formData.${po.fieldName} = formData.${po.fieldName}?formData.${po.fieldName}.format():null;
-            <#elseif po.fieldName !='id' && po.fieldType =='datetime'>
-            formData.${po.fieldName} = formData.${po.fieldName}?formData.${po.fieldName}.format('YYYY-MM-DD HH:mm:ss'):null;
-            </#if>
-            </#list>
-            
-            console.log(formData)
-            httpAction(httpurl,formData,method).then((res)=>{
-              if(res.success){
-                that.$message.success(res.message);
-                that.$emit('ok');
-              }else{
-                that.$message.warning(res.message);
-              }
-            }).finally(() => {
-              that.confirmLoading = false;
-              that.close();
-            })
-
-
-
-          }
-        })
-      },
-      handleCancel () {
-        this.close()
-      },
-
-
-    }
-  }
-</script>
-
-<style lang="less" scoped>
-/** Button按钮间距 */
-  .ant-btn {
-    margin-left: 30px;
-    margin-bottom: 30px;
-    float: right;
-  }
-</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index dee2973..8a25350 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -109,7 +109,7 @@ public class ${entityName}Controller {
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
 	@ApiOperation(value="${tableVo.ftlDescription}-编辑", notes="${tableVo.ftlDescription}-编辑")
-	@PutMapping(value = "/edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) {
 		${entityName} ${entityName?uncap_first} = new ${entityName}();
 		BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first});
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..261e51f
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,152 @@
+<template>
+   <div>
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--插槽:table标题-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+          <a-dropdown v-if="checkedKeys.length > 0">
+              <template #overlay>
+                <a-menu>
+                  <a-menu-item key="1" @click="batchHandleDelete">
+                    <Icon icon="ant-design:delete-outlined"></Icon>
+                    删除
+                  </a-menu-item>
+                </a-menu>
+              </template>
+              <a-button>批量操作
+                <Icon icon="mdi:chevron-down"></Icon>
+              </a-button>
+        </a-dropdown>
+      </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import {ref, computed, unref} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {useModal} from '/@/components/Modal';
+  import ${entityName}Modal from './modules/${entityName}Modal.vue'
+  import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
+  const checkedKeys = ref<Array<string | number>>([]);
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+   //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+      tableProps:{
+           title: '${tableVo.ftlDescription}',
+           api: list,
+           columns,
+           canResize:false,
+           formConfig: {
+                labelWidth: 120,
+                schemas: searchFormSchema,
+                autoSubmitOnEnter:true,
+                showAdvancedButton:true,
+            },
+            actionColumn: {
+               width: 120,
+            },
+        },
+        exportConfig: {
+            name:"${tableVo.ftlDescription}",
+            url: getExportUrl,
+        },
+        importConfig: {
+            url: getImportUrl
+        },
+    })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+   /**
+    * 新增事件
+    */
+  function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+  }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+  async function handleDelete(record) {
+     await deleteOne({id: record.id}, reload);
+   }
+   /**
+    * 批量删除事件
+    */
+  async function batchHandleDelete() {
+     await batchDelete({ids: checkedKeys.value}, reload);
+   }
+   /**
+    * 成功回调
+    */
+  function handleSuccess() {
+      reload();
+   }
+   /**
+      * 操作栏
+      */
+  function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+   }
+     /**
+        * 下拉操作栏
+        */
+  function getDropDownAction(record){
+      return [
+           {
+             label: '详情',
+             onClick: handleDetail.bind(null, record),
+           }, {
+             label: '删除',
+             popConfirm: {
+               title: '是否确认删除',
+               confirm: handleDelete.bind(null, record),
+             }
+           }
+      ]
+   }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..3b9ce59
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,72 @@
+import {defHttp} from '/@/utils/http/axios';
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/list',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+<#list subTables as sub><#rt/>
+  ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/query${sub.entityName}ByMainId',
+</#list>
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+<#list subTables as sub><#rt/>
+/**
+ * 查询子表数据
+ * @param params
+ */
+export const ${sub.entityName?uncap_first}List = Api.${sub.entityName?uncap_first}List;
+</#list>
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..f259669
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,95 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+import {JVxeTypes,JVxeColumn} from '/@/components/jeecg/JVxeTable/types'
+//列表数据
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+<#list columns as po>
+<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum>
+ {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+     <#if po.fieldType =='date'>
+    component: 'DatePicker'
+     <#elseif po.fieldType =='datetime'>
+    component: 'TimePicker'
+     <#elseif "int,decimal,double,"?contains(po.fieldType)>
+    component: 'InputNumber'
+     <#else>
+    component: 'Input'
+    </#if>
+  },
+</#if>
+</#list>
+];
+export const formSchema: FormSchema[] = [
+<#list columns as po><#rt/>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+     <#if po.fieldType =='date'>
+    component: 'DatePicker'
+     <#elseif po.fieldType =='datetime'>
+    component: 'TimePicker'
+     <#elseif "int,decimal,double,"?contains(po.fieldType)>
+    component: 'InputNumber'
+     <#else>
+    component: 'Input'
+    </#if>
+    <#if po.fieldName =='id'><#rt/>
+    show:false
+    </#if>
+  },
+</#list>
+];
+//子表表格配置
+<#list subTables as sub>
+export const ${sub.entityName?uncap_first}Columns: JVxeColumn[] = [
+<#-- 循环子表的列 开始 -->
+<#list sub.colums as col><#rt/>
+<#if col.filedComment !='外键' >
+    {
+      title: '${col.filedComment}',
+       key: '${col.fieldName}',
+<#if col.classType =='date'>
+      type: JVxeTypes.date,
+<#elseif col.classType =='datetime'>
+      type: JVxeTypes.datetime,
+<#elseif "int,decimal,double,"?contains(col.classType)>
+      type: JVxeTypes.inputNumber,
+<#else>
+      type: JVxeTypes.input,
+</#if>
+      width:"200px",
+      placeholder: '请输入${'$'}{title}',
+      defaultValue: '',
+<#-- 子表的校验 -->
+<#if col.nullable =='N'>
+      validateRules: [{ required: true, message: '${'$'}{title}不能为空' }],
+</#if>
+    },
+</#if>
+</#list>
+<#-- 循环子表的列 结束 -->
+  ]
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
new file mode 100644
index 0000000..6ceabde
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
@@ -0,0 +1,119 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="1000px">
+      <BasicForm @register="registerForm" ref="formRef"/>
+  <!-- 子表单区域 -->
+      <a-tabs v-model:activeKey="activeKey" @change="handleChangeTabs">
+<#list subTables as sub><#rt/>
+        <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true">
+            <JVxeTable
+              keep-source
+              resizable
+              :ref="refKeys[${sub_index}]"
+              :loading="${sub.entityName?uncap_first}Table.loading"
+              :columns="${sub.entityName?uncap_first}Table.columns"
+              :dataSource="${sub.entityName?uncap_first}Table.dataSource"
+              :maxHeight="300"
+              :rowNumber="true"
+              :rowSelection="true"
+              :toolbar="true"
+              />
+        </a-tab-pane>
+</#list>
+      </a-tabs>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref,reactive} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import { JVxeTable } from '/@/components/jeecg/JVxeTable'
+    import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods.ts'
+    import {formSchema<#list subTables as sub>,${sub.entityName?uncap_first}Columns</#list>} from '../${entityName?uncap_first}.data';
+    import {saveOrUpdate<#list subTables as sub>,${sub.entityName?uncap_first}List</#list>} from '../${entityName?uncap_first}.api';
+    import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils'
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    const refKeys = ref([<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]);
+    <#assign hasOne2Many = false>
+    const activeKey = ref('${subTables[0].entityName?uncap_first}');
+<#list subTables as sub>
+    const ${sub.entityName?uncap_first} = ref();
+</#list>
+    const tableRefs = {<#list subTables as sub>${sub.entityName?uncap_first},</#list>};
+   <#list subTables as sub>
+    const ${sub.entityName?uncap_first}Table = reactive({
+          loading: false,
+          dataSource: [],
+          columns:${sub.entityName?uncap_first}Columns
+    })
+   </#list>
+    //表单配置
+    const [registerForm, {setProps,resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+    });
+     //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await reset();
+        setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+            <#list subTables as sub><#rt/>
+             requestSubTableData(${sub.entityName?uncap_first}List, {id:data?.record?.id}, ${sub.entityName?uncap_first}Table)
+            </#list>
+        }
+        // 隐藏底部时禁用整个表单
+       setProps({ disabled: !data?.showFooter })
+    });
+    //方法配置
+    const [handleChangeTabs,handleSubmit,requestSubTableData,formRef] = useJvxeMethod(requestAddOrEdit,classifyIntoFormData,tableRefs,activeKey,refKeys);
+
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+
+    async function reset(){
+      await resetFields();
+      activeKey.value = ref('${subTables[0].entityName?uncap_first}');
+      <#list subTables as sub>
+      ${sub.entityName?uncap_first}Table.dataSource = [];
+      </#list>
+    }
+    function classifyIntoFormData(allValues) {
+         let main = Object.assign({}, allValues.formValue)
+         return {
+           ...main, // 展开
+ <#assign subManyIndex = 0>
+ <#list subTables as sub><#rt/>
+           ${sub.entityName?uncap_first}List: allValues.tablesValue[${subManyIndex}].tableData,
+           <#assign subManyIndex = subManyIndex+1>
+ </#list>
+         }
+       }
+
+    //表单提交事件
+    async function requestAddOrEdit(values) {
+        try {
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
index 93e7bb7..9ed4850 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/controller/${entityName}Controller.javai
@@ -108,7 +108,7 @@ public class ${entityName}Controller {
 	 */
 	@AutoLog(value = "${tableVo.ftlDescription}-编辑")
 	@ApiOperation(value="${tableVo.ftlDescription}-", notes="${tableVo.ftlDescription}-编辑")
-	@PutMapping(value = "/edit")
+	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
 	public Result<?> edit(@RequestBody ${entityName}Page ${entityName?uncap_first}Page) {
 		${entityName} ${entityName?uncap_first} = new ${entityName}();
 		BeanUtils.copyProperties(${entityName?uncap_first}Page, ${entityName?uncap_first});
@@ -223,7 +223,7 @@ ${sub.entityName?uncap_first}.get${key}()!=null<#rt/>
      */
     @AutoLog(value = "${sub.ftlDescription}-编辑")
     @ApiOperation(value="${sub.ftlDescription}-编辑", notes="${sub.ftlDescription}-编辑")
-    @PutMapping("/edit${sub.entityName}")
+    @RequestMapping(value = "/edit${sub.entityName}", method = {RequestMethod.PUT,RequestMethod.POST})
     public Result<?> edit${sub.entityName}(@RequestBody ${sub.entityName} ${sub.entityName?uncap_first}) {
         ${sub.entityName?uncap_first}Service.updateById(${sub.entityName?uncap_first});
         return Result.OK("编辑${sub.ftlDescription}成功!");
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
new file mode 100644
index 0000000..513f151
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}List.vuei
@@ -0,0 +1,171 @@
+<template>
+   <div>
+    <!--引用表格-->
+   <BasicTable @register="registerTable" :rowSelection="rowSelection">
+     <!--插槽:table标题-->
+      <template #tableTitle>
+          <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+          <a-button  type="primary" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
+          <j-upload-button  type="primary" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
+          <a-dropdown v-if="checkedKeys.length > 0">
+              <template #overlay>
+                <a-menu>
+                  <a-menu-item key="1" @click="batchHandleDelete">
+                    <Icon icon="ant-design:delete-outlined"></Icon>
+                    删除
+                  </a-menu-item>
+                </a-menu>
+              </template>
+              <a-button>批量操作
+                <Icon icon="mdi:chevron-down"></Icon>
+              </a-button>
+        </a-dropdown>
+      </template>
+       <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+      </template>
+    </BasicTable>
+    <a-tabs :defaultActiveKey="refKeys[0]" style="margin: 10px">
+        <#list subTables as sub><#rt/>
+          <a-tab-pane tab="${sub.ftlDescription}" :key="refKeys[${sub_index}]" :forceRender="true">
+            <${sub.entityName}List></${sub.entityName}List>
+          </a-tab-pane>
+    	</#list>
+    </a-tabs>
+
+    <!-- 表单区域 -->
+    <${entityName}Modal @register="registerModal" @success="handleSuccess"></${entityName}Modal>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import {ref, computed, unref,provide} from 'vue';
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+<#list subTables as sub><#rt/>
+  import ${sub.entityName}List from './${sub.entityName}List.vue'
+</#list>
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {useModal} from '/@/components/Modal';
+  import ${entityName}Modal from './modules/${entityName}Modal.vue'
+  import {columns, searchFormSchema} from './${entityName?uncap_first}.data';
+  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './${entityName?uncap_first}.api';
+
+  const checkedKeys = ref<Array<string | number>>([]);
+  const refKeys = ref([<#list subTables as sub>'${sub.entityName?uncap_first}', </#list>]);
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+   //注册table数据
+  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
+      tableProps:{
+           title: '${tableVo.ftlDescription}',
+           api: list,
+           columns,
+           canResize: false,
+           rowSelection: {type: 'radio'},
+           formConfig: {
+                labelWidth: 120,
+                schemas: searchFormSchema,
+                autoSubmitOnEnter:true,
+                showAdvancedButton:true,
+            },
+            actionColumn: {
+               width: 120,
+            },
+        },
+        exportConfig: {
+            name:"${tableVo.ftlDescription}",
+            url: getExportUrl,
+        },
+        importConfig: {
+            url: getImportUrl
+        },
+    })
+
+  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+
+  const mainId = computed(() => (unref(selectedRowKeys).length > 0 ? unref(selectedRowKeys)[0] : ''));
+
+  //下发 orderId,子组件接收
+  provide('mainId', mainId);
+
+   /**
+    * 新增事件
+    */
+  function handleAdd() {
+     openModal(true, {
+       isUpdate: false,
+       showFooter: true,
+     });
+  }
+   /**
+    * 编辑事件
+    */
+  function handleEdit(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: true,
+     });
+   }
+   /**
+    * 详情
+   */
+  function handleDetail(record: Recordable) {
+     openModal(true, {
+       record,
+       isUpdate: true,
+       showFooter: false,
+     });
+   }
+   /**
+    * 删除事件
+    */
+  async function handleDelete(record) {
+     await deleteOne({id: record.id}, reload);
+   }
+   /**
+    * 批量删除事件
+    */
+  async function batchHandleDelete() {
+     await batchDelete({ids: checkedKeys.value}, reload);
+   }
+   /**
+    * 成功回调
+    */
+  function handleSuccess() {
+      reload();
+   }
+   /**
+      * 操作栏
+      */
+  function getTableAction(record){
+       return [
+         {
+           label: '编辑',
+           onClick: handleEdit.bind(null, record),
+         }
+       ]
+   }
+     /**
+        * 下拉操作栏
+        */
+  function getDropDownAction(record){
+      return [
+           {
+             label: '详情',
+             onClick: handleDetail.bind(null, record),
+           }, {
+             label: '删除',
+             popConfirm: {
+               title: '是否确认删除',
+               confirm: handleDelete.bind(null, record),
+             }
+           }
+      ]
+   }
+</script>
+
+<style scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
new file mode 100644
index 0000000..f01cb16
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__api.tsi
@@ -0,0 +1,113 @@
+import {defHttp} from '/@/utils/http/axios';
+import {Modal} from 'ant-design-vue';
+
+enum Api {
+  list = '/${entityPackage}/${entityName?uncap_first}/list',
+  save='/${entityPackage}/${entityName?uncap_first}/add',
+  edit='/${entityPackage}/${entityName?uncap_first}/edit',
+  deleteOne = '/${entityPackage}/${entityName?uncap_first}/delete',
+  deleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch',
+  importExcel = '/${entityPackage}/${entityName?uncap_first}/importExcel',
+  exportXls = '/${entityPackage}/${entityName?uncap_first}/exportXls',
+<#list subTables as sub><#rt/>
+  ${sub.entityName?uncap_first}List = '/${entityPackage}/${entityName?uncap_first}/list${sub.entityName}ByMainId',
+  ${sub.entityName?uncap_first}Save='/${entityPackage}/${entityName?uncap_first}/add${sub.entityName}',
+  ${sub.entityName?uncap_first}Edit='/${entityPackage}/${entityName?uncap_first}/edit${sub.entityName}',
+  ${sub.entityName?uncap_first}Delete = '/${entityPackage}/${entityName?uncap_first}/delete${sub.entityName}',
+  ${sub.entityName?uncap_first}DeleteBatch = '/${entityPackage}/${entityName?uncap_first}/deleteBatch${sub.entityName}',
+</#list>
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) =>
+  defHttp.get({url: Api.list, params});
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({url: url, params});
+}
+
+<#list subTables as sub><#rt/>
+/**
+ * 列表接口
+ * @param params
+ */
+export const ${sub.entityName?uncap_first}List = (params) =>
+  defHttp.get({url: Api.${sub.entityName?uncap_first}List, params});
+
+/**
+ * 删除单个
+ */
+export const ${sub.entityName?uncap_first}Delete = (params,handleSuccess) => {
+  return defHttp.delete({url: Api.${sub.entityName?uncap_first}Delete, params}, {joinParamsToUrl: true}).then(() => {
+    handleSuccess();
+  });
+}
+/**
+ * 批量删除
+ * @param params
+ */
+export const  ${sub.entityName?uncap_first}DeleteBatch = (params, handleSuccess) => {
+  Modal.confirm({
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({url: Api. ${sub.entityName?uncap_first}DeleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
+        handleSuccess();
+      });
+    }
+  });
+}
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const ${sub.entityName?uncap_first}Save = (params, isUpdate) => {
+  let url = isUpdate ? Api.${sub.entityName?uncap_first}Edit : Api.${sub.entityName?uncap_first}Save;
+  return defHttp.post({url: url, params});
+}
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
new file mode 100644
index 0000000..dba08e8
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/${entityName}__data.tsi
@@ -0,0 +1,110 @@
+import {BasicColumn} from '/@/components/Table';
+import {FormSchema} from '/@/components/Table';
+import { rules} from '/@/utils/helper/validator';
+import { render } from '/@/utils/common/renderUtils';
+//列表数据
+export const columns: BasicColumn[] = [
+ <#list columns as po>
+   <#if po.fieldName !='id'>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+<#list columns as po>
+<#if po.fieldName !='id' && po_index<= tableVo.searchFieldNum>
+ {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+     <#if po.fieldType =='date'>
+    component: 'DatePicker'
+     <#elseif po.fieldType =='datetime'>
+    component: 'TimePicker'
+     <#elseif "int,decimal,double,"?contains(po.fieldType)>
+    component: 'InputNumber'
+     <#else>
+    component: 'Input'
+    </#if>
+  },
+</#if>
+</#list>
+];
+
+export const formSchema: FormSchema[] = [
+<#list columns as po><#rt/>
+  {
+    label: '${po.filedComment}',
+    field: '${po.fieldName}',
+     <#if po.fieldType =='date'>
+    component: 'DatePicker'
+     <#elseif po.fieldType =='datetime'>
+    component: 'TimePicker'
+     <#elseif "int,decimal,double,"?contains(po.fieldType)>
+    component: 'InputNumber'
+     <#else>
+    component: 'Input'
+    </#if>
+    <#if po.fieldName =='id'><#rt/>
+    show:false
+    </#if>
+  },
+</#list>
+];
+
+//子表表格配置
+<#list subTables as sub>
+//列表数据
+export const ${sub.entityName?uncap_first}Columns: BasicColumn[] = [
+ <#list sub.colums as po><#rt/>
+   <#if po.fieldName !='id' && sub.foreignKeys[0]?uncap_first != po.fieldName>
+   {
+    title: '${po.filedComment}',
+    align:"center",
+    <#if po.classType=='date'>
+    dataIndex: '${po.fieldName}',
+    customRender:({text}) =>{
+      return !text?"":(text.length>10?text.substr(0,10):text)
+    },
+   <#else>
+    dataIndex: '${po.fieldName}'
+   </#if>
+   },
+   </#if>
+ </#list>
+];
+
+export const ${sub.entityName?uncap_first}FormSchema: FormSchema[] = [
+<#-- 循环子表的列 开始 -->
+<#list sub.colums as po><#rt/>
+   {
+       label: '${po.filedComment}',
+       field: '${po.fieldName}',
+        <#if po.fieldType =='date'>
+       component: 'DatePicker'
+        <#elseif po.fieldType =='datetime'>
+       component: 'TimePicker'
+        <#elseif "int,decimal,double,"?contains(po.fieldType)>
+       component: 'InputNumber'
+        <#else>
+       component: 'Input'
+       </#if>
+       <#if po.fieldName =='id'><#rt/>
+       show:false
+       </#if>
+     },
+</#list>
+<#-- 循环子表的列 结束 -->
+  ]
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei
new file mode 100644
index 0000000..544b0cb
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/[1-n]List.vuei
@@ -0,0 +1,147 @@
+<#list subTables as subTab>
+#segment#${subTab.entityName}List.vue
+<template>
+  <div>
+     <!--table区域-begin-->
+    <BasicTable @register="registerTable" :rowSelection="rowSelection">
+      <!--插槽:table标题-->
+       <template #tableTitle>
+           <a-button type="primary" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+           <a-dropdown v-if="selectedRowKeys.length > 0">
+               <template #overlay>
+                 <a-menu>
+                   <a-menu-item key="1" @click="batchHandleDelete">
+                     <Icon icon="ant-design:delete-outlined"></Icon>
+                     删除
+                   </a-menu-item>
+                 </a-menu>
+               </template>
+               <a-button>批量操作
+                 <Icon icon="mdi:chevron-down"></Icon>
+               </a-button>
+         </a-dropdown>
+       </template>
+        <!--操作栏-->
+       <template #action="{ record }">
+         <TableAction :actions="getTableAction(record)"/>
+       </template>
+     </BasicTable>
+    <!-- table区域-end -->
+
+    <!-- 表单区域 -->
+    <${subTab.entityName}Modal @register="registerModal" @success="handleSuccess"/>
+  </div>
+</template>
+
+<script lang="ts" setup>
+  import {ref, computed, unref, watch, inject} from 'vue';
+  import ${subTab.entityName}Modal from './modules/${subTab.entityName}Modal.vue'
+  import {BasicTable, useTable, TableAction} from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage'
+  import {useModal} from '/@/components/Modal';
+  import {isEmpty} from "/@/utils/is";
+  import {useMessage} from '/@/hooks/web/useMessage';
+  import {${subTab.entityName?uncap_first}Columns} from './${entityName?uncap_first}.data';
+  import {${subTab.entityName?uncap_first}List, ${subTab.entityName?uncap_first}Delete, ${subTab.entityName?uncap_first}DeleteBatch} from './${entityName?uncap_first}.api';
+ //提示弹窗
+  const $message = useMessage()
+  //接收主表id
+  const mainId = inject('mainId') || '';
+  //查询参数
+  const searchInfo = ref({});
+  //注册model
+  const [registerModal, {openModal}] = useModal();
+ // 列表页面公共参数、方法
+  const {prefixCls, tableContext} = useListPage({
+        tableProps: {
+            api: ${subTab.entityName?uncap_first}List,
+            columns: ${subTab.entityName?uncap_first}Columns,
+            canResize: false,
+            useSearchForm: false,
+            searchInfo,
+            actionColumn: {
+                width: 180,
+            }
+        },
+    });
+
+    //注册table数据
+    const [registerTable, {reload}, {rowSelection, selectedRowKeys}] = tableContext;
+
+    watch(mainId, () => {
+            searchInfo.value['${subTab.foreignKeys[0]?uncap_first}'] = unref(mainId);
+            reload();
+        }
+    );
+
+    /**
+     * 新增事件
+     */
+    function handleAdd() {
+        if (isEmpty(unref(mainId))) {
+            $message.createMessage.warning('请选择一个主表信息')
+            return;
+        }
+        openModal(true, {
+            isUpdate: false,
+            showFooter: true,
+        });
+    }
+
+    /**
+     * 编辑事件
+     */
+    async function handleEdit(record: Recordable) {
+        openModal(true, {
+            record,
+            isUpdate: true,
+            showFooter: true,
+        });
+    }
+
+    /**
+     * 删除事件
+     */
+    async function handleDelete(record) {
+        await ${subTab.entityName?uncap_first}Delete({id: record.id}, reload);
+    }
+
+    /**
+     * 批量删除事件
+     */
+    async function batchHandleDelete() {
+        await ${subTab.entityName?uncap_first}DeleteBatch({ids: selectedRowKeys.value}, () => {
+            selectedRowKeys.value = []
+            reload()
+        })
+    }
+
+    /**
+     * 成功回调
+     */
+    function handleSuccess() {
+        reload();
+    }
+
+    /**
+     * 操作栏
+     */
+    function getTableAction(record) {
+        return [
+            {
+                label: '编辑',
+                onClick: handleEdit.bind(null, record),
+            }, {
+                label: '删除',
+                popConfirm: {
+                    title: '是否确认删除',
+                    confirm: handleDelete.bind(null, record),
+                },
+            }
+        ]
+    }
+</script>
+<style scoped>
+
+</style>
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
new file mode 100644
index 0000000..a6cdaec
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/${entityName}Modal.vuei
@@ -0,0 +1,56 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="40%">
+         <BasicForm @register="registerForm"/>
+     </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {formSchema} from '../${entityName?uncap_first}.data';
+    import {saveOrUpdate} from '../${entityName?uncap_first}.api';
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    //表单配置
+    const [registerForm, {resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+    });
+    //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await resetFields();
+        setModalProps({confirmLoading: false,showCancelBtn:data?.showFooter,showOkBtn:data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+        }
+    });
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+    //表单提交事件
+    async function handleSubmit(v) {
+        try {
+            let values = await validate();
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+
+</style>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/[1-n]Modal.vuei b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/[1-n]Modal.vuei
new file mode 100644
index 0000000..de43e2d
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/jeecg/code-template/onetomany2/java/${bussiPackage}/${entityPackage}/vue3/modules/[1-n]Modal.vuei
@@ -0,0 +1,64 @@
+<#list subTables as subTab>
+#segment#${subTab.entityName}Modal.vue
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" :title="title" @ok="handleSubmit" width="40%">
+         <BasicForm @register="registerForm"/>
+     </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref,inject} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {${subTab.entityName?uncap_first}FormSchema} from '../${entityName?uncap_first}.data';
+    import {${subTab.entityName?uncap_first}Save} from '../${entityName?uncap_first}.api';
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    //接收主表id
+    const mainId = inject('mainId');
+    const isUpdate = ref(true);
+    //表单配置
+    const [registerForm, {resetFields, setFieldsValue, validate}] = useForm({
+        labelWidth: 150,
+        schemas: ${subTab.entityName?uncap_first}FormSchema,
+        showActionButtonGroup: false,
+    });
+    //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await resetFields();
+        setModalProps({confirmLoading: false});
+        isUpdate.value = !!data?.isUpdate;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+        }
+    });
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : '编辑'));
+    //表单提交事件
+    async function handleSubmit(v) {
+        try {
+            let values = await validate();
+            setModalProps({confirmLoading: true});
+            if (unref(mainId)) {
+                values['${subTab.foreignKeys[0]?uncap_first}'] = unref(mainId);
+            }
+            //提交表单
+            await ${subTab.entityName?uncap_first}Save(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style scoped>
+
+</style>
+</#list>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-module-system/src/main/resources/templates/announcement/showContent.ftl b/jeecg-boot/jeecg-boot-module-system/src/main/resources/templates/announcement/showContent.ftl
index cbcc048..cb9408c 100644
--- a/jeecg-boot/jeecg-boot-module-system/src/main/resources/templates/announcement/showContent.ftl
+++ b/jeecg-boot/jeecg-boot-module-system/src/main/resources/templates/announcement/showContent.ftl
@@ -129,7 +129,7 @@
     </div>
 </div>
 <div>
-    ${data.msgContent}
+    ${data.msgContent!''}
 </div>
 </body>
 </html>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml
index f0b932e..76b8523 100644
--- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-starter</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>jeecg-boot-starter-cloud</artifactId>
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/resources/bootstrap.yml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/resources/bootstrap.yml
index f43a397..de7e991 100644
--- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/resources/bootstrap.yml
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-cloud/src/main/resources/bootstrap.yml
@@ -9,9 +9,9 @@ spring:
     nacos:
       config:
         # Nacos 认证用户
-        username: nacos
+        username: @config.username@
         # Nacos 认证密码
-        password: nacos
+        password: @config.password@
         # 命名空间 常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等
         namespace: @config.namespace@
         # 配置中心地址
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml
index eebd4fe..658a8e2 100644
--- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-job/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-starter</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>jeecg-boot-starter-job</artifactId>
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml
index 018c44f..abd203b 100644
--- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-starter</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>jeecg-boot-starter-lock</artifactId>
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/src/main/java/org/jeecg/boot/starter/lock/aspect/DistributedLockHandler.java b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/src/main/java/org/jeecg/boot/starter/lock/aspect/DistributedLockHandler.java
index 24151ca..c35cc93 100644
--- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/src/main/java/org/jeecg/boot/starter/lock/aspect/DistributedLockHandler.java
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-lock/src/main/java/org/jeecg/boot/starter/lock/aspect/DistributedLockHandler.java
@@ -94,9 +94,6 @@ public class DistributedLockHandler extends BaseAspect{
         Object[] args = joinPoint.getArgs();
 
         LockModel lockModel = jLock.lockModel();
-        if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.REDLOCK) && keys.length > 1) {
-            throw new RuntimeException("参数有多个,锁模式为->" + lockModel.name() + ".无法锁定");
-        }
         RLock rLock = null;
         String keyConstant = jLock.keyConstant();
         if (lockModel.equals(LockModel.AUTO)) {
@@ -106,6 +103,9 @@ public class DistributedLockHandler extends BaseAspect{
                 lockModel = LockModel.REENTRANT;
             }
         }
+        if (!lockModel.equals(LockModel.MULTIPLE) && !lockModel.equals(LockModel.REDLOCK) && keys.length > 1) {
+            throw new RuntimeException("参数有多个,锁模式为->" + lockModel.name() + ".无法锁定");
+        }
         switch (lockModel) {
             case FAIR:
                 rLock = redissonClient.getFairLock(getValueBySpEL(keys[0], parameterNames, args, keyConstant).get(0));
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml
index c94f8a1..809e1f3 100644
--- a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-rabbitmq/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-starter</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>jeecg-boot-starter-rabbitmq</artifactId>
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-seata/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-seata/pom.xml
new file mode 100644
index 0000000..b275f3a
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-seata/pom.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>jeecg-boot-starter</artifactId>
+        <groupId>org.jeecgframework.boot</groupId>
+        <version>3.1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>jeecg-boot-starter-seata</artifactId>
+    <description>分布式事务</description>
+    <dependencies>
+        <!-- seata依赖 -->
+        <dependency>
+            <groupId>io.seata</groupId>
+            <artifactId>seata-spring-boot-starter</artifactId>
+            <version>1.4.2</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba.nacos</groupId>
+            <artifactId>nacos-client</artifactId>
+            <version>1.3.3</version>
+        </dependency>
+
+    </dependencies>
+</project>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/pom.xml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/pom.xml
new file mode 100644
index 0000000..c18d6d8
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/pom.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>jeecg-boot-starter</artifactId>
+        <groupId>org.jeecgframework.boot</groupId>
+        <version>3.1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>jeecg-boot-starter-shardingsphere</artifactId>
+    <description>分库分表</description>
+    <dependencies>
+        <!-- 动态数据源 -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
+            <version>${dynamic-datasource-spring-boot-starter.version}</version>
+        </dependency>
+        <!-- 分库分表 -->
+        <dependency>
+            <groupId>org.apache.shardingsphere</groupId>
+            <artifactId>shardingsphere-jdbc-core-spring-boot-starter</artifactId>
+            <version>5.0.0</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/java/org/jeecg/boot/shardingsphere/config/DataSourceConfiguration.java b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/java/org/jeecg/boot/shardingsphere/config/DataSourceConfiguration.java
new file mode 100644
index 0000000..8d87329
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/java/org/jeecg/boot/shardingsphere/config/DataSourceConfiguration.java
@@ -0,0 +1,78 @@
+package org.jeecg.boot.shardingsphere.config;
+
+import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
+import com.baomidou.dynamic.datasource.provider.AbstractDataSourceProvider;
+import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import org.springframework.boot.SpringBootConfiguration;
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.context.annotation.Primary;
+
+import javax.annotation.Resource;
+import javax.sql.DataSource;
+import java.util.Map;
+
+/**
+ * 分库分表数据源配置
+ * @author zyf
+ */
+@Configuration
+@AutoConfigureBefore({DynamicDataSourceAutoConfiguration.class, SpringBootConfiguration.class})
+public class DataSourceConfiguration {
+    /**
+     * 分表数据源名称
+     */
+    public static final String SHARDING_DATA_SOURCE_NAME = "sharding";
+    /**
+     * 动态数据源配置项
+     */
+    @Resource
+    private DynamicDataSourceProperties dynamicDataSourceProperties;
+
+    @Lazy
+    @Resource
+    DataSource shardingDataSource;
+
+    /**
+     * 将shardingDataSource放到了多数据源(dataSourceMap)中
+     * 注意有个版本的bug,3.1.1版本 不会进入loadDataSources 方法,这样就一直造成数据源注册失败
+     */
+    @Bean
+    public DynamicDataSourceProvider dynamicDataSourceProvider() {
+        Map<String, DataSourceProperty> datasourceMap = dynamicDataSourceProperties.getDatasource();
+        return new AbstractDataSourceProvider() {
+            @Override
+            public Map<String, DataSource> loadDataSources() {
+                Map<String, DataSource> dataSourceMap = createDataSourceMap(datasourceMap);
+                // 将 shardingjdbc 管理的数据源也交给动态数据源管理
+                dataSourceMap.put(SHARDING_DATA_SOURCE_NAME, shardingDataSource);
+                return dataSourceMap;
+            }
+        };
+    }
+
+    /**
+     * 将动态数据源设置为首选的
+     * 当spring存在多个数据源时, 自动注入的是首选的对象
+     * 设置为主要的数据源之后,就可以支持shardingjdbc原生的配置方式了
+     *
+     * @return
+     */
+    @Primary
+    @Bean
+    public DataSource dataSource(DynamicDataSourceProvider dynamicDataSourceProvider) {
+        DynamicRoutingDataSource dataSource = new DynamicRoutingDataSource();
+        dataSource.setPrimary(dynamicDataSourceProperties.getPrimary());
+        dataSource.setStrict(dynamicDataSourceProperties.getStrict());
+        dataSource.setStrategy(dynamicDataSourceProperties.getStrategy());
+        dataSource.setProvider(dynamicDataSourceProvider);
+        dataSource.setP6spy(dynamicDataSourceProperties.getP6spy());
+        dataSource.setSeata(dynamicDataSourceProperties.getSeata());
+        return dataSource;
+    }
+}
diff --git a/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/resources/application.yml b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/resources/application.yml
new file mode 100644
index 0000000..c343752
--- /dev/null
+++ b/jeecg-boot/jeecg-boot-starter/jeecg-boot-starter-shardingsphere/src/main/resources/application.yml
@@ -0,0 +1,3 @@
+spring:
+  profiles:
+    active: sharding
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-boot-starter/pom.xml b/jeecg-boot/jeecg-boot-starter/pom.xml
index b08cd9c..849b9fe 100644
--- a/jeecg-boot/jeecg-boot-starter/pom.xml
+++ b/jeecg-boot/jeecg-boot-starter/pom.xml
@@ -4,7 +4,7 @@
     <parent>
         <groupId>org.jeecgframework.boot</groupId>
         <artifactId>jeecg-boot-parent</artifactId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>jeecg-boot-starter</artifactId>
@@ -20,6 +20,8 @@
         <module>jeecg-boot-starter-job</module>
         <module>jeecg-boot-starter-lock</module>
         <module>jeecg-boot-starter-rabbitmq</module>
+        <module>jeecg-boot-starter-shardingsphere</module>
+        <module>jeecg-boot-starter-seata</module>
     </modules>
     <dependencies>
         <!--jeecg-tools-->
@@ -38,4 +40,93 @@
             <optional>true</optional>
         </dependency>
     </dependencies>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <encoding>UTF-8</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-surefire-plugin</artifactId>
+                <configuration>
+                    <testFailureIgnore>true</testFailureIgnore>
+                </configuration>
+            </plugin>
+            <!--生成Source jar文件-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+                <version>2.2.1</version>
+                <executions>
+                    <execution>
+                        <id>attach-sources</id>
+                        <goals>
+                            <goal>jar-no-fork</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <!--生成Javadoc,关闭doclint,避免注解检查不通过-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.9.1</version>
+                <executions>
+                    <execution>
+                        <id>attach-javadocs</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                        <configuration>
+                            <additionalparam>-Xdoclint:none</additionalparam>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <!--Maven GPG插件用于使用以下配置对组件进行签名-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-gpg-plugin</artifactId>
+                <version>1.6</version>
+                <executions>
+                    <execution>
+                        <id>sign-artifacts</id>
+                        <phase>verify</phase>
+                        <goals>
+                            <goal>sign</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <!--Nexus Staging Maven插件是将组件部署到OSS并将其发布到Central Repository的推荐方法-->
+            <plugin>
+                <groupId>org.sonatype.plugins</groupId>
+                <artifactId>nexus-staging-maven-plugin</artifactId>
+                <version>1.6.7</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <serverId>oss</serverId>
+                    <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+                    <autoReleaseAfterClose>true</autoReleaseAfterClose>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+    <distributionManagement>
+        <snapshotRepository>
+            <id>oss</id>
+            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
+        </snapshotRepository>
+        <repository>
+            <id>oss</id>
+            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
+        </repository>
+    </distributionManagement>
 </project>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile
index b21fb63..2ee93a8 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/Dockerfile
@@ -10,6 +10,6 @@ WORKDIR /jeecg-cloud-gateway
 
 EXPOSE 9999
 
-ADD ./target/jeecg-cloud-gateway-3.0.jar ./
+ADD ./target/jeecg-cloud-gateway-3.1.0.jar ./
 
-CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-gateway-3.0.jar
\ No newline at end of file
+CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-gateway-3.1.0.jar
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml
index 9d79024..a196790 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-cloud-module</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml
index b261a1c..dac2d5f 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-gateway/src/main/resources/application.yml
@@ -65,4 +65,4 @@ hystrix:
         isolation:
           strategy: SEMAPHORE
           thread:
-            timeoutInMilliseconds: 3000
\ No newline at end of file
+            timeoutInMilliseconds: 9000
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml
index d838dde..4f045f3 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-monitor/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-cloud-module</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>jeecg-cloud-monitor</artifactId>
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile
index 644f296..75c37fd 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/Dockerfile
@@ -10,6 +10,6 @@ WORKDIR /jeecg-cloud-nacos
 
 EXPOSE 8848
 
-ADD ./target/jeecg-cloud-nacos-3.0.jar ./
+ADD ./target/jeecg-cloud-nacos-3.1.0.jar ./
 
-CMD sleep 5;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-nacos-3.0.jar
\ No newline at end of file
+CMD sleep 5;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-nacos-3.1.0.jar
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml
index 1752b18..862784d 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-nacos/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-cloud-module</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <artifactId>jeecg-cloud-nacos</artifactId>
     <name>jeecg-cloud-nacos</name>
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml
index 871c920..121dd49 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-sentinel/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-cloud-module</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <artifactId>jeecg-cloud-sentinel</artifactId>
     <name>jeecg-cloud-sentinel</name>
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile
index 1759850..2c5706e 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/Dockerfile
@@ -10,6 +10,6 @@ WORKDIR /jeecg-cloud-system
 
 EXPOSE 7001
 
-ADD ./target/jeecg-cloud-system-start-3.0.jar ./
+ADD ./target/jeecg-cloud-system-start-3.1.0.jar ./
 
-CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-system-start-3.0.jar
\ No newline at end of file
+CMD sleep 10;java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-system-start-3.1.0.jar
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml
index ed3433a..3e2fe8c 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-system-start/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-cloud-module</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
     <artifactId>jeecg-cloud-system-start</artifactId>
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/pom.xml
new file mode 100644
index 0000000..ad6d695
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>jeecg-cloud-test</artifactId>
+        <groupId>org.jeecgframework.boot</groupId>
+        <version>3.1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <description>分布式事务测试模块</description>
+    <artifactId>jeecg-cloud-test-seata</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>jeecg-boot-starter-seata</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/controller/SeataOrderController.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/controller/SeataOrderController.java
new file mode 100644
index 0000000..702380f
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/controller/SeataOrderController.java
@@ -0,0 +1,59 @@
+package org.jeecg.modules.test.seata.controller;
+
+/**
+ * @Description: TODO
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.jeecg.modules.test.seata.dto.PlaceOrderRequest;
+import org.jeecg.modules.test.seata.service.SeataOrderService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/order")
+@Api(tags = "seata测试")
+public class SeataOrderController {
+
+    @Autowired
+    private SeataOrderService orderService;
+
+    /**
+     * 自由下单
+     */
+    @PostMapping("/placeOrder")
+    @ApiOperation(value = "自由下单", notes = "自由下单")
+    public String placeOrder(@Validated @RequestBody PlaceOrderRequest request) {
+        orderService.placeOrder(request);
+        return "下单成功";
+    }
+
+    /**
+     * 测试商品库存不足-异常回滚
+     */
+    @PostMapping("/test1")
+    @ApiOperation(value = "测试商品库存不足", notes = "测试商品库存不足")
+    public String test1() {
+        //商品单价10元,库存20个,用户余额50元,模拟一次性购买22个。 期望异常回滚
+        orderService.placeOrder(new PlaceOrderRequest(1L, 1L, 22));
+        return "下单成功";
+    }
+
+    /**
+     * 测试用户账户余额不足-异常回滚
+     */
+    @PostMapping("/test2")
+    @ApiOperation(value = "测试用户账户余额不足", notes = "测试用户账户余额不足")
+    public String test2() {
+        //商品单价10元,库存20个,用户余额50元,模拟一次性购买6个。 期望异常回滚
+        orderService.placeOrder(new PlaceOrderRequest(1L, 1L, 6));
+        return "下单成功";
+    }
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/PlaceOrderRequest.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/PlaceOrderRequest.java
new file mode 100644
index 0000000..77afc5e
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/PlaceOrderRequest.java
@@ -0,0 +1,28 @@
+package org.jeecg.modules.test.seata.dto;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+/**
+ * @Description: 订单请求对象
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class PlaceOrderRequest {
+
+    @NotNull
+    private Long userId;
+
+    @NotNull
+    private Long productId;
+
+    @NotNull
+    private Integer amount;
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceBalanceRequest.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceBalanceRequest.java
new file mode 100644
index 0000000..611eca1
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceBalanceRequest.java
@@ -0,0 +1,21 @@
+package org.jeecg.modules.test.seata.dto;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @Description: 余额请求对象
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class ReduceBalanceRequest {
+
+    private Long userId;
+    private Integer price;
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceStockRequest.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceStockRequest.java
new file mode 100644
index 0000000..d282476
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/dto/ReduceStockRequest.java
@@ -0,0 +1,21 @@
+package org.jeecg.modules.test.seata.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+/**
+ * @Description: 库存请求对象
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class ReduceStockRequest {
+
+    private Long productId;
+    private Integer amount;
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataAccount.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataAccount.java
new file mode 100644
index 0000000..3b2de1d
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataAccount.java
@@ -0,0 +1,30 @@
+package org.jeecg.modules.test.seata.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @Description: 账户
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Data
+@Builder
+@TableName("account")
+public class SeataAccount {
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 余额
+     */
+    private Double balance;
+
+    private Date lastUpdateTime;
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataOrder.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataOrder.java
new file mode 100644
index 0000000..3670d40
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataOrder.java
@@ -0,0 +1,44 @@
+package org.jeecg.modules.test.seata.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Builder;
+import lombok.Data;
+import org.jeecg.modules.test.seata.enums.OrderStatus;
+
+/**
+ * @Description: 订单
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Builder
+@Data
+@TableName("p_order")
+public class SeataOrder {
+
+    @TableId(type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+    /**
+     * 商品ID
+     */
+    private Long productId;
+    /**
+     * 订单状态
+     */
+    private OrderStatus status;
+    /**
+     * 数量
+     */
+    private Integer amount;
+    /**
+     * 总金额
+     */
+    private Double totalPrice;
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataProduct.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataProduct.java
new file mode 100644
index 0000000..6609214
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/entity/SeataProduct.java
@@ -0,0 +1,33 @@
+package org.jeecg.modules.test.seata.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Date;
+/**
+ * @Description: 产品
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Data
+@Builder
+@TableName("product")
+public class SeataProduct {
+
+    @TableId(type = IdType.AUTO)
+    private Integer id;
+    /**
+     * 价格
+     */
+    private Double price;
+    /**
+     * 库存
+     */
+    private Integer stock;
+
+    private Date lastUpdateTime;
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/enums/OrderStatus.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/enums/OrderStatus.java
new file mode 100644
index 0000000..971945e
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/enums/OrderStatus.java
@@ -0,0 +1,22 @@
+package org.jeecg.modules.test.seata.enums;
+
+/**
+ * @Description: 订单状态
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+public enum OrderStatus {
+    /**
+     * INIT
+     */
+    INIT,
+    /**
+     * SUCCESS
+     */
+    SUCCESS,
+    /**
+     * FAIL
+     */
+    FAIL
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataAccountMapper.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataAccountMapper.java
new file mode 100644
index 0000000..f30e5d6
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataAccountMapper.java
@@ -0,0 +1,16 @@
+package org.jeecg.modules.test.seata.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.test.seata.entity.SeataAccount;
+
+/**
+ * @Description: TODO
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Mapper
+public interface SeataAccountMapper extends BaseMapper<SeataAccount> {
+
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataOrderMapper.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataOrderMapper.java
new file mode 100644
index 0000000..9e453fc
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataOrderMapper.java
@@ -0,0 +1,17 @@
+package org.jeecg.modules.test.seata.mapper;
+
+/**
+ * @Description: TODO
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.test.seata.entity.SeataOrder;
+
+@Mapper
+public interface SeataOrderMapper extends BaseMapper<SeataOrder> {
+
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataProductMapper.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataProductMapper.java
new file mode 100644
index 0000000..e2edaf2
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/mapper/SeataProductMapper.java
@@ -0,0 +1,15 @@
+package org.jeecg.modules.test.seata.mapper;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.jeecg.modules.test.seata.entity.SeataProduct;
+
+/**
+ * @Description: TODO
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Mapper
+public interface SeataProductMapper extends BaseMapper<SeataProduct> {
+
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataAccountService.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataAccountService.java
new file mode 100644
index 0000000..f74bc5a
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataAccountService.java
@@ -0,0 +1,15 @@
+package org.jeecg.modules.test.seata.service;
+
+/**
+ * @Description: 账户接口
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+public interface SeataAccountService {
+    /**
+     * @param userId 用户 ID
+     * @param price  扣减金额
+     */
+    void reduceBalance(Long userId, Double price);
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataOrderService.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataOrderService.java
new file mode 100644
index 0000000..ef1f28c
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataOrderService.java
@@ -0,0 +1,18 @@
+package org.jeecg.modules.test.seata.service;
+
+import org.jeecg.modules.test.seata.dto.PlaceOrderRequest;
+
+/**
+ * @Description: 订单接口
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+public interface SeataOrderService {
+    /**
+     * 下单
+     *
+     * @param placeOrderRequest 订单请求参数
+     */
+    void placeOrder(PlaceOrderRequest placeOrderRequest);
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataProductService.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataProductService.java
new file mode 100644
index 0000000..1d617f6
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/SeataProductService.java
@@ -0,0 +1,18 @@
+package org.jeecg.modules.test.seata.service;
+
+/**
+ * @Description: 产品接口
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+public interface SeataProductService {
+    /**
+     * 扣减库存
+     *
+     * @param productId 商品 ID
+     * @param amount    扣减数量
+     * @return 商品总价
+     */
+    Double reduceStock(Long productId, Integer amount);
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataAccountServiceImpl.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataAccountServiceImpl.java
new file mode 100644
index 0000000..2cc64fe
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataAccountServiceImpl.java
@@ -0,0 +1,52 @@
+package org.jeecg.modules.test.seata.service.impl;
+
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.modules.test.seata.entity.SeataAccount;
+import org.jeecg.modules.test.seata.mapper.SeataAccountMapper;
+import org.jeecg.modules.test.seata.service.SeataAccountService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+
+import javax.annotation.Resource;
+
+/**
+ * @Description: TODO
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Slf4j
+@Service
+public class SeataAccountServiceImpl implements SeataAccountService {
+    @Resource
+    private SeataAccountMapper accountMapper;
+
+    /**
+     * 事务传播特性设置为 REQUIRES_NEW 开启新的事务
+     */
+    @DS("account")
+    @Override
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    public void reduceBalance(Long userId, Double price) {
+        log.info("=============ACCOUNT START=================");
+        SeataAccount account = accountMapper.selectById(userId);
+        Assert.notNull(account, "用户不存在");
+        Double balance = account.getBalance();
+        log.info("下单用户{}余额为 {},商品总价为{}", userId, balance, price);
+
+        if (balance < price) {
+            log.warn("用户 {} 余额不足,当前余额:{}", userId, balance);
+            throw new RuntimeException("余额不足");
+        }
+        log.info("开始扣减用户 {} 余额", userId);
+        double currentBalance = account.getBalance() - price;
+        account.setBalance(currentBalance);
+        accountMapper.updateById(account);
+        log.info("扣减用户 {} 余额成功,扣减后用户账户余额为{}", userId, currentBalance);
+        log.info("=============ACCOUNT END=================");
+    }
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataOrderServiceImpl.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataOrderServiceImpl.java
new file mode 100644
index 0000000..5cb050b
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataOrderServiceImpl.java
@@ -0,0 +1,67 @@
+package org.jeecg.modules.test.seata.service.impl;
+import com.baomidou.dynamic.datasource.annotation.DS;
+
+import io.seata.spring.annotation.GlobalTransactional;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.modules.test.seata.dto.PlaceOrderRequest;
+import org.jeecg.modules.test.seata.entity.SeataOrder;
+import org.jeecg.modules.test.seata.enums.OrderStatus;
+import org.jeecg.modules.test.seata.mapper.SeataOrderMapper;
+import org.jeecg.modules.test.seata.service.SeataAccountService;
+import org.jeecg.modules.test.seata.service.SeataOrderService;
+import org.jeecg.modules.test.seata.service.SeataProductService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+/**
+ * @Description: 订单服务类
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Slf4j
+@Service
+public class SeataOrderServiceImpl implements SeataOrderService {
+
+    @Resource
+    private SeataOrderMapper orderMapper;
+    @Autowired
+    private SeataAccountService accountService;
+    @Autowired
+    private SeataProductService productService;
+
+    @DS("order")
+    @Override
+    @Transactional
+    @GlobalTransactional
+    public void placeOrder(PlaceOrderRequest request) {
+        log.info("=============ORDER START=================");
+        Long userId = request.getUserId();
+        Long productId = request.getProductId();
+        Integer amount = request.getAmount();
+        log.info("收到下单请求,用户:{}, 商品:{},数量:{}", userId, productId, amount);
+
+
+        SeataOrder order = SeataOrder.builder()
+                .userId(userId)
+                .productId(productId)
+                .status(OrderStatus.INIT)
+                .amount(amount)
+                .build();
+
+        orderMapper.insert(order);
+        log.info("订单一阶段生成,等待扣库存付款中");
+        // 扣减库存并计算总价
+        Double totalPrice = productService.reduceStock(productId, amount);
+        // 扣减余额
+        accountService.reduceBalance(userId, totalPrice);
+
+        order.setStatus(OrderStatus.SUCCESS);
+        order.setTotalPrice(totalPrice);
+        orderMapper.updateById(order);
+        log.info("订单已成功下单");
+        log.info("=============ORDER END=================");
+    }
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataProductServiceImpl.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataProductServiceImpl.java
new file mode 100644
index 0000000..25e57a7
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/java/org/jeecg/modules/test/seata/service/impl/SeataProductServiceImpl.java
@@ -0,0 +1,57 @@
+package org.jeecg.modules.test.seata.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import lombok.extern.slf4j.Slf4j;
+
+import org.jeecg.modules.test.seata.entity.SeataProduct;
+import org.jeecg.modules.test.seata.mapper.SeataProductMapper;
+import org.jeecg.modules.test.seata.service.SeataProductService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Propagation;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.Assert;
+
+import javax.annotation.Resource;
+
+/**
+ * @Description: 产品服务类
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Slf4j
+@Service
+public class SeataProductServiceImpl implements SeataProductService {
+
+    @Resource
+    private SeataProductMapper productMapper;
+
+    /**
+     * 事务传播特性设置为 REQUIRES_NEW 开启新的事务
+     */
+    @DS("product")
+    @Transactional(propagation = Propagation.REQUIRES_NEW)
+    @Override
+    public Double reduceStock(Long productId, Integer amount) {
+        log.info("=============PRODUCT START=================");
+        // 检查库存
+        SeataProduct product = productMapper.selectById(productId);
+        Assert.notNull(product, "商品不存在");
+        Integer stock = product.getStock();
+        log.info("商品编号为 {} 的库存为{},订单商品数量为{}", productId, stock, amount);
+
+        if (stock < amount) {
+            log.warn("商品编号为{} 库存不足,当前库存:{}", productId, stock);
+            throw new RuntimeException("库存不足");
+        }
+        log.info("开始扣减商品编号为 {} 库存,单价商品价格为{}", productId, product.getPrice());
+        // 扣减库存
+        int currentStock = stock - amount;
+        product.setStock(currentStock);
+        productMapper.updateById(product);
+        double totalPrice = product.getPrice() * amount;
+        log.info("扣减商品编号为 {} 库存成功,扣减后库存为{}, {} 件商品总价为 {} ", productId, currentStock, amount, totalPrice);
+        log.info("=============PRODUCT END=================");
+        return totalPrice;
+    }
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/application-seata.yml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/application-seata.yml
new file mode 100644
index 0000000..399840d
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/application-seata.yml
@@ -0,0 +1,38 @@
+seata:
+  enable-auto-data-source-proxy: false
+  service:
+    grouplist:
+      default: 127.0.0.1:8091
+    vgroup-mapping:
+      springboot-seata-group: default
+  # seata 事务组编号 用于TC集群名
+  tx-service-group: springboot-seata-group
+  transport:
+    heartbeat: false
+spring:
+  datasource:
+    dynamic:
+      seata: true    # 开启对 seata的支持
+      seata-mode: AT #支持XA及AT模式,默认AT
+      datasource:
+        # 设置 账号数据源配置
+        account:
+          driver-class-name: com.mysql.cj.jdbc.Driver
+          url: jdbc:mysql://127.0.0.1:3306/jeecg-account?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
+          username: root
+          password: root
+          schema: classpath:sql/schema-account.sql
+        # 设置 订单数据源配置
+        order:
+          driver-class-name: com.mysql.cj.jdbc.Driver
+          url: jdbc:mysql://127.0.0.1:3306/jeecg-order?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
+          username: root
+          password: root
+          schema: classpath:sql/schema-order.sql
+        # 设置商品 数据源配置
+        product:
+          driver-class-name: com.mysql.cj.jdbc.Driver
+          url: jdbc:mysql://127.0.0.1:3306/jeecg-product?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true&useSSL=false
+          username: root
+          password: root
+          schema: classpath:sql/schema-product.sql
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-account.sql b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-account.sql
new file mode 100644
index 0000000..e50abac
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-account.sql
@@ -0,0 +1,29 @@
+DROP TABLE IF EXISTS account;
+CREATE TABLE account
+(
+    id               INT(11) NOT NULL AUTO_INCREMENT,
+    balance          DOUBLE   DEFAULT NULL,
+    last_update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    PRIMARY KEY (id)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8;
+
+DROP TABLE IF EXISTS undo_log;
+CREATE TABLE undo_log
+(
+    id            BIGINT(20) NOT NULL AUTO_INCREMENT,
+    branch_id     BIGINT(20) NOT NULL,
+    xid           VARCHAR(100) NOT NULL,
+    context       VARCHAR(128) NOT NULL,
+    rollback_info LONGBLOB     NOT NULL,
+    log_status    INT(11) NOT NULL,
+    log_created   DATETIME     NOT NULL,
+    log_modified  DATETIME     NOT NULL,
+    PRIMARY KEY (id),
+    UNIQUE KEY ux_undo_log (xid, branch_id)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8;
+INSERT INTO account (id, balance)
+VALUES (1, 50);
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-order.sql b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-order.sql
new file mode 100644
index 0000000..52165a1
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-order.sql
@@ -0,0 +1,32 @@
+DROP TABLE IF EXISTS p_order;
+CREATE TABLE p_order
+(
+    id               INT(11) NOT NULL AUTO_INCREMENT,
+    user_id          INT(11) DEFAULT NULL,
+    product_id       INT(11) DEFAULT NULL,
+    amount           INT(11) DEFAULT NULL,
+    total_price      DOUBLE       DEFAULT NULL,
+    status           VARCHAR(100) DEFAULT NULL,
+    add_time         DATETIME     DEFAULT CURRENT_TIMESTAMP,
+    last_update_time DATETIME     DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    PRIMARY KEY (id)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8;
+
+DROP TABLE IF EXISTS undo_log;
+CREATE TABLE undo_log
+(
+    id            BIGINT(20) NOT NULL AUTO_INCREMENT,
+    branch_id     BIGINT(20) NOT NULL,
+    xid           VARCHAR(100) NOT NULL,
+    context       VARCHAR(128) NOT NULL,
+    rollback_info LONGBLOB     NOT NULL,
+    log_status    INT(11) NOT NULL,
+    log_created   DATETIME     NOT NULL,
+    log_modified  DATETIME     NOT NULL,
+    PRIMARY KEY (id),
+    UNIQUE KEY ux_undo_log (xid, branch_id)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8;
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-product.sql b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-product.sql
new file mode 100644
index 0000000..b634e93
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/schema-product.sql
@@ -0,0 +1,31 @@
+DROP TABLE IF EXISTS product;
+CREATE TABLE product
+(
+    id               INT(11) NOT NULL AUTO_INCREMENT,
+    price            DOUBLE   DEFAULT NULL,
+    stock            INT(11) DEFAULT NULL,
+    last_update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+    PRIMARY KEY (id)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8;
+
+DROP TABLE IF EXISTS undo_log;
+CREATE TABLE undo_log
+(
+    id            BIGINT(20) NOT NULL AUTO_INCREMENT,
+    branch_id     BIGINT(20) NOT NULL,
+    xid           VARCHAR(100) NOT NULL,
+    context       VARCHAR(128) NOT NULL,
+    rollback_info LONGBLOB     NOT NULL,
+    log_status    INT(11) NOT NULL,
+    log_created   DATETIME     NOT NULL,
+    log_modified  DATETIME     NOT NULL,
+    PRIMARY KEY (id),
+    UNIQUE KEY ux_undo_log (xid, branch_id)
+) ENGINE = InnoDB
+  AUTO_INCREMENT = 1
+  DEFAULT CHARSET = utf8;
+
+INSERT INTO product (id, price, stock)
+VALUES (1, 10, 20);
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/seata.sql b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/seata.sql
new file mode 100644
index 0000000..d9c9766
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/seata.sql
@@ -0,0 +1,79 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server         : localhost
+ Source Server Type    : MariaDB
+ Source Server Version : 100316
+ Source Host           : localhost:3300
+ Source Schema         : seata
+
+ Target Server Type    : MariaDB
+ Target Server Version : 100316
+ File Encoding         : 65001
+
+ Date: 05/01/2022 20:25:07
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for branch_table
+-- ----------------------------
+DROP TABLE IF EXISTS `branch_table`;
+CREATE TABLE `branch_table`  (
+  `branch_id` bigint(20) NOT NULL,
+  `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+  `transaction_id` bigint(20) NULL DEFAULT NULL,
+  `resource_group_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `branch_type` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `status` tinyint(4) NULL DEFAULT NULL,
+  `client_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `gmt_create` datetime(6) NULL DEFAULT NULL,
+  `gmt_modified` datetime(6) NULL DEFAULT NULL,
+  PRIMARY KEY (`branch_id`) USING BTREE,
+  INDEX `idx_xid`(`xid`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for global_table
+-- ----------------------------
+DROP TABLE IF EXISTS `global_table`;
+CREATE TABLE `global_table`  (
+  `xid` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+  `transaction_id` bigint(20) NULL DEFAULT NULL,
+  `status` tinyint(4) NOT NULL,
+  `application_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `transaction_service_group` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `transaction_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `timeout` int(11) NULL DEFAULT NULL,
+  `begin_time` bigint(20) NULL DEFAULT NULL,
+  `application_data` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `gmt_create` datetime(0) NULL DEFAULT NULL,
+  `gmt_modified` datetime(0) NULL DEFAULT NULL,
+  PRIMARY KEY (`xid`) USING BTREE,
+  INDEX `idx_gmt_modified_status`(`gmt_modified`, `status`) USING BTREE,
+  INDEX `idx_transaction_id`(`transaction_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Table structure for lock_table
+-- ----------------------------
+DROP TABLE IF EXISTS `lock_table`;
+CREATE TABLE `lock_table`  (
+  `row_key` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
+  `xid` varchar(96) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `transaction_id` bigint(20) NULL DEFAULT NULL,
+  `branch_id` bigint(20) NOT NULL,
+  `resource_id` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `table_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `pk` varchar(36) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
+  `gmt_create` datetime(0) NULL DEFAULT NULL,
+  `gmt_modified` datetime(0) NULL DEFAULT NULL,
+  PRIMARY KEY (`row_key`) USING BTREE,
+  INDEX `idx_branch_id`(`branch_id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/undo_log.sql b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/undo_log.sql
new file mode 100644
index 0000000..18fd03d
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-seata/src/main/resources/sql/undo_log.sql
@@ -0,0 +1,12 @@
+CREATE TABLE `undo_log` (
+                            `id` bigint(20) NOT NULL AUTO_INCREMENT,
+                            `branch_id` bigint(20) NOT NULL,
+                            `xid` varchar(100) NOT NULL,
+                            `context` varchar(128) NOT NULL,
+                            `rollback_info` longblob NOT NULL,
+                            `log_status` int(11) NOT NULL,
+                            `log_created` datetime NOT NULL,
+                            `log_modified` datetime NOT NULL,
+                            PRIMARY KEY (`id`),
+                            UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
+) ENGINE=InnoDB AUTO_INCREMENT=137 DEFAULT CHARSET=utf8;
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/doc/db.sql b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/doc/db.sql
new file mode 100644
index 0000000..8dc3765
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/doc/db.sql
@@ -0,0 +1,46 @@
+CREATE TABLE `sys_log0` (
+  `id` varchar(32) NOT NULL,
+  `log_type` int(2) DEFAULT NULL COMMENT '日志类型(1登录日志,2操作日志)',
+  `log_content` varchar(1000) DEFAULT NULL COMMENT '日志内容',
+  `operate_type` int(2) DEFAULT NULL COMMENT '操作类型',
+  `userid` varchar(32) DEFAULT NULL COMMENT '操作用户账号',
+  `username` varchar(100) DEFAULT NULL COMMENT '操作用户名称',
+  `ip` varchar(100) DEFAULT NULL COMMENT 'IP',
+  `method` varchar(500) DEFAULT NULL COMMENT '请求java方法',
+  `request_url` varchar(255) DEFAULT NULL COMMENT '请求路径',
+  `request_param` longtext DEFAULT NULL COMMENT '请求参数',
+  `request_type` varchar(10) DEFAULT NULL COMMENT '请求类型',
+  `cost_time` bigint(20) DEFAULT NULL COMMENT '耗时',
+  `create_by` varchar(32) DEFAULT NULL COMMENT '创建人',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  `update_by` varchar(32) DEFAULT NULL COMMENT '更新人',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `index_table_userid` (`userid`) USING BTREE,
+  KEY `index_logt_ype` (`log_type`) USING BTREE,
+  KEY `index_operate_type` (`operate_type`) USING BTREE,
+  KEY `index_createtime` (`create_time`) USING BTREE
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='系统日志表';
+CREATE TABLE `sys_log1` (
+  `id` varchar(32) NOT NULL,
+  `log_type` int(2) DEFAULT NULL COMMENT '日志类型(1登录日志,2操作日志)',
+  `log_content` varchar(1000) DEFAULT NULL COMMENT '日志内容',
+  `operate_type` int(2) DEFAULT NULL COMMENT '操作类型',
+  `userid` varchar(32) DEFAULT NULL COMMENT '操作用户账号',
+  `username` varchar(100) DEFAULT NULL COMMENT '操作用户名称',
+  `ip` varchar(100) DEFAULT NULL COMMENT 'IP',
+  `method` varchar(500) DEFAULT NULL COMMENT '请求java方法',
+  `request_url` varchar(255) DEFAULT NULL COMMENT '请求路径',
+  `request_param` longtext DEFAULT NULL COMMENT '请求参数',
+  `request_type` varchar(10) DEFAULT NULL COMMENT '请求类型',
+  `cost_time` bigint(20) DEFAULT NULL COMMENT '耗时',
+  `create_by` varchar(32) DEFAULT NULL COMMENT '创建人',
+  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
+  `update_by` varchar(32) DEFAULT NULL COMMENT '更新人',
+  `update_time` datetime DEFAULT NULL COMMENT '更新时间',
+  PRIMARY KEY (`id`) USING BTREE,
+  KEY `index_table_userid` (`userid`) USING BTREE,
+  KEY `index_logt_ype` (`log_type`) USING BTREE,
+  KEY `index_operate_type` (`operate_type`) USING BTREE,
+  KEY `index_createtime` (`create_time`) USING BTREE
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC COMMENT='系统日志表';
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/pom.xml
new file mode 100644
index 0000000..5820611
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/pom.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>jeecg-cloud-test</artifactId>
+        <groupId>org.jeecgframework.boot</groupId>
+        <version>3.1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>jeecg-cloud-test-shardingsphere</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>jeecg-boot-starter-shardingsphere</artifactId>
+            <version>3.1.0</version>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/algorithm/StandardModTableShardAlgorithm.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/algorithm/StandardModTableShardAlgorithm.java
new file mode 100644
index 0000000..73f27a5
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/algorithm/StandardModTableShardAlgorithm.java
@@ -0,0 +1,86 @@
+package org.jeecg.modules.test.sharding.algorithm;
+
+
+import org.apache.shardingsphere.sharding.api.sharding.standard.PreciseShardingValue;
+import org.apache.shardingsphere.sharding.api.sharding.standard.RangeShardingValue;
+import org.apache.shardingsphere.sharding.api.sharding.standard.StandardShardingAlgorithm;
+
+import java.util.Collection;
+import java.util.Properties;
+
+/**
+ * 用于处理使用单一键
+ * 根据分片字段的值和sharding-count进行取模运算
+ * SQL 语句中有>,>=, <=,<,=,IN 和 BETWEEN AND 操作符,都可以应用此分片策略。
+ *
+ * @author zyf
+ */
+public class StandardModTableShardAlgorithm implements StandardShardingAlgorithm<Integer> {
+    private Properties props = new Properties();
+
+
+    /**
+     * 用于处理=和IN的分片
+     *
+     * @param collection           目标分片的集合(表名)
+     * @param preciseShardingValue 逻辑表相关信息
+     * @return
+     */
+    @Override
+    public String doSharding(Collection<String> collection, PreciseShardingValue<Integer> preciseShardingValue) {
+
+        for (String name : collection) {
+            Integer value = preciseShardingValue.getValue();
+            //根据值进行取模,得到一个目标值
+            if (name.indexOf(value % 2+"") > -1) {
+                return name;
+            }
+        }
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * 用于处理BETWEEN AND分片,如果不配置RangeShardingAlgorithm,SQL中的BETWEEN AND将按照全库路由处理
+     *
+     * @param collection
+     * @param rangeShardingValue
+     * @return
+     */
+    @Override
+    public Collection<String> doSharding(Collection<String> collection, RangeShardingValue<Integer> rangeShardingValue) {
+
+        return collection;
+    }
+
+    /**
+     * 初始化对象的时候调用的方法
+     */
+    @Override
+    public void init() {
+    }
+
+    /**
+     * 对应分片算法(sharding-algorithms)的类型
+     *
+     * @return
+     */
+    @Override
+    public String getType() {
+        return "STANDARD_MOD";
+    }
+
+    @Override
+    public Properties getProps() {
+        return this.props;
+    }
+
+    /**
+     * 获取分片相关属性
+     *
+     * @param properties
+     */
+    @Override
+    public void setProps(Properties properties) {
+        this.props = properties;
+    }
+}
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/controller/JeecgShardingDemoController.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/controller/JeecgShardingDemoController.java
new file mode 100644
index 0000000..6dc0ab2
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/controller/JeecgShardingDemoController.java
@@ -0,0 +1,49 @@
+package org.jeecg.modules.test.sharding.controller;
+
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.modules.test.sharding.entity.ShardingSysLog;
+import org.jeecg.modules.test.sharding.service.IShardingSysLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @Description: 分库分表测试
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+@Slf4j
+@Api(tags = "分库分表测试")
+@RestController
+@RequestMapping("/sharding/")
+public class JeecgShardingDemoController extends JeecgController<ShardingSysLog, IShardingSysLogService> {
+    @Autowired
+    private IShardingSysLogService shardingSysLogService;
+
+    /**
+     * 添加
+     * @return
+     */
+    @PostMapping(value = "/add")
+    @AutoLog(value = "分库分表添加")
+    @ApiOperation(value = "分库分表添加", notes = "分库分表添加")
+    public Result<?> add() {
+        for (int i = 0; i < 10; i++) {
+            ShardingSysLog shardingSysLog = new ShardingSysLog();
+            shardingSysLog.setLogContent("jeecg");
+            shardingSysLog.setLogType(i);
+            shardingSysLog.setOperateType(i);
+            shardingSysLogService.save(shardingSysLog);
+        }
+        return Result.OK();
+    }
+
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/entity/ShardingSysLog.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/entity/ShardingSysLog.java
new file mode 100644
index 0000000..069120e
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/entity/ShardingSysLog.java
@@ -0,0 +1,109 @@
+package org.jeecg.modules.test.sharding.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.aspect.annotation.Dict;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <p>
+ * 系统日志表
+ * </p>
+ */
+@Data
+@TableName("sys_log")
+public class ShardingSysLog implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * id
+     */
+    @TableId(type = IdType.ASSIGN_ID)
+    private String id;
+
+    /**
+     * 创建人
+     */
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /**
+     * 更新人
+     */
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+    /**
+     * 耗时
+     */
+    private Long costTime;
+
+    /**
+     * IP
+     */
+    private String ip;
+
+    /**
+     * 请求参数
+     */
+    private String requestParam;
+
+    /**
+     * 请求类型
+     */
+    private String requestType;
+
+    /**
+     * 请求路径
+     */
+    private String requestUrl;
+    /**
+     * 请求方法
+     */
+    private String method;
+
+    /**
+     * 操作人用户名称
+     */
+    private String username;
+    /**
+     * 操作人用户账户
+     */
+    private String userid;
+    /**
+     * 操作详细日志
+     */
+    private String logContent;
+
+    /**
+     * 日志类型(1登录日志,2操作日志)
+     */
+    @Dict(dicCode = "log_type")
+    private Integer logType;
+
+    /**
+     * 操作类型(1查询,2添加,3修改,4删除,5导入,6导出)
+     */
+    @Dict(dicCode = "operate_type")
+    private Integer operateType;
+
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/ShardingSysLogMapper.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/ShardingSysLogMapper.java
new file mode 100644
index 0000000..b9e576e
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/ShardingSysLogMapper.java
@@ -0,0 +1,15 @@
+package org.jeecg.modules.test.sharding.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.modules.test.sharding.entity.ShardingSysLog;
+
+
+/**
+ * @Description: 系统日志表 Mapper 接口
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+public interface ShardingSysLogMapper extends BaseMapper<ShardingSysLog> {
+
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/xml/ShardingSysLogMapper.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/xml/ShardingSysLogMapper.xml
new file mode 100644
index 0000000..5baff85
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/mapper/xml/ShardingSysLogMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.jeecg.modules.demo.sharding.mapper.ShardingSysLogMapper">
+
+</mapper>
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/IShardingSysLogService.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/IShardingSysLogService.java
new file mode 100644
index 0000000..337dafc
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/IShardingSysLogService.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.test.sharding.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.modules.test.sharding.entity.ShardingSysLog;
+
+/**
+ * @Description:  系统日志表 服务类
+ * @author: zyf
+ * @date: 2022/01/24
+ * @version: V1.0
+ */
+public interface IShardingSysLogService extends IService<ShardingSysLog> {
+
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/impl/ShardingSysLogServiceImpl.java b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/impl/ShardingSysLogServiceImpl.java
new file mode 100644
index 0000000..b063e88
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/java/org/jeecg/modules/test/sharding/service/impl/ShardingSysLogServiceImpl.java
@@ -0,0 +1,19 @@
+package org.jeecg.modules.test.sharding.service.impl;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.modules.test.sharding.entity.ShardingSysLog;
+import org.jeecg.modules.test.sharding.mapper.ShardingSysLogMapper;
+import org.jeecg.modules.test.sharding.service.IShardingSysLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 系统日志表 服务实现类
+ * </p>
+ */
+@Service
+@DS("sharding")
+public class ShardingSysLogServiceImpl extends ServiceImpl<ShardingSysLogMapper, ShardingSysLog> implements IShardingSysLogService {
+
+}
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/resources/application-sharding.yml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/resources/application-sharding.yml
new file mode 100644
index 0000000..6a45828
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/jeecg-cloud-test-shardingsphere/src/main/resources/application-sharding.yml
@@ -0,0 +1,42 @@
+spring:
+  shardingsphere:
+    props:
+      sql-show: true
+    datasource:
+      ds0:
+        driverClassName: com.mysql.cj.jdbc.Driver
+        url: jdbc:mysql://localhost:3306/jeecg-boot?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
+        username: root
+        type: com.alibaba.druid.pool.DruidDataSource
+        password: root
+      names: ds0
+    # 规则配置
+    rules:
+      sharding:
+        # 配置绑定表,每一行为一组
+        binding-tables: sys_log
+        # 分布式序列算法配置
+        key-generators:
+          snowflake:
+            type: SNOWFLAKE
+            props:
+              worker-id: 123
+        # 分片算法配置
+        sharding-algorithms:
+          table-classbased:
+            props:
+              strategy: standard
+              algorithmClassName: org.jeecg.modules.test.sharding.algorithm.StandardModTableShardAlgorithm
+            type: CLASS_BASED
+        tables:
+          # 逻辑表名称
+          sys_log:
+            #配置具体表的数据节点
+            actual-data-nodes: ds0.sys_log$->{0..1}
+            # 分表策略
+            table-strategy:
+              standard:
+                # 分片算法名称
+                sharding-algorithm-name: table-classbased
+                # 分片列名称
+                sharding-column: log_type
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/pom.xml
new file mode 100644
index 0000000..e329b61
--- /dev/null
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-test/pom.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>jeecg-cloud-module</artifactId>
+        <groupId>org.jeecgframework.boot</groupId>
+        <version>3.1.0</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>pom</packaging>
+    <artifactId>jeecg-cloud-test</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jeecgframework.boot</groupId>
+            <artifactId>jeecg-boot-base-core</artifactId>
+        </dependency>
+    </dependencies>
+
+    <modules>
+        <module>jeecg-cloud-test-seata</module>
+        <module>jeecg-cloud-test-shardingsphere</module>
+    </modules>
+</project>
\ No newline at end of file
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile
index 67bd475..c446953 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/Dockerfile
@@ -10,7 +10,7 @@ WORKDIR /jeecg-cloud-xxljob
 
 EXPOSE 9080
 
-ADD ./target/jeecg-cloud-xxljob-3.0.jar ./
+ADD ./target/jeecg-cloud-xxljob-3.1.0.jar ./
 
-CMD java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-xxljob-3.0.jar
+CMD java -Dfile.encoding=utf-8 -Djava.security.egd=file:/dev/./urandom -jar jeecg-cloud-xxljob-3.1.0.jar
 
diff --git a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml
index eff6960..4aa3b52 100644
--- a/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml
+++ b/jeecg-boot/jeecg-cloud-module/jeecg-cloud-xxljob/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-cloud-module</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
diff --git a/jeecg-boot/jeecg-cloud-module/pom.xml b/jeecg-boot/jeecg-cloud-module/pom.xml
index 5a67552..ed73172 100644
--- a/jeecg-boot/jeecg-cloud-module/pom.xml
+++ b/jeecg-boot/jeecg-cloud-module/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <artifactId>jeecg-boot-parent</artifactId>
         <groupId>org.jeecgframework.boot</groupId>
-        <version>3.0</version>
+        <version>3.1.0</version>
     </parent>
     <modelVersion>4.0.0</modelVersion>
 
@@ -18,6 +18,7 @@
         <module>jeecg-cloud-monitor</module>
         <module>jeecg-cloud-system-start</module>
         <module>jeecg-cloud-xxljob</module>
+        <module>jeecg-cloud-test</module>
     </modules>
 
 
diff --git a/jeecg-boot/pom.xml b/jeecg-boot/pom.xml
index e190e08..7dd4829 100644
--- a/jeecg-boot/pom.xml
+++ b/jeecg-boot/pom.xml
@@ -2,7 +2,7 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.jeecgframework.boot</groupId>
   <artifactId>jeecg-boot-parent</artifactId>
-  <version>3.0</version>
+  <version>3.1.0</version>
   <packaging>pom</packaging>
   
   	<parent>
@@ -13,7 +13,7 @@
 	</parent>
 
 	<properties>
-		<jeecgboot.version>3.0</jeecgboot.version>
+		<jeecgboot.version>3.1.0</jeecgboot.version>
 		<java.version>1.8</java.version>
 		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <spring-cloud.version>Hoxton.SR8</spring-cloud.version>
@@ -42,12 +42,12 @@
 		<java-jwt.version>3.11.0</java-jwt.version>
 		<shiro-redis.version>3.1.0</shiro-redis.version>
 		<codegenerate.version>1.3.7</codegenerate.version>
-		<autopoi-web.version>1.3.6</autopoi-web.version>
+		<autopoi-web.version>1.3.9</autopoi-web.version>
 		<minio.version>8.0.3</minio.version>
 		<justauth-spring-boot-starter.version>1.3.4</justauth-spring-boot-starter.version>
 		<dom4j.version>1.6.1</dom4j.version>
 		<qiniu-java-sdk.version>7.4.0</qiniu-java-sdk.version>
-		<!-- Log4j2惊爆0Day漏洞-->
+		<!-- Log4j2爆雷漏洞 -->
 		<log4j2.version>2.17.0</log4j2.version>
 		<logback.version>1.2.9</logback.version>
 	</properties>
@@ -366,6 +366,10 @@
                 <config.server-addr>127.0.0.1:8848</config.server-addr>
                 <!--Nacos配置中心命名空间,用于支持多环境.这里必须使用ID,不能使用名称,默认为空-->
                 <config.namespace></config.namespace>
+				<!--Nacos用户名-->
+				<config.username>nacos</config.username>
+				<!--Nacos密码-->
+				<config.password>nacos</config.password>
                 <!--Nacos配置分组名称-->
                 <config.group>DEFAULT_GROUP</config.group>
                 <!--Nacos服务发现地址-->
@@ -384,6 +388,10 @@
                 <config.server-addr>127.0.0.1:8848</config.server-addr>
                 <!--Nacos配置中心命名空间,用于支持多环境.这里必须使用ID,不能使用名称,默认为空-->
                 <config.namespace></config.namespace>
+				<!--Nacos用户名-->
+				<config.username>nacos</config.username>
+				<!--Nacos密码-->
+				<config.password>nacos</config.password>
                 <!--Nacos配置分组名称-->
                 <config.group>DEFAULT_GROUP</config.group>
                 <!--Nacos服务发现地址-->
@@ -402,6 +410,10 @@
                 <config.server-addr>127.0.0.1:8848</config.server-addr>
                 <!--Nacos配置中心命名空间,用于支持多环境.这里必须使用ID,不能使用名称,默认为空-->
                 <config.namespace></config.namespace>
+				<!--Nacos用户名-->
+				<config.username>nacos</config.username>
+				<!--Nacos密码-->
+				<config.password>nacos</config.password>
                 <!--Nacos配置分组名称-->
                 <config.group>DEFAULT_GROUP</config.group>
                 <!--Nacos服务发现地址-->
--
libgit2 0.22.2