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