From a2fbe479d86e28551318159ab33c32e96ef153de Mon Sep 17 00:00:00 2001 From: Jerry <707344974@qq.com> Date: Mon, 27 Sep 2021 15:37:18 +0800 Subject: [PATCH] =?UTF-8?q?commit=EF=BC=9A=E6=94=AF=E6=8C=81flowable?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../orange-demo-flowable-service/.gitignore | 26 + .../orange-demo-flowable-service/README.md | 15 + .../application-webadmin/pom.xml | 82 + .../demo/webadmin/WebAdminApplication.java | 23 + .../app/controller/AreaCodeController.java | 72 + .../demo/webadmin/app/dao/AreaCodeMapper.java | 13 + .../app/dao/mapper/AreaCodeMapper.xml | 10 + .../demo/webadmin/app/model/AreaCode.java | 39 + .../webadmin/app/service/AreaCodeService.java | 23 + .../app/service/impl/AreaCodeServiceImpl.java | 52 + .../app/util/FlowDeptPostExtHelper.java | 45 + .../flow/demo/webadmin/app/vo/AreaCodeVo.java | 33 + .../webadmin/config/ApplicationConfig.java | 51 + .../demo/webadmin/config/DataSourceType.java | 36 + .../demo/webadmin/config/FilterConfig.java | 57 + .../webadmin/config/InterceptorConfig.java | 21 + .../config/MultiDataSourceConfig.java | 44 + .../AuthenticationInterceptor.java | 139 + .../upms/controller/LoginController.java | 292 + .../upms/controller/LoginUserController.java | 81 + .../controller/SysDataPermController.java | 281 + .../upms/controller/SysDeptController.java | 381 + .../upms/controller/SysMenuController.java | 215 + .../controller/SysPermCodeController.java | 186 + .../upms/controller/SysPermController.java | 187 + .../controller/SysPermModuleController.java | 159 + .../upms/controller/SysPostController.java | 169 + .../upms/controller/SysRoleController.java | 317 + .../upms/controller/SysUserController.java | 241 + .../upms/dao/SysDataPermDeptMapper.java | 13 + .../webadmin/upms/dao/SysDataPermMapper.java | 35 + .../upms/dao/SysDataPermUserMapper.java | 13 + .../demo/webadmin/upms/dao/SysDeptMapper.java | 26 + .../webadmin/upms/dao/SysDeptPostMapper.java | 33 + .../upms/dao/SysDeptRelationMapper.java | 42 + .../demo/webadmin/upms/dao/SysMenuMapper.java | 54 + .../upms/dao/SysMenuPermCodeMapper.java | 13 + .../webadmin/upms/dao/SysPermCodeMapper.java | 45 + .../upms/dao/SysPermCodePermMapper.java | 13 + .../demo/webadmin/upms/dao/SysPermMapper.java | 54 + .../upms/dao/SysPermModuleMapper.java | 22 + .../upms/dao/SysPermWhitelistMapper.java | 13 + .../demo/webadmin/upms/dao/SysPostMapper.java | 52 + .../demo/webadmin/upms/dao/SysRoleMapper.java | 45 + .../webadmin/upms/dao/SysRoleMenuMapper.java | 13 + .../demo/webadmin/upms/dao/SysUserMapper.java | 108 + .../webadmin/upms/dao/SysUserPostMapper.java | 13 + .../webadmin/upms/dao/SysUserRoleMapper.java | 13 + .../upms/dao/mapper/SysDataPermDeptMapper.xml | 8 + .../upms/dao/mapper/SysDataPermMapper.xml | 62 + .../upms/dao/mapper/SysDataPermUserMapper.xml | 8 + .../upms/dao/mapper/SysDeptMapper.xml | 45 + .../upms/dao/mapper/SysDeptPostMapper.xml | 46 + .../upms/dao/mapper/SysDeptRelationMapper.xml | 29 + .../upms/dao/mapper/SysMenuMapper.xml | 109 + .../upms/dao/mapper/SysMenuPermCodeMapper.xml | 8 + .../upms/dao/mapper/SysPermCodeMapper.xml | 91 + .../upms/dao/mapper/SysPermCodePermMapper.xml | 8 + .../upms/dao/mapper/SysPermMapper.xml | 132 + .../upms/dao/mapper/SysPermModuleMapper.xml | 44 + .../dao/mapper/SysPermWhitelistMapper.xml | 9 + .../upms/dao/mapper/SysPostMapper.xml | 82 + .../upms/dao/mapper/SysRoleMapper.xml | 91 + .../upms/dao/mapper/SysRoleMenuMapper.xml | 8 + .../upms/dao/mapper/SysUserMapper.xml | 213 + .../upms/dao/mapper/SysUserPostMapper.xml | 9 + .../upms/dao/mapper/SysUserRoleMapper.xml | 8 + .../webadmin/upms/dto/SysDataPermDeptDto.java | 23 + .../webadmin/upms/dto/SysDataPermDto.java | 48 + .../demo/webadmin/upms/dto/SysDeptDto.java | 40 + .../webadmin/upms/dto/SysDeptPostDto.java | 41 + .../demo/webadmin/upms/dto/SysMenuDto.java | 69 + .../webadmin/upms/dto/SysPermCodeDto.java | 55 + .../demo/webadmin/upms/dto/SysPermDto.java | 52 + .../webadmin/upms/dto/SysPermModuleDto.java | 49 + .../demo/webadmin/upms/dto/SysPostDto.java | 41 + .../demo/webadmin/upms/dto/SysRoleDto.java | 28 + .../demo/webadmin/upms/dto/SysUserDto.java | 80 + .../demo/webadmin/upms/model/SysDataPerm.java | 113 + .../webadmin/upms/model/SysDataPermDept.java | 29 + .../webadmin/upms/model/SysDataPermUser.java | 27 + .../demo/webadmin/upms/model/SysDept.java | 81 + .../demo/webadmin/upms/model/SysDeptPost.java | 39 + .../webadmin/upms/model/SysDeptRelation.java | 31 + .../demo/webadmin/upms/model/SysMenu.java | 143 + .../webadmin/upms/model/SysMenuPermCode.java | 27 + .../demo/webadmin/upms/model/SysPerm.java | 87 + .../demo/webadmin/upms/model/SysPermCode.java | 120 + .../webadmin/upms/model/SysPermCodePerm.java | 27 + .../webadmin/upms/model/SysPermModule.java | 81 + .../webadmin/upms/model/SysPermWhitelist.java | 33 + .../demo/webadmin/upms/model/SysPost.java | 104 + .../demo/webadmin/upms/model/SysRole.java | 96 + .../demo/webadmin/upms/model/SysRoleMenu.java | 27 + .../demo/webadmin/upms/model/SysUser.java | 196 + .../demo/webadmin/upms/model/SysUserPost.java | 33 + .../demo/webadmin/upms/model/SysUserRole.java | 27 + .../upms/model/constant/SysMenuType.java | 54 + .../model/constant/SysOnlineMenuPermType.java | 44 + .../upms/model/constant/SysPermCodeType.java | 49 + .../model/constant/SysPermModuleType.java | 44 + .../upms/model/constant/SysUserStatus.java | 44 + .../upms/model/constant/SysUserType.java | 49 + .../upms/service/SysDataPermService.java | 104 + .../webadmin/upms/service/SysDeptService.java | 144 + .../webadmin/upms/service/SysMenuService.java | 111 + .../upms/service/SysPermCodeService.java | 94 + .../upms/service/SysPermModuleService.java | 63 + .../webadmin/upms/service/SysPermService.java | 117 + .../upms/service/SysPermWhitelistService.java | 23 + .../webadmin/upms/service/SysPostService.java | 99 + .../webadmin/upms/service/SysRoleService.java | 97 + .../webadmin/upms/service/SysUserService.java | 164 + .../service/impl/SysDataPermServiceImpl.java | 336 + .../upms/service/impl/SysDeptServiceImpl.java | 331 + .../upms/service/impl/SysMenuServiceImpl.java | 335 + .../service/impl/SysPermCodeServiceImpl.java | 226 + .../impl/SysPermModuleServiceImpl.java | 124 + .../upms/service/impl/SysPermServiceImpl.java | 243 + .../impl/SysPermWhitelistServiceImpl.java | 52 + .../upms/service/impl/SysPostServiceImpl.java | 188 + .../upms/service/impl/SysRoleServiceImpl.java | 221 + .../upms/service/impl/SysUserServiceImpl.java | 395 + .../webadmin/upms/vo/SysDataPermDeptVo.java | 23 + .../demo/webadmin/upms/vo/SysDataPermVo.java | 60 + .../demo/webadmin/upms/vo/SysDeptPostVo.java | 33 + .../flow/demo/webadmin/upms/vo/SysDeptVo.java | 55 + .../flow/demo/webadmin/upms/vo/SysMenuVo.java | 90 + .../demo/webadmin/upms/vo/SysPermCodeVo.java | 70 + .../webadmin/upms/vo/SysPermModuleVo.java | 65 + .../flow/demo/webadmin/upms/vo/SysPermVo.java | 70 + .../flow/demo/webadmin/upms/vo/SysPostVo.java | 61 + .../flow/demo/webadmin/upms/vo/SysRoleVo.java | 50 + .../flow/demo/webadmin/upms/vo/SysUserVo.java | 102 + .../src/main/resources/application.yml | 279 + .../src/main/resources/log4j2.xml | 86 + .../resources/template/views/print_error.ftl | 329 + .../common/common-core/pom.xml | 109 + .../core/advice/MyControllerAdvice.java | 30 + .../core/advice/MyExceptionHandler.java | 141 + .../core/annotation/DeptFilterColumn.java | 16 + .../core/annotation/DisableDataFilter.java | 17 + .../core/annotation/DisableTenantFilter.java | 28 + .../core/annotation/EnableDataPerm.java | 27 + .../core/annotation/JobUpdateTimeColumn.java | 16 + .../common/core/annotation/MyDataSource.java | 21 + .../core/annotation/MyDataSourceResolver.java | 29 + .../common/core/annotation/MyRequestBody.java | 31 + .../core/annotation/NoAuthInterface.java | 15 + .../core/annotation/RelationConstDict.java | 29 + .../common/core/annotation/RelationDict.java | 70 + .../core/annotation/RelationManyToMany.java | 38 + .../RelationManyToManyAggregation.java | 95 + .../core/annotation/RelationOneToMany.java | 53 + .../RelationOneToManyAggregation.java | 67 + .../core/annotation/RelationOneToOne.java | 60 + .../core/annotation/TenantFilterColumn.java | 16 + .../core/annotation/UploadFlagColumn.java | 24 + .../core/annotation/UserFilterColumn.java | 16 + .../common/core/aop/DataSourceAspect.java | 48 + .../core/aop/DataSourceResolveAspect.java | 62 + .../common/core/aop/DictCacheSyncAspect.java | 64 + .../common/core/base/dao/BaseDaoMapper.java | 87 + .../core/base/mapper/BaseModelMapper.java | 124 + .../core/base/mapper/DummyModelMapper.java | 58 + .../core/base/service/BaseDictService.java | 266 + .../common/core/base/service/BaseService.java | 1626 + .../core/base/service/IBaseDictService.java | 82 + .../core/base/service/IBaseService.java | 286 + .../common/core/cache/DictionaryCache.java | 88 + .../common/core/cache/MapDictionaryCache.java | 358 + .../core/cache/MapTreeDictionaryCache.java | 292 + .../core/config/CommonWebMvcConfig.java | 67 + .../core/config/DataSourceContextHolder.java | 52 + .../common/core/config/DynamicDataSource.java | 17 + .../common/core/config/EncryptConfig.java | 20 + .../core/config/RestTemplateConfig.java | 64 + .../demo/common/core/config/TomcatConfig.java | 39 + .../common/core/constant/AggregationType.java | 81 + .../common/core/constant/AppDeviceType.java | 59 + .../core/constant/ApplicationConstant.java | 85 + .../common/core/constant/ErrorCodeEnum.java | 84 + .../core/constant/GlobalDeletedFlag.java | 25 + .../exception/DataValidationException.java | 26 + .../exception/InvalidClassFieldException.java | 30 + .../exception/InvalidDataFieldException.java | 30 + .../exception/InvalidDataModelException.java | 27 + .../exception/InvalidRedisModeException.java | 27 + .../exception/MapCacheAccessException.java | 20 + .../core/exception/MyRuntimeException.java | 36 + .../core/exception/NoDataAffectException.java | 26 + .../core/exception/NoDataPermException.java | 26 + .../exception/RedisCacheAccessException.java | 20 + .../MyRequestArgumentResolver.java | 234 + .../listener/LoadServiceRelationListener.java | 28 + .../demo/common/core/object/CallResult.java | 87 + .../demo/common/core/object/DummyClass.java | 27 + .../common/core/object/GlobalThreadLocal.java | 52 + .../common/core/object/LoginUserInfo.java | 62 + .../common/core/object/MyGroupCriteria.java | 24 + .../demo/common/core/object/MyGroupParam.java | 170 + .../demo/common/core/object/MyOrderParam.java | 265 + .../demo/common/core/object/MyPageData.java | 36 + .../demo/common/core/object/MyPageParam.java | 58 + .../common/core/object/MyRelationParam.java | 91 + .../common/core/object/MyWhereCriteria.java | 361 + .../common/core/object/ResponseResult.java | 221 + .../demo/common/core/object/TokenData.java | 99 + .../flow/demo/common/core/object/Tuple2.java | 50 + .../common/core/upload/BaseUpDownloader.java | 137 + .../common/core/upload/LocalUpDownloader.java | 149 + .../core/upload/UpDownloaderFactory.java | 49 + .../core/upload/UploadResponseInfo.java | 29 + .../common/core/upload/UploadStoreInfo.java | 22 + .../core/upload/UploadStoreTypeEnum.java | 19 + .../demo/common/core/util/AopTargetUtil.java | 64 + .../core/util/ApplicationContextHolder.java | 90 + .../demo/common/core/util/ContextUtil.java | 49 + .../common/core/util/DataSourceResolver.java | 19 + .../demo/common/core/util/ExportUtil.java | 95 + .../flow/demo/common/core/util/IpUtil.java | 101 + .../flow/demo/common/core/util/JwtUtil.java | 110 + .../demo/common/core/util/LogMessageUtil.java | 33 + .../demo/common/core/util/MyCommonUtil.java | 195 + .../demo/common/core/util/MyDateUtil.java | 181 + .../demo/common/core/util/MyModelUtil.java | 713 + .../demo/common/core/util/MyPageUtil.java | 108 + .../demo/common/core/util/RedisKeyUtil.java | 86 + .../flow/demo/common/core/util/RsaUtil.java | 115 + .../flow/demo/common/core/util/TreeNode.java | 93 + .../demo/common/core/validator/AddGroup.java | 10 + .../common/core/validator/ConstDictRef.java | 48 + .../core/validator/ConstDictValidator.java | 33 + .../common/core/validator/TextLength.java | 55 + .../core/validator/TextLengthValidator.java | 39 + .../common/core/validator/UpdateGroup.java | 11 + .../common/common-datafilter/pom.xml | 29 + .../aop/DisableDataFilterAspect.java | 41 + .../config/DataFilterAutoConfig.java | 13 + .../config/DataFilterProperties.java | 44 + .../config/DataFilterWebMvcConfigurer.java | 21 + .../datafilter/constant/DataPermRuleType.java | 69 + .../interceptor/DataFilterInterceptor.java | 42 + .../MybatisDataFilterInterceptor.java | 473 + .../listener/LoadDataFilterInfoListener.java | 25 + .../main/resources/META-INF/spring.factories | 2 + .../common/common-flow-online/pom.xml | 48 + .../online/config/FlowOnlineAutoConfig.java | 13 + .../online/config/FlowOnlineProperties.java | 20 + .../FlowOnlineOperationController.java | 698 + .../service/FlowOnlineOperationService.java | 116 + .../impl/FlowOnlineOperationServiceImpl.java | 247 + .../main/resources/META-INF/spring.factories | 2 + .../common/common-flow/pom.xml | 58 + .../common/flow/config/FlowAutoConfig.java | 13 + .../common/flow/config/FlowProperties.java | 20 + .../flow/constant/FlowApprovalType.java | 84 + .../common/flow/constant/FlowConstant.java | 85 + .../common/flow/constant/FlowTaskStatus.java | 64 + .../common/flow/constant/FlowTaskType.java | 44 + .../controller/FlowCategoryController.java | 195 + .../flow/controller/FlowEntryController.java | 537 + .../FlowEntryVariableController.java | 143 + .../controller/FlowOperationController.java | 508 + .../common/flow/dao/FlowCategoryMapper.java | 26 + .../demo/common/flow/dao/FlowEntryMapper.java | 26 + .../flow/dao/FlowEntryPublishMapper.java | 13 + .../dao/FlowEntryPublishVariableMapper.java | 22 + .../flow/dao/FlowEntryVariableMapper.java | 27 + .../flow/dao/FlowTaskCommentMapper.java | 13 + .../common/flow/dao/FlowTaskExtMapper.java | 22 + .../common/flow/dao/FlowWorkOrderMapper.java | 28 + .../flow/dao/mapper/FlowCategoryMapper.xml | 21 + .../flow/dao/mapper/FlowEntryMapper.xml | 73 + .../dao/mapper/FlowEntryPublishMapper.xml | 16 + .../mapper/FlowEntryPublishVariableMapper.xml | 30 + .../dao/mapper/FlowEntryVariableMapper.xml | 41 + .../flow/dao/mapper/FlowTaskCommentMapper.xml | 17 + .../flow/dao/mapper/FlowTaskExtMapper.xml | 24 + .../flow/dao/mapper/FlowWorkOrderMapper.xml | 59 + .../demo/common/flow/dto/FlowCategoryDto.java | 41 + .../demo/common/flow/dto/FlowEntryDto.java | 77 + .../common/flow/dto/FlowEntryVariableDto.java | 70 + .../common/flow/dto/FlowTaskCommentDto.java | 33 + .../common/flow/dto/FlowWorkOrderDto.java | 28 + .../exception/FlowOperationException.java | 35 + .../flow/listener/DeptPostLeaderListener.java | 34 + .../listener/UpDeptPostLeaderListener.java | 34 + .../listener/UpdateFlowStatusListener.java | 31 + .../demo/common/flow/model/FlowCategory.java | 74 + .../demo/common/flow/model/FlowEntry.java | 155 + .../common/flow/model/FlowEntryPublish.java | 77 + .../flow/model/FlowEntryPublishVariable.java | 69 + .../common/flow/model/FlowEntryVariable.java | 86 + .../common/flow/model/FlowTaskComment.java | 106 + .../demo/common/flow/model/FlowTaskExt.java | 51 + .../demo/common/flow/model/FlowWorkOrder.java | 140 + .../flow/model/constant/FlowBindFormType.java | 44 + .../flow/model/constant/FlowEntryStatus.java | 44 + .../flow/model/constant/FlowVariableType.java | 44 + .../flow/object/FlowTaskExtMultiInstance.java | 29 + .../common/flow/service/FlowApiService.java | 354 + .../flow/service/FlowCategoryService.java | 61 + .../common/flow/service/FlowEntryService.java | 145 + .../service/FlowEntryVariableService.java | 68 + .../flow/service/FlowTaskCommentService.java | 31 + .../flow/service/FlowTaskExtService.java | 38 + .../flow/service/FlowWorkOrderService.java | 76 + .../flow/service/impl/FlowApiServiceImpl.java | 615 + .../service/impl/FlowCategoryServiceImpl.java | 129 + .../service/impl/FlowEntryServiceImpl.java | 422 + .../impl/FlowEntryVariableServiceImpl.java | 131 + .../impl/FlowTaskCommentServiceImpl.java | 74 + .../service/impl/FlowTaskExtServiceImpl.java | 62 + .../impl/FlowWorkOrderServiceImpl.java | 136 + .../flow/util/BaseFlowDeptPostExtHelper.java | 75 + .../flow/util/FlowCustomExtFactory.java | 33 + .../common/flow/util/FlowOperationHelper.java | 248 + .../demo/common/flow/vo/FlowCategoryVo.java | 55 + .../common/flow/vo/FlowEntryPublishVo.java | 50 + .../common/flow/vo/FlowEntryVariableVo.java | 65 + .../flow/demo/common/flow/vo/FlowEntryVo.java | 112 + .../common/flow/vo/FlowTaskCommentVo.java | 70 + .../flow/demo/common/flow/vo/FlowTaskVo.java | 75 + .../demo/common/flow/vo/FlowWorkOrderVo.java | 108 + .../flow/demo/common/flow/vo/TaskInfoVo.java | 67 + .../main/resources/META-INF/spring.factories | 2 + .../common/common-log/pom.xml | 43 + .../common/log/annotation/OperationLog.java | 33 + .../common/log/aop/OperationLogAspect.java | 251 + .../log/config/CommonLogAutoConfig.java | 13 + .../log/config/OperationLogProperties.java | 20 + .../common/log/dao/SysOperationLogMapper.java | 34 + .../log/dao/mapper/SysOperationLogMapper.xml | 99 + .../common/log/model/SysOperationLog.java | 170 + .../model/constant/SysOperationLogType.java | 149 + .../log/service/SysOperationLogService.java | 45 + .../impl/SysOperationLogServiceImpl.java | 84 + .../main/resources/META-INF/spring.factories | 2 + .../common/common-online-api/pom.xml | 43 + .../api/config/OnlineApiAutoConfig.java | 13 + .../api/config/OnlineApiProperties.java | 32 + .../controller/OnlineColumnController.java | 400 + .../OnlineDatasourceController.java | 205 + .../OnlineDatasourceRelationController.java | 228 + .../controller/OnlineDblinkController.java | 92 + .../api/controller/OnlineDictController.java | 156 + .../api/controller/OnlineFormController.java | 257 + .../api/controller/OnlinePageController.java | 343 + .../api/controller/OnlineRuleController.java | 144 + .../api/controller/OnlineTableController.java | 118 + .../OnlineVirtualColumnController.java | 180 + .../main/resources/META-INF/spring.factories | 2 + .../common/common-online/pom.xml | 63 + .../online/config/OnlineAutoConfig.java | 13 + .../online/config/OnlineProperties.java | 30 + .../controller/OnlineOperationController.java | 786 + .../common/online/dao/OnlineColumnMapper.java | 26 + .../online/dao/OnlineColumnRuleMapper.java | 25 + .../online/dao/OnlineDatasourceMapper.java | 61 + .../dao/OnlineDatasourceRelationMapper.java | 26 + .../dao/OnlineDatasourceTableMapper.java | 13 + .../common/online/dao/OnlineDblinkMapper.java | 113 + .../common/online/dao/OnlineDictMapper.java | 26 + .../dao/OnlineFormDatasourceMapper.java | 13 + .../common/online/dao/OnlineFormMapper.java | 26 + .../online/dao/OnlineOperationMapper.java | 228 + .../dao/OnlinePageDatasourceMapper.java | 13 + .../common/online/dao/OnlinePageMapper.java | 35 + .../common/online/dao/OnlineRuleMapper.java | 52 + .../common/online/dao/OnlineTableMapper.java | 34 + .../online/dao/OnlineVirtualColumnMapper.java | 26 + .../online/dao/mapper/OnlineColumnMapper.xml | 56 + .../dao/mapper/OnlineColumnRuleMapper.xml | 30 + .../dao/mapper/OnlineDatasourceMapper.xml | 89 + .../mapper/OnlineDatasourceRelationMapper.xml | 47 + .../mapper/OnlineDatasourceTableMapper.xml | 10 + .../online/dao/mapper/OnlineDblinkMapper.xml | 34 + .../online/dao/mapper/OnlineDictMapper.xml | 52 + .../dao/mapper/OnlineFormDatasourceMapper.xml | 9 + .../online/dao/mapper/OnlineFormMapper.xml | 51 + .../dao/mapper/OnlinePageDatasourceMapper.xml | 9 + .../online/dao/mapper/OnlinePageMapper.xml | 50 + .../online/dao/mapper/OnlineRuleMapper.xml | 66 + .../online/dao/mapper/OnlineTableMapper.xml | 48 + .../dao/mapper/OnlineVirtualColumnMapper.xml | 56 + .../common/online/dto/OnlineColumnDto.java | 137 + .../online/dto/OnlineColumnRuleDto.java | 33 + .../online/dto/OnlineDatasourceDto.java | 54 + .../dto/OnlineDatasourceRelationDto.java | 93 + .../common/online/dto/OnlineDblinkDto.java | 46 + .../demo/common/online/dto/OnlineDictDto.java | 104 + .../common/online/dto/OnlineFilterDto.java | 51 + .../demo/common/online/dto/OnlineFormDto.java | 79 + .../online/dto/OnlinePageDatasourceDto.java | 34 + .../demo/common/online/dto/OnlinePageDto.java | 51 + .../demo/common/online/dto/OnlineRuleDto.java | 49 + .../common/online/dto/OnlineTableDto.java | 41 + .../online/dto/OnlineVirtualColumnDto.java | 88 + .../common/online/model/OnlineColumn.java | 196 + .../common/online/model/OnlineColumnRule.java | 36 + .../common/online/model/OnlineDatasource.java | 107 + .../model/OnlineDatasourceRelation.java | 187 + .../online/model/OnlineDatasourceTable.java | 39 + .../common/online/model/OnlineDblink.java | 62 + .../demo/common/online/model/OnlineDict.java | 169 + .../demo/common/online/model/OnlineForm.java | 138 + .../online/model/OnlineFormDatasource.java | 33 + .../demo/common/online/model/OnlinePage.java | 106 + .../online/model/OnlinePageDatasource.java | 33 + .../demo/common/online/model/OnlineRule.java | 109 + .../demo/common/online/model/OnlineTable.java | 107 + .../online/model/OnlineVirtualColumn.java | 96 + .../online/model/constant/DictType.java | 54 + .../model/constant/FieldFilterType.java | 59 + .../online/model/constant/FieldKind.java | 74 + .../online/model/constant/FormKind.java | 44 + .../online/model/constant/FormType.java | 54 + .../online/model/constant/PageStatus.java | 49 + .../online/model/constant/PageType.java | 49 + .../online/model/constant/RelationType.java | 44 + .../online/model/constant/RuleType.java | 69 + .../online/model/constant/VirtualType.java | 39 + .../demo/common/online/object/ColumnData.java | 28 + .../common/online/object/JoinTableInfo.java | 28 + .../demo/common/online/object/SqlTable.java | 41 + .../common/online/object/SqlTableColumn.java | 73 + .../online/service/OnlineColumnService.java | 150 + .../OnlineDatasourceRelationService.java | 97 + .../service/OnlineDatasourceService.java | 110 + .../online/service/OnlineDblinkService.java | 74 + .../online/service/OnlineDictService.java | 80 + .../online/service/OnlineFormService.java | 115 + .../service/OnlineOperationService.java | 142 + .../online/service/OnlinePageService.java | 112 + .../online/service/OnlineRuleService.java | 91 + .../online/service/OnlineTableService.java | 95 + .../service/OnlineVirtualColumnService.java | 78 + .../service/impl/OnlineColumnServiceImpl.java | 361 + .../OnlineDatasourceRelationServiceImpl.java | 255 + .../impl/OnlineDatasourceServiceImpl.java | 238 + .../service/impl/OnlineDblinkServiceImpl.java | 205 + .../service/impl/OnlineDictServiceImpl.java | 157 + .../service/impl/OnlineFormServiceImpl.java | 262 + .../impl/OnlineOperationServiceImpl.java | 973 + .../service/impl/OnlinePageServiceImpl.java | 233 + .../service/impl/OnlineRuleServiceImpl.java | 181 + .../service/impl/OnlineTableServiceImpl.java | 236 + .../impl/OnlineVirtualColumnServiceImpl.java | 175 + .../common/online/util/OnlineConstant.java | 15 + .../online/util/OnlineDataSourceResolver.java | 50 + .../online/util/OnlineOperationHelper.java | 388 + .../demo/common/online/util/OnlineUtil.java | 30 + .../common/online/vo/OnlineColumnRuleVo.java | 28 + .../demo/common/online/vo/OnlineColumnVo.java | 136 + .../online/vo/OnlineDatasourceRelationVo.java | 111 + .../common/online/vo/OnlineDatasourceVo.java | 67 + .../demo/common/online/vo/OnlineDblinkVo.java | 45 + .../demo/common/online/vo/OnlineDictVo.java | 116 + .../demo/common/online/vo/OnlineFormVo.java | 92 + .../online/vo/OnlinePageDatasourceVo.java | 28 + .../demo/common/online/vo/OnlinePageVo.java | 66 + .../demo/common/online/vo/OnlineRuleVo.java | 61 + .../demo/common/online/vo/OnlineTableVo.java | 45 + .../online/vo/OnlineVirtualColumnVo.java | 73 + .../main/resources/META-INF/spring.factories | 2 + .../common/common-redis/pom.xml | 29 + .../redis/cache/RedisDictionaryCache.java | 412 + .../redis/cache/RedisTreeDictionaryCache.java | 354 + .../redis/cache/RedissonCacheConfig.java | 67 + .../redis/cache/SessionCacheHelper.java | 74 + .../common/redis/config/RedissonConfig.java | 102 + .../main/resources/META-INF/spring.factories | 2 + .../common/common-sequence/pom.xml | 24 + .../config/IdGeneratorAutoConfig.java | 14 + .../config/IdGeneratorProperties.java | 20 + .../sequence/generator/BasicIdGenerator.java | 48 + .../sequence/generator/MyIdGenerator.java | 24 + .../sequence/wrapper/IdGeneratorWrapper.java | 52 + .../main/resources/META-INF/spring.factories | 2 + .../common/pom.xml | 25 + .../orange-demo-flowable-service/pom.xml | 210 + .../zz-resource/db-scripts/zzdemo-online.sql | 7977 +++ .../docker-files/docker-compose.yml | 16 + .../docker-files/services/redis/Dockerfile | 13 + .../docker-files/services/redis/redis.conf | 1307 + .../21344f62d80b417d8e25343ffe976f7f.png | Bin 0 -> 27185 bytes .../d9aa27ea7eec4375b123e11ce92ec9b5.png | Bin 0 -> 27185 bytes .../dcd2db9b75664251a3baf595f6752d90.png | Bin 0 -> 27185 bytes .../0c20b1c7256148018451852ddae9f8aa.png | Bin 0 -> 27185 bytes .../861726471ed54fee96f8c16d3e76550e.png | Bin 0 -> 27185 bytes .../e85a5b89d3bd4a3f94d58b0630afc7af.png | Bin 0 -> 27185 bytes .../1252138daaf744a3b1fdf06a07c5a173.png | Bin 0 -> 9808 bytes .../38b7e4a097654ff38e176846ba005fcf.png | Bin 0 -> 9808 bytes .../e782ced275f4402297ce5dbace68c06f.png | Bin 0 -> 27185 bytes .../f33b658b052f487c9a34af274f48dcd3.png | Bin 0 -> 9808 bytes .../orange-demo-flowable-web/.browserslistrc | 2 + .../orange-demo-flowable-web/.editorconfig | 5 + .../orange-demo-flowable-web/.eslintignore | 1 + .../orange-demo-flowable-web/.eslintrc.js | 39 + .../orange-demo-flowable-web/.gitignore | 21 + .../orange-demo-flowable-web/README.md | 15 + .../orange-demo-flowable-web/babel.config.js | 5 + .../orange-demo-flowable-web/jest.config.js | 3 + .../orange-demo-flowable-web/package.json | 71 + .../public/favicon.ico | Bin 0 -> 4286 bytes .../img/icons/android-chrome-192x192.png | Bin 0 -> 9416 bytes .../img/icons/android-chrome-512x512.png | Bin 0 -> 29808 bytes .../icons/android-chrome-maskable-192x192.png | Bin 0 -> 6401 bytes .../icons/android-chrome-maskable-512x512.png | Bin 0 -> 23038 bytes .../img/icons/apple-touch-icon-120x120.png | Bin 0 -> 3369 bytes .../img/icons/apple-touch-icon-152x152.png | Bin 0 -> 4046 bytes .../img/icons/apple-touch-icon-180x180.png | Bin 0 -> 4678 bytes .../img/icons/apple-touch-icon-60x60.png | Bin 0 -> 1491 bytes .../img/icons/apple-touch-icon-76x76.png | Bin 0 -> 1823 bytes .../public/img/icons/apple-touch-icon.png | Bin 0 -> 4678 bytes .../public/img/icons/favicon-16x16.png | Bin 0 -> 799 bytes .../public/img/icons/favicon-32x32.png | Bin 0 -> 1271 bytes .../img/icons/msapplication-icon-144x144.png | Bin 0 -> 1169 bytes .../public/img/icons/mstile-150x150.png | Bin 0 -> 4282 bytes .../public/img/icons/safari-pinned-tab.svg | 149 + .../public/index.html | 16 + .../public/robots.txt | 2 + .../orange-demo-flowable-web/src/App.vue | 21 + .../api/Controller/DictionaryController.js | 84 + .../api/Controller/SysDataPermController.js | 61 + .../src/api/Controller/SysDeptController.js | 49 + .../src/api/Controller/SysPostController.js | 21 + .../src/api/Controller/SysUserController.js | 25 + .../src/api/Controller/SystemController.js | 252 + .../FlowController/FlowCategoryController.js | 21 + .../FlowDictionaryController.js | 15 + .../api/FlowController/FlowEntryController.js | 49 + .../FlowEntryVariableController.js | 21 + .../FlowController/FlowOperationController.js | 98 + .../OnlineColumnController.js | 53 + .../OnlineDatasourceController.js | 25 + .../OnlineDatasourceRelationController.js | 25 + .../OnlineDblinkController.js | 13 + .../OnlineDictController.js | 25 + .../OnlineFormController.js | 29 + .../OnlineFormController/OnlineOperation.js | 45 + .../OnlinePageController.js | 61 + .../OnlineRuleController.js | 25 + .../OnlineTableController.js | 25 + .../OnlineVirtualColumnController.js | 21 + .../src/api/flowController.js | 13 + .../orange-demo-flowable-web/src/api/index.js | 15 + .../src/api/onlineController.js | 25 + .../src/assets/element-variables-blue.scss | 1014 + .../src/assets/element-variables-dark.scss | 1000 + .../src/assets/element-variables-green.scss | 1000 + .../src/assets/element-variables-light.scss | 998 + .../src/assets/element-variables-orange.scss | 1001 + .../src/assets/img/default-header.jpg | Bin 0 -> 14882 bytes .../src/assets/img/login.png | Bin 0 -> 728962 bytes .../src/assets/img/login_bg.jpg | Bin 0 -> 494030 bytes .../src/assets/img/login_logo.png | Bin 0 -> 16011 bytes .../src/assets/img/logo.jpg | Bin 0 -> 19013 bytes .../src/assets/img/logo.png | Bin 0 -> 9808 bytes .../src/assets/img/orange-group1.png | Bin 0 -> 10894 bytes .../src/assets/package.json | 13 + .../src/assets/style/base.scss | 651 + .../src/assets/style/element-variables.scss | 5 + .../src/assets/style/form-style.scss | 117 + .../src/assets/style/index.scss | 3 + .../src/assets/style/transition.scss | 31 + .../src/assets/theme/alert.css | 343 + .../src/assets/theme/aside.css | 136 + .../src/assets/theme/autocomplete.css | 1467 + .../src/assets/theme/avatar.css | 284 + .../src/assets/theme/backtop.css | 273 + .../src/assets/theme/badge.css | 290 + .../src/assets/theme/base.css | 1244 + .../src/assets/theme/breadcrumb-item.css | 0 .../src/assets/theme/breadcrumb.css | 287 + .../src/assets/theme/button-group.css | 0 .../src/assets/theme/button.css | 762 + .../src/assets/theme/calendar.css | 1065 + .../src/assets/theme/card.css | 271 + .../src/assets/theme/carousel-item.css | 291 + .../src/assets/theme/carousel.css | 367 + .../src/assets/theme/cascader-panel.css | 1781 + .../src/assets/theme/cascader.css | 3504 + .../src/assets/theme/checkbox-button.css | 0 .../src/assets/theme/checkbox-group.css | 0 .../src/assets/theme/checkbox.css | 636 + .../src/assets/theme/col.css | 1877 + .../src/assets/theme/collapse-item.css | 0 .../src/assets/theme/collapse.css | 543 + .../src/assets/theme/color-picker.css | 545 + .../src/assets/theme/container.css | 151 + .../src/assets/theme/date-picker.css | 3698 + .../src/assets/theme/dialog.css | 651 + .../src/assets/theme/display.css | 293 + .../src/assets/theme/divider.css | 284 + .../src/assets/theme/drawer.css | 503 + .../src/assets/theme/dropdown-item.css | 0 .../src/assets/theme/dropdown-menu.css | 0 .../src/assets/theme/dropdown.css | 1451 + .../assets/theme/element-variables-blue.css | 120 + .../assets/theme/element-variables-dark.css | 120 + .../assets/theme/element-variables-green.css | 120 + .../assets/theme/element-variables-light.css | 120 + .../assets/theme/element-variables-orange.css | 120 + .../src/assets/theme/element-variables.css | 120 + .../src/assets/theme/fonts/element-icons.ttf | Bin 0 -> 55956 bytes .../src/assets/theme/fonts/element-icons.woff | Bin 0 -> 28200 bytes .../src/assets/theme/footer.css | 256 + .../src/assets/theme/form-item.css | 0 .../src/assets/theme/form.css | 364 + .../src/assets/theme/header.css | 256 + .../src/assets/theme/icon.css | 1008 + .../src/assets/theme/image.css | 443 + .../src/assets/theme/index.css | 57046 ++++++++++++++++ .../src/assets/theme/infinite-scroll.css | 0 .../src/assets/theme/infiniteScroll.css | 0 .../src/assets/theme/input-number.css | 891 + .../src/assets/theme/input.css | 534 + .../src/assets/theme/link.css | 342 + .../src/assets/theme/loading.css | 336 + .../src/assets/theme/main.css | 261 + .../src/assets/theme/menu-item-group.css | 0 .../src/assets/theme/menu-item.css | 0 .../src/assets/theme/menu.css | 719 + .../src/assets/theme/message-box.css | 2018 + .../src/assets/theme/message.css | 336 + .../src/assets/theme/notification.css | 323 + .../src/assets/theme/option-group.css | 276 + .../src/assets/theme/option.css | 273 + .../src/assets/theme/page-header.css | 283 + .../src/assets/theme/pagination.css | 3275 + .../src/assets/theme/popconfirm.css | 264 + .../src/assets/theme/popover.css | 605 + .../src/assets/theme/popper.css | 328 + .../src/assets/theme/progress.css | 349 + .../src/assets/theme/radio-button.css | 458 + .../src/assets/theme/radio-group.css | 255 + .../src/assets/theme/radio.css | 509 + .../src/assets/theme/rate.css | 284 + .../src/assets/theme/reset.css | 174 + .../src/assets/theme/row.css | 289 + .../src/assets/theme/scrollbar.css | 296 + .../src/assets/theme/select-dropdown.css | 623 + .../src/assets/theme/select.css | 2825 + .../src/assets/theme/slider.css | 1677 + .../src/assets/theme/spinner.css | 180 + .../src/assets/theme/step.css | 485 + .../src/assets/theme/steps.css | 146 + .../src/assets/theme/submenu.css | 0 .../src/assets/theme/switch.css | 333 + .../src/assets/theme/tab-pane.css | 0 .../src/assets/theme/table-column.css | 1410 + .../src/assets/theme/table.css | 2047 + .../src/assets/theme/tabs.css | 831 + .../src/assets/theme/tag.css | 462 + .../src/assets/theme/time-picker.css | 2523 + .../src/assets/theme/time-select.css | 1918 + .../src/assets/theme/timeline-item.css | 318 + .../src/assets/theme/timeline.css | 256 + .../src/assets/theme/tooltip.css | 342 + .../src/assets/theme/transfer.css | 2349 + .../src/assets/theme/tree.css | 1210 + .../src/assets/theme/upload.css | 1045 + .../src/components/DateRange/index.vue | 305 + .../src/components/Dialog/index.js | 77 + .../src/components/FilterBox/index.vue | 134 + .../src/components/Hamburger/index.vue | 44 + .../src/components/IconSelect/icon.json | 280 + .../src/components/IconSelect/index.vue | 104 + .../src/components/InputNumberRange/index.vue | 226 + .../src/components/Progress/index.vue | 44 + .../src/components/RichEditor/index.vue | 132 + .../components/TableProgressColumn/index.vue | 119 + .../src/components/TreeSelect/index.vue | 290 + .../src/core/config/development.js | 4 + .../src/core/config/index.js | 18 + .../src/core/config/production.js | 4 + .../src/core/directive/sortable.js | 14 + .../src/core/directive/sortableData.js | 60 + .../src/core/http/index.js | 197 + .../src/core/http/request.js | 75 + .../src/core/http/requestUrl.js | 27 + .../src/core/mixins/global.js | 114 + .../src/core/mixins/index.js | 298 + .../orange-demo-flowable-web/src/main.js | 39 + .../src/registerServiceWorker.js | 32 + .../src/router/import-development.js | 1 + .../src/router/import-production.js | 1 + .../src/router/index.js | 41 + .../src/router/systemRouters.js | 68 + .../src/staticDict/flowStaticDict.js | 178 + .../src/staticDict/index.js | 201 + .../src/staticDict/onlineStaticDict.js | 566 + .../src/store/actions.js | 1 + .../src/store/getters.js | 86 + .../src/store/index.js | 15 + .../src/store/mutations.js | 161 + .../src/store/state.js | 29 + .../src/store/utils/index.js | 36 + .../src/utils/chartOption.js | 56 + .../src/utils/index.js | 438 + .../src/utils/validate.js | 33 + .../src/utils/widget.js | 322 + .../layout/components/breadcrumb/index.vue | 53 + .../components/formModifyPassword/index.vue | 98 + .../layout/components/sidebar/menu-item.vue | 59 + .../layout/components/sidebar/sidebar.vue | 82 + .../views/layout/components/tags/tagItem.vue | 79 + .../views/layout/components/tags/tagPanel.vue | 213 + .../src/views/layout/index.vue | 212 + .../src/views/login/index.vue | 130 + .../components/customFilterWidget.vue | 154 + .../onlineForm/components/customImage.vue | 28 + .../onlineForm/components/customTable.vue | 529 + .../onlineForm/components/customText.vue | 35 + .../onlineForm/components/customUpload.vue | 187 + .../onlineForm/components/customWidget.vue | 227 + .../components/dragableFilterBox.vue | 142 + .../components/editDictParamValue.vue | 148 + .../onlineForm/components/editFormParam.vue | 77 + .../components/editTableQueryParam.vue | 211 + .../components/editWidgetTableColumn.vue | 166 + .../components/editWidgetTableOperation.vue | 129 + .../components/editableWidgetItem.vue | 150 + .../onlineForm/components/formGenerator.vue | 1565 + .../onlineForm/data/onlineFormOptions.js | 239 + .../formOnlineDict/editDictDataButton.vue | 89 + .../formOnlineDict/editOnlineDict.vue | 495 + .../views/onlineForm/formOnlineDict/index.vue | 193 + .../formOnlinePage/editOnlineForm.vue | 212 + .../editOnlinePageDatasource.vue | 201 + .../editOnlinePageDatasourceRelation.vue | 358 + .../editVirtualColumnFilter.vue | 193 + .../views/onlineForm/formOnlinePage/index.vue | 203 + .../formOnlinePage/onlinePageSetting.vue | 936 + .../onlinePageTableColumnRule.vue | 568 + .../onlinePageVirtualColumn.vue | 582 + .../setOnlineTableColumnRule.vue | 285 + .../onlineForm/formRender/onlineEditForm.vue | 260 + .../onlineForm/formRender/onlineFormMixins.js | 836 + .../onlineForm/formRender/onlineQueryForm.vue | 141 + .../onlineForm/formRender/onlineWorkOrder.vue | 293 + .../onlineForm/formRender/workflowForm.vue | 250 + .../src/views/onlineForm/index.vue | 169 + .../src/views/onlineForm/utils/index.js | 105 + .../views/upms/formDictManagement/index.vue | 193 + .../src/views/upms/formEditDict/index.vue | 110 + .../views/upms/formEditSysDataPerm/index.vue | 243 + .../src/views/upms/formEditSysDept/index.vue | 201 + .../views/upms/formEditSysMenu/editColumn.vue | 108 + .../src/views/upms/formEditSysMenu/index.vue | 400 + .../src/views/upms/formEditSysPerm/index.vue | 168 + .../views/upms/formEditSysPermCode/index.vue | 221 + .../upms/formEditSysPermModule/index.vue | 184 + .../src/views/upms/formEditSysPost/index.vue | 198 + .../src/views/upms/formEditSysRole/index.vue | 158 + .../src/views/upms/formEditSysUser/index.vue | 257 + .../src/views/upms/formMenuPerm/index.vue | 150 + .../src/views/upms/formSetRoleUsers/index.vue | 211 + .../upms/formSetSysDataPermUser/index.vue | 211 + .../src/views/upms/formSysDataPerm/index.vue | 479 + .../src/views/upms/formSysDept/index.vue | 193 + .../upms/formSysDeptPost/formSetDeptPost.vue | 185 + .../src/views/upms/formSysDeptPost/index.vue | 255 + .../src/views/upms/formSysLoginUser/index.vue | 146 + .../upms/formSysMenu/formSysColumnMenu.vue | 307 + .../upms/formSysMenu/formSysMenuPerm.vue | 203 + .../src/views/upms/formSysMenu/index.vue | 241 + .../upms/formSysPerm/formSysPermDetail.vue | 323 + .../src/views/upms/formSysPerm/index.vue | 407 + .../formSysPermCode/formSysPermCodeDetail.vue | 253 + .../src/views/upms/formSysPermCode/index.vue | 270 + .../src/views/upms/formSysPost/index.vue | 200 + .../upms/formSysRole/formSysRolePerm.vue | 254 + .../src/views/upms/formSysRole/index.vue | 473 + .../upms/formSysUser/formSysUserPerm.vue | 335 + .../src/views/upms/formSysUser/index.vue | 282 + .../src/views/welcome/index.vue | 156 + .../workflow/components/HandlerFlowTask.vue | 244 + .../workflow/components/ProcessDesigner.vue | 86 + .../workflow/components/ProcessViewer.vue | 232 + .../views/workflow/components/TagSelect.vue | 75 + .../views/workflow/components/TaskCommit.vue | 107 + .../workflow/components/TaskGroupSelect.vue | 106 + .../workflow/components/TaskPostSelect.vue | 148 + .../workflow/components/TaskUserSelect.vue | 201 + .../flowCategory/formEditFlowCategory.vue | 207 + .../flowCategory/formFlowCategory.vue | 206 + .../workflow/flowEntry/formEditFlowEntry.vue | 574 + .../flowEntry/formEditFlowEntryVariable.vue | 189 + .../workflow/flowEntry/formFlowEntry.vue | 341 + .../flowEntry/formPublishedFlowEntry.vue | 175 + .../views/workflow/handlerFlowTask/index.vue | 316 + .../src/views/workflow/mixins/flowMixins.js | 79 + .../views/workflow/package/highlight/index.js | 5 + .../src/views/workflow/package/index.js | 7 + .../process-designer/ProcessDesigner.vue | 460 + .../package/process-designer/index.js | 7 + .../plugins/content-pad/contentPadProvider.js | 390 + .../plugins/content-pad/index.js | 6 + .../process-designer/plugins/defaultEmpty.js | 27 + .../descriptor/activitiDescriptor.json | 1210 + .../plugins/descriptor/camundaDescriptor.json | 1087 + .../descriptor/flowableDescriptor.json | 1206 + .../activiti/activitiExtension.js | 74 + .../extension-moddle/activiti/index.js | 9 + .../extension-moddle/camunda/extension.js | 148 + .../plugins/extension-moddle/camunda/index.js | 6 + .../flowable/flowableExtension.js | 74 + .../extension-moddle/flowable/index.js | 9 + .../process-designer/plugins/palette/index.js | 15 + .../plugins/palette/paletteProvider.js | 160 + .../plugins/translate/customTranslate.js | 41 + .../process-designer/plugins/translate/zh.js | 238 + .../package/refactor/PropertiesPanel.vue | 201 + .../package/refactor/base/ElementBaseInfo.vue | 72 + .../refactor/flow-condition/FlowCondition.vue | 200 + .../package/refactor/form-variable/index.vue | 89 + .../package/refactor/form/ElementForm.vue | 360 + .../package/refactor/form/flowFormConfig.vue | 191 + .../refactor/form/formEditOperation.vue | 97 + .../views/workflow/package/refactor/index.js | 7 + .../refactor/listeners/ElementListeners.vue | 299 + .../refactor/listeners/UserTaskListeners.vue | 323 + .../package/refactor/listeners/template.js | 178 + .../package/refactor/listeners/utilSelf.js | 60 + .../multi-instance/ElementMultiInstance.vue | 258 + .../ElementMultiInstanceAssignee.vue | 136 + .../refactor/other/ElementOtherConfig.vue | 59 + .../refactor/properties/ElementProperties.vue | 127 + .../signal-message/SignalAndMessage.vue | 104 + .../package/refactor/task/ElementTask.vue | 72 + .../task/task-components/ReceiveTask.vue | 97 + .../task/task-components/ScriptTask.vue | 85 + .../task/task-components/UserTask.vue | 343 + .../package/theme/flow-element-variables.scss | 63 + .../views/workflow/package/theme/index.scss | 86 + .../package/theme/process-designer.scss | 152 + .../workflow/package/theme/process-panel.scss | 110 + .../src/views/workflow/package/utils.js | 69 + .../workflow/taskManager/formAllInstance.vue | 189 + .../taskManager/formMyApprovedTask.vue | 174 + .../taskManager/formMyHistoryTask.vue | 163 + .../views/workflow/taskManager/formMyTask.vue | 133 + .../taskManager/formTaskProcessViewer.vue | 66 + .../views/workflow/taskManager/stopTask.vue | 82 + .../orange-demo-flowable-web/static/.gitkeep | 0 .../orange-demo-flowable-web/vue.config.js | 5 + 849 files changed, 217544 insertions(+) create mode 100644 orange-demo-flowable/orange-demo-flowable-service/.gitignore create mode 100644 orange-demo-flowable/orange-demo-flowable-service/README.md create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/WebAdminApplication.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/controller/AreaCodeController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/dao/AreaCodeMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/dao/mapper/AreaCodeMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/model/AreaCode.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/service/AreaCodeService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/service/impl/AreaCodeServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/util/FlowDeptPostExtHelper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/vo/AreaCodeVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/ApplicationConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/DataSourceType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/FilterConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/InterceptorConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/MultiDataSourceConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/interceptor/AuthenticationInterceptor.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/LoginController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/LoginUserController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysDataPermController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysDeptController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysMenuController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermCodeController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermModuleController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPostController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysRoleController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysUserController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermDeptMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermUserMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptPostMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptRelationMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysMenuMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysMenuPermCodeMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermCodeMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermCodePermMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermModuleMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermWhitelistMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPostMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysRoleMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysRoleMenuMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserPostMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserRoleMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermDeptMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermUserMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptPostMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptRelationMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysMenuMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysMenuPermCodeMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermCodeMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermCodePermMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermModuleMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermWhitelistMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPostMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysRoleMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysRoleMenuMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserPostMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserRoleMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDataPermDeptDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDataPermDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDeptDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDeptPostDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysMenuDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermCodeDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermModuleDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPostDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysRoleDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysUserDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPerm.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPermDept.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPermUser.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDept.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDeptPost.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDeptRelation.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysMenu.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysMenuPermCode.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPerm.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermCode.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermCodePerm.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermModule.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermWhitelist.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPost.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysRole.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysRoleMenu.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUser.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUserPost.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUserRole.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysMenuType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysOnlineMenuPermType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysPermCodeType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysPermModuleType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysUserStatus.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysUserType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysDataPermService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysDeptService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysMenuService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermCodeService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermModuleService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermWhitelistService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPostService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysRoleService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysUserService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysDataPermServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysDeptServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysMenuServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermCodeServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermModuleServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermWhitelistServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPostServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysRoleServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysUserServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDataPermDeptVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDataPermVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDeptPostVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDeptVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysMenuVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermCodeVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermModuleVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPostVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysRoleVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysUserVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/application.yml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/log4j2.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/template/views/print_error.ftl create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/advice/MyControllerAdvice.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/advice/MyExceptionHandler.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DeptFilterColumn.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DisableDataFilter.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DisableTenantFilter.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/EnableDataPerm.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/JobUpdateTimeColumn.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyDataSource.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyDataSourceResolver.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyRequestBody.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/NoAuthInterface.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationConstDict.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationDict.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationManyToMany.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationManyToManyAggregation.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToMany.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToManyAggregation.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToOne.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/TenantFilterColumn.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/UploadFlagColumn.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/UserFilterColumn.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DataSourceAspect.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DataSourceResolveAspect.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DictCacheSyncAspect.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/dao/BaseDaoMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/mapper/BaseModelMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/mapper/DummyModelMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/BaseDictService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/BaseService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/IBaseDictService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/IBaseService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/DictionaryCache.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/MapDictionaryCache.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/MapTreeDictionaryCache.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/CommonWebMvcConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/DataSourceContextHolder.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/DynamicDataSource.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/EncryptConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/RestTemplateConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/TomcatConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/AggregationType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/AppDeviceType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/ApplicationConstant.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/ErrorCodeEnum.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/GlobalDeletedFlag.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/DataValidationException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidClassFieldException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidDataFieldException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidDataModelException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidRedisModeException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/MapCacheAccessException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/MyRuntimeException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/NoDataAffectException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/NoDataPermException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/RedisCacheAccessException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/interceptor/MyRequestArgumentResolver.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/listener/LoadServiceRelationListener.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/CallResult.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/DummyClass.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/GlobalThreadLocal.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/LoginUserInfo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyGroupCriteria.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyGroupParam.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyOrderParam.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyPageData.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyPageParam.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyRelationParam.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyWhereCriteria.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/ResponseResult.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/TokenData.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/Tuple2.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/BaseUpDownloader.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/LocalUpDownloader.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UpDownloaderFactory.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadResponseInfo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadStoreInfo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadStoreTypeEnum.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/AopTargetUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ApplicationContextHolder.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ContextUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/DataSourceResolver.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ExportUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/IpUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/JwtUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/LogMessageUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyCommonUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyDateUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyModelUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyPageUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/RedisKeyUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/RsaUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/TreeNode.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/AddGroup.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/ConstDictRef.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/ConstDictValidator.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/TextLength.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/TextLengthValidator.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/UpdateGroup.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/aop/DisableDataFilterAspect.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterAutoConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterProperties.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterWebMvcConfigurer.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/constant/DataPermRuleType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/interceptor/DataFilterInterceptor.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/interceptor/MybatisDataFilterInterceptor.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/listener/LoadDataFilterInfoListener.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/config/FlowOnlineAutoConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/config/FlowOnlineProperties.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/controller/FlowOnlineOperationController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/service/FlowOnlineOperationService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/service/impl/FlowOnlineOperationServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/config/FlowAutoConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/config/FlowProperties.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowApprovalType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowConstant.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowTaskStatus.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowTaskType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowCategoryController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowEntryController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowEntryVariableController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowOperationController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowCategoryMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryPublishMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryPublishVariableMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryVariableMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowTaskCommentMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowTaskExtMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowWorkOrderMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowCategoryMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryPublishMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryPublishVariableMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryVariableMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowTaskCommentMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowTaskExtMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowWorkOrderMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowCategoryDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowEntryDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowEntryVariableDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowTaskCommentDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowWorkOrderDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/exception/FlowOperationException.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/DeptPostLeaderListener.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/UpDeptPostLeaderListener.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/UpdateFlowStatusListener.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowCategory.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntry.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryPublish.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryPublishVariable.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryVariable.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowTaskComment.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowTaskExt.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowWorkOrder.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowBindFormType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowEntryStatus.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowVariableType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/object/FlowTaskExtMultiInstance.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowApiService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowCategoryService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowEntryService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowEntryVariableService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowTaskCommentService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowTaskExtService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowWorkOrderService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowApiServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowCategoryServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowEntryServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowEntryVariableServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowTaskCommentServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowTaskExtServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowWorkOrderServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/BaseFlowDeptPostExtHelper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/FlowCustomExtFactory.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/FlowOperationHelper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowCategoryVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryPublishVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryVariableVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowTaskCommentVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowTaskVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowWorkOrderVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/TaskInfoVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/annotation/OperationLog.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/aop/OperationLogAspect.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/config/CommonLogAutoConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/config/OperationLogProperties.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/dao/SysOperationLogMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/dao/mapper/SysOperationLogMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/model/SysOperationLog.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/model/constant/SysOperationLogType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/service/SysOperationLogService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/service/impl/SysOperationLogServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/config/OnlineApiAutoConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/config/OnlineApiProperties.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineColumnController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDatasourceController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDatasourceRelationController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDblinkController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDictController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineFormController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlinePageController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineRuleController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineTableController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineVirtualColumnController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/config/OnlineAutoConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/config/OnlineProperties.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/controller/OnlineOperationController.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineColumnMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineColumnRuleMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceRelationMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceTableMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDblinkMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDictMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineFormDatasourceMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineFormMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineOperationMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlinePageDatasourceMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlinePageMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineRuleMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineTableMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineVirtualColumnMapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineColumnMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineColumnRuleMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceRelationMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceTableMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDblinkMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDictMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineFormDatasourceMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineFormMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlinePageDatasourceMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlinePageMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineRuleMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineTableMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineVirtualColumnMapper.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineColumnDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineColumnRuleDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDatasourceDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDatasourceRelationDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDblinkDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDictDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineFilterDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineFormDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlinePageDatasourceDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlinePageDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineRuleDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineTableDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineVirtualColumnDto.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineColumn.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineColumnRule.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasource.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasourceRelation.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasourceTable.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDblink.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDict.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineForm.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineFormDatasource.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlinePage.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlinePageDatasource.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineRule.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineTable.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineVirtualColumn.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/DictType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FieldFilterType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FieldKind.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FormKind.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FormType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/PageStatus.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/PageType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/RelationType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/RuleType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/VirtualType.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/ColumnData.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/JoinTableInfo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/SqlTable.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/SqlTableColumn.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineColumnService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDatasourceRelationService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDatasourceService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDblinkService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDictService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineFormService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineOperationService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlinePageService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineRuleService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineTableService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineVirtualColumnService.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineColumnServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDatasourceRelationServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDatasourceServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDblinkServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDictServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineFormServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineOperationServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlinePageServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineRuleServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineTableServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineVirtualColumnServiceImpl.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineConstant.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineDataSourceResolver.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineOperationHelper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineUtil.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineColumnRuleVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineColumnVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDatasourceRelationVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDatasourceVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDblinkVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDictVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineFormVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlinePageDatasourceVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlinePageVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineRuleVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineTableVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineVirtualColumnVo.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-redis/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedisDictionaryCache.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedisTreeDictionaryCache.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedissonCacheConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/SessionCacheHelper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/config/RedissonConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/config/IdGeneratorAutoConfig.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/config/IdGeneratorProperties.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/generator/BasicIdGenerator.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/generator/MyIdGenerator.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/wrapper/IdGeneratorWrapper.java create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/resources/META-INF/spring.factories create mode 100644 orange-demo-flowable/orange-demo-flowable-service/common/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/pom.xml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/db-scripts/zzdemo-online.sql create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/docker-compose.yml create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/services/redis/Dockerfile create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/services/redis/redis.conf create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/attachment/21344f62d80b417d8e25343ffe976f7f.png create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/attachment/d9aa27ea7eec4375b123e11ce92ec9b5.png create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/attachment/dcd2db9b75664251a3baf595f6752d90.png create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/security_attachment/0c20b1c7256148018451852ddae9f8aa.png create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/security_attachment/861726471ed54fee96f8c16d3e76550e.png create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/security_attachment/e85a5b89d3bd4a3f94d58b0630afc7af.png create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/image/ZzTestFlowSubmitDetail/image_url/1252138daaf744a3b1fdf06a07c5a173.png create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/image/ZzTestFlowSubmitDetail/image_url/38b7e4a097654ff38e176846ba005fcf.png create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/image/ZzTestFlowSubmitDetail/image_url/e782ced275f4402297ce5dbace68c06f.png create mode 100644 orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/image/ZzTestFlowSubmitDetail/image_url/f33b658b052f487c9a34af274f48dcd3.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/.browserslistrc create mode 100644 orange-demo-flowable/orange-demo-flowable-web/.editorconfig create mode 100644 orange-demo-flowable/orange-demo-flowable-web/.eslintignore create mode 100644 orange-demo-flowable/orange-demo-flowable-web/.eslintrc.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/.gitignore create mode 100644 orange-demo-flowable/orange-demo-flowable-web/README.md create mode 100644 orange-demo-flowable/orange-demo-flowable-web/babel.config.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/jest.config.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/package.json create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/favicon.ico create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/android-chrome-192x192.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/android-chrome-512x512.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/android-chrome-maskable-192x192.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/android-chrome-maskable-512x512.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-120x120.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-152x152.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-180x180.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-60x60.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-76x76.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/favicon-16x16.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/favicon-32x32.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/msapplication-icon-144x144.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/mstile-150x150.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/img/icons/safari-pinned-tab.svg create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/index.html create mode 100644 orange-demo-flowable/orange-demo-flowable-web/public/robots.txt create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/App.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/DictionaryController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysDataPermController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysDeptController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysPostController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysUserController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SystemController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowCategoryController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowDictionaryController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowEntryController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowEntryVariableController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowOperationController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineColumnController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDatasourceController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDatasourceRelationController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDblinkController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDictController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineFormController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineOperation.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlinePageController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineRuleController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineTableController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineVirtualColumnController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/flowController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/api/onlineController.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-blue.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-dark.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-green.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-light.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-orange.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/img/default-header.jpg create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/img/login.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/img/login_bg.jpg create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/img/login_logo.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/img/logo.jpg create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/img/logo.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/img/orange-group1.png create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/package.json create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/style/base.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/style/element-variables.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/style/form-style.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/style/index.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/style/transition.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/alert.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/aside.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/autocomplete.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/avatar.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/backtop.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/badge.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/base.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/breadcrumb-item.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/breadcrumb.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/button-group.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/button.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/calendar.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/card.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/carousel-item.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/carousel.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/cascader-panel.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/cascader.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/checkbox-button.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/checkbox-group.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/checkbox.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/col.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/collapse-item.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/collapse.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/color-picker.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/container.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/date-picker.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/dialog.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/display.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/divider.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/drawer.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/dropdown-item.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/dropdown-menu.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/dropdown.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/element-variables-blue.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/element-variables-dark.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/element-variables-green.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/element-variables-light.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/element-variables-orange.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/element-variables.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/fonts/element-icons.ttf create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/fonts/element-icons.woff create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/footer.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/form-item.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/form.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/header.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/icon.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/image.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/index.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/infinite-scroll.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/infiniteScroll.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/input-number.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/input.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/link.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/loading.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/main.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/menu-item-group.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/menu-item.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/menu.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/message-box.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/message.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/notification.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/option-group.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/option.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/page-header.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/pagination.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/popconfirm.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/popover.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/popper.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/progress.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/radio-button.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/radio-group.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/radio.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/rate.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/reset.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/row.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/scrollbar.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/select-dropdown.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/select.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/slider.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/spinner.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/step.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/steps.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/submenu.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/switch.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/tab-pane.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/table-column.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/table.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/tabs.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/tag.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/time-picker.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/time-select.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/timeline-item.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/timeline.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/tooltip.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/transfer.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/tree.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/assets/theme/upload.css create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/DateRange/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/Dialog/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/FilterBox/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/Hamburger/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/IconSelect/icon.json create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/IconSelect/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/InputNumberRange/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/Progress/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/RichEditor/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/TableProgressColumn/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/components/TreeSelect/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/config/development.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/config/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/config/production.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/directive/sortable.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/directive/sortableData.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/http/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/http/request.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/http/requestUrl.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/mixins/global.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/core/mixins/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/main.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/registerServiceWorker.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/router/import-development.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/router/import-production.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/router/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/router/systemRouters.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/staticDict/flowStaticDict.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/staticDict/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/staticDict/onlineStaticDict.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/store/actions.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/store/getters.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/store/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/store/mutations.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/store/state.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/store/utils/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/utils/chartOption.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/utils/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/utils/validate.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/utils/widget.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/layout/components/breadcrumb/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/layout/components/formModifyPassword/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/layout/components/sidebar/menu-item.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/layout/components/sidebar/sidebar.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/layout/components/tags/tagItem.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/layout/components/tags/tagPanel.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/layout/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/login/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/customFilterWidget.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/customImage.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/customTable.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/customText.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/customUpload.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/customWidget.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/dragableFilterBox.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/editDictParamValue.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/editFormParam.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/editTableQueryParam.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/editWidgetTableColumn.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/editWidgetTableOperation.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/editableWidgetItem.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/components/formGenerator.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/data/onlineFormOptions.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlineDict/editDictDataButton.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlineDict/editOnlineDict.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlineDict/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlinePage/editOnlineForm.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlinePage/editOnlinePageDatasource.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlinePage/editOnlinePageDatasourceRelation.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlinePage/editVirtualColumnFilter.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlinePage/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlinePage/onlinePageSetting.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlinePage/onlinePageTableColumnRule.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlinePage/onlinePageVirtualColumn.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formOnlinePage/setOnlineTableColumnRule.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formRender/onlineEditForm.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formRender/onlineFormMixins.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formRender/onlineQueryForm.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formRender/onlineWorkOrder.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/formRender/workflowForm.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/onlineForm/utils/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formDictManagement/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditDict/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysDataPerm/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysDept/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysMenu/editColumn.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysMenu/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysPerm/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysPermCode/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysPermModule/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysPost/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysRole/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formEditSysUser/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formMenuPerm/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSetRoleUsers/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSetSysDataPermUser/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysDataPerm/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysDept/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysDeptPost/formSetDeptPost.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysDeptPost/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysLoginUser/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysMenu/formSysColumnMenu.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysMenu/formSysMenuPerm.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysMenu/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysPerm/formSysPermDetail.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysPerm/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysPermCode/formSysPermCodeDetail.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysPermCode/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysPost/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysRole/formSysRolePerm.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysRole/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysUser/formSysUserPerm.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/upms/formSysUser/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/welcome/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/components/HandlerFlowTask.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/components/ProcessDesigner.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/components/ProcessViewer.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/components/TagSelect.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/components/TaskCommit.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/components/TaskGroupSelect.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/components/TaskPostSelect.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/components/TaskUserSelect.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/flowCategory/formEditFlowCategory.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/flowCategory/formFlowCategory.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/flowEntry/formEditFlowEntry.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/flowEntry/formEditFlowEntryVariable.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/flowEntry/formFlowEntry.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/flowEntry/formPublishedFlowEntry.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/handlerFlowTask/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/mixins/flowMixins.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/highlight/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/ProcessDesigner.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/content-pad/contentPadProvider.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/content-pad/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/defaultEmpty.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/descriptor/activitiDescriptor.json create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/descriptor/camundaDescriptor.json create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/descriptor/flowableDescriptor.json create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/extension-moddle/activiti/activitiExtension.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/extension-moddle/activiti/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/extension-moddle/camunda/extension.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/extension-moddle/camunda/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/extension-moddle/flowable/flowableExtension.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/extension-moddle/flowable/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/palette/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/palette/paletteProvider.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/translate/customTranslate.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/process-designer/plugins/translate/zh.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/PropertiesPanel.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/base/ElementBaseInfo.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/flow-condition/FlowCondition.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/form-variable/index.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/form/ElementForm.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/form/flowFormConfig.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/form/formEditOperation.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/index.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/listeners/ElementListeners.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/listeners/UserTaskListeners.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/listeners/template.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/listeners/utilSelf.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/multi-instance/ElementMultiInstance.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/multi-instance/ElementMultiInstanceAssignee.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/other/ElementOtherConfig.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/properties/ElementProperties.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/signal-message/SignalAndMessage.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/task/ElementTask.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/task/task-components/ReceiveTask.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/task/task-components/ScriptTask.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/refactor/task/task-components/UserTask.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/theme/flow-element-variables.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/theme/index.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/theme/process-designer.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/theme/process-panel.scss create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/package/utils.js create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/taskManager/formAllInstance.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/taskManager/formMyApprovedTask.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/taskManager/formMyHistoryTask.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/taskManager/formMyTask.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/taskManager/formTaskProcessViewer.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/src/views/workflow/taskManager/stopTask.vue create mode 100644 orange-demo-flowable/orange-demo-flowable-web/static/.gitkeep create mode 100644 orange-demo-flowable/orange-demo-flowable-web/vue.config.js diff --git a/orange-demo-flowable/orange-demo-flowable-service/.gitignore b/orange-demo-flowable/orange-demo-flowable-service/.gitignore new file mode 100644 index 00000000..ac242580 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/.gitignore @@ -0,0 +1,26 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar +/.mvn/* + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/README.md b/orange-demo-flowable/orange-demo-flowable-service/README.md new file mode 100644 index 00000000..0939c817 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/README.md @@ -0,0 +1,15 @@ +### 服务接口文档 +--- +- Postman + - 无需启动服务,即可将当前工程的接口导出成Postman格式。在工程的common/common-tools/模块下,找到ExportApiApp文件,并执行main函数。 + +### 服务启动环境依赖 +--- + +执行docker-compose up -d 命令启动下面依赖的服务。 +执行docker-compose down 命令停止下面服务。 + +- Redis + - 版本:4 + - 端口: 6379 + - 推荐客户端工具 [AnotherRedisDesktopManager](https://github.com/qishibo/AnotherRedisDesktopManager) diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/pom.xml new file mode 100644 index 00000000..628a6304 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/pom.xml @@ -0,0 +1,82 @@ + + + + com.flow.demo + DemoFlow + 1.0.0 + + 4.0.0 + + application-webadmin + 1.0.0 + application + jar + + + + + com.flow.demo + common-redis + 1.0.0 + + + com.flow.demo + common-online-api + 1.0.0 + + + com.flow.demo + common-flow-online + 1.0.0 + + + com.flow.demo + common-log + 1.0.0 + + + com.flow.demo + common-sequence + 1.0.0 + + + com.flow.demo + common-datafilter + 1.0.0 + + + + + + + src/main/resources + + **/*.* + + false + + + src/main/java + + **/*.xml + + false + + + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/WebAdminApplication.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/WebAdminApplication.java new file mode 100644 index 00000000..dcecef95 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/WebAdminApplication.java @@ -0,0 +1,23 @@ +package com.flow.demo.webadmin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableAsync; + +/** + * 应用服务启动类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EnableAsync +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +@ComponentScan("com.flow.demo") +public class WebAdminApplication { + + public static void main(String[] args) { + SpringApplication.run(WebAdminApplication.class, args); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/controller/AreaCodeController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/controller/AreaCodeController.java new file mode 100644 index 00000000..6d88cd24 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/controller/AreaCodeController.java @@ -0,0 +1,72 @@ +package com.flow.demo.webadmin.app.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.flow.demo.webadmin.app.model.AreaCode; +import com.flow.demo.webadmin.app.service.AreaCodeService; +import com.flow.demo.common.core.object.ResponseResult; +import com.flow.demo.common.core.annotation.MyRequestBody; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.*; + +/** + * 行政区划数据访问接口类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@RestController +@RequestMapping("/admin/app/areaCode") +public class AreaCodeController { + + @Autowired + private AreaCodeService areaCodeService; + + /** + * 按照字典的形式返回行政区划列表。 + * + * @return 字典形式的行政区划列表。 + */ + @GetMapping("/listDict") + public ResponseResult>> listDict() { + List resultList = areaCodeService.getAllListFromCache(); + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "areaId as id", "areaName as name").executeFrom(resultList)); + } + + /** + * 根据上级行政区划Id获取其下级行政区划列表。 + * + * @param parentId 上级行政区划Id。 + * @return 按照字典的形式返回下级行政区划列表。 + */ + @GetMapping("/listDictByParentId") + public ResponseResult>> listDictByParentId(@RequestParam(required = false) Long parentId) { + Collection resultList = areaCodeService.getListByParentId(parentId); + if (CollectionUtils.isEmpty(resultList)) { + return ResponseResult.success(new LinkedList<>()); + } + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "areaId as id", "areaName as name").executeFrom(resultList)); + } + + /** + * 根据字典Id集合,获取查询后的字典数据。 + * + * @param dictIds 字典Id集合。 + * @return 字典形式的行政区划列表。 + */ + @PostMapping("/listDictByIds") + public ResponseResult>> listDictByIds( + @MyRequestBody(elementType = Long.class) List dictIds) { + List resultList = areaCodeService.getInList(new HashSet<>(dictIds)); + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "areaId as id", "areaName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/dao/AreaCodeMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/dao/AreaCodeMapper.java new file mode 100644 index 00000000..21e069c4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/dao/AreaCodeMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.webadmin.app.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.app.model.AreaCode; + +/** + * 行政区划数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface AreaCodeMapper extends BaseDaoMapper { +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/dao/mapper/AreaCodeMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/dao/mapper/AreaCodeMapper.xml new file mode 100644 index 00000000..dd9cdadd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/dao/mapper/AreaCodeMapper.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/model/AreaCode.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/model/AreaCode.java new file mode 100644 index 00000000..bbf3026d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/model/AreaCode.java @@ -0,0 +1,39 @@ +package com.flow.demo.webadmin.app.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 行政区划实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_area_code") +public class AreaCode { + + /** + * 行政区划主键Id + */ + @TableId(value = "area_id") + private Long areaId; + + /** + * 行政区划名称 + */ + @TableField(value = "area_name") + private String areaName; + + /** + * 行政区划级别 (1: 省级别 2: 市级别 3: 区级别) + */ + @TableField(value = "area_level") + private Integer areaLevel; + + /** + * 父级行政区划Id + */ + @TableField(value = "parent_id") + private Long parentId; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/service/AreaCodeService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/service/AreaCodeService.java new file mode 100644 index 00000000..df824c5b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/service/AreaCodeService.java @@ -0,0 +1,23 @@ +package com.flow.demo.webadmin.app.service; + +import com.flow.demo.common.core.base.service.IBaseDictService; +import com.flow.demo.webadmin.app.model.AreaCode; + +import java.util.Collection; + +/** + * 行政区划的Service接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface AreaCodeService extends IBaseDictService { + + /** + * 根据上级行政区划Id,获取其下级行政区划列表。 + * + * @param parentId 上级行政区划Id。 + * @return 下级行政区划列表。 + */ + Collection getListByParentId(Long parentId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/service/impl/AreaCodeServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/service/impl/AreaCodeServiceImpl.java new file mode 100644 index 00000000..a4d02a74 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/service/impl/AreaCodeServiceImpl.java @@ -0,0 +1,52 @@ +package com.flow.demo.webadmin.app.service.impl; + +import com.flow.demo.webadmin.app.service.AreaCodeService; +import com.flow.demo.webadmin.app.dao.AreaCodeMapper; +import com.flow.demo.webadmin.app.model.AreaCode; +import com.flow.demo.common.core.cache.MapTreeDictionaryCache; +import com.flow.demo.common.core.base.service.BaseDictService; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.Collection; + +/** + * 行政区划的Service类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Service("areaCodeService") +public class AreaCodeServiceImpl extends BaseDictService implements AreaCodeService { + + @Autowired + private AreaCodeMapper areaCodeMapper; + + public AreaCodeServiceImpl() { + super(); + this.dictionaryCache = MapTreeDictionaryCache.create(AreaCode::getAreaId, AreaCode::getParentId); + } + + @PostConstruct + public void init() { + this.reloadCachedData(true); + } + + @Override + protected BaseDaoMapper mapper() { + return areaCodeMapper; + } + + /** + * 根据上级行政区划Id,获取其下级行政区划列表。 + * + * @param parentId 上级行政区划Id。 + * @return 下级行政区划列表。 + */ + @Override + public Collection getListByParentId(Long parentId) { + return ((MapTreeDictionaryCache) dictionaryCache).getListByParentId(parentId); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/util/FlowDeptPostExtHelper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/util/FlowDeptPostExtHelper.java new file mode 100644 index 00000000..a00a4e8b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/util/FlowDeptPostExtHelper.java @@ -0,0 +1,45 @@ +package com.flow.demo.webadmin.app.util; + +import cn.hutool.core.collection.CollUtil; +import com.flow.demo.common.flow.util.BaseFlowDeptPostExtHelper; +import com.flow.demo.common.flow.util.FlowCustomExtFactory; +import com.flow.demo.webadmin.upms.service.SysDeptService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.List; + +/** + * 为流程提供所需的部门岗位等扩展信息的帮助类。如本部门领导岗位和上级部门领导岗位。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Component +public class FlowDeptPostExtHelper implements BaseFlowDeptPostExtHelper { + + @Autowired + private SysDeptService sysDeptService; + @Autowired + private FlowCustomExtFactory flowCustomExtFactory; + + @PostConstruct + public void doRegister() { + flowCustomExtFactory.registerFlowDeptPostExtHelper(this); + } + + @Override + public Long getLeaderDeptPostId(Long deptId) { + List deptPostIdList = sysDeptService.getLeaderDeptPostIdList(deptId); + return CollUtil.isEmpty(deptPostIdList) ? null : deptPostIdList.get(0); + } + + @Override + public Long getUpLeaderDeptPostId(Long deptId) { + List deptPostIdList = sysDeptService.getUpLeaderDeptPostIdList(deptId); + return CollUtil.isEmpty(deptPostIdList) ? null : deptPostIdList.get(0); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/vo/AreaCodeVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/vo/AreaCodeVo.java new file mode 100644 index 00000000..7e1051a5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/app/vo/AreaCodeVo.java @@ -0,0 +1,33 @@ +package com.flow.demo.webadmin.app.vo; + +import lombok.Data; + +/** + * 行政区划DomainVO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class AreaCodeVo { + + /** + * 行政区划主键Id + */ + private Long areaId; + + /** + * 行政区划名称 + */ + private String areaName; + + /** + * 行政区划级别 (1: 省级别 2: 市级别 3: 区级别) + */ + private Integer areaLevel; + + /** + * 父级行政区划Id + */ + private Long parentId; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/ApplicationConfig.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/ApplicationConfig.java new file mode 100644 index 00000000..2be23ed5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/ApplicationConfig.java @@ -0,0 +1,51 @@ +package com.flow.demo.webadmin.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * 应用程序自定义的程序属性配置文件。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "application") +public class ApplicationConfig { + + /** + * token的Http Request Header的key + */ + private String tokenHeaderKey; + /** + * token在过期之前,但是已经需要被刷新时,response返回的header信息的key。 + */ + private String refreshedTokenHeaderKey; + /** + * token 加密用的密钥,该值的长度最少10个字符(过短会报错)。 + */ + private String tokenSigningKey; + /** + * 令牌的过期时间,单位毫秒 + */ + private Long expiration; + /** + * 用户密码被重置之后的缺省密码 + */ + private String defaultUserPassword; + /** + * 上传文件的基础目录 + */ + private String uploadFileBaseDir; + /** + * 授信ip列表,没有填写表示全部信任。多个ip之间逗号分隔,如: http://10.10.10.1:8080,http://10.10.10.2:8080 + */ + private String credentialIpList; + /** + * Session的用户权限在Redis中的过期时间(秒)。 + * 缺省值是 one day + */ + private int sessionExpiredSeconds = 86400; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/DataSourceType.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/DataSourceType.java new file mode 100644 index 00000000..92876210 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/DataSourceType.java @@ -0,0 +1,36 @@ +package com.flow.demo.webadmin.config; + +import java.util.HashMap; +import java.util.Map; + +/** + * 表示数据源类型的常量对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class DataSourceType { + + public static final int MAIN = 0; + + private static final Map TYPE_MAP = new HashMap<>(2); + static { + TYPE_MAP.put("main", MAIN); + } + + /** + * 根据名称获取字典类型。 + * + * @param name 数据源在配置中的名称。 + * @return 返回可用于多数据源切换的数据源类型。 + */ + public static Integer getDataSourceTypeByName(String name) { + return TYPE_MAP.get(name); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private DataSourceType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/FilterConfig.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/FilterConfig.java new file mode 100644 index 00000000..2e9d2117 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/FilterConfig.java @@ -0,0 +1,57 @@ +package com.flow.demo.webadmin.config; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +import javax.servlet.Filter; +import java.nio.charset.StandardCharsets; + +/** + * 这里主要配置Web的各种过滤器和监听器等Servlet容器组件。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +public class FilterConfig { + + /** + * 配置Ajax跨域过滤器。 + */ + @Bean + public CorsFilter corsFilterRegistration(ApplicationConfig applicationConfig) { + UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(); + CorsConfiguration corsConfiguration = new CorsConfiguration(); + if (StringUtils.isNotBlank(applicationConfig.getCredentialIpList())) { + String[] credentialIpList = StringUtils.split(applicationConfig.getCredentialIpList(), ","); + if (credentialIpList.length > 0) { + for (String ip : credentialIpList) { + corsConfiguration.addAllowedOrigin(ip); + } + } + corsConfiguration.addAllowedHeader("*"); + corsConfiguration.addAllowedMethod("*"); + corsConfiguration.addExposedHeader(applicationConfig.getRefreshedTokenHeaderKey()); + corsConfiguration.setAllowCredentials(true); + configSource.registerCorsConfiguration("/**", corsConfiguration); + } + return new CorsFilter(configSource); + } + + @Bean + public FilterRegistrationBean characterEncodingFilterRegistration() { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>( + new org.springframework.web.filter.CharacterEncodingFilter()); + filterRegistrationBean.addUrlPatterns("/*"); + filterRegistrationBean.addInitParameter("encoding", StandardCharsets.UTF_8.name()); + // forceEncoding强制response也被编码,另外即使request中已经设置encoding,forceEncoding也会重新设置 + filterRegistrationBean.addInitParameter("forceEncoding", "true"); + filterRegistrationBean.setAsyncSupported(true); + return filterRegistrationBean; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/InterceptorConfig.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/InterceptorConfig.java new file mode 100644 index 00000000..854e9fbc --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/InterceptorConfig.java @@ -0,0 +1,21 @@ +package com.flow.demo.webadmin.config; + +import com.flow.demo.webadmin.interceptor.AuthenticationInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 所有的项目拦截器都在这里集中配置 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +public class InterceptorConfig implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new AuthenticationInterceptor()).addPathPatterns("/admin/**"); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/MultiDataSourceConfig.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/MultiDataSourceConfig.java new file mode 100644 index 00000000..b7440328 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/config/MultiDataSourceConfig.java @@ -0,0 +1,44 @@ +package com.flow.demo.webadmin.config; + +import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder; +import com.flow.demo.common.core.config.DynamicDataSource; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.mybatis.spring.annotation.MapperScan; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + +/** + * 多数据源配置对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +@EnableTransactionManagement +@MapperScan(value = {"com.flow.demo.webadmin.*.dao", "com.flow.demo.common.*.dao"}) +public class MultiDataSourceConfig { + + @Bean(initMethod = "init", destroyMethod = "close") + @ConfigurationProperties(prefix = "spring.datasource.druid.main") + public DataSource mainDataSource() { + return DruidDataSourceBuilder.create().build(); + } + + @Bean + @Primary + public DynamicDataSource dataSource() { + Map targetDataSources = new HashMap<>(1); + targetDataSources.put(DataSourceType.MAIN, mainDataSource()); + // 如果当前工程支持在线表单,这里请务必保证upms数据表所在数据库为缺省数据源。 + DynamicDataSource dynamicDataSource = new DynamicDataSource(); + dynamicDataSource.setTargetDataSources(targetDataSources); + dynamicDataSource.setDefaultTargetDataSource(mainDataSource()); + return dynamicDataSource; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/interceptor/AuthenticationInterceptor.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/interceptor/AuthenticationInterceptor.java new file mode 100644 index 00000000..611a4cca --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/interceptor/AuthenticationInterceptor.java @@ -0,0 +1,139 @@ +package com.flow.demo.webadmin.interceptor; + +import com.alibaba.fastjson.JSON; +import com.flow.demo.webadmin.config.ApplicationConfig; +import com.flow.demo.webadmin.upms.model.SysPermWhitelist; +import com.flow.demo.webadmin.upms.service.SysPermWhitelistService; +import com.flow.demo.webadmin.upms.service.SysPermService; +import com.flow.demo.common.core.annotation.NoAuthInterface; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.ResponseResult; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.core.util.ApplicationContextHolder; +import com.flow.demo.common.core.util.JwtUtil; +import com.flow.demo.common.core.util.RedisKeyUtil; +import io.jsonwebtoken.Claims; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.redisson.api.RBucket; +import org.redisson.api.RSet; +import org.redisson.api.RedissonClient; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Set; +import java.util.List; +import java.util.stream.Collectors; + +/** + * 登录用户Token验证、生成和权限验证的拦截器。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class AuthenticationInterceptor implements HandlerInterceptor { + + private final ApplicationConfig appConfig = + ApplicationContextHolder.getBean("applicationConfig"); + + private final RedissonClient redissonClient = ApplicationContextHolder.getBean(RedissonClient.class); + + private final SysPermService sysPermService = + ApplicationContextHolder.getBean(SysPermService.class); + + private static SysPermWhitelistService sysPermWhitelistService = + ApplicationContextHolder.getBean(SysPermWhitelistService.class); + + private static Set whitelistPermSet; + + static { + List sysPermWhitelistList = sysPermWhitelistService.getAllList(); + whitelistPermSet = sysPermWhitelistList.stream() + .map(SysPermWhitelist::getPermUrl).collect(Collectors.toSet()); + } + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + String url = request.getRequestURI(); + // 如果接口方法标记NoAuthInterface注解,可以直接跳过Token鉴权验证,这里主要为了测试接口方便 + if (handler instanceof HandlerMethod) { + HandlerMethod hm = (HandlerMethod) handler; + if (hm.getBeanType().getAnnotation(NoAuthInterface.class) != null + || hm.getMethodAnnotation(NoAuthInterface.class) != null) { + return true; + } + } + String token = request.getHeader(appConfig.getTokenHeaderKey()); + if (StringUtils.isBlank(token)) { + token = request.getParameter(appConfig.getTokenHeaderKey()); + } + Claims c = JwtUtil.parseToken(token, appConfig.getTokenSigningKey()); + if (JwtUtil.isNullOrExpired(c)) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + this.outputResponseMessage(response, + ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, "用户会话已过期或尚未登录,请重新登录!")); + return false; + } + String sessionId = (String) c.get("sessionId"); + String sessionIdKey = RedisKeyUtil.makeSessionIdKey(sessionId); + RBucket sessionData = redissonClient.getBucket(sessionIdKey); + TokenData tokenData = null; + if (sessionData.isExists()) { + tokenData = JSON.parseObject(sessionData.get(), TokenData.class); + } + if (tokenData == null) { + response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); + this.outputResponseMessage(response, + ResponseResult.error(ErrorCodeEnum.UNAUTHORIZED_LOGIN, "用户会话已失效,请重新登录!")); + return false; + } + TokenData.addToRequest(tokenData); + // 如果url在权限资源白名单中,则不需要进行鉴权操作 + if (Boolean.FALSE.equals(tokenData.getIsAdmin()) && !whitelistPermSet.contains(url)) { + RSet permSet = redissonClient.getSet(RedisKeyUtil.makeSessionPermIdKey(sessionId)); + if (!permSet.contains(url)) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + this.outputResponseMessage(response, ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION)); + return false; + } + } + if (JwtUtil.needToRefresh(c)) { + String refreshedToken = JwtUtil.generateToken(c, appConfig.getExpiration(), appConfig.getTokenSigningKey()); + response.addHeader(appConfig.getRefreshedTokenHeaderKey(), refreshedToken); + } + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + // 这里需要空注解,否则sonar会不happy。 + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception { + // 这里需要空注解,否则sonar会不happy。 + } + + private void outputResponseMessage(HttpServletResponse response, ResponseResult respObj) { + PrintWriter out; + try { + out = response.getWriter(); + } catch (IOException e) { + log.error("Failed to call OutputResponseMessage.", e); + return; + } + response.setContentType("application/json; charset=utf-8"); + out.print(JSON.toJSONString(respObj)); + out.flush(); + out.close(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/LoginController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/LoginController.java new file mode 100644 index 00000000..23bdd2c3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/LoginController.java @@ -0,0 +1,292 @@ +package com.flow.demo.webadmin.upms.controller; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.serializer.SerializerFeature; +import lombok.extern.slf4j.Slf4j; +import com.flow.demo.webadmin.config.ApplicationConfig; +import com.flow.demo.webadmin.upms.service.*; +import com.flow.demo.webadmin.upms.model.*; +import com.flow.demo.webadmin.upms.model.constant.SysUserStatus; +import com.flow.demo.webadmin.upms.model.constant.SysUserType; +import com.flow.demo.webadmin.upms.model.constant.SysMenuType; +import com.flow.demo.webadmin.upms.model.constant.SysOnlineMenuPermType; +import com.flow.demo.common.online.util.OnlineUtil; +import com.flow.demo.common.online.model.OnlineDatasource; +import com.flow.demo.common.online.service.OnlineDatasourceService; +import com.flow.demo.common.online.api.config.OnlineApiProperties; +import com.flow.demo.common.core.annotation.NoAuthInterface; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ApplicationConstant; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.redis.cache.SessionCacheHelper; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.redisson.api.RBucket; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.web.bind.annotation.*; + +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 登录接口控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/login") +public class LoginController { + + @Autowired + private SysUserService sysUserService; + @Autowired + private SysMenuService sysMenuService; + @Autowired + private SysPermCodeService sysPermCodeService; + @Autowired + private SysPermService sysPermService; + @Autowired + private SysPostService sysPostService; + @Autowired + private SysDataPermService sysDataPermService; + @Autowired + private OnlineDatasourceService onlineDatasourceService; + @Autowired + private OnlineApiProperties onlineProperties; + @Autowired + private ApplicationConfig appConfig; + @Autowired + private RedissonClient redissonClient; + @Autowired + private SessionCacheHelper cacheHelper; + @Autowired + private PasswordEncoder passwordEncoder; + + /** + * 登录接口。 + * + * @param loginName 登录名。 + * @param password 密码。 + * @return 应答结果对象,其中包括JWT的Token数据,以及菜单列表。 + */ + @NoAuthInterface + @PostMapping("/doLogin") + public ResponseResult doLogin( + @MyRequestBody String loginName, @MyRequestBody String password) throws Exception { + if (MyCommonUtil.existBlankArgument(loginName, password)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysUser user = sysUserService.getSysUserByLoginName(loginName); + password = URLDecoder.decode(password, StandardCharsets.UTF_8.name()); + // NOTE: 第一次使用时,请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。 + // 执行RsaUtil工具类中的main函数,可以生成新的公钥和私钥。 + password = RsaUtil.decrypt(password, ApplicationConstant.PRIVATE_KEY); + if (user == null || !passwordEncoder.matches(password, user.getPassword())) { + return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD); + } + String errorMessage; + if (user.getUserStatus() == SysUserStatus.STATUS_LOCKED) { + errorMessage = "登录失败,用户账号被锁定!"; + return ResponseResult.error(ErrorCodeEnum.INVALID_USER_STATUS, errorMessage); + } + String patternKey = RedisKeyUtil.getSessionIdPrefix(user.getLoginName(), MyCommonUtil.getDeviceType()) + "*"; + redissonClient.getKeys().deleteByPatternAsync(patternKey); + JSONObject jsonData = this.buildLoginData(user); + return ResponseResult.success(jsonData); + } + + /** + * 登出操作。同时将Session相关的信息从缓存中删除。 + * + * @return 应答结果对象。 + */ + @PostMapping("/doLogout") + public ResponseResult doLogout() { + TokenData tokenData = TokenData.takeFromRequest(); + String sessionIdKey = RedisKeyUtil.makeSessionIdKey(tokenData.getSessionId()); + redissonClient.getBucket(sessionIdKey).delete(); + sysPermService.removeUserSysPermCache(tokenData.getSessionId()); + sysDataPermService.removeDataPermCache(tokenData.getSessionId()); + cacheHelper.removeAllSessionCache(tokenData.getSessionId()); + return ResponseResult.success(); + } + + /** + * 在登录之后,通过token再次获取登录信息。 + * 用于在当前浏览器登录系统后,在新tab页中可以免密登录。 + * + * @return 应答结果对象,其中包括JWT的Token数据,以及菜单列表。 + */ + @GetMapping("/getLoginInfo") + public ResponseResult getLoginInfo() { + TokenData tokenData = TokenData.takeFromRequest(); + // 这里解释一下为什么没有缓存menuList和permCodeList。 + // 1. 该操作和权限验证不同,属于低频操作。 + // 2. 第一次登录和再次获取登录信息之间,如果修改了用户的权限,那么本次获取的是最新权限。 + // 3. 上一个问题无法避免,因为即便缓存也是有过期时间的,过期之后还是要从数据库获取的。 + JSONObject jsonData = new JSONObject(); + jsonData.put("showName", tokenData.getShowName()); + jsonData.put("isAdmin", tokenData.getIsAdmin()); + Collection menuList; + Collection permCodeList; + if (tokenData.getIsAdmin()) { + menuList = sysMenuService.getAllMenuList(); + permCodeList = sysPermCodeService.getAllPermCodeList(); + } else { + menuList = sysMenuService.getMenuListByUserId(tokenData.getUserId()); + permCodeList = sysPermCodeService.getPermCodeListByUserId(tokenData.getUserId()); + } + jsonData.put("menuList", menuList); + jsonData.put("permCodeList", permCodeList); + return ResponseResult.success(jsonData); + } + + /** + * 用户修改自己的密码。 + * + * @param oldPass 原有密码。 + * @param newPass 新密码。 + * @return 应答结果对象。 + */ + @PostMapping("/changePassword") + public ResponseResult changePassword( + @MyRequestBody String oldPass, @MyRequestBody String newPass) throws Exception { + if (MyCommonUtil.existBlankArgument(oldPass, oldPass)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + TokenData tokenData = TokenData.takeFromRequest(); + SysUser user = sysUserService.getById(tokenData.getUserId()); + oldPass = URLDecoder.decode(oldPass, StandardCharsets.UTF_8.name()); + // NOTE: 第一次使用时,请务必阅读ApplicationConstant.PRIVATE_KEY的代码注释。 + // 执行RsaUtil工具类中的main函数,可以生成新的公钥和私钥。 + oldPass = RsaUtil.decrypt(oldPass, ApplicationConstant.PRIVATE_KEY); + if (user == null || !passwordEncoder.matches(oldPass, user.getPassword())) { + return ResponseResult.error(ErrorCodeEnum.INVALID_USERNAME_PASSWORD); + } + newPass = URLDecoder.decode(newPass, StandardCharsets.UTF_8.name()); + newPass = RsaUtil.decrypt(newPass, ApplicationConstant.PRIVATE_KEY); + if (!sysUserService.changePassword(tokenData.getUserId(), newPass)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + private JSONObject buildLoginData(SysUser user) { + int deviceType = MyCommonUtil.getDeviceType(); + boolean isAdmin = user.getUserType() == SysUserType.TYPE_ADMIN; + Map claims = new HashMap<>(3); + String sessionId = user.getLoginName() + "_" + deviceType + "_" + MyCommonUtil.generateUuid(); + claims.put("sessionId", sessionId); + String token = JwtUtil.generateToken(claims, appConfig.getExpiration(), appConfig.getTokenSigningKey()); + JSONObject jsonData = new JSONObject(); + jsonData.put(TokenData.REQUEST_ATTRIBUTE_NAME, token); + jsonData.put("showName", user.getShowName()); + jsonData.put("isAdmin", isAdmin); + TokenData tokenData = new TokenData(); + tokenData.setSessionId(sessionId); + tokenData.setUserId(user.getUserId()); + tokenData.setDeptId(user.getDeptId()); + tokenData.setLoginName(user.getLoginName()); + tokenData.setShowName(user.getShowName()); + tokenData.setIsAdmin(isAdmin); + tokenData.setLoginIp(IpUtil.getRemoteIpAddress(ContextUtil.getHttpRequest())); + tokenData.setLoginTime(new Date()); + tokenData.setDeviceType(deviceType); + List userPostList = sysPostService.getSysUserPostListByUserId(user.getUserId()); + if (CollectionUtils.isNotEmpty(userPostList)) { + Set deptPostIdSet = userPostList.stream().map(SysUserPost::getDeptPostId).collect(Collectors.toSet()); + tokenData.setDeptPostIds(StringUtils.join(deptPostIdSet, ",")); + } + String sessionIdKey = RedisKeyUtil.makeSessionIdKey(sessionId); + String sessionData = JSON.toJSONString(tokenData, SerializerFeature.WriteNonStringValueAsString); + RBucket bucket = redissonClient.getBucket(sessionIdKey); + bucket.set(sessionData); + bucket.expire(appConfig.getSessionExpiredSeconds(), TimeUnit.SECONDS); + // 这里手动将TokenData存入request,便于OperationLogAspect统一处理操作日志。 + TokenData.addToRequest(tokenData); + Collection menuList; + Collection permCodeList; + if (isAdmin) { + menuList = sysMenuService.getAllMenuList(); + permCodeList = sysPermCodeService.getAllPermCodeList(); + } else { + menuList = sysMenuService.getMenuListByUserId(user.getUserId()); + permCodeList = sysPermCodeService.getPermCodeListByUserId(user.getUserId()); + } + List onlineMenuList; + if (isAdmin) { + onlineMenuList = sysMenuService.getAllOnlineMenuList(SysMenuType.TYPE_BUTTON); + } else { + onlineMenuList = sysMenuService.getOnlineMenuListByUserId(user.getUserId(), SysMenuType.TYPE_BUTTON); + } + OnlinePermData onlinePermData = this.getOnlinePermCodeSet(onlineMenuList); + if (CollectionUtils.isNotEmpty(onlinePermData.permCodeSet)) { + permCodeList.addAll(onlinePermData.permCodeSet); + } + jsonData.put("menuList", menuList); + jsonData.put("permCodeList", permCodeList); + if (user.getUserType() != SysUserType.TYPE_ADMIN) { + // 缓存用户的权限资源 + sysPermService.putUserSysPermCache(sessionId, user.getUserId()); + sysPermService.putOnlinePermToCache(sessionId, onlinePermData.permUrlSet); + sysDataPermService.putDataPermCache(sessionId, user.getUserId(), user.getDeptId()); + } + return jsonData; + } + + private OnlinePermData getOnlinePermCodeSet(List onlineMenuList) { + OnlinePermData permData = new OnlinePermData(); + if (CollectionUtils.isEmpty(onlineMenuList)) { + return permData; + } + Set viewFormIdSet = new HashSet<>(); + Set editFormIdSet = new HashSet<>(); + for (SysMenu menu : onlineMenuList) { + if (menu.getOnlineMenuPermType() == SysOnlineMenuPermType.TYPE_VIEW) { + viewFormIdSet.add(menu.getOnlineFormId()); + } else if (menu.getOnlineMenuPermType() == SysOnlineMenuPermType.TYPE_EDIT) { + editFormIdSet.add(menu.getOnlineFormId()); + } + } + if (CollectionUtils.isNotEmpty(viewFormIdSet)) { + List viewDatasourceList = + onlineDatasourceService.getOnlineDatasourceListByFormIds(viewFormIdSet); + for (OnlineDatasource datasource : viewDatasourceList) { + permData.permCodeSet.add(OnlineUtil.makeViewPermCode(datasource.getVariableName())); + for (String permUrl : onlineProperties.getViewUrlList()) { + permData.permUrlSet.add(permUrl + datasource.getVariableName()); + } + } + } + if (CollectionUtils.isNotEmpty(editFormIdSet)) { + List editableDatasourceList = + onlineDatasourceService.getOnlineDatasourceListByFormIds(editFormIdSet); + for (OnlineDatasource datasource : editableDatasourceList) { + permData.permCodeSet.add(OnlineUtil.makeEditPermCode(datasource.getVariableName())); + for (String permUrl : onlineProperties.getEditUrlList()) { + permData.permUrlSet.add(permUrl + datasource.getVariableName()); + } + } + } + // 这个非常非常重要,不能删除。因为在线票单的url前缀是可以配置的,那么表单字典接口的url也是动态。 + // 所以就不能把这个字典列表接口放到数据库的白名单表中。 + permData.permUrlSet.add(onlineProperties.getUrlPrefix() + "/onlineOperation/listDict"); + permData.permUrlSet.add(onlineProperties.getUrlPrefix() + "/onlineForm/render"); + return permData; + } + + static class OnlinePermData { + public final Set permCodeSet = new HashSet<>(); + public final Set permUrlSet = new HashSet<>(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/LoginUserController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/LoginUserController.java new file mode 100644 index 00000000..7369509e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/LoginUserController.java @@ -0,0 +1,81 @@ +package com.flow.demo.webadmin.upms.controller; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.RedisKeyUtil; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RBucket; +import org.redisson.api.RedissonClient; +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 java.util.*; + +/** + * 在线用户控制器对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/loginUser") +public class LoginUserController { + + @Autowired + private RedissonClient redissonClient; + + /** + * 显示在线用户列表。 + * + * @param loginName 登录名过滤。 + * @param pageParam 分页参数。 + * @return 登录用户信息列表。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody String loginName, @MyRequestBody MyPageParam pageParam) { + int queryCount = pageParam.getPageNum() * pageParam.getPageSize(); + int skipCount = (pageParam.getPageNum() - 1) * pageParam.getPageSize(); + String patternKey; + if (StrUtil.isBlank(loginName)) { + patternKey = RedisKeyUtil.getSessionIdPrefix() + "*"; + } else { + patternKey = RedisKeyUtil.getSessionIdPrefix(loginName) + "*"; + } + List loginUserInfoList = new LinkedList<>(); + Iterable keys = redissonClient.getKeys().getKeysByPattern(patternKey); + for (String key : keys) { + loginUserInfoList.add(this.buildTokenDataByRedisKey(key)); + } + loginUserInfoList.sort((o1, o2) -> (int) (o2.getLoginTime().getTime() - o1.getLoginTime().getTime())); + int toIndex = Math.min(skipCount + pageParam.getPageSize(), loginUserInfoList.size()); + List resultList = loginUserInfoList.subList(skipCount, toIndex); + return ResponseResult.success(new MyPageData<>(resultList, (long) loginUserInfoList.size())); + } + + /** + * 强制下线指定登录会话。 + * + * @param sessionId 待强制下线的SessionId。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody String sessionId) { + // 为了保证被剔除用户正在进行的操作不被干扰,这里只是删除sessionIdKey即可,这样可以使强制下线操作更加平滑。 + // 比如,如果删除操作权限或数据权限的redis session key,那么正在请求数据的操作就会报错。 + redissonClient.getBucket(RedisKeyUtil.makeSessionIdKey(sessionId)).delete(); + return ResponseResult.success(); + } + + private LoginUserInfo buildTokenDataByRedisKey(String key) { + RBucket sessionData = redissonClient.getBucket(key); + TokenData tokenData = JSON.parseObject(sessionData.get(), TokenData.class); + return BeanUtil.copyProperties(tokenData, LoginUserInfo.class); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysDataPermController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysDataPermController.java new file mode 100644 index 00000000..7286cdfd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysDataPermController.java @@ -0,0 +1,281 @@ +package com.flow.demo.webadmin.upms.controller; + +import com.alibaba.fastjson.TypeReference; +import com.github.pagehelper.Page; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import com.flow.demo.webadmin.upms.dto.SysDataPermDto; +import com.flow.demo.webadmin.upms.dto.SysUserDto; +import com.flow.demo.webadmin.upms.vo.SysDataPermVo; +import com.flow.demo.webadmin.upms.vo.SysUserVo; +import com.flow.demo.webadmin.upms.model.SysDataPerm; +import com.flow.demo.webadmin.upms.model.SysUser; +import com.flow.demo.webadmin.upms.service.SysDataPermService; +import com.flow.demo.webadmin.upms.service.SysUserService; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.annotation.MyRequestBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 数据权限接口控制器对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysDataPerm") +public class SysDataPermController { + + @Autowired + private SysDataPermService sysDataPermService; + @Autowired + private SysUserService sysUserService; + + /** + * 添加新数据权限操作。 + * + * @param sysDataPermDto 新增对象。 + * @param deptIdListString 数据权限关联的部门Id列表,多个之间逗号分隔。 + * @return 应答结果对象。包含新增数据权限对象的主键Id。 + */ + @PostMapping("/add") + public ResponseResult add( + @MyRequestBody SysDataPermDto sysDataPermDto, @MyRequestBody String deptIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysDataPermDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysDataPerm sysDataPerm = MyModelUtil.copyTo(sysDataPermDto, SysDataPerm.class); + CallResult result = sysDataPermService.verifyRelatedData(sysDataPerm, deptIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set deptIdSet = null; + if (result.getData() != null) { + deptIdSet = result.getData().getObject("deptIdSet", new TypeReference>(){}); + } + sysDataPermService.saveNew(sysDataPerm, deptIdSet); + return ResponseResult.success(sysDataPerm.getDataPermId()); + } + + /** + * 更新数据权限操作。 + * + * @param sysDataPermDto 更新的数据权限对象。 + * @param deptIdListString 数据权限关联的部门Id列表,多个之间逗号分隔。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update( + @MyRequestBody SysDataPermDto sysDataPermDto, @MyRequestBody String deptIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysDataPermDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysDataPerm originalSysDataPerm = sysDataPermService.getById(sysDataPermDto.getDataPermId()); + if (originalSysDataPerm == null) { + errorMessage = "数据验证失败,当前数据权限并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + SysDataPerm sysDataPerm = MyModelUtil.copyTo(sysDataPermDto, SysDataPerm.class); + CallResult result = sysDataPermService.verifyRelatedData(sysDataPerm, deptIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set deptIdSet = null; + if (result.getData() != null) { + deptIdSet = result.getData().getObject("deptIdSet", new TypeReference>(){}); + } + if (!sysDataPermService.update(sysDataPerm, originalSysDataPerm, deptIdSet)) { + errorMessage = "更新失败,数据不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 删除数据权限操作。 + * + * @param dataPermId 待删除数据权限主键Id。 + * @return 应答数据结果。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long dataPermId) { + if (MyCommonUtil.existBlankArgument(dataPermId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysDataPermService.remove(dataPermId)) { + String errorMessage = "数据操作失败,数据权限不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 查看数据权限列表。 + * + * @param sysDataPermDtoFilter 数据权限查询过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象。包含数据权限列表。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody SysDataPermDto sysDataPermDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysDataPerm filter = MyModelUtil.copyTo(sysDataPermDtoFilter, SysDataPerm.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysDataPerm.class); + List dataPermList = sysDataPermService.getSysDataPermList(filter, orderBy); + List dataPermVoList = MyModelUtil.copyCollectionTo(dataPermList, SysDataPermVo.class); + long totalCount = 0L; + if (dataPermList instanceof Page) { + totalCount = ((Page) dataPermList).getTotal(); + } + return ResponseResult.success(MyPageUtil.makeResponseData(dataPermVoList, totalCount)); + } + + /** + * 查看单条数据权限详情。 + * + * @param dataPermId 数据权限的主键Id。 + * @return 应答结果对象,包含数据权限的详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long dataPermId) { + if (MyCommonUtil.existBlankArgument(dataPermId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysDataPerm dataPerm = sysDataPermService.getByIdWithRelation(dataPermId, MyRelationParam.full()); + if (dataPerm == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysDataPermVo dataPermVo = MyModelUtil.copyTo(dataPerm, SysDataPermVo.class); + return ResponseResult.success(dataPermVo); + } + + /** + * 获取不包含指定数据权限Id的用户列表。 + * 用户和数据权限是多对多关系,当前接口将返回没有赋值指定DataPermId的用户列表。可用于给数据权限添加新用户。 + * + * @param dataPermId 数据权限主键Id。 + * @param sysUserDtoFilter 用户数据的过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含用户列表数据。 + */ + @PostMapping("/listNotInDataPermUser") + public ResponseResult> listNotInDataPermUser( + @MyRequestBody Long dataPermId, + @MyRequestBody SysUserDto sysUserDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doDataPermUserVerify(dataPermId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysUser filter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List userList = + sysUserService.getNotInSysUserListByDataPermId(dataPermId, filter, orderBy); + List userVoList = MyModelUtil.copyCollectionTo(userList, SysUserVo.class); + return ResponseResult.success(MyPageUtil.makeResponseData(userVoList)); + } + + /** + * 拥有指定数据权限的用户列表。 + * + * @param dataPermId 数据权限Id。 + * @param sysUserDtoFilter 用户过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含用户列表数据。 + */ + @PostMapping("/listDataPermUser") + public ResponseResult> listDataPermUser( + @MyRequestBody Long dataPermId, + @MyRequestBody SysUserDto sysUserDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doDataPermUserVerify(dataPermId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysUser filter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List userList = + sysUserService.getSysUserListByDataPermId(dataPermId, filter, orderBy); + List userVoList = MyModelUtil.copyCollectionTo(userList, SysUserVo.class); + return ResponseResult.success(MyPageUtil.makeResponseData(userVoList)); + } + + private ResponseResult doDataPermUserVerify(Long dataPermId) { + if (MyCommonUtil.existBlankArgument(dataPermId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysDataPermService.existId(dataPermId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } + + /** + * 为指定数据权限添加用户列表。该操作可同时给一批用户赋值数据权限,并在同一事务内完成。 + * + * @param dataPermId 数据权限主键Id。 + * @param userIdListString 逗号分隔的用户Id列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addDataPermUser") + public ResponseResult addDataPermUser( + @MyRequestBody Long dataPermId, @MyRequestBody String userIdListString) { + if (MyCommonUtil.existBlankArgument(dataPermId, userIdListString)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + Set userIdSet = + Arrays.stream(userIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysDataPermService.existId(dataPermId) + || !sysUserService.existUniqueKeyList("userId", userIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + sysDataPermService.addDataPermUserList(dataPermId, userIdSet); + return ResponseResult.success(); + } + + /** + * 为指定用户移除指定数据权限。 + * + * @param dataPermId 指定数据权限主键Id。 + * @param userId 指定用户主键Id。 + * @return 应答数据结果。 + */ + @PostMapping("/deleteDataPermUser") + public ResponseResult deleteDataPermUser( + @MyRequestBody Long dataPermId, @MyRequestBody Long userId) { + if (MyCommonUtil.existBlankArgument(dataPermId, userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysDataPermService.removeDataPermUser(dataPermId, userId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysDeptController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysDeptController.java new file mode 100644 index 00000000..1da4508f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysDeptController.java @@ -0,0 +1,381 @@ +package com.flow.demo.webadmin.upms.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.page.PageMethod; +import com.flow.demo.webadmin.upms.vo.*; +import com.flow.demo.webadmin.upms.dto.*; +import com.flow.demo.webadmin.upms.model.*; +import com.flow.demo.webadmin.upms.service.*; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.constant.*; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; +import java.util.stream.Collectors; + +/** + * 部门管理操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysDept") +public class SysDeptController { + + @Autowired + private SysDeptService sysDeptService; + @Autowired + private SysPostService sysPostService; + + /** + * 新增部门管理数据。 + * + * @param sysDeptDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysDeptDto sysDeptDto) { + String errorMessage = MyCommonUtil.getModelValidationError(sysDeptDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysDept sysDept = MyModelUtil.copyTo(sysDeptDto, SysDept.class); + // 验证父Id的数据合法性 + SysDept parentSysDept = null; + if (MyCommonUtil.isNotBlankOrNull(sysDept.getParentId())) { + parentSysDept = sysDeptService.getById(sysDept.getParentId()); + if (parentSysDept == null) { + errorMessage = "数据验证失败,关联的父节点并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST, errorMessage); + } + } + sysDept = sysDeptService.saveNew(sysDept, parentSysDept); + return ResponseResult.success(sysDept.getDeptId()); + } + + /** + * 更新部门管理数据。 + * + * @param sysDeptDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysDeptDto sysDeptDto) { + String errorMessage = MyCommonUtil.getModelValidationError(sysDeptDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysDept sysDept = MyModelUtil.copyTo(sysDeptDto, SysDept.class); + SysDept originalSysDept = sysDeptService.getById(sysDept.getDeptId()); + if (originalSysDept == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证父Id的数据合法性 + if (MyCommonUtil.isNotBlankOrNull(sysDept.getParentId()) + && ObjectUtils.notEqual(sysDept.getParentId(), originalSysDept.getParentId())) { + SysDept parentSysDept = sysDeptService.getById(sysDept.getParentId()); + if (parentSysDept == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,关联的 [父节点] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST, errorMessage); + } + } + if (!sysDeptService.update(sysDept, originalSysDept)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除部门管理数据。 + * + * @param deptId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long deptId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(deptId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + SysDept originalSysDept = sysDeptService.getById(deptId); + if (originalSysDept == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (sysDeptService.hasChildren(deptId)) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象存在子对象] ,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage); + } + if (sysDeptService.hasChildrenUser(deptId)) { + errorMessage = "数据验证失败,请先移除部门用户数据后,再删除当前部门!"; + return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage); + } + if (!sysDeptService.remove(deptId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的部门管理列表。 + * + * @param sysDeptDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody SysDeptDto sysDeptDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysDept sysDeptFilter = MyModelUtil.copyTo(sysDeptDtoFilter, SysDept.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysDept.class); + List sysDeptList = sysDeptService.getSysDeptListWithRelation(sysDeptFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(sysDeptList, SysDept.INSTANCE)); + } + + /** + * 查看指定部门管理对象详情。 + * + * @param deptId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long deptId) { + if (MyCommonUtil.existBlankArgument(deptId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysDept sysDept = sysDeptService.getByIdWithRelation(deptId, MyRelationParam.full()); + if (sysDept == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysDeptVo sysDeptVo = SysDept.INSTANCE.fromModel(sysDept); + return ResponseResult.success(sysDeptVo); + } + + /** + * 列出不与指定部门管理存在多对多关系的 [岗位管理] 列表数据。通常用于查看添加新 [岗位管理] 对象的候选列表。 + * + * @param deptId 主表关联字段。 + * @param sysPostDtoFilter [岗位管理] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listNotInSysDeptPost") + public ResponseResult> listNotInSysDeptPost( + @MyRequestBody Long deptId, + @MyRequestBody SysPostDto sysPostDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doSysDeptPostVerify(deptId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysPost filter = MyModelUtil.copyTo(sysPostDtoFilter, SysPost.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysPost.class); + List sysPostList = sysPostService.getNotInSysPostListByDeptId(deptId, filter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPost.INSTANCE)); + } + + /** + * 列出与指定部门管理存在多对多关系的 [岗位管理] 列表数据。 + * + * @param deptId 主表关联字段。 + * @param sysPostDtoFilter [岗位管理] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listSysDeptPost") + public ResponseResult> listSysDeptPost( + @MyRequestBody Long deptId, + @MyRequestBody SysPostDto sysPostDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doSysDeptPostVerify(deptId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysPost filter = MyModelUtil.copyTo(sysPostDtoFilter, SysPost.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysPost.class); + List sysPostList = sysPostService.getSysPostListByDeptId(deptId, filter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPost.INSTANCE)); + } + + private ResponseResult doSysDeptPostVerify(Long deptId) { + if (MyCommonUtil.existBlankArgument(deptId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysDeptService.existId(deptId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } + + /** + * 批量添加部门管理和 [岗位管理] 对象的多对多关联关系数据。 + * + * @param deptId 主表主键Id。 + * @param sysDeptPostDtoList 关联对象列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addSysDeptPost") + public ResponseResult addSysDeptPost( + @MyRequestBody Long deptId, + @MyRequestBody(elementType = SysDeptPostDto.class) List sysDeptPostDtoList) { + if (MyCommonUtil.existBlankArgument(deptId, sysDeptPostDtoList)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + for (SysDeptPostDto sysDeptPost : sysDeptPostDtoList) { + String errorMessage = MyCommonUtil.getModelValidationError(sysDeptPost); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + Set postIdSet = sysDeptPostDtoList.stream().map(SysDeptPostDto::getPostId).collect(Collectors.toSet()); + if (!sysDeptService.existId(deptId) || !sysPostService.existUniqueKeyList("postId", postIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + List sysDeptPostList = MyModelUtil.copyCollectionTo(sysDeptPostDtoList, SysDeptPost.class); + sysDeptService.addSysDeptPostList(sysDeptPostList, deptId); + return ResponseResult.success(); + } + + /** + * 更新指定部门管理和指定 [岗位管理] 的多对多关联数据。 + * + * @param sysDeptPostDto 对多对中间表对象。 + * @return 应答结果对象。 + */ + @PostMapping("/updateSysDeptPost") + public ResponseResult updateSysDeptPost(@MyRequestBody SysDeptPostDto sysDeptPostDto) { + String errorMessage = MyCommonUtil.getModelValidationError(sysDeptPostDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysDeptPost sysDeptPost = MyModelUtil.copyTo(sysDeptPostDto, SysDeptPost.class); + if (!sysDeptService.updateSysDeptPost(sysDeptPost)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 显示部门管理和指定 [岗位管理] 的多对多关联详情数据。 + * + * @param deptId 主表主键Id。 + * @param postId 从表主键Id。 + * @return 应答结果对象,包括中间表详情。 + */ + @GetMapping("/viewSysDeptPost") + public ResponseResult viewSysDeptPost(@RequestParam Long deptId, @RequestParam Long postId) { + if (MyCommonUtil.existBlankArgument(deptId, postId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysDeptPost sysDeptPost = sysDeptService.getSysDeptPost(deptId, postId); + if (sysDeptPost == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysDeptPostVo sysDeptPostVo = MyModelUtil.copyTo(sysDeptPost, SysDeptPostVo.class); + return ResponseResult.success(sysDeptPostVo); + } + + /** + * 移除指定部门管理和指定 [岗位管理] 的多对多关联关系。 + * + * @param deptId 主表主键Id。 + * @param postId 从表主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/deleteSysDeptPost") + public ResponseResult deleteSysDeptPost(@MyRequestBody Long deptId, @MyRequestBody Long postId) { + if (MyCommonUtil.existBlankArgument(deptId, postId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysDeptService.removeSysDeptPost(deptId, postId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 获取部门岗位多对多关联数据,及其关联的部门和岗位数据。 + * + * @param deptId 部门Id,如果为空,返回全部数据列表。 + * @return 部门岗位多对多关联数据,及其关联的部门和岗位数据 + */ + @GetMapping("/listSysDeptPostWithRelation") + public ResponseResult>> listSysDeptPostWithRelation( + @RequestParam(required = false) Long deptId) { + return ResponseResult.success(sysDeptService.getSysDeptPostListWithRelationByDeptId(deptId)); + } + + /** + * 以字典形式返回全部部门管理数据集合。字典的键值为[deptId, deptName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDict") + public ResponseResult>> listDict(SysDept filter) { + List resultList = sysDeptService.getListByFilter(filter); + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "deptId as id", "deptName as name").executeFrom(resultList)); + } + + /** + * 根据字典Id集合,获取查询后的字典数据。 + * + * @param dictIds 字典Id集合。 + * @return 应答结果对象,包含字典形式的数据集合。 + */ + @PostMapping("/listDictByIds") + public ResponseResult>> listDictByIds( + @MyRequestBody(elementType = Long.class) List dictIds) { + List resultList = sysDeptService.getInList(new HashSet<>(dictIds)); + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "deptId as id", "deptName as name").executeFrom(resultList)); + } + + /** + * 根据父主键Id,以字典的形式返回其下级数据列表。 + * 白名单接口,登录用户均可访问。 + * + * @param parentId 父主键Id。 + * @return 按照字典的形式返回下级数据列表。 + */ + @GetMapping("/listDictByParentId") + public ResponseResult>> listDictByParentId(@RequestParam(required = false) Long parentId) { + List resultList = sysDeptService.getListByParentId("parentId", parentId); + return ResponseResult.success(BeanQuery.select( + "parentId as parentId", "deptId as id", "deptName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysMenuController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysMenuController.java new file mode 100644 index 00000000..e742af60 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysMenuController.java @@ -0,0 +1,215 @@ +package com.flow.demo.webadmin.upms.controller; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.TypeReference; +import lombok.extern.slf4j.Slf4j; +import com.flow.demo.webadmin.upms.dto.SysMenuDto; +import com.flow.demo.webadmin.upms.vo.SysMenuVo; +import com.flow.demo.webadmin.upms.model.SysMenu; +import com.flow.demo.webadmin.upms.model.constant.SysMenuType; +import com.flow.demo.webadmin.upms.service.SysMenuService; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.core.annotation.MyRequestBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.*; + +/** + * 菜单管理接口控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysMenu") +public class SysMenuController { + + @Autowired + private SysMenuService sysMenuService; + + /** + * 添加新菜单操作。 + * + * @param sysMenuDto 新菜单对象。 + * @param permCodeIdListString 与当前菜单Id绑定的权限Id列表,多个权限之间逗号分隔。 + * @return 应答结果对象,包含新增菜单的主键Id。 + */ + @PostMapping("/add") + public ResponseResult add( + @MyRequestBody SysMenuDto sysMenuDto, @MyRequestBody String permCodeIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysMenuDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysMenu sysMenu = MyModelUtil.copyTo(sysMenuDto, SysMenu.class); + if (sysMenu.getParentId() != null) { + SysMenu parentSysMenu = sysMenuService.getById(sysMenu.getParentId()); + if (parentSysMenu == null) { + errorMessage = "数据验证失败,关联的父菜单不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (parentSysMenu.getOnlineFormId() != null) { + errorMessage = "数据验证失败,不能动态表单菜单添加父菜单!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + CallResult result = sysMenuService.verifyRelatedData(sysMenu, null, permCodeIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set permCodeIdSet = null; + if (result.getData() != null) { + permCodeIdSet = result.getData().getObject("permCodeIdSet", new TypeReference>(){}); + } + sysMenuService.saveNew(sysMenu, permCodeIdSet); + return ResponseResult.success(sysMenu.getMenuId()); + } + + /** + * 更新菜单数据操作。 + * + * @param sysMenuDto 更新菜单对象。 + * @param permCodeIdListString 与当前菜单Id绑定的权限Id列表,多个权限之间逗号分隔。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update( + @MyRequestBody SysMenuDto sysMenuDto, @MyRequestBody String permCodeIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysMenuDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysMenu originalSysMenu = sysMenuService.getById(sysMenuDto.getMenuId()); + if (originalSysMenu == null) { + errorMessage = "数据验证失败,当前菜单并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + SysMenu sysMenu = MyModelUtil.copyTo(sysMenuDto, SysMenu.class); + if (ObjectUtil.notEqual(originalSysMenu.getOnlineFormId(), sysMenu.getOnlineFormId())) { + if (originalSysMenu.getOnlineFormId() == null) { + errorMessage = "数据验证失败,不能为当前菜单添加在线表单Id属性!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (sysMenu.getOnlineFormId() == null) { + errorMessage = "数据验证失败,不能去掉当前菜单的在线表单Id属性!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + if (originalSysMenu.getOnlineFormId() != null + && originalSysMenu.getMenuType().equals(SysMenuType.TYPE_BUTTON)) { + errorMessage = "数据验证失败,在线表单的内置菜单不能编辑!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + CallResult result = sysMenuService.verifyRelatedData(sysMenu, originalSysMenu, permCodeIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set permCodeIdSet = null; + if (result.getData() != null) { + permCodeIdSet = result.getData().getObject("permCodeIdSet", new TypeReference>(){}); + } + if (!sysMenuService.update(sysMenu, originalSysMenu, permCodeIdSet)) { + errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 删除指定菜单操作。 + * + * @param menuId 指定菜单主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long menuId) { + if (MyCommonUtil.existBlankArgument(menuId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + String errorMessage; + SysMenu menu = sysMenuService.getById(menuId); + if (menu == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + if (menu.getOnlineFormId() != null && menu.getMenuType().equals(SysMenuType.TYPE_BUTTON)) { + errorMessage = "数据验证失败,在线表单的内置菜单不能删除!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + // 对于在线表单,无需进行子菜单的验证,而是在删除的时候,连同子菜单一起删除。 + if (menu.getOnlineFormId() == null && sysMenuService.hasChildren(menuId)) { + errorMessage = "数据验证失败,当前菜单存在下级菜单!"; + return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage); + } + if (!sysMenuService.remove(menu)) { + errorMessage = "数据操作失败,菜单不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 获取全部菜单列表。 + * + * @return 应答结果对象,包含全部菜单数据列表。 + */ + @PostMapping("/list") + public ResponseResult> list() { + List sysMenuList = sysMenuService.getAllListByOrder("showOrder"); + return ResponseResult.success(MyModelUtil.copyCollectionTo(sysMenuList, SysMenuVo.class)); + } + + /** + * 查看指定菜单数据详情。 + * + * @param menuId 指定菜单主键Id。 + * @return 应答结果对象,包含菜单详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long menuId) { + if (MyCommonUtil.existBlankArgument(menuId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysMenu sysMenu = sysMenuService.getByIdWithRelation(menuId, MyRelationParam.full()); + if (sysMenu == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysMenuVo sysMenuVo = MyModelUtil.copyTo(sysMenu, SysMenuVo.class); + return ResponseResult.success(sysMenuVo); + } + + /** + * 查询菜单的权限资源地址列表。同时返回详细的分配路径。 + * + * @param menuId 菜单Id。 + * @param url 权限资源地址过滤条件。 + * @return 应答对象,包含从菜单到权限资源的权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysPermWithDetail") + public ResponseResult>> listSysPermWithDetail(Long menuId, String url) { + if (MyCommonUtil.isBlankOrNull(menuId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysMenuService.getSysPermListWithDetail(menuId, url)); + } + + /** + * 查询菜单的用户列表。同时返回详细的分配路径。 + * + * @param menuId 菜单Id。 + * @param loginName 登录名。 + * @return 应答对象,包含从菜单到用户的完整权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysUserWithDetail") + public ResponseResult>> listSysUserWithDetail(Long menuId, String loginName) { + if (MyCommonUtil.isBlankOrNull(menuId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysMenuService.getSysUserListWithDetail(menuId, loginName)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermCodeController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermCodeController.java new file mode 100644 index 00000000..d92dbbf1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermCodeController.java @@ -0,0 +1,186 @@ +package com.flow.demo.webadmin.upms.controller; + +import com.alibaba.fastjson.TypeReference; +import lombok.extern.slf4j.Slf4j; +import com.flow.demo.webadmin.upms.dto.SysPermCodeDto; +import com.flow.demo.webadmin.upms.vo.SysPermCodeVo; +import com.flow.demo.webadmin.upms.model.SysPermCode; +import com.flow.demo.webadmin.upms.service.SysPermCodeService; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.core.annotation.MyRequestBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.*; + +/** + * 权限字管理接口控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysPermCode") +public class SysPermCodeController { + + @Autowired + private SysPermCodeService sysPermCodeService; + + /** + * 新增权限字操作。 + * + * @param sysPermCodeDto 新增权限字对象。 + * @param permIdListString 与当前权限Id绑定的权限资源Id列表,多个权限资源之间逗号分隔。 + * @return 应答结果对象,包含新增权限字的主键Id。 + */ + @PostMapping("/add") + public ResponseResult add( + @MyRequestBody SysPermCodeDto sysPermCodeDto, @MyRequestBody String permIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermCodeDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED); + } + SysPermCode sysPermCode = MyModelUtil.copyTo(sysPermCodeDto, SysPermCode.class); + CallResult result = sysPermCodeService.verifyRelatedData(sysPermCode, null, permIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set permIdSet = null; + if (result.getData() != null) { + permIdSet = result.getData().getObject("permIdSet", new TypeReference>(){}); + } + sysPermCode = sysPermCodeService.saveNew(sysPermCode, permIdSet); + return ResponseResult.success(sysPermCode.getPermCodeId()); + } + + /** + * 更新权限字操作。 + * + * @param sysPermCodeDto 更新权限字对象。 + * @param permIdListString 与当前权限Id绑定的权限资源Id列表,多个权限资源之间逗号分隔。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update( + @MyRequestBody SysPermCodeDto sysPermCodeDto, @MyRequestBody String permIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermCodeDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysPermCode originalSysPermCode = sysPermCodeService.getById(sysPermCodeDto.getPermCodeId()); + if (originalSysPermCode == null) { + errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + SysPermCode sysPermCode = MyModelUtil.copyTo(sysPermCodeDto, SysPermCode.class); + CallResult result = sysPermCodeService.verifyRelatedData(sysPermCode, originalSysPermCode, permIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set permIdSet = null; + if (result.getData() != null) { + permIdSet = result.getData().getObject("permIdSet", new TypeReference>(){}); + } + try { + if (!sysPermCodeService.update(sysPermCode, originalSysPermCode, permIdSet)) { + errorMessage = "数据验证失败,当前权限字并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + } catch (DuplicateKeyException e) { + errorMessage = "数据操作失败,权限字编码已经存在!"; + return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 删除指定权限字操作。 + * + * @param permCodeId 指定的权限字主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long permCodeId) { + if (MyCommonUtil.existBlankArgument(permCodeId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + String errorMessage; + if (sysPermCodeService.hasChildren(permCodeId)) { + errorMessage = "数据验证失败,当前权限字存在下级权限字!"; + return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage); + } + if (!sysPermCodeService.remove(permCodeId)) { + errorMessage = "数据操作失败,权限字不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 查看权限字列表。 + * + * @return 应答结果对象,包含权限字列表。 + */ + @PostMapping("/list") + public ResponseResult> list() { + List sysPermCodeList = + sysPermCodeService.getAllListByOrder("permCodeType", "showOrder"); + return ResponseResult.success(MyModelUtil.copyCollectionTo(sysPermCodeList, SysPermCodeVo.class)); + } + + /** + * 查看权限字对象详情。 + * + * @param permCodeId 指定权限字主键Id。 + * @return 应答结果对象,包含权限字对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long permCodeId) { + if (MyCommonUtil.existBlankArgument(permCodeId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysPermCode sysPermCode = + sysPermCodeService.getByIdWithRelation(permCodeId, MyRelationParam.full()); + if (sysPermCode == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysPermCodeVo sysPermCodeVo = MyModelUtil.copyTo(sysPermCode, SysPermCodeVo.class); + return ResponseResult.success(sysPermCodeVo); + } + + /** + * 查询权限字的用户列表。同时返回详细的分配路径。 + * + * @param permCodeId 权限字Id。 + * @param loginName 登录名。 + * @return 应答对象。包含从权限字到用户的完整权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysUserWithDetail") + public ResponseResult>> listSysUserWithDetail(Long permCodeId, String loginName) { + if (MyCommonUtil.isBlankOrNull(permCodeId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysPermCodeService.getSysUserListWithDetail(permCodeId, loginName)); + } + + /** + * 查询权限字的角色列表。同时返回详细的分配路径。 + * + * @param permCodeId 权限字Id。 + * @param roleName 角色名。 + * @return 应答对象。包含从权限字到角色的权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysRoleWithDetail") + public ResponseResult>> listSysRoleWithDetail(Long permCodeId, String roleName) { + if (MyCommonUtil.isBlankOrNull(permCodeId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysPermCodeService.getSysRoleListWithDetail(permCodeId, roleName)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermController.java new file mode 100644 index 00000000..602ea1c0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermController.java @@ -0,0 +1,187 @@ +package com.flow.demo.webadmin.upms.controller; + +import com.github.pagehelper.Page; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import com.flow.demo.webadmin.upms.dto.SysPermDto; +import com.flow.demo.webadmin.upms.vo.SysPermVo; +import com.flow.demo.webadmin.upms.model.SysPerm; +import com.flow.demo.webadmin.upms.service.SysPermService; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.core.annotation.MyRequestBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.List; +import java.util.Map; + +/** + * 权限资源管理接口控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysPerm") +public class SysPermController { + + @Autowired + private SysPermService sysPermService; + + /** + * 新增权限资源操作。 + * + * @param sysPermDto 新增权限资源对象。 + * @return 应答结果对象,包含新增权限资源的主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysPermDto sysPermDto) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysPerm sysPerm = MyModelUtil.copyTo(sysPermDto, SysPerm.class); + CallResult result = sysPermService.verifyRelatedData(sysPerm, null); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + sysPerm = sysPermService.saveNew(sysPerm); + return ResponseResult.success(sysPerm.getPermId()); + } + + /** + * 更新权限资源操作。 + * + * @param sysPermDto 更新权限资源对象。 + * @return 应答结果对象,包含更新权限资源的主键Id。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysPermDto sysPermDto) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysPerm originalPerm = sysPermService.getById(sysPermDto.getPermId()); + if (originalPerm == null) { + errorMessage = "数据验证失败,当前权限资源并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + SysPerm sysPerm = MyModelUtil.copyTo(sysPermDto, SysPerm.class); + CallResult result = sysPermService.verifyRelatedData(sysPerm, originalPerm); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + sysPermService.update(sysPerm, originalPerm); + return ResponseResult.success(); + } + + /** + * 删除指定权限资源操作。 + * + * @param permId 指定的权限资源主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long permId) { + if (MyCommonUtil.existBlankArgument(permId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysPermService.remove(permId)) { + String errorMessage = "数据操作失败,权限不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 查看权限资源对象详情。 + * + * @param permId 指定权限资源主键Id。 + * @return 应答结果对象,包含权限资源对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long permId) { + if (MyCommonUtil.existBlankArgument(permId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysPerm perm = sysPermService.getById(permId); + if (perm == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysPermVo permVo = MyModelUtil.copyTo(perm, SysPermVo.class); + return ResponseResult.success(permVo); + } + + /** + * 查看权限资源列表。 + * + * @param sysPermDtoFilter 过滤对象。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含权限资源列表。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody SysPermDto sysPermDtoFilter, @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysPerm filter = MyModelUtil.copyTo(sysPermDtoFilter, SysPerm.class); + List permList = sysPermService.getPermListWithRelation(filter); + List permVoList = MyModelUtil.copyCollectionTo(permList, SysPermVo.class); + long totalCount = 0L; + if (permList instanceof Page) { + totalCount = ((Page) permList).getTotal(); + } + return ResponseResult.success(MyPageUtil.makeResponseData(permVoList, totalCount)); + } + + /** + * 查询权限资源地址的用户列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param loginName 登录名。 + * @return 应答对象。包含从权限资源到用户的完整权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysUserWithDetail") + public ResponseResult>> listSysUserWithDetail(Long permId, String loginName) { + if (MyCommonUtil.isBlankOrNull(permId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysPermService.getSysUserListWithDetail(permId, loginName)); + } + + /** + * 查询权限资源地址的角色列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param roleName 角色名。 + * @return 应答对象。包含从权限资源到角色的权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysRoleWithDetail") + public ResponseResult>> listSysRoleWithDetail(Long permId, String roleName) { + if (MyCommonUtil.isBlankOrNull(permId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysPermService.getSysRoleListWithDetail(permId, roleName)); + } + + /** + * 查询权限资源地址的菜单列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param menuName 菜单名。 + * @return 应答对象。包含从权限资源到菜单的权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysMenuWithDetail") + public ResponseResult>> listSysMenuWithDetail(Long permId, String menuName) { + if (MyCommonUtil.isBlankOrNull(permId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysPermService.getSysMenuListWithDetail(permId, menuName)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermModuleController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermModuleController.java new file mode 100644 index 00000000..7d0e96ef --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPermModuleController.java @@ -0,0 +1,159 @@ +package com.flow.demo.webadmin.upms.controller; + +import lombok.extern.slf4j.Slf4j; +import com.flow.demo.webadmin.upms.dto.SysPermModuleDto; +import com.flow.demo.webadmin.upms.vo.SysPermModuleVo; +import com.flow.demo.webadmin.upms.model.SysPerm; +import com.flow.demo.webadmin.upms.model.SysPermModule; +import com.flow.demo.webadmin.upms.service.SysPermModuleService; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.core.annotation.MyRequestBody; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +/** + * 权限资源模块管理接口控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysPermModule") +public class SysPermModuleController { + + @Autowired + private SysPermModuleService sysPermModuleService; + + /** + * 新增权限资源模块操作。 + * + * @param sysPermModuleDto 新增权限资源模块对象。 + * @return 应答结果对象,包含新增权限资源模块的主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysPermModuleDto sysPermModuleDto) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermModuleDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysPermModule sysPermModule = MyModelUtil.copyTo(sysPermModuleDto, SysPermModule.class); + if (sysPermModule.getParentId() != null + && sysPermModuleService.getById(sysPermModule.getParentId()) == null) { + errorMessage = "数据验证失败,关联的上级权限模块并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST, errorMessage); + } + sysPermModuleService.saveNew(sysPermModule); + return ResponseResult.success(sysPermModule.getModuleId()); + } + + /** + * 更新权限资源模块操作。 + * + * @param sysPermModuleDto 更新权限资源模块对象。 + * @return 应答结果对象,包含新增权限资源模块的主键Id。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysPermModuleDto sysPermModuleDto) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPermModuleDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysPermModule sysPermModule = MyModelUtil.copyTo(sysPermModuleDto, SysPermModule.class); + SysPermModule originalPermModule = sysPermModuleService.getById(sysPermModule.getModuleId()); + if (originalPermModule == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + if (sysPermModule.getParentId() != null + && !sysPermModule.getParentId().equals(originalPermModule.getParentId())) { + if (sysPermModuleService.getById(sysPermModule.getParentId()) == null) { + errorMessage = "数据验证失败,关联的上级权限模块并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_PARENT_ID_NOT_EXIST, errorMessage); + } + } + if (!sysPermModuleService.update(sysPermModule, originalPermModule)) { + errorMessage = "数据验证失败,当前模块并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 删除指定权限资源模块操作。 + * + * @param moduleId 指定的权限资源模块主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long moduleId) { + if (MyCommonUtil.existBlankArgument(moduleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + String errorMessage; + if (sysPermModuleService.hasChildren(moduleId) + || sysPermModuleService.hasModulePerms(moduleId)) { + errorMessage = "数据验证失败,当前权限模块存在子模块或权限资源,请先删除关联数据!"; + return ResponseResult.error(ErrorCodeEnum.HAS_CHILDREN_DATA, errorMessage); + } + if (!sysPermModuleService.remove(moduleId)) { + errorMessage = "数据操作失败,权限模块不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 查看全部权限资源模块列表。 + * + * @return 应答结果对象,包含权限资源模块列表。 + */ + @PostMapping("/list") + public ResponseResult> list() { + List permModuleList = sysPermModuleService.getAllListByOrder("showOrder"); + return ResponseResult.success(MyModelUtil.copyCollectionTo(permModuleList, SysPermModuleVo.class)); + } + + /** + * 列出全部权限资源模块及其下级关联的权限资源列表。 + * + * @return 应答结果对象,包含树状列表,结构为权限资源模块和权限资源之间的树状关系。 + */ + @PostMapping("/listAll") + public ResponseResult>> listAll() { + List sysPermModuleList = sysPermModuleService.getPermModuleAndPermList(); + List> resultList = new LinkedList<>(); + for (SysPermModule sysPermModule : sysPermModuleList) { + Map permModuleMap = new HashMap<>(5); + permModuleMap.put("id", sysPermModule.getModuleId()); + permModuleMap.put("name", sysPermModule.getModuleName()); + permModuleMap.put("type", sysPermModule.getModuleType()); + permModuleMap.put("isPerm", false); + if (MyCommonUtil.isNotBlankOrNull(sysPermModule.getParentId())) { + permModuleMap.put("parentId", sysPermModule.getParentId()); + } + resultList.add(permModuleMap); + if (CollectionUtils.isNotEmpty(sysPermModule.getSysPermList())) { + for (SysPerm sysPerm : sysPermModule.getSysPermList()) { + Map permMap = new HashMap<>(4); + permMap.put("id", sysPerm.getPermId()); + permMap.put("name", sysPerm.getPermName()); + permMap.put("isPerm", true); + permMap.put("url", sysPerm.getUrl()); + permMap.put("parentId", sysPermModule.getModuleId()); + resultList.add(permMap); + } + } + } + return ResponseResult.success(resultList); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPostController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPostController.java new file mode 100644 index 00000000..008c7401 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysPostController.java @@ -0,0 +1,169 @@ +package com.flow.demo.webadmin.upms.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.page.PageMethod; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.constant.*; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.webadmin.upms.dto.SysPostDto; +import com.flow.demo.webadmin.upms.model.SysPost; +import com.flow.demo.webadmin.upms.service.SysPostService; +import com.flow.demo.webadmin.upms.vo.SysPostVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 岗位管理操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysPost") +public class SysPostController { + + @Autowired + private SysPostService sysPostService; + + /** + * 新增岗位管理数据。 + * + * @param sysPostDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody SysPostDto sysPostDto) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPostDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysPost sysPost = MyModelUtil.copyTo(sysPostDto, SysPost.class); + sysPost = sysPostService.saveNew(sysPost); + return ResponseResult.success(sysPost.getPostId()); + } + + /** + * 更新岗位管理数据。 + * + * @param sysPostDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody SysPostDto sysPostDto) { + String errorMessage = MyCommonUtil.getModelValidationError(sysPostDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysPost sysPost = MyModelUtil.copyTo(sysPostDto, SysPost.class); + SysPost originalSysPost = sysPostService.getById(sysPost.getPostId()); + if (originalSysPost == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!sysPostService.update(sysPost, originalSysPost)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除岗位管理数据。 + * + * @param postId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long postId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(postId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + SysPost originalSysPost = sysPostService.getById(postId); + if (originalSysPost == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!sysPostService.remove(postId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的岗位管理列表。 + * + * @param sysPostDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody SysPostDto sysPostDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysPost sysPostFilter = MyModelUtil.copyTo(sysPostDtoFilter, SysPost.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysPost.class); + List sysPostList = sysPostService.getSysPostListWithRelation(sysPostFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(sysPostList, SysPost.INSTANCE)); + } + + /** + * 查看指定岗位管理对象详情。 + * + * @param postId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long postId) { + if (MyCommonUtil.existBlankArgument(postId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysPost sysPost = sysPostService.getByIdWithRelation(postId, MyRelationParam.full()); + if (sysPost == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysPostVo sysPostVo = SysPost.INSTANCE.fromModel(sysPost); + return ResponseResult.success(sysPostVo); + } + + /** + * 以字典形式返回全部岗位管理数据集合。字典的键值为[postId, postName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDict") + public ResponseResult>> listDict(SysPost filter) { + List resultList = sysPostService.getListByFilter(filter); + return ResponseResult.success(BeanQuery.select("postId as id", "postName as name").executeFrom(resultList)); + } + + /** + * 根据字典Id集合,获取查询后的字典数据。 + * + * @param postIds 字典Id集合。 + * @return 应答结果对象,包含字典形式的数据集合。 + */ + @PostMapping("/listDictByIds") + public ResponseResult>> listDictByIds( + @MyRequestBody(elementType = Long.class) List postIds) { + List resultList = sysPostService.getInList(new HashSet<>(postIds)); + return ResponseResult.success(BeanQuery.select("postId as id", "postName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysRoleController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysRoleController.java new file mode 100644 index 00000000..f806adbd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysRoleController.java @@ -0,0 +1,317 @@ +package com.flow.demo.webadmin.upms.controller; + +import com.alibaba.fastjson.TypeReference; +import com.github.pagehelper.Page; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import com.flow.demo.webadmin.upms.dto.SysRoleDto; +import com.flow.demo.webadmin.upms.dto.SysUserDto; +import com.flow.demo.webadmin.upms.vo.SysRoleVo; +import com.flow.demo.webadmin.upms.vo.SysUserVo; +import com.flow.demo.webadmin.upms.model.SysRole; +import com.flow.demo.webadmin.upms.model.SysUser; +import com.flow.demo.webadmin.upms.model.SysUserRole; +import com.flow.demo.webadmin.upms.service.SysRoleService; +import com.flow.demo.webadmin.upms.service.SysUserService; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.annotation.MyRequestBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 角色管理接口控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysRole") +public class SysRoleController { + + @Autowired + private SysRoleService sysRoleService; + @Autowired + private SysUserService sysUserService; + + /** + * 新增角色操作。 + * + * @param sysRoleDto 新增角色对象。 + * @param menuIdListString 与当前角色Id绑定的menuId列表,多个menuId之间逗号分隔。 + * @return 应答结果对象,包含新增角色的主键Id。 + */ + @PostMapping("/add") + public ResponseResult add( + @MyRequestBody SysRoleDto sysRoleDto, @MyRequestBody String menuIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysRoleDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysRole sysRole = MyModelUtil.copyTo(sysRoleDto, SysRole.class); + CallResult result = sysRoleService.verifyRelatedData(sysRole, null, menuIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set menuIdSet = null; + if (result.getData() != null) { + menuIdSet = result.getData().getObject("menuIdSet", new TypeReference>(){}); + } + sysRoleService.saveNew(sysRole, menuIdSet); + return ResponseResult.success(sysRole.getRoleId()); + } + + /** + * 更新角色操作。 + * + * @param sysRoleDto 更新角色对象。 + * @param menuIdListString 与当前角色Id绑定的menuId列表,多个menuId之间逗号分隔。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update( + @MyRequestBody SysRoleDto sysRoleDto, @MyRequestBody String menuIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysRoleDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysRole originalSysRole = sysRoleService.getById(sysRoleDto.getRoleId()); + if (originalSysRole == null) { + errorMessage = "数据验证失败,当前角色并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + SysRole sysRole = MyModelUtil.copyTo(sysRoleDto, SysRole.class); + CallResult result = sysRoleService.verifyRelatedData(sysRole, originalSysRole, menuIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set menuIdSet = null; + if (result.getData() != null) { + menuIdSet = result.getData().getObject("menuIdSet", new TypeReference>(){}); + } + if (!sysRoleService.update(sysRole, originalSysRole, menuIdSet)) { + errorMessage = "更新失败,数据不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 删除指定角色操作。 + * + * @param roleId 指定角色主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long roleId) { + if (MyCommonUtil.existBlankArgument(roleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysRoleService.remove(roleId)) { + String errorMessage = "数据操作失败,角色不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 查看角色列表。 + * + * @param sysRoleDtoFilter 角色过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含角色列表。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody SysRoleDto sysRoleDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysRole filter = MyModelUtil.copyTo(sysRoleDtoFilter, SysRole.class); + List roleList = sysRoleService.getSysRoleList( + filter, MyOrderParam.buildOrderBy(orderParam, SysRole.class)); + List roleVoList = MyModelUtil.copyCollectionTo(roleList, SysRoleVo.class); + long totalCount = 0L; + if (roleList instanceof Page) { + totalCount = ((Page) roleList).getTotal(); + } + return ResponseResult.success(MyPageUtil.makeResponseData(roleVoList, totalCount)); + } + + /** + * 查看角色详情。 + * + * @param roleId 指定角色主键Id。 + * @return 应答结果对象,包含角色详情对象。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long roleId) { + if (MyCommonUtil.existBlankArgument(roleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + SysRole sysRole = sysRoleService.getByIdWithRelation(roleId, MyRelationParam.full()); + if (sysRole == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysRoleVo sysRoleVo = MyModelUtil.copyTo(sysRole, SysRoleVo.class); + return ResponseResult.success(sysRoleVo); + } + + /** + * 获取不包含指定角色Id的用户列表。 + * 用户和角色是多对多关系,当前接口将返回没有赋值指定RoleId的用户列表。可用于给角色添加新用户。 + * + * @param roleId 角色主键Id。 + * @param sysUserDtoFilter 用户过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含用户列表数据。 + */ + @PostMapping("/listNotInUserRole") + public ResponseResult> listNotInUserRole( + @MyRequestBody Long roleId, + @MyRequestBody SysUserDto sysUserDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doRoleUserVerify(roleId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysUser filter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List userList = sysUserService.getNotInSysUserListByRoleId(roleId, filter, orderBy); + List userVoList = MyModelUtil.copyCollectionTo(userList, SysUserVo.class); + return ResponseResult.success(MyPageUtil.makeResponseData(userVoList)); + } + + /** + * 拥有指定角色的用户列表。 + * + * @param roleId 角色主键Id。 + * @param sysUserDtoFilter 用户过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含用户列表数据。 + */ + @PostMapping("/listUserRole") + public ResponseResult> listUserRole( + @MyRequestBody Long roleId, + @MyRequestBody SysUserDto sysUserDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doRoleUserVerify(roleId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysUser filter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List userList = sysUserService.getSysUserListByRoleId(roleId, filter, orderBy); + List userVoList = MyModelUtil.copyCollectionTo(userList, SysUserVo.class); + return ResponseResult.success(MyPageUtil.makeResponseData(userVoList)); + } + + private ResponseResult doRoleUserVerify(Long roleId) { + if (MyCommonUtil.existBlankArgument(roleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysRoleService.existId(roleId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } + + /** + * 为指定角色添加用户列表。该操作可同时给一批用户赋值角色,并在同一事务内完成。 + * + * @param roleId 角色主键Id。 + * @param userIdListString 逗号分隔的用户Id列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addUserRole") + public ResponseResult addUserRole( + @MyRequestBody Long roleId, @MyRequestBody String userIdListString) { + if (MyCommonUtil.existBlankArgument(roleId, userIdListString)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + Set userIdSet = Arrays.stream( + userIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysRoleService.existId(roleId) + || !sysUserService.existUniqueKeyList("userId", userIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + List userRoleList = new LinkedList<>(); + for (Long userId : userIdSet) { + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(roleId); + userRole.setUserId(userId); + userRoleList.add(userRole); + } + sysRoleService.addUserRoleList(userRoleList); + return ResponseResult.success(); + } + + /** + * 为指定用户移除指定角色。 + * + * @param roleId 指定角色主键Id。 + * @param userId 指定用户主键Id。 + * @return 应答数据结果。 + */ + @PostMapping("/deleteUserRole") + public ResponseResult deleteUserRole( + @MyRequestBody Long roleId, @MyRequestBody Long userId) { + if (MyCommonUtil.existBlankArgument(roleId, userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysRoleService.removeUserRole(roleId, userId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 查询角色的权限资源地址列表。同时返回详细的分配路径。 + * + * @param roleId 角色Id。 + * @param url url过滤条件。 + * @return 应答对象,包含从角色到权限资源的完整权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysPermWithDetail") + public ResponseResult>> listSysPermByWithDetail(Long roleId, String url) { + if (MyCommonUtil.isBlankOrNull(roleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysRoleService.getSysPermListWithDetail(roleId, url)); + } + + /** + * 查询角色的权限字列表。同时返回详细的分配路径。 + * + * @param roleId 角色Id。 + * @param permCode 权限字名称过滤条件。 + * @return 应答对象,包含从角色到权限字的权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysPermCodeWithDetail") + public ResponseResult>> listSysPermCodeWithDetail(Long roleId, String permCode) { + if (MyCommonUtil.isBlankOrNull(roleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysRoleService.getSysPermCodeListWithDetail(roleId, permCode)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysUserController.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysUserController.java new file mode 100644 index 00000000..ef762fb3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/controller/SysUserController.java @@ -0,0 +1,241 @@ +package com.flow.demo.webadmin.upms.controller; + +import com.alibaba.fastjson.TypeReference; +import com.github.pagehelper.page.PageMethod; +import com.flow.demo.webadmin.upms.vo.*; +import com.flow.demo.webadmin.upms.dto.*; +import com.flow.demo.webadmin.upms.model.*; +import com.flow.demo.webadmin.upms.service.*; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.constant.*; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.validator.AddGroup; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.webadmin.config.ApplicationConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 用户管理操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("/admin/upms/sysUser") +public class SysUserController { + + @Autowired + private SysUserService sysUserService; + @Autowired + private PasswordEncoder passwordEncoder; + @Autowired + private ApplicationConfig appConfig; + + /** + * 新增用户操作。 + * + * @param sysUserDto 新增用户对象。 + * @param deptPostIdListString 逗号分隔的部门岗位Id列表。 + * @param dataPermIdListString 逗号分隔的数据权限Id列表。 + * @param roleIdListString 逗号分隔的角色Id列表。 + * @return 应答结果对象,包含新增用户的主键Id。 + */ + @PostMapping("/add") + public ResponseResult add( + @MyRequestBody SysUserDto sysUserDto, + @MyRequestBody String deptPostIdListString, + @MyRequestBody String dataPermIdListString, + @MyRequestBody String roleIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysUserDto, Default.class, AddGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysUser sysUser = MyModelUtil.copyTo(sysUserDto, SysUser.class); + CallResult result = sysUserService.verifyRelatedData( + sysUser, null, roleIdListString, deptPostIdListString, dataPermIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set deptPostIdSet = result.getData().getObject("deptPostIdSet", new TypeReference>() {}); + Set roleIdSet = result.getData().getObject("roleIdSet", new TypeReference>() {}); + Set dataPermIdSet = result.getData().getObject("dataPermIdSet", new TypeReference>() {}); + sysUserService.saveNew(sysUser, roleIdSet, deptPostIdSet, dataPermIdSet); + return ResponseResult.success(sysUser.getUserId()); + } + + /** + * 更新用户操作。 + * + * @param sysUserDto 更新用户对象。 + * @param deptPostIdListString 逗号分隔的部门岗位Id列表。 + * @param dataPermIdListString 逗号分隔的数据权限Id列表。 + * @param roleIdListString 逗号分隔的角色Id列表。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update( + @MyRequestBody SysUserDto sysUserDto, + @MyRequestBody String deptPostIdListString, + @MyRequestBody String dataPermIdListString, + @MyRequestBody String roleIdListString) { + String errorMessage = MyCommonUtil.getModelValidationError(sysUserDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SysUser originalUser = sysUserService.getById(sysUserDto.getUserId()); + if (originalUser == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysUser sysUser = MyModelUtil.copyTo(sysUserDto, SysUser.class); + CallResult result = sysUserService.verifyRelatedData( + sysUser, originalUser, roleIdListString, deptPostIdListString, dataPermIdListString); + if (!result.isSuccess()) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, result.getErrorMessage()); + } + Set deptPostIdSet = result.getData().getObject("deptPostIdSet", new TypeReference>() {}); + Set roleIdSet = result.getData().getObject("roleIdSet", new TypeReference>() {}); + Set dataPermIdSet = result.getData().getObject("dataPermIdSet", new TypeReference>() {}); + if (!sysUserService.update(sysUser, originalUser, roleIdSet, deptPostIdSet, dataPermIdSet)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 重置密码操作。 + * + * @param userId 指定用户主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/resetPassword") + public ResponseResult resetPassword(@MyRequestBody Long userId) { + if (MyCommonUtil.existBlankArgument(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!sysUserService.changePassword(userId, appConfig.getDefaultUserPassword())) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除用户管理数据。 + * + * @param userId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long userId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + SysUser originalSysUser = sysUserService.getById(userId); + if (originalSysUser == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!sysUserService.remove(userId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的用户管理列表。 + * + * @param sysUserDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody SysUserDto sysUserDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + SysUser sysUserFilter = MyModelUtil.copyTo(sysUserDtoFilter, SysUser.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, SysUser.class); + List sysUserList = sysUserService.getSysUserListWithRelation(sysUserFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(sysUserList, SysUser.INSTANCE)); + } + + /** + * 查看指定用户管理对象详情。 + * + * @param userId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long userId) { + if (MyCommonUtil.existBlankArgument(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 这里查看用户数据时候,需要把用户多对多关联的角色和数据权限Id一并查出。 + SysUser sysUser = sysUserService.getByIdWithRelation(userId, MyRelationParam.full()); + if (sysUser == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + SysUserVo sysUserVo = SysUser.INSTANCE.fromModel(sysUser); + return ResponseResult.success(sysUserVo); + } + + /** + * 查询用户的权限资源地址列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param url url过滤条件。 + * @return 应答对象,包含从用户到权限资源的完整权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysPermWithDetail") + public ResponseResult>> listSysPermWithDetail(Long userId, String url) { + if (MyCommonUtil.isBlankOrNull(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysUserService.getSysPermListWithDetail(userId, url)); + } + + /** + * 查询用户的权限字列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param permCode 权限字名称过滤条件。 + * @return 应答对象,包含从用户到权限字的权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysPermCodeWithDetail") + public ResponseResult>> listSysPermCodeWithDetail(Long userId, String permCode) { + if (MyCommonUtil.isBlankOrNull(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysUserService.getSysPermCodeListWithDetail(userId, permCode)); + } + + /** + * 查询用户的菜单列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param menuName 菜单名称过滤条件。 + * @return 应答对象,包含从用户到菜单的权限分配路径信息的查询结果列表。 + */ + @GetMapping("/listSysMenuWithDetail") + public ResponseResult>> listSysMenuWithDetail(Long userId, String menuName) { + if (MyCommonUtil.isBlankOrNull(userId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + return ResponseResult.success(sysUserService.getSysMenuListWithDetail(userId, menuName)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermDeptMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermDeptMapper.java new file mode 100644 index 00000000..7497a954 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermDeptMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysDataPermDept; + +/** + * 数据权限与部门关系数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysDataPermDeptMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermMapper.java new file mode 100644 index 00000000..59612cae --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermMapper.java @@ -0,0 +1,35 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysDataPerm; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 数据权限数据访问操作接口。 + * NOTE: 该对象一定不能被 @EnableDataPerm 注解标注,否则会导致无限递归。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysDataPermMapper extends BaseDaoMapper { + + /** + * 获取数据权限列表。 + * + * @param sysDataPermFilter 过滤对象。 + * @param orderBy 排序字符串。 + * @return 过滤后的数据权限列表。 + */ + List getSysDataPermList( + @Param("sysDataPermFilter") SysDataPerm sysDataPermFilter, @Param("orderBy") String orderBy); + + /** + * 获取指定用户的数据权限列表。 + * + * @param userId 用户Id。 + * @return 数据权限列表。 + */ + List getSysDataPermListByUserId(@Param("userId") Long userId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermUserMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermUserMapper.java new file mode 100644 index 00000000..9a3b3817 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDataPermUserMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysDataPermUser; + +/** + * 数据权限与用户关系数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysDataPermUserMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptMapper.java new file mode 100644 index 00000000..5745592c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptMapper.java @@ -0,0 +1,26 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysDept; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 部门管理数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysDeptMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param sysDeptFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSysDeptList( + @Param("sysDeptFilter") SysDept sysDeptFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptPostMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptPostMapper.java new file mode 100644 index 00000000..c405692a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptPostMapper.java @@ -0,0 +1,33 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysDeptPost; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 部门岗位数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysDeptPostMapper extends BaseDaoMapper { + + /** + * 获取指定部门Id的部门岗位多对多关联数据列表,以及关联的部门和岗位数据。 + * + * @param deptId 部门Id。如果参数为空则返回全部数据。 + * @return 部门岗位多对多数量列表。 + */ + List> getSysDeptPostListWithRelationByDeptId(@Param("deptId") Long deptId); + + /** + * 获取指定部门Id的领导部门岗位列表。 + * + * @param deptId 部门Id。 + * @return 指定部门Id的领导部门岗位列表 + */ + List getLeaderDeptPostList(@Param("deptId") Long deptId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptRelationMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptRelationMapper.java new file mode 100644 index 00000000..267c4ad3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysDeptRelationMapper.java @@ -0,0 +1,42 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysDeptRelation; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 部门关系树关联关系表访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysDeptRelationMapper extends BaseDaoMapper { + + /** + * 将myDeptId的所有子部门,与其父部门parentDeptId解除关联关系。 + * + * @param parentDeptId myDeptId的父部门Id。 + * @param myDeptId 当前部门。 + */ + void removeBetweenChildrenAndParents( + @Param("parentDeptId") Long parentDeptId, @Param("myDeptId") Long myDeptId); + + /** + * 批量插入部门关联数据。 + * 由于目前版本(3.4.1)的Mybatis Plus没有提供真正的批量插入,为了保证效率需要自己实现。 + * 目前我们仅仅给出MySQL的insert list实现作为参考,其他数据库需要自行修改。 + * + * @param deptRelationList 部门关联关系数据列表。 + */ + void insertList(List deptRelationList); + + /** + * 批量插入当前部门的所有父部门列表,包括自己和自己的关系。 + * + * @param parentDeptId myDeptId的父部门Id。 + * @param myDeptId 当前部门。 + */ + void insertParentList(@Param("parentDeptId") Long parentDeptId, @Param("myDeptId") Long myDeptId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysMenuMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysMenuMapper.java new file mode 100644 index 00000000..c557f90a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysMenuMapper.java @@ -0,0 +1,54 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysMenu; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 菜单数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysMenuMapper extends BaseDaoMapper { + + /** + * 获取登录用户的菜单列表。 + * + * @param userId 登录用户。 + * @return 菜单列表。 + */ + List getMenuListByUserId(@Param("userId") Long userId); + + /** + * 获取当前用户有权访问的在线表单菜单,仅返回类型为BUTTON的菜单。 + * + * @param userId 指定的用户。 + * @param menuType 菜单类型,NULL则返回全部类型。 + * @return 在线表单关联的菜单列表。 + */ + List getOnlineMenuListByUserId( + @Param("userId") Long userId, @Param("menuType") Integer menuType); + + /** + * 查询菜单的权限资源地址列表。同时返回详细的分配路径。 + * + * @param menuId 菜单Id。 + * @param url 权限资源地址过滤条件。 + * @return 包含从菜单到权限资源的权限分配路径信息的查询结果列表。 + */ + List> getSysPermListWithDetail( + @Param("menuId") Long menuId, @Param("url") String url); + + /** + * 查询菜单的用户列表。同时返回详细的分配路径。 + * + * @param menuId 菜单Id。 + * @param loginName 登录名。 + * @return 包含从菜单到用户的完整权限分配路径信息的查询结果列表。 + */ + List> getSysUserListWithDetail( + @Param("menuId") Long menuId, @Param("loginName") String loginName); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysMenuPermCodeMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysMenuPermCodeMapper.java new file mode 100644 index 00000000..c4e930ce --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysMenuPermCodeMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysMenuPermCode; + +/** + * 菜单与权限字关系数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysMenuPermCodeMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermCodeMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermCodeMapper.java new file mode 100644 index 00000000..76711a40 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermCodeMapper.java @@ -0,0 +1,45 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysPermCode; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 权限字数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPermCodeMapper extends BaseDaoMapper { + + /** + * 获取用户的所有权限字列表。 + * + * @param userId 用户Id。 + * @return 该用户的权限字列表。 + */ + List getPermCodeListByUserId(@Param("userId") Long userId); + + /** + * 查询权限字的用户列表。同时返回详细的分配路径。 + * + * @param permCodeId 权限字Id。 + * @param loginName 登录名。 + * @return 包含从权限字到用户的完整权限分配路径信息的查询结果列表。 + */ + List> getSysUserListWithDetail( + @Param("permCodeId") Long permCodeId, @Param("loginName") String loginName); + + /** + * 查询权限字的角色列表。同时返回详细的分配路径。 + * + * @param permCodeId 权限字Id。 + * @param roleName 角色名。 + * @return 包含从权限字到角色的权限分配路径信息的查询结果列表。 + */ + List> getSysRoleListWithDetail( + @Param("permCodeId") Long permCodeId, @Param("roleName") String roleName); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermCodePermMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermCodePermMapper.java new file mode 100644 index 00000000..80dae542 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermCodePermMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysPermCodePerm; + +/** + * 权限字与权限资源关系数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPermCodePermMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermMapper.java new file mode 100644 index 00000000..d8e351b1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermMapper.java @@ -0,0 +1,54 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysPerm; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 权限资源数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPermMapper extends BaseDaoMapper { + + /** + * 获取用户的权限列表。 + * + * @param userId 用户Id。 + * @return 该用户的权限标识列表。 + */ + List getPermListByUserId(@Param("userId") Long userId); + + /** + * 查询权限资源地址的用户列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param loginName 登录名。 + * @return 包含从权限资源到用户的完整权限分配路径信息的查询结果列表。 + */ + List> getSysUserListWithDetail( + @Param("permId") Long permId, @Param("loginName") String loginName); + + /** + * 查询权限资源地址的角色列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param roleName 角色名。 + * @return 包含从权限资源到角色的权限分配路径信息的查询结果列表。 + */ + List> getSysRoleListWithDetail( + @Param("permId") Long permId, @Param("roleName") String roleName); + + /** + * 查询权限资源地址的菜单列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param menuName 菜单名。 + * @return 包含从权限资源到菜单的权限分配路径信息的查询结果列表。 + */ + List> getSysMenuListWithDetail( + @Param("permId") Long permId, @Param("menuName") String menuName); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermModuleMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermModuleMapper.java new file mode 100644 index 00000000..494eb9ba --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermModuleMapper.java @@ -0,0 +1,22 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysPermModule; + +import java.util.List; + +/** + * 权限资源模块数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPermModuleMapper extends BaseDaoMapper { + + /** + * 获取整个权限模块和权限关联后的全部数据。 + * + * @return 关联的权限模块和权限资源列表。 + */ + List getPermModuleAndPermList(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermWhitelistMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermWhitelistMapper.java new file mode 100644 index 00000000..803a2c5c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPermWhitelistMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysPermWhitelist; + +/** + * 权限资源白名单数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPermWhitelistMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPostMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPostMapper.java new file mode 100644 index 00000000..1bb63676 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysPostMapper.java @@ -0,0 +1,52 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysPost; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 岗位管理数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPostMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param sysPostFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSysPostList( + @Param("sysPostFilter") SysPost sysPostFilter, @Param("orderBy") String orderBy); + + /** + * 获取指定部门的岗位列表。 + * + * @param deptId 部门Id。 + * @param sysPostFilter 从表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 岗位数据列表。 + */ + List getSysPostListByDeptId( + @Param("deptId") Long deptId, + @Param("sysPostFilter") SysPost sysPostFilter, + @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表中没有和主表建立关联关系的数据列表。 + * + * @param deptId 关联主表Id。 + * @param sysPostFilter 过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 与主表没有建立关联的从表数据列表。 + */ + List getNotInSysPostListByDeptId( + @Param("deptId") Long deptId, + @Param("sysPostFilter") SysPost sysPostFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysRoleMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysRoleMapper.java new file mode 100644 index 00000000..bb9c5e81 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysRoleMapper.java @@ -0,0 +1,45 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysRole; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 角色数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysRoleMapper extends BaseDaoMapper { + + /** + * 获取对象列表,过滤条件中包含like和between条件。 + * + * @param sysRoleFilter 过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSysRoleList(@Param("sysRoleFilter") SysRole sysRoleFilter, @Param("orderBy") String orderBy); + + /** + * 查询角色的权限资源地址列表。同时返回详细的分配路径。 + * + * @param roleId 角色Id。 + * @param url url过滤条件。 + * @return 包含从角色到权限资源的完整权限分配路径信息的查询结果列表。 + */ + List> getSysPermListWithDetail( + @Param("roleId") Long roleId, @Param("url") String url); + + /** + * 查询角色的权限字列表。同时返回详细的分配路径。 + * + * @param roleId 角色Id。 + * @param permCode 权限字名称过滤条件。 + * @return 包含从角色到权限字的权限分配路径信息的查询结果列表。 + */ + List> getSysPermCodeListWithDetail( + @Param("roleId") Long roleId, @Param("permCode") String permCode); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysRoleMenuMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysRoleMenuMapper.java new file mode 100644 index 00000000..0c141fe3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysRoleMenuMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysRoleMenu; + +/** + * 角色与菜单操作关联关系数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysRoleMenuMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserMapper.java new file mode 100644 index 00000000..518dbdd0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserMapper.java @@ -0,0 +1,108 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysUser; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 用户管理数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysUserMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param sysUserFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getSysUserList( + @Param("sysUserFilter") SysUser sysUserFilter, @Param("orderBy") String orderBy); + + /** + * 根据角色Id,获取关联的用户Id列表。 + * + * @param roleId 关联的角色Id。 + * @param sysUserFilter 用户过滤条件对象。 + * @param orderBy order by从句的参数。 + * @return 和RoleId关联的用户列表。 + */ + List getSysUserListByRoleId( + @Param("roleId") Long roleId, + @Param("sysUserFilter") SysUser sysUserFilter, + @Param("orderBy") String orderBy); + + /** + * 根据角色Id,获取和当前角色Id没有建立多对多关联关系的用户Id列表。 + * + * @param roleId 关联的角色Id。 + * @param sysUserFilter 用户过滤条件对象。 + * @param orderBy order by从句的参数。 + * @return 和RoleId没有建立关联关系的用户列表。 + */ + List getNotInSysUserListByRoleId( + @Param("roleId") Long roleId, + @Param("sysUserFilter") SysUser sysUserFilter, + @Param("orderBy") String orderBy); + + /** + * 根据数据权限Id,获取关联的用户Id列表。 + * + * @param dataPermId 关联的数据权限Id。 + * @param sysUserFilter 用户过滤条件对象。 + * @param orderBy order by从句的参数。 + * @return 和DataPermId关联的用户列表。 + */ + List getSysUserListByDataPermId( + @Param("dataPermId") Long dataPermId, + @Param("sysUserFilter") SysUser sysUserFilter, + @Param("orderBy") String orderBy); + + /** + * 根据数据权限Id,获取和当前数据权限Id没有建立多对多关联关系的用户Id列表。 + * + * @param dataPermId 关联的数据权限Id。 + * @param sysUserFilter 用户过滤条件对象。 + * @param orderBy order by从句的参数。 + * @return 和DataPermId没有建立关联关系的用户列表。 + */ + List getNotInSysUserListByDataPermId( + @Param("dataPermId") Long dataPermId, + @Param("sysUserFilter") SysUser sysUserFilter, + @Param("orderBy") String orderBy); + + /** + * 查询用户的权限资源地址列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param url url过滤条件。 + * @return 包含从用户到权限资源的完整权限分配路径信息的查询结果列表。 + */ + List> getSysPermListWithDetail( + @Param("userId") Long userId, @Param("url") String url); + + /** + * 查询用户的权限字列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param permCode 权限字名称过滤条件。 + * @return 包含从用户到权限字的权限分配路径信息的查询结果列表。 + */ + List> getSysPermCodeListWithDetail( + @Param("userId") Long userId, @Param("permCode") String permCode); + + /** + * 查询用户的菜单列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param menuName 菜单名称过滤条件。 + * @return 包含从用户到菜单的权限分配路径信息的查询结果列表。 + */ + List> getSysMenuListWithDetail( + @Param("userId") Long userId, @Param("menuName") String menuName); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserPostMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserPostMapper.java new file mode 100644 index 00000000..c876543d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserPostMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysUserPost; + +/** + * 用户岗位数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysUserPostMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserRoleMapper.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserRoleMapper.java new file mode 100644 index 00000000..93b04971 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/SysUserRoleMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.webadmin.upms.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.model.SysUserRole; + +/** + * 用户与角色关联关系数据访问操作接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysUserRoleMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermDeptMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermDeptMapper.xml new file mode 100644 index 00000000..22b6372e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermDeptMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermMapper.xml new file mode 100644 index 00000000..b01c1acc --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermMapper.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + AND zz_sys_data_perm.rule_type = #{sysDataPermFilter.ruleType} + + + + AND IFNULL(zz_sys_data_perm.data_perm_name, '') LIKE #{safeSearchString} + + + AND zz_sys_data_perm.deleted_flag = ${@com.flow.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermUserMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermUserMapper.xml new file mode 100644 index 00000000..259f00ad --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDataPermUserMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptMapper.xml new file mode 100644 index 00000000..e356422f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptMapper.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + AND zz_sys_dept.deleted_flag = ${@com.flow.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + + + + + AND zz_sys_dept.dept_name LIKE #{safeSysDeptDeptName} + + + AND zz_sys_dept.parent_id = #{sysDeptFilter.parentId} + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptPostMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptPostMapper.xml new file mode 100644 index 00000000..aad5efc8 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptPostMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptRelationMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptRelationMapper.xml new file mode 100644 index 00000000..9f7c2093 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysDeptRelationMapper.xml @@ -0,0 +1,29 @@ + + + + + + + + + + DELETE a FROM zz_sys_dept_relation a + INNER JOIN zz_sys_dept_relation b ON a.dept_id = b.dept_id + WHERE a.parent_dept_id = #{parentDeptId} AND b.parent_dept_id = #{myDeptId} + + + + INSERT INTO zz_sys_dept_relation(parent_dept_id, dept_id) VALUES + + (#{item.parentDeptId}, #{item.deptId}) + + + + + INSERT INTO zz_sys_dept_relation(parent_dept_id, dept_id) + SELECT t.parent_dept_id, #{myDeptId} FROM zz_sys_dept_relation t + WHERE t.dept_id = #{parentDeptId} + UNION ALL + SELECT #{myDeptId}, #{myDeptId} + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysMenuMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysMenuMapper.xml new file mode 100644 index 00000000..9fb5725d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysMenuMapper.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysMenuPermCodeMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysMenuPermCodeMapper.xml new file mode 100644 index 00000000..33446247 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysMenuPermCodeMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermCodeMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermCodeMapper.xml new file mode 100644 index 00000000..84a45935 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermCodeMapper.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermCodePermMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermCodePermMapper.xml new file mode 100644 index 00000000..c2aeef33 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermCodePermMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermMapper.xml new file mode 100644 index 00000000..eabe9f32 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermMapper.xml @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermModuleMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermModuleMapper.xml new file mode 100644 index 00000000..50f93342 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermModuleMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermWhitelistMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermWhitelistMapper.xml new file mode 100644 index 00000000..ca7cef02 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPermWhitelistMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPostMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPostMapper.xml new file mode 100644 index 00000000..4eb8348e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysPostMapper.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + AND zz_sys_post.deleted_flag = ${@com.flow.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + + + + + AND zz_sys_post.post_name LIKE #{safeSysPostPostName} + + + AND zz_sys_post.leader_post = #{sysPostFilter.leaderPost} + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysRoleMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysRoleMapper.xml new file mode 100644 index 00000000..62b5f581 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysRoleMapper.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + AND role_name LIKE #{safeRoleName} + + + AND deleted_flag = ${@com.flow.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysRoleMenuMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysRoleMenuMapper.xml new file mode 100644 index 00000000..30fec4eb --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysRoleMenuMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserMapper.xml new file mode 100644 index 00000000..5fa3cfdd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserMapper.xml @@ -0,0 +1,213 @@ + + + + + + + + + + + + + + + + + + + + + + + + AND zz_sys_user.deleted_flag = ${@com.flow.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + + + + + AND zz_sys_user.login_name LIKE #{safeSysUserLoginName} + + + + AND zz_sys_user.show_name LIKE #{safeSysUserShowName} + + + AND zz_sys_user.dept_id = #{sysUserFilter.deptId} + + + AND zz_sys_user.user_status = #{sysUserFilter.userStatus} + + + AND zz_sys_user.create_time >= #{sysUserFilter.createTimeStart} + + + AND zz_sys_user.create_time <= #{sysUserFilter.createTimeEnd} + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserPostMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserPostMapper.xml new file mode 100644 index 00000000..e2747cd2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserPostMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserRoleMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserRoleMapper.xml new file mode 100644 index 00000000..cecb2dd7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dao/mapper/SysUserRoleMapper.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDataPermDeptDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDataPermDeptDto.java new file mode 100644 index 00000000..d1f4f9ae --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDataPermDeptDto.java @@ -0,0 +1,23 @@ +package com.flow.demo.webadmin.upms.dto; + +import lombok.Data; + +/** + * 数据权限与部门关联Dto。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysDataPermDeptDto { + + /** + * 数据权限Id。 + */ + private Long dataPermId; + + /** + * 关联部门Id。 + */ + private Long deptId; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDataPermDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDataPermDto.java new file mode 100644 index 00000000..6c974605 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDataPermDto.java @@ -0,0 +1,48 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.datafilter.constant.DataPermRuleType; + +import lombok.Data; + +import javax.validation.constraints.*; + +/** + * 数据权限Dto。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysDataPermDto { + + /** + * 数据权限Id。 + */ + @NotNull(message = "数据权限Id不能为空!", groups = {UpdateGroup.class}) + private Long dataPermId; + + /** + * 显示名称。 + */ + @NotBlank(message = "数据权限名称不能为空!") + private String dataPermName; + + /** + * 数据权限规则类型(0: 全部可见 1: 只看自己 2: 只看本部门 3: 本部门及子部门 4: 多部门及子部门 5: 自定义部门列表)。 + */ + @NotNull(message = "数据权限规则类型不能为空!") + @ConstDictRef(constDictClass = DataPermRuleType.class) + private Integer ruleType; + + /** + * 部门Id列表(逗号分隔)。 + */ + private String deptIdListString; + + /** + * 搜索字符串。 + */ + private String searchString; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDeptDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDeptDto.java new file mode 100644 index 00000000..8ab96987 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDeptDto.java @@ -0,0 +1,40 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; + +import lombok.Data; + +import javax.validation.constraints.*; + +/** + * SysDeptDto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysDeptDto { + + /** + * 部门Id。 + */ + @NotNull(message = "数据验证失败,部门Id不能为空!", groups = {UpdateGroup.class}) + private Long deptId; + + /** + * 部门名称。 + */ + @NotBlank(message = "数据验证失败,部门名称不能为空!") + private String deptName; + + /** + * 显示顺序。 + */ + @NotNull(message = "数据验证失败,显示顺序不能为空!") + private Integer showOrder; + + /** + * 父部门Id。 + */ + private Long parentId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDeptPostDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDeptPostDto.java new file mode 100644 index 00000000..d17e2478 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysDeptPostDto.java @@ -0,0 +1,41 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; + +import lombok.Data; + +import javax.validation.constraints.*; + +/** + * 部门岗位Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysDeptPostDto { + + /** + * 部门岗位Id。 + */ + @NotNull(message = "数据验证失败,部门岗位Id不能为空!", groups = {UpdateGroup.class}) + private Long deptPostId; + + /** + * 部门Id。 + */ + @NotNull(message = "数据验证失败,部门Id不能为空!", groups = {UpdateGroup.class}) + private Long deptId; + + /** + * 岗位Id。 + */ + @NotNull(message = "数据验证失败,岗位Id不能为空!", groups = {UpdateGroup.class}) + private Long postId; + + /** + * 部门岗位显示名称。 + */ + @NotBlank(message = "数据验证失败,部门岗位显示名称不能为空!") + private String postShowName; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysMenuDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysMenuDto.java new file mode 100644 index 00000000..2e53b1ae --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysMenuDto.java @@ -0,0 +1,69 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.webadmin.upms.model.constant.SysMenuType; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 菜单Dto。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysMenuDto { + + /** + * 菜单Id。 + */ + @NotNull(message = "菜单Id不能为空!", groups = {UpdateGroup.class}) + private Long menuId; + + /** + * 父菜单Id,目录菜单的父菜单为null + */ + private Long parentId; + + /** + * 菜单显示名称。 + */ + @NotBlank(message = "菜单显示名称不能为空!") + private String menuName; + + /** + * 菜单类型 (0: 目录 1: 菜单 2: 按钮 3: UI片段)。 + */ + @NotNull(message = "菜单类型不能为空!") + @ConstDictRef(constDictClass = SysMenuType.class, message = "数据验证失败,菜单类型为无效值!") + private Integer menuType; + + /** + * 前端表单路由名称,仅用于menu_type为1的菜单类型。 + */ + private String formRouterName; + + /** + * 在线表单主键Id,仅用于在线表单绑定的菜单。 + */ + private Long onlineFormId; + + /** + * 仅用于在线表单的流程Id。 + */ + private Long onlineFlowEntryId; + + /** + * 菜单显示顺序 (值越小,排序越靠前)。 + */ + @NotNull(message = "菜单显示顺序不能为空!") + private Integer showOrder; + + /** + * 菜单图标。 + */ + private String icon; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermCodeDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermCodeDto.java new file mode 100644 index 00000000..d7cbe342 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermCodeDto.java @@ -0,0 +1,55 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.webadmin.upms.model.constant.SysPermCodeType; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 权限字Dto。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysPermCodeDto { + + /** + * 权限字Id。 + */ + @NotNull(message = "权限字Id不能为空!", groups = {UpdateGroup.class}) + private Long permCodeId; + + /** + * 权限字标识(一般为有含义的英文字符串)。 + */ + @NotBlank(message = "权限字编码不能为空!") + private String permCode; + + /** + * 上级权限字Id。 + */ + private Long parentId; + + /** + * 权限字类型(0: 表单 1: UI片段 2: 操作)。 + */ + @NotNull(message = "权限字类型不能为空!") + @ConstDictRef(constDictClass = SysPermCodeType.class, message = "数据验证失败,权限类型为无效值!") + private Integer permCodeType; + + /** + * 显示名称。 + */ + @NotBlank(message = "权限字显示名称不能为空!") + private String showName; + + /** + * 显示顺序(数值越小,越靠前)。 + */ + @NotNull(message = "权限字显示顺序不能为空!") + private Integer showOrder; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermDto.java new file mode 100644 index 00000000..6f5133f6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermDto.java @@ -0,0 +1,52 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 权限资源Dto。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysPermDto { + + /** + * 权限资源Id。 + */ + @NotNull(message = "权限Id不能为空!", groups = {UpdateGroup.class}) + private Long permId; + + /** + * 权限资源名称。 + */ + @NotBlank(message = "权限资源名称不能为空!") + private String permName; + + /** + * shiro格式的权限字,如(upms:sysUser:add)。 + */ + private String permCode; + + /** + * 权限所在的权限模块Id。 + */ + @NotNull(message = "权限模块Id不能为空!") + private Long moduleId; + + /** + * 关联的URL。 + */ + @NotBlank(message = "权限关联的url不能为空!") + private String url; + + /** + * 权限在当前模块下的顺序,由小到大。 + */ + @NotNull(message = "权限显示顺序不能为空!") + private Integer showOrder; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermModuleDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermModuleDto.java new file mode 100644 index 00000000..46de7ae3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPermModuleDto.java @@ -0,0 +1,49 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.webadmin.upms.model.constant.SysPermModuleType; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 权限资源模块Dto。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysPermModuleDto { + + /** + * 权限模块Id。 + */ + @NotNull(message = "权限模块Id不能为空!", groups = {UpdateGroup.class}) + private Long moduleId; + + /** + * 权限模块名称。 + */ + @NotBlank(message = "权限模块名称不能为空!") + private String moduleName; + + /** + * 上级权限模块Id。 + */ + private Long parentId; + + /** + * 权限模块类型(0: 普通模块 1: Controller模块)。 + */ + @NotNull(message = "模块类型不能为空!") + @ConstDictRef(constDictClass = SysPermModuleType.class, message = "数据验证失败,权限模块类型为无效值!") + private Integer moduleType; + + /** + * 权限模块在当前层级下的顺序,由小到大。 + */ + @NotNull(message = "权限模块显示顺序不能为空!") + private Integer showOrder; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPostDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPostDto.java new file mode 100644 index 00000000..a4178825 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysPostDto.java @@ -0,0 +1,41 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; + +import lombok.Data; + +import javax.validation.constraints.*; + +/** + * 岗位Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysPostDto { + + /** + * 岗位Id。 + */ + @NotNull(message = "数据验证失败,岗位Id不能为空!", groups = {UpdateGroup.class}) + private Long postId; + + /** + * 岗位名称。 + */ + @NotBlank(message = "数据验证失败,岗位名称不能为空!") + private String postName; + + /** + * 岗位层级,数值越小级别越高。 + */ + @NotNull(message = "数据验证失败,岗位层级不能为空!") + private Integer level; + + /** + * 是否领导岗位。 + */ + @NotNull(message = "数据验证失败,领导岗位不能为空!", groups = {UpdateGroup.class}) + private Boolean leaderPost; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysRoleDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysRoleDto.java new file mode 100644 index 00000000..529181c6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysRoleDto.java @@ -0,0 +1,28 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.*; + +/** + * 角色Dto。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysRoleDto { + + /** + * 角色Id。 + */ + @NotNull(message = "角色Id不能为空!", groups = {UpdateGroup.class}) + private Long roleId; + + /** + * 角色名称。 + */ + @NotBlank(message = "角色名称不能为空!") + private String roleName; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysUserDto.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysUserDto.java new file mode 100644 index 00000000..ec0b2776 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/dto/SysUserDto.java @@ -0,0 +1,80 @@ +package com.flow.demo.webadmin.upms.dto; + +import com.flow.demo.common.core.validator.AddGroup; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.webadmin.upms.model.constant.SysUserType; +import com.flow.demo.webadmin.upms.model.constant.SysUserStatus; + +import lombok.Data; + +import javax.validation.constraints.*; + +/** + * SysUserDto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysUserDto { + + /** + * 用户Id。 + */ + @NotNull(message = "数据验证失败,用户Id不能为空!", groups = {UpdateGroup.class}) + private Long userId; + + /** + * 登录用户名。 + */ + @NotBlank(message = "数据验证失败,登录用户名不能为空!") + private String loginName; + + /** + * 用户密码。 + */ + @NotBlank(message = "数据验证失败,用户密码不能为空!", groups = {AddGroup.class}) + private String password; + + /** + * 用户显示名称。 + */ + @NotBlank(message = "数据验证失败,用户显示名称不能为空!") + private String showName; + + /** + * 用户部门Id。 + */ + @NotNull(message = "数据验证失败,用户部门Id不能为空!") + private Long deptId; + + /** + * 用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)。 + */ + @NotNull(message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)不能为空!") + @ConstDictRef(constDictClass = SysUserType.class, message = "数据验证失败,用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)为无效值!") + private Integer userType; + + /** + * 用户头像的Url。 + */ + private String headImageUrl; + + /** + * 用户状态(0: 正常 1: 锁定)。 + */ + @NotNull(message = "数据验证失败,用户状态(0: 正常 1: 锁定)不能为空!") + @ConstDictRef(constDictClass = SysUserStatus.class, message = "数据验证失败,用户状态(0: 正常 1: 锁定)为无效值!") + private Integer userStatus; + + /** + * createTime 范围过滤起始值(>=)。 + */ + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + private String createTimeEnd; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPerm.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPerm.java new file mode 100644 index 00000000..ce798258 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPerm.java @@ -0,0 +1,113 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.annotation.RelationManyToMany; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.webadmin.upms.vo.SysDataPermVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.*; + +/** + * 数据权限实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_data_perm") +public class SysDataPerm { + + /** + * 主键Id。 + */ + @TableId(value = "data_perm_id") + private Long dataPermId; + + /** + * 显示名称。 + */ + @TableField(value = "data_perm_name") + private String dataPermName; + + /** + * 数据权限规则类型(0: 全部可见 1: 只看自己 2: 只看本部门 3: 本部门及子部门 4: 多部门及子部门 5: 自定义部门列表)。 + */ + @TableField(value = "rule_type") + private Integer ruleType; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + @TableField(exist = false) + private String deptIdListString; + + @RelationManyToMany( + relationMapperName = "sysDataPermDeptMapper", + relationMasterIdField = "dataPermId", + relationModelClass = SysDataPermDept.class) + @TableField(exist = false) + private List dataPermDeptList; + + @TableField(exist = false) + private String searchString; + + public void setSearchString(String searchString) { + this.searchString = MyCommonUtil.replaceSqlWildcard(searchString); + } + + @Mapper + public interface SysDataPermModelMapper extends BaseModelMapper { + /** + * 转换VO对象到实体对象。 + * + * @param sysDataPermVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "dataPermDeptList", expression = "java(mapToBean(sysDataPermVo.getDataPermDeptList(), com.flow.demo.webadmin.upms.model.SysDataPermDept.class))") + @Override + SysDataPerm toModel(SysDataPermVo sysDataPermVo); + /** + * 转换实体对象到VO对象。 + * + * @param sysDataPerm 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "dataPermDeptList", expression = "java(beanToMap(sysDataPerm.getDataPermDeptList(), false))") + @Override + SysDataPermVo fromModel(SysDataPerm sysDataPerm); + } + public static final SysDataPermModelMapper INSTANCE = Mappers.getMapper(SysDataPerm.SysDataPermModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPermDept.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPermDept.java new file mode 100644 index 00000000..39c4a94c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPermDept.java @@ -0,0 +1,29 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.ToString; + +/** + * 数据权限与部门关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ToString(of = {"deptId"}) +@TableName(value = "zz_sys_data_perm_dept") +public class SysDataPermDept { + + /** + * 数据权限Id。 + */ + @TableField(value = "data_perm_id") + private Long dataPermId; + + /** + * 关联部门Id。 + */ + @TableField(value = "dept_id") + private Long deptId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPermUser.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPermUser.java new file mode 100644 index 00000000..8a19c9b6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDataPermUser.java @@ -0,0 +1,27 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 数据权限与用户关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_data_perm_user") +public class SysDataPermUser { + + /** + * 数据权限Id。 + */ + @TableField(value = "data_perm_id") + private Long dataPermId; + + /** + * 用户Id。 + */ + @TableField(value = "user_id") + private Long userId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDept.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDept.java new file mode 100644 index 00000000..303c8345 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDept.java @@ -0,0 +1,81 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.webadmin.upms.vo.SysDeptVo; +import lombok.Data; +import org.mapstruct.*; +import org.mapstruct.factory.Mappers; + +import java.util.Date; + +/** + * SysDept实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_dept") +public class SysDept { + + /** + * 部门Id。 + */ + @TableId(value = "dept_id") + private Long deptId; + + /** + * 部门名称。 + */ + @TableField(value = "dept_name") + private String deptName; + + /** + * 显示顺序。 + */ + @TableField(value = "show_order") + private Integer showOrder; + + /** + * 父部门Id。 + */ + @TableField(value = "parent_id") + private Long parentId; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + @Mapper + public interface SysDeptModelMapper extends BaseModelMapper { + } + public static final SysDeptModelMapper INSTANCE = Mappers.getMapper(SysDeptModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDeptPost.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDeptPost.java new file mode 100644 index 00000000..d0600879 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDeptPost.java @@ -0,0 +1,39 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 部门岗位多对多关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_dept_post") +public class SysDeptPost { + + /** + * 部门岗位Id。 + */ + @TableId(value = "dept_post_id") + private Long deptPostId; + + /** + * 部门Id。 + */ + @TableField(value = "dept_id") + private Long deptId; + + /** + * 岗位Id。 + */ + @TableField(value = "post_id") + private Long postId; + + /** + * 部门岗位显示名称。 + */ + @TableField(value = "post_show_name") + private String postShowName; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDeptRelation.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDeptRelation.java new file mode 100644 index 00000000..7faf2306 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysDeptRelation.java @@ -0,0 +1,31 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 部门关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@TableName(value = "zz_sys_dept_relation") +public class SysDeptRelation { + + /** + * 上级部门Id。 + */ + @TableField(value = "parent_dept_id") + private Long parentDeptId; + + /** + * 部门Id。 + */ + @TableField(value = "dept_id") + private Long deptId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysMenu.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysMenu.java new file mode 100644 index 00000000..66cd7d10 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysMenu.java @@ -0,0 +1,143 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationManyToMany; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.webadmin.upms.vo.SysMenuVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.*; + +/** + * 菜单实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_menu") +public class SysMenu { + + /** + * 菜单Id。 + */ + @TableId(value = "menu_id") + private Long menuId; + + /** + * 父菜单Id,目录菜单的父菜单为null。 + */ + @TableField(value = "parent_id") + private Long parentId; + + /** + * 菜单显示名称。 + */ + @TableField(value = "menu_name") + private String menuName; + + /** + * 菜单类型(0: 目录 1: 菜单 2: 按钮 3: UI片段)。 + */ + @TableField(value = "menu_type") + private Integer menuType; + + /** + * 前端表单路由名称,仅用于menu_type为1的菜单类型。 + */ + @TableField(value = "form_router_name") + private String formRouterName; + + /** + * 在线表单主键Id,仅用于在线表单绑定的菜单。 + */ + @TableField(value = "online_form_id") + private Long onlineFormId; + + /** + * 在线表单菜单的权限控制类型,具体值可参考SysOnlineMenuPermType常量对象。 + */ + @TableField(value = "online_menu_perm_type") + private Integer onlineMenuPermType; + + /** + * 仅用于在线表单的流程Id。 + */ + @TableField(value = "online_flow_entry_id") + private Long onlineFlowEntryId; + + /** + * 菜单显示顺序 (值越小,排序越靠前)。 + */ + @TableField(value = "show_order") + private Integer showOrder; + + /** + * 菜单图标。 + */ + private String icon; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + @RelationManyToMany( + relationMapperName = "sysMenuPermCodeMapper", + relationMasterIdField = "menuId", + relationModelClass = SysMenuPermCode.class) + @TableField(exist = false) + private List sysMenuPermCodeList; + + @Mapper + public interface SysMenuModelMapper extends BaseModelMapper { + /** + * 转换VO对象到实体对象。 + * + * @param sysMenuVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "sysMenuPermCodeList", expression = "java(mapToBean(sysMenuVo.getSysMenuPermCodeList(), com.flow.demo.webadmin.upms.model.SysMenuPermCode.class))") + @Override + SysMenu toModel(SysMenuVo sysMenuVo); + /** + * 转换实体对象到VO对象。 + * + * @param sysMenu 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "sysMenuPermCodeList", expression = "java(beanToMap(sysMenu.getSysMenuPermCodeList(), false))") + @Override + SysMenuVo fromModel(SysMenu sysMenu); + } + public static final SysMenuModelMapper INSTANCE = Mappers.getMapper(SysMenu.SysMenuModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysMenuPermCode.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysMenuPermCode.java new file mode 100644 index 00000000..ad47fa04 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysMenuPermCode.java @@ -0,0 +1,27 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 菜单与权限字关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_menu_perm_code") +public class SysMenuPermCode { + + /** + * 关联菜单Id。 + */ + @TableField(value = "menu_id") + private Long menuId; + + /** + * 关联权限字Id。 + */ + @TableField(value = "perm_code_id") + private Long permCodeId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPerm.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPerm.java new file mode 100644 index 00000000..2e78d04c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPerm.java @@ -0,0 +1,87 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationDict; +import lombok.Data; + +import java.util.*; + +/** + * 权限资源实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_perm") +public class SysPerm { + + /** + * 权限资源Id。 + */ + @TableId(value = "perm_id") + private Long permId; + + /** + * 权限所在的权限模块Id。 + */ + @TableField(value = "module_id") + private Long moduleId; + + /** + * 权限名称。 + */ + @TableField(value = "perm_name") + private String permName; + + /** + * 关联的URL。 + */ + private String url; + + /** + * 权限在当前模块下的顺序,由小到大。 + */ + @TableField(value = "show_order") + private Integer showOrder; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + @RelationDict( + masterIdField = "moduleId", + slaveServiceName = "SysPermModuleService", + slaveModelClass = SysPermModule.class, + slaveIdField = "moduleId", + slaveNameField = "moduleName") + @TableField(exist = false) + private Map moduleIdDictMap; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermCode.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermCode.java new file mode 100644 index 00000000..23bc944c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermCode.java @@ -0,0 +1,120 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationManyToMany; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.webadmin.upms.vo.SysPermCodeVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.*; + +/** + * 权限字实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_perm_code") +public class SysPermCode { + + /** + * 权限字Id。 + */ + @TableId(value = "perm_code_id") + private Long permCodeId; + + /** + * 上级权限字Id。 + */ + @TableField(value = "parent_id") + private Long parentId; + + /** + * 权限字标识(一般为有含义的英文字符串)。 + */ + @TableField(value = "perm_code") + private String permCode; + + /** + * 权限类型(0: 表单 1: UI片段 2: 操作)。 + */ + @TableField(value = "perm_code_type") + private Integer permCodeType; + + /** + * 显示名称。 + */ + @TableField(value = "show_name") + private String showName; + + /** + * 显示顺序(数值越小,越靠前)。 + */ + @TableField(value = "show_order") + private Integer showOrder; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + @RelationManyToMany( + relationMapperName = "sysPermCodePermMapper", + relationMasterIdField = "permCodeId", + relationModelClass = SysPermCodePerm.class) + @TableField(exist = false) + private List sysPermCodePermList; + + @Mapper + public interface SysPermCodeModelMapper extends BaseModelMapper { + /** + * 转换VO对象到实体对象。 + * + * @param sysPermCodeVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "sysPermCodePermList", expression = "java(mapToBean(sysPermCodeVo.getSysPermCodePermList(), com.flow.demo.webadmin.upms.model.SysPermCodePerm.class))") + @Override + SysPermCode toModel(SysPermCodeVo sysPermCodeVo); + /** + * 转换实体对象到VO对象。 + * + * @param sysPermCode 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "sysPermCodePermList", expression = "java(beanToMap(sysPermCode.getSysPermCodePermList(), false))") + @Override + SysPermCodeVo fromModel(SysPermCode sysPermCode); + } + public static final SysPermCodeModelMapper INSTANCE = Mappers.getMapper(SysPermCode.SysPermCodeModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermCodePerm.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermCodePerm.java new file mode 100644 index 00000000..1b39a351 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermCodePerm.java @@ -0,0 +1,27 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 权限字与权限资源关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_perm_code_perm") +public class SysPermCodePerm { + + /** + * 权限字Id。 + */ + @TableField(value = "perm_code_id") + private Long permCodeId; + + /** + * 权限Id。 + */ + @TableField(value = "perm_id") + private Long permId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermModule.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermModule.java new file mode 100644 index 00000000..d80f38bb --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermModule.java @@ -0,0 +1,81 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.util.*; + +/** + * 权限模块实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_perm_module") +public class SysPermModule { + + /** + * 权限模块Id。 + */ + @TableId(value = "module_id") + private Long moduleId; + + /** + * 上级权限模块Id。 + */ + @TableField(value = "parent_id") + private Long parentId; + + /** + * 权限模块名称。 + */ + @TableField(value = "module_name") + private String moduleName; + + /** + * 权限模块类型(0: 普通模块 1: Controller模块)。 + */ + @TableField(value = "module_type") + private Integer moduleType; + + /** + * 权限模块在当前层级下的顺序,由小到大。 + */ + @TableField(value = "show_order") + private Integer showOrder; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + @TableField(exist = false) + private List sysPermList; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermWhitelist.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermWhitelist.java new file mode 100644 index 00000000..1cccff3b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPermWhitelist.java @@ -0,0 +1,33 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 白名单实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_perm_whitelist") +public class SysPermWhitelist { + + /** + * 权限资源的URL。 + */ + @TableId(value = "perm_url") + private String permUrl; + + /** + * 权限资源所属模块名字(通常是Controller的名字)。 + */ + @TableField(value = "module_name") + private String moduleName; + + /** + * 权限的名称。 + */ + @TableField(value = "perm_name") + private String permName; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPost.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPost.java new file mode 100644 index 00000000..e87190a9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysPost.java @@ -0,0 +1,104 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.webadmin.upms.vo.SysPostVo; +import lombok.Data; +import org.mapstruct.*; +import org.mapstruct.factory.Mappers; + +import java.util.Date; + +/** + * 岗位实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_post") +public class SysPost { + + /** + * 岗位Id。 + */ + @TableId(value = "post_id") + private Long postId; + + /** + * 岗位名称。 + */ + @TableField(value = "post_name") + private String postName; + + /** + * 岗位层级,数值越小级别越高。 + */ + private Integer level; + + /** + * 是否领导岗位。 + */ + @TableField(value = "leader_post") + private Boolean leaderPost; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + /** + * postId 的多对多关联表数据对象。 + */ + @TableField(exist = false) + private SysDeptPost sysDeptPost; + + @Mapper + public interface SysPostModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param sysPostVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "sysDeptPost", expression = "java(mapToBean(sysPostVo.getSysDeptPost(), com.flow.demo.webadmin.upms.model.SysDeptPost.class))") + @Override + SysPost toModel(SysPostVo sysPostVo); + /** + * 转换实体对象到VO对象。 + * + * @param sysPost 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "sysDeptPost", expression = "java(beanToMap(sysPost.getSysDeptPost(), false))") + @Override + SysPostVo fromModel(SysPost sysPost); + } + public static final SysPostModelMapper INSTANCE = Mappers.getMapper(SysPostModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysRole.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysRole.java new file mode 100644 index 00000000..4f4af670 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysRole.java @@ -0,0 +1,96 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationManyToMany; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.webadmin.upms.vo.SysRoleVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.*; + +/** + * 角色实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_role") +public class SysRole { + + /** + * 角色Id。 + */ + @TableId(value = "role_id") + private Long roleId; + + /** + * 角色名称。 + */ + @TableField(value = "role_name") + private String roleName; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + @RelationManyToMany( + relationMapperName = "sysRoleMenuMapper", + relationMasterIdField = "roleId", + relationModelClass = SysRoleMenu.class) + @TableField(exist = false) + private List sysRoleMenuList; + + @Mapper + public interface SysRoleModelMapper extends BaseModelMapper { + /** + * 转换VO对象到实体对象。 + * + * @param sysRoleVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "sysRoleMenuList", expression = "java(mapToBean(sysRoleVo.getSysRoleMenuList(), com.flow.demo.webadmin.upms.model.SysRoleMenu.class))") + @Override + SysRole toModel(SysRoleVo sysRoleVo); + /** + * 转换实体对象到VO对象。 + * + * @param sysRole 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "sysRoleMenuList", expression = "java(beanToMap(sysRole.getSysRoleMenuList(), false))") + @Override + SysRoleVo fromModel(SysRole sysRole); + } + public static final SysRoleModelMapper INSTANCE = Mappers.getMapper(SysRole.SysRoleModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysRoleMenu.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysRoleMenu.java new file mode 100644 index 00000000..b094e37a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysRoleMenu.java @@ -0,0 +1,27 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 角色菜单实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_role_menu") +public class SysRoleMenu { + + /** + * 角色Id。 + */ + @TableField(value = "role_id") + private Long roleId; + + /** + * 菜单Id。 + */ + @TableField(value = "menu_id") + private Long menuId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUser.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUser.java new file mode 100644 index 00000000..2fb16f3f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUser.java @@ -0,0 +1,196 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.webadmin.upms.model.constant.SysUserType; +import com.flow.demo.webadmin.upms.model.constant.SysUserStatus; +import com.flow.demo.common.core.annotation.RelationDict; +import com.flow.demo.common.core.annotation.RelationConstDict; +import com.flow.demo.common.core.annotation.RelationManyToMany; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.webadmin.upms.vo.SysUserVo; +import lombok.Data; +import org.mapstruct.*; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.Map; +import java.util.List; + +/** + * SysUser实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_user") +public class SysUser { + + /** + * 用户Id。 + */ + @TableId(value = "user_id") + private Long userId; + + /** + * 登录用户名。 + */ + @TableField(value = "login_name") + private String loginName; + + /** + * 用户密码。 + */ + private String password; + + /** + * 用户显示名称。 + */ + @TableField(value = "show_name") + private String showName; + + /** + * 用户部门Id。 + */ + @TableField(value = "dept_id") + private Long deptId; + + /** + * 用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)。 + */ + @TableField(value = "user_type") + private Integer userType; + + /** + * 用户头像的Url。 + */ + @TableField(value = "head_image_url") + private String headImageUrl; + + /** + * 用户状态(0: 正常 1: 锁定)。 + */ + @TableField(value = "user_status") + private Integer userStatus; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * createTime 范围过滤起始值(>=)。 + */ + @TableField(exist = false) + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + @TableField(exist = false) + private String createTimeEnd; + + /** + * 多对多用户部门岗位数据集合。 + */ + @RelationManyToMany( + relationMapperName = "sysUserPostMapper", + relationMasterIdField = "userId", + relationModelClass = SysUserPost.class) + @TableField(exist = false) + private List sysUserPostList; + + /** + * 多对多用户角色数据集合。 + */ + @RelationManyToMany( + relationMapperName = "sysUserRoleMapper", + relationMasterIdField = "userId", + relationModelClass = SysUserRole.class) + @TableField(exist = false) + private List sysUserRoleList; + + /** + * 多对多用户数据权限数据集合。 + */ + @RelationManyToMany( + relationMapperName = "sysDataPermUserMapper", + relationMasterIdField = "userId", + relationModelClass = SysDataPermUser.class) + @TableField(exist = false) + private List sysDataPermUserList; + + @RelationDict( + masterIdField = "deptId", + slaveServiceName = "sysDeptService", + slaveModelClass = SysDept.class, + slaveIdField = "deptId", + slaveNameField = "deptName") + @TableField(exist = false) + private Map deptIdDictMap; + + @RelationConstDict( + masterIdField = "userType", + constantDictClass = SysUserType.class) + @TableField(exist = false) + private Map userTypeDictMap; + + @RelationConstDict( + masterIdField = "userStatus", + constantDictClass = SysUserStatus.class) + @TableField(exist = false) + private Map userStatusDictMap; + + @Mapper + public interface SysUserModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param sysUserVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "sysUserRoleList", expression = "java(mapToBean(sysUserVo.getSysUserRoleList(), com.flow.demo.webadmin.upms.model.SysUserRole.class))") + @Mapping(target = "sysUserPostList", expression = "java(mapToBean(sysUserVo.getSysUserPostList(), com.flow.demo.webadmin.upms.model.SysUserPost.class))") + @Mapping(target = "sysDataPermUserList", expression = "java(mapToBean(sysUserVo.getSysDataPermUserList(), com.flow.demo.webadmin.upms.model.SysDataPermUser.class))") + @Override + SysUser toModel(SysUserVo sysUserVo); + /** + * 转换实体对象到VO对象。 + * + * @param sysUser 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "sysUserRoleList", expression = "java(beanToMap(sysUser.getSysUserRoleList(), false))") + @Mapping(target = "sysUserPostList", expression = "java(beanToMap(sysUser.getSysUserPostList(), false))") + @Mapping(target = "sysDataPermUserList", expression = "java(beanToMap(sysUser.getSysDataPermUserList(), false))") + @Override + SysUserVo fromModel(SysUser sysUser); + } + public static final SysUserModelMapper INSTANCE = Mappers.getMapper(SysUserModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUserPost.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUserPost.java new file mode 100644 index 00000000..babc5814 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUserPost.java @@ -0,0 +1,33 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 用户岗位多对多关系实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_user_post") +public class SysUserPost { + + /** + * 用户Id。 + */ + @TableField(value = "user_id") + private Long userId; + + /** + * 部门岗位Id。 + */ + @TableField(value = "dept_post_id") + private Long deptPostId; + + /** + * 岗位Id。 + */ + @TableField(value = "post_id") + private Long postId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUserRole.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUserRole.java new file mode 100644 index 00000000..04718de3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/SysUserRole.java @@ -0,0 +1,27 @@ +package com.flow.demo.webadmin.upms.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 用户角色实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_sys_user_role") +public class SysUserRole { + + /** + * 用户Id。 + */ + @TableField(value = "user_id") + private Long userId; + + /** + * 角色Id。 + */ + @TableField(value = "role_id") + private Long roleId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysMenuType.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysMenuType.java new file mode 100644 index 00000000..b46d11f8 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysMenuType.java @@ -0,0 +1,54 @@ +package com.flow.demo.webadmin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 菜单类型常量对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class SysMenuType { + + /** + * 目录菜单。 + */ + public static final int TYPE_DIRECTORY = 0; + /** + * 普通菜单。 + */ + public static final int TYPE_MENU = 1; + /** + * 表单片段类型。 + */ + public static final int TYPE_UI_FRAGMENT = 2; + /** + * 按钮类型。 + */ + public static final int TYPE_BUTTON = 3; + + private static final Map DICT_MAP = new HashMap<>(4); + static { + DICT_MAP.put(TYPE_DIRECTORY, "目录菜单"); + DICT_MAP.put(TYPE_MENU, "普通菜单"); + DICT_MAP.put(TYPE_UI_FRAGMENT, "表单片段类型"); + DICT_MAP.put(TYPE_BUTTON, "按钮类型"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysMenuType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysOnlineMenuPermType.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysOnlineMenuPermType.java new file mode 100644 index 00000000..b026e64f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysOnlineMenuPermType.java @@ -0,0 +1,44 @@ +package com.flow.demo.webadmin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 菜单关联在线表单的控制权限类型。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class SysOnlineMenuPermType { + + /** + * 查看。 + */ + public static final int TYPE_VIEW = 0; + /** + * 编辑。 + */ + public static final int TYPE_EDIT = 1; + + private static final Map DICT_MAP = new HashMap<>(4); + static { + DICT_MAP.put(TYPE_VIEW, "查看"); + DICT_MAP.put(TYPE_EDIT, "编辑"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysOnlineMenuPermType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysPermCodeType.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysPermCodeType.java new file mode 100644 index 00000000..d17b8b6d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysPermCodeType.java @@ -0,0 +1,49 @@ +package com.flow.demo.webadmin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 权限字类型常量对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class SysPermCodeType { + + /** + * 表单权限字。 + */ + public static final int TYPE_FORM = 0; + /** + * 表单片段布局权限字。 + */ + public static final int TYPE_FRAGMENT = 1; + /** + * 操作权限字。 + */ + public static final int TYPE_OPERATION = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(TYPE_FORM, "表单权限字"); + DICT_MAP.put(TYPE_FRAGMENT, "表单片段布局权限字"); + DICT_MAP.put(TYPE_OPERATION, "操作权限字"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysPermCodeType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysPermModuleType.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysPermModuleType.java new file mode 100644 index 00000000..68eed76e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysPermModuleType.java @@ -0,0 +1,44 @@ +package com.flow.demo.webadmin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 权限资源模块类型常量对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class SysPermModuleType { + + /** + * 普通模块。 + */ + public static final int TYPE_NORMAL = 0; + /** + * controller接口模块。 + */ + public static final int TYPE_CONTROLLER = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(TYPE_NORMAL, "普通模块"); + DICT_MAP.put(TYPE_CONTROLLER, "controller接口模块"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysPermModuleType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysUserStatus.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysUserStatus.java new file mode 100644 index 00000000..f08e455f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysUserStatus.java @@ -0,0 +1,44 @@ +package com.flow.demo.webadmin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 用户状态常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class SysUserStatus { + + /** + * 正常状态。 + */ + public static final int STATUS_NORMAL = 0; + /** + * 锁定状态。 + */ + public static final int STATUS_LOCKED = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(STATUS_NORMAL, "正常状态"); + DICT_MAP.put(STATUS_LOCKED, "锁定状态"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysUserStatus() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysUserType.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysUserType.java new file mode 100644 index 00000000..580f492e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/model/constant/SysUserType.java @@ -0,0 +1,49 @@ +package com.flow.demo.webadmin.upms.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 用户类型常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class SysUserType { + + /** + * 管理员。 + */ + public static final int TYPE_ADMIN = 0; + /** + * 系统操作员。 + */ + public static final int TYPE_SYSTEM = 1; + /** + * 普通操作员。 + */ + public static final int TYPE_OPERATOR = 2; + + private static final Map DICT_MAP = new HashMap<>(3); + static { + DICT_MAP.put(TYPE_ADMIN, "管理员"); + DICT_MAP.put(TYPE_SYSTEM, "系统操作员"); + DICT_MAP.put(TYPE_OPERATOR, "普通操作员"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysUserType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysDataPermService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysDataPermService.java new file mode 100644 index 00000000..3012c5e9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysDataPermService.java @@ -0,0 +1,104 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.webadmin.upms.model.*; + +import java.util.*; + +/** + * 数据权限数据服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysDataPermService extends IBaseService { + + /** + * 保存新增的数据权限对象。 + * + * @param dataPerm 新增的数据权限对象。 + * @param deptIdSet 关联的部门Id列表。 + * @return 新增后的数据权限对象。 + */ + SysDataPerm saveNew(SysDataPerm dataPerm, Set deptIdSet); + + /** + * 更新数据权限对象。 + * + * @param dataPerm 更新的数据权限对象。 + * @param originalDataPerm 原有的数据权限对象。 + * @param deptIdSet 关联的部门Id列表。 + * @return 更新成功返回true,否则false。 + */ + boolean update(SysDataPerm dataPerm, SysDataPerm originalDataPerm, Set deptIdSet); + + /** + * 删除指定数据权限。 + * + * @param dataPermId 数据权限主键Id。 + * @return 删除成功返回true,否则false。 + */ + boolean remove(Long dataPermId); + + /** + * 获取数据权限列表。 + * + * @param filter 数据权限过滤对象。 + * @param orderBy 排序参数。 + * @return 数据权限查询列表。 + */ + List getSysDataPermList(SysDataPerm filter, String orderBy); + + /** + * 将指定用户的指定会话的数据权限集合存入缓存。 + * + * @param sessionId 会话Id。 + * @param userId 用户主键Id。 + * @param deptId 用户所属部门主键Id。 + * @return 查询并缓存后的数据权限集合。返回格式为,Map。 + */ + Map putDataPermCache(String sessionId, Long userId, Long deptId); + + /** + * 将指定会话的数据权限集合从缓存中移除。 + * + * @param sessionId 会话Id。 + */ + void removeDataPermCache(String sessionId); + + /** + * 获取指定用户Id的数据权限列表。并基于权限规则类型进行了一级分组。 + * + * @param userId 指定的用户Id。 + * @param deptId 用户所属部门主键Id。 + * @return 合并优化后的数据权限列表。返回格式为,Map。 + */ + Map getSysDataPermListByUserId(Long userId, Long deptId); + + /** + * 添加用户和数据权限之间的多对多关联关系。 + * + * @param dataPermId 数据权限Id。 + * @param userIdSet 关联的用户Id列表。 + */ + void addDataPermUserList(Long dataPermId, Set userIdSet); + + /** + * 移除用户和数据权限之间的多对多关联关系。 + * + * @param dataPermId 数据权限主键Id。 + * @param userId 用户主键Id。 + * @return true移除成功,否则false。 + */ + boolean removeDataPermUser(Long dataPermId, Long userId); + + /** + * 验证数据权限对象关联菜单数据是否都合法。 + * + * @param dataPerm 数据权限关对象。 + * @param deptIdListString 与数据权限关联的部门Id列表。 + * @return 验证结果。 + */ + CallResult verifyRelatedData(SysDataPerm dataPerm, String deptIdListString); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysDeptService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysDeptService.java new file mode 100644 index 00000000..bfdae383 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysDeptService.java @@ -0,0 +1,144 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.webadmin.upms.model.*; +import com.flow.demo.common.core.base.service.IBaseService; + +import java.util.*; + +/** + * 部门管理数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysDeptService extends IBaseService { + + /** + * 保存新增的部门对象。 + * + * @param sysDept 新增的部门对象。 + * @param parentSysDept 上级部门对象。 + * @return 新增后的部门对象。 + */ + SysDept saveNew(SysDept sysDept, SysDept parentSysDept); + + /** + * 更新部门对象。 + * + * @param sysDept 更新的部门对象。 + * @param originalSysDept 原有的部门对象。 + * @return 更新成功返回true,否则false。 + */ + boolean update(SysDept sysDept, SysDept originalSysDept); + + /** + * 删除指定数据。 + * + * @param deptId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long deptId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSysDeptListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getSysDeptList(SysDept filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getSysDeptList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getSysDeptListWithRelation(SysDept filter, String orderBy); + + /** + * 判断指定对象是否包含下级对象。 + * + * @param deptId 主键Id。 + * @return 存在返回true,否则false。 + */ + boolean hasChildren(Long deptId); + + /** + * 判断指定部门Id是否包含用户对象。 + * + * @param deptId 部门主键Id。 + * @return 存在返回true,否则false。 + */ + boolean hasChildrenUser(Long deptId); + + /** + * 批量添加多对多关联关系。 + * + * @param sysDeptPostList 多对多关联表对象集合。 + * @param deptId 主表Id。 + */ + void addSysDeptPostList(List sysDeptPostList, Long deptId); + + /** + * 更新中间表数据。 + * + * @param sysDeptPost 中间表对象。 + * @return 更新成功与否。 + */ + boolean updateSysDeptPost(SysDeptPost sysDeptPost); + + /** + * 移除单条多对多关系。 + * + * @param deptId 主表Id。 + * @param postId 从表Id。 + * @return 成功返回true,否则false。 + */ + boolean removeSysDeptPost(Long deptId, Long postId); + + /** + * 获取中间表数据。 + * + * @param deptId 主表Id。 + * @param postId 从表Id。 + * @return 中间表对象。 + */ + SysDeptPost getSysDeptPost(Long deptId, Long postId); + + /** + * 根据部门岗位Id获取部门岗位关联对象。 + * + * @param deptPostId 部门岗位Id。 + * @return 部门岗位对象。 + */ + SysDeptPost getSysDeptPost(Long deptPostId); + + /** + * 获取指定部门Id的部门岗位多对多关联数据列表,以及关联的部门和岗位数据。 + * + * @param deptId 部门Id。如果参数为空则返回全部数据。 + * @return 部门岗位多对多数量列表。 + */ + List> getSysDeptPostListWithRelationByDeptId(Long deptId); + + /** + * 根据部门Id获取该部门领导岗位的部门岗位Id集合。 + * + * @param deptId 部门Id。 + * @return 部门领导岗位的部门岗位Id集合。 + */ + List getLeaderDeptPostIdList(Long deptId); + + /** + * 根据部门Id获取上级部门领导岗位的部门岗位Id集合。 + * + * @param deptId 部门Id。 + * @return 上级部门领导岗位的部门岗位Id集合。 + */ + List getUpLeaderDeptPostIdList(Long deptId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysMenuService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysMenuService.java new file mode 100644 index 00000000..c320452f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysMenuService.java @@ -0,0 +1,111 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.webadmin.upms.model.SysMenu; + +import java.util.*; + +/** + * 菜单数据服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysMenuService extends IBaseService { + + /** + * 保存新增的菜单对象。 + * + * @param sysMenu 新增的菜单对象。 + * @param permCodeIdSet 权限字Id列表。 + * @return 新增后的菜单对象。 + */ + SysMenu saveNew(SysMenu sysMenu, Set permCodeIdSet); + + /** + * 更新菜单对象。 + * + * @param sysMenu 更新的菜单对象。 + * @param originalSysMenu 原有的菜单对象。 + * @param permCodeIdSet 权限字Id列表。 + * @return 更新成功返回true,否则false。 + */ + boolean update(SysMenu sysMenu, SysMenu originalSysMenu, Set permCodeIdSet); + + /** + * 删除指定的菜单。 + * + * @param menu 菜单对象。 + * @return 删除成功返回true,否则false。 + */ + boolean remove(SysMenu menu); + + /** + * 获取全部菜单列表。 + * + * @return 全部菜单列表。 + */ + Collection getAllMenuList(); + + /** + * 获取指定用户Id的菜单列表,已去重。 + * + * @param userId 用户主键Id。 + * @return 用户关联的菜单列表。 + */ + Collection getMenuListByUserId(Long userId); + + /** + * 判断当前菜单是否存在子菜单。 + * + * @param menuId 菜单主键Id。 + * @return 存在返回true,否则false。 + */ + boolean hasChildren(Long menuId); + + /** + * 验证菜单对象关联的数据是否都合法。 + * + * @param sysMenu 当前操作的对象。 + * @param originalSysMenu 原有对象。 + * @param permCodeIdListString 逗号分隔的权限Id列表。 + * @return 验证结果。 + */ + CallResult verifyRelatedData(SysMenu sysMenu, SysMenu originalSysMenu, String permCodeIdListString); + + /** + * 查询菜单的权限资源地址列表。同时返回详细的分配路径。 + * + * @param menuId 菜单Id。 + * @param url 权限资源地址过滤条件。 + * @return 包含从菜单到权限资源的权限分配路径信息的查询结果列表。 + */ + List> getSysPermListWithDetail(Long menuId, String url); + + /** + * 查询菜单的用户列表。同时返回详细的分配路径。 + * + * @param menuId 菜单Id。 + * @param loginName 登录名。 + * @return 包含从菜单到用户的完整权限分配路径信息的查询结果列表。 + */ + List> getSysUserListWithDetail(Long menuId, String loginName); + + /** + * 获取指定类型的所有在线表单的菜单。 + * + * @param menuType 菜单类型,NULL则返回全部类型。 + * @return 在线表单关联的菜单列表。 + */ + List getAllOnlineMenuList(Integer menuType); + + /** + * 获取当前用户有权访问的在线表单菜单,仅返回类型为BUTTON的菜单。 + * + * @param userId 指定的用户。 + * @param menuType 菜单类型,NULL则返回全部类型。 + * @return 在线表单关联的菜单列表。 + */ + List getOnlineMenuListByUserId(Long userId, Integer menuType); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermCodeService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermCodeService.java new file mode 100644 index 00000000..2863fea0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermCodeService.java @@ -0,0 +1,94 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.webadmin.upms.model.SysPermCode; + +import java.util.*; + +/** + * 权限字数据服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPermCodeService extends IBaseService { + + /** + * 获取指定用户的权限字列表,已去重。 + * + * @param userId 用户主键Id。 + * @return 用户关联的权限字列表。 + */ + Collection getPermCodeListByUserId(Long userId); + + /** + * 获取所有权限字数据列表,已去重。 + * + * @return 全部权限字列表。 + */ + Collection getAllPermCodeList(); + + /** + * 保存新增的权限字对象。 + * + * @param sysPermCode 新增的权限字对象。 + * @param permIdSet 权限资源Id列表。 + * @return 新增后的权限字对象。 + */ + SysPermCode saveNew(SysPermCode sysPermCode, Set permIdSet); + + /** + * 更新权限字对象。 + * + * @param sysPermCode 更新的权限字对象。 + * @param originalSysPermCode 原有的权限字对象。 + * @param permIdSet 权限资源Id列表。 + * @return 更新成功返回true,否则false。 + */ + boolean update(SysPermCode sysPermCode, SysPermCode originalSysPermCode, Set permIdSet); + + /** + * 删除指定的权限字。 + * + * @param permCodeId 权限字主键Id。 + * @return 删除成功返回true,否则false。 + */ + boolean remove(Long permCodeId); + + /** + * 判断当前权限字是否存在下级权限字对象。 + * + * @param permCodeId 权限字主键Id。 + * @return 存在返回true,否则false。 + */ + boolean hasChildren(Long permCodeId); + + /** + * 验证权限字对象关联的数据是否都合法。 + * + * @param sysPermCode 当前操作的对象。 + * @param originalSysPermCode 原有对象。 + * @param permIdListString 逗号分隔的权限资源Id列表。 + * @return 验证结果。 + */ + CallResult verifyRelatedData(SysPermCode sysPermCode, SysPermCode originalSysPermCode, String permIdListString); + + /** + * 查询权限字的用户列表。同时返回详细的分配路径。 + * + * @param permCodeId 权限字Id。 + * @param loginName 登录名。 + * @return 包含从权限字到用户的完整权限分配路径信息的查询结果列表。 + */ + List> getSysUserListWithDetail(Long permCodeId, String loginName); + + /** + * 查询权限字的角色列表。同时返回详细的分配路径。 + * + * @param permCodeId 权限字Id。 + * @param roleName 角色名。 + * @return 包含从权限字到角色的权限分配路径信息的查询结果列表。 + */ + List> getSysRoleListWithDetail(Long permCodeId, String roleName); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermModuleService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermModuleService.java new file mode 100644 index 00000000..ebd3ff49 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermModuleService.java @@ -0,0 +1,63 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.webadmin.upms.model.SysPermModule; + +import java.util.*; + +/** + * 权限资源模块数据服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPermModuleService extends IBaseService { + + /** + * 保存新增的权限资源模块对象。 + * + * @param sysPermModule 新增的权限资源模块对象。 + * @return 新增后的权限资源模块对象。 + */ + SysPermModule saveNew(SysPermModule sysPermModule); + + /** + * 更新权限资源模块对象。 + * + * @param sysPermModule 更新的权限资源模块对象。 + * @param originalSysPermModule 原有的权限资源模块对象。 + * @return 更新成功返回true,否则false + */ + boolean update(SysPermModule sysPermModule, SysPermModule originalSysPermModule); + + /** + * 删除指定的权限资源模块。 + * + * @param moduleId 权限资源模块主键Id。 + * @return 删除成功返回true,否则false。 + */ + boolean remove(Long moduleId); + + /** + * 获取权限模块资源及其关联的权限资源列表。 + * + * @return 权限资源模块及其关联的权限资源列表。 + */ + List getPermModuleAndPermList(); + + /** + * 判断是否存在下级权限资源模块。 + * + * @param moduleId 权限资源模块主键Id。 + * @return 存在返回true,否则false。 + */ + boolean hasChildren(Long moduleId); + + /** + * 判断是否存在权限数据。 + * + * @param moduleId 权限资源模块主键Id。 + * @return 存在返回true,否则false。 + */ + boolean hasModulePerms(Long moduleId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermService.java new file mode 100644 index 00000000..a863f729 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermService.java @@ -0,0 +1,117 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.webadmin.upms.model.SysPerm; + +import java.util.*; + +/** + * 权限资源数据服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPermService extends IBaseService { + + /** + * 保存新增的权限资源对象。 + * + * @param perm 新增的权限资源对象。 + * @return 新增后的权限资源对象。 + */ + SysPerm saveNew(SysPerm perm); + + /** + * 更新权限资源对象。 + * + * @param perm 更新的权限资源对象。 + * @param originalPerm 原有的权限资源对象。 + * @return 更新成功返回true,否则false。 + */ + boolean update(SysPerm perm, SysPerm originalPerm); + + /** + * 删除权限资源。 + * + * @param permId 权限资源主键Id。 + * @return 删除成功返回true,否则false。 + */ + boolean remove(Long permId); + + /** + * 获取权限数据列表。 + * + * @param sysPermFilter 过滤对象。 + * @return 权限列表。 + */ + List getPermListWithRelation(SysPerm sysPermFilter); + + /** + * 将指定用户的指定会话的权限集合存入缓存。 + * + * @param sessionId 会话Id。 + * @param userId 用户主键Id。 + * @return 查询并缓存后的权限集合。 + */ + Collection putUserSysPermCache(String sessionId, Long userId); + + /** + * 把在线表单的权限URL集合,存放到权限URL的缓存中。 + * + * @param sessionId 会话Id。 + * @param permUrlSet URL集合。 + */ + void putOnlinePermToCache(String sessionId, Set permUrlSet); + + /** + * 将指定会话的权限集合从缓存中移除。 + * + * @param sessionId 会话Id。 + */ + void removeUserSysPermCache(String sessionId); + + /** + * 获取与指定用户关联的权限资源列表,已去重。 + * + * @param userId 关联的用户主键Id。 + * @return 与指定用户Id关联的权限资源列表。 + */ + Collection getPermListByUserId(Long userId); + + /** + * 验证权限资源对象关联的数据是否都合法。 + * + * @param sysPerm 当前操作的对象。 + * @param originalSysPerm 原有对象。 + * @return 验证结果。 + */ + CallResult verifyRelatedData(SysPerm sysPerm, SysPerm originalSysPerm); + + /** + * 查询权限资源地址的用户列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param loginName 登录名。 + * @return 包含从权限资源到用户的完整权限分配路径信息的查询结果列表。 + */ + List> getSysUserListWithDetail(Long permId, String loginName); + + /** + * 查询权限资源地址的角色列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param roleName 角色名。 + * @return 包含从权限资源到角色的权限分配路径信息的查询结果列表。 + */ + List> getSysRoleListWithDetail(Long permId, String roleName); + + /** + * 查询权限资源地址的菜单列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param menuName 菜单名。 + * @return 包含从权限资源到菜单的权限分配路径信息的查询结果列表。 + */ + List> getSysMenuListWithDetail(Long permId, String menuName); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermWhitelistService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermWhitelistService.java new file mode 100644 index 00000000..3ff3d340 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPermWhitelistService.java @@ -0,0 +1,23 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.webadmin.upms.model.SysPermWhitelist; + +import java.util.List; + +/** + * 权限资源白名单数据服务接口。 + * 白名单中的权限资源,可以不受权限控制,任何用户皆可访问,一般用于常用的字典数据列表接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPermWhitelistService extends IBaseService { + + /** + * 获取白名单权限资源的列表。 + * + * @return 白名单权限资源地址列表。 + */ + List getWhitelistPermList(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPostService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPostService.java new file mode 100644 index 00000000..ee7bd497 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysPostService.java @@ -0,0 +1,99 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.webadmin.upms.model.SysPost; +import com.flow.demo.webadmin.upms.model.SysUserPost; + +import java.util.*; + +/** + * 岗位管理数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysPostService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param sysPost 新增对象。 + * @return 返回新增对象。 + */ + SysPost saveNew(SysPost sysPost); + + /** + * 更新数据对象。 + * + * @param sysPost 更新的对象。 + * @param originalSysPost 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(SysPost sysPost, SysPost originalSysPost); + + /** + * 删除指定数据。 + * + * @param postId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long postId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSysPostListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getSysPostList(SysPost filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getSysPostList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getSysPostListWithRelation(SysPost filter, String orderBy); + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param deptId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getNotInSysPostListByDeptId(Long deptId, SysPost filter, String orderBy); + + /** + * 获取指定部门的岗位列表。 + * + * @param deptId 部门Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getSysPostListByDeptId(Long deptId, SysPost filter, String orderBy); + + /** + * 获取指定用户的用户岗位多对多关联数据列表。 + * + * @param userId 用户Id。 + * @return 用户岗位多对多关联数据列表。 + */ + List getSysUserPostListByUserId(Long userId); + + /** + * 判断指定的部门岗位Id集合是否都属于指定的部门Id。 + * + * @param deptPostIdSet 部门岗位Id集合。 + * @param deptId 部门Id。 + * @return 全部是返回true,否则false。 + */ + boolean existAllPrimaryKeys(Set deptPostIdSet, Long deptId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysRoleService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysRoleService.java new file mode 100644 index 00000000..6077e985 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysRoleService.java @@ -0,0 +1,97 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.webadmin.upms.model.SysRole; +import com.flow.demo.webadmin.upms.model.SysUserRole; + +import java.util.*; + +/** + * 角色数据服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysRoleService extends IBaseService { + + /** + * 保存新增的角色对象。 + * + * @param role 新增的角色对象。 + * @param menuIdSet 菜单Id列表。 + * @return 新增后的角色对象。 + */ + SysRole saveNew(SysRole role, Set menuIdSet); + + /** + * 更新角色对象。 + * + * @param role 更新的角色对象。 + * @param originalRole 原有的角色对象。 + * @param menuIdSet 菜单Id列表。 + * @return 更新成功返回true,否则false。 + */ + boolean update(SysRole role, SysRole originalRole, Set menuIdSet); + + /** + * 删除指定角色。 + * + * @param roleId 角色主键Id。 + * @return 删除成功返回true,否则false。 + */ + boolean remove(Long roleId); + + /** + * 获取角色列表。 + * + * @param filter 角色过滤对象。 + * @param orderBy 排序参数。 + * @return 角色列表。 + */ + List getSysRoleList(SysRole filter, String orderBy); + + /** + * 批量新增用户角色关联。 + * + * @param userRoleList 用户角色关系数据列表。 + */ + void addUserRoleList(List userRoleList); + + /** + * 移除指定用户和指定角色的关联关系。 + * + * @param roleId 角色主键Id。 + * @param userId 用户主键Id。 + * @return 移除成功返回true,否则false。 + */ + boolean removeUserRole(Long roleId, Long userId); + + /** + * 验证角色对象关联的数据是否都合法。 + * + * @param sysRole 当前操作的对象。 + * @param originalSysRole 原有对象。 + * @param menuIdListString 逗号分隔的menuId列表。 + * @return 验证结果。 + */ + CallResult verifyRelatedData(SysRole sysRole, SysRole originalSysRole, String menuIdListString); + + /** + * 查询角色的权限资源地址列表。同时返回详细的分配路径。 + * + * @param roleId 角色Id。 + * @param url url过滤条件。 + * @return 包含从角色到权限资源的完整权限分配路径信息的查询结果列表。 + */ + List> getSysPermListWithDetail(Long roleId, String url); + + /** + * 查询角色的权限字列表。同时返回详细的分配路径。 + * + * @param roleId 角色Id。 + * @param permCode 权限字名称过滤条件。 + * @return 包含从角色到权限字的权限分配路径信息的查询结果列表。 + */ + List> getSysPermCodeListWithDetail(Long roleId, String permCode); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysUserService.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysUserService.java new file mode 100644 index 00000000..503d46ef --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/SysUserService.java @@ -0,0 +1,164 @@ +package com.flow.demo.webadmin.upms.service; + +import com.flow.demo.webadmin.upms.model.*; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.base.service.IBaseService; + +import java.util.*; + +/** + * 用户管理数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysUserService extends IBaseService { + + /** + * 获取指定登录名的用户对象。 + * + * @param loginName 指定登录用户名。 + * @return 用户对象。 + */ + SysUser getSysUserByLoginName(String loginName); + + /** + * 保存新增的用户对象。 + * + * @param user 新增的用户对象。 + * @param roleIdSet 用户角色Id集合。 + * @param deptPostIdSet 部门岗位Id集合。 + * @param dataPermIdSet 数据权限Id集合。 + * @return 新增后的用户对象。 + */ + SysUser saveNew(SysUser user, Set roleIdSet, Set deptPostIdSet, Set dataPermIdSet); + + /** + * 更新用户对象。 + * + * @param user 更新的用户对象。 + * @param originalUser 原有的用户对象。 + * @param roleIdSet 用户角色Id列表。 + * @param deptPostIdSet 部门岗位Id集合。 + * @param dataPermIdSet 数据权限Id集合。 + * @return 更新成功返回true,否则false。 + */ + boolean update(SysUser user, SysUser originalUser, Set roleIdSet, Set deptPostIdSet, Set dataPermIdSet); + + /** + * 修改用户密码。 + * @param userId 用户主键Id。 + * @param newPass 新密码。 + * @return 成功返回true,否则false。 + */ + boolean changePassword(Long userId, String newPass); + + /** + * 删除指定数据。 + * + * @param userId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long userId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSysUserListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getSysUserList(SysUser filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getSysUserList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getSysUserListWithRelation(SysUser filter, String orderBy); + + /** + * 获取指定角色的用户列表。 + * + * @param roleId 角色主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + List getSysUserListByRoleId(Long roleId, SysUser filter, String orderBy); + + /** + * 获取不属于指定角色的用户列表。 + * + * @param roleId 角色主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + List getNotInSysUserListByRoleId(Long roleId, SysUser filter, String orderBy); + + /** + * 获取指定数据权限的用户列表。 + * + * @param dataPermId 数据权限主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + List getSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy); + + /** + * 获取不属于指定数据权限的用户列表。 + * + * @param dataPermId 数据权限主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + List getNotInSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy); + + /** + * 查询用户的权限资源地址列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param url url过滤条件。 + * @return 包含从用户到权限资源的完整权限分配路径信息的查询结果列表。 + */ + List> getSysPermListWithDetail(Long userId, String url); + + /** + * 查询用户的权限字列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param permCode 权限字名称过滤条件。 + * @return 包含从用户到权限字的权限分配路径信息的查询结果列表。 + */ + List> getSysPermCodeListWithDetail(Long userId, String permCode); + + /** + * 查询用户的菜单列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param menuName 菜单名称过滤条件。 + * @return 包含从用户到菜单的权限分配路径信息的查询结果列表。 + */ + List> getSysMenuListWithDetail(Long userId, String menuName); + + /** + * 验证用户对象关联的数据是否都合法。 + * + * @param sysUser 当前操作的对象。 + * @param originalSysUser 原有对象。 + * @param roleIds 逗号分隔的角色Id列表字符串。 + * @param deptPostIds 逗号分隔的部门岗位Id列表字符串。 + * @param dataPermIds 逗号分隔的数据权限Id列表字符串。 + * @return 验证结果。 + */ + CallResult verifyRelatedData( + SysUser sysUser, SysUser originalSysUser, String roleIds, String deptPostIds, String dataPermIds); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysDataPermServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysDataPermServiceImpl.java new file mode 100644 index 00000000..492c4203 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysDataPermServiceImpl.java @@ -0,0 +1,336 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.datafilter.constant.DataPermRuleType; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.RedisKeyUtil; +import com.flow.demo.webadmin.config.ApplicationConfig; +import com.flow.demo.webadmin.upms.dao.SysDataPermDeptMapper; +import com.flow.demo.webadmin.upms.dao.SysDataPermMapper; +import com.flow.demo.webadmin.upms.dao.SysDataPermUserMapper; +import com.flow.demo.webadmin.upms.model.*; +import com.flow.demo.webadmin.upms.service.SysDataPermService; +import com.flow.demo.webadmin.upms.service.SysDeptService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.collections4.CollectionUtils; +import org.redisson.api.RBucket; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 数据权限数据服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysDataPermService") +public class SysDataPermServiceImpl extends BaseService implements SysDataPermService { + + @Autowired + private SysDataPermMapper sysDataPermMapper; + @Autowired + private SysDataPermDeptMapper sysDataPermDeptMapper; + @Autowired + private SysDataPermUserMapper sysDataPermUserMapper; + @Autowired + private SysDeptService sysDeptService; + @Autowired + private RedissonClient redissonClient; + @Autowired + private ApplicationConfig applicationConfig; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysDataPermMapper; + } + + /** + * 保存新增的数据权限对象。 + * + * @param dataPerm 新增的数据权限对象。 + * @param deptIdSet 关联的部门Id列表。 + * @return 新增后的数据权限对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public SysDataPerm saveNew(SysDataPerm dataPerm, Set deptIdSet) { + dataPerm.setDataPermId(idGenerator.nextLongId()); + MyModelUtil.fillCommonsForInsert(dataPerm); + dataPerm.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysDataPermMapper.insert(dataPerm); + this.insertRelationData(dataPerm, deptIdSet); + return dataPerm; + } + + /** + * 更新数据权限对象。 + * + * @param dataPerm 更新的数据权限对象。 + * @param originalDataPerm 原有的数据权限对象。 + * @param deptIdSet 关联的部门Id列表。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(SysDataPerm dataPerm, SysDataPerm originalDataPerm, Set deptIdSet) { + MyModelUtil.fillCommonsForUpdate(dataPerm, originalDataPerm); + UpdateWrapper uw = this.createUpdateQueryForNullValue(dataPerm, dataPerm.getDataPermId()); + if (sysDataPermMapper.update(dataPerm, uw) != 1) { + return false; + } + SysDataPermDept dataPermDept = new SysDataPermDept(); + dataPermDept.setDataPermId(dataPerm.getDataPermId()); + sysDataPermDeptMapper.delete(new QueryWrapper<>(dataPermDept)); + this.insertRelationData(dataPerm, deptIdSet); + return true; + } + + /** + * 删除指定数据权限。 + * + * @param dataPermId 数据权限主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long dataPermId) { + if (sysDataPermMapper.deleteById(dataPermId) != 1) { + return false; + } + SysDataPermDept dataPermDept = new SysDataPermDept(); + dataPermDept.setDataPermId(dataPermId); + sysDataPermDeptMapper.delete(new QueryWrapper<>(dataPermDept)); + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + sysDataPermUserMapper.delete(new QueryWrapper<>(dataPermUser)); + return true; + } + + /** + * 获取数据权限列表。 + * + * @param filter 数据权限过滤对象。 + * @param orderBy 排序参数。 + * @return 数据权限查询列表。 + */ + @Override + public List getSysDataPermList(SysDataPerm filter, String orderBy) { + return sysDataPermMapper.getSysDataPermList(filter, orderBy); + } + + /** + * 将指定用户的指定会话的数据权限集合存入缓存。 + * + * @param sessionId 会话Id。 + * @param userId 用户主键Id。 + * @param deptId 用户所属部门主键Id。 + * @return 查询并缓存后的数据权限集合。返回格式为,Map。 + */ + @Override + public Map putDataPermCache(String sessionId, Long userId, Long deptId) { + Map dataPermMap = this.getSysDataPermListByUserId(userId, deptId); + if (dataPermMap.size() > 0) { + String dataPermSessionKey = RedisKeyUtil.makeSessionDataPermIdKey(sessionId); + RBucket bucket = redissonClient.getBucket(dataPermSessionKey); + bucket.set(JSON.toJSONString(dataPermMap), + applicationConfig.getSessionExpiredSeconds(), TimeUnit.SECONDS); + } + return dataPermMap; + } + + /** + * 将指定会话的数据权限集合从缓存中移除。 + * + * @param sessionId 会话Id。 + */ + @Override + public void removeDataPermCache(String sessionId) { + String sessionPermKey = RedisKeyUtil.makeSessionDataPermIdKey(sessionId); + redissonClient.getBucket(sessionPermKey).deleteAsync(); + } + + /** + * 获取指定用户Id的数据权限列表。并基于权限规则类型进行了一级分组。 + * + * @param userId 指定的用户Id。 + * @param deptId 用户所属部门主键Id。 + * @return 合并优化后的数据权限列表。返回格式为,Map。 + */ + @Override + public Map getSysDataPermListByUserId(Long userId, Long deptId) { + List dataPermList = sysDataPermMapper.getSysDataPermListByUserId(userId); + dataPermList.forEach(dataPerm -> { + if (CollectionUtils.isNotEmpty(dataPerm.getDataPermDeptList())) { + Set deptIdSet = dataPerm.getDataPermDeptList().stream() + .map(SysDataPermDept::getDeptId).collect(Collectors.toSet()); + dataPerm.setDeptIdListString(StringUtils.join(deptIdSet, ",")); + } + }); + // 为了更方便进行后续的合并优化处理,这里再基于规则类型进行分组。ruleMap的key是规则类型。 + Map> ruleMap = + dataPermList.stream().collect(Collectors.groupingBy(SysDataPerm::getRuleType)); + Map resultMap = new HashMap<>(ruleMap.size()); + // 如有有ALL存在,就可以直接退出了,没有必要在处理后续的规则了。 + if (ruleMap.containsKey(DataPermRuleType.TYPE_ALL)) { + resultMap.put(DataPermRuleType.TYPE_ALL, "null"); + return resultMap; + } + // 这里优先合并最复杂的多部门及子部门场景。 + String deptIds = processMultiDeptAndChildren(ruleMap, deptId); + if (deptIds != null) { + resultMap.put(DataPermRuleType.TYPE_MULTI_DEPT_AND_CHILD_DEPT, deptIds); + } + // 合并当前部门及子部门的优化 + if (ruleMap.get(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT) != null) { + // 需要与仅仅当前部门规则进行合并。 + ruleMap.remove(DataPermRuleType.TYPE_DEPT_ONLY); + resultMap.put(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT, "null"); + } + // 合并自定义部门了。 + deptIds = processMultiDept(ruleMap, deptId); + if (deptIds != null) { + resultMap.put(DataPermRuleType.TYPE_CUSTOM_DEPT_LIST, deptIds); + } + // 最后处理当前部门和当前用户。 + if (ruleMap.get(DataPermRuleType.TYPE_DEPT_ONLY) != null) { + resultMap.put(DataPermRuleType.TYPE_DEPT_ONLY, "null"); + } + if (ruleMap.get(DataPermRuleType.TYPE_USER_ONLY) != null) { + resultMap.put(DataPermRuleType.TYPE_USER_ONLY, "null"); + } + return resultMap; + } + + private String processMultiDeptAndChildren(Map> ruleMap, Long deptId) { + List parentDeptList = ruleMap.get(DataPermRuleType.TYPE_MULTI_DEPT_AND_CHILD_DEPT); + if (parentDeptList == null) { + return null; + } + Set deptIdSet = new HashSet<>(); + for (SysDataPerm parentDept : parentDeptList) { + deptIdSet.addAll(Arrays.stream(StringUtils.split( + parentDept.getDeptIdListString(), ",")).map(Long::valueOf).collect(Collectors.toSet())); + } + // 在合并所有的多父部门Id之后,需要判断是否有本部门及子部门的规则。如果有,就继续合并。 + if (ruleMap.containsKey(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT)) { + // 如果多父部门列表中包含当前部门,那么可以直接删除该规则了,如果没包含,就加入到多部门的DEPT_ID的IN LIST中。 + deptIdSet.add(deptId); + ruleMap.remove(DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT); + } + // 需要与仅仅当前部门规则进行合并。 + if (ruleMap.containsKey(DataPermRuleType.TYPE_DEPT_ONLY)) { + if (deptIdSet.contains(deptId)) { + ruleMap.remove(DataPermRuleType.TYPE_DEPT_ONLY); + } + } + return StringUtils.join(deptIdSet, ','); + } + + private String processMultiDept(Map> ruleMap, Long deptId) { + List customDeptList = ruleMap.get(DataPermRuleType.TYPE_CUSTOM_DEPT_LIST); + if (customDeptList == null) { + return null; + } + Set deptIdSet = new HashSet<>(); + for (SysDataPerm customDept : customDeptList) { + deptIdSet.addAll(Arrays.stream(StringUtils.split( + customDept.getDeptIdListString(), ",")).map(Long::valueOf).collect(Collectors.toSet())); + } + if (ruleMap.containsKey(DataPermRuleType.TYPE_DEPT_ONLY)) { + deptIdSet.add(deptId); + ruleMap.remove(DataPermRuleType.TYPE_DEPT_ONLY); + } + return StringUtils.join(deptIdSet, ','); + } + + /** + * 添加用户和数据权限之间的多对多关联关系。 + * + * @param dataPermId 数据权限Id。 + * @param userIdSet 关联的用户Id列表。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void addDataPermUserList(Long dataPermId, Set userIdSet) { + for (Long userId : userIdSet) { + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + dataPermUser.setUserId(userId); + sysDataPermUserMapper.insert(dataPermUser); + } + } + + /** + * 移除用户和数据权限之间的多对多关联关系。 + * + * @param dataPermId 数据权限主键Id。 + * @param userId 用户主键Id。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean removeDataPermUser(Long dataPermId, Long userId) { + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + dataPermUser.setUserId(userId); + return sysDataPermUserMapper.delete(new QueryWrapper<>(dataPermUser)) == 1; + } + + /** + * 验证数据权限对象关联菜单数据是否都合法。 + * + * @param dataPerm 数据权限关对象。 + * @param deptIdListString 与数据权限关联的部门Id列表。 + * @return 验证结果。 + */ + @Override + public CallResult verifyRelatedData(SysDataPerm dataPerm, String deptIdListString) { + JSONObject jsonObject = new JSONObject(); + if (dataPerm.getRuleType() == DataPermRuleType.TYPE_MULTI_DEPT_AND_CHILD_DEPT + || dataPerm.getRuleType() == DataPermRuleType.TYPE_CUSTOM_DEPT_LIST) { + if (StringUtils.isBlank(deptIdListString)) { + return CallResult.error("数据验证失败,部门列表不能为空!"); + } + Set deptIdSet = Arrays.stream(StringUtils.split( + deptIdListString, ",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysDeptService.existAllPrimaryKeys(deptIdSet)) { + return CallResult.error("数据验证失败,存在不合法的部门数据,请刷新后重试!"); + } + jsonObject.put("deptIdSet", deptIdSet); + } + return CallResult.ok(jsonObject); + } + + private void insertRelationData(SysDataPerm dataPerm, Set deptIdSet) { + if (CollectionUtils.isNotEmpty(deptIdSet)) { + for (Long deptId : deptIdSet) { + SysDataPermDept dataPermDept = new SysDataPermDept(); + dataPermDept.setDataPermId(dataPerm.getDataPermId()); + dataPermDept.setDeptId(deptId); + sysDataPermDeptMapper.insert(dataPermDept); + } + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysDeptServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysDeptServiceImpl.java new file mode 100644 index 00000000..a0835a51 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysDeptServiceImpl.java @@ -0,0 +1,331 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.webadmin.upms.service.*; +import com.flow.demo.webadmin.upms.dao.*; +import com.flow.demo.webadmin.upms.model.*; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 部门管理数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysDeptService") +public class SysDeptServiceImpl extends BaseService implements SysDeptService { + + @Autowired + private SysDeptMapper sysDeptMapper; + @Autowired + private SysDeptRelationMapper sysDeptRelationMapper; + @Autowired + private SysUserService sysUserService; + @Autowired + private SysDeptPostMapper sysDeptPostMapper; + @Autowired + private SysDataPermDeptMapper sysDataPermDeptMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysDeptMapper; + } + + /** + * 保存新增的部门对象。 + * + * @param sysDept 新增的部门对象。 + * @param parentSysDept 上级部门对象。 + * @return 新增后的部门对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public SysDept saveNew(SysDept sysDept, SysDept parentSysDept) { + sysDept.setDeptId(idGenerator.nextLongId()); + sysDept.setDeletedFlag(GlobalDeletedFlag.NORMAL); + MyModelUtil.fillCommonsForInsert(sysDept); + sysDeptMapper.insert(sysDept); + // 同步插入部门关联关系数据 + if (parentSysDept == null) { + sysDeptRelationMapper.insert(new SysDeptRelation(sysDept.getDeptId(), sysDept.getDeptId())); + } else { + sysDeptRelationMapper.insertParentList(parentSysDept.getDeptId(), sysDept.getDeptId()); + } + return sysDept; + } + + /** + * 更新部门对象。 + * + * @param sysDept 更新的部门对象。 + * @param originalSysDept 原有的部门对象。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(SysDept sysDept, SysDept originalSysDept) { + MyModelUtil.fillCommonsForUpdate(sysDept, originalSysDept); + UpdateWrapper uw = this.createUpdateQueryForNullValue(sysDept, sysDept.getDeptId()); + if (sysDeptMapper.update(sysDept, uw) == 0) { + return false; + } + if (ObjectUtils.notEqual(sysDept.getParentId(), originalSysDept.getParentId())) { + this.updateParentRelation(sysDept, originalSysDept); + } + return true; + } + + private void updateParentRelation(SysDept sysDept, SysDept originalSysDept) { + // 1. 在删除当前部门与原有父部门的关联关系之前,先将原有的所有父部门Id缓存。 + List originalParentIdList = new LinkedList<>(); + if (originalSysDept.getParentId() != null) { + SysDept originalParentDept = getById(originalSysDept.getParentId()); + while (originalParentDept != null) { + originalParentIdList.add(originalParentDept.getDeptId()); + if (originalParentDept.getParentId() == null) { + break; + } + originalParentDept = getById(originalParentDept.getParentId()); + } + } + // 删除其子部门与其原有父部门之间的关联关系。 + for (Long parentDeptId : originalParentIdList) { + sysDeptRelationMapper.removeBetweenChildrenAndParents(parentDeptId, sysDept.getDeptId()); + } + // 2. 将当前部门与原有的父部门列表解除关系。 + SysDeptRelation filter = new SysDeptRelation(); + filter.setDeptId(sysDept.getDeptId()); + sysDeptRelationMapper.delete(new QueryWrapper<>(filter)); + // 3. 将当前部门和新的父部门列表建立关联关系。 + // 在插入与新父部门的关联关系 + List deptRelationList = new LinkedList<>(); + // 先插入自己和自己的关系。 + deptRelationList.add(new SysDeptRelation(sysDept.getDeptId(), sysDept.getDeptId())); + SysDept parentSysDept = null; + if (sysDept.getParentId() != null) { + parentSysDept = getById(sysDept.getParentId()); + } + List newParentIdList = new LinkedList<>(); + // 再插入直接父部门,以及父部门的父部门,并向上以此类推。 + while (parentSysDept != null) { + newParentIdList.add(parentSysDept.getDeptId()); + deptRelationList.add( + new SysDeptRelation(parentSysDept.getDeptId(), sysDept.getDeptId())); + if (parentSysDept.getParentId() == null) { + break; + } + parentSysDept = getById(parentSysDept.getParentId()); + } + sysDeptRelationMapper.insertList(deptRelationList); + // 4. 将当前部门的子部门与其新的父部门建立关联关系 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq(MyModelUtil.mapToColumnName("parentDeptId", SysDeptRelation.class), sysDept.getDeptId()); + queryWrapper.ne(MyModelUtil.mapToColumnName("deptId", SysDeptRelation.class), sysDept.getDeptId()); + List childRelationList = sysDeptRelationMapper.selectList(queryWrapper); + List newChildrenAndParentList = new LinkedList<>(); + for (Long newParentId : newParentIdList) { + for (SysDeptRelation childDeptRelation : childRelationList) { + newChildrenAndParentList.add(new SysDeptRelation(newParentId, childDeptRelation.getDeptId())); + } + } + if (CollectionUtils.isNotEmpty(newChildrenAndParentList)) { + sysDeptRelationMapper.insertList(newChildrenAndParentList); + } + } + + /** + * 删除指定数据。 + * + * @param deptId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long deptId) { + if (sysDeptMapper.deleteById(deptId) == 0) { + return false; + } + // 这里删除当前部门及其父部门的关联关系。 + // 当前部门和子部门的关系无需在这里删除,因为包含子部门时不能删除父部门。 + SysDeptRelation deptRelation = new SysDeptRelation(); + deptRelation.setDeptId(deptId); + sysDeptRelationMapper.delete(new QueryWrapper<>(deptRelation)); + SysDataPermDept dataPermDept = new SysDataPermDept(); + dataPermDept.setDeptId(deptId); + sysDataPermDeptMapper.delete(new QueryWrapper<>(dataPermDept)); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSysDeptListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getSysDeptList(SysDept filter, String orderBy) { + return sysDeptMapper.getSysDeptList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getSysDeptList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getSysDeptListWithRelation(SysDept filter, String orderBy) { + List resultList = sysDeptMapper.getSysDeptList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 判断指定对象是否包含下级对象。 + * + * @param deptId 主键Id。 + * @return 存在返回true,否则false。 + */ + @Override + public boolean hasChildren(Long deptId) { + SysDept filter = new SysDept(); + filter.setParentId(deptId); + return getCountByFilter(filter) > 0; + } + + /** + * 判断指定部门Id是否包含用户对象。 + * + * @param deptId 部门主键Id。 + * @return 存在返回true,否则false。 + */ + @Override + public boolean hasChildrenUser(Long deptId) { + SysUser sysUser = new SysUser(); + sysUser.setDeptId(deptId); + return sysUserService.getCountByFilter(sysUser) > 0; + } + + /** + * 批量添加多对多关联关系。 + * + * @param sysDeptPostList 多对多关联表对象集合。 + * @param deptId 主表Id。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void addSysDeptPostList(List sysDeptPostList, Long deptId) { + for (SysDeptPost sysDeptPost : sysDeptPostList) { + sysDeptPost.setDeptPostId(idGenerator.nextLongId()); + sysDeptPost.setDeptId(deptId); + sysDeptPostMapper.insert(sysDeptPost); + } + } + + /** + * 更新中间表数据。 + * + * @param sysDeptPost 中间表对象。 + * @return 更新成功与否。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean updateSysDeptPost(SysDeptPost sysDeptPost) { + SysDeptPost filter = new SysDeptPost(); + filter.setDeptPostId(sysDeptPost.getDeptPostId()); + filter.setDeptId(sysDeptPost.getDeptId()); + filter.setPostId(sysDeptPost.getPostId()); + UpdateWrapper uw = + BaseService.createUpdateQueryForNullValue(sysDeptPost, SysDeptPost.class); + uw.setEntity(filter); + return sysDeptPostMapper.update(sysDeptPost, uw) > 0; + } + + /** + * 移除单条多对多关系。 + * + * @param deptId 主表Id。 + * @param postId 从表Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean removeSysDeptPost(Long deptId, Long postId) { + SysDeptPost filter = new SysDeptPost(); + filter.setDeptId(deptId); + filter.setPostId(postId); + return sysDeptPostMapper.delete(new QueryWrapper<>(filter)) > 0; + } + + /** + * 获取中间表数据。 + * + * @param deptId 主表Id。 + * @param postId 从表Id。 + * @return 中间表对象。 + */ + @Override + public SysDeptPost getSysDeptPost(Long deptId, Long postId) { + SysDeptPost filter = new SysDeptPost(); + filter.setDeptId(deptId); + filter.setPostId(postId); + return sysDeptPostMapper.selectOne(new QueryWrapper<>(filter)); + } + + @Override + public SysDeptPost getSysDeptPost(Long deptPostId) { + return sysDeptPostMapper.selectById(deptPostId); + } + + @Override + public List> getSysDeptPostListWithRelationByDeptId(Long deptId) { + return sysDeptPostMapper.getSysDeptPostListWithRelationByDeptId(deptId); + } + + @Override + public List getLeaderDeptPostIdList(Long deptId) { + List resultList = sysDeptPostMapper.getLeaderDeptPostList(deptId); + return resultList.stream().map(SysDeptPost::getDeptPostId).collect(Collectors.toList()); + } + + @Override + public List getUpLeaderDeptPostIdList(Long deptId) { + SysDept sysDept = this.getById(deptId); + if (sysDept.getParentId() == null) { + return new LinkedList<>(); + } + return this.getLeaderDeptPostIdList(sysDept.getParentId()); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysMenuServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysMenuServiceImpl.java new file mode 100644 index 00000000..84282819 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysMenuServiceImpl.java @@ -0,0 +1,335 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.webadmin.upms.dao.SysMenuMapper; +import com.flow.demo.webadmin.upms.dao.SysMenuPermCodeMapper; +import com.flow.demo.webadmin.upms.dao.SysRoleMenuMapper; +import com.flow.demo.webadmin.upms.model.SysMenu; +import com.flow.demo.webadmin.upms.model.SysMenuPermCode; +import com.flow.demo.webadmin.upms.model.SysRoleMenu; +import com.flow.demo.webadmin.upms.model.constant.SysMenuType; +import com.flow.demo.webadmin.upms.model.constant.SysOnlineMenuPermType; +import com.flow.demo.webadmin.upms.service.SysMenuService; +import com.flow.demo.webadmin.upms.service.SysPermCodeService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 菜单数据服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysMenuService") +public class SysMenuServiceImpl extends BaseService implements SysMenuService { + + @Autowired + private SysMenuMapper sysMenuMapper; + @Autowired + private SysRoleMenuMapper sysRoleMenuMapper; + @Autowired + private SysMenuPermCodeMapper sysMenuPermCodeMapper; + @Autowired + private SysPermCodeService sysPermCodeService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysMenuMapper; + } + + /** + * 保存新增的菜单对象。 + * + * @param sysMenu 新增的菜单对象。 + * @param permCodeIdSet 权限字Id列表。 + * @return 新增后的菜单对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public SysMenu saveNew(SysMenu sysMenu, Set permCodeIdSet) { + sysMenu.setMenuId(idGenerator.nextLongId()); + MyModelUtil.fillCommonsForInsert(sysMenu); + sysMenu.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysMenuMapper.insert(sysMenu); + if (permCodeIdSet != null) { + for (Long permCodeId : permCodeIdSet) { + SysMenuPermCode menuPermCode = new SysMenuPermCode(); + menuPermCode.setMenuId(sysMenu.getMenuId()); + menuPermCode.setPermCodeId(permCodeId); + sysMenuPermCodeMapper.insert(menuPermCode); + } + } + // 判断当前菜单是否为指向在线表单的菜单,并将根据约定,动态插入两个子菜单。 + if (sysMenu.getOnlineFormId() != null && sysMenu.getOnlineFlowEntryId() == null) { + SysMenu viewSubMenu = new SysMenu(); + viewSubMenu.setMenuId(idGenerator.nextLongId()); + viewSubMenu.setParentId(sysMenu.getMenuId()); + viewSubMenu.setMenuType(SysMenuType.TYPE_BUTTON); + viewSubMenu.setMenuName("查看"); + viewSubMenu.setShowOrder(0); + viewSubMenu.setOnlineFormId(sysMenu.getOnlineFormId()); + viewSubMenu.setOnlineMenuPermType(SysOnlineMenuPermType.TYPE_VIEW); + viewSubMenu.setDeletedFlag(GlobalDeletedFlag.NORMAL); + MyModelUtil.fillCommonsForInsert(viewSubMenu); + sysMenuMapper.insert(viewSubMenu); + SysMenu editSubMenu = new SysMenu(); + editSubMenu.setMenuId(idGenerator.nextLongId()); + editSubMenu.setParentId(sysMenu.getMenuId()); + editSubMenu.setMenuType(SysMenuType.TYPE_BUTTON); + editSubMenu.setMenuName("编辑"); + editSubMenu.setShowOrder(1); + editSubMenu.setOnlineFormId(sysMenu.getOnlineFormId()); + editSubMenu.setOnlineMenuPermType(SysOnlineMenuPermType.TYPE_EDIT); + editSubMenu.setDeletedFlag(GlobalDeletedFlag.NORMAL); + MyModelUtil.fillCommonsForInsert(editSubMenu); + sysMenuMapper.insert(editSubMenu); + } + return sysMenu; + } + + /** + * 更新菜单对象。 + * + * @param sysMenu 更新的菜单对象。 + * @param originalSysMenu 原有的菜单对象。 + * @param permCodeIdSet 权限字Id列表。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(SysMenu sysMenu, SysMenu originalSysMenu, Set permCodeIdSet) { + MyModelUtil.fillCommonsForUpdate(sysMenu, originalSysMenu); + sysMenu.setMenuType(originalSysMenu.getMenuType()); + UpdateWrapper uw = this.createUpdateQueryForNullValue(sysMenu, sysMenu.getMenuId()); + if (sysMenuMapper.update(sysMenu, uw) != 1) { + return false; + } + SysMenuPermCode deletedMenuPermCode = new SysMenuPermCode(); + deletedMenuPermCode.setMenuId(sysMenu.getMenuId()); + sysMenuPermCodeMapper.delete(new QueryWrapper<>(deletedMenuPermCode)); + if (permCodeIdSet != null) { + for (Long permCodeId : permCodeIdSet) { + SysMenuPermCode menuPermCode = new SysMenuPermCode(); + menuPermCode.setMenuId(sysMenu.getMenuId()); + menuPermCode.setPermCodeId(permCodeId); + sysMenuPermCodeMapper.insert(menuPermCode); + } + } + // 如果当前菜单的在线表单Id变化了,就需要同步更新他的内置子菜单也同步更新。 + if (ObjectUtil.notEqual(originalSysMenu.getOnlineFormId(), sysMenu.getOnlineFormId())) { + SysMenu onlineSubMenu = new SysMenu(); + onlineSubMenu.setOnlineFormId(sysMenu.getOnlineFormId()); + sysMenuMapper.update(onlineSubMenu, + new QueryWrapper().lambda().eq(SysMenu::getParentId, sysMenu.getMenuId())); + } + return true; + } + + /** + * 删除指定的菜单。 + * + * @param menu 菜单对象。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(SysMenu menu) { + Long menuId = menu.getMenuId(); + if (sysMenuMapper.deleteById(menuId) != 1) { + return false; + } + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setMenuId(menuId); + sysRoleMenuMapper.delete(new QueryWrapper<>(roleMenu)); + SysMenuPermCode menuPermCode = new SysMenuPermCode(); + menuPermCode.setMenuId(menuId); + sysMenuPermCodeMapper.delete(new QueryWrapper<>(menuPermCode)); + // 如果为指向在线表单的菜单,则连同删除子菜单 + if (menu.getOnlineFormId() != null) { + sysMenuMapper.delete(new QueryWrapper().lambda().eq(SysMenu::getParentId, menuId)); + } + return true; + } + + /** + * 获取全部菜单列表。 + * + * @return 全部菜单列表。 + */ + @Override + public Collection getAllMenuList() { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc(this.safeMapToColumnName("showOrder")); + queryWrapper.in(this.safeMapToColumnName("menuType"), + Arrays.asList(SysMenuType.TYPE_MENU, SysMenuType.TYPE_DIRECTORY)); + return sysMenuMapper.selectList(queryWrapper); + } + + /** + * 获取指定用户Id的菜单列表,已去重。 + * + * @param userId 用户主键Id。 + * @return 用户关联的菜单列表。 + */ + @Override + public Collection getMenuListByUserId(Long userId) { + List menuList = sysMenuMapper.getMenuListByUserId(userId); + LinkedHashMap menuMap = new LinkedHashMap<>(); + for (SysMenu menu : menuList) { + menuMap.put(menu.getMenuId(), menu); + } + return menuMap.values(); + } + + /** + * 判断当前菜单是否存在子菜单。 + * + * @param menuId 菜单主键Id。 + * @return 存在返回true,否则false。 + */ + @Override + public boolean hasChildren(Long menuId) { + SysMenu menu = new SysMenu(); + menu.setParentId(menuId); + return this.getCountByFilter(menu) > 0; + } + + /** + * 验证菜单对象关联的数据是否都合法。 + * + * @param sysMenu 当前操作的对象。 + * @param originalSysMenu 原有对象。 + * @param permCodeIdListString 逗号分隔的权限Id列表。 + * @return 验证结果。 + */ + @Override + public CallResult verifyRelatedData(SysMenu sysMenu, SysMenu originalSysMenu, String permCodeIdListString) { + // menu、ui fragment和button类型的menu不能没有parentId + if (sysMenu.getParentId() == null) { + if (sysMenu.getMenuType() != SysMenuType.TYPE_DIRECTORY) { + return CallResult.error("数据验证失败,当前类型菜单项的上级菜单不能为空!"); + } + } + if (this.needToVerify(sysMenu, originalSysMenu, SysMenu::getParentId)) { + String errorMessage = checkErrorOfNonDirectoryMenu(sysMenu); + if (errorMessage != null) { + return CallResult.error(errorMessage); + } + } + JSONObject jsonObject = null; + if (StringUtils.isNotBlank(permCodeIdListString)) { + Set permCodeIdSet = Arrays.stream( + permCodeIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysPermCodeService.existAllPrimaryKeys(permCodeIdSet)) { + return CallResult.error("数据验证失败,存在不合法的权限字,请刷新后重试!"); + } + jsonObject = new JSONObject(); + jsonObject.put("permCodeIdSet", permCodeIdSet); + } + return CallResult.ok(jsonObject); + } + + /** + * 查询菜单的权限资源地址列表。同时返回详细的分配路径。 + * + * @param menuId 菜单Id。 + * @param url 权限资源地址过滤条件。 + * @return 包含从菜单到权限资源的权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysPermListWithDetail(Long menuId, String url) { + return sysMenuMapper.getSysPermListWithDetail(menuId, url); + } + + /** + * 查询菜单的用户列表。同时返回详细的分配路径。 + * + * @param menuId 菜单Id。 + * @param loginName 登录名。 + * @return 包含从菜单到用户的完整权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysUserListWithDetail(Long menuId, String loginName) { + return sysMenuMapper.getSysUserListWithDetail(menuId, loginName); + } + + /** + * 获取指定类型的所有在线表单的菜单。 + * + * @param menuType 菜单类型,NULL则返回全部类型。 + * @return 在线表单关联的菜单列表。 + */ + @Override + public List getAllOnlineMenuList(Integer menuType) { + LambdaQueryWrapper queryWrapper = + new QueryWrapper().lambda().isNotNull(SysMenu::getOnlineFormId); + if (menuType != null) { + queryWrapper.eq(SysMenu::getMenuType, menuType); + } + return sysMenuMapper.selectList(queryWrapper); + } + + /** + * 获取当前用户有权访问的在线表单菜单,仅返回类型为BUTTON的菜单。 + * + * @param userId 指定的用户。 + * @param menuType 菜单类型,NULL则返回全部类型。 + * @return 在线表单关联的菜单列表。 + */ + @Override + public List getOnlineMenuListByUserId(Long userId, Integer menuType) { + return sysMenuMapper.getOnlineMenuListByUserId(userId, menuType); + } + + private String checkErrorOfNonDirectoryMenu(SysMenu sysMenu) { + // 判断父节点是否存在 + SysMenu parentSysMenu = getById(sysMenu.getParentId()); + if (parentSysMenu == null) { + return "数据验证失败,关联的上级菜单并不存在,请刷新后重试!"; + } + // 逐个判断每种类型的菜单,他的父菜单的合法性,先从目录类型和菜单类型开始 + if (sysMenu.getMenuType() == SysMenuType.TYPE_DIRECTORY + || sysMenu.getMenuType() == SysMenuType.TYPE_MENU) { + // 他们的上级只能是目录 + if (parentSysMenu.getMenuType() != SysMenuType.TYPE_DIRECTORY) { + return "数据验证失败,当前类型菜单项的上级菜单只能是目录类型!"; + } + } else if (sysMenu.getMenuType() == SysMenuType.TYPE_UI_FRAGMENT) { + // ui fragment的上级只能是menu类型 + if (parentSysMenu.getMenuType() != SysMenuType.TYPE_MENU) { + return "数据验证失败,当前类型菜单项的上级菜单只能是菜单类型和按钮类型!"; + } + } else if (sysMenu.getMenuType() == SysMenuType.TYPE_BUTTON) { + // button的上级只能是menu和ui fragment + if (parentSysMenu.getMenuType() != SysMenuType.TYPE_MENU + && parentSysMenu.getMenuType() != SysMenuType.TYPE_UI_FRAGMENT) { + return "数据验证失败,当前类型菜单项的上级菜单只能是菜单类型和UI片段类型!"; + } + } + return null; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermCodeServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermCodeServiceImpl.java new file mode 100644 index 00000000..1de30fe3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermCodeServiceImpl.java @@ -0,0 +1,226 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.webadmin.upms.dao.SysMenuPermCodeMapper; +import com.flow.demo.webadmin.upms.dao.SysPermCodeMapper; +import com.flow.demo.webadmin.upms.dao.SysPermCodePermMapper; +import com.flow.demo.webadmin.upms.model.SysMenuPermCode; +import com.flow.demo.webadmin.upms.model.SysPermCode; +import com.flow.demo.webadmin.upms.model.SysPermCodePerm; +import com.flow.demo.webadmin.upms.service.SysPermCodeService; +import com.flow.demo.webadmin.upms.service.SysPermService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 权限字数据服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysPermCodeService") +public class SysPermCodeServiceImpl extends BaseService implements SysPermCodeService { + + @Autowired + private SysPermCodeMapper sysPermCodeMapper; + @Autowired + private SysPermCodePermMapper sysPermCodePermMapper; + @Autowired + private SysMenuPermCodeMapper sysMenuPermCodeMapper; + @Autowired + private SysPermService sysPermService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermCodeMapper; + } + + /** + * 获取指定用户的权限字列表,已去重。 + * + * @param userId 用户主键Id。 + * @return 用户关联的权限字列表。 + */ + @Override + public Collection getPermCodeListByUserId(Long userId) { + List permCodeList = sysPermCodeMapper.getPermCodeListByUserId(userId); + return new HashSet<>(permCodeList); + } + + /** + * 获取所有权限字数据列表,已去重。 + * + * @return 全部权限字列表。 + */ + @Override + public Collection getAllPermCodeList() { + List permCodeList = this.getAllList(); + return permCodeList.stream().map(SysPermCode::getPermCode).collect(Collectors.toSet()); + } + + /** + * 保存新增的权限字对象。 + * + * @param sysPermCode 新增的权限字对象。 + * @param permIdSet 权限资源Id列表。 + * @return 新增后的权限字对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public SysPermCode saveNew(SysPermCode sysPermCode, Set permIdSet) { + sysPermCode.setPermCodeId(idGenerator.nextLongId()); + MyModelUtil.fillCommonsForInsert(sysPermCode); + sysPermCode.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysPermCodeMapper.insert(sysPermCode); + if (permIdSet != null) { + for (Long permId : permIdSet) { + SysPermCodePerm permCodePerm = new SysPermCodePerm(); + permCodePerm.setPermCodeId(sysPermCode.getPermCodeId()); + permCodePerm.setPermId(permId); + sysPermCodePermMapper.insert(permCodePerm); + } + } + return sysPermCode; + } + + /** + * 更新权限字对象。 + * + * @param sysPermCode 更新的权限字对象。 + * @param originalSysPermCode 原有的权限字对象。 + * @param permIdSet 权限资源Id列表。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(SysPermCode sysPermCode, SysPermCode originalSysPermCode, Set permIdSet) { + MyModelUtil.fillCommonsForUpdate(sysPermCode, originalSysPermCode); + sysPermCode.setParentId(originalSysPermCode.getParentId()); + UpdateWrapper uw = + this.createUpdateQueryForNullValue(sysPermCode, sysPermCode.getPermCodeId()); + if (sysPermCodeMapper.update(sysPermCode, uw) != 1) { + return false; + } + SysPermCodePerm deletedPermCodePerm = new SysPermCodePerm(); + deletedPermCodePerm.setPermCodeId(sysPermCode.getPermCodeId()); + sysPermCodePermMapper.delete(new QueryWrapper<>(deletedPermCodePerm)); + if (permIdSet != null) { + for (Long permId : permIdSet) { + SysPermCodePerm permCodePerm = new SysPermCodePerm(); + permCodePerm.setPermCodeId(sysPermCode.getPermCodeId()); + permCodePerm.setPermId(permId); + sysPermCodePermMapper.insert(permCodePerm); + } + } + return true; + } + + /** + * 删除指定的权限字。 + * + * @param permCodeId 权限字主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long permCodeId) { + if (sysPermCodeMapper.deleteById(permCodeId) != 1) { + return false; + } + SysMenuPermCode menuPermCode = new SysMenuPermCode(); + menuPermCode.setPermCodeId(permCodeId); + sysMenuPermCodeMapper.delete(new QueryWrapper<>(menuPermCode)); + SysPermCodePerm permCodePerm = new SysPermCodePerm(); + permCodePerm.setPermCodeId(permCodeId); + sysPermCodePermMapper.delete(new QueryWrapper<>(permCodePerm)); + return true; + } + + /** + * 判断当前权限字是否存在下级权限字对象。 + * + * @param permCodeId 权限字主键Id。 + * @return 存在返回true,否则false。 + */ + @Override + public boolean hasChildren(Long permCodeId) { + SysPermCode permCode = new SysPermCode(); + permCode.setParentId(permCodeId); + return this.getCountByFilter(permCode) > 0; + } + + /** + * 验证权限字对象关联的数据是否都合法。 + * + * @param sysPermCode 当前操作的对象。 + * @param originalSysPermCode 原有对象。 + * @param permIdListString 逗号分隔的权限资源Id列表。 + * @return 验证结果。 + */ + @Override + public CallResult verifyRelatedData( + SysPermCode sysPermCode, SysPermCode originalSysPermCode, String permIdListString) { + if (this.needToVerify(sysPermCode, originalSysPermCode, SysPermCode::getParentId)) { + if (getById(sysPermCode.getParentId()) == null) { + return CallResult.error("数据验证失败,关联的上级权限字并不存在,请刷新后重试!"); + } + } + JSONObject jsonObject = null; + if (StringUtils.isNotBlank(permIdListString)) { + Set permIdSet = Arrays.stream( + permIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysPermService.existAllPrimaryKeys(permIdSet)) { + return CallResult.error("数据验证失败,存在不合法的权限资源,请刷新后重试!"); + } + jsonObject = new JSONObject(); + jsonObject.put("permIdSet", permIdSet); + } + return CallResult.ok(jsonObject); + } + + /** + * 查询权限字的用户列表。同时返回详细的分配路径。 + * + * @param permCodeId 权限字Id。 + * @param loginName 登录名。 + * @return 包含从权限字到用户的完整权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysUserListWithDetail(Long permCodeId, String loginName) { + return sysPermCodeMapper.getSysUserListWithDetail(permCodeId, loginName); + } + + /** + * 查询权限字的角色列表。同时返回详细的分配路径。 + * + * @param permCodeId 权限字Id。 + * @param roleName 角色名。 + * @return 包含从权限字到角色的权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysRoleListWithDetail(Long permCodeId, String roleName) { + return sysPermCodeMapper.getSysRoleListWithDetail(permCodeId, roleName); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermModuleServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermModuleServiceImpl.java new file mode 100644 index 00000000..20f5dc6f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermModuleServiceImpl.java @@ -0,0 +1,124 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.webadmin.upms.dao.SysPermModuleMapper; +import com.flow.demo.webadmin.upms.model.SysPerm; +import com.flow.demo.webadmin.upms.model.SysPermModule; +import com.flow.demo.webadmin.upms.service.SysPermModuleService; +import com.flow.demo.webadmin.upms.service.SysPermService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 权限资源模块数据服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysPermModuleService") +public class SysPermModuleServiceImpl extends BaseService implements SysPermModuleService { + + @Autowired + private SysPermModuleMapper sysPermModuleMapper; + @Autowired + private SysPermService sysPermService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermModuleMapper; + } + + /** + * 保存新增的权限资源模块对象。 + * + * @param sysPermModule 新增的权限资源模块对象。 + * @return 新增后的权限资源模块对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public SysPermModule saveNew(SysPermModule sysPermModule) { + sysPermModule.setModuleId(idGenerator.nextLongId()); + MyModelUtil.fillCommonsForInsert(sysPermModule); + sysPermModule.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysPermModuleMapper.insert(sysPermModule); + return sysPermModule; + } + + /** + * 更新权限资源模块对象。 + * + * @param sysPermModule 更新的权限资源模块对象。 + * @param originalSysPermModule 原有的权限资源模块对象。 + * @return 更新成功返回true,否则false + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(SysPermModule sysPermModule, SysPermModule originalSysPermModule) { + MyModelUtil.fillCommonsForUpdate(sysPermModule, originalSysPermModule); + return sysPermModuleMapper.updateById(sysPermModule) != 0; + } + + /** + * 删除指定的权限资源模块。 + * + * @param moduleId 权限资源模块主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long moduleId) { + return sysPermModuleMapper.deleteById(moduleId) == 1; + } + + /** + * 获取权限模块资源及其关联的权限资源列表。 + * + * @return 权限资源模块及其关联的权限资源列表。 + */ + @Override + public List getPermModuleAndPermList() { + return sysPermModuleMapper.getPermModuleAndPermList(); + } + + /** + * 判断是否存在下级权限资源模块。 + * + * @param moduleId 权限资源模块主键Id。 + * @return 存在返回true,否则false。 + */ + @Override + public boolean hasChildren(Long moduleId) { + SysPermModule permModule = new SysPermModule(); + permModule.setParentId(moduleId); + return this.getCountByFilter(permModule) > 0; + } + + /** + * 判断是否存在权限数据。 + * + * @param moduleId 权限资源模块主键Id。 + * @return 存在返回true,否则false。 + */ + @Override + public boolean hasModulePerms(Long moduleId) { + SysPerm filter = new SysPerm(); + filter.setModuleId(moduleId); + return sysPermService.getCountByFilter(filter) > 0; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermServiceImpl.java new file mode 100644 index 00000000..b8719b9e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermServiceImpl.java @@ -0,0 +1,243 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import cn.hutool.core.util.ObjectUtil; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.RedisKeyUtil; +import com.flow.demo.webadmin.config.ApplicationConfig; +import com.flow.demo.webadmin.upms.service.*; +import com.flow.demo.webadmin.upms.dao.SysPermCodePermMapper; +import com.flow.demo.webadmin.upms.dao.SysPermMapper; +import com.flow.demo.webadmin.upms.model.SysPerm; +import com.flow.demo.webadmin.upms.model.SysPermCodePerm; +import com.flow.demo.webadmin.upms.model.SysPermModule; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.redisson.api.RSet; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 权限资源数据服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysPermService") +public class SysPermServiceImpl extends BaseService implements SysPermService { + + @Autowired + private SysPermMapper sysPermMapper; + @Autowired + private SysPermCodePermMapper sysPermCodePermMapper; + @Autowired + private SysPermModuleService sysPermModuleService; + @Autowired + private SysUserService sysUserService; + @Autowired + private IdGeneratorWrapper idGenerator; + @Autowired + private RedissonClient redissonClient; + @Autowired + private ApplicationConfig applicationConfig; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermMapper; + } + + /** + * 保存新增的权限资源对象。 + * + * @param perm 新增的权限资源对象。 + * @return 新增后的权限资源对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public SysPerm saveNew(SysPerm perm) { + perm.setPermId(idGenerator.nextLongId()); + MyModelUtil.fillCommonsForInsert(perm); + perm.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysPermMapper.insert(perm); + return perm; + } + + /** + * 更新权限资源对象。 + * + * @param perm 更新的权限资源对象。 + * @param originalPerm 原有的权限资源对象。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(SysPerm perm, SysPerm originalPerm) { + MyModelUtil.fillCommonsForUpdate(perm, originalPerm); + return sysPermMapper.updateById(perm) != 0; + } + + /** + * 删除权限资源。 + * + * @param permId 权限资源主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long permId) { + if (sysPermMapper.deleteById(permId) != 1) { + return false; + } + SysPermCodePerm permCodePerm = new SysPermCodePerm(); + permCodePerm.setPermId(permId); + sysPermCodePermMapper.delete(new QueryWrapper<>(permCodePerm)); + return true; + } + + /** + * 获取权限数据列表。 + * + * @param sysPermFilter 过滤对象。 + * @return 权限列表。 + */ + @Override + public List getPermListWithRelation(SysPerm sysPermFilter) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.orderByAsc(this.safeMapToColumnName("showOrder")); + queryWrapper.eq(ObjectUtil.isNotNull(sysPermFilter.getModuleId()), + this.safeMapToColumnName("moduleId"), sysPermFilter.getModuleId()); + queryWrapper.like(ObjectUtil.isNotNull(sysPermFilter.getUrl()), + this.safeMapToColumnName("url"), "%" + sysPermFilter.getUrl() + "%"); + List permList = sysPermMapper.selectList(queryWrapper); + // 这里因为权限只有字典数据,所以仅仅做字典关联。 + this.buildRelationForDataList(permList, MyRelationParam.dictOnly()); + return permList; + } + + /** + * 将指定用户的指定会话的权限集合存入缓存。 + * + * @param sessionId 会话Id。 + * @param userId 用户主键Id。 + * @return 查询并缓存后的权限集合。 + */ + @Override + public Collection putUserSysPermCache(String sessionId, Long userId) { + Collection permList = this.getPermListByUserId(userId); + if (CollectionUtils.isEmpty(permList)) { + return permList; + } + String sessionPermKey = RedisKeyUtil.makeSessionPermIdKey(sessionId); + RSet redisPermSet = redissonClient.getSet(sessionPermKey); + redisPermSet.addAll(permList.stream().map(Object::toString).collect(Collectors.toSet())); + redisPermSet.expire(applicationConfig.getSessionExpiredSeconds(), TimeUnit.SECONDS); + return permList; + } + + /** + * 把在线表单的权限URL集合,存放到权限URL的缓存中。 + * + * @param sessionId 会话Id。 + * @param permUrlSet URL集合。 + */ + @Override + public void putOnlinePermToCache(String sessionId, Set permUrlSet) { + String sessionPermKey = RedisKeyUtil.makeSessionPermIdKey(sessionId); + redissonClient.getSet(sessionPermKey).addAll(permUrlSet); + } + + /** + * 将指定会话的权限集合从缓存中移除。 + * + * @param sessionId 会话Id。 + */ + @Override + public void removeUserSysPermCache(String sessionId) { + String sessionPermKey = RedisKeyUtil.makeSessionPermIdKey(sessionId); + redissonClient.getSet(sessionPermKey).deleteAsync(); + } + + /** + * 获取与指定用户关联的权限资源列表,已去重。 + * + * @param userId 关联的用户主键Id。 + * @return 与指定用户Id关联的权限资源列表。 + */ + @Override + public Collection getPermListByUserId(Long userId) { + List urlList = sysPermMapper.getPermListByUserId(userId); + return new HashSet<>(urlList); + } + + /** + * 验证权限资源对象关联的数据是否都合法。 + * + * @param sysPerm 当前操作的对象。 + * @param originalSysPerm 原有对象。 + * @return 验证结果。 + */ + @Override + public CallResult verifyRelatedData(SysPerm sysPerm, SysPerm originalSysPerm) { + if (this.needToVerify(sysPerm, originalSysPerm, SysPerm::getModuleId)) { + SysPermModule permModule = sysPermModuleService.getById(sysPerm.getModuleId()); + if (permModule == null) { + return CallResult.error("数据验证失败,关联的权限模块Id并不存在,请刷新后重试!"); + } + } + return CallResult.ok(); + } + + /** + * 查询权限资源地址的用户列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param loginName 登录名。 + * @return 包含从权限资源到用户的完整权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysUserListWithDetail(Long permId, String loginName) { + return sysPermMapper.getSysUserListWithDetail(permId, loginName); + } + + /** + * 查询权限资源地址的角色列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param roleName 角色名。 + * @return 包含从权限资源到角色的权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysRoleListWithDetail(Long permId, String roleName) { + return sysPermMapper.getSysRoleListWithDetail(permId, roleName); + } + + /** + * 查询权限资源地址的菜单列表。同时返回详细的分配路径。 + * + * @param permId 权限资源Id。 + * @param menuName 菜单名。 + * @return 包含从权限资源到菜单的权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysMenuListWithDetail(Long permId, String menuName) { + return sysPermMapper.getSysMenuListWithDetail(permId, menuName); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermWhitelistServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermWhitelistServiceImpl.java new file mode 100644 index 00000000..f9058e73 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPermWhitelistServiceImpl.java @@ -0,0 +1,52 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.webadmin.upms.dao.SysPermWhitelistMapper; +import com.flow.demo.webadmin.upms.model.SysPermWhitelist; +import com.flow.demo.webadmin.upms.service.SysPermWhitelistService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 权限资源白名单数据服务类。 + * 白名单中的权限资源,可以不受权限控制,任何用户皆可访问,一般用于常用的字典数据列表接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysPermWhitelistService") +public class SysPermWhitelistServiceImpl extends BaseService implements SysPermWhitelistService { + + @Autowired + private SysPermWhitelistMapper sysPermWhitelistMapper; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPermWhitelistMapper; + } + + /** + * 获取白名单权限资源的列表。 + * + * @return 白名单权限资源地址列表。 + */ + @Override + public List getWhitelistPermList() { + List dataList = this.getAllList(); + Function getterFunc = SysPermWhitelist::getPermUrl; + return dataList.stream() + .filter(x -> getterFunc.apply(x) != null).map(getterFunc).collect(Collectors.toList()); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPostServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPostServiceImpl.java new file mode 100644 index 00000000..5f7b23c0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysPostServiceImpl.java @@ -0,0 +1,188 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.github.pagehelper.Page; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.webadmin.upms.dao.SysDeptPostMapper; +import com.flow.demo.webadmin.upms.dao.SysPostMapper; +import com.flow.demo.webadmin.upms.dao.SysUserPostMapper; +import com.flow.demo.webadmin.upms.model.SysDeptPost; +import com.flow.demo.webadmin.upms.model.SysPost; +import com.flow.demo.webadmin.upms.model.SysUserPost; +import com.flow.demo.webadmin.upms.service.SysPostService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Set; + +/** + * 岗位管理数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysPostService") +public class SysPostServiceImpl extends BaseService implements SysPostService { + + @Autowired + private SysPostMapper sysPostMapper; + @Autowired + private SysUserPostMapper sysUserPostMapper; + @Autowired + private SysDeptPostMapper sysDeptPostMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysPostMapper; + } + + /** + * 保存新增对象。 + * + * @param sysPost 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public SysPost saveNew(SysPost sysPost) { + sysPost.setPostId(idGenerator.nextLongId()); + sysPost.setDeletedFlag(GlobalDeletedFlag.NORMAL); + MyModelUtil.fillCommonsForInsert(sysPost); + MyModelUtil.setDefaultValue(sysPost, "leaderPost", false); + sysPostMapper.insert(sysPost); + return sysPost; + } + + /** + * 更新数据对象。 + * + * @param sysPost 更新的对象。 + * @param originalSysPost 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(SysPost sysPost, SysPost originalSysPost) { + MyModelUtil.fillCommonsForUpdate(sysPost, originalSysPost); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + UpdateWrapper uw = this.createUpdateQueryForNullValue(sysPost, sysPost.getPostId()); + return sysPostMapper.update(sysPost, uw) == 1; + } + + /** + * 删除指定数据。 + * + * @param postId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long postId) { + if (sysPostMapper.deleteById(postId) != 1) { + return false; + } + // 开始删除多对多父表的关联 + SysUserPost sysUserPost = new SysUserPost(); + sysUserPost.setPostId(postId); + sysUserPostMapper.delete(new QueryWrapper<>(sysUserPost)); + SysDeptPost sysDeptPost = new SysDeptPost(); + sysDeptPost.setPostId(postId); + sysDeptPostMapper.delete(new QueryWrapper<>(sysDeptPost)); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSysPostListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getSysPostList(SysPost filter, String orderBy) { + return sysPostMapper.getSysPostList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getSysPostList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getSysPostListWithRelation(SysPost filter, String orderBy) { + List resultList = sysPostMapper.getSysPostList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param deptId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getNotInSysPostListByDeptId(Long deptId, SysPost filter, String orderBy) { + List resultList = sysPostMapper.getNotInSysPostListByDeptId(deptId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly()); + return resultList; + } + + /** + * 获取指定部门的岗位列表。 + * + * @param deptId 部门Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getSysPostListByDeptId(Long deptId, SysPost filter, String orderBy) { + List resultList = sysPostMapper.getSysPostListByDeptId(deptId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly()); + return resultList; + } + + @Override + public List getSysUserPostListByUserId(Long userId) { + SysUserPost filter = new SysUserPost(); + filter.setUserId(userId); + return sysUserPostMapper.selectList(new QueryWrapper<>(filter)); + } + + @Override + public boolean existAllPrimaryKeys(Set deptPostIdSet, Long deptId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(SysDeptPost::getDeptId, deptId); + queryWrapper.in(SysDeptPost::getDeptPostId, deptPostIdSet); + return sysDeptPostMapper.selectCount(queryWrapper) == deptPostIdSet.size(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysRoleServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysRoleServiceImpl.java new file mode 100644 index 00000000..1d01de6e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysRoleServiceImpl.java @@ -0,0 +1,221 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.webadmin.upms.dao.SysRoleMapper; +import com.flow.demo.webadmin.upms.dao.SysRoleMenuMapper; +import com.flow.demo.webadmin.upms.dao.SysUserRoleMapper; +import com.flow.demo.webadmin.upms.model.SysRole; +import com.flow.demo.webadmin.upms.model.SysRoleMenu; +import com.flow.demo.webadmin.upms.model.SysUserRole; +import com.flow.demo.webadmin.upms.service.SysMenuService; +import com.flow.demo.webadmin.upms.service.SysRoleService; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 角色数据服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysRoleService") +public class SysRoleServiceImpl extends BaseService implements SysRoleService { + + @Autowired + private SysRoleMapper sysRoleMapper; + @Autowired + private SysRoleMenuMapper sysRoleMenuMapper; + @Autowired + private SysUserRoleMapper sysUserRoleMapper; + @Autowired + private SysMenuService sysMenuService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回主对象的Mapper对象。 + * + * @return 主对象的Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysRoleMapper; + } + + /** + * 保存新增的角色对象。 + * + * @param role 新增的角色对象。 + * @param menuIdSet 菜单Id列表。 + * @return 新增后的角色对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public SysRole saveNew(SysRole role, Set menuIdSet) { + role.setRoleId(idGenerator.nextLongId()); + MyModelUtil.fillCommonsForInsert(role); + role.setDeletedFlag(GlobalDeletedFlag.NORMAL); + sysRoleMapper.insert(role); + if (menuIdSet != null) { + for (Long menuId : menuIdSet) { + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(role.getRoleId()); + roleMenu.setMenuId(menuId); + sysRoleMenuMapper.insert(roleMenu); + } + } + return role; + } + + /** + * 更新角色对象。 + * + * @param role 更新的角色对象。 + * @param originalRole 原有的角色对象。 + * @param menuIdSet 菜单Id列表。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(SysRole role, SysRole originalRole, Set menuIdSet) { + MyModelUtil.fillCommonsForUpdate(role, originalRole); + if (sysRoleMapper.updateById(role) != 1) { + return false; + } + SysRoleMenu deletedRoleMenu = new SysRoleMenu(); + deletedRoleMenu.setRoleId(role.getRoleId()); + sysRoleMenuMapper.delete(new QueryWrapper<>(deletedRoleMenu)); + if (menuIdSet != null) { + for (Long menuId : menuIdSet) { + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(role.getRoleId()); + roleMenu.setMenuId(menuId); + sysRoleMenuMapper.insert(roleMenu); + } + } + return true; + } + + /** + * 删除指定角色。 + * + * @param roleId 角色主键Id。 + * @return 删除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long roleId) { + if (sysRoleMapper.deleteById(roleId) != 1) { + return false; + } + SysRoleMenu roleMenu = new SysRoleMenu(); + roleMenu.setRoleId(roleId); + sysRoleMenuMapper.delete(new QueryWrapper<>(roleMenu)); + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(roleId); + sysUserRoleMapper.delete(new QueryWrapper<>(userRole)); + return true; + } + + /** + * 获取角色列表。 + * + * @param filter 角色过滤对象。 + * @param orderBy 排序参数。 + * @return 角色列表。 + */ + @Override + public List getSysRoleList(SysRole filter, String orderBy) { + return sysRoleMapper.getSysRoleList(filter, orderBy); + } + + /** + * 批量新增用户角色关联。 + * + * @param userRoleList 用户角色关系数据列表。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void addUserRoleList(List userRoleList) { + for (SysUserRole userRole : userRoleList) { + sysUserRoleMapper.insert(userRole); + } + } + + /** + * 移除指定用户和指定角色的关联关系。 + * + * @param roleId 角色主键Id。 + * @param userId 用户主键Id。 + * @return 移除成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean removeUserRole(Long roleId, Long userId) { + SysUserRole userRole = new SysUserRole(); + userRole.setRoleId(roleId); + userRole.setUserId(userId); + return sysUserRoleMapper.delete(new QueryWrapper<>(userRole)) == 1; + } + + /** + * 验证角色对象关联的数据是否都合法。 + * + * @param sysRole 当前操作的对象。 + * @param originalSysRole 原有对象。 + * @param menuIdListString 逗号分隔的menuId列表。 + * @return 验证结果。 + */ + @Override + public CallResult verifyRelatedData(SysRole sysRole, SysRole originalSysRole, String menuIdListString) { + JSONObject jsonObject = null; + if (StringUtils.isNotBlank(menuIdListString)) { + Set menuIdSet = Arrays.stream( + menuIdListString.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysMenuService.existAllPrimaryKeys(menuIdSet)) { + return CallResult.error("数据验证失败,存在不合法的菜单权限,请刷新后重试!"); + } + jsonObject = new JSONObject(); + jsonObject.put("menuIdSet", menuIdSet); + } + return CallResult.ok(jsonObject); + } + + /** + * 查询角色的权限资源地址列表。同时返回详细的分配路径。 + * + * @param roleId 角色Id。 + * @param url url过滤条件。 + * @return 包含从角色到权限资源的完整权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysPermListWithDetail(Long roleId, String url) { + return sysRoleMapper.getSysPermListWithDetail(roleId, url); + } + + /** + * 查询角色的权限字列表。同时返回详细的分配路径。 + * + * @param roleId 角色Id。 + * @param permCode 权限字名称过滤条件。 + * @return 包含从角色到权限字的权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysPermCodeListWithDetail(Long roleId, String permCode) { + return sysRoleMapper.getSysPermCodeListWithDetail(roleId, permCode); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysUserServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysUserServiceImpl.java new file mode 100644 index 00000000..a0c56cce --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/service/impl/SysUserServiceImpl.java @@ -0,0 +1,395 @@ +package com.flow.demo.webadmin.upms.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.webadmin.upms.service.*; +import com.flow.demo.webadmin.upms.dao.*; +import com.flow.demo.webadmin.upms.model.*; +import com.flow.demo.webadmin.upms.model.constant.SysUserStatus; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 用户管理数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("sysUserService") +public class SysUserServiceImpl extends BaseService implements SysUserService { + + @Autowired + private SysUserMapper sysUserMapper; + @Autowired + private SysUserRoleMapper sysUserRoleMapper; + @Autowired + private SysUserPostMapper sysUserPostMapper; + @Autowired + private SysDataPermUserMapper sysDataPermUserMapper; + @Autowired + private SysDeptService sysDeptService; + @Autowired + private SysRoleService sysRoleService; + @Autowired + private SysDataPermService sysDataPermService; + @Autowired + private SysPostService sysPostService; + @Autowired + private IdGeneratorWrapper idGenerator; + @Autowired + private PasswordEncoder passwordEncoder; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return sysUserMapper; + } + + /** + * 获取指定登录名的用户对象。 + * + * @param loginName 指定登录用户名。 + * @return 用户对象。 + */ + @Override + public SysUser getSysUserByLoginName(String loginName) { + SysUser filter = new SysUser(); + filter.setLoginName(loginName); + return sysUserMapper.selectOne(new QueryWrapper<>(filter)); + } + + /** + * 保存新增的用户对象。 + * + * @param user 新增的用户对象。 + * @param roleIdSet 用户角色Id集合。 + * @param deptPostIdSet 部门岗位Id集合。 + * @param dataPermIdSet 数据权限Id集合。 + * @return 新增后的用户对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public SysUser saveNew(SysUser user, Set roleIdSet, Set deptPostIdSet, Set dataPermIdSet) { + user.setUserId(idGenerator.nextLongId()); + user.setPassword(passwordEncoder.encode(user.getPassword())); + user.setUserStatus(SysUserStatus.STATUS_NORMAL); + user.setDeletedFlag(GlobalDeletedFlag.NORMAL); + MyModelUtil.fillCommonsForInsert(user); + sysUserMapper.insert(user); + if (CollectionUtils.isNotEmpty(deptPostIdSet)) { + for (Long deptPostId : deptPostIdSet) { + SysDeptPost deptPost = sysDeptService.getSysDeptPost(deptPostId); + SysUserPost userPost = new SysUserPost(); + userPost.setUserId(user.getUserId()); + userPost.setDeptPostId(deptPostId); + userPost.setPostId(deptPost.getPostId()); + sysUserPostMapper.insert(userPost); + } + } + if (CollectionUtils.isNotEmpty(roleIdSet)) { + for (Long roleId : roleIdSet) { + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(user.getUserId()); + userRole.setRoleId(roleId); + sysUserRoleMapper.insert(userRole); + } + } + if (CollectionUtils.isNotEmpty(dataPermIdSet)) { + for (Long dataPermId : dataPermIdSet) { + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + dataPermUser.setUserId(user.getUserId()); + sysDataPermUserMapper.insert(dataPermUser); + } + } + return user; + } + + /** + * 更新用户对象。 + * + * @param user 更新的用户对象。 + * @param originalUser 原有的用户对象。 + * @param roleIdSet 用户角色Id列表。 + * @param deptPostIdSet 部门岗位Id集合。 + * @param dataPermIdSet 数据权限Id集合。 + * @return 更新成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(SysUser user, SysUser originalUser, Set roleIdSet, Set deptPostIdSet, Set dataPermIdSet) { + user.setLoginName(originalUser.getLoginName()); + user.setPassword(originalUser.getPassword()); + MyModelUtil.fillCommonsForUpdate(user, originalUser); + UpdateWrapper uw = this.createUpdateQueryForNullValue(user, user.getUserId()); + if (sysUserMapper.update(user, uw) != 1) { + return false; + } + // 先删除原有的User-Post关联关系,再重新插入新的关联关系 + SysUserPost deletedUserPost = new SysUserPost(); + deletedUserPost.setUserId(user.getUserId()); + sysUserPostMapper.delete(new QueryWrapper<>(deletedUserPost)); + if (CollectionUtils.isNotEmpty(deptPostIdSet)) { + for (Long deptPostId : deptPostIdSet) { + SysDeptPost deptPost = sysDeptService.getSysDeptPost(deptPostId); + SysUserPost userPost = new SysUserPost(); + userPost.setUserId(user.getUserId()); + userPost.setDeptPostId(deptPostId); + userPost.setPostId(deptPost.getPostId()); + sysUserPostMapper.insert(userPost); + } + } + // 先删除原有的User-Role关联关系,再重新插入新的关联关系 + SysUserRole deletedUserRole = new SysUserRole(); + deletedUserRole.setUserId(user.getUserId()); + sysUserRoleMapper.delete(new QueryWrapper<>(deletedUserRole)); + if (CollectionUtils.isNotEmpty(roleIdSet)) { + for (Long roleId : roleIdSet) { + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(user.getUserId()); + userRole.setRoleId(roleId); + sysUserRoleMapper.insert(userRole); + } + } + // 先删除原有的DataPerm-User关联关系,在重新插入新的关联关系 + SysDataPermUser deletedDataPermUser = new SysDataPermUser(); + deletedDataPermUser.setUserId(user.getUserId()); + sysDataPermUserMapper.delete(new QueryWrapper<>(deletedDataPermUser)); + if (CollectionUtils.isNotEmpty(dataPermIdSet)) { + for (Long dataPermId : dataPermIdSet) { + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setDataPermId(dataPermId); + dataPermUser.setUserId(user.getUserId()); + sysDataPermUserMapper.insert(dataPermUser); + } + } + return true; + } + + /** + * 修改用户密码。 + * @param userId 用户主键Id。 + * @param newPass 新密码。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean changePassword(Long userId, String newPass) { + SysUser updatedUser = new SysUser(); + updatedUser.setUserId(userId); + updatedUser.setPassword(passwordEncoder.encode(newPass)); + return sysUserMapper.updateById(updatedUser) == 1; + } + + /** + * 删除指定数据。 + * + * @param userId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long userId) { + if (sysUserMapper.deleteById(userId) == 0) { + return false; + } + SysUserRole userRole = new SysUserRole(); + userRole.setUserId(userId); + sysUserRoleMapper.delete(new QueryWrapper<>(userRole)); + SysDataPermUser dataPermUser = new SysDataPermUser(); + dataPermUser.setUserId(userId); + sysDataPermUserMapper.delete(new QueryWrapper<>(dataPermUser)); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getSysUserListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getSysUserList(SysUser filter, String orderBy) { + return sysUserMapper.getSysUserList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getSysUserList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getSysUserListWithRelation(SysUser filter, String orderBy) { + List resultList = sysUserMapper.getSysUserList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 获取指定角色的用户列表。 + * + * @param roleId 角色主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + @Override + public List getSysUserListByRoleId(Long roleId, SysUser filter, String orderBy) { + return sysUserMapper.getSysUserListByRoleId(roleId, filter, orderBy); + } + + /** + * 获取不属于指定角色的用户列表。 + * + * @param roleId 角色主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + @Override + public List getNotInSysUserListByRoleId(Long roleId, SysUser filter, String orderBy) { + return sysUserMapper.getNotInSysUserListByRoleId(roleId, filter, orderBy); + } + + /** + * 获取指定数据权限的用户列表。 + * + * @param dataPermId 数据权限主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + @Override + public List getSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy) { + return sysUserMapper.getSysUserListByDataPermId(dataPermId, filter, orderBy); + } + + /** + * 获取不属于指定数据权限的用户列表。 + * + * @param dataPermId 数据权限主键Id。 + * @param filter 用户过滤对象。 + * @param orderBy 排序参数。 + * @return 用户列表。 + */ + @Override + public List getNotInSysUserListByDataPermId(Long dataPermId, SysUser filter, String orderBy) { + return sysUserMapper.getNotInSysUserListByDataPermId(dataPermId, filter, orderBy); + } + + /** + * 查询用户的权限资源地址列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param url url过滤条件。 + * @return 包含从用户到权限资源的完整权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysPermListWithDetail(Long userId, String url) { + return sysUserMapper.getSysPermListWithDetail(userId, url); + } + + /** + * 查询用户的权限字列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param permCode 权限字名称过滤条件。 + * @return 包含从用户到权限字的权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysPermCodeListWithDetail(Long userId, String permCode) { + return sysUserMapper.getSysPermCodeListWithDetail(userId, permCode); + } + + /** + * 查询用户的菜单列表。同时返回详细的分配路径。 + * + * @param userId 用户Id。 + * @param menuName 菜单名称过滤条件。 + * @return 包含从用户到菜单的权限分配路径信息的查询结果列表。 + */ + @Override + public List> getSysMenuListWithDetail(Long userId, String menuName) { + return sysUserMapper.getSysMenuListWithDetail(userId, menuName); + } + + /** + * 验证用户对象关联的数据是否都合法。 + * + * @param sysUser 当前操作的对象。 + * @param originalSysUser 原有对象。 + * @param roleIds 逗号分隔的角色Id列表字符串。 + * @param deptPostIds 逗号分隔的部门岗位Id列表字符串。 + * @param dataPermIds 逗号分隔的数据权限Id列表字符串。 + * @return 验证结果。 + */ + @Override + public CallResult verifyRelatedData( + SysUser sysUser, SysUser originalSysUser, String roleIds, String deptPostIds, String dataPermIds) { + JSONObject jsonObject = new JSONObject(); + if (StringUtils.isBlank(deptPostIds)) { + return CallResult.error("数据验证失败,用户的部门岗位数据不能为空!"); + } + Set deptPostIdSet = + Arrays.stream(deptPostIds.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysPostService.existAllPrimaryKeys(deptPostIdSet, sysUser.getDeptId())) { + return CallResult.error("数据验证失败,存在不合法的用户岗位,请刷新后重试!"); + } + jsonObject.put("deptPostIdSet", deptPostIdSet); + if (StringUtils.isBlank(roleIds)) { + return CallResult.error("数据验证失败,用户的角色数据不能为空!"); + } + Set roleIdSet = Arrays.stream( + roleIds.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysRoleService.existAllPrimaryKeys(roleIdSet)) { + return CallResult.error("数据验证失败,存在不合法的用户角色,请刷新后重试!"); + } + jsonObject.put("roleIdSet", roleIdSet); + if (StringUtils.isBlank(dataPermIds)) { + return CallResult.error("数据验证失败,用户的数据权限不能为空!"); + } + Set dataPermIdSet = Arrays.stream( + dataPermIds.split(",")).map(Long::valueOf).collect(Collectors.toSet()); + if (!sysDataPermService.existAllPrimaryKeys(dataPermIdSet)) { + return CallResult.error("数据验证失败,存在不合法的数据权限,请刷新后重试!"); + } + jsonObject.put("dataPermIdSet", dataPermIdSet); + //这里是基于字典的验证。 + if (this.needToVerify(sysUser, originalSysUser, SysUser::getDeptId) + && !sysDeptService.existId(sysUser.getDeptId())) { + return CallResult.error("数据验证失败,关联的用户部门Id并不存在,请刷新后重试!"); + } + return CallResult.ok(jsonObject); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDataPermDeptVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDataPermDeptVo.java new file mode 100644 index 00000000..92a85f63 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDataPermDeptVo.java @@ -0,0 +1,23 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +/** + * 数据权限与部门关联VO。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysDataPermDeptVo { + + /** + * 数据权限Id。 + */ + private Long dataPermId; + + /** + * 关联部门Id。 + */ + private Long deptId; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDataPermVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDataPermVo.java new file mode 100644 index 00000000..9c353b33 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDataPermVo.java @@ -0,0 +1,60 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +import java.util.*; + +/** + * 数据权限VO。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysDataPermVo { + + /** + * 数据权限Id。 + */ + private Long dataPermId; + + /** + * 显示名称。 + */ + private String dataPermName; + + /** + * 数据权限规则类型(0: 全部可见 1: 只看自己 2: 只看本部门 3: 本部门及子部门 4: 多部门及子部门 5: 自定义部门列表)。 + */ + private Integer ruleType; + + /** + * 部门Id列表(逗号分隔)。 + */ + private String deptIdListString; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 数据权限与部门关联对象列表。 + */ + private List> dataPermDeptList; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDeptPostVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDeptPostVo.java new file mode 100644 index 00000000..8bc7cb90 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDeptPostVo.java @@ -0,0 +1,33 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +/** + * 部门岗位VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysDeptPostVo { + + /** + * 部门岗位Id。 + */ + private Long deptPostId; + + /** + * 部门Id。 + */ + private Long deptId; + + /** + * 岗位Id。 + */ + private Long postId; + + /** + * 部门岗位显示名称。 + */ + private String postShowName; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDeptVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDeptVo.java new file mode 100644 index 00000000..aaef4ed9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysDeptVo.java @@ -0,0 +1,55 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * SysDeptVO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysDeptVo { + + /** + * 部门Id。 + */ + private Long deptId; + + /** + * 部门名称。 + */ + private String deptName; + + /** + * 显示顺序。 + */ + private Integer showOrder; + + /** + * 父部门Id。 + */ + private Long parentId; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 更新时间。 + */ + private Date updateTime; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysMenuVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysMenuVo.java new file mode 100644 index 00000000..2d6afe24 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysMenuVo.java @@ -0,0 +1,90 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +import java.util.*; + +/** + * 菜单VO。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysMenuVo { + + /** + * 菜单Id。 + */ + private Long menuId; + + /** + * 父菜单Id,目录菜单的父菜单为null + */ + private Long parentId; + + /** + * 菜单显示名称。 + */ + private String menuName; + + /** + * 菜单类型 (0: 目录 1: 菜单 2: 按钮 3: UI片段)。 + */ + private Integer menuType; + + /** + * 前端表单路由名称,仅用于menu_type为1的菜单类型。 + */ + private String formRouterName; + + /** + * 在线表单主键Id,仅用于在线表单绑定的菜单。 + */ + private Long onlineFormId; + + /** + * 在线表单菜单的权限控制类型,具体值可参考SysOnlineMenuPermType常量对象。 + */ + private Integer onlineMenuPermType; + + /** + * 仅用于在线表单的流程Id。 + */ + private Long onlineFlowEntryId; + + /** + * 菜单显示顺序 (值越小,排序越靠前)。 + */ + private Integer showOrder; + + /** + * 菜单图标。 + */ + private String icon; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 菜单与权限字关联对象列表。 + */ + private List> sysMenuPermCodeList; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermCodeVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermCodeVo.java new file mode 100644 index 00000000..fe409c2a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermCodeVo.java @@ -0,0 +1,70 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +import java.util.*; + +/** + * 权限字VO。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysPermCodeVo { + + /** + * 权限字Id。 + */ + private Long permCodeId; + + /** + * 权限字标识(一般为有含义的英文字符串)。 + */ + private String permCode; + + /** + * 上级权限字Id。 + */ + private Long parentId; + + /** + * 权限字类型(0: 表单 1: UI片段 2: 操作)。 + */ + private Integer permCodeType; + + /** + * 显示名称。 + */ + private String showName; + + /** + * 显示顺序(数值越小,越靠前)。 + */ + private Integer showOrder; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 权限字与权限资源关联对象列表。 + */ + private List> sysPermCodePermList; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermModuleVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermModuleVo.java new file mode 100644 index 00000000..7b025bda --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermModuleVo.java @@ -0,0 +1,65 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +import java.util.*; + +/** + * 权限资源模块VO。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysPermModuleVo { + + /** + * 权限模块Id。 + */ + private Long moduleId; + + /** + * 权限模块名称。 + */ + private String moduleName; + + /** + * 上级权限模块Id。 + */ + private Long parentId; + + /** + * 权限模块类型(0: 普通模块 1: Controller模块)。 + */ + private Integer moduleType; + + /** + * 权限模块在当前层级下的顺序,由小到大。 + */ + private Integer showOrder; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 权限资源对象列表。 + */ + private List sysPermList; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermVo.java new file mode 100644 index 00000000..b2177f22 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPermVo.java @@ -0,0 +1,70 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +import java.util.*; + +/** + * 权限资源VO。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysPermVo { + + /** + * 权限资源Id。 + */ + private Long permId; + + /** + * 权限资源名称。 + */ + private String permName; + + /** + * shiro格式的权限字,如(upms:sysUser:add)。 + */ + private String permCode; + + /** + * 权限所在的权限模块Id。 + */ + private Long moduleId; + + /** + * 关联的URL。 + */ + private String url; + + /** + * 权限在当前模块下的顺序,由小到大。 + */ + private Integer showOrder; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 模块Id的字典关联数据。 + */ + private Map moduleIdDictMap; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPostVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPostVo.java new file mode 100644 index 00000000..5bd47260 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysPostVo.java @@ -0,0 +1,61 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 岗位VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysPostVo { + + /** + * 岗位Id。 + */ + private Long postId; + + /** + * 岗位名称。 + */ + private String postName; + + /** + * 岗位层级,数值越小级别越高。 + */ + private Integer level; + + /** + * 是否领导岗位。 + */ + private Boolean leaderPost; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * postId 的多对多关联表数据对象,数据对应类型为SysDeptPostVo。 + */ + private Map sysDeptPost; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysRoleVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysRoleVo.java new file mode 100644 index 00000000..15ead111 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysRoleVo.java @@ -0,0 +1,50 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +import java.util.*; + +/** + * 角色VO。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysRoleVo { + + /** + * 角色Id。 + */ + private Long roleId; + + /** + * 角色名称。 + */ + private String roleName; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 角色与菜单关联对象列表。 + */ + private List> sysRoleMenuList; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysUserVo.java b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysUserVo.java new file mode 100644 index 00000000..34e7df51 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/java/com/flow/demo/webadmin/upms/vo/SysUserVo.java @@ -0,0 +1,102 @@ +package com.flow.demo.webadmin.upms.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.Map; +import java.util.List; + +/** + * SysUserVO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SysUserVo { + + /** + * 用户Id。 + */ + private Long userId; + + /** + * 登录用户名。 + */ + private String loginName; + + /** + * 用户显示名称。 + */ + private String showName; + + /** + * 用户部门Id。 + */ + private Long deptId; + + /** + * 用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)。 + */ + private Integer userType; + + /** + * 用户头像的Url。 + */ + private String headImageUrl; + + /** + * 用户状态(0: 正常 1: 锁定)。 + */ + private Integer userStatus; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 多对多用户岗位数据集合。 + */ + private List> sysUserPostList; + + /** + * 多对多用户角色数据集合。 + */ + private List> sysUserRoleList; + + /** + * 多对多用户数据权限数据集合。 + */ + private List> sysDataPermUserList; + + /** + * deptId 字典关联数据。 + */ + private Map deptIdDictMap; + + /** + * userType 常量字典关联数据。 + */ + private Map userTypeDictMap; + + /** + * userStatus 常量字典关联数据。 + */ + private Map userStatusDictMap; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/application.yml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/application.yml new file mode 100644 index 00000000..8dc8213c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/application.yml @@ -0,0 +1,279 @@ +logging: + level: + # 这里设置的日志级别优先于log4j2.xml文件Loggers中的日志级别。 + com.flow.demo: info + +server: + port: 8082 + tomcat: + uri-encoding: UTF-8 + threads: + max: 100 + min-spare: 10 + servlet: + encoding: + force: true + charset: UTF-8 + enabled: true + +# spring相关配置 +spring: + application: + name: application-webadmin + profiles: + active: dev + servlet: + multipart: + max-file-size: 50MB + max-request-size: 50MB + mvc: + converters: + preferred-json-mapper: fastjson + freemarker: + template-loader-path: classpath:/template/ + cache: false + charset: UTF-8 + check-template-location: true + content-type: text/html + expose-request-attributes: false + expose-session-attributes: false + request-context-attribute: request + suffix: .ftl + +flowable: + async-executor-activate: false + database-schema-update: false + +mybatis-plus: + mapper-locations: classpath:com/flow/demo/webadmin/*/dao/mapper/*Mapper.xml,com/flow/demo/common/log/dao/mapper/*Mapper.xml,com/flow/demo/common/online/dao/mapper/*Mapper.xml,com/flow/demo/common/flow/dao/mapper/*Mapper.xml + type-aliases-package: com.flow.demo.webadmin.*.model,com.flow.demo.common.log.model,com.flow.demo.common.online.model,com.flow.demo.common.flow.model + global-config: + db-config: + logic-delete-value: -1 + logic-not-delete-value: 1 + +# 自动分页的配置 +pagehelper: + helperDialect: mysql + reasonable: true + supportMethodsArguments: false + params: count=countSql + +# 存储session数据的Redis,所有服务均需要,因此放到公共配置中。 +# 根据实际情况,该Redis也可以用于存储其他数据。 +redis: + # redisson的配置。每个服务可以自己的配置文件中覆盖此选项。 + redisson: + # 如果该值为false,系统将不会创建RedissionClient的bean。 + enabled: true + # mode的可用值为,single/cluster/sentinel/master-slave + mode: single + # single: 单机模式 + # address: redis://localhost:6379 + # cluster: 集群模式 + # 每个节点逗号分隔,同时每个节点前必须以redis://开头。 + # address: redis://localhost:6379,redis://localhost:6378,... + # sentinel: + # 每个节点逗号分隔,同时每个节点前必须以redis://开头。 + # address: redis://localhost:6379,redis://localhost:6378,... + # master-slave: + # 每个节点逗号分隔,第一个为主节点,其余为从节点。同时每个节点前必须以redis://开头。 + # address: redis://localhost:6379,redis://localhost:6378,... + address: redis://localhost:6379 + # 链接超时,单位毫秒。 + timeout: 6000 + # 单位毫秒。分布式锁的超时检测时长。 + # 如果一次锁内操作超该毫秒数,或在释放锁之前异常退出,Redis会在该时长之后主动删除该锁使用的key。 + lockWatchdogTimeout: 60000 + # redis 密码,空可以不填。 + password: + pool: + # 连接池数量。 + poolSize: 20 + # 连接池中最小空闲数量。 + minIdle: 5 + +common-online: + # 注意不要以反斜杠(/)结尾。 + operationUrlPrefix: /admin/online + # 在线表单业务数据上传资源路径 + uploadFileBaseDir: ./zz-resource/upload-files/online + # 如果为false,OnlineOperationController中的接口将不能使用。 + operationEnabled: true + +common-online-api: + # 注意不要以反斜杠(/)结尾。 + urlPrefix: /admin/online + # 下面的url列表,请保持反斜杠(/)结尾。 + viewUrlList: + - ${common-online.operationUrlPrefix}/onlineOperation/viewByDatasourceId/ + - ${common-online.operationUrlPrefix}/onlineOperation/viewByOneToManyRelationId/ + - ${common-online.operationUrlPrefix}/onlineOperation/listByDatasourceId/ + - ${common-online.operationUrlPrefix}/onlineOperation/listByOneToManyRelationId/ + - ${common-online.operationUrlPrefix}/onlineOperation/downloadDatasource/ + - ${common-online.operationUrlPrefix}/onlineOperation/downloadOneToManyRelation/ + editUrlList: + - ${common-online.operationUrlPrefix}/onlineOperation/addDatasource/ + - ${common-online.operationUrlPrefix}/onlineOperation/addOneToManyRelation/ + - ${common-online.operationUrlPrefix}/onlineOperation/updateDatasource/ + - ${common-online.operationUrlPrefix}/onlineOperation/updateOneToManyRelation/ + - ${common-online.operationUrlPrefix}/onlineOperation/deleteDatasource/ + - ${common-online.operationUrlPrefix}/onlineOperation/deleteOneToManyRelation/ + - ${common-online.operationUrlPrefix}/onlineOperation/uploadDatasource/ + - ${common-online.operationUrlPrefix}/onlineOperation/uploadOneToManyRelation/ + +common-flow: + # 请慎重修改urlPrefix的缺省配置,注意不要以反斜杠(/)结尾。如必须修改其他路径,请同步修改数据库脚本。 + urlPrefix: /admin/flow + +datafilter: + tenant: + # 对于单体服务,该值始终为false。 + enabled: false + dataperm: + enabled: true + # 在拼接数据权限过滤的SQL时,我们会用到sys_dept_relation表,该表的前缀由此配置项指定。 + # 如果没有前缀,请使用 "" 。 + deptRelationTablePrefix: zz_ + +# 暴露监控端点 +management: + endpoints: + web: + exposure: + include: '*' + jmx: + exposure: + include: '*' + endpoint: + # 与中间件相关的健康详情也会被展示 + health: + show-details: always + configprops: + # 在/actuator/configprops中,所有包含password的配置,将用 * 隐藏。 + # 如果不想隐藏任何配置项的值,可以直接使用如下被注释的空值。 + # keys-to-sanitize: + keys-to-sanitize: password + server: + servlet: + context-path: "/" + +# 开发数据库相关配置 +--- +spring: + profiles: dev + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + main: + url: jdbc:mysql://localhost:3306/zzdemo-online?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai + username: root + password: 123456 + driver-class-name: com.mysql.cj.jdbc.Driver + name: application-webadmin + initialSize: 10 + minIdle: 10 + maxActive: 50 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + poolPreparedStatements: true + maxPoolPreparedStatementPerConnectionSize: 20 + maxOpenPreparedStatements: 20 + validationQuery: SELECT 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + filters: stat,wall + useGlobalDataSourceStat: true + web-stat-filter: + enabled: true + url-pattern: /* + exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/actuator/*" + stat-view-servlet: + enabled: true + urlPattern: /druid/* + resetEnable: true + +application: + # Jwt令牌加密的签名值。该值的长度要超过10个字符(过短会报错)。 + tokenSigningKey: DemoFlow-signing-key + # Jwt令牌在Http Header中的键名称。 + tokenHeaderKey: Authorization + # Jwt令牌刷新后在Http Header中的键名称。 + refreshedTokenHeaderKey: RefreshedToken + # Jwt令牌过期时间(毫秒)。 + expiration: 72000000 + # 初始化密码。 + defaultUserPassword: 123456 + # 缺省的文件上传根目录。 + uploadFileBaseDir: ./zz-resource/upload-files/app + # 跨域的IP(http://192.168.10.10:8086)白名单列表,多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。 + credentialIpList: "*" + # Session的用户和数据权限在Redis中的过期时间(秒)。 + sessionExpiredSeconds: 86400 + +sequence: + # Snowflake 分布式Id生成算法所需的WorkNode参数值。 + snowflakeWorkNode: 1 + +# 发布数据库相关配置 +--- +spring: + profiles: product + datasource: + type: com.alibaba.druid.pool.DruidDataSource + druid: + main: + url: jdbc:mysql://localhost:3306/zzdemo-online?characterEncoding=utf8&useSSL=true&serverTimezone=Asia/Shanghai + username: root + password: 123456 + driver-class-name: com.mysql.cj.jdbc.Driver + name: application-webadmin + initialSize: 10 + minIdle: 10 + maxActive: 50 + maxWait: 60000 + timeBetweenEvictionRunsMillis: 60000 + minEvictableIdleTimeMillis: 300000 + poolPreparedStatements: true + maxPoolPreparedStatementPerConnectionSize: 20 + maxOpenPreparedStatements: 20 + validationQuery: SELECT 'x' + testWhileIdle: true + testOnBorrow: false + testOnReturn: false + connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000 + filters: stat,wall + useGlobalDataSourceStat: true + web-stat-filter: + enabled: true + url-pattern: /* + exclusions: "*.js,*.gif,*.jpg,*.bmp,*.png,*.css,*.ico,/druid/*,/actuator/*" + stat-view-servlet: + enabled: true + urlPattern: /druid/* + resetEnable: true + +application: + # Jwt令牌加密的签名值。该值的长度要超过10个字符(过短会报错)。 + tokenSigningKey: DemoFlow-signing-key + # Jwt令牌在Http Header中的键名称。 + tokenHeaderKey: Authorization + # Jwt令牌刷新后在Http Header中的键名称。 + refreshedTokenHeaderKey: RefreshedToken + # Jwt令牌过期时间(毫秒)。 + expiration: 72000000 + # 初始化密码。 + defaultUserPassword: 123456 + # 缺省的文件上传根目录。 + uploadFileBaseDir: ./zz-resource/upload-files/app + # 跨域的IP(http://192.168.10.10:8086)白名单列表,多个IP之间逗号分隔(* 表示全部信任,空白表示禁用跨域信任)。 + credentialIpList: "*" + # Session的用户和数据权限在Redis中的过期时间(秒)。 + sessionExpiredSeconds: 86400 + +sequence: + # Snowflake 分布式Id生成算法所需的WorkNode参数值。 + snowflakeWorkNode: 1 \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/log4j2.xml b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/log4j2.xml new file mode 100644 index 00000000..e62fa5f5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/log4j2.xml @@ -0,0 +1,86 @@ + + + + + + + + + + ./zzlogs/application-webadmin + + ./zzlogs/application-webadmin/backup + + info + + + + + + + + [%-5p] [%d{YYYY-MM-dd HH:mm:ss}] [%t] ==> %msg%n + + + [%-5p] [%d{YYYY-MM-dd HH:mm:ss}] T:[%X{traceId}] S:[%X{sessionId}] U:[%X{userId}] [%t] ==> %msg%n + + + 31 + + 20M + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/template/views/print_error.ftl b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/template/views/print_error.ftl new file mode 100644 index 00000000..af8b36a7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/application-webadmin/src/main/resources/template/views/print_error.ftl @@ -0,0 +1,329 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
天津公安警官职业学院2017—2018学年度第一学期课程表
班 级星期一星期二星期三星期四星期五
第1节第2节第3节第1节第2节第3节第1节第2节第3节第1节第2节第3节第1节第2节
16 级 刑 事 技 术 班 课程刑法自习刑事图像民 法(选修)派出所工作刑事图像法医学派出所工作法医学国内安全保卫体能自习刑事技术总论刑法
自习自习自习
教师曾岚陈磊邵刚杨丽伟陈磊于辉杨丽伟于辉朱学强张付海王 伟(刑技)曾岚
   
教室206206206206206206206206206操场206206
   
16 级 刑 事 侦 查 课程自习侦查措施经济案件侦查公安信息化公安信息化刑法体能自习痕迹检验刑法国内安全保卫经济案件侦查痕迹检验民 法(选修)
侦查措施
教师徐宏涛张静赵晓松赵晓松王骏强张付海郭海川王骏强朱学强张静郭海川邵刚
徐宏涛
教室2022023号机房3号机房202操场202202202202202202
16 级 治 安 管 理 班 课程刑事技术体能刑事技术治安秩序管理刑事侦查概论刑法群众工作与纠纷调解群众工作与纠纷调解公共关系(选修)刑事侦查概论刑法自习自习自习
q
教师郭海川 韩易浦张付海郭海川 韩易浦翟政亮邵妍薛强刘晓鹏刘晓鹏尚欣邵妍薛强
翟政亮
教室218操场218218218218218218218218218
16 网 络 安 全 监 察 1 班课程应用写作数据库系统应用周二中午:计算机安全管理及实用技术刑事诉讼法周一中午:数据库系统应用民法体育VB语言程序设计选修VB语言程序设计刑事诉讼法选修应用写作犯罪心理
民法犯罪心理
教师关利杨斌赵晓松王伟杨斌李静程军赵伟赵伟王伟关利张学林
李静张学林
教室东阶梯2号机房主楼2011012号机房101操场3号机房3号机房101东阶梯主楼201
主楼201
注:1、课程一栏中有两科次的,上面的课程单周上课,下面的课程双周上课。2、每天上课时间:上午第1节8:30至9:55;第2节10:15至11:40;中午上课时间12:30至13:55;下午第3节14:00至15:25。
+ + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/pom.xml new file mode 100644 index 00000000..eeb54b02 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/pom.xml @@ -0,0 +1,109 @@ + + + + com.flow.demo + common + 1.0.0 + + 4.0.0 + + common-core + 1.0.0 + common-core + jar + + + + + com.google.guava + guava + + + org.apache.commons + commons-lang3 + + + commons-codec + commons-codec + + + commons-io + commons-io + + + commons-fileupload + commons-fileupload + + + org.apache.httpcomponents + httpclient + + + joda-time + joda-time + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + org.apache.commons + commons-csv + ${common-csv.version} + + + cn.hutool + hutool-all + ${hutool.version} + + + io.jsonwebtoken + jjwt + ${jjwt.version} + + + com.alibaba + fastjson + ${fastjson.version} + + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + + + cn.jimmyshi + bean-query + ${bean.query.version} + + + + org.apache.poi + poi-ooxml + ${poi-ooxml.version} + + + + mysql + mysql-connector-java + runtime + + + com.alibaba + druid-spring-boot-starter + ${druid.version} + + + com.baomidou + mybatis-plus-boot-starter + ${mybatisplus.version} + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper.version} + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/advice/MyControllerAdvice.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/advice/MyControllerAdvice.java new file mode 100644 index 00000000..5ee612f2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/advice/MyControllerAdvice.java @@ -0,0 +1,30 @@ +package com.flow.demo.common.core.advice; + +import org.springframework.beans.propertyeditors.CustomDateEditor; +import org.springframework.web.bind.WebDataBinder; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.InitBinder; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Controller的环绕拦截类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@ControllerAdvice +public class MyControllerAdvice { + + /** + * 转换前端传入的日期变量参数为指定格式。 + * + * @param binder 数据绑定参数。 + */ + @InitBinder + public void initBinder(WebDataBinder binder) { + binder.registerCustomEditor(Date.class, + new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"), false)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/advice/MyExceptionHandler.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/advice/MyExceptionHandler.java new file mode 100644 index 00000000..426b87f4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/advice/MyExceptionHandler.java @@ -0,0 +1,141 @@ +package com.flow.demo.common.core.advice; + +import com.flow.demo.common.core.exception.*; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.ResponseResult; +import com.flow.demo.common.core.util.ContextUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.ibatis.exceptions.PersistenceException; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DuplicateKeyException; +import org.springframework.dao.PermissionDeniedDataAccessException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.concurrent.TimeoutException; + +/** + * 业务层的异常处理类,这里只是给出最通用的Exception的捕捉,今后可以根据业务需要, + * 用不同的函数,处理不同类型的异常。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestControllerAdvice("com.flow.demo") +public class MyExceptionHandler { + + /** + * 通用异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = Exception.class) + public ResponseResult exceptionHandle(Exception ex, HttpServletRequest request) { + log.error("Unhandled exception from URL [" + request.getRequestURI() + "]", ex); + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + return ResponseResult.error(ErrorCodeEnum.UNHANDLED_EXCEPTION, ex.getMessage()); + } + + /** + * 无效的实体对象异常。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = InvalidDataModelException.class) + public ResponseResult invalidDataModelExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("InvalidDataModelException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.INVALID_DATA_MODEL); + } + + /** + * 无效的实体对象字段异常。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = InvalidDataFieldException.class) + public ResponseResult invalidDataFieldExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("InvalidDataFieldException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.INVALID_DATA_FIELD); + } + + /** + * 无效类字段异常。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = InvalidClassFieldException.class) + public ResponseResult invalidClassFieldExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("InvalidClassFieldException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.INVALID_CLASS_FIELD); + } + + /** + * 重复键异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = DuplicateKeyException.class) + public ResponseResult duplicateKeyExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("DuplicateKeyException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.DUPLICATED_UNIQUE_KEY); + } + + /** + * 数据访问失败异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = DataAccessException.class) + public ResponseResult dataAccessExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("DataAccessException exception from URL [" + request.getRequestURI() + "]", ex); + if (ex.getCause() instanceof PersistenceException + && ex.getCause().getCause() instanceof PermissionDeniedDataAccessException) { + return ResponseResult.error(ErrorCodeEnum.DATA_PERM_ACCESS_FAILED); + } + return ResponseResult.error(ErrorCodeEnum.DATA_ACCESS_FAILED); + } + + /** + * 操作不存在或已逻辑删除数据的异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = NoDataAffectException.class) + public ResponseResult noDataEffectExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("NoDataAffectException exception from URL [" + request.getRequestURI() + "]", ex); + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + + /** + * Redis缓存访问异常处理方法。 + * + * @param ex 异常对象。 + * @param request http请求。 + * @return 应答对象。 + */ + @ExceptionHandler(value = RedisCacheAccessException.class) + public ResponseResult redisCacheAccessExceptionHandle(Exception ex, HttpServletRequest request) { + log.error("RedisCacheAccessException exception from URL [" + request.getRequestURI() + "]", ex); + if (ex.getCause() instanceof TimeoutException) { + return ResponseResult.error(ErrorCodeEnum.REDIS_CACHE_ACCESS_TIMEOUT); + } + return ResponseResult.error(ErrorCodeEnum.REDIS_CACHE_ACCESS_STATE_ERROR); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DeptFilterColumn.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DeptFilterColumn.java new file mode 100644 index 00000000..a9293921 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DeptFilterColumn.java @@ -0,0 +1,16 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记数据权限中基于DeptId进行过滤的字段。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DeptFilterColumn { + +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DisableDataFilter.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DisableDataFilter.java new file mode 100644 index 00000000..fd8916ec --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DisableDataFilter.java @@ -0,0 +1,17 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 作为DisableDataFilterAspect的切点。 + * 该注解仅能标记在方法上,方法内所有的查询语句,均不会被Mybatis拦截器过滤数据。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DisableDataFilter { + +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DisableTenantFilter.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DisableTenantFilter.java new file mode 100644 index 00000000..6b5e6058 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/DisableTenantFilter.java @@ -0,0 +1,28 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 仅用于微服务的多租户项目。 + * 用于注解DAO层Mapper对象的租户过滤规则。被包含的方法将不会进行租户Id的过滤。 + * 对于tk mapper和mybatis plus中的内置方法,可以直接指定方法名即可,如:selectOne。 + * 需要说明的是,在大多数场景下,只要在实体对象中指定了租户Id字段,基于该主表的绝大部分增删改操作, + * 都需要经过租户Id过滤,仅当查询非常复杂,或者主表不在SQL语句之中的时候,可以通过该注解禁用该SQL, + * 并根据需求通过手动的方式实现租户过滤。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface DisableTenantFilter { + + /** + * 包含的方法名称数组。该值不能为空,因为如想取消所有方法的租户过滤, + * 可以通过在实体对象中不指定租户Id字段注解的方式实现。 + * + * @return 被包括的方法名称数组。 + */ + String[] includeMethodName(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/EnableDataPerm.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/EnableDataPerm.java new file mode 100644 index 00000000..7de7a959 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/EnableDataPerm.java @@ -0,0 +1,27 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 用于注解DAO层Mapper对象的数据权限规则。 + * 由于框架使用了tk.mapper,所以并非所有的Mapper接口均在当前Mapper对象中定义,有一部分被tk.mapper封装,如selectAll等。 + * 如果需要排除tk.mapper中的方法,可以直接使用tk.mapper基类所声明的方法名称即可。 + * 另外,比较特殊的场景是,因为tk.mapper是通用框架,所以同样的selectAll方法,可以获取不同的数据集合,因此在service中如果 + * 出现两个不同的方法调用Mapper的selectAll方法,但是一个需要参与过滤,另外一个不需要参与,那么就需要修改当前类的Mapper方法, + * 将其中一个方法重新定义一个具体的接口方法,并重新设定其是否参与数据过滤。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface EnableDataPerm { + + /** + * 排除的方法名称数组。如果为空,所有的方法均会被Mybaits拦截注入权限过滤条件。 + * + * @return 被排序的方法名称数据。 + */ + String[] excluseMethodName() default {}; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/JobUpdateTimeColumn.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/JobUpdateTimeColumn.java new file mode 100644 index 00000000..c9a77cde --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/JobUpdateTimeColumn.java @@ -0,0 +1,16 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记更新字段。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface JobUpdateTimeColumn { + +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyDataSource.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyDataSource.java new file mode 100644 index 00000000..9ba15833 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyDataSource.java @@ -0,0 +1,21 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记Service所依赖的数据源类型。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MyDataSource { + + /** + * 标注的数据源类型 + * @return 当前标注的数据源类型。 + */ + int value(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyDataSourceResolver.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyDataSourceResolver.java new file mode 100644 index 00000000..1bbdc853 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyDataSourceResolver.java @@ -0,0 +1,29 @@ +package com.flow.demo.common.core.annotation; + +import com.flow.demo.common.core.util.DataSourceResolver; + +import java.lang.annotation.*; + +/** + * 基于自定义解析规则的多数据源注解。主要用于标注Service的实现类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface MyDataSourceResolver { + + /** + * 多数据源路由键解析接口的Class。 + * @return 多数据源路由键解析接口的Class。 + */ + Class resolver(); + + /** + * DataSourceResolver.resovle方法的入参。 + * @return DataSourceResolver.resovle方法的入参。 + */ + String arg() default ""; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyRequestBody.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyRequestBody.java new file mode 100644 index 00000000..ec4e7186 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/MyRequestBody.java @@ -0,0 +1,31 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 标记Controller中的方法参数,参数解析器会根据该注解将请求中的JSON数据,映射到参数中的绑定字段。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target(ElementType.PARAMETER) +@Retention(RetentionPolicy.RUNTIME) +public @interface MyRequestBody { + + /** + * 是否必须出现的参数。 + */ + boolean required() default false; + /** + * 解析时用到的JSON的key。 + */ + String value() default ""; + /** + * 集合元素的ClassType。只有在接口参数为List的时候,需要把E的class传入。 + * 缺省值Class.class表示没有设置。 + */ + Class elementType() default Class.class; +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/NoAuthInterface.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/NoAuthInterface.java new file mode 100644 index 00000000..9ae83b4f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/NoAuthInterface.java @@ -0,0 +1,15 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记无需Token验证的接口 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.METHOD, ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface NoAuthInterface { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationConstDict.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationConstDict.java new file mode 100644 index 00000000..c15ffd50 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationConstDict.java @@ -0,0 +1,29 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标识Model和常量字典之间的关联关系。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationConstDict { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联的常量字典的Class对象。 + * + * @return 关联的常量字典的Class对象。 + */ + Class constantDictClass(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationDict.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationDict.java new file mode 100644 index 00000000..f479a48f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationDict.java @@ -0,0 +1,70 @@ +package com.flow.demo.common.core.annotation; + +import com.flow.demo.common.core.object.DummyClass; + +import java.lang.annotation.*; + +/** + * 标识Model之间的字典关联关系。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationDict { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联Model对象的关联Name字段名称。 + * + * @return 被关联Model对象的关联Name字段名称。 + */ + String slaveNameField(); + + /** + * 被关联的本地Service对象名称。 + * 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName() default ""; + + /** + * 被关联的本地Service对象CLass类型。 + * + * @return 被关联的本地Service对象CLass类型。 + */ + Class slaveServiceClass() default DummyClass.class; + + /** + * 在同一个实体对象中,如果有一对一关联和字典关联,都是基于相同的主表字段,并关联到 + * 相同关联表的同一关联字段时,可以在字典关联的注解中引用被一对一注解标准的对象属性。 + * 从而在数据整合时,当前字典的数据可以直接取自"equalOneToOneRelationField"指定 + * 的字段,从而避免一次没必要的数据库查询操作,提升了加载显示的效率。 + * + * @return 与该字典字段引用关系完全相同的一对一关联属性名称。 + */ + String equalOneToOneRelationField() default ""; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationManyToMany.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationManyToMany.java new file mode 100644 index 00000000..c799f736 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationManyToMany.java @@ -0,0 +1,38 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 标注多对多的Model关系。 + * 重要提示:由于多对多关联表数据,很多时候都不需要跟随主表数据返回,所以该注解不会在 + * 生成的时候自动添加到实体类字段上,需要的时候,用户可自行手动添加。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationManyToMany { + + /** + * 多对多中间表的Mapper对象名称。 + * + * @return 被关联的本地Service对象名称。 + */ + String relationMapperName(); + + /** + * 多对多关联表Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class relationModelClass(); + + /** + * 多对多关联表Model对象中与主表关联的Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String relationMasterIdField(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationManyToManyAggregation.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationManyToManyAggregation.java new file mode 100644 index 00000000..2aadeb16 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationManyToManyAggregation.java @@ -0,0 +1,95 @@ +package com.flow.demo.common.core.annotation; + +import com.flow.demo.common.core.object.DummyClass; + +import java.lang.annotation.*; + +/** + * 主要用于多对多的Model关系。标注通过从表关联字段或者关联表关联字段计算主表聚合计算字段的规则。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationManyToManyAggregation { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联的本地Service对象名称。 + * 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName() default ""; + + /** + * 被关联的本地Service对象CLass类型。 + * + * @return 被关联的本地Service对象CLass类型。 + */ + Class slaveServiceClass() default DummyClass.class; + + /** + * 多对多从表Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class slaveModelClass(); + + /** + * 多对多从表Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 多对多关联表Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class relationModelClass(); + + /** + * 多对多关联表Model对象中与主表关联的Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String relationMasterIdField(); + + /** + * 多对多关联表Model对象中与从表关联的Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String relationSlaveIdField(); + + /** + * 聚合计算所在的Model。 + * + * @return 聚合计算所在Model的Class。 + */ + Class aggregationModelClass(); + + /** + * 聚合类型。具体数值参考AggregationType对象。 + * + * @return 聚合类型。 + */ + int aggregationType(); + + /** + * 聚合计算所在Model的字段名称。 + * + * @return 聚合计算所在Model的字段名称。 + */ + String aggregationField(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToMany.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToMany.java new file mode 100644 index 00000000..c7056e1e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToMany.java @@ -0,0 +1,53 @@ +package com.flow.demo.common.core.annotation; + +import com.flow.demo.common.core.object.DummyClass; + +import java.lang.annotation.*; + +/** + * 标识Model之间的一对多关联关系。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationOneToMany { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联的本地Service对象名称。 + * 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName() default ""; + + /** + * 被关联的本地Service对象CLass类型。 + * + * @return 被关联的本地Service对象CLass类型。 + */ + Class slaveServiceClass() default DummyClass.class; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToManyAggregation.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToManyAggregation.java new file mode 100644 index 00000000..d896e8c1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToManyAggregation.java @@ -0,0 +1,67 @@ +package com.flow.demo.common.core.annotation; + +import com.flow.demo.common.core.object.DummyClass; + +import java.lang.annotation.*; + +/** + * 主要用于一对多的Model关系。标注通过从表关联字段计算主表聚合计算字段的规则。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationOneToManyAggregation { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联的本地Service对象名称。 + * 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName() default ""; + + /** + * 被关联的本地Service对象CLass类型。 + * + * @return 被关联的本地Service对象CLass类型。 + */ + Class slaveServiceClass() default DummyClass.class; + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联Model对象中参与计算的聚合类型。具体数值参考AggregationType对象。 + * + * @return 被关联Model对象中参与计算的聚合类型。 + */ + int aggregationType(); + + /** + * 被关联Model对象中参与聚合计算的字段名称。 + * + * @return 被关联Model对象中参与计算字段的名称。 + */ + String aggregationField(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToOne.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToOne.java new file mode 100644 index 00000000..79e12472 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/RelationOneToOne.java @@ -0,0 +1,60 @@ +package com.flow.demo.common.core.annotation; + +import com.flow.demo.common.core.object.DummyClass; + +import java.lang.annotation.*; + +/** + * 标识Model之间的一对一关联关系。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RelationOneToOne { + + /** + * 当前对象的关联Id字段名称。 + * + * @return 当前对象的关联Id字段名称。 + */ + String masterIdField(); + + /** + * 被关联Model对象的Class对象。 + * + * @return 被关联Model对象的Class对象。 + */ + Class slaveModelClass(); + + /** + * 被关联Model对象的关联Id字段名称。 + * + * @return 被关联Model对象的关联Id字段名称。 + */ + String slaveIdField(); + + /** + * 被关联的本地Service对象名称。 + * 该参数的优先级高于 slaveService(),如果定义了该值,会优先使用加载service的bean对象。 + * + * @return 被关联的本地Service对象名称。 + */ + String slaveServiceName() default ""; + + /** + * 被关联的本地Service对象CLass类型。 + * + * @return 被关联的本地Service对象CLass类型。 + */ + Class slaveServiceClass() default DummyClass.class; + + /** + * 在一对一关联时,是否加载从表的字典关联。 + * + * @return 是否加载从表的字典关联。true关联,false则只返回从表自身数据。 + */ + boolean loadSlaveDict() default true; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/TenantFilterColumn.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/TenantFilterColumn.java new file mode 100644 index 00000000..783dde28 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/TenantFilterColumn.java @@ -0,0 +1,16 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记通过租户Id进行过滤的字段。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface TenantFilterColumn { + +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/UploadFlagColumn.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/UploadFlagColumn.java new file mode 100644 index 00000000..efdf3ee3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/UploadFlagColumn.java @@ -0,0 +1,24 @@ +package com.flow.demo.common.core.annotation; + +import com.flow.demo.common.core.upload.UploadStoreTypeEnum; + +import java.lang.annotation.*; + +/** + * 用于标记支持数据上传和下载的字段。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface UploadFlagColumn { + + /** + * 上传数据存储类型。 + * + * @return 上传数据存储类型。 + */ + UploadStoreTypeEnum storeType(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/UserFilterColumn.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/UserFilterColumn.java new file mode 100644 index 00000000..90836fdd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/annotation/UserFilterColumn.java @@ -0,0 +1,16 @@ +package com.flow.demo.common.core.annotation; + +import java.lang.annotation.*; + +/** + * 主要用于标记数据权限中基于UserId进行过滤的字段。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface UserFilterColumn { + +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DataSourceAspect.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DataSourceAspect.java new file mode 100644 index 00000000..88b91175 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DataSourceAspect.java @@ -0,0 +1,48 @@ +package com.flow.demo.common.core.aop; + +import com.flow.demo.common.core.annotation.MyDataSource; +import com.flow.demo.common.core.config.DataSourceContextHolder; +import lombok.extern.slf4j.Slf4j; +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.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * 多数据源AOP切面处理类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Aspect +@Component +@Order(1) +@Slf4j +public class DataSourceAspect { + + /** + * 所有配置MyDataSource注解的Service实现类。 + */ + @Pointcut("execution(public * com.flow.demo..service..*(..)) " + + "&& @target(com.flow.demo.common.core.annotation.MyDataSource)") + public void datasourcePointCut() { + // 空注释,避免sonar警告 + } + + @Around("datasourcePointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + Class clazz = point.getTarget().getClass(); + MyDataSource ds = clazz.getAnnotation(MyDataSource.class); + // 通过判断 DataSource 中的值来判断当前方法应用哪个数据源 + Integer originalType = DataSourceContextHolder.setDataSourceType(ds.value()); + log.debug("set datasource is " + ds.value()); + try { + return point.proceed(); + } finally { + DataSourceContextHolder.unset(originalType); + log.debug("unset datasource is " + originalType); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DataSourceResolveAspect.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DataSourceResolveAspect.java new file mode 100644 index 00000000..9589f156 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DataSourceResolveAspect.java @@ -0,0 +1,62 @@ +package com.flow.demo.common.core.aop; + +import com.flow.demo.common.core.annotation.MyDataSourceResolver; +import com.flow.demo.common.core.util.DataSourceResolver; +import com.flow.demo.common.core.config.DataSourceContextHolder; +import com.flow.demo.common.core.util.ApplicationContextHolder; +import lombok.extern.slf4j.Slf4j; +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.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * 基于自定义解析规则的多数据源AOP切面处理类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Aspect +@Component +@Order(1) +@Slf4j +public class DataSourceResolveAspect { + + private final Map, DataSourceResolver> resolverMap = new HashMap<>(); + + /** + * 所有配置 MyDataSource 注解的Service。 + */ + @Pointcut("execution(public * com.flow.demo..service..*(..)) " + + "&& @target(com.flow.demo.common.core.annotation.MyDataSourceResolver)") + public void datasourceResolverPointCut() { + // 空注释,避免sonar警告 + } + + @Around("datasourceResolverPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + Class clazz = point.getTarget().getClass(); + MyDataSourceResolver dsr = clazz.getAnnotation(MyDataSourceResolver.class); + Class resolverClass = dsr.resolver(); + DataSourceResolver resolver = resolverMap.get(resolverClass); + if (resolver == null) { + resolver = ApplicationContextHolder.getBean(resolverClass); + resolverMap.put(resolverClass, resolver); + } + int type = resolver.resolve(dsr.arg(), point.getArgs()); + // 通过判断 DataSource 中的值来判断当前方法应用哪个数据源 + Integer originalType = DataSourceContextHolder.setDataSourceType(type); + log.debug("set datasource is " + type); + try { + return point.proceed(); + } finally { + DataSourceContextHolder.unset(originalType); + log.debug("unset datasource is " + originalType); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DictCacheSyncAspect.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DictCacheSyncAspect.java new file mode 100644 index 00000000..ad5ee152 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/aop/DictCacheSyncAspect.java @@ -0,0 +1,64 @@ +package com.flow.demo.common.core.aop; + +import com.flow.demo.common.core.base.service.BaseDictService; +import lombok.extern.slf4j.Slf4j; +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.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.io.Serializable; + +/** + * 字典缓存同步的AOP。该AOP的优先级必须比事务切面的优先级高,因此会在事务外执行该切面的代码。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Aspect +@Component +@Order(Ordered.LOWEST_PRECEDENCE - 1) +@Slf4j +public class DictCacheSyncAspect { + + /** + * BaseDictService 字典服务父类中的字典数据增删改的方法。 + */ + @Pointcut("execution(public * com.flow.demo..BaseDictService.saveNew (..)) " + + "|| execution(public * com.flow.demo..BaseDictService.update (..)) " + + "|| execution(public * com.flow.demo..BaseDictService.remove (..))" ) + public void baseDictServicePointCut() { + // 空注释,避免sonar警告 + } + + @SuppressWarnings("unchecked") + @Around("baseDictServicePointCut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + String methodName = joinPoint.getSignature().getName(); + Object arg = joinPoint.getArgs()[0]; + if ("saveNew".equals(methodName)) { + Object data = joinPoint.proceed(); + BaseDictService service = + (BaseDictService) joinPoint.getTarget(); + // 这里参数必须使用saveNew方法的返回对象,因为里面包含实际主键值。 + service.putDictionaryCache(data); + return data; + } else if ("update".equals(methodName)) { + Object data = joinPoint.proceed(); + BaseDictService service = + (BaseDictService) joinPoint.getTarget(); + // update的方法返回的是boolean,因此这里的参数需要使用第一个参数即可。 + service.putDictionaryCache(arg); + return data; + } else { + // remove + BaseDictService service = + (BaseDictService) joinPoint.getTarget(); + service.removeDictionaryCache((Serializable) arg); + return joinPoint.proceed(); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/dao/BaseDaoMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/dao/BaseDaoMapper.java new file mode 100644 index 00000000..7b7c7ff8 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/dao/BaseDaoMapper.java @@ -0,0 +1,87 @@ +package com.flow.demo.common.core.base.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; +import java.util.Map; + +/** + * 数据访问对象的基类。 + * + * @param 主Model实体对象。 + * @author Jerry + * @date 2021-06-06 + */ +public interface BaseDaoMapper extends BaseMapper { + + /** + * 根据指定的表名、显示字段列表、过滤条件字符串和分组字段,返回聚合计算后的查询结果。 + * + * @param selectTable 表名称。 + * @param selectFields 返回字段列表,逗号分隔。 + * @param whereClause SQL常量形式的条件从句。 + * @param groupBy 分组字段列表,逗号分隔。 + * @return 对象可选字段Map列表。 + */ + @Select("") + List> getGroupedListByCondition( + @Param("selectTable") String selectTable, + @Param("selectFields") String selectFields, + @Param("whereClause") String whereClause, + @Param("groupBy") String groupBy); + + /** + * 根据指定的表名、显示字段列表、过滤条件字符串和排序字符串,返回查询结果。 + * + * @param selectTable 表名称。 + * @param selectFields 选择的字段列表。 + * @param whereClause 过滤字符串。 + * @param orderBy 排序字符串。 + * @return 查询结果。 + */ + @Select("") + List> getListByCondition( + @Param("selectTable") String selectTable, + @Param("selectFields") String selectFields, + @Param("whereClause") String whereClause, + @Param("orderBy") String orderBy); + + /** + * 用指定过滤条件,计算记录数量。 + * + * @param selectTable 表名称。 + * @param whereClause 过滤字符串。 + * @return 返回过滤后的数据数量。 + */ + @Select("") + int getCountByCondition(@Param("selectTable") String selectTable, @Param("whereClause") String whereClause); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/mapper/BaseModelMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/mapper/BaseModelMapper.java new file mode 100644 index 00000000..9e03fdb9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/mapper/BaseModelMapper.java @@ -0,0 +1,124 @@ +package com.flow.demo.common.core.base.mapper; + +import cn.hutool.core.bean.BeanUtil; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * Model对象到Domain类型对象的相互转换。实现类通常声明在Model实体类中。 + * + * @param Domain域对象类型。 + * @param Model实体对象类型。 + * @author Jerry + * @date 2021-06-06 + */ +public interface BaseModelMapper { + + /** + * 转换Model实体对象到Domain域对象。 + * + * @param model Model实体对象。 + * @return Domain域对象。 + */ + D fromModel(M model); + + /** + * 转换Model实体对象列表到Domain域对象列表。 + * + * @param modelList Model实体对象列表。 + * @return Domain域对象列表。 + */ + List fromModelList(List modelList); + + /** + * 转换Domain域对象到Model实体对象。 + * + * @param domain Domain域对象。 + * @return Model实体对象。 + */ + M toModel(D domain); + + /** + * 转换Domain域对象列表到Model实体对象列表。 + * + * @param domainList Domain域对象列表。 + * @return Model实体对象列表。 + */ + List toModelList(List domainList); + + /** + * 转换bean到map + * + * @param bean bean对象。 + * @param ignoreNullValue 值为null的字段是否转换到Map。 + * @param bean类型。 + * @return 转换后的map对象。 + */ + default Map beanToMap(T bean, boolean ignoreNullValue) { + return BeanUtil.beanToMap(bean, false, ignoreNullValue); + } + + /** + * 转换bean集合到map集合 + * + * @param dataList bean对象集合。 + * @param ignoreNullValue 值为null的字段是否转换到Map。 + * @param bean类型。 + * @return 转换后的map对象集合。 + */ + default List> beanToMap(List dataList, boolean ignoreNullValue) { + if (CollectionUtils.isEmpty(dataList)) { + return new LinkedList<>(); + } + return dataList.stream() + .map(o -> BeanUtil.beanToMap(o, false, ignoreNullValue)) + .collect(Collectors.toList()); + } + + /** + * 转换map到bean。 + * + * @param map map对象。 + * @param beanClazz bean的Class对象。 + * @param bean类型。 + * @return 转换后的bean对象。 + */ + default T mapToBean(Map map, Class beanClazz) { + return BeanUtil.toBeanIgnoreError(map, beanClazz); + } + + /** + * 转换map集合到bean集合。 + * + * @param mapList map对象集合。 + * @param beanClazz bean的Class对象。 + * @param bean类型。 + * @return 转换后的bean对象集合。 + */ + default List mapToBean(List> mapList, Class beanClazz) { + if (CollectionUtils.isEmpty(mapList)) { + return new LinkedList<>(); + } + return mapList.stream() + .map(m -> BeanUtil.toBeanIgnoreError(m, beanClazz)) + .collect(Collectors.toList()); + } + + /** + * 对于Map字段到Map字段的映射场景,MapStruct会根据方法签名自动选择该函数 + * 作为对象copy的函数。由于该函数是直接返回的,因此没有对象copy,效率更高。 + * 如果没有该函数,MapStruct会生成如下代码: + * Map map = courseDto.getTeacherIdDictMap(); + * if ( map != null ) { + * course.setTeacherIdDictMap( new HashMap( map ) ); + * } + * + * @param map map对象。 + * @return 直接返回的map。 + */ + default Map mapToMap(Map map) { + return map; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/mapper/DummyModelMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/mapper/DummyModelMapper.java new file mode 100644 index 00000000..be1d66ba --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/mapper/DummyModelMapper.java @@ -0,0 +1,58 @@ +package com.flow.demo.common.core.base.mapper; + +import java.util.List; + +/** + * 哑元占位对象。Model实体对象和Domain域对象相同的场景下使用。 + * 由于没有实际的数据转换,因此同时保证了代码统一和执行效率。 + * + * @param 数据类型。 + * @author Jerry + * @date 2021-06-06 + */ +public class DummyModelMapper implements BaseModelMapper { + + /** + * 不转换直接返回。 + * + * @param model Model实体对象。 + * @return Domain域对象。 + */ + @Override + public M fromModel(M model) { + return model; + } + + /** + * 不转换直接返回。 + * + * @param modelList Model实体对象列表。 + * @return Domain域对象列表。 + */ + @Override + public List fromModelList(List modelList) { + return modelList; + } + + /** + * 不转换直接返回。 + * + * @param domain Domain域对象。 + * @return Model实体对象。 + */ + @Override + public M toModel(M domain) { + return domain; + } + + /** + * 不转换直接返回。 + * + * @param domainList Domain域对象列表。 + * @return Model实体对象列表。 + */ + @Override + public List toModelList(List domainList) { + return domainList; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/BaseDictService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/BaseDictService.java new file mode 100644 index 00000000..e5ee066b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/BaseDictService.java @@ -0,0 +1,266 @@ +package com.flow.demo.common.core.base.service; + +import cn.hutool.core.util.ReflectUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.exception.MyRuntimeException; +import com.flow.demo.common.core.cache.DictionaryCache; +import com.flow.demo.common.core.object.TokenData; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.transaction.annotation.Transactional; + +import java.io.Serializable; +import java.util.*; + +/** + * 带有缓存功能的字典Service基类,需要留意的是,由于缓存基于Key/Value方式存储, + * 目前仅支持基于主键字段的缓存查找,其他条件的查找仍然从数据源获取。 + * + * @param Model实体对象的类型。 + * @param Model对象主键的类型。 + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public abstract class BaseDictService extends BaseService implements IBaseDictService { + + /** + * 缓存池对象。 + */ + protected DictionaryCache dictionaryCache; + + /** + * 构造函数使用缺省缓存池对象。 + */ + public BaseDictService() { + super(); + } + + /** + * 重新加载数据库中所有当前表数据到系统内存。 + * + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + @Override + public void reloadCachedData(boolean force) { + // 在非强制刷新情况下。 + // 先行判断缓存中是否存在数据,如果有就不加载了。 + if (!force && dictionaryCache.getCount() > 0) { + return; + } + List allList = super.getAllList(); + dictionaryCache.reload(allList, force); + } + + /** + * 保存新增对象。 + * + * @param data 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public M saveNew(M data) { + if (deletedFlagFieldName != null) { + try { + setDeletedFlagMethod.invoke(data, GlobalDeletedFlag.NORMAL); + } catch (Exception e) { + log.error("Failed to call reflection [setDeletedFlagMethod] in BaseDictService.saveNew.", e); + throw new MyRuntimeException(e); + } + } + if (tenantIdField != null) { + ReflectUtil.setFieldValue(data, tenantIdField, TokenData.takeFromRequest().getTenantId()); + } + mapper().insert(data); + return data; + } + + /** + * 更新数据对象。 + * + * @param data 更新的对象。 + * @param originalData 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(M data, M originalData) { + if (tenantIdField != null) { + ReflectUtil.setFieldValue(data, tenantIdField, TokenData.takeFromRequest().getTenantId()); + } + return mapper().updateById(data) == 1; + } + + /** + * 删除指定数据。 + * + * @param id 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(K id) { + return mapper().deleteById(id) == 1; + } + + /** + * 直接从缓存池中获取主键Id关联的数据。如果缓存中不存在,再从数据库中取出并回写到缓存。 + * + * @param id 主键Id。 + * @return 主键关联的数据,不存在返回null。 + */ + @SuppressWarnings("unchecked") + @Override + public M getById(Serializable id) { + M data = dictionaryCache.get((K) id); + if (data != null) { + return data; + } + data = super.getById(id); + if (data != null) { + this.dictionaryCache.put((K) id, data); + } + return data; + } + + /** + * 直接从缓存池中获取所有数据。 + * + * @return 返回所有数据。 + */ + @Override + public List getAllListFromCache() { + return dictionaryCache.getAll(); + } + + /** + * 直接从缓存池中返回符合主键 in (idValues) 条件的所有数据。 + * 对于缓存中不存在的数据,从数据库中获取并回写入缓存。 + * + * @param idValues 主键值列表。 + * @return 检索后的数据列表。 + */ + @SuppressWarnings("unchecked") + @Override + public List getInList(Set idValues) { + List resultList = dictionaryCache.getInList(idValues); + if (resultList.size() == idValues.size()) { + return resultList; + } + Set cachedIdList = new HashSet<>(); + for (M data : resultList) { + try { + cachedIdList.add((K) getIdFieldMethod.invoke(data)); + } catch (Exception e) { + log.error("Failed to call reflection method in BaseDictService.getInList.", e); + throw new MyRuntimeException(e); + } + } + // 找到未缓存的数据,然后从数据库读取后缓存。 + Set uncachedIdList = new HashSet<>(); + for (K id : idValues) { + if (!cachedIdList.contains(id)) { + uncachedIdList.add(id); + } + } + List uncachedResultList = super.getInList(uncachedIdList); + if (CollectionUtils.isNotEmpty(uncachedResultList)) { + for (M data : uncachedResultList) { + try { + K id = (K) getIdFieldMethod.invoke(data); + this.dictionaryCache.put(id, data); + } catch (Exception e) { + log.error("Failed to call reflection method in BaseDictService.getInList.", e); + throw new MyRuntimeException(e); + } + } + resultList.addAll(uncachedResultList); + } + return resultList; + } + + /** + * 返回符合 inFilterField in (inFilterValues) 条件的所有数据。属性property是主键,则从缓存中读取。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param inFilterValues 参与(In-list)过滤的Java字段值集合。 + * @return 检索后的数据列表。 + */ + @SuppressWarnings("unchecked") + @Override + public List getInList(String inFilterField, Set inFilterValues) { + if (inFilterField.equals(this.idFieldName)) { + return this.getInList((Set) inFilterValues); + } + return super.getInList(inFilterField, inFilterValues); + } + + /** + * 判断参数值列表中的所有数据,是否全部存在。另外,keyName字段在数据表中必须是唯一键值,否则返回结果会出现误判。 + * + * @param inFilterField 待校验的数据字段,这里使用Java对象中的属性,如courseId,而不是数据字段名course_id。 + * @param inFilterValues 数据值集合。 + * @return 全部存在返回true,否则false。 + */ + @SuppressWarnings("unchecked") + @Override + public boolean existUniqueKeyList(String inFilterField, Set inFilterValues) { + if (CollectionUtils.isEmpty(inFilterValues)) { + return true; + } + if (inFilterField.equals(this.idFieldName)) { + List dataList = this.getInList((Set) inFilterValues); + return dataList.size() == inFilterValues.size(); + } + String columnName = this.safeMapToColumnName(inFilterField); + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.in(columnName, inFilterValues); + return mapper().selectCount(queryWrapper) == inFilterValues.size(); + } + + /** + * 存入缓存。 + * + * @param data 新增或更新数据。 + */ + @SuppressWarnings("unchecked") + @Override + public void putDictionaryCache(M data) { + K key = (K) ReflectUtil.getFieldValue(data, idFieldName); + this.dictionaryCache.put(key, data); + } + + /** + * 根据字典主键将数据从缓存中删除。 + * + * @param id 字典主键。 + */ + @Override + public void removeDictionaryCache(K id) { + this.dictionaryCache.invalidate(id); + } + + /** + * 根据字典对象将数据从缓存中删除。 + * + * @param data 字典数据。 + */ + @SuppressWarnings("unchecked") + @Override + public void removeDictionaryCacheByModel(M data) { + K key = (K) ReflectUtil.getFieldValue(data, idFieldName); + this.dictionaryCache.invalidate(key); + } + + /** + * 获取缓存中的数据数量。 + * + * @return 缓存中的数据总量。 + */ + @Override + public int getCachedCount() { + return dictionaryCache.getCount(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/BaseService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/BaseService.java new file mode 100644 index 00000000..17e7b15f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/BaseService.java @@ -0,0 +1,1626 @@ +package com.flow.demo.common.core.base.service; + +import com.baomidou.mybatisplus.annotation.*; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.flow.demo.common.core.annotation.*; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.constant.AggregationType; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.exception.InvalidDataFieldException; +import com.flow.demo.common.core.exception.MyRuntimeException; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.AopTargetUtil; +import com.flow.demo.common.core.util.ApplicationContextHolder; +import com.flow.demo.common.core.util.MyModelUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.transaction.annotation.Transactional; +import cn.hutool.core.util.ReflectUtil; + +import java.io.Serializable; +import java.lang.reflect.Modifier; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.util.*; +import java.util.function.Function; +import java.util.function.Consumer; +import java.util.function.Supplier; + +import static java.util.stream.Collectors.*; + +/** + * 所有Service的基类。 + * + * @param Model对象的类型。 + * @param Model对象主键的类型。 + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public abstract class BaseService extends ServiceImpl, M> implements IBaseService { + /** + * 当前Service关联的主Model实体对象的Class。 + */ + protected final Class modelClass; + /** + * 当前Service关联的主Model实体对象主键字段的Class。 + */ + protected final Class idFieldClass; + /** + * 当前Service关联的主Model实体对象的实际表名称。 + */ + protected final String tableName; + /** + * 当前Service关联的主Model对象主键字段名称。 + */ + protected String idFieldName; + /** + * 当前Service关联的主数据表中主键列名称。 + */ + protected String idColumnName; + /** + * 当前Service关联的主Model对象逻辑删除字段名称。 + */ + protected String deletedFlagFieldName; + /** + * 当前Service关联的主数据表中逻辑删除字段名称。 + */ + protected String deletedFlagColumnName; + /** + * 当前Service关联的主Model对象租户Id字段。 + */ + protected Field tenantIdField; + /** + * 当前Service关联的主Model对象租户Id字段名称。 + */ + protected String tenantIdFieldName; + /** + * 当前Service关联的主数据表中租户Id列名称。 + */ + protected String tenantIdColumnName; + /** + * 当前Job服务源主表Model对象最后更新时间字段名称。 + */ + protected String updateTimeFieldName; + /** + * 当前Job服务源主表Model对象最后更新时间列名称。 + */ + protected String updateTimeColumnName; + /** + * 当前Service关联的主Model对象主键字段赋值方法的反射对象。 + */ + protected Method setIdFieldMethod; + /** + * 当前Service关联的主Model对象主键字段访问方法的反射对象。 + */ + protected Method getIdFieldMethod; + /** + * 当前Service关联的主Model对象逻辑删除字段赋值方法的反射对象。 + */ + protected Method setDeletedFlagMethod; + /** + * 当前Service关联的主Model对象的所有字典关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private final List relationDictStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有常量字典关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private final List relationConstDictStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有一对一关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private final List relationOneToOneStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有一对多关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private final List relationOneToManyStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有多对多关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private final List relationManyToManyStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有一对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private final List relationOneToManyAggrStructList = new LinkedList<>(); + /** + * 当前Service关联的主Model对象的所有多对多聚合关联的结构列表,该字段在系统启动阶段一次性预加载,提升运行时效率。 + */ + private final List relationManyToManyAggrStructList = new LinkedList<>(); + + private static final String GROUPED_KEY = "groupedKey"; + private static final String AGGREGATED_VALUE = "aggregatedValue"; + private static final String AND_OP = " AND "; + + @Override + public BaseDaoMapper getBaseMapper() { + return mapper(); + } + + /** + * 构造函数,在实例化的时候,一次性完成所有有关主Model对象信息的加载。 + */ + @SuppressWarnings("unchecked") + public BaseService() { + modelClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; + idFieldClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1]; + this.tableName = modelClass.getAnnotation(TableName.class).value(); + Field[] fields = ReflectUtil.getFields(modelClass); + for (Field field : fields) { + initializeField(field); + } + } + + private void initializeField(Field field) { + if (idFieldName == null && null != field.getAnnotation(TableId.class)) { + idFieldName = field.getName(); + TableId c = field.getAnnotation(TableId.class); + idColumnName = c == null ? idFieldName : c.value(); + setIdFieldMethod = ReflectUtil.getMethod( + modelClass, "set" + StringUtils.capitalize(idFieldName), idFieldClass); + getIdFieldMethod = ReflectUtil.getMethod( + modelClass, "get" + StringUtils.capitalize(idFieldName)); + } + if (updateTimeFieldName == null && null != field.getAnnotation(JobUpdateTimeColumn.class)) { + updateTimeFieldName = field.getName(); + updateTimeColumnName = this.safeMapToColumnName(updateTimeFieldName); + } + if (deletedFlagFieldName == null && null != field.getAnnotation(TableLogic.class)) { + deletedFlagFieldName = field.getName(); + deletedFlagColumnName = this.safeMapToColumnName(deletedFlagFieldName); + setDeletedFlagMethod = ReflectUtil.getMethod( + modelClass, "set" + StringUtils.capitalize(deletedFlagFieldName), Integer.class); + } + if (tenantIdFieldName == null && null != field.getAnnotation(TenantFilterColumn.class)) { + tenantIdField = field; + tenantIdFieldName = field.getName(); + tenantIdColumnName = this.safeMapToColumnName(tenantIdFieldName); + } + } + + /** + * 获取子类中注入的Mapper类。 + * + * @return 子类中注入的Mapper类。 + */ + protected abstract BaseDaoMapper mapper(); + + /** + * 根据过滤条件删除数据。 + * + * @param filter 过滤对象。 + * @return 删除数量。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public Integer removeBy(M filter) { + return mapper().delete(new QueryWrapper<>(filter)); + } + + /** + * 判断指定字段的数据是否存在,且仅仅存在一条记录。 + * 如果是基于主键的过滤,会直接调用existId过滤函数,提升性能。在有缓存的场景下,也可以利用缓存。 + * + * @param fieldName 待过滤的字段名(Java 字段)。 + * @param fieldValue 字段值。 + * @return 存在且仅存在一条返回true,否则false。 + */ + @SuppressWarnings("unchecked") + @Override + public boolean existOne(String fieldName, Object fieldValue) { + if (fieldName.equals(this.idFieldName)) { + return this.existId((K) fieldValue); + } + String columnName = MyModelUtil.mapToColumnName(fieldName, modelClass); + return mapper().selectCount(new QueryWrapper().eq(columnName, fieldValue)) == 1; + } + + /** + * 判断主键Id关联的数据是否存在。 + * + * @param id 主键Id。 + * @return 存在返回true,否则false。 + */ + @Override + public boolean existId(K id) { + return getById(id) != null; + } + + /** + * 返回符合 filterField = filterValue 条件的一条数据。 + * + * @param filterField 过滤的Java字段。 + * @param filterValue 过滤的Java字段值。 + * @return 查询后的数据对象。 + */ + @SuppressWarnings("unchecked") + @Override + public M getOne(String filterField, Object filterValue) { + if (filterField.equals(idFieldName)) { + return this.getById((K) filterValue); + } + String columnName = this.safeMapToColumnName(filterField); + QueryWrapper queryWrapper = new QueryWrapper().eq(columnName, filterValue); + return mapper().selectOne(queryWrapper); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * + * @param id 主表主键Id。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @return 查询结果对象。 + */ + @Override + public M getByIdWithRelation(K id, MyRelationParam relationParam) { + M dataObject = this.getById(id); + this.buildRelationForData(dataObject, relationParam); + return dataObject; + } + + /** + * 获取所有数据。 + * + * @return 返回所有数据。 + */ + @Override + public List getAllList() { + return mapper().selectList(Wrappers.emptyWrapper()); + } + + /** + * 获取排序后所有数据。 + * + * @param orderByProperties 需要排序的字段属性,这里使用Java对象中的属性名,而不是数据库字段名。 + * @return 返回排序后所有数据。 + */ + @Override + public List getAllListByOrder(String... orderByProperties) { + String[] columns = new String[orderByProperties.length]; + for (int i = 0; i < orderByProperties.length; i++) { + columns[i] = this.safeMapToColumnName(orderByProperties[i]); + } + return mapper().selectList(new QueryWrapper().orderByAsc(columns)); + } + + /** + * 判断参数值主键集合中的所有数据,是否全部存在 + * + * @param idSet 待校验的主键集合。 + * @return 全部存在返回true,否则false。 + */ + @Override + public boolean existAllPrimaryKeys(Set idSet) { + if (CollectionUtils.isEmpty(idSet)) { + return true; + } + return this.existUniqueKeyList(idFieldName, idSet); + } + + /** + * 判断参数值列表中的所有数据,是否全部存在。另外,keyName字段在数据表中必须是唯一键值,否则返回结果会出现误判。 + * + * @param inFilterField 待校验的数据字段,这里使用Java对象中的属性,如courseId,而不是数据字段名course_id + * @param inFilterValues 数据值列表。 + * @return 全部存在返回true,否则false。 + */ + @Override + public boolean existUniqueKeyList(String inFilterField, Set inFilterValues) { + if (CollectionUtils.isEmpty(inFilterValues)) { + return true; + } + String column = this.safeMapToColumnName(inFilterField); + return mapper().selectCount(new QueryWrapper().in(column, inFilterValues)) == inFilterValues.size(); + } + + /** + * 返回符合主键 in (idValues) 条件的所有数据。 + * + * @param idValues 主键值集合。 + * @return 检索后的数据列表。 + */ + @Override + public List getInList(Set idValues) { + return this.getInList(idFieldName, idValues, null); + } + + /** + * 返回符合 inFilterField in (inFilterValues) 条件的所有数据。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param inFilterValues 参与(In-list)过滤的Java字段值集合。 + * @return 检索后的数据列表。 + */ + @Override + public List getInList(String inFilterField, Set inFilterValues) { + return this.getInList(inFilterField, inFilterValues, null); + } + + /** + * 返回符合 inFilterField in (inFilterValues) 条件的所有数据,并根据orderBy字段排序。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param inFilterValues 参与(In-list)过滤的Java字段值集合。 + * @param orderBy 排序字段。 + * @return 检索后的数据列表。 + */ + @Override + public List getInList(String inFilterField, Set inFilterValues, String orderBy) { + if (CollectionUtils.isEmpty(inFilterValues)) { + return new LinkedList<>(); + } + String column = this.safeMapToColumnName(inFilterField); + QueryWrapper queryWrapper = new QueryWrapper().in(column, inFilterValues); + if (StringUtils.isNotBlank(orderBy)) { + queryWrapper.last(orderBy); + } + return mapper().selectList(queryWrapper); + } + + /** + * 用参数对象作为过滤条件,获取数据数量。 + * + * @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件。 + * @return 返回过滤后的数据数量。 + */ + @Override + public int getCountByFilter(M filter) { + return mapper().selectCount(new QueryWrapper<>(filter)); + } + + /** + * 用参数对象作为过滤条件,判断是否存在过滤数据。 + * + * @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件。 + * @return 存在返回true,否则false。 + */ + @Override + public boolean existByFilter(M filter) { + return this.getCountByFilter(filter) > 0; + } + + /** + * 用参数对象作为过滤条件,获取查询结果。 + * + * @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。 + * @return 返回过滤后的数据。 + */ + @Override + public List getListByFilter(M filter) { + return mapper().selectList(new QueryWrapper<>(filter)); + } + + /** + * 获取父主键Id下的所有子数据列表。 + * + * @param parentIdFieldName 父主键字段名字,如"courseId"。 + * @param parentId 父主键的值。 + * @return 父主键Id下的所有子数据列表。 + */ + @Override + public List getListByParentId(String parentIdFieldName, K parentId) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + String parentIdColumn = this.safeMapToColumnName(parentIdFieldName); + if (parentId != null) { + queryWrapper.eq(parentIdColumn, parentId); + } else { + queryWrapper.isNull(parentIdColumn); + } + return mapper().selectList(queryWrapper); + } + + /** + * 根据指定的显示字段列表、过滤条件字符串和分组字符串,返回聚合计算后的查询结果。(基本是内部框架使用,不建议外部接口直接使用)。 + * + * @param selectFields 选择的字段列表,多个字段逗号分隔。 + * NOTE: 如果数据表字段和Java对象字段名字不同,Java对象字段应该以别名的形式出现。 + * 如: table_column_name modelFieldName。否则无法被反射回Bean对象。 + * @param whereClause SQL常量形式的条件从句。 + * @param groupBy SQL常量形式分组字段列表,逗号分隔。 + * @return 聚合计算后的数据结果集。 + */ + @Override + public List> getGroupedListByCondition( + String selectFields, String whereClause, String groupBy) { + return mapper().getGroupedListByCondition(tableName, selectFields, whereClause, groupBy); + } + + /** + * 根据指定的显示字段列表、过滤条件字符串和排序字符串,返回查询结果。(基本是内部框架使用,不建议外部接口直接使用)。 + * + * @param selectList 选择的Java字段列表。如果为空表示返回全部字段。 + * @param filter 过滤对象。 + * @param whereClause SQL常量形式的条件从句。 + * @param orderBy SQL常量形式排序字段列表,逗号分隔。 + * @return 查询结果。 + */ + @Override + public List getListByCondition(List selectList, M filter, String whereClause, String orderBy) { + QueryWrapper queryWrapper = new QueryWrapper<>(filter); + if (CollectionUtils.isNotEmpty(selectList)) { + String[] columns = new String[selectList.size()]; + for (int i = 0; i < selectList.size(); i++) { + columns[i] = this.safeMapToColumnName(selectList.get(i)); + } + queryWrapper.select(columns); + } + if (StringUtils.isNotBlank(whereClause)) { + queryWrapper.apply(whereClause); + } + if (StringUtils.isNotBlank(orderBy)) { + queryWrapper.last(" ORDER BY " + orderBy); + } + return mapper().selectList(queryWrapper); + } + + /** + * 用指定过滤条件,计算记录数量。(基本是内部框架使用,不建议外部接口直接使用)。 + * + * @param whereClause SQL常量形式的条件从句。 + * @return 返回过滤后的数据数量。 + */ + @Override + public Integer getCountByCondition(String whereClause) { + return mapper().getCountByCondition(this.tableName, whereClause); + } + + /** + * 集成所有与主表实体对象相关的关联数据列表。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param relationParam 实体对象数据组装的参数构建器。 + */ + @Override + public void buildRelationForDataList(List resultList, MyRelationParam relationParam) { + this.buildRelationForDataList(resultList, relationParam, null); + } + + /** + * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + @Override + public void buildRelationForDataList( + List resultList, MyRelationParam relationParam, Set ignoreFields) { + if (relationParam == null || CollectionUtils.isEmpty(resultList)) { + return; + } + boolean dataFilterValue = GlobalThreadLocal.setDataFilter(false); + try { + // 集成本地一对一和字段级别的数据关联。 + boolean buildOneToOne = relationParam.isBuildOneToOne() || relationParam.isBuildOneToOneWithDict(); + // 这里集成一对一关联。 + if (buildOneToOne) { + this.buildOneToOneForDataList(resultList, relationParam.isBuildOneToOneWithDict(), ignoreFields); + } + // 集成一对多关联 + if (relationParam.isBuildOneToMany()) { + this.buildOneToManyForDataList(resultList, ignoreFields); + } + // 这里集成字典关联 + if (relationParam.isBuildDict()) { + // 构建常量字典关联关系 + this.buildConstDictForDataList(resultList, ignoreFields); + this.buildDictForDataList(resultList, buildOneToOne, ignoreFields); + } + // 组装本地聚合计算关联数据 + if (relationParam.isBuildRelationAggregation()) { + // 处理多对多场景下,根据主表的结果,进行从表聚合数据的计算。 + this.buildManyToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria(), ignoreFields); + // 处理多一多场景下,根据主表的结果,进行从表聚合数据的计算。 + this.buildOneToManyAggregationForDataList(resultList, buildAggregationAdditionalWhereCriteria(), ignoreFields); + } + } finally { + GlobalThreadLocal.setDataFilter(dataFilterValue); + } + } + + /** + * 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询,批量导出没有分页机制, + * 因此在导出数据量较大的情况下,很容易给数据库的内存、CPU和IO带来较大的压力。而通过 + * 我们的分批处理,可以极大的规避该问题的出现几率。调整batchSize的大小,也可以有效的 + * 改善运行效率。 + * 我们目前的处理机制是,先从主表取出所有符合条件的主表数据,这样可以避免分批处理时, + * 后面几批数据,因为skip过多而带来的效率问题。因为是单表过滤,不会给数据库带来过大的压力。 + * 之后再在主表结果集数据上进行分批级联处理。 + * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param batchSize 每批集成的记录数量。小于等于0时将不做分批处理。 + */ + @Override + public void buildRelationForDataList(List resultList, MyRelationParam relationParam, int batchSize) { + this.buildRelationForDataList(resultList, relationParam, batchSize, null); + } + + /** + * 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询,批量导出没有分页机制, + * 因此在导出数据量较大的情况下,很容易给数据库的内存、CPU和IO带来较大的压力。而通过 + * 我们的分批处理,可以极大的规避该问题的出现几率。调整batchSize的大小,也可以有效的 + * 改善运行效率。 + * 我们目前的处理机制是,先从主表取出所有符合条件的主表数据,这样可以避免分批处理时, + * 后面几批数据,因为skip过多而带来的效率问题。因为是单表过滤,不会给数据库带来过大的压力。 + * 之后再在主表结果集数据上进行分批级联处理。 + * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param batchSize 每批集成的记录数量。小于等于0时将不做分批处理。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + @Override + public void buildRelationForDataList( + List resultList, MyRelationParam relationParam, int batchSize, Set ignoreFields) { + if (CollectionUtils.isEmpty(resultList)) { + return; + } + if (batchSize <= 0) { + this.buildRelationForDataList(resultList, relationParam); + return; + } + int totalCount = resultList.size(); + int fromIndex = 0; + int toIndex = Math.min(batchSize, totalCount); + while (toIndex > fromIndex) { + List subResultList = resultList.subList(fromIndex, toIndex); + this.buildRelationForDataList(subResultList, relationParam, ignoreFields); + fromIndex = toIndex; + toIndex = Math.min(batchSize + fromIndex, totalCount); + } + } + + /** + * 集成所有与主表实体对象相关的关联数据对象。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param dataObject 主表实体对象。数据集成将直接作用于该对象。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param 实体对象类型。 + */ + @Override + public void buildRelationForData(T dataObject, MyRelationParam relationParam) { + this.buildRelationForData(dataObject, relationParam, null); + } + + /** + * 集成所有与主表实体对象相关的关联数据对象。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param dataObject 主表实体对象。数据集成将直接作用于该对象。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + * @param 实体对象类型。 + */ + @Override + public void buildRelationForData(T dataObject, MyRelationParam relationParam, Set ignoreFields) { + if (dataObject == null || relationParam == null) { + return; + } + boolean dataFilterValue = GlobalThreadLocal.setDataFilter(false); + try { + // 集成本地一对一和字段级别的数据关联。 + boolean buildOneToOne = relationParam.isBuildOneToOne() || relationParam.isBuildOneToOneWithDict(); + if (buildOneToOne) { + this.buildOneToOneForData(dataObject, relationParam.isBuildOneToOneWithDict(), ignoreFields); + } + // 集成一对多关联 + if (relationParam.isBuildOneToMany()) { + this.buildOneToManyForData(dataObject, ignoreFields); + } + if (relationParam.isBuildDict()) { + // 构建常量字典关联关系 + this.buildConstDictForData(dataObject, ignoreFields); + // 构建本地数据字典关联关系。 + this.buildDictForData(dataObject, buildOneToOne, ignoreFields); + } + // 组装本地聚合计算关联数据 + if (relationParam.isBuildRelationAggregation()) { + // 开始处理多对多场景。 + buildManyToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria(), ignoreFields); + // 构建一对多场景 + buildOneToManyAggregationForData(dataObject, buildAggregationAdditionalWhereCriteria(), ignoreFields); + } + if (relationParam.isBuildRelationManyToMany()) { + this.buildRelationManyToMany(dataObject, ignoreFields); + } + } finally { + GlobalThreadLocal.setDataFilter(dataFilterValue); + } + } + + /** + * 集成主表和多对多中间表之间的关联关系。 + * + * @param dataObject 关联后的主表数据对象。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildRelationManyToMany(T dataObject, Set ignoreFields) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationManyToManyStructList)) { + return; + } + for (RelationStruct relationStruct : this.relationManyToManyStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + String masterIdColumn = this.safeMapToColumnName(relationStruct.masterIdField.getName()); + Map filterMap = new HashMap<>(1); + filterMap.put(masterIdColumn, masterIdValue); + List manyToManyList = relationStruct.manyToManyMapper.selectByMap(filterMap); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, manyToManyList); + } + } + + /** + * 为实体对象参数列表数据集成本地静态字典关联数据。 + * + * @param resultList 主表数据列表。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildConstDictForDataList(List resultList, Set ignoreFields) { + if (CollectionUtils.isEmpty(this.relationConstDictStructList) || CollectionUtils.isEmpty(resultList)) { + return; + } + for (RelationStruct relationStruct : this.relationConstDictStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + for (M dataObject : resultList) { + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + String name = relationStruct.dictMap.get(id); + if (name != null) { + Map dictMap = new HashMap<>(2); + dictMap.put("id", id); + dictMap.put("name", name); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, dictMap); + } + } + } + } + } + + /** + * 为参数实体对象数据集成本地静态字典关联数据。 + * + * @param dataObject 实体对象。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildConstDictForData(T dataObject, Set ignoreFields) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationConstDictStructList)) { + return; + } + for (RelationStruct relationStruct : this.relationConstDictStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + String name = relationStruct.dictMap.get(id); + if (name != null) { + Map dictMap = new HashMap<>(2); + dictMap.put("id", id); + dictMap.put("name", name); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, dictMap); + } + } + } + } + + /** + * 为实体对象参数列表数据集成本地字典关联数据。 + * + * @param resultList 实体对象数据列表。 + * @param hasBuiltOneToOne 性能优化参数。如果该值为true,同时注解参数RelationDict.equalOneToOneRelationField + * 不为空,则直接从已经完成一对一数据关联的从表对象中获取数据,减少一次数据库交互。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildDictForDataList(List resultList, boolean hasBuiltOneToOne, Set ignoreFields) { + if (CollectionUtils.isEmpty(this.relationDictStructList) || CollectionUtils.isEmpty(resultList)) { + return; + } + for (RelationStruct relationStruct : this.relationDictStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + List relationList = null; + if (hasBuiltOneToOne && relationStruct.equalOneToOneRelationField != null) { + relationList = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.equalOneToOneRelationField)) + .filter(Objects::nonNull) + .collect(toList()); + } else { + String slaveId = relationStruct.relationDict.slaveIdField(); + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + if (CollectionUtils.isNotEmpty(masterIdSet)) { + relationList = relationStruct.service.getInList(slaveId, masterIdSet); + } + } + MyModelUtil.makeDictRelation( + modelClass, resultList, relationList, relationStruct.relationField.getName()); + } + } + + /** + * 为实体对象数据集成本地数据字典关联数据。 + * + * @param dataObject 实体对象。 + * @param hasBuiltOneToOne 性能优化参数。如果该值为true,同时注解参数RelationDict.equalOneToOneRelationField + * 不为空,则直接从已经完成一对一数据关联的从表对象中获取数据,减少一次数据库交互。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildDictForData(T dataObject, boolean hasBuiltOneToOne, Set ignoreFields) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationDictStructList)) { + return; + } + for (RelationStruct relationStruct : this.relationDictStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Object relationObject = null; + if (hasBuiltOneToOne && relationStruct.equalOneToOneRelationField != null) { + relationObject = ReflectUtil.getFieldValue(dataObject, relationStruct.equalOneToOneRelationField); + } else { + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + relationObject = relationStruct.service.getOne(relationStruct.relationDict.slaveIdField(), id); + } + } + MyModelUtil.makeDictRelation( + modelClass, dataObject, relationObject, relationStruct.relationField.getName()); + } + } + + /** + * 为实体对象参数列表数据集成本地一对一关联数据。 + * + * @param resultList 实体对象数据列表。 + * @param withDict 关联从表数据后,是否把从表的字典数据也一起关联了。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildOneToOneForDataList(List resultList, boolean withDict, Set ignoreFields) { + if (CollectionUtils.isEmpty(this.relationOneToOneStructList) || CollectionUtils.isEmpty(resultList)) { + return; + } + for (RelationStruct relationStruct : this.relationOneToOneStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + // 从主表集合中,抽取主表关联字段的集合,再以in list形式去从表中查询。 + if (CollectionUtils.isNotEmpty(masterIdSet)) { + BaseService relationService = relationStruct.service; + List relationList = + relationService.getInList(relationStruct.relationOneToOne.slaveIdField(), masterIdSet); + MyModelUtil.makeOneToOneRelation( + modelClass, resultList, relationList, relationStruct.relationField.getName()); + // 仅仅当需要加载从表字典关联时,才去加载。 + if (withDict && relationStruct.relationOneToOne.loadSlaveDict() + && CollectionUtils.isNotEmpty(relationList)) { + @SuppressWarnings("unchecked") + BaseService proxyTarget = + (BaseService) AopTargetUtil.getTarget(relationService); + // 关联本地字典。 + proxyTarget.buildDictForDataList(relationList, false, ignoreFields); + // 关联常量字典 + proxyTarget.buildConstDictForDataList(relationList, ignoreFields); + } + } + } + } + + /** + * 为实体对象数据集成本地一对一关联数据。 + * + * @param dataObject 实体对象。 + * @param withDict 关联从表数据后,是否把从表的字典数据也一起关联了。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildOneToOneForData(M dataObject, boolean withDict, Set ignoreFields) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToOneStructList)) { + return; + } + for (RelationStruct relationStruct : this.relationOneToOneStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + BaseService relationService = relationStruct.service; + Object relationObject = relationService.getOne(relationStruct.relationOneToOne.slaveIdField(), id); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, relationObject); + // 仅仅当需要加载从表字典关联时,才去加载。 + if (withDict && relationStruct.relationOneToOne.loadSlaveDict() && relationObject != null) { + @SuppressWarnings("unchecked") + BaseService proxyTarget = + (BaseService) AopTargetUtil.getTarget(relationService); + // 关联本地字典 + proxyTarget.buildDictForData(relationObject, false, ignoreFields); + // 关联常量字典 + proxyTarget.buildConstDictForData(relationObject, ignoreFields); + } + } + } + } + + /** + * 为实体对象参数列表数据集成本地一对多关联数据。 + * + * @param resultList 实体对象数据列表。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildOneToManyForDataList(List resultList, Set ignoreFields) { + if (CollectionUtils.isEmpty(this.relationOneToManyStructList) || CollectionUtils.isEmpty(resultList)) { + return; + } + for (RelationStruct relationStruct : this.relationOneToManyStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + // 从主表集合中,抽取主表关联字段的集合,再以in list形式去从表中查询。 + if (CollectionUtils.isNotEmpty(masterIdSet)) { + BaseService relationService = relationStruct.service; + List relationList = + relationService.getInList(relationStruct.relationOneToMany.slaveIdField(), masterIdSet); + MyModelUtil.makeOneToManyRelation( + modelClass, resultList, relationList, relationStruct.relationField.getName()); + } + } + } + + /** + * 为实体对象数据集成本地一对多关联数据。 + * + * @param dataObject 实体对象。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildOneToManyForData(M dataObject, Set ignoreFields) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToManyStructList)) { + return; + } + for (RelationStruct relationStruct : this.relationOneToManyStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Object id = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (id != null) { + BaseService relationService = relationStruct.service; + Set masterIdSet = new HashSet<>(1); + masterIdSet.add(id); + List relationObject = relationService.getInList( + relationStruct.relationOneToMany.slaveIdField(), masterIdSet); + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, relationObject); + } + } + } + + /** + * 根据实体对象参数列表和过滤条件,集成本地多对多关联聚合计算数据。 + * + * @param resultList 实体对象数据列表。 + * @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildManyToManyAggregationForDataList( + List resultList, Map> criteriaListMap, Set ignoreFields) { + if (CollectionUtils.isEmpty(this.relationManyToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) { + return; + } + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(this.relationManyToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationManyToManyAggrStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + if (CollectionUtils.isEmpty(masterIdSet)) { + continue; + } + RelationManyToManyAggregation relation = relationStruct.relationManyToManyAggregation; + // 提取关联中用到的各种字段和表数据。 + BasicAggregationRelationInfo basicRelationInfo = + this.parseBasicAggregationRelationInfo(relationStruct, criteriaListMap); + // 构建多表关联的where语句 + StringBuilder whereClause = new StringBuilder(256); + // 如果需要从表聚合计算或参与过滤,则需要把中间表和从表之间的关联条件加上。 + if (!basicRelationInfo.onlySelectRelationTable) { + whereClause.append(basicRelationInfo.relationTable) + .append(".") + .append(basicRelationInfo.relationSlaveColumn) + .append(" = ") + .append(basicRelationInfo.slaveTable) + .append(".") + .append(basicRelationInfo.slaveColumn); + } else { + whereClause.append("1 = 1"); + } + List criteriaList = criteriaListMap.get(relationStruct.relationField.getName()); + if (criteriaList == null) { + criteriaList = new LinkedList<>(); + } + MyWhereCriteria inlistFilter = new MyWhereCriteria(); + inlistFilter.setCriteria(relation.relationModelClass(), + relation.relationMasterIdField(), MyWhereCriteria.OPERATOR_IN, masterIdSet); + criteriaList.add(inlistFilter); + if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) { + MyWhereCriteria deleteFilter = new MyWhereCriteria(); + deleteFilter.setCriteria( + relation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList); + whereClause.append(AND_OP).append(criteriaString); + StringBuilder tableNames = new StringBuilder(64); + tableNames.append(basicRelationInfo.relationTable); + if (!basicRelationInfo.onlySelectRelationTable) { + tableNames.append(", ").append(basicRelationInfo.slaveTable); + } + List> aggregationMapList = + mapper().getGroupedListByCondition(tableNames.toString(), + basicRelationInfo.selectList, whereClause.toString(), basicRelationInfo.groupBy); + doMakeLocalAggregationData(aggregationMapList, resultList, relationStruct); + } + } + + /** + * 根据实体对象和过滤条件,集成本地多对多关联聚合计算数据。 + * + * @param dataObject 实体对象。 + * @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildManyToManyAggregationForData( + T dataObject, Map> criteriaListMap, Set ignoreFields) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationManyToManyAggrStructList)) { + return; + } + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(relationManyToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationManyToManyAggrStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (masterIdValue != null) { + BasicAggregationRelationInfo basicRelationInfo = + this.parseBasicAggregationRelationInfo(relationStruct, criteriaListMap); + // 组装过滤条件 + String whereClause = this.makeManyToManyWhereClause( + relationStruct, masterIdValue, basicRelationInfo, criteriaListMap); + StringBuilder tableNames = new StringBuilder(64); + tableNames.append(basicRelationInfo.relationTable); + if (!basicRelationInfo.onlySelectRelationTable) { + tableNames.append(", ").append(basicRelationInfo.slaveTable); + } + List> aggregationMapList = + mapper().getGroupedListByCondition(tableNames.toString(), + basicRelationInfo.selectList, whereClause, basicRelationInfo.groupBy); + // 将查询后的结果回填到主表数据中。 + if (CollectionUtils.isNotEmpty(aggregationMapList)) { + Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE); + if (value != null) { + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value); + } + } + } + } + } + + /** + * 根据实体对象参数列表和过滤条件,集成本地一对多关联聚合计算数据。 + * + * @param resultList 实体对象数据列表。 + * @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildOneToManyAggregationForDataList( + List resultList, Map> criteriaListMap, Set ignoreFields) { + // 处理多一多场景下,根据主表的结果,进行从表聚合数据的计算。 + if (CollectionUtils.isEmpty(this.relationOneToManyAggrStructList) || CollectionUtils.isEmpty(resultList)) { + return; + } + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationOneToManyAggrStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Set masterIdSet = resultList.stream() + .map(obj -> ReflectUtil.getFieldValue(obj, relationStruct.masterIdField)) + .filter(Objects::nonNull) + .collect(toSet()); + if (CollectionUtils.isEmpty(masterIdSet)) { + continue; + } + RelationOneToManyAggregation relation = relationStruct.relationOneToManyAggregation; + // 开始获取后面所需的各种关联数据。此部分今后可以移植到缓存中,无需每次计算。 + String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass()); + String slaveColumnName = MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass()); + Tuple2 selectAndGroupByTuple = makeSelectListAndGroupByClause( + slaveTable, slaveColumnName, relation.slaveModelClass(), + slaveTable, relation.aggregationField(), relation.aggregationType()); + String selectList = selectAndGroupByTuple.getFirst(); + String groupBy = selectAndGroupByTuple.getSecond(); + List criteriaList = criteriaListMap.get(relationStruct.relationField.getName()); + if (criteriaList == null) { + criteriaList = new LinkedList<>(); + } + MyWhereCriteria inlistFilter = new MyWhereCriteria(); + inlistFilter.setCriteria(relation.slaveModelClass(), + relation.slaveIdField(), MyWhereCriteria.OPERATOR_IN, masterIdSet); + criteriaList.add(inlistFilter); + if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) { + MyWhereCriteria deleteFilter = new MyWhereCriteria(); + deleteFilter.setCriteria( + relation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList); + List> aggregationMapList = + mapper().getGroupedListByCondition(slaveTable, selectList, criteriaString, groupBy); + doMakeLocalAggregationData(aggregationMapList, resultList, relationStruct); + } + } + + /** + * 根据实体对象和过滤条件,集成本地一对多关联聚合计算数据。 + * + * @param dataObject 实体对象。 + * @param criteriaListMap 过滤参数。key为主表字段名称,value是过滤条件列表。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + private void buildOneToManyAggregationForData( + T dataObject, Map> criteriaListMap, Set ignoreFields) { + if (dataObject == null || CollectionUtils.isEmpty(this.relationOneToManyAggrStructList)) { + return; + } + if (criteriaListMap == null) { + criteriaListMap = new HashMap<>(relationOneToManyAggrStructList.size()); + } + for (RelationStruct relationStruct : this.relationOneToManyAggrStructList) { + if (ignoreFields != null && ignoreFields.contains(relationStruct.relationField.getName())) { + continue; + } + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (masterIdValue != null) { + RelationOneToManyAggregation relation = relationStruct.relationOneToManyAggregation; + String slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass()); + String slaveColumnName = + MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass()); + Tuple2 selectAndGroupByTuple = makeSelectListAndGroupByClause( + slaveTable, slaveColumnName, relation.slaveModelClass(), + slaveTable, relation.aggregationField(), relation.aggregationType()); + String selectList = selectAndGroupByTuple.getFirst(); + String groupBy = selectAndGroupByTuple.getSecond(); + String whereClause = this.makeOneToManyWhereClause( + relationStruct, masterIdValue, slaveColumnName, criteriaListMap); + // 获取分组聚合计算结果 + List> aggregationMapList = + mapper().getGroupedListByCondition(slaveTable, selectList, whereClause, groupBy); + // 将计算结果回填到主表关联字段 + if (CollectionUtils.isNotEmpty(aggregationMapList)) { + Object value = aggregationMapList.get(0).get(AGGREGATED_VALUE); + if (value != null) { + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value); + } + } + } + } + } + + /** + * 仅仅在spring boot 启动后的监听器事件中调用,缓存所有service的关联关系,加速后续的数据绑定效率。 + */ + @Override + public void loadRelationStruct() { + Field[] fields = ReflectUtil.getFields(modelClass); + for (Field f : fields) { + initializeRelationDictStruct(f); + initializeRelationStruct(f); + initializeRelationAggregationStruct(f); + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void saveInternal(List dataList, Supplier idGenerator, Consumer> batchInserter) { + if (CollectionUtils.isEmpty(dataList)) { + return; + } + dataList.stream().filter(c -> ReflectUtil.getFieldValue(c, idFieldName) == null) + .forEach(o -> ReflectUtil.setFieldValue(o, idFieldName, idGenerator.get())); + if (batchInserter != null) { + batchInserter.accept(dataList); + } else { + for (M data : dataList) { + mapper().insert(data); + } + } + } + + /** + * 缺省实现返回null,在进行一对多和多对多聚合计算时,没有额外的自定义过滤条件。如有需要,需子类自行实现。 + * + * @return 自定义过滤条件列表。 + */ + protected Map> buildAggregationAdditionalWhereCriteria() { + return null; + } + + /** + * 判断当前对象的关联字段数据是否需要被验证,如果原有对象为null,表示新对象第一次插入,则必须验证。 + * + * @param object 新对象。 + * @param originalObject 原有对象。 + * @param fieldGetter 获取需要验证字段的函数对象。 + * @param 需要验证字段的类型。 + * @return 需要关联验证返回true,否则false。 + */ + protected boolean needToVerify(M object, M originalObject, Function fieldGetter) { + T data = fieldGetter.apply(object); + if (data == null) { + return false; + } + if (data instanceof String) { + String stringData = (String) data; + if (stringData.length() == 0) { + return false; + } + } + if (originalObject == null) { + return true; + } + T originalData = fieldGetter.apply(originalObject); + return !data.equals(originalData); + } + + /** + * 因为Mybatis Plus中QueryWrapper的条件方法都要求传入数据表字段名,因此提供该函数将 + * Java实体对象的字段名转换为数据表字段名,如果不存在会抛出异常。 + * 另外在MyModelUtil.mapToColumnName有一级缓存,对于查询过的对象字段都会放到缓存中, + * 下次映射转换的时候,会直接从缓存获取。 + * + * @param fieldName Java实体对象的字段名。 + * @return 对应的数据表字段名。 + */ + protected String safeMapToColumnName(String fieldName) { + String columnName = MyModelUtil.mapToColumnName(fieldName, modelClass); + if (columnName == null) { + throw new InvalidDataFieldException(modelClass.getSimpleName(), fieldName); + } + return columnName; + } + + /** + * 因为Mybatis Plus在update的时候,不能将实体对象中值为null的字段,更新为null, + * 而且忽略更新,在全部更新场景下,这个是非常重要的,所以我们写了这个函数绕开这一问题。 + * 该函数会遍历实体对象中,所有不包含@Transient注解,没有transient修饰符的字段,如果 + * 当前对象的该字段值为null,则会调用UpdateWrapper的set方法,将该字段赋值为null。 + * 相比于其他重载方法,该方法会将参数中的主键id,设置到UpdateWrapper的过滤条件中。 + * + * @param o 实体对象。 + * @param id 实体对象的主键值。 + * @return 创建后的UpdateWrapper。 + */ + protected UpdateWrapper createUpdateQueryForNullValue(M o, K id) { + UpdateWrapper uw = createUpdateQueryForNullValue(o, modelClass); + try { + M filter = modelClass.newInstance(); + this.setIdFieldMethod.invoke(filter, id); + uw.setEntity(filter); + } catch (Exception e) { + log.error("Failed to call reflection code of BaseService.createUpdateQueryForNullValue.", e); + throw new MyRuntimeException(e); + } + return uw; + } + + /** + * 因为Mybatis Plus在update的时候,不能将实体对象中值为null的字段,更新为null, + * 而且忽略更新,在全部更新场景下,这个是非常重要的,所以我们写了这个函数绕开这一问题。 + * 该函数会遍历实体对象中,所有不包含@Transient注解,没有transient修饰符的字段,如果 + * 当前对象的该字段值为null,则会调用UpdateWrapper的set方法,将该字段赋值为null。 + * + * @param o 实体对象。 + * @return 创建后的UpdateWrapper。 + */ + protected UpdateWrapper createUpdateQueryForNullValue(M o) { + return createUpdateQueryForNullValue(o, modelClass); + } + + /** + * 因为Mybatis Plus在update的时候,不能将实体对象中值为null的字段,更新为null, + * 而且忽略更新,在全部更新场景下,这个是非常重要的,所以我们写了这个函数绕开这一问题。 + * 该函数会遍历实体对象中,所有不包含@Transient注解,没有transient修饰符的字段,如果 + * 当前对象的该字段值为null,则会调用UpdateWrapper的set方法,将该字段赋值为null。 + * + * @param o 实体对象。 + * @param clazz 实体对象的class。 + * @return 创建后的UpdateWrapper。 + */ + public static UpdateWrapper createUpdateQueryForNullValue(T o, Class clazz) { + UpdateWrapper uw = new UpdateWrapper<>(); + Field[] fields = ReflectUtil.getFields(clazz); + List nullColumnList = new LinkedList<>(); + for (Field field : fields) { + TableField tableField = field.getAnnotation(TableField.class); + if (tableField == null || tableField.exist()) { + int modifiers = field.getModifiers(); + // transient类型的字段不能作为查询条件,静态字段和逻辑删除都不考虑。 + int transientMask = 128; + if ((modifiers & transientMask) == 1 + || Modifier.isStatic(modifiers) + || field.getAnnotation(TableLogic.class) != null) { + continue; + } + // 仅当实体对象参数中,当前字段值为null的时候,才会赋值给UpdateWrapper。 + // 以便在后续的更新中,可以将这些null字段的值设置到数据库表对应的字段中。 + if (ReflectUtil.getFieldValue(o, field) == null) { + nullColumnList.add(MyModelUtil.safeMapToColumnName(field.getName(), clazz)); + } + } + } + if (CollectionUtils.isNotEmpty(nullColumnList)) { + for (String nullColumn : nullColumnList) { + uw.set(nullColumn, null); + } + } + return uw; + } + + @SuppressWarnings("unchecked") + private void initializeRelationStruct(Field f) { + RelationOneToOne relationOneToOne = f.getAnnotation(RelationOneToOne.class); + if (relationOneToOne != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToOne.masterIdField()); + relationStruct.relationOneToOne = relationOneToOne; + if (StringUtils.isNotBlank(relationOneToOne.slaveServiceName())) { + relationStruct.service = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationOneToOne.slaveServiceName())); + } else { + relationStruct.service = (BaseService) + ApplicationContextHolder.getBean(relationOneToOne.slaveServiceClass()); + } + relationOneToOneStructList.add(relationStruct); + return; + } + RelationOneToMany relationOneToMany = f.getAnnotation(RelationOneToMany.class); + if (relationOneToMany != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToMany.masterIdField()); + relationStruct.relationOneToMany = relationOneToMany; + if (StringUtils.isNotBlank(relationOneToMany.slaveServiceName())) { + relationStruct.service = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationOneToMany.slaveServiceName())); + } else { + relationStruct.service = (BaseService) + ApplicationContextHolder.getBean(relationOneToMany.slaveServiceClass()); + } + relationOneToManyStructList.add(relationStruct); + return; + } + RelationManyToMany relationManyToMany = f.getAnnotation(RelationManyToMany.class); + if (relationManyToMany != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationManyToMany.relationMasterIdField()); + relationStruct.relationManyToMany = relationManyToMany; + relationStruct.manyToManyMapper = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationManyToMany.relationMapperName())); + relationManyToManyStructList.add(relationStruct); + } + } + + @SuppressWarnings("unchecked") + private void initializeRelationAggregationStruct(Field f) { + RelationOneToManyAggregation relationOneToManyAggregation = f.getAnnotation(RelationOneToManyAggregation.class); + if (relationOneToManyAggregation != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationOneToManyAggregation.masterIdField()); + relationStruct.relationOneToManyAggregation = relationOneToManyAggregation; + if (StringUtils.isNotBlank(relationOneToManyAggregation.slaveServiceName())) { + relationStruct.service = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationOneToManyAggregation.slaveServiceName())); + } else { + relationStruct.service = (BaseService) + ApplicationContextHolder.getBean(relationOneToManyAggregation.slaveServiceClass()); + } + relationOneToManyAggrStructList.add(relationStruct); + return; + } + RelationManyToManyAggregation relationManyToManyAggregation = f.getAnnotation(RelationManyToManyAggregation.class); + if (relationManyToManyAggregation != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationManyToManyAggregation.masterIdField()); + relationStruct.relationManyToManyAggregation = relationManyToManyAggregation; + if (StringUtils.isNotBlank(relationManyToManyAggregation.slaveServiceName())) { + relationStruct.service = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationManyToManyAggregation.slaveServiceName())); + } else { + relationStruct.service = (BaseService) + ApplicationContextHolder.getBean(relationManyToManyAggregation.slaveServiceClass()); + } + relationManyToManyAggrStructList.add(relationStruct); + } + } + + @SuppressWarnings("unchecked") + private void initializeRelationDictStruct(Field f) { + RelationConstDict relationConstDict = f.getAnnotation(RelationConstDict.class); + if (relationConstDict != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationConstDict.masterIdField()); + Field dictMapField = ReflectUtil.getField(relationConstDict.constantDictClass(), "DICT_MAP"); + relationStruct.dictMap = (Map) ReflectUtil.getFieldValue(modelClass, dictMapField); + relationConstDictStructList.add(relationStruct); + return; + } + RelationDict relationDict = f.getAnnotation(RelationDict.class); + if (relationDict != null) { + RelationStruct relationStruct = new RelationStruct(); + relationStruct.relationField = f; + relationStruct.masterIdField = ReflectUtil.getField(modelClass, relationDict.masterIdField()); + relationStruct.relationDict = relationDict; + if (StringUtils.isNotBlank(relationDict.equalOneToOneRelationField())) { + relationStruct.equalOneToOneRelationField = + ReflectUtil.getField(modelClass, relationDict.equalOneToOneRelationField()); + } + if (StringUtils.isNotBlank(relationDict.slaveServiceName())) { + relationStruct.service = ApplicationContextHolder.getBean( + StringUtils.uncapitalize(relationDict.slaveServiceName())); + } else { + relationStruct.service = (BaseService) + ApplicationContextHolder.getBean(relationDict.slaveServiceClass()); + } + relationDictStructList.add(relationStruct); + } + } + + private BasicAggregationRelationInfo parseBasicAggregationRelationInfo( + RelationStruct relationStruct, Map> criteriaListMap) { + RelationManyToManyAggregation relation = relationStruct.relationManyToManyAggregation; + BasicAggregationRelationInfo relationInfo = new BasicAggregationRelationInfo(); + // 提取关联中用到的各种字段和表数据。 + relationInfo.slaveTable = MyModelUtil.mapToTableName(relation.slaveModelClass()); + relationInfo.relationTable = MyModelUtil.mapToTableName(relation.relationModelClass()); + relationInfo.relationMasterColumn = + MyModelUtil.mapToColumnName(relation.relationMasterIdField(), relation.relationModelClass()); + relationInfo.relationSlaveColumn = + MyModelUtil.mapToColumnName(relation.relationSlaveIdField(), relation.relationModelClass()); + relationInfo.slaveColumn = MyModelUtil.mapToColumnName(relation.slaveIdField(), relation.slaveModelClass()); + // 判断是否只需要关联中间表即可,从而提升查询统计的效率。 + // 1. 统计字段为中间表字段。2. 自定义过滤条件中没有基于从表字段的过滤条件。 + relationInfo.onlySelectRelationTable = + relation.aggregationModelClass().equals(relation.relationModelClass()); + if (relationInfo.onlySelectRelationTable && MapUtils.isNotEmpty(criteriaListMap)) { + List criteriaList = + criteriaListMap.get(relationStruct.relationField.getName()); + if (CollectionUtils.isNotEmpty(criteriaList)) { + for (MyWhereCriteria whereCriteria : criteriaList) { + if (whereCriteria.getModelClazz().equals(relation.slaveModelClass())) { + relationInfo.onlySelectRelationTable = false; + break; + } + } + } + } + String aggregationTable = relation.aggregationModelClass().equals(relation.relationModelClass()) + ? relationInfo.relationTable : relationInfo.slaveTable; + Tuple2 selectAndGroupByTuple = makeSelectListAndGroupByClause( + relationInfo.relationTable, relationInfo.relationMasterColumn, relation.aggregationModelClass(), + aggregationTable, relation.aggregationField(), relation.aggregationType()); + relationInfo.selectList = selectAndGroupByTuple.getFirst(); + relationInfo.groupBy = selectAndGroupByTuple.getSecond(); + return relationInfo; + } + + private String makeManyToManyWhereClause( + RelationStruct relationStruct, + Object masterIdValue, + BasicAggregationRelationInfo basicRelationInfo, + Map> criteriaListMap) { + StringBuilder whereClause = new StringBuilder(256); + whereClause.append(basicRelationInfo.relationTable) + .append(".").append(basicRelationInfo.relationMasterColumn); + if (masterIdValue instanceof Number) { + whereClause.append(" = ").append(masterIdValue); + } else { + whereClause.append(" = '").append(masterIdValue).append("'"); + } + // 如果需要从表聚合计算或参与过滤,则需要把中间表和从表之间的关联条件加上。 + if (!basicRelationInfo.onlySelectRelationTable) { + whereClause.append(AND_OP) + .append(basicRelationInfo.relationTable) + .append(".") + .append(basicRelationInfo.relationSlaveColumn) + .append(" = ") + .append(basicRelationInfo.slaveTable) + .append(".") + .append(basicRelationInfo.slaveColumn); + } + List criteriaList = criteriaListMap.get(relationStruct.relationField.getName()); + if (criteriaList == null) { + criteriaList = new LinkedList<>(); + } + if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) { + MyWhereCriteria deleteFilter = new MyWhereCriteria(); + deleteFilter.setCriteria( + relationStruct.relationManyToManyAggregation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + if (CollectionUtils.isNotEmpty(criteriaList)) { + String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList); + whereClause.append(AND_OP).append(criteriaString); + } + return whereClause.toString(); + } + + private String makeOneToManyWhereClause( + RelationStruct relationStruct, + Object masterIdValue, + String slaveColumnName, + Map> criteriaListMap) { + StringBuilder whereClause = new StringBuilder(64); + if (masterIdValue instanceof Number) { + whereClause.append(slaveColumnName).append(" = ").append(masterIdValue); + } else { + whereClause.append(slaveColumnName).append(" = '").append(masterIdValue).append("'"); + } + List criteriaList = criteriaListMap.get(relationStruct.relationField.getName()); + if (criteriaList == null) { + criteriaList = new LinkedList<>(); + } + if (StringUtils.isNotBlank(relationStruct.service.deletedFlagFieldName)) { + MyWhereCriteria deleteFilter = new MyWhereCriteria(); + deleteFilter.setCriteria( + relationStruct.relationOneToManyAggregation.slaveModelClass(), + relationStruct.service.deletedFlagFieldName, + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + if (CollectionUtils.isNotEmpty(criteriaList)) { + String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList); + whereClause.append(AND_OP).append(criteriaString); + } + return whereClause.toString(); + } + + private static class BasicAggregationRelationInfo { + private String slaveTable; + private String slaveColumn; + private String relationTable; + private String relationMasterColumn; + private String relationSlaveColumn; + private String selectList; + private String groupBy; + private boolean onlySelectRelationTable; + } + + private void doMakeLocalAggregationData( + List> aggregationMapList, List resultList, RelationStruct relationStruct) { + if (CollectionUtils.isEmpty(resultList)) { + return; + } + // 根据获取的分组聚合结果集,绑定到主表总的关联字段。 + if (CollectionUtils.isNotEmpty(aggregationMapList)) { + Map relatedMap = new HashMap<>(aggregationMapList.size()); + for (Map map : aggregationMapList) { + relatedMap.put(map.get(GROUPED_KEY), map.get(AGGREGATED_VALUE)); + } + for (M dataObject : resultList) { + Object masterIdValue = ReflectUtil.getFieldValue(dataObject, relationStruct.masterIdField); + if (masterIdValue != null) { + Object value = relatedMap.get(masterIdValue); + if (value != null) { + ReflectUtil.setFieldValue(dataObject, relationStruct.relationField, value); + } + } + } + } + } + + private Tuple2 makeSelectListAndGroupByClause( + String groupTableName, + String groupColumnName, + Class aggregationModel, + String aggregationTableName, + String aggregationField, + Integer aggregationType) { + if (!AggregationType.isValid(aggregationType)) { + throw new IllegalArgumentException("Invalid AggregationType Value [" + + aggregationType + "] in Model [" + aggregationModel.getName() + "]."); + } + String aggregationFunc = AggregationType.getAggregationFunction(aggregationType); + String aggregationColumn = MyModelUtil.mapToColumnName(aggregationField, aggregationModel); + if (StringUtils.isBlank(aggregationColumn)) { + throw new IllegalArgumentException("Invalid AggregationField [" + + aggregationField + "] in Model [" + aggregationModel.getName() + "]."); + } + // 构建Select List + // 如:r_table.master_id groupedKey, SUM(r_table.aggr_column) aggregated_value + StringBuilder groupedSelectList = new StringBuilder(128); + groupedSelectList.append(groupTableName) + .append(".") + .append(groupColumnName) + .append(" ") + .append(GROUPED_KEY) + .append(", ") + .append(aggregationFunc) + .append("(") + .append(aggregationTableName) + .append(".") + .append(aggregationColumn) + .append(") ") + .append(AGGREGATED_VALUE) + .append(" "); + StringBuilder groupBy = new StringBuilder(64); + groupBy.append(groupTableName).append(".").append(groupColumnName); + return new Tuple2<>(groupedSelectList.toString(), groupBy.toString()); + } + + static class RelationStruct { + private Field relationField; + private Field masterIdField; + private Field equalOneToOneRelationField; + private BaseService service; + private BaseDaoMapper manyToManyMapper; + private Map dictMap; + private RelationDict relationDict; + private RelationOneToOne relationOneToOne; + private RelationOneToMany relationOneToMany; + private RelationManyToMany relationManyToMany; + private RelationOneToManyAggregation relationOneToManyAggregation; + private RelationManyToManyAggregation relationManyToManyAggregation; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/IBaseDictService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/IBaseDictService.java new file mode 100644 index 00000000..f2c9e049 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/IBaseDictService.java @@ -0,0 +1,82 @@ +package com.flow.demo.common.core.base.service; + +import java.io.Serializable; +import java.util.List; + +/** + * 带有缓存功能的字典Service接口。 + * + * @param Model实体对象的类型。 + * @param Model对象主键的类型。 + * @author Jerry + * @date 2021-06-06 + */ +public interface IBaseDictService extends IBaseService { + + /** + * 重新加载数据库中所有当前表数据到系统内存。 + * + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + void reloadCachedData(boolean force); + + /** + * 保存新增对象。 + * + * @param data 新增对象。 + * @return 返回新增对象。 + */ + M saveNew(M data); + + /** + * 更新数据对象。 + * + * @param data 更新的对象。 + * @param originalData 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(M data, M originalData); + + /** + * 删除指定数据。 + * + * @param id 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(K id); + + /** + * 直接从缓存池中获取所有数据。 + * + * @return 返回所有数据。 + */ + List getAllListFromCache(); + + /** + * 存入缓存。 + * + * @param data 新增或更新数据。 + */ + void putDictionaryCache(M data); + + /** + * 根据字典主键将数据从缓存中删除。 + * + * @param id 字典主键。 + */ + void removeDictionaryCache(K id); + + /** + * 根据字典对象将数据从缓存中删除。 + * + * @param data 字典数据。 + */ + void removeDictionaryCacheByModel(M data); + + /** + * 获取缓存中的数据数量。 + * + * @return 缓存中的数据总量。 + */ + int getCachedCount(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/IBaseService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/IBaseService.java new file mode 100644 index 00000000..d909614c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/base/service/IBaseService.java @@ -0,0 +1,286 @@ +package com.flow.demo.common.core.base.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.flow.demo.common.core.object.MyRelationParam; + +import java.io.Serializable; +import java.util.*; +import java.util.function.Consumer; +import java.util.function.Supplier; + +/** + * 所有Service的接口。 + * + * @param Model对象的类型。 + * @param Model对象主键的类型。 + * @author Jerry + * @date 2021-06-06 + */ +public interface IBaseService extends IService{ + + /** + * 根据过滤条件删除数据。 + * + * @param filter 过滤对象。 + * @return 删除数量。 + */ + Integer removeBy(M filter); + + /** + * 判断指定字段的数据是否存在,且仅仅存在一条记录。 + * 如果是基于主键的过滤,会直接调用existId过滤函数,提升性能。在有缓存的场景下,也可以利用缓存。 + * + * @param fieldName 待过滤的字段名(Java 字段)。 + * @param fieldValue 字段值。 + * @return 存在且仅存在一条返回true,否则false。 + */ + boolean existOne(String fieldName, Object fieldValue); + + /** + * 判断主键Id关联的数据是否存在。 + * + * @param id 主键Id。 + * @return 存在返回true,否则false。 + */ + boolean existId(K id); + + /** + * 返回符合 filterField = filterValue 条件的一条数据。 + * + * @param filterField 过滤的Java字段。 + * @param filterValue 过滤的Java字段值。 + * @return 查询后的数据对象。 + */ + M getOne(String filterField, Object filterValue); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * + * @param id 主表主键Id。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @return 查询结果对象。 + */ + M getByIdWithRelation(K id, MyRelationParam relationParam); + + /** + * 获取所有数据。 + * + * @return 返回所有数据。 + */ + List getAllList(); + + /** + * 获取排序后所有数据。 + * + * @param orderByProperties 需要排序的字段属性,这里使用Java对象中的属性名,而不是数据库字段名。 + * @return 返回排序后所有数据。 + */ + List getAllListByOrder(String... orderByProperties); + + /** + * 判断参数值主键集合中的所有数据,是否全部存在 + * + * @param idSet 待校验的主键集合。 + * @return 全部存在返回true,否则false。 + */ + boolean existAllPrimaryKeys(Set idSet); + + /** + * 判断参数值列表中的所有数据,是否全部存在。另外,keyName字段在数据表中必须是唯一键值,否则返回结果会出现误判。 + * + * @param inFilterField 待校验的数据字段,这里使用Java对象中的属性,如courseId,而不是数据字段名course_id + * @param inFilterValues 数据值列表。 + * @return 全部存在返回true,否则false。 + */ + boolean existUniqueKeyList(String inFilterField, Set inFilterValues); + + /** + * 返回符合主键 in (idValues) 条件的所有数据。 + * + * @param idValues 主键值集合。 + * @return 检索后的数据列表。 + */ + List getInList(Set idValues); + + /** + * 返回符合 inFilterField in (inFilterValues) 条件的所有数据。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param inFilterValues 参与(In-list)过滤的Java字段值集合。 + * @return 检索后的数据列表。 + */ + List getInList(String inFilterField, Set inFilterValues); + + /** + * 返回符合 inFilterField in (inFilterValues) 条件的所有数据,并根据orderBy字段排序。 + * + * @param inFilterField 参与(In-list)过滤的Java字段。 + * @param inFilterValues 参与(In-list)过滤的Java字段值集合。 + * @param orderBy 排序字段。 + * @return 检索后的数据列表。 + */ + List getInList(String inFilterField, Set inFilterValues, String orderBy); + + /** + * 用参数对象作为过滤条件,获取数据数量。 + * + * @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件。 + * @return 返回过滤后的数据数量。 + */ + int getCountByFilter(M filter); + + /** + * 用参数对象作为过滤条件,判断是否存在过滤数据。 + * + * @param filter 该方法基于mybatis 通用mapper,过滤对象中,只有被赋值的字段,才会成为where中的条件。 + * @return 存在返回true,否则false。 + */ + boolean existByFilter(M filter); + + /** + * 用参数对象作为过滤条件,获取查询结果。 + * + * @param filter 该方法基于mybatis的通用mapper。如果参数为null,则返回全部数据。 + * @return 返回过滤后的数据。 + */ + List getListByFilter(M filter); + + /** + * 获取父主键Id下的所有子数据列表。 + * + * @param parentIdFieldName 父主键字段名字,如"courseId"。 + * @param parentId 父主键的值。 + * @return 父主键Id下的所有子数据列表。 + */ + List getListByParentId(String parentIdFieldName, K parentId); + + /** + * 根据指定的显示字段列表、过滤条件字符串和分组字符串,返回聚合计算后的查询结果。(基本是内部框架使用,不建议外部接口直接使用)。 + * + * @param selectFields 选择的字段列表,多个字段逗号分隔。 + * NOTE: 如果数据表字段和Java对象字段名字不同,Java对象字段应该以别名的形式出现。 + * 如: table_column_name modelFieldName。否则无法被反射回Bean对象。 + * @param whereClause SQL常量形式的条件从句。 + * @param groupBy SQL常量形式分组字段列表,逗号分隔。 + * @return 聚合计算后的数据结果集。 + */ + List> getGroupedListByCondition(String selectFields, String whereClause, String groupBy); + + /** + * 根据指定的显示字段列表、过滤条件字符串和排序字符串,返回查询结果。(基本是内部框架使用,不建议外部接口直接使用)。 + * + * @param selectList 选择的Java字段列表。如果为空表示返回全部字段。 + * @param filter 过滤对象。 + * @param whereClause SQL常量形式的条件从句。 + * @param orderBy SQL常量形式排序字段列表,逗号分隔。 + * @return 查询结果。 + */ + List getListByCondition(List selectList, M filter, String whereClause, String orderBy); + + /** + * 用指定过滤条件,计算记录数量。(基本是内部框架使用,不建议外部接口直接使用)。 + * + * @param whereClause SQL常量形式的条件从句。 + * @return 返回过滤后的数据数量。 + */ + Integer getCountByCondition(String whereClause); + + /** + * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param relationParam 实体对象数据组装的参数构建器。 + */ + void buildRelationForDataList(List resultList, MyRelationParam relationParam); + + /** + * 集成所有与主表实体对象相关的关联数据列表。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + void buildRelationForDataList(List resultList, MyRelationParam relationParam, Set ignoreFields); + + /** + * 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询,批量导出没有分页机制, + * 因此在导出数据量较大的情况下,很容易给数据库的内存、CPU和IO带来较大的压力。而通过 + * 我们的分批处理,可以极大的规避该问题的出现几率。调整batchSize的大小,也可以有效的 + * 改善运行效率。 + * 我们目前的处理机制是,先从主表取出所有符合条件的主表数据,这样可以避免分批处理时, + * 后面几批数据,因为skip过多而带来的效率问题。因为是单表过滤,不会给数据库带来过大的压力。 + * 之后再在主表结果集数据上进行分批级联处理。 + * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param batchSize 每批集成的记录数量。小于等于0时将不做分批处理。 + */ + void buildRelationForDataList(List resultList, MyRelationParam relationParam, int batchSize); + + /** + * 该函数主要用于对查询结果的批量导出。不同于支持分页的列表查询,批量导出没有分页机制, + * 因此在导出数据量较大的情况下,很容易给数据库的内存、CPU和IO带来较大的压力。而通过 + * 我们的分批处理,可以极大的规避该问题的出现几率。调整batchSize的大小,也可以有效的 + * 改善运行效率。 + * 我们目前的处理机制是,先从主表取出所有符合条件的主表数据,这样可以避免分批处理时, + * 后面几批数据,因为skip过多而带来的效率问题。因为是单表过滤,不会给数据库带来过大的压力。 + * 之后再在主表结果集数据上进行分批级联处理。 + * 集成所有与主表实体对象相关的关联数据列表。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param resultList 主表实体对象列表。数据集成将直接作用于该对象列表。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param batchSize 每批集成的记录数量。小于等于0时将不做分批处理。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + */ + void buildRelationForDataList( + List resultList, MyRelationParam relationParam, int batchSize, Set ignoreFields); + + /** + * 集成所有与主表实体对象相关的关联数据对象。包括一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param dataObject 主表实体对象。数据集成将直接作用于该对象。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param 实体对象类型。 + */ + void buildRelationForData(T dataObject, MyRelationParam relationParam); + + /** + * 集成所有与主表实体对象相关的关联数据对象。包括本地和远程服务的一对一、字典、一对多和多对多聚合运算等。 + * 也可以根据实际需求,单独调用该函数所包含的各个数据集成函数。 + * NOTE: 该方法内执行的SQL将禁用数据权限过滤。 + * + * @param dataObject 主表实体对象。数据集成将直接作用于该对象。 + * @param relationParam 实体对象数据组装的参数构建器。 + * @param ignoreFields 该集合中的字段,即便包含注解也不会在当前调用中进行数据组装。 + * @param 实体对象类型。 + */ + void buildRelationForData(T dataObject, MyRelationParam relationParam, Set ignoreFields); + + /** + * 仅仅在spring boot 启动后的监听器事件中调用,缓存所有service的关联关系,加速后续的数据绑定效率。 + */ + void loadRelationStruct(); + + /** + * 内部使用的批量保存方法。在使用前要确保清楚该方法的实现功能。 + * 该方法通常用于从表数据的批量更新,为了保证已有数据的主键不变,我们通常会在执行该方法前,根据主表的关联数据, + * 删除从表中的数据。之后在迭代参数dataList,并将没有主键值的对象视为新对象,该方法将为这些新对象生成主键值。 + * 其他包含主键值的对象,为已有对象,不做任何修改。填充主键后,将dataList集合中的数据批量插入到数据表。 + * + * @param dataList 待操作的数据列表。 + * @param idGenerator 主键值生成器方法。 + * @param batchInserter 批量插入方法。 + */ + void saveInternal(List dataList, Supplier idGenerator, Consumer> batchInserter); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/DictionaryCache.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/DictionaryCache.java new file mode 100644 index 00000000..bfbd1ce5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/DictionaryCache.java @@ -0,0 +1,88 @@ +package com.flow.demo.common.core.cache; + +import java.util.List; +import java.util.Set; + +/** + * 主要用于完整缓存字典表数据的接口对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Jerry + * @date 2021-06-06 + */ +public interface DictionaryCache { + + /** + * 按照数据插入的顺序返回全部字典对象的列表。 + * + * @return 全部字段数据列表。 + */ + List getAll(); + + /** + * 获取缓存中与键列表对应的对象列表。 + * + * @param keys 主键集合。 + * @return 对象列表。 + */ + List getInList(Set keys); + + /** + * 将参数List中的数据保存到缓存中,同时保证getAll返回的数据列表,与参数列表中数据项的顺序保持一致。 + * + * @param dataList 待缓存的数据列表。 + */ + void putAll(List dataList); + + /** + * 重新加载,先清空原有数据,在执行putAll的操作。 + * + * @param dataList 待缓存的数据列表。 + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + void reload(List dataList, boolean force); + + /** + * 从缓存中获取指定的数据。 + * + * @param key 数据的key。 + * @return 获取到的数据,如果没有返回null。 + */ + V get(K key); + + /** + * 将数据存入缓存。 + * + * @param key 通常为字典数据的主键。 + * @param object 字典数据对象。 + */ + void put(K key, V object); + + /** + * 获取缓存中数据条目的数量。 + * + * @return 返回缓存的数据数量。 + */ + int getCount(); + + /** + * 删除缓存中指定的键。 + * + * @param key 待删除数据的主键。 + * @return 返回被删除的对象,如果主键不存在,返回null。 + */ + V invalidate(K key); + + /** + * 删除缓存中,参数列表中包含的键。 + * + * @param keys 待删除数据的主键集合。 + */ + void invalidateSet(Set keys); + + /** + * 清空缓存。 + */ + void invalidateAll(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/MapDictionaryCache.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/MapDictionaryCache.java new file mode 100644 index 00000000..21b5969e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/MapDictionaryCache.java @@ -0,0 +1,358 @@ +package com.flow.demo.common.core.cache; + +import com.flow.demo.common.core.exception.MapCacheAccessException; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Function; + +/** + * 字典数据内存缓存对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class MapDictionaryCache implements DictionaryCache { + + /** + * 存储字典数据的Map。 + */ + protected final LinkedHashMap dataMap = new LinkedHashMap<>(); + /** + * 获取字典主键数据的函数对象。 + */ + protected final Function idGetter; + /** + * 由于大部分场景是读取操作,所以使用读写锁提高并发的伸缩性。 + */ + protected final ReadWriteLock lock = new ReentrantReadWriteLock(); + /** + * 超时时长。单位毫秒。 + */ + protected static final long TIMEOUT = 2000L; + + /** + * 当前对象的构造器函数。 + * + * @param idGetter 获取当前类主键字段值的函数对象。 + * @param 字典主键类型。 + * @param 字典对象类型 + * @return 实例化后的字典内存缓存对象。 + */ + public static MapDictionaryCache create(Function idGetter) { + if (idGetter == null) { + throw new IllegalArgumentException("IdGetter can't be NULL."); + } + return new MapDictionaryCache<>(idGetter); + } + + /** + * 构造函数。 + * + * @param idGetter 主键Id的获取函数对象。 + */ + public MapDictionaryCache(Function idGetter) { + this.idGetter = idGetter; + } + + /** + * 按照数据插入的顺序返回全部字典对象的列表。 + * + * @return 全部字段数据列表。 + */ + @Override + public List getAll() { + List resultList = new LinkedList<>(); + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + for (Map.Entry entry : dataMap.entrySet()) { + resultList.add(entry.getValue()); + } + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + return resultList; + } + + /** + * 获取缓存中与键列表对应的对象列表。 + * + * @param keys 主键集合。 + * @return 对象列表。 + */ + @Override + public List getInList(Set keys) { + List resultList = new LinkedList<>(); + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + keys.forEach(key -> { + V object = dataMap.get(key); + if (object != null) { + resultList.add(object); + } + }); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + return resultList; + } + + /** + * 将参数List中的数据保存到缓存中,同时保证getAll返回的数据列表,与参数列表中数据项的顺序保持一致。 + * + * @param dataList 待缓存的数据列表。 + */ + @Override + public void putAll(List dataList) { + if (dataList == null) { + return; + } + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataList.forEach(dataObj -> { + K id = idGetter.apply(dataObj); + dataMap.put(id, dataObj); + }); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } + + /** + * 重新加载,先清空原有数据,在执行putAll的操作。 + * + * @param dataList 待缓存的数据列表。 + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + @Override + public void reload(List dataList, boolean force) { + if (!force && this.getCount() > 0) { + return; + } + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.clear(); + dataList.forEach(dataObj -> { + K id = idGetter.apply(dataObj); + dataMap.put(id, dataObj); + }); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } + + /** + * 从缓存中获取指定的数据。 + * + * @param id 数据的key。 + * @return 获取到的数据,如果没有返回null。 + */ + @Override + public V get(K id) { + if (id == null) { + return null; + } + V data; + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + data = dataMap.get(id); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + return data; + } + + /** + * 将数据存入缓存。 + * + * @param id 通常为字典数据的主键。 + * @param object 字典数据对象。 + */ + @Override + public void put(K id, V object) { + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.put(id, object); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } + + /** + * 获取缓存中数据条目的数量。 + * + * @return 返回缓存的数据数量。 + */ + @Override + public int getCount() { + return dataMap.size(); + } + + /** + * 删除缓存中指定的键。 + * + * @param id 待删除数据的主键。 + * @return 返回被删除的对象,如果主键不存在,返回null。 + */ + @Override + public V invalidate(K id) { + if (id == null) { + return null; + } + String exceptionMessage; + V data; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + data = dataMap.remove(id); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + return data; + } + + /** + * 删除缓存中,参数列表中包含的键。 + * + * @param keys 待删除数据的主键集合。 + */ + @Override + public void invalidateSet(Set keys) { + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + keys.forEach(id -> { + if (id != null) { + dataMap.remove(id); + } + }); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } + + /** + * 清空缓存。 + */ + @Override + public void invalidateAll() { + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.clear(); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/MapTreeDictionaryCache.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/MapTreeDictionaryCache.java new file mode 100644 index 00000000..f06d37f6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/cache/MapTreeDictionaryCache.java @@ -0,0 +1,292 @@ +package com.flow.demo.common.core.cache; + +import com.flow.demo.common.core.exception.MapCacheAccessException; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import lombok.extern.slf4j.Slf4j; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; + +/** + * 树形字典数据内存缓存对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class MapTreeDictionaryCache extends MapDictionaryCache { + + /** + * 树形数据存储对象。 + */ + private final Multimap allTreeMap = LinkedHashMultimap.create(); + /** + * 获取字典父主键数据的函数对象。 + */ + protected final Function parentIdGetter; + + /** + * 当前对象的构造器函数。 + * + * @param idGetter 获取当前类主键字段值的函数对象。 + * @param parentIdGetter 获取当前类父主键字段值的函数对象。 + * @param 字典主键类型。 + * @param 字典对象类型 + * @return 实例化后的树形字典内存缓存对象。 + */ + public static MapTreeDictionaryCache create(Function idGetter, Function parentIdGetter) { + if (idGetter == null) { + throw new IllegalArgumentException("IdGetter can't be NULL."); + } + if (parentIdGetter == null) { + throw new IllegalArgumentException("ParentIdGetter can't be NULL."); + } + return new MapTreeDictionaryCache<>(idGetter, parentIdGetter); + } + + /** + * 构造函数。 + * + * @param idGetter 获取当前类主键字段值的函数对象。 + * @param parentIdGetter 获取当前类父主键字段值的函数对象。 + */ + public MapTreeDictionaryCache(Function idGetter, Function parentIdGetter) { + super(idGetter); + this.parentIdGetter = parentIdGetter; + } + + + /** + * 重新加载,先清空原有数据,在执行putAll的操作。 + * + * @param dataList 待缓存的数据列表。 + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + @Override + public void reload(List dataList, boolean force) { + if (!force && this.getCount() > 0) { + return; + } + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.clear(); + allTreeMap.clear(); + dataList.forEach(data -> { + K id = idGetter.apply(data); + dataMap.put(id, data); + K parentId = parentIdGetter.apply(data); + allTreeMap.put(parentId, data); + }); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } + + /** + * 获取该父主键的子数据列表。 + * + * @param parentId 父主键Id。 + * @return 子数据列表。 + */ + public List getListByParentId(K parentId) { + List resultList = new LinkedList<>(); + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + resultList.addAll(allTreeMap.get(parentId)); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + return resultList; + } + + /** + * 将参数List中的数据保存到缓存中,同时保证getAll返回的数据列表,与参数列表中数据项的顺序保持一致。 + * + * @param dataList 待缓存的数据列表。 + */ + @Override + public void putAll(List dataList) { + if (dataList == null) { + return; + } + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataList.forEach(data -> { + K id = idGetter.apply(data); + dataMap.put(id, data); + K parentId = parentIdGetter.apply(data); + allTreeMap.remove(parentId, data); + allTreeMap.put(parentId, data); + }); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } + + /** + * 将数据存入缓存。 + * + * @param id 通常为字典数据的主键。 + * @param data 字典数据对象。 + */ + @Override + public void put(K id, V data) { + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.put(id, data); + K parentId = parentIdGetter.apply(data); + allTreeMap.remove(parentId, data); + allTreeMap.put(parentId, data); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } + + /** + * 删除缓存中指定的键。 + * + * @param id 待删除数据的主键。 + * @return 返回被删除的对象,如果主键不存在,返回null。 + */ + @Override + public V invalidate(K id) { + V v; + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + v = dataMap.remove(id); + if (v != null) { + K parentId = parentIdGetter.apply(v); + allTreeMap.remove(parentId, v); + } + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + return v; + } + + /** + * 删除缓存中,参数列表中包含的键。 + * + * @param keys 待删除数据的主键集合。 + */ + @Override + public void invalidateSet(Set keys) { + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + keys.forEach(id -> { + if (id != null) { + V data = dataMap.remove(id); + if (data != null) { + K parentId = parentIdGetter.apply(data); + allTreeMap.remove(parentId, data); + } + } + }); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } + + /** + * 清空缓存。 + */ + @Override + public void invalidateAll() { + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.clear(); + allTreeMap.clear(); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [MapDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT.", + e.getClass().getSimpleName()); + log.warn(exceptionMessage); + throw new MapCacheAccessException(exceptionMessage, e); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/CommonWebMvcConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/CommonWebMvcConfig.java new file mode 100644 index 00000000..02c1bbf3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/CommonWebMvcConfig.java @@ -0,0 +1,67 @@ +package com.flow.demo.common.core.config; + +import com.alibaba.fastjson.serializer.SerializerFeature; +import com.alibaba.fastjson.support.config.FastJsonConfig; +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import com.flow.demo.common.core.interceptor.MyRequestArgumentResolver; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.validation.beanvalidation.MethodValidationPostProcessor; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * 所有的项目拦截器、参数解析器、消息对象转换器都在这里集中配置。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +public class CommonWebMvcConfig implements WebMvcConfigurer { + + @Bean + public MethodValidationPostProcessor methodValidationPostProcessor() { + return new MethodValidationPostProcessor(); + } + + @Override + public void addArgumentResolvers(List argumentResolvers) { + // 添加MyRequestBody参数解析器 + argumentResolvers.add(new MyRequestArgumentResolver()); + } + + @Bean + public HttpMessageConverter responseBodyConverter() { + return new StringHttpMessageConverter(StandardCharsets.UTF_8); + } + + @Bean + public FastJsonHttpMessageConverter fastJsonHttpMessageConverters() { + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + List supportedMediaTypes = new ArrayList<>(); + supportedMediaTypes.add(MediaType.APPLICATION_JSON); + supportedMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); + fastConverter.setSupportedMediaTypes(supportedMediaTypes); + FastJsonConfig fastJsonConfig = new FastJsonConfig(); + fastJsonConfig.setSerializerFeatures( + SerializerFeature.PrettyFormat, + SerializerFeature.DisableCircularReferenceDetect, + SerializerFeature.IgnoreNonFieldGetter); + fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); + fastConverter.setFastJsonConfig(fastJsonConfig); + return fastConverter; + } + + @Override + public void configureMessageConverters(List> converters) { + converters.add(responseBodyConverter()); + converters.add(fastJsonHttpMessageConverters()); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/DataSourceContextHolder.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/DataSourceContextHolder.java new file mode 100644 index 00000000..ccc5700c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/DataSourceContextHolder.java @@ -0,0 +1,52 @@ +package com.flow.demo.common.core.config; + +/** + * 通过线程本地存储的方式,保存当前数据库操作所需的数据源类型,动态数据源会根据该值,进行动态切换。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class DataSourceContextHolder { + + private static final ThreadLocal CONTEXT_HOLDER = new ThreadLocal<>(); + + /** + * 设置数据源类型。 + * + * @param type 数据源类型 + * @return 原有数据源类型,如果第一次设置则返回null。 + */ + public static Integer setDataSourceType(Integer type) { + Integer datasourceType = CONTEXT_HOLDER.get(); + CONTEXT_HOLDER.set(type); + return datasourceType; + } + + /** + * 获取当前数据库操作执行线程的数据源类型,同时由动态数据源的路由函数调用。 + * + * @return 数据源类型。 + */ + public static Integer getDataSourceType() { + return CONTEXT_HOLDER.get(); + } + + /** + * 清除线程本地变量,以免内存泄漏。 + + * @param originalType 原有的数据源类型,如果该值为null,则情况本地化变量。 + */ + public static void unset(Integer originalType) { + if (originalType == null) { + CONTEXT_HOLDER.remove(); + } else { + CONTEXT_HOLDER.set(originalType); + } + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private DataSourceContextHolder() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/DynamicDataSource.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/DynamicDataSource.java new file mode 100644 index 00000000..88d93205 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/DynamicDataSource.java @@ -0,0 +1,17 @@ +package com.flow.demo.common.core.config; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +/** + * 动态数据源对象。当存在多个数据连接时使用。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class DynamicDataSource extends AbstractRoutingDataSource { + + @Override + protected Object determineCurrentLookupKey() { + return DataSourceContextHolder.getDataSourceType(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/EncryptConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/EncryptConfig.java new file mode 100644 index 00000000..4d91b5cf --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/EncryptConfig.java @@ -0,0 +1,20 @@ +package com.flow.demo.common.core.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; + +/** + * 目前用于用户密码加密,UAA接入应用客户端的client_secret加密。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +public class EncryptConfig { + + @Bean + public BCryptPasswordEncoder passwordEncoder() { + return new BCryptPasswordEncoder(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/RestTemplateConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/RestTemplateConfig.java new file mode 100644 index 00000000..526e6127 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/RestTemplateConfig.java @@ -0,0 +1,64 @@ +package com.flow.demo.common.core.config; + +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.apache.http.client.HttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.ClientHttpResponse; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.web.client.DefaultResponseErrorHandler; +import org.springframework.web.client.RestOperations; +import org.springframework.web.client.RestTemplate; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + * RestTemplate连接池配置对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +public class RestTemplateConfig { + private static final int MAX_TOTAL_CONNECTION = 50; + private static final int MAX_CONNECTION_PER_ROUTE = 20; + private static final int CONNECTION_TIMEOUT = 20000; + private static final int READ_TIMEOUT = 30000; + + @Bean + @ConditionalOnMissingBean({RestOperations.class, RestTemplate.class}) + public RestTemplate restTemplate() { + RestTemplate restTemplate = new RestTemplate(createFactory()); + List> messageConverters = restTemplate.getMessageConverters(); + messageConverters.removeIf( + c -> c instanceof StringHttpMessageConverter || c instanceof MappingJackson2HttpMessageConverter); + messageConverters.add(1, new StringHttpMessageConverter(StandardCharsets.UTF_8)); + messageConverters.add(new FastJsonHttpMessageConverter()); + restTemplate.setErrorHandler(new DefaultResponseErrorHandler() { + @Override + public void handleError(ClientHttpResponse response) throws IOException { + // 防止400+和500等错误被直接抛出异常,这里避开了缺省处理方式,所有的错误均交给业务代码处理。 + } + }); + return restTemplate; + } + + private ClientHttpRequestFactory createFactory() { + HttpClient httpClient = HttpClientBuilder.create() + .setMaxConnTotal(MAX_TOTAL_CONNECTION) + .setMaxConnPerRoute(MAX_CONNECTION_PER_ROUTE) + .build(); + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); + factory.setReadTimeout(READ_TIMEOUT); + factory.setConnectTimeout(CONNECTION_TIMEOUT); + return factory; + } +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/TomcatConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/TomcatConfig.java new file mode 100644 index 00000000..a143b8bd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/config/TomcatConfig.java @@ -0,0 +1,39 @@ +package com.flow.demo.common.core.config; + +import org.apache.tomcat.util.descriptor.web.SecurityCollection; +import org.apache.tomcat.util.descriptor.web.SecurityConstraint; +import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * tomcat配置对象。当前配置禁用了PUT和DELETE方法,防止渗透攻击。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +public class TomcatConfig { + + @Bean + public TomcatServletWebServerFactory servletContainer() { + TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory(); + factory.addContextCustomizers(context -> { + SecurityConstraint securityConstraint = new SecurityConstraint(); + securityConstraint.setUserConstraint("CONFIDENTIAL"); + SecurityCollection collection = new SecurityCollection(); + collection.addPattern("/*"); + collection.addMethod("HEAD"); + collection.addMethod("PUT"); + collection.addMethod("PATCH"); + collection.addMethod("DELETE"); + collection.addMethod("TRACE"); + collection.addMethod("COPY"); + collection.addMethod("SEARCH"); + collection.addMethod("PROPFIND"); + securityConstraint.addCollection(collection); + context.addConstraint(securityConstraint); + }); + return factory; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/AggregationType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/AggregationType.java new file mode 100644 index 00000000..75f4b647 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/AggregationType.java @@ -0,0 +1,81 @@ +package com.flow.demo.common.core.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 聚合计算的常量类型对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class AggregationType { + + /** + * sum 计数 + */ + public static final int SUM = 0; + /** + * count 汇总 + */ + public static final int COUNT = 1; + /** + * average 平均值 + */ + public static final int AVG = 2; + /** + * min 最小值 + */ + public static final int MIN = 3; + /** + * max 最大值 + */ + public static final int MAX = 4; + + private static final Map DICT_MAP = new HashMap<>(5); + static { + DICT_MAP.put(SUM, "累计总和"); + DICT_MAP.put(COUNT, "数量总和"); + DICT_MAP.put(AVG, "平均值"); + DICT_MAP.put(MIN, "最小值"); + DICT_MAP.put(MAX, "最大值"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 获取与SQL对应的聚合函数字符串名称。 + * + * @return 聚合函数名称。 + */ + public static String getAggregationFunction(Integer aggregationType) { + switch (aggregationType) { + case COUNT: + return "COUNT"; + case AVG: + return "AVG"; + case SUM: + return "SUM"; + case MAX: + return "MAX"; + case MIN: + return "MIN"; + default: + throw new IllegalArgumentException("无效的聚合类型!"); + } + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private AggregationType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/AppDeviceType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/AppDeviceType.java new file mode 100644 index 00000000..6e56974b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/AppDeviceType.java @@ -0,0 +1,59 @@ +package com.flow.demo.common.core.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * App 登录的设备类型。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class AppDeviceType { + + /** + * 移动端 (如果不考虑区分android或ios的,可以使用该值) + */ + public static final int MOBILE = 0; + /** + * android + */ + public static final int ANDROID = 1; + /** + * iOS + */ + public static final int IOS = 2; + /** + * 微信公众号和小程序 + */ + public static final int WEIXIN = 3; + /** + * PC WEB + */ + public static final int WEB = 4; + + private static final Map DICT_MAP = new HashMap<>(5); + static { + DICT_MAP.put(MOBILE, "移动端"); + DICT_MAP.put(ANDROID, "Android"); + DICT_MAP.put(IOS, "iOS"); + DICT_MAP.put(WEIXIN, "微信"); + DICT_MAP.put(WEB, "PC WEB"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private AppDeviceType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/ApplicationConstant.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/ApplicationConstant.java new file mode 100644 index 00000000..8bbc1238 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/ApplicationConstant.java @@ -0,0 +1,85 @@ +package com.flow.demo.common.core.constant; + +/** + * 应用程序的常量声明对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class ApplicationConstant { + + /** + * 数据同步使用的缺省消息队列主题名称。 + */ + public static final String DEFAULT_DATA_SYNC_TOPIC = "DemoFlow"; + /** + * 全量数据同步中,新增数据对象的键名称。 + */ + public static final String DEFAULT_FULL_SYNC_DATA_KEY = "data"; + /** + * 全量数据同步中,原有数据对象的键名称。 + */ + public static final String DEFAULT_FULL_SYNC_OLD_DATA_KEY = "oldData"; + /** + * 全量数据同步中,数据对象主键的键名称。 + */ + public static final String DEFAULT_FULL_SYNC_ID_KEY = "id"; + /** + * 为字典表数据缓存时,缓存名称的固定后缀。 + */ + public static final String DICT_CACHE_NAME_SUFFIX = "-DICT"; + /** + * 为树形字典表数据缓存时,缓存名称的固定后缀。 + */ + public static final String TREE_DICT_CACHE_NAME_SUFFIX = "-TREE-DICT"; + /** + * 图片文件上传的父目录。 + */ + public static final String UPLOAD_IMAGE_PARENT_PATH = "image"; + /** + * 附件文件上传的父目录。 + */ + public static final String UPLOAD_ATTACHMENT_PARENT_PATH = "attachment"; + /** + * CSV文件扩展名。 + */ + public static final String CSV_EXT = "csv"; + /** + * XLSX文件扩展名。 + */ + public static final String XLSX_EXT = "xlsx"; + /** + * 统计分类计算时,按天聚合计算的常量值。(前端在MyOrderParam和MyGroupParam中传给后台) + */ + public static final String DAY_AGGREGATION = "day"; + /** + * 统计分类计算时,按月聚合计算的常量值。(前端在MyOrderParam和MyGroupParam中传给后台) + */ + public static final String MONTH_AGGREGATION = "month"; + /** + * 统计分类计算时,按年聚合计算的常量值。(前端在MyOrderParam和MyGroupParam中传给后台) + */ + public static final String YEAR_AGGREGATION = "year"; + /** + * 请求头跟踪id名。 + */ + public static final String HTTP_HEADER_TRACE_ID = "traceId"; + /** + * 操作日志的数据源类型。仅当前服务为多数据源时使用。 + * 在common-log模块中,SysOperationLogServiceImpl的MyDataSource注解一定要使用该参数。 + * 在多数据源的业务服务中,DataSourceType的常量一定要包含该值,多数据源的配置中,也一定要有与该值匹配的数据源Bean。 + */ + public static final int OPERATION_LOG_DATASOURCE_TYPE = 1000; + /** + * 重要说明:该值为项目生成后的缺省密钥,仅为使用户可以快速上手并跑通流程。 + * 在实际的应用中,一定要为不同的项目或服务,自行生成公钥和私钥,并将 PRIVATE_KEY 的引用改为服务的配置项。 + * 密钥的生成方式,可通过执行common.core.util.RsaUtil类的main函数动态生成。 + */ + public static final String PRIVATE_KEY = + "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKkLhAydtOtA4WuIkkIIUVaGWu4ElOEAQF9GTulHHWOwCHI1UvcKolvS1G+mdsKcmGtEAQ92AUde/kDRGu8Wn7kLDtCgUfo72soHz7Qfv5pVB4ohMxQd/9cxeKjKbDoirhB9Z3xGF20zUozp4ZPLxpTtI7azr0xzUtd5+D/HfLDrAgMBAAECgYEApESZhDz4YyeAJiPnpJ06lS8oS2VOWzsIUs0av5uoloeoHXtt7Lx7u2kroHeNrl3Hy2yg7ypH4dgQkGHin3VHrVAgjG3TxhgBXIqqntzzk2AGJKBeIIkRX86uTvtKZyp3flUgcwcGmpepAHS1V1DPY3aVYvbcqAmoL6DX6VYN0NECQQDQUitMdC76lEtAr5/ywS0nrZJDo6U7eQ7ywx/eiJ+YmrSye8oorlAj1VBWG+Cl6jdHOHtTQyYv/tu71fjzQiJTAkEAz7wb47/vcSUpNWQxItFpXz0o6rbJh71xmShn1AKP7XptOVZGlW9QRYEzHabV9m/DHqI00cMGhHrWZAhCiTkUCQJAFsJjaJ7o4weAkTieyO7B+CvGZw1h5/V55Jvcx3s1tH5yb22G0Jr6tm9/r2isSnQkReutzZLwgR3e886UvD7lcQJAAUcD2OOuQkDbPwPNtYwaHMbQgJj9JkOI9kskUE5vuiMdltOr/XFAyhygRtdmy2wmhAK1VnDfkmL6/IR8fEGImQJABOB0KCalb0M8CPnqqHzozrD8gPObnIIr4aVvLIPATN2g7MM2N6F7JbI4RZFiKa92LV6bhQCY8OvHi5K2cgFpbw=="; + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ApplicationConstant() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/ErrorCodeEnum.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/ErrorCodeEnum.java new file mode 100644 index 00000000..7c676cb9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/ErrorCodeEnum.java @@ -0,0 +1,84 @@ +package com.flow.demo.common.core.constant; + +/** + * 返回应答中的错误代码和错误信息。 + * + * @author Jerry + * @date 2021-06-06 + */ +public enum ErrorCodeEnum { + + /** + * 没有错误 + */ + NO_ERROR("没有错误"), + /** + * 未处理的异常! + */ + UNHANDLED_EXCEPTION("未处理的异常!"), + + ARGUMENT_NULL_EXIST("数据验证失败,接口调用参数存在空值,请核对!"), + ARGUMENT_PK_ID_NULL("数据验证失败,接口调用主键Id参数为空,请核对!"), + INVALID_ARGUMENT_FORMAT("数据验证失败,不合法的参数格式,请核对!"), + INVALID_STATUS_ARGUMENT("数据验证失败,无效的状态参数值,请核对!"), + UPLOAD_FAILED("数据验证失败,数据上传失败!"), + INVALID_UPLOAD_FIELD("数据验证失败,该字段不支持数据上传!"), + INVALID_UPLOAD_STORE_TYPE("数据验证失败,并不支持上传存储类型!"), + INVALID_UPLOAD_FILE_ARGUMENT("数据验证失败,上传文件参数错误,请核对!"), + INVALID_UPLOAD_FILE_IOERROR("上传文件写入失败,请联系管理员!"), + UNAUTHORIZED_LOGIN("当前用户尚未登录或登录已超时,请重新登录!"), + UNAUTHORIZED_USER_PERMISSION("权限验证失败,当前用户不能访问该接口,请核对!"), + NO_ACCESS_PERMISSION("当前用户没有访问权限,请核对!"), + NO_OPERATION_PERMISSION("当前用户没有操作权限,请核对!"), + + PASSWORD_ERR("密码错误,请重试!"), + INVALID_USERNAME_PASSWORD("用户名或密码错误,请重试!"), + INVALID_ACCESS_TOKEN("无效的用户访问令牌!"), + INVALID_USER_STATUS("用户状态错误,请刷新后重试!"), + INVALID_TENANT_CODE("指定的租户编码并不存在,请刷新后重试!"), + INVALID_TENANT_STATUS("当前租户为不可用状态,请刷新后重试!"), + INVALID_USER_TENANT("当前用户并不属于当前租户,请刷新后重试!"), + + HAS_CHILDREN_DATA("数据验证失败,子数据存在,请刷新后重试!"), + DATA_VALIDATED_FAILED("数据验证失败,请核对!"), + UPLOAD_FILE_FAILED("文件上传失败,请联系管理员!"), + DATA_SAVE_FAILED("数据保存失败,请联系管理员!"), + DATA_ACCESS_FAILED("数据访问失败,请联系管理员!"), + DATA_PERM_ACCESS_FAILED("数据访问失败,您没有该页面的数据访问权限!"), + DUPLICATED_UNIQUE_KEY("数据保存失败,存在重复数据,请核对!"), + DATA_NOT_EXIST("数据不存在,请刷新后重试!"), + DATA_PARENT_LEVEL_ID_NOT_EXIST("数据验证失败,父级别关联Id不存在,请刷新后重试!"), + DATA_PARENT_ID_NOT_EXIST("数据验证失败,ParentId不存在,请核对!"), + INVALID_RELATED_RECORD_ID("数据验证失败,关联数据并不存在,请刷新后重试!"), + INVALID_DATA_MODEL("数据验证失败,无效的数据实体对象!"), + INVALID_DATA_FIELD("数据验证失败,无效的数据实体对象字段!"), + INVALID_CLASS_FIELD("数据验证失败,无效的类对象字段!"), + SERVER_INTERNAL_ERROR("服务器内部错误,请联系管理员!"), + REDIS_CACHE_ACCESS_TIMEOUT("Redis缓存数据访问超时,请刷新后重试!"), + REDIS_CACHE_ACCESS_STATE_ERROR("Redis缓存数据访问状态错误,请刷新后重试!"); + + // 下面的枚举值为特定枚举值,即开发者可以根据自己的项目需求定义更多的非通用枚举值 + + /** + * 构造函数。 + * + * @param errorMessage 错误消息。 + */ + ErrorCodeEnum(String errorMessage) { + this.errorMessage = errorMessage; + } + + /** + * 错误信息。 + */ + private final String errorMessage; + + /** + * 获取错误信息。 + * + * @return 错误信息。 + */ + public String getErrorMessage() { + return errorMessage; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/GlobalDeletedFlag.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/GlobalDeletedFlag.java new file mode 100644 index 00000000..052e3385 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/constant/GlobalDeletedFlag.java @@ -0,0 +1,25 @@ +package com.flow.demo.common.core.constant; + +/** + * 数据记录逻辑删除标记常量。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class GlobalDeletedFlag { + + /** + * 表示数据表记录已经删除 + */ + public static final int DELETED = -1; + /** + * 数据记录正常 + */ + public static final int NORMAL = 1; + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private GlobalDeletedFlag() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/DataValidationException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/DataValidationException.java new file mode 100644 index 00000000..97905b08 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/DataValidationException.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.core.exception; + +/** + * 数据验证失败的自定义异常。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class DataValidationException extends RuntimeException { + + /** + * 构造函数。 + */ + public DataValidationException() { + + } + + /** + * 构造函数。 + * + * @param msg 错误信息。 + */ + public DataValidationException(String msg) { + super(msg); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidClassFieldException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidClassFieldException.java new file mode 100644 index 00000000..d58f347d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidClassFieldException.java @@ -0,0 +1,30 @@ +package com.flow.demo.common.core.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 无效的类对象字段的自定义异常。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class InvalidClassFieldException extends RuntimeException { + + private final String className; + private final String fieldName; + + /** + * 构造函数。 + * + * @param className 对象名。 + * @param fieldName 字段名。 + */ + public InvalidClassFieldException(String className, String fieldName) { + super("Invalid FieldName [" + fieldName + "] in Class [" + className + "]."); + this.className = className; + this.fieldName = fieldName; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidDataFieldException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidDataFieldException.java new file mode 100644 index 00000000..20b24849 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidDataFieldException.java @@ -0,0 +1,30 @@ +package com.flow.demo.common.core.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 无效的实体对象字段的自定义异常。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class InvalidDataFieldException extends RuntimeException { + + private final String modelName; + private final String fieldName; + + /** + * 构造函数。 + * + * @param modelName 实体对象名。 + * @param fieldName 字段名。 + */ + public InvalidDataFieldException(String modelName, String fieldName) { + super("Invalid FieldName [" + fieldName + "] in Model Class [" + modelName + "]."); + this.modelName = modelName; + this.fieldName = fieldName; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidDataModelException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidDataModelException.java new file mode 100644 index 00000000..aa4d481c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidDataModelException.java @@ -0,0 +1,27 @@ +package com.flow.demo.common.core.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 无效的实体对象的自定义异常。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class InvalidDataModelException extends RuntimeException { + + private final String modelName; + + /** + * 构造函数。 + * + * @param modelName 实体对象名。 + */ + public InvalidDataModelException(String modelName) { + super("Invalid Model Class [" + modelName + "]."); + this.modelName = modelName; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidRedisModeException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidRedisModeException.java new file mode 100644 index 00000000..40230035 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/InvalidRedisModeException.java @@ -0,0 +1,27 @@ +package com.flow.demo.common.core.exception; + +import lombok.Data; +import lombok.EqualsAndHashCode; + +/** + * 无效的Redis模式的自定义异常。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@EqualsAndHashCode(callSuper = true) +public class InvalidRedisModeException extends RuntimeException { + + private final String mode; + + /** + * 构造函数。 + * + * @param mode 错误的模式。 + */ + public InvalidRedisModeException(String mode) { + super("Invalid Redis Mode [" + mode + "], only supports [single/cluster/sentinel/master_slave]"); + this.mode = mode; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/MapCacheAccessException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/MapCacheAccessException.java new file mode 100644 index 00000000..8cfe48f9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/MapCacheAccessException.java @@ -0,0 +1,20 @@ +package com.flow.demo.common.core.exception; + +/** + * 内存缓存访问失败。比如:获取分布式数据锁超时、等待线程中断等。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class MapCacheAccessException extends RuntimeException { + + /** + * 构造函数。 + * + * @param msg 错误信息。 + * @param cause 原始异常。 + */ + public MapCacheAccessException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/MyRuntimeException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/MyRuntimeException.java new file mode 100644 index 00000000..c1399cbc --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/MyRuntimeException.java @@ -0,0 +1,36 @@ +package com.flow.demo.common.core.exception; + +/** + * 自定义的运行时异常,在需要抛出运行时异常时,可使用该异常。 + * NOTE:主要是为了避免SonarQube进行代码质量扫描时,给出警告。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class MyRuntimeException extends RuntimeException { + + /** + * 构造函数。 + */ + public MyRuntimeException() { + + } + + /** + * 构造函数。 + * + * @param throwable 引发异常对象。 + */ + public MyRuntimeException(Throwable throwable) { + super(throwable); + } + + /** + * 构造函数。 + * + * @param msg 错误信息。 + */ + public MyRuntimeException(String msg) { + super(msg); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/NoDataAffectException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/NoDataAffectException.java new file mode 100644 index 00000000..e755dc25 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/NoDataAffectException.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.core.exception; + +/** + * 没有数据被修改的自定义异常。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class NoDataAffectException extends RuntimeException { + + /** + * 构造函数。 + */ + public NoDataAffectException() { + + } + + /** + * 构造函数。 + * + * @param msg 错误信息。 + */ + public NoDataAffectException(String msg) { + super(msg); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/NoDataPermException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/NoDataPermException.java new file mode 100644 index 00000000..e156ee0a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/NoDataPermException.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.core.exception; + +/** + * 没有数据访问权限的自定义异常。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class NoDataPermException extends RuntimeException { + + /** + * 构造函数。 + */ + public NoDataPermException() { + + } + + /** + * 构造函数。 + * + * @param msg 错误信息。 + */ + public NoDataPermException(String msg) { + super(msg); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/RedisCacheAccessException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/RedisCacheAccessException.java new file mode 100644 index 00000000..c0682b42 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/exception/RedisCacheAccessException.java @@ -0,0 +1,20 @@ +package com.flow.demo.common.core.exception; + +/** + * Redis缓存访问失败。比如:获取分布式数据锁超时、等待线程中断等。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class RedisCacheAccessException extends RuntimeException { + + /** + * 构造函数。 + * + * @param msg 错误信息。 + * @param cause 原始异常。 + */ + public RedisCacheAccessException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/interceptor/MyRequestArgumentResolver.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/interceptor/MyRequestArgumentResolver.java new file mode 100644 index 00000000..329edd08 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/interceptor/MyRequestArgumentResolver.java @@ -0,0 +1,234 @@ +package com.flow.demo.common.core.interceptor; + +import cn.hutool.core.convert.Convert; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.annotation.MyRequestBody; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.MethodParameter; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.lang.NonNull; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.lang.reflect.ParameterizedType; +import java.math.BigDecimal; +import java.util.*; + +/** + * MyRequestBody解析器 + * 解决的问题: + * 1、单个字符串等包装类型都要写一个对象才可以用@RequestBody接收; + * 2、多个对象需要封装到一个对象里才可以用@RequestBody接收。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class MyRequestArgumentResolver implements HandlerMethodArgumentResolver { + + private static final String JSONBODY_ATTRIBUTE = "MY_REQUEST_BODY_ATTRIBUTE_XX"; + + private static final Set> CLASS_SET = new HashSet<>(); + + static { + CLASS_SET.add(Integer.class); + CLASS_SET.add(Long.class); + CLASS_SET.add(Short.class); + CLASS_SET.add(Float.class); + CLASS_SET.add(Double.class); + CLASS_SET.add(Boolean.class); + CLASS_SET.add(Byte.class); + CLASS_SET.add(BigDecimal.class); + CLASS_SET.add(Character.class); + } + + /** + * 设置支持的方法参数类型。 + * + * @param parameter 方法参数。 + * @return 支持的类型。 + */ + @Override + public boolean supportsParameter(@NonNull MethodParameter parameter) { + return parameter.hasParameterAnnotation(MyRequestBody.class); + } + + /** + * 参数解析,利用fastjson。 + * 注意:非基本类型返回null会报空指针异常,要通过反射或者JSON工具类创建一个空对象。 + */ + @Override + public Object resolveArgument( + @NonNull MethodParameter parameter, + ModelAndViewContainer mavContainer, + @NonNull NativeWebRequest webRequest, + WebDataBinderFactory binderFactory) throws Exception { + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + String contentType = servletRequest.getContentType(); + if (!HttpMethod.POST.name().equals(servletRequest.getMethod())) { + throw new IllegalArgumentException("Only POST method can be applied @MyRequestBody annotation!"); + } + if (!StringUtils.containsIgnoreCase(contentType, MediaType.APPLICATION_JSON_VALUE)) { + throw new IllegalArgumentException( + "Only application/json Content-Type can be applied @MyRequestBody annotation!"); + } + // 根据@MyRequestBody注解value作为json解析的key + MyRequestBody parameterAnnotation = parameter.getParameterAnnotation(MyRequestBody.class); + JSONObject jsonObject = getRequestBody(webRequest); + if (jsonObject == null) { + if (parameterAnnotation.required()) { + throw new IllegalArgumentException("Request Body is EMPTY!"); + } + return null; + } + String key = parameterAnnotation.value(); + if (StringUtils.isBlank(key)) { + key = parameter.getParameterName(); + } + Object value = jsonObject.get(key); + if (value == null) { + if (parameterAnnotation.required()) { + throw new IllegalArgumentException(String.format("Required parameter %s is not present!", key)); + } + return null; + } + // 获取参数类型。 + Class parameterType = parameter.getParameterType(); + // 基本类型 + if (parameterType.isPrimitive()) { + return parsePrimitive(parameterType.getName(), value); + } + // 基本类型包装类 + if (isBasicDataTypes(parameterType)) { + return parseBasicTypeWrapper(parameterType, value); + } else if (parameterType == String.class) { + // 字符串类型 + return value.toString(); + } + // 数组类型 + if (value instanceof JSONArray) { + return parseArray(parameterType, parameterAnnotation.elementType(), key, value); + } + // 其他复杂对象 + return JSON.toJavaObject((JSONObject) value, parameterType); + } + + @SuppressWarnings("unchecked") + private Object parseArray(Class parameterType, Class elementType, String key, Object value) + throws IllegalAccessException, InstantiationException { + Object o; + if (!parameterType.equals(List.class)) { + o = parameterType.newInstance(); + parameterType = (Class) ((ParameterizedType) + parameterType.getGenericSuperclass()).getActualTypeArguments()[0]; + } else { + parameterType = elementType; + if (parameterType.equals(Class.class)) { + throw new IllegalArgumentException( + String.format("List Type parameter %s MUST have elementType!", key)); + } + o = new LinkedList<>(); + } + if (!(o instanceof List)) { + throw new IllegalArgumentException(String.format("Required parameter %s is List!", key)); + } + ((List) o).addAll(((JSONArray) value).toJavaList(parameterType)); + return o; + } + + private Object parsePrimitive(String parameterTypeName, Object value) { + final String booleanTypeName = "boolean"; + if (booleanTypeName.equals(parameterTypeName)) { + return Boolean.valueOf(value.toString()); + } + final String intTypeName = "int"; + if (intTypeName.equals(parameterTypeName)) { + return Integer.valueOf(value.toString()); + } + final String charTypeName = "char"; + if (charTypeName.equals(parameterTypeName)) { + return value.toString().charAt(0); + } + final String shortTypeName = "short"; + if (shortTypeName.equals(parameterTypeName)) { + return Short.valueOf(value.toString()); + } + final String longTypeName = "long"; + if (longTypeName.equals(parameterTypeName)) { + return Long.valueOf(value.toString()); + } + final String floatTypeName = "float"; + if (floatTypeName.equals(parameterTypeName)) { + return Float.valueOf(value.toString()); + } + final String doubleTypeName = "double"; + if (doubleTypeName.equals(parameterTypeName)) { + return Double.valueOf(value.toString()); + } + final String byteTypeName = "byte"; + if (byteTypeName.equals(parameterTypeName)) { + return Byte.valueOf(value.toString()); + } + return null; + } + + private Object parseBasicTypeWrapper(Class parameterType, Object value) { + if (Number.class.isAssignableFrom(parameterType)) { + if (value instanceof String) { + return Convert.convert(parameterType, value); + } + Number number = (Number) value; + if (parameterType == Integer.class) { + return number.intValue(); + } else if (parameterType == Short.class) { + return number.shortValue(); + } else if (parameterType == Long.class) { + return number.longValue(); + } else if (parameterType == Float.class) { + return number.floatValue(); + } else if (parameterType == Double.class) { + return number.doubleValue(); + } else if (parameterType == Byte.class) { + return number.byteValue(); + } else if (parameterType == BigDecimal.class) { + if (value instanceof Double || value instanceof Float) { + return BigDecimal.valueOf(number.doubleValue()); + } else { + return BigDecimal.valueOf(number.longValue()); + } + } + } else if (parameterType == Boolean.class) { + return value; + } else if (parameterType == Character.class) { + return value.toString().charAt(0); + } + return null; + } + + private boolean isBasicDataTypes(Class clazz) { + return CLASS_SET.contains(clazz); + } + + private JSONObject getRequestBody(NativeWebRequest webRequest) throws IOException { + HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); + // 有就直接获取 + JSONObject jsonObject = (JSONObject) webRequest.getAttribute(JSONBODY_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); + // 没有就从请求中读取 + if (jsonObject == null) { + String jsonBody = IOUtils.toString(servletRequest.getReader()); + jsonObject = JSON.parseObject(jsonBody); + if (jsonObject != null) { + webRequest.setAttribute(JSONBODY_ATTRIBUTE, jsonObject, RequestAttributes.SCOPE_REQUEST); + } + } + return jsonObject; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/listener/LoadServiceRelationListener.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/listener/LoadServiceRelationListener.java new file mode 100644 index 00000000..abb8f85b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/listener/LoadServiceRelationListener.java @@ -0,0 +1,28 @@ +package com.flow.demo.common.core.listener; + +import com.flow.demo.common.core.base.service.BaseService; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import java.util.Map; + +/** + * 应用程序启动后的事件监听对象。主要负责加载Model之间的字典关联和一对一关联所对应的Service结构关系。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Component +public class LoadServiceRelationListener implements ApplicationListener { + + @SuppressWarnings("all") + @Override + public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { + Map serviceMap = + applicationReadyEvent.getApplicationContext().getBeansOfType(BaseService.class); + for (Map.Entry e : serviceMap.entrySet()) { + e.getValue().loadRelationStruct(); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/CallResult.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/CallResult.java new file mode 100644 index 00000000..18599d51 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/CallResult.java @@ -0,0 +1,87 @@ +package com.flow.demo.common.core.object; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +/** + * 接口数据验证结果对象。主要是Service类使用。 + * 同时为了提升效率,减少查询次数,可以根据具体的需求,将部分验证关联对象存入data字段,以供Controller使用。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class CallResult { + + /** + * 为了优化性能,所有没有携带数据的正确结果,均可用该对象表示。 + */ + private static final CallResult OK = new CallResult(); + /** + * 是否成功标记。 + */ + private boolean success = true; + /** + * 错误信息描述。 + */ + private String errorMessage = null; + /** + * 在验证同时,仍然需要附加的关联数据对象。 + */ + private JSONObject data; + + /** + * 创建验证结果对象。 + * + * @param errorMessage 错误描述信息。 + * @return 如果参数为空,表示成功,否则返回代码错误信息的错误对象实例。 + */ + public static CallResult create(String errorMessage) { + return errorMessage == null ? ok() : error(errorMessage); + } + + /** + * 创建验证结果对象。 + * + * @param errorMessage 错误描述信息。 + * @param data 附带的数据对象。 + * @return 如果参数为空,表示成功,否则返回代码错误信息的错误对象实例。 + */ + public static CallResult create(String errorMessage, JSONObject data) { + return errorMessage == null ? ok(data) : error(errorMessage); + } + + /** + * 创建表示验证成功的对象实例。 + * + * @return 验证成功对象实例。 + */ + public static CallResult ok() { + return OK; + } + + /** + * 创建表示验证成功的对象实例。 + * + * @param data 附带的数据对象。 + * @return 验证成功对象实例。 + */ + public static CallResult ok(JSONObject data) { + CallResult result = new CallResult(); + result.data = data; + return result; + } + + /** + * 创建表示验证失败的对象实例。 + * + * @param errorMessage 错误描述。 + * @return 验证失败对象实例。 + */ + public static CallResult error(String errorMessage) { + CallResult result = new CallResult(); + result.success = false; + result.errorMessage = errorMessage; + return result; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/DummyClass.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/DummyClass.java new file mode 100644 index 00000000..44b04319 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/DummyClass.java @@ -0,0 +1,27 @@ +package com.flow.demo.common.core.object; + +/** + * 哑元对象,主要用于注解中的缺省对象占位符。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class DummyClass { + + private static final Object EMPTY_OBJECT = new Object(); + + /** + * 可以忽略的空对象。避免sonarqube的各种警告。 + * + * @return 空对象。 + */ + public static Object emptyObject() { + return EMPTY_OBJECT; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private DummyClass() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/GlobalThreadLocal.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/GlobalThreadLocal.java new file mode 100644 index 00000000..3afd7722 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/GlobalThreadLocal.java @@ -0,0 +1,52 @@ +package com.flow.demo.common.core.object; + +import cn.hutool.core.util.BooleanUtil; + +/** + * 线程本地化数据管理的工具类。可根据需求自行添加更多的线程本地化变量及其操作方法。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class GlobalThreadLocal { + + /** + * 存储数据权限过滤是否启用的线程本地化对象。 + * 目前的过滤条件,包括数据权限和租户过滤。 + */ + private static final ThreadLocal DATA_FILTER_ENABLE = ThreadLocal.withInitial(() -> Boolean.TRUE); + + /** + * 设置数据过滤是否打开。如果打开,当前Servlet线程所执行的SQL操作,均会进行数据过滤。 + * + * @param enable 打开为true,否则false。 + * @return 返回之前的状态,便于恢复。 + */ + public static boolean setDataFilter(boolean enable) { + boolean oldValue = DATA_FILTER_ENABLE.get(); + DATA_FILTER_ENABLE.set(enable); + return oldValue; + } + + /** + * 判断当前Servlet线程所执行的SQL操作,是否进行数据过滤。 + * + * @return true 进行数据权限过滤,否则false。 + */ + public static boolean enabledDataFilter() { + return BooleanUtil.isTrue(DATA_FILTER_ENABLE.get()); + } + + /** + * 清空该存储数据,主动释放线程本地化存储资源。 + */ + public static void clearDataFilter() { + DATA_FILTER_ENABLE.remove(); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private GlobalThreadLocal() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/LoginUserInfo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/LoginUserInfo.java new file mode 100644 index 00000000..da0fc1e7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/LoginUserInfo.java @@ -0,0 +1,62 @@ +package com.flow.demo.common.core.object; + +import lombok.Data; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; + +/** + * 在线登录用户信息。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ToString +@Slf4j +public class LoginUserInfo { + + /** + * 用户Id。 + */ + private Long userId; + /** + * 用户所在部门Id。 + * 仅当系统支持uaa时可用,否则可以直接忽略该字段。保留该字段是为了保持单体和微服务通用代码部分的兼容性。 + */ + private Long deptId; + /** + * 租户Id。 + * 仅当系统支持uaa时可用,否则可以直接忽略该字段。保留该字段是为了保持单体和微服务通用代码部分的兼容性。 + */ + private Long tenantId; + /** + * 是否为超级管理员。 + */ + private Boolean isAdmin; + /** + * 用户登录名。 + */ + private String loginName; + /** + * 用户显示名称。 + */ + private String showName; + /** + * 标识不同登录的会话Id。 + */ + private String sessionId; + /** + * 登录IP。 + */ + private String loginIp; + /** + * 登录时间。 + */ + private Date loginTime; + /** + * 登录设备类型。 + */ + private Integer deviceType; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyGroupCriteria.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyGroupCriteria.java new file mode 100644 index 00000000..5ecc7da3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyGroupCriteria.java @@ -0,0 +1,24 @@ +package com.flow.demo.common.core.object; + +import lombok.AllArgsConstructor; +import lombok.Data; + +/** + * Mybatis Mapper.xml中所需的分组条件对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@AllArgsConstructor +public class MyGroupCriteria { + + /** + * GROUP BY 从句后面的参数。 + */ + private String groupBy; + /** + * SELECT 从句后面的分组显示字段。 + */ + private String groupSelect; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyGroupParam.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyGroupParam.java new file mode 100644 index 00000000..b46c57e4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyGroupParam.java @@ -0,0 +1,170 @@ +package com.flow.demo.common.core.object; + +import cn.hutool.core.util.ReflectUtil; +import com.flow.demo.common.core.constant.ApplicationConstant; +import com.flow.demo.common.core.exception.InvalidClassFieldException; +import com.flow.demo.common.core.exception.InvalidDataFieldException; +import com.flow.demo.common.core.exception.InvalidDataModelException; +import com.flow.demo.common.core.util.MyModelUtil; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +/** + * 查询分组参数请求对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EqualsAndHashCode(callSuper = true) +@Slf4j +@Data +public class MyGroupParam extends ArrayList { + + /** + * SQL语句的SELECT LIST中,分组字段的返回字段名称列表。 + */ + private List selectGroupFieldList; + /** + * 分组参数解析后构建的SQL语句中所需的分组数据,如GROUP BY的字段列表和SELECT LIST中的分组字段显示列表。 + */ + private MyGroupCriteria groupCriteria; + /** + * 基于分组参数对象中的数据,构建SQL中select list和group by从句可以直接使用的分组对象。 + * + * @param groupParam 分组参数对象。 + * @param modelClazz 查询表对应的主对象的Class。 + * @return SQL中所需的GROUP对象。详见MyGroupCriteria类定义。 + */ + public static MyGroupParam buildGroupBy(MyGroupParam groupParam, Class modelClazz) { + if (groupParam == null) { + return null; + } + if (modelClazz == null) { + throw new IllegalArgumentException("modelClazz Argument can't be NULL"); + } + groupParam.selectGroupFieldList = new LinkedList<>(); + StringBuilder groupByBuilder = new StringBuilder(128); + StringBuilder groupSelectBuilder = new StringBuilder(128); + int i = 0; + for (GroupInfo groupInfo : groupParam) { + GroupBaseData groupBaseData = parseGroupBaseData(groupInfo, modelClazz); + if (StringUtils.isBlank(groupBaseData.tableName)) { + throw new InvalidDataModelException(groupBaseData.modelName); + } + if (StringUtils.isBlank(groupBaseData.columnName)) { + throw new InvalidDataFieldException(groupBaseData.modelName, groupBaseData.fieldName); + } + processGroupInfo(groupInfo, groupBaseData, groupByBuilder, groupSelectBuilder); + String aliasName = StringUtils.isBlank(groupInfo.aliasName) ? groupInfo.fieldName : groupInfo.aliasName; + // selectGroupFieldList中的元素,目前只是被export操作使用。会根据集合中的元素名称匹配导出表头。 + groupParam.selectGroupFieldList.add(aliasName); + if (++i < groupParam.size()) { + groupByBuilder.append(", "); + groupSelectBuilder.append(", "); + } + } + groupParam.groupCriteria = new MyGroupCriteria(groupByBuilder.toString(), groupSelectBuilder.toString()); + return groupParam; + } + + private static GroupBaseData parseGroupBaseData(GroupInfo groupInfo, Class modelClazz) { + GroupBaseData baseData = new GroupBaseData(); + if (StringUtils.isBlank(groupInfo.fieldName)) { + throw new IllegalArgumentException("GroupInfo.fieldName can't be EMPTY"); + } + String[] stringArray = StringUtils.split(groupInfo.fieldName,'.'); + if (stringArray.length == 1) { + baseData.modelName = modelClazz.getSimpleName(); + baseData.fieldName = groupInfo.fieldName; + baseData.tableName = MyModelUtil.mapToTableName(modelClazz); + baseData.columnName = MyModelUtil.mapToColumnName(groupInfo.fieldName, modelClazz); + } else { + Field field = ReflectUtil.getField(modelClazz, stringArray[0]); + if (field == null) { + throw new InvalidClassFieldException(modelClazz.getSimpleName(), stringArray[0]); + } + Class fieldClazz = field.getType(); + baseData.modelName = fieldClazz.getSimpleName(); + baseData.fieldName = stringArray[1]; + baseData.tableName = MyModelUtil.mapToTableName(fieldClazz); + baseData.columnName = MyModelUtil.mapToColumnName(baseData.fieldName, fieldClazz); + } + return baseData; + } + + private static void processGroupInfo( + GroupInfo groupInfo, + GroupBaseData baseData, + StringBuilder groupByBuilder, + StringBuilder groupSelectBuilder) { + String tableName = baseData.tableName; + String columnName = baseData.columnName; + if (StringUtils.isNotBlank(groupInfo.dateAggregateBy)) { + groupByBuilder.append("DATE_FORMAT(").append(tableName).append(".").append(columnName); + groupSelectBuilder.append("DATE_FORMAT(").append(tableName).append(".").append(columnName); + if (ApplicationConstant.DAY_AGGREGATION.equals(groupInfo.dateAggregateBy)) { + groupByBuilder.append(", '%Y-%m-%d')"); + groupSelectBuilder.append(", '%Y-%m-%d')"); + } else if (ApplicationConstant.MONTH_AGGREGATION.equals(groupInfo.dateAggregateBy)) { + groupByBuilder.append(", '%Y-%m-01')"); + groupSelectBuilder.append(", '%Y-%m-01')"); + } else if (ApplicationConstant.YEAR_AGGREGATION.equals(groupInfo.dateAggregateBy)) { + groupByBuilder.append(", '%Y-01-01')"); + groupSelectBuilder.append(", '%Y-01-01')"); + } else { + throw new IllegalArgumentException("Illegal DATE_FORMAT for GROUP ID list."); + } + if (StringUtils.isNotBlank(groupInfo.aliasName)) { + groupSelectBuilder.append(" ").append(groupInfo.aliasName); + } else { + groupSelectBuilder.append(" ").append(columnName); + } + } else { + groupByBuilder.append(tableName).append(".").append(columnName); + groupSelectBuilder.append(tableName).append(".").append(columnName); + if (StringUtils.isNotBlank(groupInfo.aliasName)) { + groupSelectBuilder.append(" ").append(groupInfo.aliasName); + } + } + } + + /** + * 分组信息对象。 + */ + @Data + public static class GroupInfo { + /** + * Java对象的字段名。目前主要包含三种格式: + * 1. 简单的属性名称,如userId,将会直接映射到与其关联的数据库字段。表名为当前ModelClazz所对应的表名。 + * 映射结果或为 my_main_table.user_id + * 2. 一对一关联表属性,如user.userId,这里将先获取user属性的对象类型并映射到对应的表名,后面的userId为 + * user所在实体的属性。映射结果或为:my_sys_user.user_id + */ + private String fieldName; + /** + * SQL语句的Select List中,分组字段的别名。如果别名为NULL,直接取fieldName。 + */ + private String aliasName; + /** + * 如果该值不为NULL,则会对分组字段进行DATE_FORMAT函数的计算,并根据具体的值,将日期数据截取到指定的位。 + * day: 表示按照天聚合,将会截取到天。DATE_FORMAT(columnName, '%Y-%m-%d') + * month: 表示按照月聚合,将会截取到月。DATE_FORMAT(columnName, '%Y-%m-01') + * year: 表示按照年聚合,将会截取到年。DATE_FORMAT(columnName, '%Y-01-01') + */ + private String dateAggregateBy; + } + + private static class GroupBaseData { + private String modelName; + private String fieldName; + private String tableName; + private String columnName; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyOrderParam.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyOrderParam.java new file mode 100644 index 00000000..c3095e5d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyOrderParam.java @@ -0,0 +1,265 @@ +package com.flow.demo.common.core.object; + +import cn.hutool.core.util.ReflectUtil; +import com.flow.demo.common.core.constant.ApplicationConstant; +import com.flow.demo.common.core.exception.InvalidClassFieldException; +import com.flow.demo.common.core.exception.InvalidDataFieldException; +import com.flow.demo.common.core.exception.InvalidDataModelException; +import com.flow.demo.common.core.util.MyModelUtil; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Field; +import java.util.*; + +/** + * Controller参数中的排序请求对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EqualsAndHashCode(callSuper = true) +@Slf4j +@Data +public class MyOrderParam extends ArrayList { + + private static final String DICT_MAP = "DictMap."; + /** + * 基于排序对象中的JSON数据,构建SQL中order by从句可以直接使用的排序字符串。 + * + * @param orderParam 排序参数对象。 + * @param modelClazz 查询主表对应的主对象的Class。 + * @return SQL中order by从句可以直接使用的排序字符串。 + */ + public static String buildOrderBy(MyOrderParam orderParam, Class modelClazz) { + if (orderParam == null) { + return null; + } + if (modelClazz == null) { + throw new IllegalArgumentException( + "modelClazz Argument in MyOrderParam.buildOrderBy can't be NULL"); + } + int i = 0; + StringBuilder orderBy = new StringBuilder(128); + for (OrderInfo orderInfo : orderParam) { + if (StringUtils.isBlank(orderInfo.getFieldName())) { + continue; + } + OrderBaseData orderBaseData = parseOrderBaseData(orderInfo, modelClazz); + if (StringUtils.isBlank(orderBaseData.tableName)) { + throw new InvalidDataModelException(orderBaseData.modelName); + } + if (StringUtils.isBlank(orderBaseData.columnName)) { + throw new InvalidDataFieldException(orderBaseData.modelName, orderBaseData.fieldName); + } + processOrderInfo(orderInfo, orderBaseData, orderBy); + if (++i < orderParam.size()) { + orderBy.append(", "); + } + } + return orderBy.toString(); + } + + private static void processOrderInfo( + OrderInfo orderInfo, OrderBaseData orderBaseData, StringBuilder orderByBuilder) { + if (StringUtils.isNotBlank(orderInfo.dateAggregateBy)) { + orderByBuilder.append("DATE_FORMAT(") + .append(orderBaseData.tableName).append(".").append(orderBaseData.columnName); + if (ApplicationConstant.DAY_AGGREGATION.equals(orderInfo.dateAggregateBy)) { + orderByBuilder.append(", '%Y-%m-%d')"); + } else if (ApplicationConstant.MONTH_AGGREGATION.equals(orderInfo.dateAggregateBy)) { + orderByBuilder.append(", '%Y-%m-01')"); + } else if (ApplicationConstant.YEAR_AGGREGATION.equals(orderInfo.dateAggregateBy)) { + orderByBuilder.append(", '%Y-01-01')"); + } else { + throw new IllegalArgumentException("Illegal DATE_FORMAT for GROUP ID list."); + } + } else { + orderByBuilder.append(orderBaseData.tableName).append(".").append(orderBaseData.columnName); + } + if (orderInfo.asc != null && !orderInfo.asc) { + orderByBuilder.append(" DESC"); + } + } + + private static OrderBaseData parseOrderBaseData(OrderInfo orderInfo, Class modelClazz) { + OrderBaseData orderBaseData = new OrderBaseData(); + orderBaseData.fieldName = StringUtils.substringBefore(orderInfo.fieldName, DICT_MAP); + String[] stringArray = StringUtils.split(orderBaseData.fieldName, '.'); + if (stringArray.length == 1) { + orderBaseData.modelName = modelClazz.getSimpleName(); + orderBaseData.tableName = MyModelUtil.mapToTableName(modelClazz); + orderBaseData.columnName = MyModelUtil.mapToColumnName(orderBaseData.fieldName, modelClazz); + } else { + Field field = ReflectUtil.getField(modelClazz, stringArray[0]); + if (field == null) { + throw new InvalidClassFieldException(modelClazz.getSimpleName(), stringArray[0]); + } + Class fieldClazz = field.getType(); + orderBaseData.modelName = fieldClazz.getSimpleName(); + orderBaseData.fieldName = stringArray[1]; + orderBaseData.tableName = MyModelUtil.mapToTableName(fieldClazz); + orderBaseData.columnName = MyModelUtil.mapToColumnName(orderBaseData.fieldName, fieldClazz); + } + return orderBaseData; + } + + /** + * 在排序列表中,可能存在基于指定表字段的排序,该函数将获取指定表的所有排序字段。 + * 返回的字符串,可直接用于SQL中的ORDER BY从句。 + * + * @param orderParam 排序参数对象。 + * @param modelClazz 查询主表对应的主对象的Class。 + * @param relationModelName 与关联表对应的Model的名称,如my_course_paper表应对的Java对象CoursePaper。 + * 如果该值为null或空字符串,则获取所有主表的排序字段。 + * @return 返回的是表字段,而非Java对象的属性,多个字段之间逗号分隔。 + */ + public static String getOrderClauseByModelName( + MyOrderParam orderParam, Class modelClazz, String relationModelName) { + if (orderParam == null) { + return null; + } + if (modelClazz == null) { + throw new IllegalArgumentException( + "modelClazz Argument in MyOrderParam.getOrderClauseByModelName can't be NULL"); + } + List fieldNameList = new LinkedList<>(); + String prefix = null; + if (StringUtils.isNotBlank(relationModelName)) { + prefix = relationModelName + "."; + } + for (OrderInfo orderInfo : orderParam) { + OrderBaseData baseData = parseOrderBaseData(orderInfo, modelClazz, prefix, relationModelName); + if (baseData != null) { + fieldNameList.add(makeOrderBy(baseData, orderInfo.asc)); + } + } + return StringUtils.join(fieldNameList, ", "); + } + + private static OrderBaseData parseOrderBaseData( + OrderInfo orderInfo, Class modelClazz, String prefix, String relationModelName) { + OrderBaseData baseData = null; + String fieldName = StringUtils.substringBefore(orderInfo.fieldName, DICT_MAP); + if (prefix != null) { + if (fieldName.startsWith(prefix)) { + baseData = new OrderBaseData(); + Field field = ReflectUtil.getField(modelClazz, relationModelName); + if (field == null) { + throw new InvalidClassFieldException(modelClazz.getSimpleName(), relationModelName); + } + Class fieldClazz = field.getType(); + baseData.modelName = fieldClazz.getSimpleName(); + baseData.fieldName = StringUtils.removeStart(fieldName, prefix); + baseData.tableName = MyModelUtil.mapToTableName(fieldClazz); + baseData.columnName = MyModelUtil.mapToColumnName(fieldName, fieldClazz); + } + } else { + String dotLimitor = "."; + if (!fieldName.contains(dotLimitor)) { + baseData = new OrderBaseData(); + baseData.modelName = modelClazz.getSimpleName(); + baseData.tableName = MyModelUtil.mapToTableName(modelClazz); + baseData.columnName = MyModelUtil.mapToColumnName(fieldName, modelClazz); + } + } + return baseData; + } + + private static String makeOrderBy(OrderBaseData baseData, Boolean asc) { + if (StringUtils.isBlank(baseData.tableName)) { + throw new InvalidDataModelException(baseData.modelName); + } + if (StringUtils.isBlank(baseData.columnName)) { + throw new InvalidDataFieldException(baseData.modelName, baseData.fieldName); + } + StringBuilder orderBy = new StringBuilder(128); + orderBy.append(baseData.tableName).append(".").append(baseData.columnName); + if (asc != null && !asc) { + orderBy.append(" DESC"); + } + return orderBy.toString(); + } + + /** + * 在排序列表中,可能存在基于指定表字段的排序,该函数将删除指定表的所有排序字段。 + * + * @param orderParam 排序参数对象。 + * @param modelClazz 查询主表对应的主对象的Class。 + * @param relationModelName 与关联表对应的Model的名称,如my_course_paper表应对的Java对象CoursePaper。 + * 如果该值为null或空字符串,则获取所有主表的排序字段。 + */ + public static void removeOrderClauseByModelName( + MyOrderParam orderParam, Class modelClazz, String relationModelName) { + if (orderParam == null) { + return; + } + if (modelClazz == null) { + throw new IllegalArgumentException( + "modelClazz Argument in MyOrderParam.removeOrderClauseByModelName can't be NULL"); + } + List fieldIndexList = new LinkedList<>(); + String prefix = null; + if (StringUtils.isNotBlank(relationModelName)) { + prefix = relationModelName + "."; + } + int i = 0; + for (OrderInfo orderInfo : orderParam) { + String fieldName = StringUtils.substringBefore(orderInfo.fieldName, DICT_MAP); + if (prefix != null) { + if (fieldName.startsWith(prefix)) { + fieldIndexList.add(i); + } + } else { + if (!fieldName.contains(".")) { + fieldIndexList.add(i); + } + } + ++i; + } + for (int index : fieldIndexList) { + orderParam.remove(index); + } + } + + /** + * 排序信息对象。 + */ + @AllArgsConstructor + @NoArgsConstructor + @Data + public static class OrderInfo { + /** + * Java对象的字段名。如果fieldName为空,则忽略跳过。目前主要包含三种格式: + * 1. 简单的属性名称,如userId,将会直接映射到与其关联的数据库字段。表名为当前ModelClazz所对应的表名。 + * 映射结果或为 my_main_table.user_id + * 2. 字典属性名称,如userIdDictMap.id,由于仅仅支持字典中Id数据的排序,所以直接截取DictMap之前的字符串userId作为排序属性。 + * 表名为当前ModelClazz所对应的表名。映射结果或为 my_main_table.user_id + * 3. 一对一关联表属性,如user.userId,这里将先获取user属性的对象类型并映射到对应的表名,后面的userId为 + * user所在实体的属性。映射结果或为:my_sys_user.user_id + */ + private String fieldName; + /** + * 排序方向。true为升序,否则降序。 + */ + private Boolean asc = true; + /** + * 如果该值不为NULL,则会对日期型排序字段进行DATE_FORMAT函数的计算,并根据具体的值,将日期数据截取到指定的位。 + * day: 表示按照天聚合,将会截取到天。DATE_FORMAT(columnName, '%Y-%m-%d') + * month: 表示按照月聚合,将会截取到月。DATE_FORMAT(columnName, '%Y-%m-01') + * year: 表示按照年聚合,将会截取到年。DATE_FORMAT(columnName, '%Y-01-01') + */ + private String dateAggregateBy; + } + + private static class OrderBaseData { + private String modelName; + private String fieldName; + private String tableName; + private String columnName; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyPageData.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyPageData.java new file mode 100644 index 00000000..741b227c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyPageData.java @@ -0,0 +1,36 @@ +package com.flow.demo.common.core.object; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.LinkedList; +import java.util.List; + +/** + * 分页数据的应答返回对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class MyPageData { + /** + * 数据列表。 + */ + private List dataList; + /** + * 数据总数量。 + */ + private Long totalCount; + + /** + * 为了保持前端的数据格式兼容性,在没有数据的时候,需要返回空分页对象。 + * @return 空分页对象。 + */ + public static MyPageData emptyPageData() { + return new MyPageData<>(new LinkedList<>(), 0L); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyPageParam.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyPageParam.java new file mode 100644 index 00000000..03fc8e30 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyPageParam.java @@ -0,0 +1,58 @@ +package com.flow.demo.common.core.object; + +import lombok.Getter; + +/** + * Controller参数中的分页请求对象 + * + * @author Jerry + * @date 2021-06-06 + */ +@Getter +public class MyPageParam { + + public static final int DEFAULT_PAGE_NUM = 1; + public static final int DEFAULT_PAGE_SIZE = 10; + public static final int DEFAULT_MAX_SIZE = 100; + + /** + * 分页号码,从1开始计数。 + */ + private Integer pageNum; + + /** + * 每页大小。 + */ + private Integer pageSize; + + /** + * 设置当前分页页号。 + * + * @param pageNum 页号,如果传入非法值,则使用缺省值。 + */ + public void setPageNum(Integer pageNum) { + if (pageNum == null) { + return; + } + if (pageNum <= 0) { + pageNum = DEFAULT_PAGE_NUM; + } + this.pageNum = pageNum; + } + + /** + * 设置分页的大小。 + * + * @param pageSize 分页大小,如果传入非法值,则使用缺省值。 + */ + public void setPageSize(Integer pageSize) { + if (pageSize == null) { + return; + } + if (pageSize <= 0 || pageSize > DEFAULT_MAX_SIZE) { + pageSize = DEFAULT_PAGE_SIZE; + } + this.pageSize = pageSize; + } + +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyRelationParam.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyRelationParam.java new file mode 100644 index 00000000..64e125a0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyRelationParam.java @@ -0,0 +1,91 @@ +package com.flow.demo.common.core.object; + +import lombok.Builder; +import lombok.Data; + +/** + * 实体对象数据组装参数构建器。 + * BaseService中的实体对象数据组装函数,会根据该参数对象进行数据组装。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@Builder +public class MyRelationParam { + + /** + * 是否组装字典关联的标记。 + * 组装RelationDict和RelationConstDict注解标记的字段。 + */ + private boolean buildDict; + + /** + * 是否组装一对一关联的标记。 + * 组装RelationOneToOne注解标记的字段。 + */ + private boolean buildOneToOne; + + /** + * 是否组装一对多关联的标记。 + * 组装RelationOneToMany注解标记的字段。 + */ + private boolean buildOneToMany; + + /** + * 在组装一对一关联的同时,是否继续关联从表中的字典。 + * 从表中RelationDict和RelationConstDict注解标记的字段。 + * 该字段为true时,无需设置buildOneToOne了。 + */ + private boolean buildOneToOneWithDict; + + /** + * 是否组装主表对多对多中间表关联的标记。 + * 组装RelationManyToMany注解标记的字段。 + */ + private boolean buildRelationManyToMany; + + /** + * 是否组装聚合计算关联的标记。 + * 组装RelationOneToManyAggregation和RelationManyToManyAggregation注解标记的字段。 + */ + private boolean buildRelationAggregation; + + /** + * 便捷方法,返回仅做字典关联的参数对象。 + * + * @return 返回仅做字典关联的参数对象。 + */ + public static MyRelationParam dictOnly() { + return MyRelationParam.builder().buildDict(true).build(); + } + + /** + * 便捷方法,返回仅做字典关联、一对一从表及其字典和聚合计算的参数对象。 + * NOTE: 对于一对多和多对多,这种从表数据是列表结果的关联,均不返回。 + * + * @return 返回仅做字典关联、一对一从表及其字典和聚合计算的参数对象。 + */ + public static MyRelationParam normal() { + return MyRelationParam.builder() + .buildDict(true) + .buildOneToOneWithDict(true) + .buildRelationAggregation(true) + .build(); + } + + /** + * 便捷方法,返回全部关联的参数对象。 + * + * @return 返回全部关联的参数对象。 + */ + public static MyRelationParam full() { + return MyRelationParam.builder() + .buildDict(true) + .buildOneToOneWithDict(true) + .buildRelationAggregation(true) + .buildRelationManyToMany(true) + .buildOneToMany(true) + .build(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyWhereCriteria.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyWhereCriteria.java new file mode 100644 index 00000000..ed0a2ff0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/MyWhereCriteria.java @@ -0,0 +1,361 @@ +package com.flow.demo.common.core.object; + +import cn.hutool.core.util.ReflectUtil; +import com.alibaba.fastjson.annotation.JSONField; +import com.flow.demo.common.core.exception.InvalidDataFieldException; +import com.flow.demo.common.core.exception.InvalidDataModelException; +import com.flow.demo.common.core.util.MyModelUtil; +import lombok.*; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.Collection; +import java.util.Date; +import java.util.List; + +/** + * Where中的条件语句。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Data +@NoArgsConstructor +public class MyWhereCriteria { + + /** + * 等于 + */ + public static final int OPERATOR_EQUAL = 0; + + /** + * 不等于 + */ + public static final int OPERATOR_NOT_EQUAL = 1; + + /** + * 大于等于 + */ + public static final int OPERATOR_GE = 2; + + /** + * 大于 + */ + public static final int OPERATOR_GT = 3; + + /** + * 小于等于 + */ + public static final int OPERATOR_LE = 4; + + /** + * 小于 + */ + public static final int OPERATOR_LT = 5; + + /** + * LIKE + */ + public static final int OPERATOR_LIKE = 6; + + /** + * NOT NULL + */ + public static final int OPERATOR_NOT_NULL = 7; + + /** + * IS NULL + */ + public static final int OPERATOR_IS_NULL = 8; + + /** + * IN + */ + public static final int OPERATOR_IN = 9; + + /** + * 参与过滤的实体对象的Class。 + */ + @JSONField(serialize = false) + private Class modelClazz; + + /** + * 数据库表名。 + */ + private String tableName; + + /** + * Java属性名称。 + */ + private String fieldName; + + /** + * 数据表字段名。 + */ + private String columnName; + + /** + * 数据表字段类型。 + */ + private Integer columnType; + + /** + * 操作符类型,取值范围见上面的常量值。 + */ + private Integer operatorType; + + /** + * 条件数据值。 + */ + private Object value; + + public MyWhereCriteria(Class modelClazz, String fieldName, Integer operatorType, Object value) { + this.modelClazz = modelClazz; + this.fieldName = fieldName; + this.operatorType = operatorType; + this.value = value; + } + + /** + * 设置条件值。 + * + * @param fieldName 条件所属的实体对象的字段名。 + * @param operatorType 条件操作符。具体值可参考当前对象的静态变量。 + * @param value 条件过滤值。 + * @return 验证结果对象,如果有错误将会返回具体的错误信息。 + */ + public CallResult setCriteria(String fieldName, Integer operatorType, Object value) { + this.operatorType = operatorType; + this.fieldName = fieldName; + this.value = value; + return doVerify(); + } + + /** + * 设置条件值。 + * + * @param modelClazz 数据表对应实体对象的Class. + * @param fieldName 条件所属的实体对象的字段名。 + * @param operatorType 条件操作符。具体值可参考当前对象的静态变量。 + * @param value 条件过滤值。 + * @return 验证结果对象,如果有错误将会返回具体的错误信息。 + */ + public CallResult setCriteria(Class modelClazz, String fieldName, Integer operatorType, Object value) { + this.modelClazz = modelClazz; + this.operatorType = operatorType; + this.fieldName = fieldName; + this.value = value; + return doVerify(); + } + + /** + * 设置条件值,通过该构造方法设置时,通常是直接将表名、字段名、字段类型等赋值,无需在通过modelClazz进行推演。 + * + * @param tableName 数据表名。 + * @param columnName 数据字段名。 + * @param columnType 数据字段类型。 + * @param operatorType 操作类型。具体值可参考当前对象的静态变量。 + * @param value 条件过滤值。 + */ + public void setCriteria( + String tableName, String columnName, String columnType, Integer operatorType, Object value) { + this.tableName = tableName; + this.columnName = columnName; + this.columnType = MyModelUtil.NUMERIC_FIELD_TYPE; + if (String.class.getSimpleName().equals(columnType)) { + this.columnType = MyModelUtil.STRING_FIELD_TYPE; + } else if (Date.class.getSimpleName().equals(columnType)) { + this.columnType = MyModelUtil.DATE_FIELD_TYPE; + } + this.operatorType = operatorType; + this.value = value; + } + + /** + * 在执行该函数之前,该对象的所有数据均已经赋值完毕。 + * 该函数主要验证操作符字段和条件值字段对应关系的合法性。 + * + * @return 验证结果对象,如果有错误将会返回具体的错误信息。 + */ + public CallResult doVerify() { + if (fieldName == null) { + return CallResult.error("过滤字段名称 [fieldName] 不能为空!"); + } + if (modelClazz != null && ReflectUtil.getField(modelClazz, fieldName) == null) { + return CallResult.error( + "过滤字段 [" + fieldName + "] 在实体对象 [" + modelClazz.getSimpleName() + "] 中并不存在!"); + } + if (!checkOperatorType()) { + return CallResult.error("无效的操作符类型 [" + operatorType + "]!"); + } + // 其他操作符必须包含value值 + if (operatorType != OPERATOR_IS_NULL && operatorType != OPERATOR_NOT_NULL && value == null) { + String operatorString = this.getOperatorString(); + return CallResult.error("操作符 [" + operatorString + "] 的条件值不能为空!"); + } + if (this.operatorType == OPERATOR_IN) { + if (!(value instanceof Collection)) { + return CallResult.error("操作符 [IN] 的条件值必须为集合对象!"); + } + if (CollectionUtils.isEmpty((Collection) value)) { + return CallResult.error("操作符 [IN] 的条件值不能为空!"); + } + } + return CallResult.ok(); + } + + /** + * 判断操作符类型是否合法。 + * + * @return 合法返回true,否则false。 + */ + public boolean checkOperatorType() { + return operatorType != null + && (operatorType >= OPERATOR_EQUAL && operatorType <= OPERATOR_IN); + } + + /** + * 获取操作符的字符串形式。 + * + * @return 操作符的字符串。 + */ + public String getOperatorString() { + switch (operatorType) { + case OPERATOR_EQUAL: + return " = "; + case OPERATOR_NOT_EQUAL: + return " != "; + case OPERATOR_GE: + return " >= "; + case OPERATOR_GT: + return " > "; + case OPERATOR_LE: + return " <= "; + case OPERATOR_LT: + return " < "; + case OPERATOR_LIKE: + return " LIKE "; + case OPERATOR_NOT_NULL: + return " IS NOT NULL "; + case OPERATOR_IS_NULL: + return " IS NULL "; + case OPERATOR_IN: + return " IN "; + default: + return null; + } + } + + /** + * 获取组装后的SQL Where从句,如 table_name.column_name = 'value'。 + * 与查询数据表对应的实体对象Class为当前对象的modelClazz字段。 + * + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public String makeCriteriaString() { + return makeCriteriaString(this.modelClazz); + } + + /** + * 获取组装后的SQL Where从句,如 table_name.column_name = 'value'。 + * + * @param modelClazz 与查询数据表对应的实体对象的Class。 + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @exception InvalidDataModelException 参数modelClazz没有对应的table,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public String makeCriteriaString(Class modelClazz) { + String tableName; + String columnName; + Integer columnType; + if (modelClazz != null) { + Tuple2 fieldInfo = MyModelUtil.mapToColumnInfo(fieldName, modelClazz); + if (fieldInfo == null) { + throw new InvalidDataFieldException(modelClazz.getSimpleName(), fieldName); + } + columnName = fieldInfo.getFirst(); + columnType = fieldInfo.getSecond(); + tableName = MyModelUtil.mapToTableName(modelClazz); + if (tableName == null) { + throw new InvalidDataModelException(modelClazz.getSimpleName()); + } + } else { + tableName = this.tableName; + columnName = this.columnName; + columnType = this.columnType; + } + return this.buildClauseString(tableName, columnName, columnType); + } + + /** + * 获取组装后的SQL Where从句。如 table_name.column_name = 'value'。 + * + * @param criteriaList 条件列表,所有条件直接目前仅支持 AND 的关系。 + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public static String makeCriteriaString(List criteriaList) { + return makeCriteriaString(criteriaList, null); + } + + /** + * 获取组装后的SQL Where从句。如 table_name.column_name = 'value'。 + * + * @param criteriaList 条件列表,所有条件直接目前仅支持 AND 的关系。 + * @param modelClazz 与数据表对应的实体对象的Class。 + * 如果不为NULL实体对象Class使用该值,否则使用每个MyWhereCriteria自身的modelClazz。 + * @exception InvalidDataFieldException selectFieldList中存在非法实体字段时,抛出该异常。 + * @return 组装后的SQL条件从句。 + */ + public static String makeCriteriaString(List criteriaList, Class modelClazz) { + if (CollectionUtils.isEmpty(criteriaList)) { + return null; + } + StringBuilder sb = new StringBuilder(256); + int i = 0; + for (MyWhereCriteria whereCriteria : criteriaList) { + Class clazz = modelClazz; + if (clazz == null) { + clazz = whereCriteria.modelClazz; + } + if (i++ != 0) { + sb.append(" AND "); + } + String criteriaString = whereCriteria.makeCriteriaString(clazz); + sb.append(criteriaString); + } + return sb.length() == 0 ? null : sb.toString(); + } + + private String buildClauseString(String tableName, String columnName, Integer columnType) { + StringBuilder sb = new StringBuilder(64); + sb.append(tableName).append(".").append(columnName).append(getOperatorString()); + if (operatorType == OPERATOR_IN) { + Collection filterValues = (Collection) value; + sb.append("("); + int i = 0; + for (Object filterValue : filterValues) { + if (columnType.equals(MyModelUtil.NUMERIC_FIELD_TYPE)) { + sb.append(filterValue); + } else { + sb.append("'").append(filterValue).append("'"); + } + if (i++ != filterValues.size() - 1) { + sb.append(", "); + } + } + sb.append(")"); + return sb.toString(); + } + if (value != null) { + if (columnType.equals(MyModelUtil.NUMERIC_FIELD_TYPE)) { + sb.append(value); + } else { + sb.append("'").append(value).append("'"); + } + } + return sb.toString(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/ResponseResult.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/ResponseResult.java new file mode 100644 index 00000000..5d62e3c7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/ResponseResult.java @@ -0,0 +1,221 @@ +package com.flow.demo.common.core.object; + +import com.alibaba.fastjson.JSON; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.util.ContextUtil; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * 接口返回对象 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Data +public class ResponseResult { + + /** + * 为了优化性能,所有没有携带数据的正确结果,均可用该对象表示。 + */ + private static final ResponseResult OK = new ResponseResult<>(); + /** + * 是否成功标记。 + */ + private boolean success = true; + /** + * 错误码。 + */ + private String errorCode = "NO-ERROR"; + /** + * 错误信息描述。 + */ + private String errorMessage = "NO-MESSAGE"; + /** + * 实际数据。 + */ + private T data = null; + + /** + * 根据参数errorCodeEnum的枚举值,判断创建成功对象还是错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCodeEnum 的 name() 和 getErrorMessage()。 + * + * @param errorCodeEnum 错误码枚举 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult create(ErrorCodeEnum errorCodeEnum) { + return create(errorCodeEnum, errorCodeEnum.getErrorMessage()); + } + + /** + * 根据参数errorCodeEnum的枚举值,判断创建成功对象还是错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCodeEnum 的 name() 和参数 errorMessage。 + * + * @param errorCodeEnum 错误码枚举。 + * @param errorMessage 如果该参数为null,错误信息取自errorCodeEnum参数内置的errorMessage,否则使用当前参数。 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult create(ErrorCodeEnum errorCodeEnum, String errorMessage) { + errorMessage = errorMessage != null ? errorMessage : errorCodeEnum.getErrorMessage(); + return errorCodeEnum == ErrorCodeEnum.NO_ERROR ? success() : error(errorCodeEnum.name(), errorMessage); + } + + /** + * 根据参数errorCode是否为空,判断创建成功对象还是错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCode 和参数 errorMessage。 + * + * @param errorCode 自定义的错误码 + * @param errorMessage 自定义的错误信息 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult create(String errorCode, String errorMessage) { + return errorCode == null ? success() : error(errorCode, errorMessage); + } + + /** + * 创建成功对象。 + * 如果需要绑定返回数据,可以在实例化后调用setDataObject方法。 + * + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult success() { + return OK; + } + + /** + * 创建带有返回数据的成功对象。 + * + * @param data 返回的数据对象 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult success(T data) { + ResponseResult resp = new ResponseResult<>(); + resp.data = data; + return resp; + } + + /** + * 创建错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCodeEnum 的 name() 和 getErrorMessage()。 + * + * @param errorCodeEnum 错误码枚举 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult error(ErrorCodeEnum errorCodeEnum) { + return error(errorCodeEnum.name(), errorCodeEnum.getErrorMessage()); + } + + /** + * 创建错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCodeEnum 的 name() 和参数 errorMessage。 + * + * @param errorCodeEnum 错误码枚举 + * @param errorMessage 自定义的错误信息 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult error(ErrorCodeEnum errorCodeEnum, String errorMessage) { + return error(errorCodeEnum.name(), errorMessage); + } + + /** + * 创建错误对象。 + * 如果返回错误对象,errorCode 和 errorMessage 分别取自于参数 errorCode 和参数 errorMessage。 + * + * @param errorCode 自定义的错误码 + * @param errorMessage 自定义的错误信息 + * @return 返回创建的ResponseResult实例对象 + */ + public static ResponseResult error(String errorCode, String errorMessage) { + return new ResponseResult<>(errorCode, errorMessage); + } + + /** + * 根据参数中出错的ResponseResult,创建新的错误应答对象。 + * + * @param errorCause 导致错误原因的应答对象。 + * @return 返回创建的ResponseResult实例对象。 + */ + public static ResponseResult errorFrom(ResponseResult errorCause) { + return error(errorCause.errorCode, errorCause.getErrorMessage()); + } + + /** + * 根据参数中出错的CallResult,创建新的错误应答对象。 + * + * @param errorCause 导致错误原因的应答对象。 + * @return 返回创建的ResponseResult实例对象。 + */ + public static ResponseResult errorFrom(CallResult errorCause) { + return error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorCause.getErrorMessage()); + } + + /** + * 是否成功。 + * + * @return true成功,否则false。 + */ + public boolean isSuccess() { + return success; + } + + /** + * 通过HttpServletResponse直接输出应该信息的工具方法。 + * + * @param httpStatus http状态码。 + * @param responseResult 应答内容。 + * @param 数据对象类型。 + * @throws IOException 异常错误。 + */ + public static void output(int httpStatus, ResponseResult responseResult) throws IOException { + if (httpStatus != HttpServletResponse.SC_OK) { + log.error(JSON.toJSONString(responseResult)); + } else { + log.info(JSON.toJSONString(responseResult)); + } + HttpServletResponse response = ContextUtil.getHttpResponse(); + PrintWriter out = response.getWriter(); + response.setContentType("application/json; charset=utf-8"); + response.setStatus(httpStatus); + if (responseResult != null) { + out.print(JSON.toJSONString(responseResult)); + } + out.flush(); + } + + /** + * 通过HttpServletResponse直接输出应该信息的工具方法。 + * + * @param httpStatus http状态码。 + * @param 数据对象类型。 + * @throws IOException 异常错误。 + */ + public static void output(int httpStatus) throws IOException { + output(httpStatus, null); + } + + /** + * 通过HttpServletResponse直接输出应该信息的工具方法。Http状态码为200。 + * + * @param responseResult 应答内容。 + * @param 数据对象类型。 + * @throws IOException 异常错误。 + */ + public static void output(ResponseResult responseResult) throws IOException { + output(HttpServletResponse.SC_OK, responseResult); + } + + private ResponseResult() { + + } + + private ResponseResult(String errorCode, String errorMessage) { + this.success = false; + this.errorCode = errorCode; + this.errorMessage = errorMessage; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/TokenData.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/TokenData.java new file mode 100644 index 00000000..88ab4aa0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/TokenData.java @@ -0,0 +1,99 @@ +package com.flow.demo.common.core.object; + +import com.flow.demo.common.core.util.ContextUtil; +import lombok.Data; +import lombok.ToString; + +import javax.servlet.http.HttpServletRequest; +import java.util.Date; + +/** + * 基于Jwt,用于前后端传递的令牌对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ToString +public class TokenData { + + /** + * 在HTTP Request对象中的属性键。 + */ + public static final String REQUEST_ATTRIBUTE_NAME = "tokenData"; + /** + * 用户Id。 + */ + private Long userId; + /** + * 用户所在部门Id。 + * 仅当系统支持uaa时可用,否则可以直接忽略该字段。保留该字段是为了保持单体和微服务通用代码部分的兼容性。 + */ + private Long deptId; + /** + * 用户的部门岗位Id。多个岗位之间逗号分隔。仅当系统支持岗位时有值。 + */ + private String deptPostIds; + /** + * 租户Id。 + * 仅当系统支持uaa时可用,否则可以直接忽略该字段。保留该字段是为了保持单体和微服务通用代码部分的兼容性。 + */ + private Long tenantId; + /** + * 是否为超级管理员。 + */ + private Boolean isAdmin; + /** + * 用户登录名。 + */ + private String loginName; + /** + * 用户显示名称。 + */ + private String showName; + /** + * 设备类型。参考 AppDeviceType。 + */ + private Integer deviceType; + /** + * 标识不同登录的会话Id。 + */ + private String sessionId; + /** + * 访问uaa的授权token。 + * 仅当系统支持uaa时可用,否则可以直接忽略该字段。保留该字段是为了保持单体和微服务通用代码部分的兼容性。 + */ + private String uaaAccessToken; + /** + * 数据库路由键(仅当水平分库时使用)。 + */ + private Integer datasourceRouteKey; + /** + * 登录IP。 + */ + private String loginIp; + /** + * 登录时间。 + */ + private Date loginTime; + + /** + * 将令牌对象添加到Http请求对象。 + * + * @param tokenData 令牌对象。 + */ + public static void addToRequest(TokenData tokenData) { + HttpServletRequest request = ContextUtil.getHttpRequest(); + request.setAttribute(TokenData.REQUEST_ATTRIBUTE_NAME, tokenData); + } + + /** + * 从Http Request对象中获取令牌对象。 + * + * @return 令牌对象。 + */ + public static TokenData takeFromRequest() { + HttpServletRequest request = ContextUtil.getHttpRequest(); + return (TokenData) request.getAttribute(REQUEST_ATTRIBUTE_NAME); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/Tuple2.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/Tuple2.java new file mode 100644 index 00000000..397b1fa6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/object/Tuple2.java @@ -0,0 +1,50 @@ +package com.flow.demo.common.core.object; + +/** + * 二元组对象。主要用于可以一次返回多个结果的场景,同时还能避免强制转换。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class Tuple2 { + + /** + * 第一个变量。 + */ + private final T1 first; + /** + * 第二个变量。 + */ + private final T2 second; + + /** + * 构造函数。 + * + * @param first 第一个变量。 + * @param second 第二个变量。 + */ + public Tuple2(T1 first, T2 second) { + this.first = first; + this.second = second; + } + + /** + * 获取第一个变量。 + * + * @return 返回第一个变量。 + */ + public T1 getFirst() { + return first; + } + + /** + * 获取第二个变量。 + * + * @return 返回第二个变量。 + */ + public T2 getSecond() { + return second; + } + +} + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/BaseUpDownloader.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/BaseUpDownloader.java new file mode 100644 index 00000000..25a85be3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/BaseUpDownloader.java @@ -0,0 +1,137 @@ +package com.flow.demo.common.core.upload; + +import com.alibaba.fastjson.JSON; +import com.flow.demo.common.core.constant.ApplicationConstant; +import com.flow.demo.common.core.util.ContextUtil; +import com.flow.demo.common.core.util.MyCommonUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.List; + +/** + * 上传或下载文件抽象父类。 + * 包含存储本地文件的功能,以及上传和下载所需的通用方法。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public abstract class BaseUpDownloader { + + /** + * 构建上传文件的完整目录。 + * + * @param rootBaseDir 文件下载的根目录。 + * @param modelName 所在数据表的实体对象名。 + * @param fieldName 关联字段的实体对象属性名。 + * @param asImage 是否为图片对象。图片是无需权限验证的,因此和附件存放在不同的子目录。 + * @return 上传文件的完整路径名。 + */ + public String makeFullPath( + String rootBaseDir, String modelName, String fieldName, Boolean asImage) { + StringBuilder uploadPathBuilder = new StringBuilder(128); + if (StringUtils.isNotBlank(rootBaseDir)) { + uploadPathBuilder.append(rootBaseDir).append("/"); + } + if (Boolean.TRUE.equals(asImage)) { + uploadPathBuilder.append(ApplicationConstant.UPLOAD_IMAGE_PARENT_PATH); + } else { + uploadPathBuilder.append(ApplicationConstant.UPLOAD_ATTACHMENT_PARENT_PATH); + } + uploadPathBuilder.append("/").append(modelName).append("/").append(fieldName).append("/"); + return uploadPathBuilder.toString(); + } + + /** + * 构建上传操作的返回对象。 + * + * @param serviceContextPath 微服务的上下文路径,如: /admin/upms。 + * @param originalFilename 上传文件的原始文件名(包含扩展名)。 + */ + public void fillUploadResponseInfo( + UploadResponseInfo responseInfo, String serviceContextPath, String originalFilename) { + // 根据请求上传的uri构建下载uri,只是将末尾的/upload改为/download即可。 + HttpServletRequest request = ContextUtil.getHttpRequest(); + String uri = request.getRequestURI(); + uri = StringUtils.removeEnd(uri, "/"); + uri = StringUtils.removeEnd(uri, "/upload"); + String downloadUri; + if (StringUtils.isBlank(serviceContextPath)) { + downloadUri = uri + "/download"; + } else { + downloadUri = serviceContextPath + uri + "/download"; + } + StringBuilder filenameBuilder = new StringBuilder(64); + filenameBuilder.append(MyCommonUtil.generateUuid()) + .append(".").append(FilenameUtils.getExtension(originalFilename)); + responseInfo.setDownloadUri(downloadUri); + responseInfo.setFilename(filenameBuilder.toString()); + } + + /** + * 执行下载操作,从本地文件系统读取数据,并将读取的数据直接写入到HttpServletResponse应答对象。 + * + * @param rootBaseDir 文件下载的根目录。 + * @param modelName 所在数据表的实体对象名。 + * @param fieldName 关联字段的实体对象属性名。 + * @param fileName 文件名。 + * @param asImage 是否为图片对象。图片是无需权限验证的,因此和附件存放在不同的子目录。 + * @param response Http 应答对象。 + * @throws Exception 操作错误。 + */ + public abstract void doDownload( + String rootBaseDir, + String modelName, + String fieldName, + String fileName, + Boolean asImage, + HttpServletResponse response) throws Exception; + + /** + * 执行文件上传操作,并存入本地文件系统,再将与该文件下载对应的Url直接写入到HttpServletResponse应答对象,返回给前端。 + * + * @param serviceContextPath 微服务的上下文路径,如: /admin/upms。 + * @param rootBaseDir 存放上传文件的根目录。 + * @param modelName 所在数据表的实体对象名。 + * @param fieldName 关联字段的实体对象属性名。 + * @param uploadFile Http请求中上传的文件对象。 + * @param asImage 是否为图片对象。图片是无需权限验证的,因此和附件存放在不同的子目录。 + * @return 存储在本地上传文件名。 + * @throws Exception 操作错误。 + */ + public abstract UploadResponseInfo doUpload( + String serviceContextPath, + String rootBaseDir, + String modelName, + String fieldName, + Boolean asImage, + MultipartFile uploadFile) throws Exception; + + /** + * 判断filename参数指定的文件名,是否被包含在fileInfoJson参数中。 + * + * @param fileInfoJson 内部类UploadFileInfo的JSONArray数组。 + * @param filename 被包含的文件名。 + * @return 存在返回true,否则false。 + */ + public static boolean containFile(String fileInfoJson, String filename) { + if (StringUtils.isAnyBlank(fileInfoJson, filename)) { + return false; + } + List fileInfoList = JSON.parseArray(fileInfoJson, UploadResponseInfo.class); + if (CollectionUtils.isNotEmpty(fileInfoList)) { + for (UploadResponseInfo fileInfo : fileInfoList) { + if (StringUtils.equals(filename, fileInfo.getFilename())) { + return true; + } + } + } + return false; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/LocalUpDownloader.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/LocalUpDownloader.java new file mode 100644 index 00000000..268f6009 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/LocalUpDownloader.java @@ -0,0 +1,149 @@ +package com.flow.demo.common.core.upload; + +import com.alibaba.fastjson.JSON; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Objects; + +/** + * 存储本地文件的上传下载实现类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Component +public class LocalUpDownloader extends BaseUpDownloader { + + @Autowired + private UpDownloaderFactory factory; + + @PostConstruct + public void doRegister() { + factory.registerUpDownloader(UploadStoreTypeEnum.LOCAL_SYSTEM, this); + } + + /** + * 执行下载操作,从本地文件系统读取数据,并将读取的数据直接写入到HttpServletResponse应答对象。 + * + * @param rootBaseDir 文件下载的根目录。 + * @param modelName 所在数据表的实体对象名。 + * @param fieldName 关联字段的实体对象属性名。 + * @param fileName 文件名。 + * @param asImage 是否为图片对象。图片是无需权限验证的,因此和附件存放在不同的子目录。 + * @param response Http 应答对象。 + */ + @Override + public void doDownload( + String rootBaseDir, + String modelName, + String fieldName, + String fileName, + Boolean asImage, + HttpServletResponse response) { + String uploadPath = makeFullPath(rootBaseDir, modelName, fieldName, asImage); + String fullFileanme = uploadPath + "/" + fileName; + File file = new File(fullFileanme); + if (!file.exists()) { + log.warn("Download file [" + fullFileanme + "] failed, no file found!"); + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + return; + } + response.setHeader("content-type", "application/octet-stream"); + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + fileName); + byte[] buff = new byte[2048]; + try (OutputStream os = response.getOutputStream(); + BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) { + int i = bis.read(buff); + while (i != -1) { + os.write(buff, 0, i); + os.flush(); + i = bis.read(buff); + } + } catch (IOException e) { + log.error("Failed to call LocalUpDownloader.doDownload", e); + } + } + + /** + * 执行文件上传操作,并存入本地文件系统,再将与该文件下载对应的Url直接写入到HttpServletResponse应答对象,返回给前端。 + * + * @param serviceContextPath 微服务的上下文路径,如: /admin/upms。 + * @param rootBaseDir 存放上传文件的根目录。 + * @param modelName 所在数据表的实体对象名。 + * @param fieldName 关联字段的实体对象属性名。 + * @param uploadFile Http请求中上传的文件对象。 + * @param asImage 是否为图片对象。图片是无需权限验证的,因此和附件存放在不同的子目录。 + * @return 存储在本地上传文件名。 + * @throws IOException 文件操作错误。 + */ + @Override + public UploadResponseInfo doUpload( + String serviceContextPath, + String rootBaseDir, + String modelName, + String fieldName, + Boolean asImage, + MultipartFile uploadFile) throws IOException { + UploadResponseInfo responseInfo = new UploadResponseInfo(); + if (Objects.isNull(uploadFile) || uploadFile.isEmpty()) { + responseInfo.setUploadFailed(true); + responseInfo.setErrorMessage(ErrorCodeEnum.INVALID_UPLOAD_FILE_ARGUMENT.getErrorMessage()); + return responseInfo; + } + String uploadPath = makeFullPath(rootBaseDir, modelName, fieldName, asImage); + fillUploadResponseInfo(responseInfo, serviceContextPath, uploadFile.getOriginalFilename()); + try { + byte[] bytes = uploadFile.getBytes(); + Path path = Paths.get(uploadPath + responseInfo.getFilename()); + // 如果没有files文件夹,则创建 + if (!Files.isWritable(path)) { + Files.createDirectories(Paths.get(uploadPath)); + } + // 文件写入指定路径 + Files.write(path, bytes); + } catch (IOException e) { + log.error("Failed to write uploaded file [" + uploadFile.getOriginalFilename() + " ].", e); + responseInfo.setUploadFailed(true); + responseInfo.setErrorMessage(ErrorCodeEnum.INVALID_UPLOAD_FILE_IOERROR.getErrorMessage()); + return responseInfo; + } + return responseInfo; + } + + /** + * 判断filename参数指定的文件名,是否被包含在fileInfoJson参数中。 + * + * @param fileInfoJson 内部类UploadFileInfo的JSONArray数组。 + * @param filename 被包含的文件名。 + * @return 存在返回true,否则false。 + */ + public static boolean containFile(String fileInfoJson, String filename) { + if (StringUtils.isAnyBlank(fileInfoJson, filename)) { + return false; + } + List fileInfoList = JSON.parseArray(fileInfoJson, UploadResponseInfo.class); + if (CollectionUtils.isNotEmpty(fileInfoList)) { + for (UploadResponseInfo fileInfo : fileInfoList) { + if (StringUtils.equals(filename, fileInfo.getFilename())) { + return true; + } + } + } + return false; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UpDownloaderFactory.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UpDownloaderFactory.java new file mode 100644 index 00000000..74ce3d10 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UpDownloaderFactory.java @@ -0,0 +1,49 @@ +package com.flow.demo.common.core.upload; + +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * 业务对象根据上传下载存储类型,获取上传下载对象的工厂类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Component +public class UpDownloaderFactory { + + private final Map upDownloaderMap = new HashMap<>(); + + /** + * 根据存储类型获取上传下载对象。 + * @param storeType 存储类型。 + * @return 匹配的上传下载对象。 + */ + public BaseUpDownloader get(UploadStoreTypeEnum storeType) { + BaseUpDownloader upDownloader = upDownloaderMap.get(storeType); + if (upDownloader == null) { + throw new UnsupportedOperationException( + "The storeType [" + storeType.name() + "] isn't supported, please add dependency jar first."); + } + return upDownloader; + } + + /** + * 注册上传下载对象到工厂。 + * + * @param storeType 存储类型。 + * @param upDownloader 上传下载对象。 + */ + public void registerUpDownloader(UploadStoreTypeEnum storeType, BaseUpDownloader upDownloader) { + if (storeType == null || upDownloader == null) { + throw new IllegalArgumentException("The Argument can't be NULL."); + } + if (upDownloaderMap.containsKey(storeType)) { + throw new UnsupportedOperationException( + "The storeType [" + storeType.name() + "] has been registered already."); + } + upDownloaderMap.put(storeType, upDownloader); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadResponseInfo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadResponseInfo.java new file mode 100644 index 00000000..7da0f300 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadResponseInfo.java @@ -0,0 +1,29 @@ +package com.flow.demo.common.core.upload; + +import lombok.Data; + +/** + * 数据上传操作的应答信息对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class UploadResponseInfo { + /** + * 上传是否出现错误。 + */ + private Boolean uploadFailed = false; + /** + * 具体错误信息。 + */ + private String errorMessage; + /** + * 返回前端的下载url。 + */ + private String downloadUri; + /** + * 返回给前端的文件名。 + */ + private String filename; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadStoreInfo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadStoreInfo.java new file mode 100644 index 00000000..ec8accfa --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadStoreInfo.java @@ -0,0 +1,22 @@ +package com.flow.demo.common.core.upload; + +import lombok.Data; + +/** + * 上传数据存储信息对象。这里之所以使用对象,主要是便于今后扩展。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class UploadStoreInfo { + + /** + * 是否支持上传。 + */ + private boolean supportUpload; + /** + * 上传数据存储类型。 + */ + private UploadStoreTypeEnum storeType; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadStoreTypeEnum.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadStoreTypeEnum.java new file mode 100644 index 00000000..cef43e6c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/upload/UploadStoreTypeEnum.java @@ -0,0 +1,19 @@ +package com.flow.demo.common.core.upload; + +/** + * 上传数据存储介质类型枚举。 + * + * @author Jerry + * @date 2021-06-06 + */ +public enum UploadStoreTypeEnum { + + /** + * 本地系统。 + */ + LOCAL_SYSTEM, + /** + * minio分布式存储。 + */ + MINIO_SYSTEM +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/AopTargetUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/AopTargetUtil.java new file mode 100644 index 00000000..7d2e9ae5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/AopTargetUtil.java @@ -0,0 +1,64 @@ +package com.flow.demo.common.core.util; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.framework.AdvisedSupport; +import org.springframework.aop.framework.AopProxy; +import org.springframework.aop.support.AopUtils; + +import java.lang.reflect.Field; + +/** + * 获取JDK动态代理/CGLIB代理对象代理的目标对象的工具类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class AopTargetUtil { + + /** + * 获取参数对象代理的目标对象。 + * + * @param proxy 代理对象 + * @return 代理的目标对象。 + */ + public static Object getTarget(Object proxy) { + if (!AopUtils.isAopProxy(proxy)) { + return proxy; + } + try { + if (AopUtils.isJdkDynamicProxy(proxy)) { + return getJdkDynamicProxyTargetObject(proxy); + } else { + return getCglibProxyTargetObject(proxy); + } + } catch (Exception e) { + log.error("Failed to call getJdkDynamicProxyTargetObject or getCglibProxyTargetObject", e); + return null; + } + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private AopTargetUtil() { + } + + private static Object getCglibProxyTargetObject(Object proxy) throws Exception { + Field h = proxy.getClass().getDeclaredField("CGLIB$CALLBACK_0"); + h.setAccessible(true); + Object dynamicAdvisedInterceptor = h.get(proxy); + Field advised = dynamicAdvisedInterceptor.getClass().getDeclaredField("advised"); + advised.setAccessible(true); + return ((AdvisedSupport) advised.get(dynamicAdvisedInterceptor)).getTargetSource().getTarget(); + } + + private static Object getJdkDynamicProxyTargetObject(Object proxy) throws Exception { + Field h = proxy.getClass().getSuperclass().getDeclaredField("h"); + h.setAccessible(true); + AopProxy aopProxy = (AopProxy) h.get(proxy); + Field advised = aopProxy.getClass().getDeclaredField("advised"); + advised.setAccessible(true); + return ((AdvisedSupport) advised.get(aopProxy)).getTargetSource().getTarget(); + } +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ApplicationContextHolder.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ApplicationContextHolder.java new file mode 100644 index 00000000..d96f01e8 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ApplicationContextHolder.java @@ -0,0 +1,90 @@ +package com.flow.demo.common.core.util; + +import com.flow.demo.common.core.exception.MyRuntimeException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.lang.NonNull; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.Map; + +/** + * Spring 系统启动应用感知对象,主要用于获取Spring Bean的上下文对象,后续的代码中可以直接查找系统中加载的Bean对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Component +public class ApplicationContextHolder implements ApplicationContextAware { + + private static ApplicationContext applicationContext; + + /** + * Spring 启动的过程中会自动调用,并将应用上下文对象赋值进来。 + * + * @param applicationContext 应用上下文对象,可通过该对象查找Spring中已经加载的Bean。 + */ + @Override + public void setApplicationContext(@NonNull ApplicationContext applicationContext) { + doSetApplicationContext(applicationContext); + } + + /** + * 获取应用上下文对象。 + * + * @return 应用上下文。 + */ + public static ApplicationContext getApplicationContext() { + assertApplicationContext(); + return applicationContext; + } + + /** + * 根据BeanName,获取Bean对象。 + * + * @param beanName Bean名称。 + * @param 返回的Bean类型。 + * @return Bean对象。 + */ + @SuppressWarnings("unchecked") + public static T getBean(String beanName) { + assertApplicationContext(); + return (T) applicationContext.getBean(beanName); + } + + /** + * 根据Bean的ClassType,获取Bean对象。 + * + * @param beanType Bean的Class类型。 + * @param 返回的Bean类型。 + * @return Bean对象。 + */ + public static T getBean(Class beanType) { + assertApplicationContext(); + return applicationContext.getBean(beanType); + } + + /** + * 根据Bean的ClassType,获取Bean对象列表。 + * + * @param beanType Bean的Class类型。 + * @param 返回的Bean类型。 + * @return Bean对象列表。 + */ + public static Collection getBeanListOfType(Class beanType) { + assertApplicationContext(); + Map beanMap = applicationContext.getBeansOfType(beanType); + return beanMap == null ? null : beanMap.values(); + } + + private static void assertApplicationContext() { + if (ApplicationContextHolder.applicationContext == null) { + throw new MyRuntimeException("applicaitonContext属性为null,请检查是否注入了ApplicationContextHolder!"); + } + } + + private static void doSetApplicationContext(ApplicationContext applicationContext) { + ApplicationContextHolder.applicationContext = applicationContext; + } +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ContextUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ContextUtil.java new file mode 100644 index 00000000..d6c90591 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ContextUtil.java @@ -0,0 +1,49 @@ +package com.flow.demo.common.core.util; + +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 获取Servlet HttpRequest和HttpResponse的工具类。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class ContextUtil { + + /** + * 判断当前是否处于HttpServletRequest上下文环境。 + * + * @return 是返回true,否则false。 + */ + public static boolean hasRequestContext() { + return RequestContextHolder.getRequestAttributes() != null; + } + + /** + * 获取Servlet请求上下文的HttpRequest对象。 + * + * @return 请求上下文中的HttpRequest对象。 + */ + public static HttpServletRequest getHttpRequest() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + } + + /** + * 获取Servlet请求上下文的HttpResponse对象。 + * + * @return 请求上下文中的HttpResponse对象。 + */ + public static HttpServletResponse getHttpResponse() { + return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse(); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ContextUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/DataSourceResolver.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/DataSourceResolver.java new file mode 100644 index 00000000..f065a7d4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/DataSourceResolver.java @@ -0,0 +1,19 @@ +package com.flow.demo.common.core.util; + +/** + * 基于自定义解析规则的多数据源解析接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface DataSourceResolver { + + /** + * 动态解析方法。实现类可以根据当前的请求,或者上下文环境进行动态解析。 + * + * @param arg 可选的入参。MyDataSourceResolver注解中的arg参数。 + * @param methodArgs 被织入方法的所有参数。 + * @return 返回用于多数据源切换的类型值。DataSourceResolveAspect 切面方法会根据该返回值和配置信息,进行多数据源切换。 + */ + int resolve(String arg, Object[] methodArgs); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ExportUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ExportUtil.java new file mode 100644 index 00000000..d53c3ea1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/ExportUtil.java @@ -0,0 +1,95 @@ +package com.flow.demo.common.core.util; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.poi.excel.ExcelUtil; +import cn.hutool.poi.excel.ExcelWriter; +import cn.jimmyshi.beanquery.BeanQuery; +import com.flow.demo.common.core.constant.ApplicationConstant; +import com.flow.demo.common.core.exception.MyRuntimeException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVPrinter; +import org.apache.commons.io.FilenameUtils; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * 导出工具类,目前支持xlsx和csv两种类型。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class ExportUtil { + + /** + * 数据导出。目前仅支持xlsx和csv。 + * + * @param dataList 导出数据列表。 + * @param selectFieldMap 导出的数据字段,key为对象字段名称,value为中文标题名称。 + * @param filename 导出文件名。 + * @param 数据对象类型。 + * @throws IOException 文件操作失败。 + */ + public static void doExport( + Collection dataList, Map selectFieldMap, String filename) throws IOException { + if (CollectionUtils.isEmpty(dataList)) { + return; + } + StringBuilder sb = new StringBuilder(128); + for (Map.Entry e : selectFieldMap.entrySet()) { + sb.append(e.getKey()).append(" as ").append(e.getValue()).append(", "); + } + // 去掉末尾的逗号 + String selectFieldString = sb.substring(0, sb.length() - 2); + // 写出数据到xcel格式的输出流 + List> resultList = BeanQuery.select(selectFieldString).executeFrom(dataList); + // 构建HTTP输出流参数 + HttpServletResponse response = ContextUtil.getHttpResponse(); + response.setHeader("content-type", "application/octet-stream"); + response.setContentType("application/octet-stream"); + response.setHeader("Content-Disposition", "attachment;filename=" + filename); + if (ApplicationConstant.XLSX_EXT.equals(FilenameUtils.getExtension(filename))) { + ServletOutputStream out = response.getOutputStream(); + ExcelWriter writer = ExcelUtil.getWriter(true); + writer.setRowHeight(-1, 30); + writer.setColumnWidth(-1, 30); + writer.setColumnWidth(1, 20); + writer.write(resultList); + writer.flush(out); + writer.close(); + IoUtil.close(out); + } else if (ApplicationConstant.CSV_EXT.equals(FilenameUtils.getExtension(filename))) { + Collection headerList = selectFieldMap.values(); + String[] headerArray = new String[headerList.size()]; + headerList.toArray(headerArray); + CSVFormat format = CSVFormat.DEFAULT.withHeader(headerArray); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + try (Writer out = response.getWriter(); CSVPrinter printer = new CSVPrinter(out, format)) { + for (Map o : resultList) { + for (Map.Entry entry : o.entrySet()) { + printer.print(entry.getValue()); + } + printer.println(); + } + printer.flush(); + } catch (Exception e) { + log.error("Failed to call ExportUtil.doExport", e); + } + } else { + throw new MyRuntimeException("不支持的导出文件类型!"); + } + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private ExportUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/IpUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/IpUtil.java new file mode 100644 index 00000000..b55382b8 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/IpUtil.java @@ -0,0 +1,101 @@ +package com.flow.demo.common.core.util; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** + * Ip工具类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class IpUtil { + + private static final String UNKNOWN = "unknown"; + + /** + * 通过Servlet的HttpRequest对象获取Ip地址。 + * + * @param request HttpRequest对象。 + * @return 本次请求的Ip地址。 + */ + public static String getRemoteIpAddress(HttpServletRequest request) { + String ip = null; + // X-Forwarded-For:Squid 服务代理 + String ipAddresses = request.getHeader("X-Forwarded-For"); + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + // Proxy-Client-IP:apache 服务代理 + ipAddresses = request.getHeader("Proxy-Client-IP"); + } + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + // WL-Proxy-Client-IP:weblogic 服务代理 + ipAddresses = request.getHeader("WL-Proxy-Client-IP"); + } + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + // HTTP_CLIENT_IP:有些代理服务器 + ipAddresses = request.getHeader("HTTP_CLIENT_IP"); + } + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + // X-Real-IP:nginx服务代理 + ipAddresses = request.getHeader("X-Real-IP"); + } + // 有些网络通过多层代理,那么获取到的ip就会有多个,一般都是通过逗号(,)分割开来,并且第一个ip为客户端的真实IP + if (StringUtils.isNotBlank(ipAddresses)) { + ip = ipAddresses.split(",")[0]; + } + // 还是不能获取到,最后再通过request.getRemoteAddr();获取 + if (StringUtils.isBlank(ipAddresses) || UNKNOWN.equalsIgnoreCase(ipAddresses)) { + ip = request.getRemoteAddr(); + } + return ip; + } + + public static String getFirstLocalIpAddress() { + String ip; + try { + List ipList = getHostAddress(); + // default the first + ip = (!ipList.isEmpty()) ? ipList.get(0) : ""; + } catch (Exception ex) { + ip = ""; + log.error("Failed to call ", ex); + } + return ip; + } + + private static List getHostAddress() throws SocketException { + List ipList = new ArrayList<>(5); + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface ni = interfaces.nextElement(); + Enumeration allAddress = ni.getInetAddresses(); + while (allAddress.hasMoreElements()) { + InetAddress address = allAddress.nextElement(); + // skip the IPv6 addr + // skip the IPv6 addr + if (address.isLoopbackAddress() || address instanceof Inet6Address) { + continue; + } + String hostAddress = address.getHostAddress(); + ipList.add(hostAddress); + } + } + return ipList; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private IpUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/JwtUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/JwtUtil.java new file mode 100644 index 00000000..484c4879 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/JwtUtil.java @@ -0,0 +1,110 @@ +package com.flow.demo.common.core.util; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import lombok.extern.slf4j.Slf4j; + +import java.util.Date; +import java.util.Map; + +/** + * 基于JWT的Token生成工具类 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class JwtUtil { + + private static final String TOKEN_PREFIX = "Bearer "; + private static final String CLAIM_KEY_CREATEDTIME = "CreatedTime"; + + /** + * Token缺省过期时间是30分钟 + */ + private static final Long TOKEN_EXPIRATION = 1800000L; + /** + * 缺省情况下,Token会每5分钟被刷新一次 + */ + private static final Long REFRESH_TOKEN_INTERVAL = 300000L; + + /** + * 生成加密后的JWT令牌,生成的结果中包含令牌前缀,如"Bearer " + * + * @param claims 令牌中携带的数据 + * @param expirationMillisecond 过期的毫秒数 + * @return 生成后的令牌信息 + */ + public static String generateToken(Map claims, long expirationMillisecond, String signingKey) { + // 自动添加token的创建时间 + long createTime = System.currentTimeMillis(); + claims.put(CLAIM_KEY_CREATEDTIME, createTime); + String token = Jwts.builder() + .setClaims(claims) + .setExpiration(new Date(createTime + expirationMillisecond)) + .signWith(SignatureAlgorithm.HS512, signingKey) + .compact(); + return TOKEN_PREFIX + token; + } + + /** + * 生成加密后的JWT令牌,生成的结果中包含令牌前缀,如"Bearer " + * + * @param claims 令牌中携带的数据 + * @return 生成后的令牌信息 + */ + public static String generateToken(Map claims, String signingKey) { + return generateToken(claims, TOKEN_EXPIRATION, signingKey); + } + + /** + * 获取token中的数据对象 + * + * @param token 令牌信息(需要包含令牌前缀,如"Bearer ") + * @return 令牌中的数据对象,解析视频返回null。 + */ + public static Claims parseToken(String token, String signingKey) { + if (token == null || !token.startsWith(TOKEN_PREFIX)) { + return null; + } + String tokenKey = token.substring(TOKEN_PREFIX.length()); + Claims claims = null; + try { + claims = Jwts.parser().setSigningKey(signingKey).parseClaimsJws(tokenKey).getBody(); + } catch (Exception e) { + log.error("Token Expired", e); + } + return claims; + } + + /** + * 判断令牌是否过期 + * + * @param claims 令牌解密后的Map对象。 + * @return true 过期,否则false。 + */ + public static boolean isNullOrExpired(Claims claims) { + return claims == null || claims.getExpiration().before(new Date()); + } + + /** + * 判断解密后的Token payload是否需要被强制刷新,如果需要,则调用generateToken方法重新生成Token。 + * + * @param claims Token解密后payload数据 + * @return true 需要刷新,否则false + */ + public static boolean needToRefresh(Claims claims) { + if (claims == null) { + return false; + } + Long createTime = (Long) claims.get(CLAIM_KEY_CREATEDTIME); + return createTime == null || System.currentTimeMillis() - createTime > REFRESH_TOKEN_INTERVAL; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private JwtUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/LogMessageUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/LogMessageUtil.java new file mode 100644 index 00000000..54c21efe --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/LogMessageUtil.java @@ -0,0 +1,33 @@ +package com.flow.demo.common.core.util; + +/** + * 拼接日志消息的工具类。 + * 主要目标是,尽量保证日志输出的统一性,同时也可以有效减少与日志信息相关的常量字符串, + * 提高代码的规范度和可维护性。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class LogMessageUtil { + + /** + * RPC调用错误格式。 + */ + private static final String RPC_ERROR_MSG_FORMAT = "RPC Failed with Error message [%s]"; + + /** + * 组装RPC调用的错误信息。 + * + * @param errorMsg 具体的错误信息。 + * @return 格式化后的错误信息。 + */ + public static String makeRpcError(String errorMsg) { + return String.format(RPC_ERROR_MSG_FORMAT, errorMsg); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private LogMessageUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyCommonUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyCommonUtil.java new file mode 100644 index 00000000..e1b0f762 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyCommonUtil.java @@ -0,0 +1,195 @@ +package com.flow.demo.common.core.util; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.crypto.digest.DigestUtil; +import com.flow.demo.common.core.constant.AppDeviceType; + +import javax.validation.ConstraintViolation; +import javax.validation.Validation; +import javax.validation.Validator; +import java.lang.reflect.Field; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 脚手架中常用的基本工具方法集合,一般而言工程内部使用的方法。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class MyCommonUtil { + + private static final Validator VALIDATOR; + + static { + VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator(); + } + + /** + * 创建uuid。 + * + * @return 返回uuid。 + */ + public static String generateUuid() { + return UUID.randomUUID().toString().replace("-", ""); + } + + /** + * 对用户密码进行加盐后加密。 + * + * @param password 明文密码。 + * @param passwordSalt 盐值。 + * @return 加密后的密码。 + */ + public static String encrptedPassword(String password, String passwordSalt) { + return DigestUtil.md5Hex(password + passwordSalt); + } + + /** + * 这个方法一般用于Controller对于入口参数的基本验证。 + * 对于字符串,如果为空字符串,也将视为Blank,同时返回true。 + * + * @param objs 一组参数。 + * @return 返回是否存在null或空字符串的参数。 + */ + public static boolean existBlankArgument(Object...objs) { + for (Object obj : objs) { + if (MyCommonUtil.isBlankOrNull(obj)) { + return true; + } + } + return false; + } + + /** + * 结果和 existBlankArgument 相反。 + * + * @param objs 一组参数。 + * @return 返回是否存在null或空字符串的参数。 + */ + public static boolean existNotBlankArgument(Object...objs) { + for (Object obj : objs) { + if (!MyCommonUtil.isBlankOrNull(obj)) { + return true; + } + } + return false; + } + + /** + * 验证参数是否为空。 + * + * @param obj 待判断的参数。 + * @return 空或者null返回true,否则false。 + */ + public static boolean isBlankOrNull(Object obj) { + if (obj instanceof Collection) { + return CollUtil.isEmpty((Collection) obj); + } + return obj == null || (obj instanceof CharSequence && StrUtil.isBlank((CharSequence) obj)); + } + + /** + * 验证参数是否为非空。 + * + * @param obj 待判断的参数。 + * @return 空或者null返回false,否则true。 + */ + public static boolean isNotBlankOrNull(Object obj) { + return !isBlankOrNull(obj); + } + + /** + * 判断模型对象是否通过校验,没有通过返回具体的校验错误信息。 + * + * @param model 带校验的model。 + * @param groups Validate绑定的校验组。 + * @return 没有错误返回null,否则返回具体的错误信息。 + */ + public static String getModelValidationError(T model, Class...groups) { + Set> constraintViolations = VALIDATOR.validate(model, groups); + if (!constraintViolations.isEmpty()) { + Iterator> it = constraintViolations.iterator(); + ConstraintViolation constraint = it.next(); + return constraint.getMessage(); + } + return null; + } + + /** + * 拼接参数中的字符串列表,用指定分隔符进行分割,同时每个字符串对象用单引号括起来。 + * + * @param dataList 字符串集合。 + * @param separator 分隔符。 + * @return 拼接后的字符串。 + */ + public static String joinString(Collection dataList, final char separator) { + int index = 0; + StringBuilder sb = new StringBuilder(128); + for (String data : dataList) { + sb.append("'").append(data).append("'"); + if (index++ != dataList.size() - 1) { + sb.append(separator); + } + } + return sb.toString(); + } + + /** + * 将SQL Like中的通配符替换为字符本身的含义,以便于比较。 + * + * @param str 待替换的字符串。 + * @return 替换后的字符串。 + */ + public static String replaceSqlWildcard(String str) { + if (StrUtil.isBlank(str)) { + return str; + } + return StrUtil.replaceChars(StrUtil.replaceChars(str, "_", "\\_"), "%", "\\%"); + } + + /** + * 获取对象中,非空字段的名字列表。 + * + * @param object 数据对象。 + * @param clazz 数据对象的class类型。 + * @param 数据对象类型。 + * @return 数据对象中,值不为NULL的字段数组。 + */ + public static String[] getNotNullFieldNames(T object, Class clazz) { + Field[] fields = ReflectUtil.getFields(clazz); + List fieldNameList = Arrays.stream(fields) + .filter(f -> ReflectUtil.getFieldValue(object, f) != null) + .map(Field::getName).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(fieldNameList)) { + return fieldNameList.toArray(new String[]{}); + } + return new String[]{}; + } + + /** + * 获取请求头中的设备信息。 + * + * @return 设备类型,具体值可参考AppDeviceType常量类。 + */ + public static int getDeviceType() { + // 缺省都按照Web登录方式设置,如果前端header中的值为不合法值,这里也不会报错,而是使用Web缺省方式。 + int deviceType = AppDeviceType.WEB; + String deviceTypeString = ContextUtil.getHttpRequest().getHeader("deviceType"); + if (StrUtil.isNotBlank(deviceTypeString)) { + Integer type = Integer.valueOf(deviceTypeString); + if (AppDeviceType.isValid(type)) { + deviceType = type; + } + } + return deviceType; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private MyCommonUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyDateUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyDateUtil.java new file mode 100644 index 00000000..a46fe00b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyDateUtil.java @@ -0,0 +1,181 @@ +package com.flow.demo.common.core.util; + +import com.flow.demo.common.core.object.Tuple2; +import org.apache.commons.lang3.time.DateUtils; +import org.joda.time.DateTime; +import org.joda.time.Period; +import org.joda.time.format.DateTimeFormat; +import org.joda.time.format.DateTimeFormatter; + +import java.util.Calendar; +import java.util.Date; + +import static org.joda.time.PeriodType.days; + +/** + * 日期工具类,主要封装了部分joda-time中的方法,让很多代码一行完成,同时统一了日期到字符串的pattern格式。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class MyDateUtil { + + /** + * 统一的日期pattern,今后可以根据自己的需求去修改。 + */ + public static final String COMMON_DATE_FORMAT = "yyyy-MM-dd"; + /** + * 统一的日期时间pattern,今后可以根据自己的需求去修改。 + */ + public static final String COMMON_DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; + /** + * 缺省日期格式化器,提前获取提升运行时效率。 + */ + private static final DateTimeFormatter DATE_PARSE_FORMATTER = + DateTimeFormat.forPattern(MyDateUtil.COMMON_DATE_FORMAT); + /** + * 缺省日期时间格式化器,提前获取提升运行时效率。 + */ + private static final DateTimeFormatter DATETIME_PARSE_FORMATTER = + DateTimeFormat.forPattern(MyDateUtil.COMMON_DATETIME_FORMAT); + + /** + * 获取一天的开始时间的字符串格式,如2019-08-03 00:00:00.000。 + * + * @param dateTime 待格式化的日期时间对象。 + * @return 格式化后的字符串。 + */ + public static String getBeginTimeOfDay(DateTime dateTime) { + return dateTime.withTimeAtStartOfDay().toString(COMMON_DATETIME_FORMAT); + } + + /** + * 获取一天的结束时间的字符串格式,如2019-08-03 23:59:59.999。 + * + * @param dateTime 待格式化的日期时间对象。 + * @return 格式化后的字符串。 + */ + public static String getEndTimeOfDay(DateTime dateTime) { + return dateTime.withTime(23, 59, 59, 999).toString(COMMON_DATETIME_FORMAT); + } + + /** + * 获取一天中的开始时间和结束时间的字符串格式,如2019-08-03 00:00:00.000 和 2019-08-03 23:59:59.999。 + * + * @param dateTime 待格式化的日期时间对象。 + * @return 包含格式后字符串的二元组对象。 + */ + public static Tuple2 getDateTimeRangeOfDay(DateTime dateTime) { + return new Tuple2<>(getBeginTimeOfDay(dateTime), getEndTimeOfDay(dateTime)); + } + + /** + * 获取本月第一天的日期格式。如2019-08-01。 + * + * @param dateTime 待格式化的日期对象。 + * @return 格式化后的字符串。 + */ + public static String getBeginDateOfMonth(DateTime dateTime) { + return dateTime.withDayOfMonth(1).toString(COMMON_DATE_FORMAT); + } + + /** + * 获取本月第一天的日期格式。如2019-08-01。 + * + * @param dateString 待格式化的日期字符串对象。 + * @return 格式化后的字符串。 + */ + public static String getBeginDateOfMonth(String dateString) { + DateTime dateTime = toDate(dateString); + return dateTime.withDayOfMonth(1).toString(COMMON_DATE_FORMAT); + } + + /** + * 计算指定日期距离今天相差的天数。 + * + * @param dateTime 待格式化的日期时间对象。 + * @return 相差天数。 + */ + public static int getDayDiffToNow(DateTime dateTime) { + return new Period(dateTime, new DateTime(), days()).getDays(); + } + + /** + * 将日期对象格式化为缺省的字符串格式。 + * + * @param dateTime 待格式化的日期对象。 + * @return 格式化后的字符串。 + */ + public static String toDateString(DateTime dateTime) { + return dateTime.toString(COMMON_DATE_FORMAT); + } + + /** + * 将日期时间对象格式化为缺省的字符串格式。 + * + * @param dateTime 待格式化的日期对象。 + * @return 格式化后的字符串。 + */ + public static String toDateTimeString(DateTime dateTime) { + return dateTime.toString(COMMON_DATETIME_FORMAT); + } + + /** + * 将缺省格式的日期字符串解析为日期对象。 + * + * @param dateString 待解析的字符串。 + * @return 解析后的日期对象。 + */ + public static DateTime toDate(String dateString) { + return DATE_PARSE_FORMATTER.parseDateTime(dateString); + } + + /** + * 将缺省格式的日期字符串解析为日期对象。 + * + * @param dateTimeString 待解析的字符串。 + * @return 解析后的日期对象。 + */ + public static DateTime toDateTime(String dateTimeString) { + return DATETIME_PARSE_FORMATTER.parseDateTime(dateTimeString); + } + + /** + * 截取时间到天。如2019-10-03 01:20:30 转换为 2019-10-03 00:00:00。 + * 由于没有字符串的中间转换,因此效率更高。 + * + * @param date 待截取日期对象。 + * @return 转换后日期对象。 + */ + public static Date truncateToDay(Date date) { + return DateUtils.truncate(date, Calendar.DAY_OF_MONTH); + } + + /** + * 截取时间到月。如2019-10-03 01:20:30 转换为 2019-10-01 00:00:00。 + * 由于没有字符串的中间转换,因此效率更高。 + * + * @param date 待截取日期对象。 + * @return 转换后日期对象。 + */ + public static Date truncateToMonth(Date date) { + return DateUtils.truncate(date, Calendar.MONTH); + } + + /** + * 截取时间到年。如2019-10-03 01:20:30 转换为 2019-01-01 00:00:00。 + * 由于没有字符串的中间转换,因此效率更高。 + * + * @param date 待截取日期对象。 + * @return 转换后日期对象。 + */ + public static Date truncateToYear(Date date) { + return DateUtils.truncate(date, Calendar.YEAR); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private MyDateUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyModelUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyModelUtil.java new file mode 100644 index 00000000..e47f418d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyModelUtil.java @@ -0,0 +1,713 @@ +package com.flow.demo.common.core.util; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.util.ReflectUtil; +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.exception.InvalidDataFieldException; +import com.flow.demo.common.core.annotation.*; +import com.flow.demo.common.core.exception.MyRuntimeException; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.core.object.Tuple2; +import com.flow.demo.common.core.upload.UploadStoreInfo; +import com.google.common.base.CaseFormat; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; + +import java.lang.reflect.Field; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 负责Model数据操作、类型转换和关系关联等行为的工具类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class MyModelUtil { + + /** + * 数值型字段。 + */ + public static final Integer NUMERIC_FIELD_TYPE = 0; + /** + * 字符型字段。 + */ + public static final Integer STRING_FIELD_TYPE = 1; + /** + * 日期型字段。 + */ + public static final Integer DATE_FIELD_TYPE = 2; + /** + * 整个工程的实体对象中,创建者Id字段的Java对象名。 + */ + public static final String CREATE_USER_ID_FIELD_NAME = "createUserId"; + /** + * 整个工程的实体对象中,创建时间字段的Java对象名。 + */ + public static final String CREATE_TIME_FIELD_NAME = "createTime"; + /** + * 整个工程的实体对象中,更新者Id字段的Java对象名。 + */ + public static final String UPDATE_USER_ID_FIELD_NAME = "updateUserId"; + /** + * 整个工程的实体对象中,更新时间字段的Java对象名。 + */ + public static final String UPDATE_TIME_FIELD_NAME = "updateTime"; + /** + * mapToColumnName和mapToColumnInfo使用的缓存。 + */ + private static final Map> CACHED_COLUMNINFO_MAP = new ConcurrentHashMap<>(); + + /** + * 将bean的数据列表转换为Map列表。 + * + * @param dataList bean数据列表。 + * @param bean对象类型。 + * @return 转换后的Map列表。 + */ + public static List> beanToMapList(List dataList) { + if (CollectionUtils.isEmpty(dataList)) { + return null; + } + List> resultList = new LinkedList<>(); + for (T data : dataList) { + resultList.add(BeanUtil.beanToMap(data)); + } + return resultList; + } + + /** + * 拷贝源类型的集合数据到目标类型的集合中,其中源类型和目标类型中的对象字段类型完全相同。 + * NOTE: 该函数主要应用于框架中,Dto和Model之间的copy,特别针对一对一关联的深度copy。 + * 在Dto中,一对一对象可以使用Map来表示,而不需要使用从表对象的Dto。 + * + * @param sourceCollection 源类型集合。 + * @param targetClazz 目标类型的Class对象。 + * @param 源类型。 + * @param 目标类型。 + * @return copy后的目标类型对象集合。 + */ + public static List copyCollectionTo(Collection sourceCollection, Class targetClazz) { + List targetList = new LinkedList<>(); + if (CollectionUtils.isNotEmpty(sourceCollection)) { + for (S source : sourceCollection) { + try { + T target = targetClazz.newInstance(); + BeanUtil.copyProperties(source, target); + targetList.add(target); + } catch (Exception e) { + log.error("Failed to call MyModelUtil.copyCollectionTo", e); + return Collections.emptyList(); + } + } + } + return targetList; + } + + /** + * 拷贝源类型的对象数据到目标类型的对象中,其中源类型和目标类型中的对象字段类型完全相同。 + * NOTE: 该函数主要应用于框架中,Dto和Model之间的copy,特别针对一对一关联的深度copy。 + * 在Dto中,一对一对象可以使用Map来表示,而不需要使用从表对象的Dto。 + * + * @param source 源类型对象。 + * @param targetClazz 目标类型的Class对象。 + * @param 源类型。 + * @param 目标类型。 + * @return copy后的目标类型对象。 + */ + public static T copyTo(S source, Class targetClazz) { + if (source == null) { + return null; + } + try { + T target = targetClazz.newInstance(); + BeanUtil.copyProperties(source, target); + return target; + } catch (Exception e) { + log.error("Failed to call MyModelUtil.copyTo", e); + return null; + } + } + + /** + * 映射Model对象的字段反射对象,获取与该字段对应的数据库列名称。 + * + * @param field 字段反射对象。 + * @param modelClazz Model对象的Class类。 + * @return 该字段所对应的数据表列名称。 + */ + public static String mapToColumnName(Field field, Class modelClazz) { + return mapToColumnName(field.getName(), modelClazz); + } + + /** + * 映射Model对象的字段名称,获取与该字段对应的数据库列名称。 + * + * @param fieldName 字段名称。 + * @param modelClazz Model对象的Class类。 + * @return 该字段所对应的数据表列名称。 + */ + public static String mapToColumnName(String fieldName, Class modelClazz) { + Tuple2 columnInfo = mapToColumnInfo(fieldName, modelClazz); + return columnInfo == null ? null : columnInfo.getFirst(); + } + + /** + * 映射Model对象的字段反射对象,获取与该字段对应的数据库列名称。 + * 如果没有匹配到ColumnName,则立刻抛出异常。 + * + * @param field 字段反射对象。 + * @param modelClazz Model对象的Class类。 + * @return 该字段所对应的数据表列名称。 + */ + public static String safeMapToColumnName(Field field, Class modelClazz) { + return safeMapToColumnName(field.getName(), modelClazz); + } + + /** + * 映射Model对象的字段名称,获取与该字段对应的数据库列名称。 + * 如果没有匹配到ColumnName,则立刻抛出异常。 + * + * @param fieldName 字段名称。 + * @param modelClazz Model对象的Class类。 + * @return 该字段所对应的数据表列名称。 + */ + public static String safeMapToColumnName(String fieldName, Class modelClazz) { + String columnName = mapToColumnName(fieldName, modelClazz); + if (columnName == null) { + throw new InvalidDataFieldException(modelClazz.getSimpleName(), fieldName); + } + return columnName; + } + + /** + * 映射Model对象的字段名称,获取与该字段对应的数据库列名称和字段类型。 + * + * @param fieldName 字段名称。 + * @param modelClazz Model对象的Class类。 + * @return 该字段所对应的数据表列名称和Java字段类型。 + */ + public static Tuple2 mapToColumnInfo(String fieldName, Class modelClazz) { + if (StringUtils.isBlank(fieldName)) { + return null; + } + StringBuilder sb = new StringBuilder(128); + sb.append(modelClazz.getName()).append("-#-").append(fieldName); + Tuple2 columnInfo = CACHED_COLUMNINFO_MAP.get(sb.toString()); + if (columnInfo == null) { + Field field = ReflectUtil.getField(modelClazz, fieldName); + if (field == null) { + return null; + } + TableField c = field.getAnnotation(TableField.class); + String columnName = null; + if (c == null) { + TableId id = field.getAnnotation(TableId.class); + if (id != null) { + columnName = id.value(); + } + } + if (columnName == null) { + columnName = c == null ? CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName) : c.value(); + if (StringUtils.isBlank(columnName)) { + columnName = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, fieldName); + } + } + // 这里缺省情况下都是按照整型去处理,因为他覆盖太多的类型了。 + // 如Integer/Long/Double/BigDecimal,可根据实际情况完善和扩充。 + String typeName = field.getType().getSimpleName(); + Integer type = NUMERIC_FIELD_TYPE; + if (String.class.getSimpleName().equals(typeName)) { + type = STRING_FIELD_TYPE; + } else if (Date.class.getSimpleName().equals(typeName)) { + type = DATE_FIELD_TYPE; + } + columnInfo = new Tuple2<>(columnName, type); + CACHED_COLUMNINFO_MAP.put(sb.toString(), columnInfo); + } + return columnInfo; + } + + /** + * 映射Model主对象的Class名称,到Model所对应的表名称。 + * + * @param modelClazz Model主对象的Class。 + * @return Model对象对应的数据表名称。 + */ + public static String mapToTableName(Class modelClazz) { + TableName t = modelClazz.getAnnotation(TableName.class); + return t == null ? null : t.value(); + } + + /** + * 主Model类型中,遍历所有包含RelationConstDict注解的字段,并将关联的静态字典中的数据, + * 填充到thisModel对象的被注解字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModel 主对象。 + * @param 主表对象类型。 + */ + @SuppressWarnings("unchecked") + public static void makeConstDictRelation(Class thisClazz, T thisModel) { + if (thisModel == null) { + return; + } + Field[] fields = ReflectUtil.getFields(thisClazz); + for (Field field : fields) { + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, field.getName()); + RelationConstDict r = thisTargetField.getAnnotation(RelationConstDict.class); + if (r == null) { + continue; + } + Field dictMapField = ReflectUtil.getField(r.constantDictClass(), "DICT_MAP"); + Map dictMap = + (Map) ReflectUtil.getFieldValue(r.constantDictClass(), dictMapField); + Object id = ReflectUtil.getFieldValue(thisModel, r.masterIdField()); + if (id != null) { + String name = dictMap.get(id); + if (name != null) { + Map m = new HashMap<>(2); + m.put("id", id); + m.put("name", name); + ReflectUtil.setFieldValue(thisModel, thisTargetField, m); + } + } + } + } + + /** + * 主Model类型中,遍历所有包含RelationConstDict注解的字段,并将关联的静态字典中的数据, + * 填充到thisModelList集合元素对象的被注解字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param 主表对象类型。 + */ + @SuppressWarnings("unchecked") + public static void makeConstDictRelation(Class thisClazz, List thisModelList) { + if (CollectionUtils.isEmpty(thisModelList)) { + return; + } + Field[] fields = ReflectUtil.getFields(thisClazz); + for (Field field : fields) { + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, field.getName()); + RelationConstDict r = thisTargetField.getAnnotation(RelationConstDict.class); + if (r == null) { + continue; + } + Field dictMapField = ReflectUtil.getField(r.constantDictClass(), "DICT_MAP"); + Map dictMap = + (Map) ReflectUtil.getFieldValue(r.constantDictClass(), dictMapField); + for (T thisModel : thisModelList) { + if (thisModel == null) { + continue; + } + Object id = ReflectUtil.getFieldValue(thisModel, r.masterIdField()); + if (id != null) { + String name = dictMap.get(id); + if (name != null) { + Map m = new HashMap<>(2); + m.put("id", id); + m.put("name", name); + ReflectUtil.setFieldValue(thisModel, thisTargetField, m); + } + } + } + } + } + + /** + * 在主Model类型中,根据thisRelationField字段的RelationDict注解参数,将被关联对象thatModel中的数据, + * 关联到thisModel对象的thisRelationField字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModel 主对象。 + * @param thatModel 字典关联对象。 + * @param thisRelationField 主表对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeDictRelation( + Class thisClazz, T thisModel, R thatModel, String thisRelationField) { + if (thatModel == null || thisModel == null) { + return; + } + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + RelationDict r = thisTargetField.getAnnotation(RelationDict.class); + Class thatClass = r.slaveModelClass(); + Field slaveIdField = ReflectUtil.getField(thatClass, r.slaveIdField()); + Field slaveNameField = ReflectUtil.getField(thatClass, r.slaveNameField()); + Map m = new HashMap<>(2); + m.put("id", ReflectUtil.getFieldValue(thatModel, slaveIdField)); + m.put("name", ReflectUtil.getFieldValue(thatModel, slaveNameField)); + ReflectUtil.setFieldValue(thisModel, thisTargetField, m); + } + + /** + * 在主Model类型中,根据thisRelationField字段的RelationDict注解参数,将被关联对象集合thatModelList中的数据, + * 逐个关联到thisModelList每一个元素的thisRelationField字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thatModelList 字典关联对象列表集合。 + * @param thisRelationField 主表对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeDictRelation( + Class thisClazz, List thisModelList, List thatModelList, String thisRelationField) { + if (CollectionUtils.isEmpty(thatModelList) + || CollectionUtils.isEmpty(thisModelList)) { + return; + } + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + RelationDict r = thisTargetField.getAnnotation(RelationDict.class); + Field masterIdField = ReflectUtil.getField(thisClazz, r.masterIdField()); + Class thatClass = r.slaveModelClass(); + Field slaveIdField = ReflectUtil.getField(thatClass, r.slaveIdField()); + Field slaveNameField = ReflectUtil.getField(thatClass, r.slaveNameField()); + Map thatMap = new HashMap<>(20); + thatModelList.forEach(thatModel -> { + Object id = ReflectUtil.getFieldValue(thatModel, slaveIdField); + thatMap.put(id, thatModel); + }); + thisModelList.forEach(thisModel -> { + if (thisModel != null) { + Object id = ReflectUtil.getFieldValue(thisModel, masterIdField); + R thatModel = thatMap.get(id); + if (thatModel != null) { + Map m = new HashMap<>(4); + m.put("id", id); + m.put("name", ReflectUtil.getFieldValue(thatModel, slaveNameField)); + ReflectUtil.setFieldValue(thisModel, thisTargetField, m); + } + } + }); + } + + /** + * 在主Model类型中,根据thisRelationField字段的RelationDict注解参数,将被关联对象集合thatModelMap中的数据, + * 逐个关联到thisModelList每一个元素的thisRelationField字段中。 + * 该函数之所以使用Map,主要出于性能优化考虑,在连续使用thatModelMap进行关联时,有效的避免了从多次从List转换到Map的过程。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thatMadelMap 字典关联对象映射集合。 + * @param thisRelationField 主表对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeDictRelation( + Class thisClazz, List thisModelList, Map thatMadelMap, String thisRelationField) { + if (MapUtils.isEmpty(thatMadelMap) + || CollectionUtils.isEmpty(thisModelList)) { + return; + } + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + RelationDict r = thisTargetField.getAnnotation(RelationDict.class); + Field masterIdField = ReflectUtil.getField(thisClazz, r.masterIdField()); + Class thatClass = r.slaveModelClass(); + Field slaveNameField = ReflectUtil.getField(thatClass, r.slaveNameField()); + thisModelList.forEach(thisModel -> { + if (thisModel != null) { + Object id = ReflectUtil.getFieldValue(thisModel, masterIdField); + R thatModel = thatMadelMap.get(id); + if (thatModel != null) { + Map m = new HashMap<>(4); + m.put("id", id); + m.put("name", ReflectUtil.getFieldValue(thatModel, slaveNameField)); + ReflectUtil.setFieldValue(thisModel, thisTargetField, m); + } + } + }); + } + + /** + * 在主Model类型中,根据thisRelationField字段的RelationOneToOne注解参数,将被关联对象列表thatModelList中的数据, + * 逐个关联到thisModelList每一个元素的thisRelationField字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thatModelList 一对一关联对象列表。 + * @param thisRelationField 主表对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeOneToOneRelation( + Class thisClazz, List thisModelList, List thatModelList, String thisRelationField) { + if (CollectionUtils.isEmpty(thatModelList) + || CollectionUtils.isEmpty(thisModelList)) { + return; + } + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + RelationOneToOne r = thisTargetField.getAnnotation(RelationOneToOne.class); + Field masterIdField = ReflectUtil.getField(thisClazz, r.masterIdField()); + Class thatClass = r.slaveModelClass(); + Field slaveIdField = ReflectUtil.getField(thatClass, r.slaveIdField()); + Map thatMap = new HashMap<>(20); + thatModelList.forEach(thatModel -> { + Object id = ReflectUtil.getFieldValue(thatModel, slaveIdField); + thatMap.put(id, thatModel); + }); + // 判断放在循环的外部,提升一点儿效率。 + if (thisTargetField.getType().equals(Map.class)) { + thisModelList.forEach(thisModel -> { + Object id = ReflectUtil.getFieldValue(thisModel, masterIdField); + R thatModel = thatMap.get(id); + if (thatModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, BeanUtil.beanToMap(thatModel)); + } + }); + } else { + thisModelList.forEach(thisModel -> { + Object id = ReflectUtil.getFieldValue(thisModel, masterIdField); + R thatModel = thatMap.get(id); + if (thatModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, thatModel); + } + }); + } + } + + /** + * 根据主对象和关联对象各自的关联Id函数,将主对象列表和关联对象列表中的数据关联到一起,并将关联对象 + * 设置到主对象的指定关联字段中。 + * NOTE: 用于主对象关联字段中,没有包含RelationOneToOne注解的场景。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thisIdGetterFunc 主对象Id的Getter函数。 + * @param thatModelList 关联对象列表。 + * @param thatIdGetterFunc 关联对象Id的Getter函数。 + * @param thisRelationField 主对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeOneToOneRelation( + Class thisClazz, + List thisModelList, + Function thisIdGetterFunc, + List thatModelList, + Function thatIdGetterFunc, + String thisRelationField) { + makeOneToOneRelation(thisClazz, thisModelList, + thisIdGetterFunc, thatModelList, thatIdGetterFunc, thisRelationField, false); + } + + /** + * 根据主对象和关联对象各自的关联Id函数,将主对象列表和关联对象列表中的数据关联到一起,并将关联对象 + * 设置到主对象的指定关联字段中。 + * NOTE: 用于主对象关联字段中,没有包含RelationOneToOne注解的场景。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thisIdGetterFunc 主对象Id的Getter函数。 + * @param thatModelList 关联对象列表。 + * @param thatIdGetterFunc 关联对象Id的Getter函数。 + * @param thisRelationField 主对象中保存被关联对象的字段名称。 + * @param orderByThatList 如果为true,则按照ThatModelList的顺序输出。同时thisModelList被排序后的新列表替换。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeOneToOneRelation( + Class thisClazz, + List thisModelList, + Function thisIdGetterFunc, + List thatModelList, + Function thatIdGetterFunc, + String thisRelationField, + boolean orderByThatList) { + if (CollectionUtils.isEmpty(thisModelList)) { + return; + } + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + boolean isMap = thisTargetField.getType().equals(Map.class); + if (orderByThatList) { + List newThisModelList = new LinkedList<>(); + Map thisModelMap = + thisModelList.stream().collect(Collectors.toMap(thisIdGetterFunc, c -> c)); + thatModelList.forEach(thatModel -> { + Object thatId = thatIdGetterFunc.apply(thatModel); + T thisModel = thisModelMap.get(thatId); + if (thisModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, normalize(isMap, thatModel)); + newThisModelList.add(thisModel); + } + }); + thisModelList.clear(); + thisModelList.addAll(newThisModelList); + } else { + Map thatMadelMap = + thatModelList.stream().collect(Collectors.toMap(thatIdGetterFunc, c -> c)); + thisModelList.forEach(thisModel -> { + Object thisId = thisIdGetterFunc.apply(thisModel); + R thatModel = thatMadelMap.get(thisId); + if (thatModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, normalize(isMap, thatModel)); + } + }); + } + } + + /** + * 在主Model类型中,根据thisRelationField字段的RelationOneToMany注解参数,将被关联对象列表thatModelList中的数据, + * 逐个关联到thisModelList每一个元素的thisRelationField字段中。 + * + * @param thisClazz 主对象的Class对象。 + * @param thisModelList 主对象列表。 + * @param thatModelList 一对多关联对象列表。 + * @param thisRelationField 主表对象中保存被关联对象的字段名称。 + * @param 主表对象类型。 + * @param 从表对象类型。 + */ + public static void makeOneToManyRelation( + Class thisClazz, List thisModelList, List thatModelList, String thisRelationField) { + if (CollectionUtils.isEmpty(thatModelList) || CollectionUtils.isEmpty(thisModelList)) { + return; + } + // 这里不做任何空值判断,从而让配置错误在调试期间即可抛出 + Field thisTargetField = ReflectUtil.getField(thisClazz, thisRelationField); + RelationOneToMany r = thisTargetField.getAnnotation(RelationOneToMany.class); + Field masterIdField = ReflectUtil.getField(thisClazz, r.masterIdField()); + Class thatClass = r.slaveModelClass(); + Field slaveIdField = ReflectUtil.getField(thatClass, r.slaveIdField()); + Map> thatMap = new HashMap<>(20); + thatModelList.forEach(thatModel -> { + Object id = ReflectUtil.getFieldValue(thatModel, slaveIdField); + List thatModelSubList = thatMap.computeIfAbsent(id, k -> new LinkedList<>()); + thatModelSubList.add(thatModel); + }); + thisModelList.forEach(thisModel -> { + Object id = ReflectUtil.getFieldValue(thisModel, masterIdField); + List thatModel = thatMap.get(id); + if (thatModel != null) { + ReflectUtil.setFieldValue(thisModel, thisTargetField, thatModel); + } + }); + } + + private static Object normalize(boolean isMap, M model) { + return isMap ? BeanUtil.beanToMap(model) : model; + } + + /** + * 获取上传字段的存储信息。 + * + * @param modelClass model的class对象。 + * @param uploadFieldName 上传字段名。 + * @param model的类型。 + * @return 字段的上传存储信息对象。该值始终不会返回null。 + */ + public static UploadStoreInfo getUploadStoreInfo(Class modelClass, String uploadFieldName) { + UploadStoreInfo uploadStoreInfo = new UploadStoreInfo(); + Field uploadField = ReflectUtil.getField(modelClass, uploadFieldName); + if (uploadField == null) { + throw new UnsupportedOperationException("The Field [" + + uploadFieldName + "] doesn't exist in Model [" + modelClass.getSimpleName() + "]."); + } + uploadStoreInfo.setSupportUpload(false); + UploadFlagColumn anno = uploadField.getAnnotation(UploadFlagColumn.class); + if (anno != null) { + uploadStoreInfo.setSupportUpload(true); + uploadStoreInfo.setStoreType(anno.storeType()); + } + return uploadStoreInfo; + } + + /** + * 在插入实体对象数据之前,可以调用该方法,初始化通用字段的数据。 + * + * @param data 实体对象。 + * @param 实体对象类型。 + */ + public static void fillCommonsForInsert(M data) { + try { + Field createdByField = ReflectUtil.getField(data.getClass(), CREATE_USER_ID_FIELD_NAME); + if (createdByField != null) { + ReflectUtil.setAccessible(createdByField); + createdByField.set(data, TokenData.takeFromRequest().getUserId()); + } + Field createTimeField = ReflectUtil.getField(data.getClass(), CREATE_TIME_FIELD_NAME); + if (createTimeField != null) { + ReflectUtil.setAccessible(createTimeField); + createTimeField.set(data, new Date()); + } + Field updatedByField = ReflectUtil.getField(data.getClass(), UPDATE_USER_ID_FIELD_NAME); + if (updatedByField != null) { + ReflectUtil.setAccessible(updatedByField); + updatedByField.set(data, TokenData.takeFromRequest().getUserId()); + } + Field updateTimeField = ReflectUtil.getField(data.getClass(), UPDATE_TIME_FIELD_NAME); + if (updateTimeField != null) { + ReflectUtil.setAccessible(updateTimeField); + updateTimeField.set(data, new Date()); + } + } catch (IllegalAccessException e) { + throw new MyRuntimeException(e); + } + } + + /** + * 在更新实体对象数据之前,可以调用该方法,更新通用字段的数据。 + * + * @param data 实体对象。 + * @param originalData 原有实体对象。 + * @param 实体对象类型。 + */ + public static void fillCommonsForUpdate(M data, M originalData) { + try { + Object createdByValue = ReflectUtil.getFieldValue(originalData, CREATE_USER_ID_FIELD_NAME); + if (createdByValue != null) { + ReflectUtil.setFieldValue(data, CREATE_USER_ID_FIELD_NAME, createdByValue); + } + Object createTimeValue = ReflectUtil.getFieldValue(originalData, CREATE_TIME_FIELD_NAME); + if (createTimeValue != null) { + ReflectUtil.setFieldValue(data, CREATE_TIME_FIELD_NAME, createTimeValue); + } + Field updatedByField = ReflectUtil.getField(data.getClass(), UPDATE_USER_ID_FIELD_NAME); + if (updatedByField != null) { + ReflectUtil.setAccessible(updatedByField); + updatedByField.set(data, TokenData.takeFromRequest().getUserId()); + } + Field updateTimeField = ReflectUtil.getField(data.getClass(), UPDATE_TIME_FIELD_NAME); + if (updateTimeField != null) { + ReflectUtil.setAccessible(updateTimeField); + updateTimeField.set(data, new Date()); + } + } catch (IllegalAccessException e) { + throw new MyRuntimeException(e); + } + } + + /** + * 为实体对象字段设置缺省值。如果data对象中指定字段的值为NULL,则设置缺省值,否则跳过。 + * @param data 实体对象。 + * @param fieldName 实体对象字段名。 + * @param defaultValue 缺省值。 + * @param 实体对象类型。 + * @param 缺省值类型。 + */ + public static void setDefaultValue(M data, String fieldName, V defaultValue) { + Object v = ReflectUtil.getFieldValue(data, fieldName); + if (v == null) { + ReflectUtil.setFieldValue(data, fieldName, defaultValue); + } + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private MyModelUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyPageUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyPageUtil.java new file mode 100644 index 00000000..6b167ed7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/MyPageUtil.java @@ -0,0 +1,108 @@ +package com.flow.demo.common.core.util; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.Page; +import org.apache.commons.collections4.CollectionUtils; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.core.object.MyPageData; +import com.flow.demo.common.core.object.Tuple2; + +import java.util.List; + +/** + * 生成带有分页信息的数据列表 + * + * @author Jerry + * @date 2021-06-06 + */ +public class MyPageUtil { + + private static final String DATA_LIST_LITERAL = "dataList"; + private static final String TOTAL_COUNT_LITERAL = "totalCount"; + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 数据列表,该参数必须是调用PageMethod.startPage之后,立即执行mybatis查询操作的结果集。 + * @param includeFields 结果集中需要返回到前端的字段,多个字段之间逗号分隔。 + * @return 返回只是包含includeFields字段的数据列表,以及结果集TotalCount。 + */ + public static JSONObject makeResponseData(List dataList, String includeFields) { + JSONObject pageData = new JSONObject(); + pageData.put(DATA_LIST_LITERAL, BeanQuery.select(includeFields).from(dataList).execute()); + if (dataList instanceof Page) { + pageData.put(TOTAL_COUNT_LITERAL, ((Page)dataList).getTotal()); + } + return pageData; + } + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 数据列表,该参数必须是调用PageMethod.startPage之后,立即执行mybatis查询操作的结果集。 + * @return 返回分页数据对象。 + */ + public static MyPageData makeResponseData(List dataList) { + MyPageData pageData = new MyPageData<>(); + pageData.setDataList(dataList); + if (dataList instanceof Page) { + pageData.setTotalCount(((Page)dataList).getTotal()); + } + return pageData; + } + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 数据列表,该参数必须是调用PageMethod.startPage之后,立即执行mybatis查询操作的结果集。 + * @param totalCount 总数量。 + * @return 返回分页数据对象。 + */ + public static MyPageData makeResponseData(List dataList, Long totalCount) { + MyPageData pageData = new MyPageData<>(); + pageData.setDataList(dataList); + if (totalCount != null) { + pageData.setTotalCount(totalCount); + } + return pageData; + } + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param dataList 实体对象数据列表。 + * @param modelMapper 实体对象到DomainVO对象的数据映射器。 + * @param DomainVO对象类型。 + * @param 实体对象类型。 + * @return 返回分页数据对象。 + */ + public static MyPageData makeResponseData(List dataList, BaseModelMapper modelMapper) { + long totalCount = 0L; + if (CollectionUtils.isEmpty(dataList)) { + // 这里需要构建分页数据对象,统一前端数据格式 + return MyPageData.emptyPageData(); + } + if (dataList instanceof Page) { + totalCount = ((Page) dataList).getTotal(); + } + return MyPageUtil.makeResponseData(modelMapper.fromModelList(dataList), totalCount); + } + + /** + * 用户构建带有分页信息的数据列表。 + * + * @param responseData 第一个数据时数据列表,第二个是列表数量。 + * @param 源数据类型。 + * @return 返回分页数据对象。 + */ + public static MyPageData makeResponseData(Tuple2, Long> responseData) { + return makeResponseData(responseData.getFirst(), responseData.getSecond()); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private MyPageUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/RedisKeyUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/RedisKeyUtil.java new file mode 100644 index 00000000..065a1477 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/RedisKeyUtil.java @@ -0,0 +1,86 @@ +package com.flow.demo.common.core.util; + +/** + * Redis 键生成工具类。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class RedisKeyUtil { + + /** + * 获取通用的session缓存的键前缀。 + * + * @return session缓存的键前缀。 + */ + public static String getSessionIdPrefix() { + return "SESSIONID__"; + } + + /** + * 获取指定用户Id的session缓存的键前缀。 + * + * @param loginName 指定的用户登录名。 + * @return session缓存的键前缀。 + */ + public static String getSessionIdPrefix(String loginName) { + return "SESSIONID__" + loginName + "_"; + } + + /** + * 获取指定用户Id和登录设备类型的session缓存的键前缀。 + * + * @param loginName 指定的用户登录名。 + * @param deviceType 设备类型。 + * @return session缓存的键前缀。 + */ + public static String getSessionIdPrefix(String loginName, int deviceType) { + return "SESSIONID__" + loginName + "_" + deviceType + "_"; + } + + /** + * 计算SessionId返回存储于Redis中的键。 + * + * @param sessionId 会话Id。 + * @return 会话存储于Redis中的键值。 + */ + public static String makeSessionIdKey(String sessionId) { + return "SESSIONID__" + sessionId; + } + + /** + * 计算SessionId关联的权限数据存储于Redis中的键。 + * + * @param sessionId 会话Id。 + * @return 会话关联的权限数据存储于Redis中的键值。 + */ + public static String makeSessionPermIdKey(String sessionId) { + return "PERM__" + sessionId; + } + + /** + * 计算SessionId关联的数据权限数据存储于Redis中的键。 + * + * @param sessionId 会话Id。 + * @return 会话关联的数据权限数据存储于Redis中的键值。 + */ + public static String makeSessionDataPermIdKey(String sessionId) { + return "DATA_PERM__" + sessionId; + } + + /** + * 计算在线表对象缓存在Redis中的键值。 + * + * @param tableId 在线表主键Id。 + * @return 会话关联的数据权限数据存储于Redis中的键值。 + */ + public static String makeOnlineTableKey(Long tableId) { + return "ONLINE_TABLE_" + tableId; + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private RedisKeyUtil() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/RsaUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/RsaUtil.java new file mode 100644 index 00000000..a8b37ed0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/RsaUtil.java @@ -0,0 +1,115 @@ +package com.flow.demo.common.core.util; + +import javax.crypto.Cipher; +import java.nio.charset.StandardCharsets; +import java.security.*; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.HashMap; +import java.util.Map; + +/** + * Java RSA 加密工具类。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class RsaUtil { + + /** + * 密钥长度 于原文长度对应 以及越长速度越慢 + */ + private static final int KEY_SIZE = 1024; + /** + * 用于封装随机产生的公钥与私钥 + */ + private static final Map KEY_MAP = new HashMap<>(); + + /** + * 随机生成密钥对。 + */ + public static void genKeyPair() throws NoSuchAlgorithmException { + // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象 + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); + // 初始化密钥对生成器 + keyPairGen.initialize(KEY_SIZE, new SecureRandom()); + // 生成一个密钥对,保存在keyPair中 + KeyPair keyPair = keyPairGen.generateKeyPair(); + // 得到私钥 + RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); + // 得到公钥 + RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); + String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded()); + // 得到私钥字符串 + String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded()); + // 将公钥和私钥保存到Map + // 0表示公钥 + KEY_MAP.put(0, publicKeyString); + // 1表示私钥 + KEY_MAP.put(1, privateKeyString); + } + + /** + * RSA公钥加密。 + * + * @param str 加密字符串 + * @param publicKey 公钥 + * @return 密文 + * @throws Exception 加密过程中的异常信息 + */ + public static String encrypt(String str, String publicKey) throws Exception { + // base64编码的公钥 + byte[] decoded = Base64.getDecoder().decode(publicKey); + RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded)); + // RSA加密。后面这个更安全,但是SonarQube始终report安全漏洞。"RSA/ECB/PKCS1Padding" + // 而浏览器自带的Javascript加密功能,目前safari不支持,而且用的人也不太多。所以暂时都不考虑了。 + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.ENCRYPT_MODE, pubKey); + return Base64.getEncoder().encodeToString(cipher.doFinal(str.getBytes(StandardCharsets.UTF_8))); + } + + /** + * RSA私钥解密。 + * + * @param str 加密字符串 + * @param privateKey 私钥 + * @return 明文 + * @throws Exception 解密过程中的异常信息 + */ + public static String decrypt(String str, String privateKey) throws Exception { + // 64位解码加密后的字符串 + byte[] inputByte = Base64.getDecoder().decode(str); + // base64编码的私钥 + byte[] decoded = Base64.getDecoder().decode(privateKey); + RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded)); + // RSA解密 + Cipher cipher = Cipher.getInstance("RSA"); + cipher.init(Cipher.DECRYPT_MODE, priKey); + return new String(cipher.doFinal(inputByte)); + } + + public static void main(String[] args) throws Exception { + long temp = System.currentTimeMillis(); + // 生成公钥和私钥 + genKeyPair(); + // 加密字符串 + System.out.println("公钥:" + KEY_MAP.get(0)); + System.out.println("私钥:" + KEY_MAP.get(1)); + System.out.println("生成密钥消耗时间:" + (System.currentTimeMillis() - temp) / 1000.0 + "秒"); + System.out.println("生成后的公钥前端使用!"); + System.out.println("生成后的私钥后台使用!"); + String message = "RSA测试ABCD~!@#$"; + System.out.println("原文:" + message); + temp = System.currentTimeMillis(); + String messageEn = encrypt(message, KEY_MAP.get(0)); + System.out.println("密文:" + messageEn); + System.out.println("加密消耗时间:" + (System.currentTimeMillis() - temp) / 1000.0 + "秒"); + temp = System.currentTimeMillis(); + String messageDe = decrypt(messageEn, KEY_MAP.get(1)); + System.out.println("解密:" + messageDe); + System.out.println("解密消耗时间:" + (System.currentTimeMillis() - temp) / 1000.0 + "秒"); + } +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/TreeNode.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/TreeNode.java new file mode 100644 index 00000000..8f52d5ff --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/util/TreeNode.java @@ -0,0 +1,93 @@ +package com.flow.demo.common.core.util; + +import lombok.Data; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +/** + * 将列表结构组建为树结构的工具类。 + * + * @param 对象类型。 + * @param 节点之间关联键的类型。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class TreeNode { + + private K id; + private K parentId; + private T data; + private List> childList = new ArrayList<>(); + + /** + * 将列表结构组建为树结构的工具方法。 + * + * @param dataList 数据列表结构。 + * @param idFunc 获取关联id的函数对象。 + * @param parentIdFunc 获取关联ParentId的函数对象。 + * @param root 根节点。 + * @param 数据对象类型。 + * @param 节点之间关联键的类型。 + * @return 源数据对象的树结构存储。 + */ + public static List> build( + List dataList, Function idFunc, Function parentIdFunc, K root) { + List> treeNodeList = new ArrayList<>(); + for (T data : dataList) { + if (parentIdFunc.apply(data).equals(idFunc.apply(data))) { + continue; + } + TreeNode dataNode = new TreeNode<>(); + dataNode.setId(idFunc.apply(data)); + dataNode.setParentId(parentIdFunc.apply(data)); + dataNode.setData(data); + treeNodeList.add(dataNode); + } + return root == null ? toBuildTreeWithoutRoot(treeNodeList) : toBuildTree(treeNodeList, root); + } + + private static List> toBuildTreeWithoutRoot(List> treeNodes) { + Map> treeNodeMap = new HashMap<>(treeNodes.size()); + for (TreeNode treeNode : treeNodes) { + treeNodeMap.put(treeNode.id, treeNode); + } + List> treeNodeList = new ArrayList<>(); + for (TreeNode treeNode : treeNodes) { + TreeNode parentNode = treeNodeMap.get(treeNode.getParentId()); + if (parentNode == null) { + treeNodeList.add(treeNode); + } else { + parentNode.add(treeNode); + } + } + return treeNodeList; + } + + private static List> toBuildTree(List> treeNodes, K root) { + List> treeNodeList = new ArrayList<>(); + for (TreeNode treeNode : treeNodes) { + if (root.equals(treeNode.getParentId())) { + treeNodeList.add(treeNode); + } + for (TreeNode it : treeNodes) { + if (it.getParentId() == treeNode.getId()) { + if (treeNode.getChildList() == null) { + treeNode.setChildList(new ArrayList<>()); + } + treeNode.add(it); + } + } + } + return treeNodeList; + } + + private void add(TreeNode node) { + childList.add(node); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/AddGroup.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/AddGroup.java new file mode 100644 index 00000000..5b8b586a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/AddGroup.java @@ -0,0 +1,10 @@ +package com.flow.demo.common.core.validator; + +/** + * 数据增加的验证分组。通常用于数据新增场景。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface AddGroup { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/ConstDictRef.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/ConstDictRef.java new file mode 100644 index 00000000..01990460 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/ConstDictRef.java @@ -0,0 +1,48 @@ +package com.flow.demo.common.core.validator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 定义在Model对象中,标注字段值引用自指定的常量字典,和ConstDictRefValidator对象配合完成数据验证。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ConstDictValidator.class) +public @interface ConstDictRef { + + /** + * 引用的常量字典对象,该对象必须包含isValid的静态方法。 + * + * @return 最大长度。 + */ + Class constDictClass(); + + /** + * 超过边界后的错误消息提示。 + * + * @return 错误提示。 + */ + String message() default "无效的字典引用值!"; + + /** + * 验证分组。 + * + * @return 验证分组。 + */ + Class[] groups() default {}; + + /** + * 载荷对象类型。 + * + * @return 载荷对象。 + */ + Class[] payload() default {}; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/ConstDictValidator.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/ConstDictValidator.java new file mode 100644 index 00000000..d62b6a88 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/ConstDictValidator.java @@ -0,0 +1,33 @@ +package com.flow.demo.common.core.validator; + +import cn.hutool.core.util.ReflectUtil; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.lang.reflect.Method; + +/** + * 数据字段自定义验证,用于验证Model中字符串字段的最大长度和最小长度。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class ConstDictValidator implements ConstraintValidator { + + private ConstDictRef constDictRef; + + @Override + public void initialize(ConstDictRef constDictRef) { + this.constDictRef = constDictRef; + } + + @Override + public boolean isValid(Object s, ConstraintValidatorContext constraintValidatorContext) { + if (s == null) { + return true; + } + Method method = + ReflectUtil.getMethodByName(constDictRef.constDictClass(), "isValid"); + return ReflectUtil.invokeStatic(method, s); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/TextLength.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/TextLength.java new file mode 100644 index 00000000..ec3a9795 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/TextLength.java @@ -0,0 +1,55 @@ +package com.flow.demo.common.core.validator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 定义在Model或Dto对象中,UTF-8编码的字符串字段长度的上限和下限,和TextLengthValidator对象配合完成数据验证。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = TextLengthValidator.class) +public @interface TextLength { + + /** + * 字符串字段的最小长度。 + * + * @return 最小长度。 + */ + int min() default 0; + + /** + * 字符串字段的最大长度。 + * + * @return 最大长度。 + */ + int max() default Integer.MAX_VALUE; + + /** + * 超过边界后的错误消息提示。 + * + * @return 错误提示。 + */ + String message() default "字段长度超过最大字节数!"; + + /** + * 验证分组。 + * + * @return 验证分组。 + */ + Class[] groups() default { }; + + /** + * 载荷对象类型。 + * + * @return 载荷对象。 + */ + Class[] payload() default { }; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/TextLengthValidator.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/TextLengthValidator.java new file mode 100644 index 00000000..5c40ddc8 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/TextLengthValidator.java @@ -0,0 +1,39 @@ +package com.flow.demo.common.core.validator; + +import org.apache.commons.lang3.CharUtils; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; + +/** + * 数据字段自定义验证,用于验证Model中UTF-8编码的字符串字段的最大长度和最小长度。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class TextLengthValidator implements ConstraintValidator { + + private TextLength textLength; + + @Override + public void initialize(TextLength textLength) { + this.textLength = textLength; + } + + @Override + public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { + if (s == null) { + return true; + } + int length = 0; + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (CharUtils.isAscii(c)) { + ++length; + } else { + length += 2; + } + } + return length >= textLength.min() && length <= textLength.max(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/UpdateGroup.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/UpdateGroup.java new file mode 100644 index 00000000..193406d6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-core/src/main/java/com/flow/demo/common/core/validator/UpdateGroup.java @@ -0,0 +1,11 @@ +package com.flow.demo.common.core.validator; + +/** + * 数据修改的验证分组。通常用于数据更新的场景。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface UpdateGroup { + +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/pom.xml new file mode 100644 index 00000000..62a44e17 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/pom.xml @@ -0,0 +1,29 @@ + + + + common + com.flow.demo + 1.0.0 + + 4.0.0 + + common-datafilter + 1.0.0 + common-datafilter + jar + + + + com.flow.demo + common-core + 1.0.0 + + + com.flow.demo + common-redis + 1.0.0 + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/aop/DisableDataFilterAspect.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/aop/DisableDataFilterAspect.java new file mode 100644 index 00000000..dad1b077 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/aop/DisableDataFilterAspect.java @@ -0,0 +1,41 @@ +package com.flow.demo.common.datafilter.aop; + +import com.flow.demo.common.core.object.GlobalThreadLocal; +import lombok.extern.slf4j.Slf4j; +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.core.annotation.Order; +import org.springframework.stereotype.Component; + +/** + * 禁用Mybatis拦截器数据过滤的AOP处理类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Aspect +@Component +@Order(1) +@Slf4j +public class DisableDataFilterAspect { + + /** + * 所有标记了DisableDataFilter注解的方法。 + */ + @Pointcut("@annotation(com.flow.demo.common.core.annotation.DisableDataFilter)") + public void disableDataFilterPointCut() { + // 空注释,避免sonar警告 + } + + @Around("disableDataFilterPointCut()") + public Object around(ProceedingJoinPoint point) throws Throwable { + boolean dataFilterEnabled = GlobalThreadLocal.setDataFilter(false); + try { + return point.proceed(); + } finally { + GlobalThreadLocal.setDataFilter(dataFilterEnabled); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterAutoConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterAutoConfig.java new file mode 100644 index 00000000..8a330340 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterAutoConfig.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.datafilter.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +/** + * common-datafilter模块的自动配置引导类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EnableConfigurationProperties({DataFilterProperties.class}) +public class DataFilterAutoConfig { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterProperties.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterProperties.java new file mode 100644 index 00000000..a8e401f5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterProperties.java @@ -0,0 +1,44 @@ +package com.flow.demo.common.datafilter.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * common-datafilter模块的配置类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ConfigurationProperties(prefix = "datafilter") +public class DataFilterProperties { + + /** + * 是否启用租户过滤。 + */ + @Value("${datafilter.tenant.enabled}") + private Boolean enabledTenantFilter; + + /** + * 是否启动数据权限过滤。 + */ + @Value("${datafilter.dataperm.enabled}") + private Boolean enabledDataPermFilter; + + /** + * 部门关联表的表名前缀,如zz_。该值主要用在MybatisDataFilterInterceptor拦截器中, + * 用于拼接数据权限过滤的SQL语句。 + */ + @Value("${datafilter.dataperm.deptRelationTablePrefix:}") + private String deptRelationTablePrefix; + + /** + * 该值为true的时候,在进行数据权限过滤时,会加上表名,如:zz_sys_user.dept_id = xxx。 + * 为false时,过滤条件不加表名,只是使用字段名,如:dept_id = xxx。该值目前主要适用于 + * Oracle分页SQL使用了子查询的场景。此场景下,由于子查询使用了别名,再在数据权限过滤条件中 + * 加上原有表名时,SQL语法会报错。 + */ + @Value("${datafilter.dataperm.addTableNamePrefix:true}") + private Boolean addTableNamePrefix; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterWebMvcConfigurer.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterWebMvcConfigurer.java new file mode 100644 index 00000000..acf7f246 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/config/DataFilterWebMvcConfigurer.java @@ -0,0 +1,21 @@ +package com.flow.demo.common.datafilter.config; + +import com.flow.demo.common.datafilter.interceptor.DataFilterInterceptor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * 添加数据过滤相关的拦截器。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +public class DataFilterWebMvcConfigurer implements WebMvcConfigurer { + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(new DataFilterInterceptor()).addPathPatterns("/**"); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/constant/DataPermRuleType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/constant/DataPermRuleType.java new file mode 100644 index 00000000..836730f6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/constant/DataPermRuleType.java @@ -0,0 +1,69 @@ +package com.flow.demo.common.datafilter.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 数据权限规则类型常量类。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class DataPermRuleType { + + /** + * 查看全部。 + */ + public static final int TYPE_ALL = 0; + + /** + * 仅查看当前用户 + */ + public static final int TYPE_USER_ONLY = 1; + + /** + * 仅查看当前部门 + */ + public static final int TYPE_DEPT_ONLY = 2; + + /** + * 所在部门及子部门 + */ + public static final int TYPE_DEPT_AND_CHILD_DEPT = 3; + + /** + * 多部门及子部门 + */ + public static final int TYPE_MULTI_DEPT_AND_CHILD_DEPT = 4; + + /** + * 自定义部门列表 + */ + public static final int TYPE_CUSTOM_DEPT_LIST = 5; + + private static final Map DICT_MAP = new HashMap<>(6); + static { + DICT_MAP.put(0, "查看全部"); + DICT_MAP.put(1, "仅查看当前用户"); + DICT_MAP.put(2, "仅查看所在部门"); + DICT_MAP.put(3, "所在部门及子部门"); + DICT_MAP.put(4, "多部门及子部门"); + DICT_MAP.put(5, "自定义部门列表"); + } + + /** + * 判断参数是否为当前常量字典的合法取值范围。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private DataPermRuleType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/interceptor/DataFilterInterceptor.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/interceptor/DataFilterInterceptor.java new file mode 100644 index 00000000..d67112f8 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/interceptor/DataFilterInterceptor.java @@ -0,0 +1,42 @@ +package com.flow.demo.common.datafilter.interceptor; + +import com.flow.demo.common.core.object.GlobalThreadLocal; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 主要用于初始化,通过Mybatis拦截器插件进行数据过滤的标记。 + * 在调用controller接口处理方法之前,必须强制将数据过滤标记设置为缺省值。 + * 这样可以避免使用当前线程在处理上一个请求时,未能正常清理的数据过滤标记值。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class DataFilterInterceptor implements HandlerInterceptor { + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) + throws Exception { + // 每次进入Controller接口之前,均主动打开数据权限验证。 + // 可以避免该Servlet线程在处理之前的请求时异常退出,从而导致该状态数据没有被正常清除。 + GlobalThreadLocal.setDataFilter(true); + return true; + } + + @Override + public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, + ModelAndView modelAndView) throws Exception { + // 这里需要加注释,否则sonar不happy。 + } + + @Override + public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) + throws Exception { + GlobalThreadLocal.clearDataFilter(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/interceptor/MybatisDataFilterInterceptor.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/interceptor/MybatisDataFilterInterceptor.java new file mode 100644 index 00000000..dd37914d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/interceptor/MybatisDataFilterInterceptor.java @@ -0,0 +1,473 @@ +package com.flow.demo.common.datafilter.interceptor; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ReflectUtil; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.annotation.TableName; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.annotation.*; +import com.flow.demo.common.core.exception.NoDataPermException; +import com.flow.demo.common.core.object.GlobalThreadLocal; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.core.util.ApplicationContextHolder; +import com.flow.demo.common.core.util.ContextUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.RedisKeyUtil; +import com.flow.demo.common.datafilter.config.DataFilterProperties; +import com.flow.demo.common.datafilter.constant.DataPermRuleType; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.expression.operators.conditional.AndExpression; +import net.sf.jsqlparser.parser.CCJSqlParserUtil; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.delete.Delete; +import net.sf.jsqlparser.statement.select.FromItem; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SubSelect; +import net.sf.jsqlparser.statement.update.Update; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.executor.statement.RoutingStatementHandler; +import org.apache.ibatis.executor.statement.StatementHandler; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.MappedStatement; +import org.apache.ibatis.mapping.SqlCommandType; +import org.apache.ibatis.plugin.*; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Field; +import java.lang.reflect.ParameterizedType; +import java.sql.Connection; +import java.util.*; + +/** + * Mybatis拦截器。目前用于数据权限的统一拦截和注入处理。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Intercepts({@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})}) +@Slf4j +@Component +public class MybatisDataFilterInterceptor implements Interceptor { + + @Autowired + private RedissonClient redissonClient; + @Autowired + private DataFilterProperties properties; + + /** + * 对象缓存。由于Set是排序后的,因此在查找排除方法名称时效率更高。 + * 在应用服务启动的监听器中(LoadDataPermMapperListener),会调用当前对象的(loadMappersWithDataPerm)方法,加载缓存。 + */ + private final Map cachedDataPermMap = new HashMap<>(); + /** + * 租户租户对象缓存。 + */ + private final Map cachedTenantMap = new HashMap<>(); + + /** + * 预先加载与数据过滤相关的数据到缓存,该函数会在(LoadDataFilterInfoListener)监听器中调用。 + */ + @SuppressWarnings("all") + public void loadInfoWithDataFilter() { + Map mapperMap = + ApplicationContextHolder.getApplicationContext().getBeansOfType(BaseDaoMapper.class); + for (BaseDaoMapper mapperProxy : mapperMap.values()) { + // 优先处理jdk的代理 + Object proxy = ReflectUtil.getFieldValue(mapperProxy, "h"); + // 如果不是jdk的代理,再看看cjlib的代理。 + if (proxy == null) { + proxy = ReflectUtil.getFieldValue(mapperProxy, "CGLIB$CALLBACK_0"); + } + Class mapperClass = + (Class) ReflectUtil.getFieldValue(proxy, "mapperInterface"); + if (properties.getEnabledTenantFilter()) { + loadTenantFilterData(mapperClass); + } + if (properties.getEnabledDataPermFilter()) { + EnableDataPerm rule = mapperClass.getAnnotation(EnableDataPerm.class); + if (rule != null) { + loadDataPermFilterRules(mapperClass, rule); + } + } + } + } + + private void loadTenantFilterData(Class mapperClass) { + Class modelClass = (Class) ((ParameterizedType) + mapperClass.getGenericInterfaces()[0]).getActualTypeArguments()[0]; + Field[] fields = ReflectUtil.getFields(modelClass); + for (Field field : fields) { + if (field.getAnnotation(TenantFilterColumn.class) != null) { + ModelTenantInfo tenantInfo = new ModelTenantInfo(); + tenantInfo.setModelName(modelClass.getSimpleName()); + tenantInfo.setTableName(modelClass.getAnnotation(TableName.class).value()); + tenantInfo.setFieldName(field.getName()); + tenantInfo.setColumnName(MyModelUtil.mapToColumnName(field, modelClass)); + // 判断当前dao中是否包括不需要自动注入租户Id过滤的方法。 + DisableTenantFilter disableTenantFilter = + mapperClass.getAnnotation(DisableTenantFilter.class); + if (disableTenantFilter != null) { + // 这里开始获取当前Mapper已经声明的的SqlId中,有哪些是需要排除在外的。 + // 排除在外的将不进行数据过滤。 + Set excludeMethodNameSet = new HashSet<>(); + for (String excludeName : disableTenantFilter.includeMethodName()) { + excludeMethodNameSet.add(excludeName); + // 这里是给pagehelper中,分页查询先获取数据总量的查询。 + excludeMethodNameSet.add(excludeName + "_COUNT"); + } + tenantInfo.setExcludeMethodNameSet(excludeMethodNameSet); + } + cachedTenantMap.put(mapperClass.getName(), tenantInfo); + break; + } + } + } + + private void loadDataPermFilterRules(Class mapperClass, EnableDataPerm rule) { + String sysDataPermMapperName = "SysDataPermMapper"; + // 由于给数据权限Mapper添加@EnableDataPerm,将会导致无限递归,因此这里检测到之后, + // 会在系统启动加载监听器的时候,及时抛出异常。 + if (StringUtils.equals(sysDataPermMapperName, mapperClass.getSimpleName())) { + throw new IllegalStateException("Add @EnableDataPerm annotation to SysDataPermMapper is ILLEGAL!"); + } + // 这里开始获取当前Mapper已经声明的的SqlId中,有哪些是需要排除在外的。 + // 排除在外的将不进行数据过滤。 + Set excludeMethodNameSet = null; + String[] excludes = rule.excluseMethodName(); + if (excludes.length > 0) { + excludeMethodNameSet = new HashSet<>(); + for (String excludeName : excludes) { + excludeMethodNameSet.add(excludeName); + // 这里是给pagehelper中,分页查询先获取数据总量的查询。 + excludeMethodNameSet.add(excludeName + "_COUNT"); + } + } + // 获取Mapper关联的主表信息,包括表名,user过滤字段名和dept过滤字段名。 + Class modelClazz = (Class) + ((ParameterizedType) mapperClass.getGenericInterfaces()[0]).getActualTypeArguments()[0]; + Field[] fields = ReflectUtil.getFields(modelClazz); + Field userFilterField = null; + Field deptFilterField = null; + for (Field field : fields) { + if (null != field.getAnnotation(UserFilterColumn.class)) { + userFilterField = field; + } + if (null != field.getAnnotation(DeptFilterColumn.class)) { + deptFilterField = field; + } + if (userFilterField != null && deptFilterField != null) { + break; + } + } + // 通过注解解析与Mapper关联的Model,并获取与数据权限关联的信息,并将结果缓存。 + ModelDataPermInfo info = new ModelDataPermInfo(); + info.setMainTableName(MyModelUtil.mapToTableName(modelClazz)); + info.setExcludeMethodNameSet(excludeMethodNameSet); + if (userFilterField != null) { + info.setUserFilterColumn(MyModelUtil.mapToColumnName(userFilterField, modelClazz)); + } + if (deptFilterField != null) { + info.setDeptFilterColumn(MyModelUtil.mapToColumnName(deptFilterField, modelClazz)); + } + cachedDataPermMap.put(mapperClass.getName(), info); + } + + @Override + public Object intercept(Invocation invocation) throws Throwable { + // 判断当前线程本地存储中,业务操作是否禁用了数据权限过滤,如果禁用,则不进行后续的数据过滤处理了。 + if (!GlobalThreadLocal.enabledDataFilter()) { + return invocation.proceed(); + } + // 只有在HttpServletRequest场景下,该拦截器才起作用,对于系统级别的预加载数据不会应用数据权限。 + if (!ContextUtil.hasRequestContext()) { + return invocation.proceed(); + } + // 没有登录的用户,不会参与租户过滤,如果需要过滤的,自己在代码中手动实现 + // 通常对于无需登录的白名单url,也无需过滤了。 + // 另外就是登录接口中,获取菜单列表的接口,由于尚未登录,没有TokenData,所以这个接口我们手动加入了该条件。 + if (TokenData.takeFromRequest() == null) { + return invocation.proceed(); + } + RoutingStatementHandler handler = (RoutingStatementHandler) invocation.getTarget(); + StatementHandler delegate = + (StatementHandler) ReflectUtil.getFieldValue(handler, "delegate"); + // 通过反射获取delegate父类BaseStatementHandler的mappedStatement属性 + MappedStatement mappedStatement = + (MappedStatement) ReflectUtil.getFieldValue(delegate, "mappedStatement"); + SqlCommandType commandType = mappedStatement.getSqlCommandType(); + // 对于INSERT语句,我们不进行任何数据过滤。 + if (commandType == SqlCommandType.INSERT) { + return invocation.proceed(); + } + String sqlId = mappedStatement.getId(); + int pos = StringUtils.lastIndexOf(sqlId, "."); + String className = StringUtils.substring(sqlId, 0, pos); + String methodName = StringUtils.substring(sqlId, pos + 1); + // 先进行租户过滤条件的处理,再将解析并处理后的SQL Statement交给下一步的数据权限过滤去处理。 + // 这样做的目的主要是为了减少一次SQL解析的过程,因为这是高频操作,所以要尽量去优化。 + Statement statement = null; + if (properties.getEnabledTenantFilter()) { + statement = this.processTenantFilter(className, methodName, delegate.getBoundSql(), commandType); + } + // 处理数据权限过滤。 + if (properties.getEnabledDataPermFilter()) { + this.processDataPermFilter(className, methodName, delegate.getBoundSql(), commandType, statement, sqlId); + } + return invocation.proceed(); + } + + private Statement processTenantFilter( + String className, String methodName, BoundSql boundSql, SqlCommandType commandType) throws JSQLParserException { + ModelTenantInfo info = cachedTenantMap.get(className); + if (info == null || CollUtil.contains(info.getExcludeMethodNameSet(), methodName)) { + return null; + } + String sql = boundSql.getSql(); + Statement statement = CCJSqlParserUtil.parse(sql); + StringBuilder filterBuilder = new StringBuilder(64); + filterBuilder.append(info.tableName).append(".") + .append(info.columnName) + .append("=") + .append(TokenData.takeFromRequest().getTenantId()); + String dataFilter = filterBuilder.toString(); + if (commandType == SqlCommandType.UPDATE) { + Update update = (Update) statement; + this.buildWhereClause(update, dataFilter); + } else if (commandType == SqlCommandType.DELETE) { + Delete delete = (Delete) statement; + this.buildWhereClause(delete, dataFilter); + } else { + Select select = (Select) statement; + PlainSelect selectBody = (PlainSelect) select.getSelectBody(); + FromItem fromItem = selectBody.getFromItem(); + if (fromItem != null) { + PlainSelect subSelect = null; + if (fromItem instanceof SubSelect) { + subSelect = (PlainSelect) ((SubSelect) fromItem).getSelectBody(); + } + if (subSelect != null) { + buildWhereClause(subSelect, dataFilter); + } else { + buildWhereClause(selectBody, dataFilter); + } + } + } + ReflectUtil.setFieldValue(boundSql, "sql", statement.toString()); + return statement; + } + + private void processDataPermFilter( + String className, String methodName, BoundSql boundSql, SqlCommandType commandType, Statement statement, String sqlId) + throws JSQLParserException { + // 判断当前线程本地存储中,业务操作是否禁用了数据权限过滤,如果禁用,则不进行后续的数据过滤处理了。 + // 数据过滤权限中,INSERT不过滤。如果是管理员则不参与数据权限的数据过滤,显示全部数据。 + TokenData tokenData = TokenData.takeFromRequest(); + if (Boolean.TRUE.equals(tokenData.getIsAdmin())) { + return; + } + ModelDataPermInfo info = cachedDataPermMap.get(className); + // 再次查找当前方法是否为排除方法,如果不是,就参与数据权限注入过滤。 + if (info == null || CollUtil.contains(info.getExcludeMethodNameSet(), methodName)) { + return; + } + String dataPermSessionKey = RedisKeyUtil.makeSessionDataPermIdKey(tokenData.getSessionId()); + String dataPermData = redissonClient.getBucket(dataPermSessionKey).get().toString(); + if (StringUtils.isBlank(dataPermData)) { + throw new NoDataPermException( + "No Related DataPerm found for SQL_ID [ " + sqlId + " ]."); + } + Map dataPermMap = new HashMap<>(8); + for (Map.Entry entry : JSON.parseObject(dataPermData).entrySet()) { + dataPermMap.put(Integer.valueOf(entry.getKey()), entry.getValue().toString()); + } + if (MapUtils.isEmpty(dataPermMap)) { + throw new NoDataPermException( + "No Related DataPerm found for SQL_ID [ " + sqlId + " ]."); + } + if (dataPermMap.containsKey(DataPermRuleType.TYPE_ALL)) { + return; + } + this.processDataPerm(info, dataPermMap, boundSql, commandType, statement); + } + + private void processDataPerm( + ModelDataPermInfo info, + Map dataPermMap, + BoundSql boundSql, + SqlCommandType commandType, + Statement statement) throws JSQLParserException { + List criteriaList = new LinkedList<>(); + for (Map.Entry entry : dataPermMap.entrySet()) { + String filterClause = processDataPermRule(info, entry.getKey(), entry.getValue()); + if (StringUtils.isNotBlank(filterClause)) { + criteriaList.add(filterClause); + } + } + if (CollectionUtils.isEmpty(criteriaList)) { + return; + } + StringBuilder filterBuilder = new StringBuilder(128); + filterBuilder.append("("); + filterBuilder.append(StringUtils.join(criteriaList, " OR ")); + filterBuilder.append(")"); + String dataFilter = filterBuilder.toString(); + if (statement == null) { + String sql = boundSql.getSql(); + statement = CCJSqlParserUtil.parse(sql); + } + if (commandType == SqlCommandType.UPDATE) { + Update update = (Update) statement; + this.buildWhereClause(update, dataFilter); + } else if (commandType == SqlCommandType.DELETE) { + Delete delete = (Delete) statement; + this.buildWhereClause(delete, dataFilter); + } else { + Select select = (Select) statement; + PlainSelect selectBody = (PlainSelect) select.getSelectBody(); + FromItem fromItem = selectBody.getFromItem(); + PlainSelect subSelect = null; + if (fromItem != null) { + if (fromItem instanceof SubSelect) { + subSelect = (PlainSelect) ((SubSelect) fromItem).getSelectBody(); + } + if (subSelect != null) { + buildWhereClause(subSelect, dataFilter); + } else { + buildWhereClause(selectBody, dataFilter); + } + } + } + ReflectUtil.setFieldValue(boundSql, "sql", statement.toString()); + } + + private String processDataPermRule(ModelDataPermInfo info, Integer ruleType, String deptIds) { + TokenData tokenData = TokenData.takeFromRequest(); + StringBuilder filter = new StringBuilder(128); + if (ruleType == DataPermRuleType.TYPE_USER_ONLY) { + if (StringUtils.isNotBlank(info.getUserFilterColumn())) { + if (properties.getAddTableNamePrefix()) { + filter.append(info.getMainTableName()).append("."); + } + filter.append(info.getUserFilterColumn()) + .append(" = ") + .append(tokenData.getUserId()); + } + } else { + if (StringUtils.isNotBlank(info.getDeptFilterColumn())) { + if (ruleType == DataPermRuleType.TYPE_DEPT_ONLY) { + if (properties.getAddTableNamePrefix()) { + filter.append(info.getMainTableName()).append("."); + } + filter.append(info.getDeptFilterColumn()) + .append(" = ") + .append(tokenData.getDeptId()); + } else if (ruleType == DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT) { + filter.append(" EXISTS ") + .append("(SELECT 1 FROM ") + .append(properties.getDeptRelationTablePrefix()) + .append("sys_dept_relation WHERE ") + .append(properties.getDeptRelationTablePrefix()) + .append("sys_dept_relation.parent_dept_id = ") + .append(tokenData.getDeptId()) + .append(" AND "); + if (properties.getAddTableNamePrefix()) { + filter.append(info.getMainTableName()).append("."); + } + filter.append(info.getDeptFilterColumn()) + .append(" = ") + .append(properties.getDeptRelationTablePrefix()) + .append("sys_dept_relation.dept_id) "); + } else if (ruleType == DataPermRuleType.TYPE_MULTI_DEPT_AND_CHILD_DEPT) { + filter.append(" EXISTS ") + .append("(SELECT 1 FROM ") + .append(properties.getDeptRelationTablePrefix()) + .append("sys_dept_relation WHERE ") + .append(properties.getDeptRelationTablePrefix()) + .append("sys_dept_relation.parent_dept_id IN (") + .append(deptIds) + .append(") AND "); + if (properties.getAddTableNamePrefix()) { + filter.append(info.getMainTableName()).append("."); + } + filter.append(info.getDeptFilterColumn()) + .append(" = ") + .append(properties.getDeptRelationTablePrefix()) + .append("sys_dept_relation.dept_id) "); + } else if (ruleType == DataPermRuleType.TYPE_CUSTOM_DEPT_LIST) { + if (properties.getAddTableNamePrefix()) { + filter.append(info.getMainTableName()).append("."); + } + filter.append(info.getDeptFilterColumn()) + .append(" IN (") + .append(deptIds) + .append(") "); + } + } + } + return filter.toString(); + } + + private void buildWhereClause(Update update, String dataFilter) throws JSQLParserException { + if (update.getWhere() == null) { + update.setWhere(CCJSqlParserUtil.parseCondExpression(dataFilter)); + } else { + AndExpression and = new AndExpression( + CCJSqlParserUtil.parseCondExpression(dataFilter), update.getWhere()); + update.setWhere(and); + } + } + + private void buildWhereClause(Delete delete, String dataFilter) throws JSQLParserException { + if (delete.getWhere() == null) { + delete.setWhere(CCJSqlParserUtil.parseCondExpression(dataFilter)); + } else { + AndExpression and = new AndExpression( + CCJSqlParserUtil.parseCondExpression(dataFilter), delete.getWhere()); + delete.setWhere(and); + } + } + + private void buildWhereClause(PlainSelect select, String dataFilter) throws JSQLParserException { + if (select.getWhere() == null) { + select.setWhere(CCJSqlParserUtil.parseCondExpression(dataFilter)); + } else { + AndExpression and = new AndExpression( + CCJSqlParserUtil.parseCondExpression(dataFilter), select.getWhere()); + select.setWhere(and); + } + } + + @Override + public Object plugin(Object target) { + return Plugin.wrap(target, this); + } + + @Override + public void setProperties(Properties properties) { + // 这里需要空注解,否则sonar会不happy。 + } + + @Data + private static final class ModelDataPermInfo { + private Set excludeMethodNameSet; + private String userFilterColumn; + private String deptFilterColumn; + private String mainTableName; + } + + @Data + private static final class ModelTenantInfo { + private Set excludeMethodNameSet; + private String modelName; + private String tableName; + private String fieldName; + private String columnName; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/listener/LoadDataFilterInfoListener.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/listener/LoadDataFilterInfoListener.java new file mode 100644 index 00000000..ebfeb13c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/java/com/flow/demo/common/datafilter/listener/LoadDataFilterInfoListener.java @@ -0,0 +1,25 @@ +package com.flow.demo.common.datafilter.listener; + +import com.flow.demo.common.datafilter.interceptor.MybatisDataFilterInterceptor; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +/** + * 应用服务启动监听器。 + * 目前主要功能是调用MybatisDataFilterInterceptor中的loadInfoWithDataFilter方法, + * 将标记有过滤注解的数据加载到缓存,以提升系统运行时效率。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Component +public class LoadDataFilterInfoListener implements ApplicationListener { + + @Override + public void onApplicationEvent(ApplicationReadyEvent applicationReadyEvent) { + MybatisDataFilterInterceptor interceptor = + applicationReadyEvent.getApplicationContext().getBean(MybatisDataFilterInterceptor.class); + interceptor.loadInfoWithDataFilter(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/resources/META-INF/spring.factories b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..d60d87d2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-datafilter/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.flow.demo.common.datafilter.config.DataFilterAutoConfig \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/pom.xml new file mode 100644 index 00000000..e103d8ba --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/pom.xml @@ -0,0 +1,48 @@ + + + + common + com.flow.demo + 1.0.0 + + 4.0.0 + + common-flow-online + 1.0.0 + common-flow-online + jar + + + + com.flow.demo + common-flow + 1.0.0 + + + com.flow.demo + common-online + 1.0.0 + + + + + + + src/main/resources + + **/*.* + + false + + + src/main/java + + **/*.xml + + false + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/config/FlowOnlineAutoConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/config/FlowOnlineAutoConfig.java new file mode 100644 index 00000000..4b398c02 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/config/FlowOnlineAutoConfig.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.flow.online.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +/** + * common-flow-online模块的自动配置引导类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EnableConfigurationProperties({FlowOnlineProperties.class}) +public class FlowOnlineAutoConfig { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/config/FlowOnlineProperties.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/config/FlowOnlineProperties.java new file mode 100644 index 00000000..2748f2ba --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/config/FlowOnlineProperties.java @@ -0,0 +1,20 @@ +package com.flow.demo.common.flow.online.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 在线表单工作流模块的配置对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ConfigurationProperties(prefix = "common-flow-online") +public class FlowOnlineProperties { + + /** + * 在线表单的URL前缀。 + */ + private String urlPrefix; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/controller/FlowOnlineOperationController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/controller/FlowOnlineOperationController.java new file mode 100644 index 00000000..830a90f1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/controller/FlowOnlineOperationController.java @@ -0,0 +1,698 @@ +package com.flow.demo.common.flow.online.controller; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.page.PageMethod; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.flow.dto.FlowWorkOrderDto; +import com.flow.demo.common.flow.vo.FlowEntryVo; +import com.flow.demo.common.flow.vo.FlowWorkOrderVo; +import com.flow.demo.common.online.dto.OnlineFilterDto; +import com.flow.demo.common.online.model.*; +import com.flow.demo.common.online.model.constant.FieldFilterType; +import com.flow.demo.common.online.model.constant.RelationType; +import com.flow.demo.common.online.object.ColumnData; +import com.flow.demo.common.online.service.OnlineFormService; +import com.flow.demo.common.online.service.OnlinePageService; +import com.flow.demo.common.online.service.OnlineOperationService; +import com.flow.demo.common.online.service.OnlineTableService; +import com.flow.demo.common.online.util.OnlineOperationHelper; +import com.flow.demo.common.flow.online.service.FlowOnlineOperationService; +import com.flow.demo.common.flow.constant.FlowApprovalType; +import com.flow.demo.common.flow.util.FlowOperationHelper; +import com.flow.demo.common.flow.constant.FlowTaskStatus; +import com.flow.demo.common.flow.dto.FlowTaskCommentDto; +import com.flow.demo.common.flow.exception.FlowOperationException; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.flow.vo.TaskInfoVo; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 流程操作接口类 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-flow.urlPrefix}/flowOnlineOperation") +public class FlowOnlineOperationController { + + @Autowired + private FlowEntryService flowEntryService; + @Autowired + private FlowApiService flowApiService; + @Autowired + private FlowOperationHelper flowOperationHelper; + @Autowired + private FlowOnlineOperationService flowOnlineOperationService; + @Autowired + private FlowWorkOrderService flowWorkOrderService; + @Autowired + private OnlineFormService onlineFormService; + @Autowired + private OnlinePageService onlinePageService; + @Autowired + private OnlineOperationService onlineOperationService; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private OnlineOperationHelper onlineOperationHelper; + + /** + * 根据指定流程的主版本,发起一个流程实例,同时作为第一个任务节点的执行人,执行第一个用户任务。 + * + * @param processDefinitionKey 流程定义标识。 + * @param flowTaskCommentDto 审批意见。 + * @param taskVariableData 流程任务变量数据。 + * @param masterData 流程审批相关的主表数据。 + * @param slaveData 流程审批相关的多个从表数据。 + * @return 应答结果对象。 + */ + @PostMapping("/startAndTakeUserTask/{processDefinitionKey}") + public ResponseResult startAndTakeUserTask( + @PathVariable("processDefinitionKey") String processDefinitionKey, + @MyRequestBody(required = true) FlowTaskCommentDto flowTaskCommentDto, + @MyRequestBody JSONObject taskVariableData, + @MyRequestBody(required = true) JSONObject masterData, + @MyRequestBody JSONObject slaveData) { + String errorMessage; + // 1. 验证流程数据的合法性。 + ResponseResult flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey); + if (!flowEntryResult.isSuccess()) { + return ResponseResult.errorFrom(flowEntryResult); + } + // 2. 验证流程一个用户任务的合法性。 + FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish(); + if (!flowEntryPublish.getActiveStatus()) { + errorMessage = "数据验证失败,当前流程发布对象已被挂起,不能启动新流程!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + ResponseResult taskInfoResult = + flowOperationHelper.verifyAndGetInitialTaskInfo(flowEntryPublish, true); + if (!taskInfoResult.isSuccess()) { + return ResponseResult.errorFrom(taskInfoResult); + } + TaskInfoVo taskInfo = taskInfoResult.getData(); + // 3. 验证在线表单及其关联数据源的合法性。 + ResponseResult datasourceResult = this.verifyAndGetOnlineDatasource(taskInfo.getFormId()); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + OnlineDatasource datasource = datasourceResult.getData(); + OnlineTable masterTable = datasource.getMasterTable(); + // 4. 为本次流程操作构建数据。 + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(masterTable, masterData, false, null); + if (!columnDataListResult.isSuccess()) { + return ResponseResult.errorFrom(columnDataListResult); + } + FlowTaskComment flowTaskComment = BeanUtil.copyProperties(flowTaskCommentDto, FlowTaskComment.class); + // 5. 保存在线表单提交的数据,同时启动流程和自动完成第一个用户任务。 + if (slaveData == null) { + flowOnlineOperationService.saveNewAndStartProcess( + flowEntryPublish.getProcessDefinitionId(), + flowTaskComment, + taskVariableData, + masterTable, + columnDataListResult.getData()); + } else { + // 如果本次请求中包含从表数据,则一同插入。 + ResponseResult>>> slaveDataListResult = + onlineOperationHelper.buildSlaveDataList(datasource.getDatasourceId(), slaveData); + if (!slaveDataListResult.isSuccess()) { + return ResponseResult.errorFrom(slaveDataListResult); + } + flowOnlineOperationService.saveNewAndStartProcess( + flowEntryPublish.getProcessDefinitionId(), + flowTaskComment, + taskVariableData, + masterTable, + columnDataListResult.getData(), + slaveDataListResult.getData()); + } + return ResponseResult.success(); + } + + /** + * 提交流程的用户任务。 + * + * @param processInstanceId 流程实例Id。 + * @param taskId 流程任务Id。 + * @param flowTaskCommentDto 流程审批数据。 + * @param taskVariableData 流程任务变量数据。 + * @param masterData 流程审批相关的主表数据。 + * @param slaveData 流程审批相关的多个从表数据。 + * @return 应答结果对象。 + */ + @PostMapping("/submitUserTask") + public ResponseResult submitUserTask( + @MyRequestBody(required = true) String processInstanceId, + @MyRequestBody(required = true) String taskId, + @MyRequestBody(required = true) FlowTaskCommentDto flowTaskCommentDto, + @MyRequestBody JSONObject taskVariableData, + @MyRequestBody JSONObject masterData, + @MyRequestBody JSONObject slaveData) { + String errorMessage; + // 验证流程任务的合法性。 + Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId); + ResponseResult taskInfoResult = flowOperationHelper.verifyAndGetRuntimeTaskInfo(task); + if (!taskInfoResult.isSuccess()) { + return ResponseResult.errorFrom(taskInfoResult); + } + TaskInfoVo taskInfo = taskInfoResult.getData(); + // 验证在线表单及其关联数据源的合法性。 + ResponseResult datasourceResult = this.verifyAndGetOnlineDatasource(taskInfo.getFormId()); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + CallResult assigneeVerifyResult = flowApiService.verifyAssigneeOrCandidateAndClaim(task); + if (!assigneeVerifyResult.isSuccess()) { + return ResponseResult.errorFrom(assigneeVerifyResult); + } + OnlineDatasource datasource = datasourceResult.getData(); + OnlineTable masterTable = datasource.getMasterTable(); + Long datasourceId = datasource.getDatasourceId(); + ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId); + String dataId = instance.getBusinessKey(); + FlowTaskComment flowTaskComment = BeanUtil.copyProperties(flowTaskCommentDto, FlowTaskComment.class); + if (StrUtil.isBlank(dataId)) { + return this.submitNewTask(processInstanceId, taskId, + flowTaskComment, taskVariableData, masterTable, masterData, slaveData, datasourceId); + } + try { + if (StrUtil.equals(flowTaskComment.getApprovalType(), FlowApprovalType.TRANSFER)) { + if (StrUtil.isBlank(flowTaskComment.getDelegateAssginee())) { + errorMessage = "数据验证失败,加签或转办任务指派人不能为空!!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + flowOnlineOperationService.updateAndTakeTask( + task, flowTaskComment, taskVariableData, masterTable, masterData, dataId, slaveData, datasourceId); + } catch (FlowOperationException e) { + log.error("Failed to call [FlowOnlineOperationService.updateAndTakeTask]", e); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, e.getMessage()); + } + return ResponseResult.success(); + } + + /** + * 获取当前流程实例的详情数据。包括主表数据、一对一从表数据、一对多从表数据列表等。 + * + * @param processInstanceId 当前运行时的流程实例Id。 + * @param taskId 流程任务Id。 + * @return 当前流程实例的详情数据。 + */ + @GetMapping("/viewUserTask") + public ResponseResult viewUserTask(@RequestParam String processInstanceId, @RequestParam String taskId) { + String errorMessage; + // 验证流程任务的合法性。 + Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId); + ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId); + // 如果业务主数据为空,则直接返回。 + if (StrUtil.isBlank(instance.getBusinessKey())) { + return ResponseResult.success(null); + } + ResponseResult taskInfoResult = flowOperationHelper.verifyAndGetRuntimeTaskInfo(task); + if (!taskInfoResult.isSuccess()) { + return ResponseResult.errorFrom(taskInfoResult); + } + TaskInfoVo taskInfo = taskInfoResult.getData(); + // 验证在线表单及其关联数据源的合法性。 + ResponseResult datasourceResult = this.verifyAndGetOnlineDatasource(taskInfo.getFormId()); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + OnlineDatasource datasource = datasourceResult.getData(); + ResponseResult> relationListResult = + onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null); + if (!relationListResult.isSuccess()) { + return ResponseResult.errorFrom(relationListResult); + } + JSONObject jsonData = this.buildUserTaskData( + instance.getBusinessKey(), datasource.getMasterTable(), relationListResult.getData()); + return ResponseResult.success(jsonData); + } + + /** + * 获取已经结束的流程实例的详情数据。包括主表数据、一对一从表数据、一对多从表数据列表等。 + * + * @param processInstanceId 历史流程实例Id。 + * @param taskId 历史任务Id。如果该值为null,仅有发起人可以查看当前流程数据,否则只有任务的指派人才能查看。 + * @return 历史流程实例的详情数据。 + */ + @GetMapping("/viewHistoricProcessInstance") + public ResponseResult viewHistoricProcessInstance( + @RequestParam String processInstanceId, @RequestParam(required = false) String taskId) { + String errorMessage; + // 验证流程实例的合法性。 + HistoricProcessInstance instance = flowApiService.getHistoricProcessInstance(processInstanceId); + if (instance == null) { + errorMessage = "数据验证失败,指定的流程实例Id并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + String loginName = TokenData.takeFromRequest().getLoginName(); + if (StrUtil.isBlank(taskId)) { + if (!StrUtil.equals(loginName, instance.getStartUserId())) { + errorMessage = "数据验证失败,指定历史流程的发起人与当前用户不匹配!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } else { + HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId); + if (taskInstance == null) { + errorMessage = "数据验证失败,指定的任务Id并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!StrUtil.equals(loginName, taskInstance.getAssignee())) { + errorMessage = "数据验证失败,历史任务的指派人与当前用户不匹配!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + if (StrUtil.isBlank(instance.getBusinessKey())) { + // 对于没有提交过任何用户任务的场景,可直接返回空数据。 + return ResponseResult.success(new JSONObject()); + } + FlowEntryPublish flowEntryPublish = + flowEntryService.getFlowEntryPublishList(CollUtil.newHashSet(instance.getProcessDefinitionId())).get(0); + TaskInfoVo taskInfoVo = JSON.parseObject(flowEntryPublish.getInitTaskInfo(), TaskInfoVo.class); + // 验证在线表单及其关联数据源的合法性。 + ResponseResult datasourceResult = this.verifyAndGetOnlineDatasource(taskInfoVo.getFormId()); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + OnlineDatasource datasource = datasourceResult.getData(); + ResponseResult> relationListResult = + onlineOperationHelper.verifyAndGetRelationList(datasource.getDatasourceId(), null); + if (!relationListResult.isSuccess()) { + return ResponseResult.errorFrom(relationListResult); + } + JSONObject jsonData = this.buildUserTaskData( + instance.getBusinessKey(), datasource.getMasterTable(), relationListResult.getData()); + return ResponseResult.success(jsonData); + } + + /** + * 工作流工单列表。 + * + * @param processDefinitionKey 流程标识名。 + * @param flowWorkOrderDtoFilter 过滤对象。 + * @param pageParam 分页参数。 + * @return 查询结果。 + */ + @PostMapping("/listWorkOrder/{processDefinitionKey}") + public ResponseResult> listWorkOrder( + @PathVariable("processDefinitionKey") String processDefinitionKey, + @MyRequestBody FlowWorkOrderDto flowWorkOrderDtoFilter, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + FlowWorkOrder flowWorkOrderFilter = + flowOperationHelper.makeWorkOrderFilter(flowWorkOrderDtoFilter, processDefinitionKey); + MyOrderParam orderParam = new MyOrderParam(); + orderParam.add(new MyOrderParam.OrderInfo("workOrderId", false, null)); + String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowWorkOrder.class); + List flowWorkOrderList = flowWorkOrderService.getFlowWorkOrderList(flowWorkOrderFilter, orderBy); + MyPageData resultData = + MyPageUtil.makeResponseData(flowWorkOrderList, FlowWorkOrder.INSTANCE); + this.makeWorkOrderTaskInfo(resultData.getDataList()); + return ResponseResult.success(resultData); + } + + /** + * 为数据源主表字段上传文件。 + * + * @param processDefinitionKey 流程引擎流程定义标识。 + * @param processInstanceId 流程实例Id。 + * @param taskId 流程任务Id。 + * @param datasourceId 数据源Id。 + * @param relationId 数据源关联Id。 + * @param fieldName 数据表字段名。 + * @param asImage 是否为图片文件。 + * @param uploadFile 上传文件对象。 + */ + @PostMapping("/upload") + public void upload( + @RequestParam String processDefinitionKey, + @RequestParam(required = false) String processInstanceId, + @RequestParam(required = false) String taskId, + @RequestParam Long datasourceId, + @RequestParam(required = false) Long relationId, + @RequestParam String fieldName, + @RequestParam Boolean asImage, + @RequestParam("uploadFile") MultipartFile uploadFile) throws Exception { + ResponseResult verifyResult = + this.verifyUploadOrDownload(processDefinitionKey, processInstanceId, taskId, datasourceId); + if (!verifyResult.isSuccess()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.errorFrom(verifyResult)); + return; + } + ResponseResult verifyTableResult = + this.verifyAndGetOnlineTable(datasourceId, relationId, null, null); + if (!verifyTableResult.isSuccess()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.errorFrom(verifyTableResult)); + return; + } + onlineOperationHelper.doUpload(verifyTableResult.getData(), fieldName, asImage, uploadFile); + } + + /** + * 下载文件接口。 + * 越权访问限制说明: + * taskId为空,当前用户必须为当前流程的发起人,否则必须为当前任务的指派人或候选人。 + * relationId为空,下载数据为主表字段,否则为关联的从表字段。 + * + * @param processDefinitionKey 流程引擎流程定义标识。 + * @param processInstanceId 流程实例Id。 + * @param taskId 流程任务Id。 + * @param datasourceId 数据源Id。 + * @param relationId 数据源关联Id。 + * @param dataId 附件所在记录的主键Id。 + * @param fieldName 数据表字段名。 + * @param asImage 是否为图片文件。 + * @param response Http 应答对象。 + */ + @GetMapping("/download") + public void download( + @RequestParam String processDefinitionKey, + @RequestParam(required = false) String processInstanceId, + @RequestParam(required = false) String taskId, + @RequestParam Long datasourceId, + @RequestParam(required = false) Long relationId, + @RequestParam(required = false) String dataId, + @RequestParam String fieldName, + @RequestParam String filename, + @RequestParam Boolean asImage, + HttpServletResponse response) throws Exception { + ResponseResult verifyResult = + this.verifyUploadOrDownload(processDefinitionKey, processInstanceId, taskId, datasourceId); + if (!verifyResult.isSuccess()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.errorFrom(verifyResult)); + return; + } + ResponseResult verifyTableResult = + this.verifyAndGetOnlineTable(datasourceId, relationId, verifyResult.getData(), dataId); + if (!verifyTableResult.isSuccess()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.errorFrom(verifyTableResult)); + return; + } + onlineOperationHelper.doDownload(verifyTableResult.getData(), dataId, fieldName, filename, asImage, response); + } + + /** + * 获取所有流程对象,同时获取关联的在线表单对象列表。 + * + * @return 查询结果。 + */ + @GetMapping("/listFlowEntryForm") + public ResponseResult> listFlowEntryForm() { + List flowEntryList = flowEntryService.getAllList(); + List flowEntryVoList = FlowEntry.INSTANCE.fromModelList(flowEntryList); + if (CollUtil.isNotEmpty(flowEntryVoList)) { + Set pageIdSet = flowEntryVoList.stream().map(FlowEntryVo::getPageId).collect(Collectors.toSet()); + List formList = onlineFormService.getOnlineFormListByPageIds(pageIdSet); + Map> formMap = + formList.stream().collect(Collectors.groupingBy(OnlineForm::getPageId)); + for (FlowEntryVo flowEntryVo : flowEntryVoList) { + List flowEntryFormList = formMap.get(flowEntryVo.getPageId()); + flowEntryVo.setFormList(MyModelUtil.beanToMapList(flowEntryFormList)); + } + } + return ResponseResult.success(flowEntryVoList); + } + + private ResponseResult verifyAndGetOnlineDatasource(Long formId) { + List formDatasourceList = onlineFormService.getFormDatasourceListByFormId(formId); + if (CollUtil.isEmpty(formDatasourceList)) { + String errorMessage = "数据验证失败,流程任务绑定的在线表单Id [" + formId + "] 不存在,请修改流程图!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + return onlineOperationHelper.verifyAndGetDatasource(formDatasourceList.get(0).getDatasourceId()); + } + + private JSONObject buildUserTaskData( + String businessKey, OnlineTable masterTable, List relationList) { + JSONObject jsonData = new JSONObject(); + List oneToOneRelationList = relationList.stream() + .filter(r -> r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList()); + Map result = + onlineOperationService.getMasterData(masterTable, oneToOneRelationList, relationList, businessKey); + if (MapUtil.isEmpty(result)) { + return jsonData; + } + jsonData.put("masterAndOneToOne", result); + List oneToManyRelationList = relationList.stream() + .filter(r -> r.getRelationType().equals(RelationType.ONE_TO_MANY)).collect(Collectors.toList()); + if (CollUtil.isEmpty(oneToManyRelationList)) { + return jsonData; + } + JSONObject oneToManyJsonData = new JSONObject(); + jsonData.put("oneToMany", oneToManyJsonData); + for (OnlineDatasourceRelation relation : oneToManyRelationList) { + OnlineFilterDto filterDto = new OnlineFilterDto(); + filterDto.setTableName(relation.getSlaveTable().getTableName()); + OnlineColumn slaveColumn = relation.getSlaveTable().getColumnMap().get(relation.getSlaveColumnId()); + filterDto.setColumnName(slaveColumn.getColumnName()); + filterDto.setFilterType(FieldFilterType.EQUAL_FILTER); + Object columnValue = result.get(masterTable.getPrimaryKeyColumn().getColumnName()); + filterDto.setColumnValue(columnValue); + List> slaveResultList = + onlineOperationService.getSlaveDataList(relation, CollUtil.newLinkedList(filterDto), null); + if (CollUtil.isNotEmpty(slaveResultList)) { + oneToManyJsonData.put(relation.getVariableName(), slaveResultList); + } + } + return jsonData; + } + + private ResponseResult submitNewTask( + String processInstanceId, + String taskId, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable masterTable, + JSONObject masterData, + JSONObject slaveData, + Long datasourceId) { + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(masterTable, masterData, false, null); + if (!columnDataListResult.isSuccess()) { + return ResponseResult.errorFrom(columnDataListResult); + } + // 保存在线表单提交的数据,同时启动流程和自动完成第一个用户任务。 + if (slaveData == null) { + flowOnlineOperationService.saveNewAndTakeTask( + processInstanceId, + taskId, + flowTaskComment, + taskVariableData, + masterTable, + columnDataListResult.getData()); + } else { + // 如果本次请求中包含从表数据,则一同插入。 + ResponseResult>>> slaveDataListResult = + onlineOperationHelper.buildSlaveDataList(datasourceId, slaveData); + if (!slaveDataListResult.isSuccess()) { + return ResponseResult.errorFrom(slaveDataListResult); + } + flowOnlineOperationService.saveNewAndTakeTask( + processInstanceId, + taskId, + flowTaskComment, + taskVariableData, + masterTable, + columnDataListResult.getData(), + slaveDataListResult.getData()); + } + return ResponseResult.success(); + } + + private ResponseResult verifyAndGetOnlineTable( + Long datasourceId, Long relationId, String businessKey, String dataId) { + ResponseResult datasourceResult = + onlineOperationHelper.verifyAndGetDatasource(datasourceId); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + OnlineTable masterTable = datasourceResult.getData().getMasterTable(); + OnlineTable table = masterTable; + ResponseResult relationResult = null; + if (relationId != null) { + relationResult = onlineOperationHelper.verifyAndGetRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + return ResponseResult.errorFrom(relationResult); + } + table = relationResult.getData().getSlaveTable(); + } + if (StrUtil.hasBlank(businessKey, dataId)) { + return ResponseResult.success(table); + } + String errorMessage; + // 如果relationId为null,这里就是主表数据。 + if (relationId == null) { + if (!StrUtil.equals(businessKey, dataId)) { + errorMessage = "数据验证失败,参数主键Id与流程主表主键Id不匹配!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + return ResponseResult.success(table); + } + OnlineDatasourceRelation relation = relationResult.getData(); + OnlineTable slaveTable = relation.getSlaveTable(); + Map dataMap = + onlineOperationService.getMasterData(slaveTable, null, null, dataId); + if (dataMap == null) { + errorMessage = "数据验证失败,从表主键Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineColumn slaveColumn = slaveTable.getColumnMap().get(relation.getSlaveColumnId()); + Object relationSlaveDataId = dataMap.get(slaveColumn.getColumnName()); + if (relationSlaveDataId == null) { + errorMessage = "数据验证失败,当前关联的从表字段值为NULL!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineColumn masterColumn = masterTable.getColumnMap().get(relation.getMasterColumnId()); + if (masterColumn.getPrimaryKey()) { + if (!StrUtil.equals(relationSlaveDataId.toString(), businessKey)) { + errorMessage = "数据验证失败,当前从表主键Id关联的主表Id当前流程的BusinessKey不一致!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + Map masterDataMap = + onlineOperationService.getMasterData(masterTable, null, null, businessKey); + if (masterDataMap == null) { + errorMessage = "数据验证失败,主表主键Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + Object relationMasterDataId = masterDataMap.get(masterColumn.getColumnName()); + if (relationMasterDataId == null) { + errorMessage = "数据验证失败,当前关联的主表字段值为NULL!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!StrUtil.equals(relationMasterDataId.toString(), relationSlaveDataId.toString())) { + errorMessage = "数据验证失败,当前关联的主表字段值和从表字段值不一致!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + return ResponseResult.success(table); + } + + private ResponseResult verifyUploadOrDownload( + String processDefinitionKey, String processInstanceId, String taskId, Long datasourceId) { + if (!StrUtil.isAllBlank(processInstanceId, taskId)) { + ResponseResult verifyResult = + flowOperationHelper.verifyUploadOrDownloadPermission(processInstanceId, taskId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(ResponseResult.errorFrom(verifyResult)); + } + } + String errorMessage; + FlowEntry flowEntry = flowEntryService.getFlowEntryByProcessDefinitionKey(processDefinitionKey); + if (flowEntry == null) { + errorMessage = "数据验证失败,指定流程Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + String businessKey = null; + if (processInstanceId != null) { + HistoricProcessInstance instance = flowApiService.getHistoricProcessInstance(processInstanceId); + if (!StrUtil.equals(flowEntry.getProcessDefinitionKey(), instance.getProcessDefinitionKey())) { + errorMessage = "数据验证失败,指定流程实例并不属于当前流程!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + businessKey = instance.getBusinessKey(); + } + List datasourceList = + onlinePageService.getOnlinePageDatasourceListByPageId(flowEntry.getPageId()); + Optional r = datasourceList.stream() + .map(OnlinePageDatasource::getDatasourceId).filter(c -> c.equals(datasourceId)).findFirst(); + if (!r.isPresent()) { + errorMessage = "数据验证失败,当前数据源Id并不属于当前流程!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + return ResponseResult.success(businessKey); + } + + private void makeWorkOrderTaskInfo(List flowWorkOrderVoList) { + if (CollUtil.isEmpty(flowWorkOrderVoList)) { + return; + } + Set definitionIdSet = + flowWorkOrderVoList.stream().map(FlowWorkOrderVo::getProcessDefinitionId).collect(Collectors.toSet()); + List flowEntryPublishList = flowEntryService.getFlowEntryPublishList(definitionIdSet); + Map flowEntryPublishMap = + flowEntryPublishList.stream().collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c)); + for (FlowWorkOrderVo flowWorkOrderVo : flowWorkOrderVoList) { + FlowEntryPublish flowEntryPublish = flowEntryPublishMap.get(flowWorkOrderVo.getProcessDefinitionId()); + flowWorkOrderVo.setInitTaskInfo(flowEntryPublish.getInitTaskInfo()); + } + Set businessKeySet = + flowWorkOrderVoList.stream().map(FlowWorkOrderVo::getBusinessKey).collect(Collectors.toSet()); + Long tableId = flowWorkOrderVoList.get(0).getOnlineTableId(); + OnlineTable masterTable = onlineTableService.getOnlineTableFromCache(tableId); + Set convertedBusinessKeySet = + onlineOperationHelper.convertToTypeValue(masterTable.getPrimaryKeyColumn(), businessKeySet); + List filterList = new LinkedList<>(); + OnlineFilterDto filterDto = new OnlineFilterDto(); + filterDto.setTableName(masterTable.getTableName()); + filterDto.setColumnName(masterTable.getPrimaryKeyColumn().getColumnName()); + filterDto.setFilterType(FieldFilterType.IN_LIST_FILTER); + filterDto.setColumnValue(convertedBusinessKeySet); + List> dataList = onlineOperationService.getMasterDataList( + masterTable, null, null, filterList, null); + Map> dataMap = dataList.stream() + .collect(Collectors.toMap(c -> c.get(masterTable.getPrimaryKeyColumn().getColumnName()), c -> c)); + for (FlowWorkOrderVo flowWorkOrderVo : flowWorkOrderVoList) { + Object dataId = onlineOperationHelper.convertToTypeValue( + masterTable.getPrimaryKeyColumn(), flowWorkOrderVo.getBusinessKey()); + Map data = dataMap.get(dataId); + if (data != null) { + flowWorkOrderVo.setMasterData(data); + } + } + List unfinishedProcessInstanceIds = flowWorkOrderVoList.stream() + .filter(c -> !c.getFlowStatus().equals(FlowTaskStatus.FINISHED)) + .map(FlowWorkOrderVo::getProcessInstanceId) + .collect(Collectors.toList()); + if (CollUtil.isEmpty(unfinishedProcessInstanceIds)) { + return; + } + List taskList = flowApiService.getTaskListByProcessInstanceIds(unfinishedProcessInstanceIds); + Map> taskMap = + taskList.stream().collect(Collectors.groupingBy(Task::getProcessInstanceId)); + for (FlowWorkOrderVo flowWorkOrderVo : flowWorkOrderVoList) { + List instanceTaskList = taskMap.get(flowWorkOrderVo.getProcessInstanceId()); + if (instanceTaskList == null) { + continue; + } + JSONArray taskArray = new JSONArray(); + for (Task task : instanceTaskList) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("taskId", task.getId()); + jsonObject.put("taskName", task.getName()); + jsonObject.put("taskKey", task.getTaskDefinitionKey()); + jsonObject.put("assignee", task.getAssignee()); + taskArray.add(jsonObject); + } + flowWorkOrderVo.setRuntimeTaskInfoList(taskArray); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/service/FlowOnlineOperationService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/service/FlowOnlineOperationService.java new file mode 100644 index 00000000..510fd07e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/service/FlowOnlineOperationService.java @@ -0,0 +1,116 @@ +package com.flow.demo.common.flow.online.service; + +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.online.model.OnlineDatasourceRelation; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.object.ColumnData; +import com.flow.demo.common.flow.model.FlowTaskComment; +import org.flowable.task.api.Task; + +import java.util.List; +import java.util.Map; + +/** + * 流程操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowOnlineOperationService { + + /** + * 保存在线表单的数据,同时启动流程。如果当前用户是第一个用户任务的Assignee, + * 或者第一个用户任务的Assignee是流程发起人变量,该方法还会自动Take第一个任务。 + * + * @param processDefinitionId 流程定义Id。 + * @param flowTaskComment 流程审批批注对象。 + * @param taskVariableData 流程任务的变量数据。 + * @param table 表对象。 + * @param columnDataList 表数据。 + */ + void saveNewAndStartProcess( + String processDefinitionId, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable table, + List columnDataList); + + /** + * 保存在线表单的数据,同时启动流程。如果当前用户是第一个用户任务的Assignee, + * 或者第一个用户任务的Assignee是流程发起人变量,该方法还会自动Take第一个任务。 + * + * @param processDefinitionId 流程定义Id。 + * @param flowTaskComment 流程审批批注对象。 + * @param taskVariableData 流程任务的变量数据。 + * @param masterTable 主表对象。 + * @param masterColumnDataList 主表数据。 + * @param slaveColumnDataListMap 关联从表数据Map。 + */ + void saveNewAndStartProcess( + String processDefinitionId, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable masterTable, + List masterColumnDataList, + Map>> slaveColumnDataListMap); + + /** + * 保存在线表单的数据,同时Take用户任务。 + * + * @param processInstanceId 流程实例Id。 + * @param taskId 流程任务Id。 + * @param flowTaskComment 流程审批批注对象。 + * @param taskVariableData 流程任务的变量数据。 + * @param table 表对象。 + * @param columnDataList 表数据。 + */ + void saveNewAndTakeTask( + String processInstanceId, + String taskId, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable table, + List columnDataList); + + /** + * 保存在线表单的数据,同时Take用户任务。 + * + * @param processInstanceId 流程实例Id。 + * @param taskId 流程任务Id。 + * @param flowTaskComment 流程审批批注对象。 + * @param taskVariableData 流程任务的变量数据。 + * @param masterTable 主表对象。 + * @param masterColumnDataList 主表数据。 + * @param slaveColumnDataListMap 关联从表数据Map。 + */ + void saveNewAndTakeTask( + String processInstanceId, + String taskId, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable masterTable, + List masterColumnDataList, + Map>> slaveColumnDataListMap); + + /** + * 保存业务表数据,同时接收流程任务。 + * + * @param task 流程任务。 + * @param flowTaskComment 流程审批批注对象。 + * @param taskVariableData 流程任务的变量数据。 + * @param masterTable 主表对象。 + * @param masterData 主表数据。 + * @param masterDataId 主表数据主键。 + * @param slaveData 从表数据。 + * @param datasourceId 在线表所属数据源Id。 + */ + void updateAndTakeTask( + Task task, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable masterTable, + JSONObject masterData, + String masterDataId, + JSONObject slaveData, + Long datasourceId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/service/impl/FlowOnlineOperationServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/service/impl/FlowOnlineOperationServiceImpl.java new file mode 100644 index 00000000..518e8dd4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/java/com/flow/demo/common/flow/online/service/impl/FlowOnlineOperationServiceImpl.java @@ -0,0 +1,247 @@ +package com.flow.demo.common.flow.online.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.object.ResponseResult; +import com.flow.demo.common.online.model.OnlineColumn; +import com.flow.demo.common.online.model.OnlineDatasourceRelation; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.model.constant.RelationType; +import com.flow.demo.common.online.object.ColumnData; +import com.flow.demo.common.online.service.OnlineOperationService; +import com.flow.demo.common.online.util.OnlineOperationHelper; +import com.flow.demo.common.flow.constant.FlowApprovalType; +import com.flow.demo.common.flow.constant.FlowTaskStatus; +import com.flow.demo.common.flow.exception.FlowOperationException; +import com.flow.demo.common.flow.model.FlowTaskComment; +import com.flow.demo.common.flow.service.FlowApiService; +import com.flow.demo.common.flow.service.FlowWorkOrderService; +import com.flow.demo.common.flow.online.service.FlowOnlineOperationService; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Map; + +@Slf4j +@Service("flowOnlineOperationService") +public class FlowOnlineOperationServiceImpl implements FlowOnlineOperationService { + + @Autowired + private FlowApiService flowApiService; + @Autowired + private FlowWorkOrderService flowWorkOrderService; + @Autowired + private OnlineOperationService onlineOperationService; + @Autowired + private OnlineOperationHelper onlineOperationHelper; + + @Transactional(rollbackFor = Exception.class) + @Override + public void saveNewAndStartProcess( + String processDefinitionId, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable table, + List columnDataList) { + Object dataId = onlineOperationService.saveNew(table, columnDataList); + ProcessInstance instance = + flowApiService.startAndTakeFirst(processDefinitionId, dataId, flowTaskComment, taskVariableData); + flowWorkOrderService.saveNew(instance, dataId, table.getTableId()); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void saveNewAndStartProcess( + String processDefinitionId, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable masterTable, + List masterColumnDataList, + Map>> slaveColumnDataListMap) { + Object dataId = onlineOperationService.saveNewAndSlaveRelation( + masterTable, masterColumnDataList, slaveColumnDataListMap); + ProcessInstance instance = + flowApiService.startAndTakeFirst(processDefinitionId, dataId, flowTaskComment, taskVariableData); + flowWorkOrderService.saveNew(instance, dataId, masterTable.getTableId()); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void saveNewAndTakeTask( + String processInstanceId, + String taskId, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable table, + List columnDataList) { + Object dataId = onlineOperationService.saveNew(table, columnDataList); + Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId); + flowApiService.setBusinessKeyForProcessInstance(processInstanceId, dataId); + Map variables = + flowApiService.initAndGetProcessInstanceVariables(task.getProcessDefinitionId()); + if (taskVariableData == null) { + taskVariableData = new JSONObject(); + } + taskVariableData.putAll(variables); + flowApiService.completeTask(task, flowTaskComment, taskVariableData); + ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId); + flowWorkOrderService.saveNew(instance, dataId, table.getTableId()); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void saveNewAndTakeTask( + String processInstanceId, + String taskId, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable masterTable, + List masterColumnDataList, + Map>> slaveColumnDataListMap) { + Object dataId = onlineOperationService.saveNewAndSlaveRelation( + masterTable, masterColumnDataList, slaveColumnDataListMap); + Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId); + flowApiService.setBusinessKeyForProcessInstance(processInstanceId, dataId); + Map variables = + flowApiService.initAndGetProcessInstanceVariables(task.getProcessDefinitionId()); + if (taskVariableData == null) { + taskVariableData = new JSONObject(); + } + taskVariableData.putAll(variables); + flowApiService.completeTask(task, flowTaskComment, taskVariableData); + ProcessInstance instance = flowApiService.getProcessInstance(processInstanceId); + flowWorkOrderService.saveNew(instance, dataId, masterTable.getTableId()); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void updateAndTakeTask( + Task task, + FlowTaskComment flowTaskComment, + JSONObject taskVariableData, + OnlineTable masterTable, + JSONObject masterData, + String masterDataId, + JSONObject slaveData, + Long datasourceId) { + int flowStatus = FlowTaskStatus.APPROVING; + if (flowTaskComment.getApprovalType().equals(FlowApprovalType.REFUSE)) { + flowStatus = FlowTaskStatus.REFUSED; + } + flowWorkOrderService.updateFlowStatusByProcessInstanceId(task.getProcessInstanceId(), flowStatus); + this.handleMasterTableData(masterTable, masterData, masterDataId); + if (slaveData != null) { + for (Map.Entry relationEntry : slaveData.entrySet()) { + Long relationId = Long.parseLong(relationEntry.getKey()); + this.handleSlaveTableData( + relationId, relationEntry.getValue(), datasourceId, masterTable, masterData, masterDataId); + } + } + flowApiService.completeTask(task, flowTaskComment, taskVariableData); + } + + private void handleMasterTableData(OnlineTable masterTable, JSONObject masterData, String dataId) { + // 如果存在主表数据,就执行主表数据的更新。 + if (masterData != null) { + Map originalMasterData = + onlineOperationService.getMasterData(masterTable, null, null, dataId); + for (Map.Entry entry : originalMasterData.entrySet()) { + masterData.putIfAbsent(entry.getKey(), entry.getValue()); + } + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(masterTable, masterData, true, null); + if (!columnDataListResult.isSuccess()) { + throw new FlowOperationException(columnDataListResult.getErrorMessage()); + } + if (!onlineOperationService.update(masterTable, columnDataListResult.getData())) { + throw new FlowOperationException("主表数据不存在!"); + } + } + } + + private void handleSlaveTableData( + Long relationId, + Object slaveData, + Long datasourceId, + OnlineTable masterTable, + Map masterData, + String masterDataId) { + ResponseResult relationResult = + onlineOperationHelper.verifyAndGetOneToManyRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + throw new FlowOperationException(relationResult.getErrorMessage()); + } + OnlineDatasourceRelation relation = relationResult.getData(); + OnlineTable slaveTable = relation.getSlaveTable(); + if (relation.getRelationType().equals(RelationType.ONE_TO_ONE)) { + String keyColumnName = slaveTable.getPrimaryKeyColumn().getColumnName(); + JSONObject relationData = (JSONObject) slaveData; + if (MapUtil.isEmpty(relationData)) { + return; + } + String slaveDataId = relationData.getString(keyColumnName); + if (slaveDataId == null) { + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(slaveTable, relationData, false, null); + if (!columnDataListResult.isSuccess()) { + throw new FlowOperationException(columnDataListResult.getErrorMessage()); + } + onlineOperationService.saveNew(slaveTable, columnDataListResult.getData()); + } else { + Map originalSlaveData = + onlineOperationService.getMasterData(slaveTable, null, null, slaveDataId); + for (Map.Entry entry : originalSlaveData.entrySet()) { + relationData.putIfAbsent(entry.getKey(), entry.getValue()); + } + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(slaveTable, relationData, true, null); + if (!columnDataListResult.isSuccess()) { + throw new FlowOperationException(columnDataListResult.getErrorMessage()); + } + if (!onlineOperationService.update(slaveTable, columnDataListResult.getData())) { + throw new FlowOperationException("关联从表 [" + slaveTable.getTableName() + "] 中的更新数据不存在"); + } + } + } else if (relation.getRelationType().equals(RelationType.ONE_TO_MANY)) { + JSONArray relationDataArray = (JSONArray) slaveData; + if (CollUtil.isEmpty(relationDataArray)) { + return; + } + JSONObject firstData = relationDataArray.getJSONObject(0); + Object key = firstData.get(slaveTable.getPrimaryKeyColumn().getColumnName()); + // 如果一对多关联数据中存在主键数据,则需要先批量删除。 + if (key != null) { + OnlineColumn slaveColumn = relation.getSlaveTable().getColumnMap().get(relation.getSlaveColumnId()); + Object relationSlaveColumnValue = firstData.get(slaveColumn.getColumnName()); + onlineOperationService.forceDelete( + relation.getSlaveTable(), slaveColumn, relationSlaveColumnValue.toString()); + } + if (masterData == null) { + masterData = onlineOperationService.getMasterData( + masterTable, null, null, masterDataId); + } + for (int i = 0; i < relationDataArray.size(); i++) { + JSONObject relationSlaveData = relationDataArray.getJSONObject(i); + // 自动补齐主表关联数据。 + OnlineColumn masterColumn = masterTable.getColumnMap().get(relation.getMasterColumnId()); + Object masterColumnValue = masterData.get(masterColumn.getColumnName()); + OnlineColumn slaveColumn = slaveTable.getColumnMap().get(relation.getSlaveColumnId()); + relationSlaveData.put(slaveColumn.getColumnName(), masterColumnValue); + // 拆解主表和一对多关联从表的输入参数,并构建出数据表的待插入数据列表。 + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(slaveTable, relationSlaveData, false, null); + if (!columnDataListResult.isSuccess()) { + throw new FlowOperationException(columnDataListResult.getErrorMessage()); + } + onlineOperationService.saveNew(slaveTable, columnDataListResult.getData()); + } + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/resources/META-INF/spring.factories b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..da4f864b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow-online/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.flow.demo.common.flow.online.config.FlowOnlineAutoConfig \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/pom.xml new file mode 100644 index 00000000..a02d892a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/pom.xml @@ -0,0 +1,58 @@ + + + + common + com.flow.demo + 1.0.0 + + 4.0.0 + + common-flow + 1.0.0 + common-flow + jar + + + + com.flow.demo + common-datafilter + 1.0.0 + + + com.flow.demo + common-sequence + 1.0.0 + + + com.flow.demo + common-log + 1.0.0 + + + org.flowable + flowable-spring-boot-starter-basic + ${flowable.version} + + + + + + + src/main/resources + + **/*.* + + false + + + src/main/java + + **/*.xml + + false + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/config/FlowAutoConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/config/FlowAutoConfig.java new file mode 100644 index 00000000..ab4b46e9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/config/FlowAutoConfig.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.flow.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +/** + * common-flow模块的自动配置引导类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EnableConfigurationProperties({FlowProperties.class}) +public class FlowAutoConfig { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/config/FlowProperties.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/config/FlowProperties.java new file mode 100644 index 00000000..e768876c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/config/FlowProperties.java @@ -0,0 +1,20 @@ +package com.flow.demo.common.flow.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 工作流的配置对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ConfigurationProperties(prefix = "common-flow") +public class FlowProperties { + + /** + * 工作落工单操作接口的URL前缀。 + */ + private String urlPrefix; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowApprovalType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowApprovalType.java new file mode 100644 index 00000000..a0e9d77d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowApprovalType.java @@ -0,0 +1,84 @@ +package com.flow.demo.common.flow.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 工作流任务触发BUTTON。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FlowApprovalType { + + /** + * 保存。 + */ + public static final String SAVE = "save"; + /** + * 同意。 + */ + public static final String AGREE = "agree"; + /** + * 拒绝。 + */ + public static final String REFUSE = "refuse"; + /** + * 指派。 + */ + public static final String TRANSFER = "transfer"; + /** + * 多实例会签。 + */ + public static final String MULTI_SIGN = "multi_sign"; + /** + * 会签同意。 + */ + public static final String MULTI_AGREE = "multi_agree"; + /** + * 会签拒绝。 + */ + public static final String MULTI_REFUSE = "multi_refuse"; + /** + * 会签弃权。 + */ + public static final String MULTI_ABSTAIN = "multi_abstain"; + /** + * 多实例加签。 + */ + public static final String MULTI_CONSIGN = "multi_consign"; + /** + * 中止。 + */ + public static final String STOP = "stop"; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(SAVE, "保存"); + DICT_MAP.put(AGREE, "同意"); + DICT_MAP.put(REFUSE, "拒绝"); + DICT_MAP.put(TRANSFER, "指派"); + DICT_MAP.put(MULTI_SIGN, "多实例会签"); + DICT_MAP.put(MULTI_AGREE, "会签同意"); + DICT_MAP.put(MULTI_REFUSE, "会签拒绝"); + DICT_MAP.put(MULTI_ABSTAIN, "会签弃权"); + DICT_MAP.put(MULTI_CONSIGN, "多实例加签"); + DICT_MAP.put(STOP, "中止"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FlowApprovalType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowConstant.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowConstant.java new file mode 100644 index 00000000..7a8bb44f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowConstant.java @@ -0,0 +1,85 @@ +package com.flow.demo.common.flow.constant; + +/** + * 工作流中的常量数据。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class FlowConstant { + + /** + * 标识流程实例启动用户的变量名。 + */ + public final static String START_USER_NAME_VAR = "${startUserName}"; + + /** + * 流程实例发起人变量名。 + */ + public final static String PROC_INSTANCE_INITIATOR_VAR = "initiator"; + + /** + * 流程实例中发起人用户的变量名。 + */ + public final static String PROC_INSTANCE_START_USER_NAME_VAR = "startUserName"; + + /** + * 操作类型变量。 + */ + public final static String OPERATION_TYPE_VAR = "operationType"; + + /** + * 多任务拒绝数量变量。 + */ + public final static String MULTI_REFUSE_COUNT_VAR = "multiRefuseCount"; + + /** + * 多任务同意数量变量。 + */ + public final static String MULTI_AGREE_COUNT_VAR = "multiAgreeCount"; + + /** + * 多任务弃权数量变量。 + */ + public final static String MULTI_ABSTAIN_COUNT_VAR = "multiAbstainCount"; + + /** + * 会签发起任务。 + */ + public final static String MULTI_SIGN_START_TASK_VAR = "multiSignStartTask"; + + /** + * 会签任务总数量。 + */ + public final static String MULTI_SIGN_NUM_OF_INSTANCES_VAR = "multiNumOfInstances"; + + /** + * 多实例实例数量变量。 + */ + public final static String NUMBER_OF_INSTANCES_VAR = "nrOfInstances"; + + /** + * 多任务指派人列表变量。 + */ + public final static String MULTI_ASSIGNEE_LIST_VAR = "assigneeList"; + + /** + * 上级部门领导审批变量 + */ + public final static String GROUP_TYPE_UP_DEPT_POST_LEADER_VAR = "upDeptPostLeader"; + + /** + * 上级部门领导审批变量 + */ + public final static String GROUP_TYPE_DEPT_POST_LEADER_VAR = "deptPostLeader"; + + /** + * 上级部门领导审批 + */ + public final static String GROUP_TYPE_UP_DEPT_POST_LEADER = "UP_DEPT_POST_LEADER"; + + /** + * 本部门岗位领导审批 + */ + public final static String GROUP_TYPE_DEPT_POST_LEADER = "DEPT_POST_LEADER"; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowTaskStatus.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowTaskStatus.java new file mode 100644 index 00000000..4573242a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowTaskStatus.java @@ -0,0 +1,64 @@ +package com.flow.demo.common.flow.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 工作流任务类型。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FlowTaskStatus { + + /** + * 已提交。 + */ + public static final int SUBMITTED = 0; + /** + * 审批中。 + */ + public static final int APPROVING = 1; + /** + * 被拒绝。 + */ + public static final int REFUSED = 2; + /** + * 已结束。 + */ + public static final int FINISHED = 3; + /** + * 提前停止。 + */ + public static final Integer STOPPED = 4; + /** + * 已取消。 + */ + public static final Integer CANCELLED = 5; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(SUBMITTED, "已提交"); + DICT_MAP.put(APPROVING, "审批中"); + DICT_MAP.put(REFUSED, "被拒绝"); + DICT_MAP.put(FINISHED, "已结束"); + DICT_MAP.put(STOPPED, "提前停止"); + DICT_MAP.put(CANCELLED, "已取消"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FlowTaskStatus() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowTaskType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowTaskType.java new file mode 100644 index 00000000..1f22e5f1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/constant/FlowTaskType.java @@ -0,0 +1,44 @@ +package com.flow.demo.common.flow.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 工作流任务类型。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FlowTaskType { + + /** + * 其他类型任务。 + */ + public static final int OTHER_TYPE = 0; + /** + * 用户任务。 + */ + public static final int USER_TYPE = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(OTHER_TYPE, "其他任务类型"); + DICT_MAP.put(USER_TYPE, "用户任务类型"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FlowTaskType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowCategoryController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowCategoryController.java new file mode 100644 index 00000000..5107c057 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowCategoryController.java @@ -0,0 +1,195 @@ +package com.flow.demo.common.flow.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.jimmyshi.beanquery.BeanQuery; +import com.github.pagehelper.page.PageMethod; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.flow.dto.*; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.flow.model.constant.FlowEntryStatus; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.flow.vo.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +/** + * 工作流分类操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-flow.urlPrefix}/flowCategory") +public class FlowCategoryController { + + @Autowired + private FlowCategoryService flowCategoryService; + @Autowired + private FlowEntryService flowEntryService; + + /** + * 新增FlowCategory数据。 + * + * @param flowCategoryDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody FlowCategoryDto flowCategoryDto) { + String errorMessage = MyCommonUtil.getModelValidationError(flowCategoryDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + FlowCategory flowCategory = MyModelUtil.copyTo(flowCategoryDto, FlowCategory.class); + flowCategory = flowCategoryService.saveNew(flowCategory); + return ResponseResult.success(flowCategory.getCategoryId()); + } + + /** + * 更新FlowCategory数据。 + * + * @param flowCategoryDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody FlowCategoryDto flowCategoryDto) { + String errorMessage = MyCommonUtil.getModelValidationError(flowCategoryDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + FlowCategory flowCategory = MyModelUtil.copyTo(flowCategoryDto, FlowCategory.class); + FlowCategory originalFlowCategory = flowCategoryService.getById(flowCategory.getCategoryId()); + if (originalFlowCategory == null) { + errorMessage = "数据验证失败,当前流程分类并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!StrUtil.equals(flowCategory.getCode(), originalFlowCategory.getCode())) { + FlowEntry filter = new FlowEntry(); + filter.setCategoryId(flowCategory.getCategoryId()); + filter.setStatus(FlowEntryStatus.PUBLISHED); + List flowEntryList = flowEntryService.getListByFilter(filter); + if (CollUtil.isNotEmpty(flowEntryList)) { + errorMessage = "数据验证失败,当前流程分类存在已经发布的流程数据,因此分类标识不能修改!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + if (!flowCategoryService.update(flowCategory, originalFlowCategory)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除FlowCategory数据。 + * + * @param categoryId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long categoryId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(categoryId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + FlowCategory originalFlowCategory = flowCategoryService.getById(categoryId); + if (originalFlowCategory == null) { + errorMessage = "数据验证失败,当前流程分类并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + FlowEntry filter = new FlowEntry(); + filter.setCategoryId(categoryId); + List flowEntryList = flowEntryService.getListByFilter(filter); + if (CollUtil.isNotEmpty(flowEntryList)) { + errorMessage = "数据验证失败,请先删除当前流程分类关联的流程数据!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!flowCategoryService.remove(categoryId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的FlowCategory列表。 + * + * @param flowCategoryDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody FlowCategoryDto flowCategoryDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + FlowCategory flowCategoryFilter = MyModelUtil.copyTo(flowCategoryDtoFilter, FlowCategory.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowCategory.class); + List flowCategoryList = flowCategoryService.getFlowCategoryListWithRelation(flowCategoryFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(flowCategoryList, FlowCategory.INSTANCE)); + } + + /** + * 查看指定FlowCategory对象详情。 + * + * @param categoryId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long categoryId) { + if (MyCommonUtil.existBlankArgument(categoryId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + FlowCategory flowCategory = flowCategoryService.getByIdWithRelation(categoryId, MyRelationParam.full()); + if (flowCategory == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + FlowCategoryVo flowCategoryVo = FlowCategory.INSTANCE.fromModel(flowCategory); + return ResponseResult.success(flowCategoryVo); + } + + /** + * 以字典形式返回全部FlowCategory数据集合。字典的键值为[categoryId, name]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDict") + public ResponseResult>> listDict(FlowCategory filter) { + List resultList = flowCategoryService.getListByFilter(filter); + return ResponseResult.success(BeanQuery.select( + "categoryId as id", "name as name").executeFrom(resultList)); + } + + /** + * 根据字典Id集合,获取查询后的字典数据。 + * + * @param dictIds 字典Id集合。 + * @return 应答结果对象,包含字典形式的数据集合。 + */ + @PostMapping("/listDictByIds") + public ResponseResult>> listDictByIds( + @MyRequestBody(elementType = Long.class) List dictIds) { + List resultList = flowCategoryService.getInList(new HashSet<>(dictIds)); + return ResponseResult.success(BeanQuery.select( + "categoryId as id", "name as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowEntryController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowEntryController.java new file mode 100644 index 00000000..96df3500 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowEntryController.java @@ -0,0 +1,537 @@ +package com.flow.demo.common.flow.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.jimmyshi.beanquery.BeanQuery; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.page.PageMethod; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.flow.constant.FlowTaskType; +import com.flow.demo.common.flow.dto.*; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.flow.model.constant.FlowEntryStatus; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.flow.vo.*; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.*; +import org.flowable.bpmn.model.Process; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.*; + +/** + * 工作流操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-flow.urlPrefix}/flowEntry") +public class FlowEntryController { + + @Autowired + private FlowEntryService flowEntryService; + @Autowired + private FlowCategoryService flowCategoryService; + @Autowired + private FlowEntryVariableService flowEntryVariableService; + + /** + * 新增工作流对象数据。 + * + * @param flowEntryDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody FlowEntryDto flowEntryDto) { + String errorMessage = MyCommonUtil.getModelValidationError(flowEntryDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + FlowEntry flowEntry = MyModelUtil.copyTo(flowEntryDto, FlowEntry.class); + if (flowEntryService.existOne("processDefinitionKey", flowEntry.getProcessDefinitionKey())) { + errorMessage = "数据验证失败,该流程定义标识已存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = flowEntryService.verifyRelatedData(flowEntry, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + flowEntry = flowEntryService.saveNew(flowEntry); + return ResponseResult.success(flowEntry.getEntryId()); + } + + /** + * 更新工作流对象数据。 + * + * @param flowEntryDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody FlowEntryDto flowEntryDto) { + String errorMessage = MyCommonUtil.getModelValidationError(flowEntryDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + FlowEntry flowEntry = MyModelUtil.copyTo(flowEntryDto, FlowEntry.class); + FlowEntry originalFlowEntry = flowEntryService.getById(flowEntry.getEntryId()); + if (originalFlowEntry == null) { + errorMessage = "数据验证失败,当前流程并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (ObjectUtil.notEqual(flowEntry.getProcessDefinitionKey(), originalFlowEntry.getProcessDefinitionKey())) { + if (originalFlowEntry.getStatus().equals(FlowEntryStatus.PUBLISHED)) { + errorMessage = "数据验证失败,当前流程为发布状态,流程标识不能修改!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (flowEntryService.existOne("processDefinitionKey", flowEntry.getProcessDefinitionKey())) { + errorMessage = "数据验证失败,该流程定义标识已存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + if (ObjectUtil.notEqual(flowEntry.getCategoryId(), originalFlowEntry.getCategoryId())) { + if (originalFlowEntry.getStatus().equals(FlowEntryStatus.PUBLISHED)) { + errorMessage = "数据验证失败,当前流程为发布状态,流程分类不能修改!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + } + // 验证关联Id的数据合法性 + CallResult callResult = flowEntryService.verifyRelatedData(flowEntry, originalFlowEntry); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!flowEntryService.update(flowEntry, originalFlowEntry)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除工作流对象数据。 + * + * @param entryId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long entryId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(entryId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + FlowEntry originalFlowEntry = flowEntryService.getById(entryId); + if (originalFlowEntry == null) { + errorMessage = "数据验证失败,当前流程并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (originalFlowEntry.getStatus().equals(FlowEntryStatus.PUBLISHED)) { + errorMessage = "数据验证失败,当前流程为发布状态,不能删除!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!flowEntryService.remove(entryId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 发布工作流。 + * + * @param entryId 流程主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/publish") + public ResponseResult publish(@MyRequestBody(required = true) Long entryId) throws XMLStreamException { + String errorMessage; + FlowEntry flowEntry = flowEntryService.getById(entryId); + if (flowEntry == null) { + errorMessage = "数据验证失败,该流程并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (StrUtil.isBlank(flowEntry.getBpmnXml())) { + errorMessage = "数据验证失败,该流程没有流程图不能被发布!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + ResponseResult taskInfoResult = this.verifyAndGetInitialTaskInfo(flowEntry); + if (!taskInfoResult.isSuccess()) { + return ResponseResult.errorFrom(taskInfoResult); + } + List flowTaskExtList = this.buildTaskExtList(flowEntry); + String taskInfo = taskInfoResult.getData() == null ? null : JSON.toJSONString(taskInfoResult.getData()); + flowEntryService.publish(flowEntry, taskInfo, flowTaskExtList); + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的工作流列表。 + * + * @param flowEntryDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody FlowEntryDto flowEntryDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + FlowEntry flowEntryFilter = MyModelUtil.copyTo(flowEntryDtoFilter, FlowEntry.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowEntry.class); + List flowEntryList = flowEntryService.getFlowEntryListWithRelation(flowEntryFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(flowEntryList, FlowEntry.INSTANCE)); + } + + /** + * 查看指定工作流对象详情。 + * + * @param entryId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long entryId) { + if (MyCommonUtil.existBlankArgument(entryId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + FlowEntry flowEntry = flowEntryService.getByIdWithRelation(entryId, MyRelationParam.full()); + if (flowEntry == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + FlowEntryVo flowEntryVo = FlowEntry.INSTANCE.fromModel(flowEntry); + return ResponseResult.success(flowEntryVo); + } + + /** + * 列出指定流程的发布版本列表。 + * + * @param entryId 流程主键Id。 + * @return 应答结果对象,包含流程发布列表数据。 + */ + @GetMapping("/listFlowEntryPublish") + public ResponseResult> listFlowEntryPublish(@RequestParam Long entryId) { + List flowEntryPublishList = flowEntryService.getFlowEntryPublishList(entryId); + return ResponseResult.success(MyModelUtil.copyCollectionTo(flowEntryPublishList, FlowEntryPublishVo.class)); + } + + /** + * 以字典形式返回全部FlowEntry数据集合。字典的键值为[entryId, procDefinitionName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDict") + public ResponseResult>> listDict(FlowEntry filter) { + List resultList = flowEntryService.getListByFilter(filter); + return ResponseResult.success(BeanQuery.select( + "entryId as id", "processDefinitionName as name").executeFrom(resultList)); + } + + /** + * 白名单接口,根据流程Id,获取流程引擎需要的流程标识和流程名称。 + * + * @param entryId 流程Id。 + * @return 流程的部分数据。 + */ + @GetMapping("/viewDict") + public ResponseResult> viewDict(@RequestParam Long entryId) { + FlowEntry flowEntry = flowEntryService.getById(entryId); + if (flowEntry == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + Map resultMap = new HashMap<>(2); + resultMap.put("processDefinitionKey", flowEntry.getProcessDefinitionKey()); + resultMap.put("processDefinitionName", flowEntry.getProcessDefinitionName()); + return ResponseResult.success(resultMap); + } + + /** + * 切换指定工作的发布主版本。 + * + * @param entryId 工作流主键Id。 + * @param newEntryPublishId 新的工作流发布主版本对象的主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/updateMainVersion") + public ResponseResult updateMainVersion( + @MyRequestBody(required = true) Long entryId, + @MyRequestBody(required = true) Long newEntryPublishId) { + String errorMessage; + FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishById(newEntryPublishId); + if (flowEntryPublish == null) { + errorMessage = "数据验证失败,当前流程发布版本并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (ObjectUtil.notEqual(entryId, flowEntryPublish.getEntryId())) { + errorMessage = "数据验证失败,当前工作流并不包含该工作流发布版本数据,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (flowEntryPublish.getMainVersion()) { + errorMessage = "数据验证失败,该版本已经为当前工作流的发布主版本,不能重复设置!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + flowEntryService.updateFlowEntryMainVersion(flowEntryService.getById(entryId), flowEntryPublish); + return ResponseResult.success(); + } + + /** + * 挂起工作流的指定发布版本。 + * + * @param entryPublishId 工作发布Id。 + * @return 应答结果对象。 + */ + @PostMapping("/suspendFlowEntryPublish") + public ResponseResult suspendFlowEntryPublish(@MyRequestBody(required = true) Long entryPublishId) { + String errorMessage; + FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishById(entryPublishId); + if (flowEntryPublish == null) { + errorMessage = "数据验证失败,当前流程发布版本并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!flowEntryPublish.getActiveStatus()) { + errorMessage = "数据验证失败,当前流程发布版本已处于挂起状态!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + flowEntryService.suspendFlowEntryPublish(flowEntryPublish); + return ResponseResult.success(); + } + + /** + * 激活工作流的指定发布版本。 + * + * @param entryPublishId 工作发布Id。 + * @return 应答结果对象。 + */ + @PostMapping("/activateFlowEntryPublish") + public ResponseResult activateFlowEntryPublish(@MyRequestBody(required = true) Long entryPublishId) { + String errorMessage; + FlowEntryPublish flowEntryPublish = flowEntryService.getFlowEntryPublishById(entryPublishId); + if (flowEntryPublish == null) { + errorMessage = "数据验证失败,当前流程发布版本并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (flowEntryPublish.getActiveStatus()) { + errorMessage = "数据验证失败,当前流程发布版本已处于激活状态!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + flowEntryService.activateFlowEntryPublish(flowEntryPublish); + return ResponseResult.success(); + } + + private FlowTaskExt buildTaskExt(UserTask userTask) { + FlowTaskExt flowTaskExt = new FlowTaskExt(); + flowTaskExt.setTaskId(userTask.getId()); + String formKey = userTask.getFormKey(); + if (StrUtil.isNotBlank(formKey)) { + TaskInfoVo taskInfoVo = JSON.parseObject(formKey, TaskInfoVo.class); + flowTaskExt.setGroupType(taskInfoVo.getGroupType()); + } + Map> extensionMap = userTask.getExtensionElements(); + if (MapUtil.isNotEmpty(extensionMap)) { + List operationList = this.buildUserTaskOperationListExtensionElement(extensionMap); + if (CollUtil.isNotEmpty(operationList)) { + flowTaskExt.setOperationListJson(JSON.toJSONString(operationList)); + } + List variableList = this.buildUserTaskVariableListExtensionElement(extensionMap); + if (CollUtil.isNotEmpty(variableList)) { + flowTaskExt.setVariableListJson(JSON.toJSONString(variableList)); + } + JSONObject assigneeListObject = this.buildUserTaskAssigneeListExtensionElement(extensionMap); + if (assigneeListObject != null) { + flowTaskExt.setAssigneeListJson(JSON.toJSONString(assigneeListObject)); + } + } + return flowTaskExt; + } + + private List buildTaskExtList(FlowEntry flowEntry) throws XMLStreamException { + List flowTaskExtList = new LinkedList<>(); + BpmnModel bpmnModel = this.convertToBpmnModel(flowEntry.getBpmnXml()); + List processList = bpmnModel.getProcesses(); + for (Process process : processList) { + for (FlowElement element : process.getFlowElements()) { + if (element instanceof UserTask) { + FlowTaskExt flowTaskExt = this.buildTaskExt((UserTask) element); + flowTaskExtList.add(flowTaskExt); + } + } + } + return flowTaskExtList; + } + + private ResponseResult verifyAndGetInitialTaskInfo(FlowEntry flowEntry) throws XMLStreamException { + String errorMessage; + BpmnModel bpmnModel = this.convertToBpmnModel(flowEntry.getBpmnXml()); + Process process = bpmnModel.getMainProcess(); + if (process == null) { + errorMessage = "数据验证失败,当前流程标识 [" + flowEntry.getProcessDefinitionKey() + "] 关联的流程模型并不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + Collection elementList = process.getFlowElements(); + FlowElement startEvent = null; + FlowElement firstTask = null; + // 这里我们只定位流程模型中的第二个节点。 + for (FlowElement flowElement : elementList) { + if (flowElement instanceof StartEvent) { + startEvent = flowElement; + break; + } + } + if (startEvent == null) { + errorMessage = "数据验证失败,当前流程图没有包含 [开始事件] 节点,请修改流程图!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + for (FlowElement flowElement : elementList) { + if (flowElement instanceof SequenceFlow) { + SequenceFlow sequenceFlow = (SequenceFlow) flowElement; + if (sequenceFlow.getSourceFlowElement().equals(startEvent)) { + firstTask = sequenceFlow.getTargetFlowElement(); + break; + } + } + } + if (firstTask == null) { + errorMessage = "数据验证失败,当前流程图没有包含 [开始事件] 节点没有任何连线,请修改流程图!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + TaskInfoVo taskInfoVo; + if (firstTask instanceof UserTask) { + UserTask userTask = (UserTask) firstTask; + String formKey = userTask.getFormKey(); + if (StrUtil.isNotBlank(formKey)) { + taskInfoVo = JSON.parseObject(formKey, TaskInfoVo.class); + } else { + taskInfoVo = new TaskInfoVo(); + } + taskInfoVo.setAssignee(userTask.getAssignee()); + taskInfoVo.setTaskKey(userTask.getId()); + taskInfoVo.setTaskType(FlowTaskType.USER_TYPE); + Map> extensionMap = userTask.getExtensionElements(); + if (MapUtil.isNotEmpty(extensionMap)) { + taskInfoVo.setOperationList(this.buildUserTaskOperationListExtensionElement(extensionMap)); + taskInfoVo.setVariableList(this.buildUserTaskVariableListExtensionElement(extensionMap)); + } + } else { + taskInfoVo = new TaskInfoVo(); + taskInfoVo.setTaskType(FlowTaskType.OTHER_TYPE); + } + return ResponseResult.success(taskInfoVo); + } + + private JSONObject buildUserTaskAssigneeListExtensionElement( + Map> extensionMap) { + JSONObject jsonData = null; + List elementAssigneeList = extensionMap.get("assigneeList"); + if (CollUtil.isEmpty(elementAssigneeList)) { + return jsonData; + } + ExtensionElement ee = elementAssigneeList.get(0); + Map> childExtensionMap = ee.getChildElements(); + if (MapUtil.isEmpty(childExtensionMap)) { + return jsonData; + } + List assigneeElements = childExtensionMap.get("assignee"); + if (CollUtil.isEmpty(assigneeElements)) { + return jsonData; + } + JSONArray assigneeIdArray = new JSONArray(); + for (ExtensionElement e : assigneeElements) { + assigneeIdArray.add(e.getAttributeValue(null, "id")); + } + jsonData = new JSONObject(); + String assigneeType = ee.getAttributeValue(null, "type"); + jsonData.put("assigneeType", assigneeType); + jsonData.put("assigneeList", assigneeIdArray); + return jsonData; + } + + private List buildUserTaskOperationListExtensionElement( + Map> extensionMap) { + List resultList = null; + List elementOperationList = extensionMap.get("operationList"); + if (CollUtil.isEmpty(elementOperationList)) { + return resultList; + } + ExtensionElement ee = elementOperationList.get(0); + Map> childExtensionMap = ee.getChildElements(); + if (MapUtil.isEmpty(childExtensionMap)) { + return resultList; + } + List formOperationElements = childExtensionMap.get("formOperation"); + if (CollUtil.isEmpty(formOperationElements)) { + return resultList; + } + resultList = new LinkedList<>(); + for (ExtensionElement e : formOperationElements) { + JSONObject operationJsonData = new JSONObject(); + operationJsonData.put("id", e.getAttributeValue(null, "id")); + operationJsonData.put("label", e.getAttributeValue(null, "label")); + operationJsonData.put("type", e.getAttributeValue(null, "type")); + operationJsonData.put("showOrder", e.getAttributeValue(null, "showOrder")); + resultList.add(operationJsonData); + } + return resultList; + } + + private List buildUserTaskVariableListExtensionElement( + Map> extensionMap) { + List elementVariableList = extensionMap.get("variableList"); + if (CollUtil.isEmpty(elementVariableList)) { + return null; + } + ExtensionElement ee = elementVariableList.get(0); + Map> childExtensionMap = ee.getChildElements(); + if (MapUtil.isEmpty(childExtensionMap)) { + return null; + } + List formVariableElements = childExtensionMap.get("formVariable"); + if (CollUtil.isEmpty(formVariableElements)) { + return null; + } + Set variableIdSet = new HashSet<>(); + for (ExtensionElement e : formVariableElements) { + String id = e.getAttributeValue(null, "id"); + variableIdSet.add(Long.parseLong(id)); + } + List variableList = flowEntryVariableService.getInList(variableIdSet); + List resultList = new LinkedList<>(); + for (FlowEntryVariable variable : variableList) { + resultList.add((JSONObject) JSON.toJSON(variable)); + } + return resultList; + } + + private BpmnModel convertToBpmnModel(String bpmnXml) throws XMLStreamException { + BpmnXMLConverter converter = new BpmnXMLConverter(); + InputStream in = new ByteArrayInputStream(bpmnXml.getBytes(StandardCharsets.UTF_8)); + @Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(in); + return converter.convertToBpmnModel(reader); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowEntryVariableController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowEntryVariableController.java new file mode 100644 index 00000000..1fd1b71e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowEntryVariableController.java @@ -0,0 +1,143 @@ +package com.flow.demo.common.flow.controller; + +import com.github.pagehelper.page.PageMethod; +import com.flow.demo.common.flow.vo.*; +import com.flow.demo.common.flow.dto.*; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.constant.*; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 流程变量操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-flow.urlPrefix}/flowEntryVariable") +public class FlowEntryVariableController { + + @Autowired + private FlowEntryVariableService flowEntryVariableService; + + /** + * 新增流程变量数据。 + * + * @param flowEntryVariableDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody FlowEntryVariableDto flowEntryVariableDto) { + String errorMessage = MyCommonUtil.getModelValidationError(flowEntryVariableDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + FlowEntryVariable flowEntryVariable = MyModelUtil.copyTo(flowEntryVariableDto, FlowEntryVariable.class); + flowEntryVariable = flowEntryVariableService.saveNew(flowEntryVariable); + return ResponseResult.success(flowEntryVariable.getVariableId()); + } + + /** + * 更新流程变量数据。 + * + * @param flowEntryVariableDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody FlowEntryVariableDto flowEntryVariableDto) { + String errorMessage = MyCommonUtil.getModelValidationError(flowEntryVariableDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + FlowEntryVariable flowEntryVariable = MyModelUtil.copyTo(flowEntryVariableDto, FlowEntryVariable.class); + FlowEntryVariable originalFlowEntryVariable = flowEntryVariableService.getById(flowEntryVariable.getVariableId()); + if (originalFlowEntryVariable == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!flowEntryVariableService.update(flowEntryVariable, originalFlowEntryVariable)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除流程变量数据。 + * + * @param variableId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long variableId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(variableId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + FlowEntryVariable originalFlowEntryVariable = flowEntryVariableService.getById(variableId); + if (originalFlowEntryVariable == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!flowEntryVariableService.remove(variableId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的流程变量列表。 + * + * @param flowEntryVariableDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody FlowEntryVariableDto flowEntryVariableDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + FlowEntryVariable flowEntryVariableFilter = MyModelUtil.copyTo(flowEntryVariableDtoFilter, FlowEntryVariable.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, FlowEntryVariable.class); + List flowEntryVariableList = + flowEntryVariableService.getFlowEntryVariableListWithRelation(flowEntryVariableFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(flowEntryVariableList, FlowEntryVariable.INSTANCE)); + } + + /** + * 查看指定流程变量对象详情。 + * + * @param variableId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long variableId) { + if (MyCommonUtil.existBlankArgument(variableId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + FlowEntryVariable flowEntryVariable = flowEntryVariableService.getByIdWithRelation(variableId, MyRelationParam.full()); + if (flowEntryVariable == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + FlowEntryVariableVo flowEntryVariableVo = FlowEntryVariable.INSTANCE.fromModel(flowEntryVariable); + return ResponseResult.success(flowEntryVariableVo); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowOperationController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowOperationController.java new file mode 100644 index 00000000..c1fdb6e2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/controller/FlowOperationController.java @@ -0,0 +1,508 @@ +package com.flow.demo.common.flow.controller; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.flow.constant.FlowConstant; +import com.flow.demo.common.flow.constant.FlowTaskStatus; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.flow.util.FlowOperationHelper; +import com.flow.demo.common.flow.vo.FlowTaskCommentVo; +import com.flow.demo.common.flow.vo.FlowTaskVo; +import com.flow.demo.common.flow.vo.TaskInfoVo; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.Process; +import org.flowable.bpmn.model.SequenceFlow; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.task.api.Task; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.StreamUtils; +import org.springframework.web.bind.annotation.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 流程操作接口类 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-flow.urlPrefix}/flowOperation") +public class FlowOperationController { + + @Autowired + private FlowEntryService flowEntryService; + @Autowired + private FlowTaskCommentService flowTaskCommentService; + @Autowired + private FlowTaskExtService flowTaskExtService; + @Autowired + private FlowApiService flowApiService; + @Autowired + private FlowWorkOrderService flowWorkOrderService; + @Autowired + private FlowOperationHelper flowOperationHelper; + + /** + * 根据指定流程的主版本,发起一个流程实例。 + * + * @param processDefinitionKey 流程标识。 + * @return 应答结果对象。 + */ + @PostMapping("/startOnly") + public ResponseResult startOnly(@MyRequestBody(required = true) String processDefinitionKey) { + // 1. 验证流程数据的合法性。 + ResponseResult flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey); + if (!flowEntryResult.isSuccess()) { + return ResponseResult.errorFrom(flowEntryResult); + } + // 2. 验证流程一个用户任务的合法性。 + FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish(); + ResponseResult taskInfoResult = + flowOperationHelper.verifyAndGetInitialTaskInfo(flowEntryPublish, false); + if (!taskInfoResult.isSuccess()) { + return ResponseResult.errorFrom(taskInfoResult); + } + flowApiService.start(flowEntryPublish.getProcessDefinitionId()); + return ResponseResult.success(); + } + + /** + * 获取开始节点之后的第一个任务节点的数据。 + * + * @param processDefinitionKey 流程标识。 + * @return 任务节点的自定义对象数据。 + */ + @GetMapping("/viewInitialTaskInfo") + public ResponseResult viewInitialTaskInfo(@RequestParam String processDefinitionKey) { + ResponseResult flowEntryResult = flowOperationHelper.verifyAndGetFlowEntry(processDefinitionKey); + if (!flowEntryResult.isSuccess()) { + return ResponseResult.errorFrom(flowEntryResult); + } + FlowEntryPublish flowEntryPublish = flowEntryResult.getData().getMainFlowEntryPublish(); + String initTaskInfo = flowEntryPublish.getInitTaskInfo(); + TaskInfoVo taskInfo = StrUtil.isBlank(initTaskInfo) + ? null : JSON.parseObject(initTaskInfo, TaskInfoVo.class); + if (taskInfo != null) { + String loginName = TokenData.takeFromRequest().getLoginName(); + taskInfo.setAssignedMe(StrUtil.equalsAny( + taskInfo.getAssignee(), loginName, FlowConstant.START_USER_NAME_VAR)); + } + return ResponseResult.success(taskInfo); + } + + /** + * 获取流程运行时指定任务的信息。 + * + * @param processDefinitionId 流程引擎的定义Id。 + * @param processInstanceId 流程引擎的实例Id。 + * @param taskId 流程引擎的任务Id。 + * @return 任务节点的自定义对象数据。 + */ + @GetMapping("/viewRuntimeTaskInfo") + public ResponseResult viewRuntimeTaskInfo( + @RequestParam String processDefinitionId, + @RequestParam String processInstanceId, + @RequestParam String taskId) { + Task task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId); + ResponseResult taskInfoResult = flowOperationHelper.verifyAndGetRuntimeTaskInfo(task); + if (!taskInfoResult.isSuccess()) { + return ResponseResult.errorFrom(taskInfoResult); + } + TaskInfoVo taskInfoVo = taskInfoResult.getData(); + FlowTaskExt flowTaskExt = + flowTaskExtService.getByProcessDefinitionIdAndTaskId(processDefinitionId, taskInfoVo.getTaskKey()); + if (flowTaskExt != null) { + if (StrUtil.isNotBlank(flowTaskExt.getOperationListJson())) { + taskInfoVo.setOperationList(JSON.parseArray(flowTaskExt.getOperationListJson(), JSONObject.class)); + } + if (StrUtil.isNotBlank(flowTaskExt.getVariableListJson())) { + taskInfoVo.setVariableList(JSON.parseArray(flowTaskExt.getVariableListJson(), JSONObject.class)); + } + } + return ResponseResult.success(taskInfoVo); + } + + /** + * 获取流程运行时指定任务的信息。 + * + * @param processDefinitionId 流程引擎的定义Id。 + * @param processInstanceId 流程引擎的实例Id。 + * @param taskId 流程引擎的任务Id。 + * @return 任务节点的自定义对象数据。 + */ + @GetMapping("/viewHistoricTaskInfo") + public ResponseResult viewHistoricTaskInfo( + @RequestParam String processDefinitionId, + @RequestParam String processInstanceId, + @RequestParam String taskId) { + String errorMessage; + HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId); + String loginName = TokenData.takeFromRequest().getLoginName(); + if (!StrUtil.equals(taskInstance.getAssignee(), loginName)) { + errorMessage = "数据验证失败,当前用户不是指派人!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + TaskInfoVo taskInfoVo = JSON.parseObject(taskInstance.getFormKey(), TaskInfoVo.class); + FlowTaskExt flowTaskExt = + flowTaskExtService.getByProcessDefinitionIdAndTaskId(processDefinitionId, taskInstance.getTaskDefinitionKey()); + if (flowTaskExt != null) { + if (StrUtil.isNotBlank(flowTaskExt.getOperationListJson())) { + taskInfoVo.setOperationList(JSON.parseArray(flowTaskExt.getOperationListJson(), JSONObject.class)); + } + if (StrUtil.isNotBlank(flowTaskExt.getVariableListJson())) { + taskInfoVo.setVariableList(JSON.parseArray(flowTaskExt.getVariableListJson(), JSONObject.class)); + } + } + return ResponseResult.success(taskInfoVo); + } + + /** + * 获取第一个提交表单数据的任务信息。 + * + * @param processInstanceId 流程实例Id。 + * @return 任务节点的自定义对象数据。 + */ + @GetMapping("/viewInitialHistoricTaskInfo") + public ResponseResult viewInitialHistoricTaskInfo(@RequestParam String processInstanceId) { + String errorMessage; + List taskCommentList = + flowTaskCommentService.getFlowTaskCommentList(processInstanceId); + if (CollUtil.isEmpty(taskCommentList)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + FlowTaskComment taskComment = taskCommentList.get(0); + if (ObjectUtil.notEqual(taskComment.getCreateUserId(), TokenData.takeFromRequest().getUserId())) { + errorMessage = "数据验证失败,当前流程发起人与当前用户不匹配!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + HistoricTaskInstance task = flowApiService.getHistoricTaskInstance(processInstanceId, taskComment.getTaskId()); + if (StrUtil.isBlank(task.getFormKey())) { + errorMessage = "数据验证失败,指定任务的formKey属性不存在,请重新修改流程图!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + TaskInfoVo taskInfo = JSON.parseObject(task.getFormKey(), TaskInfoVo.class); + taskInfo.setTaskKey(task.getTaskDefinitionKey()); + return ResponseResult.success(taskInfo); + } + + /** + * 提交多实例加签。 + * + * @param processInstanceId 流程实例Id。 + * @param taskId 多实例任务的上一级任务Id。 + * @param newAssignees 新的加签人列表,多个指派人之间逗号分隔。 + * @return 应答结果。 + */ + @PostMapping("/submitConsign") + public ResponseResult submitConsign( + @MyRequestBody(required = true) String processInstanceId, + @MyRequestBody(required = true) String taskId, + @MyRequestBody(required = true) String newAssignees) { + String errorMessage; + if (!flowApiService.existActiveProcessInstance(processInstanceId)) { + errorMessage = "数据验证失败,当前流程实例已经结束,不能执行加签!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + HistoricTaskInstance taskInstance = flowApiService.getHistoricTaskInstance(processInstanceId, taskId); + if (taskInstance == null) { + errorMessage = "数据验证失败,当前任务不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!StrUtil.equals(taskInstance.getAssignee(), TokenData.takeFromRequest().getLoginName())) { + errorMessage = "数据验证失败,任务指派人与当前用户不匹配!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + List activeTaskList = flowApiService.getProcessInstanceActiveTaskList(processInstanceId); + Task activeMultiInstanceTask = null; + for (Task activeTask : activeTaskList) { + Object startTaskId = flowApiService.getTaskVariable( + activeTask.getId(), FlowConstant.MULTI_SIGN_START_TASK_VAR); + if (startTaskId != null && startTaskId.toString().equals(taskId)) { + activeMultiInstanceTask = activeTask; + break; + } + } + if (activeMultiInstanceTask == null) { + errorMessage = "数据验证失败,指定加签任务不存在或已审批完毕!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + flowApiService.submitConsign(taskInstance, activeMultiInstanceTask, newAssignees); + return ResponseResult.success(); + } + + /** + * 返回当前用户待办的任务列表。 + * + * @param processDefinitionKey 流程标识。 + * @param pageParam 分页对象。 + * @return 返回当前用户待办的任务列表。如果指定流程标识,则仅返回该流程的待办任务列表。 + */ + @PostMapping("/listRuntimeTask") + public ResponseResult> listRuntimeTask( + @MyRequestBody String processDefinitionKey, + @MyRequestBody(required = true) MyPageParam pageParam) { + String username = TokenData.takeFromRequest().getLoginName(); + MyPageData pageData = flowApiService.getTaskListByUserName(username, processDefinitionKey, pageParam); + List flowTaskVoList = flowApiService.convertToFlowTaskList(pageData.getDataList()); + return ResponseResult.success(MyPageUtil.makeResponseData(flowTaskVoList, pageData.getTotalCount())); + } + + /** + * 返回当前用户待办的任务数量。 + * + * @return 返回当前用户待办的任务数量。 + */ + @PostMapping("/countRuntimeTask") + public ResponseResult countRuntimeTask() { + String username = TokenData.takeFromRequest().getLoginName(); + long totalCount = flowApiService.getTaskCountByUserName(username); + return ResponseResult.success(totalCount); + } + + /** + * 获取当前流程任务的审批列表。 + * + * @param processInstanceId 当前运行时的流程实例Id。 + * @return 当前流程实例的详情数据。 + */ + @GetMapping("/listFlowTaskComment") + public ResponseResult> listFlowTaskComment(@RequestParam String processInstanceId) { + List flowTaskCommentList = + flowTaskCommentService.getFlowTaskCommentList(processInstanceId); + List resultList = FlowTaskComment.INSTANCE.fromModelList(flowTaskCommentList); + return ResponseResult.success(resultList); + } + + /** + * 获取指定流程定义的流程图。 + * + * @param processDefinitionId 流程定义Id。 + * @return 流程图。 + */ + @GetMapping("/viewProcessBpmn") + public ResponseResult viewProcessBpmn(@RequestParam String processDefinitionId) throws IOException { + BpmnXMLConverter converter = new BpmnXMLConverter(); + BpmnModel bpmnModel = flowApiService.getBpmnModelByDefinitionId(processDefinitionId); + byte[] xmlBytes = converter.convertToXML(bpmnModel); + InputStream in = new ByteArrayInputStream(xmlBytes); + return ResponseResult.success(StreamUtils.copyToString(in, StandardCharsets.UTF_8)); + } + + /** + * 获取流程图高亮数据。 + * + * @param processInstanceId 流程实例Id。 + * @return 流程图高亮数据。 + */ + @GetMapping("/viewHighlightFlowData") + public ResponseResult viewHighlightFlowData(@RequestParam String processInstanceId) { + HistoricProcessInstance hpi = flowApiService.getHistoricProcessInstance(processInstanceId); + BpmnModel bpmnModel = flowApiService.getBpmnModelByDefinitionId(hpi.getProcessDefinitionId()); + List processList = bpmnModel.getProcesses(); + List flowElementList = new LinkedList<>(); + processList.forEach(p -> flowElementList.addAll(p.getFlowElements())); + Map allSequenceFlowMap = new HashMap<>(16); + for (FlowElement flowElement : flowElementList) { + if (flowElement instanceof SequenceFlow) { + SequenceFlow sequenceFlow = (SequenceFlow) flowElement; + String ref = sequenceFlow.getSourceRef(); + String targetRef = sequenceFlow.getTargetRef(); + allSequenceFlowMap.put(ref + targetRef, sequenceFlow.getId()); + } + } + Set finishedTaskSet = new LinkedHashSet<>(); + //获取流程实例的历史节点(全部执行过的节点,被拒绝的任务节点将会出现多次) + List activityInstanceList = + flowApiService.getHistoricActivityInstanceList(processInstanceId); + Set finishedTaskSequenceSet = new LinkedHashSet<>(); + for (int i = 0; i < activityInstanceList.size(); i++) { + HistoricActivityInstance current = activityInstanceList.get(i); + if (i != activityInstanceList.size() - 1) { + HistoricActivityInstance next = activityInstanceList.get(i + 1); + finishedTaskSequenceSet.add(current.getActivityId() + next.getActivityId()); + } + finishedTaskSet.add(current.getActivityId()); + } + Set finishedSequenceFlowSet = new HashSet<>(); + finishedTaskSequenceSet.forEach(s -> finishedSequenceFlowSet.add(allSequenceFlowMap.get(s))); + //获取流程实例当前正在待办的节点 + List unfinishedInstanceList = + flowApiService.getHistoricUnfinishedInstanceList(processInstanceId); + Set unfinishedTaskSet = new LinkedHashSet<>(); + for (HistoricActivityInstance unfinishedActivity : unfinishedInstanceList) { + unfinishedTaskSet.add(unfinishedActivity.getActivityId()); + } + JSONObject jsonData = new JSONObject(); + jsonData.put("finishedTaskSet", finishedTaskSet); + jsonData.put("finishedSequenceFlowSet", finishedSequenceFlowSet); + jsonData.put("unfinishedTaskSet", unfinishedTaskSet); + return ResponseResult.success(jsonData); + } + + /** + * 获取当前用户的已办理的审批任务列表。 + * + * @param processDefinitionName 流程名。 + * @param beginDate 流程发起开始时间。 + * @param endDate 流程发起结束时间。 + * @param pageParam 分页对象。 + * @return 查询结果应答。 + */ + @PostMapping("/listHistoricTask") + public ResponseResult>> listHistoricTask( + @MyRequestBody String processDefinitionName, + @MyRequestBody String beginDate, + @MyRequestBody String endDate, + @MyRequestBody(required = true) MyPageParam pageParam) throws ParseException { + MyPageData pageData = + flowApiService.getHistoricTaskInstanceFinishedList(processDefinitionName, beginDate, endDate, pageParam); + List> resultList = new LinkedList<>(); + pageData.getDataList().forEach(instance -> resultList.add(BeanUtil.beanToMap(instance))); + List taskInstanceList = pageData.getDataList(); + if (CollUtil.isNotEmpty(taskInstanceList)) { + Set instanceIdSet = taskInstanceList.stream() + .map(HistoricTaskInstance::getProcessInstanceId).collect(Collectors.toSet()); + List instanceList = flowApiService.getHistoricProcessInstanceList(instanceIdSet); + Map instanceMap = + instanceList.stream().collect(Collectors.toMap(HistoricProcessInstance::getId, c -> c)); + resultList.forEach(result -> { + HistoricProcessInstance instance = instanceMap.get(result.get("processInstanceId").toString()); + result.put("processDefinitionKey", instance.getProcessDefinitionKey()); + result.put("processDefinitionName", instance.getProcessDefinitionName()); + result.put("startUser", instance.getStartUserId()); + }); + } + return ResponseResult.success(MyPageUtil.makeResponseData(resultList, pageData.getTotalCount())); + } + + /** + * 根据输入参数查询,当前用户的历史流程数据。 + * + * @param processDefinitionName 流程名。 + * @param beginDate 流程发起开始时间。 + * @param endDate 流程发起结束时间。 + * @param pageParam 分页对象。 + * @return 查询结果应答。 + */ + @PostMapping("/listHistoricProcessInstance") + public ResponseResult>> listHistoricProcessInstance( + @MyRequestBody String processDefinitionName, + @MyRequestBody String beginDate, + @MyRequestBody String endDate, + @MyRequestBody(required = true) MyPageParam pageParam) throws ParseException { + String loginName = TokenData.takeFromRequest().getLoginName(); + MyPageData pageData = flowApiService.getHistoricProcessInstanceList( + null, processDefinitionName, loginName, beginDate, endDate, pageParam, true); + List> resultList = new LinkedList<>(); + pageData.getDataList().forEach(instance -> resultList.add(BeanUtil.beanToMap(instance))); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList, pageData.getTotalCount())); + } + + /** + * 根据输入参数查询,所有历史流程数据。 + * + * @param processDefinitionName 流程名。 + * @param startUser 流程发起用户。 + * @param beginDate 流程发起开始时间。 + * @param endDate 流程发起结束时间。 + * @param pageParam 分页对象。 + * @return 查询结果。 + */ + @PostMapping("/listAllHistoricProcessInstance") + public ResponseResult>> listAllHistoricProcessInstance( + @MyRequestBody String processDefinitionName, + @MyRequestBody String startUser, + @MyRequestBody String beginDate, + @MyRequestBody String endDate, + @MyRequestBody(required = true) MyPageParam pageParam) throws ParseException { + MyPageData pageData = flowApiService.getHistoricProcessInstanceList( + null, processDefinitionName, startUser, beginDate, endDate, pageParam, false); + List> resultList = new LinkedList<>(); + pageData.getDataList().forEach(instance -> resultList.add(BeanUtil.beanToMap(instance))); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList, pageData.getTotalCount())); + } + + /** + * 取消工作流工单,仅当没有进入任何审批流程之前,才可以取消工单。 + * + * @param workOrderId 工单Id。 + * @param cancelReason 取消原因。 + * @return 应答结果。 + */ + @PostMapping("/cancelWorkOrder") + public ResponseResult cancelWorkOrder( + @MyRequestBody(required = true) Long workOrderId, + @MyRequestBody(required = true) String cancelReason) { + FlowWorkOrder flowWorkOrder = flowWorkOrderService.getById(workOrderId); + if (flowWorkOrder == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + String errorMessage; + if (!flowWorkOrder.getFlowStatus().equals(FlowTaskStatus.SUBMITTED)) { + errorMessage = "数据验证失败,当前流程已经进入审批状态,不能撤销工单!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!flowWorkOrder.getCreateUserId().equals(TokenData.takeFromRequest().getUserId())) { + errorMessage = "数据验证失败,当前用户不是工单所有者,不能撤销工单!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + CallResult result = flowApiService.stopProcessInstance( + flowWorkOrder.getProcessInstanceId(), cancelReason, true); + if (!result.isSuccess()) { + return ResponseResult.errorFrom(result); + } + return ResponseResult.success(); + } + + /** + * 终止流程实例,将任务从当前节点直接流转到主流程的结束事件。 + * + * @param processInstanceId 流程实例Id。 + * @param stopReason 停止原因。 + * @return 执行结果应答。 + */ + @PostMapping("/stopProcessInstance") + public ResponseResult stopProcessInstance( + @MyRequestBody(required = true) String processInstanceId, + @MyRequestBody(required = true) String stopReason) { + CallResult result = flowApiService.stopProcessInstance(processInstanceId, stopReason, false); + if (!result.isSuccess()) { + return ResponseResult.errorFrom(result); + } + return ResponseResult.success(); + } + + /** + * 删除流程实例。 + * + * @param processInstanceId 流程实例Id。 + * @return 执行结果应答。 + */ + @PostMapping("/deleteProcessInstance") + public ResponseResult deleteProcessInstance(@MyRequestBody(required = true) String processInstanceId) { + flowApiService.deleteProcessInstance(processInstanceId); + return ResponseResult.success(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowCategoryMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowCategoryMapper.java new file mode 100644 index 00000000..dc25d705 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowCategoryMapper.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.flow.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.flow.model.FlowCategory; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * FlowCategory数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowCategoryMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param flowCategoryFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getFlowCategoryList( + @Param("flowCategoryFilter") FlowCategory flowCategoryFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryMapper.java new file mode 100644 index 00000000..6e6ca9f3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryMapper.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.flow.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.flow.model.FlowEntry; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * FlowEntry数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowEntryMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param flowEntryFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getFlowEntryList( + @Param("flowEntryFilter") FlowEntry flowEntryFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryPublishMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryPublishMapper.java new file mode 100644 index 00000000..eacd4652 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryPublishMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.flow.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.flow.model.FlowEntryPublish; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowEntryPublishMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryPublishVariableMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryPublishVariableMapper.java new file mode 100644 index 00000000..5d714b81 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryPublishVariableMapper.java @@ -0,0 +1,22 @@ +package com.flow.demo.common.flow.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.flow.model.FlowEntryPublishVariable; + +import java.util.List; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowEntryPublishVariableMapper extends BaseDaoMapper { + + /** + * 批量插入流程发布的变量列表。 + * + * @param entryPublishVariableList 流程发布的变量列表。 + */ + void insertList(List entryPublishVariableList); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryVariableMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryVariableMapper.java new file mode 100644 index 00000000..2ca74e77 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowEntryVariableMapper.java @@ -0,0 +1,27 @@ +package com.flow.demo.common.flow.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.flow.model.FlowEntryVariable; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 流程变量数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowEntryVariableMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param flowEntryVariableFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getFlowEntryVariableList( + @Param("flowEntryVariableFilter") FlowEntryVariable flowEntryVariableFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowTaskCommentMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowTaskCommentMapper.java new file mode 100644 index 00000000..b8e6bfd5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowTaskCommentMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.flow.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.flow.model.FlowTaskComment; + +/** + * 流程任务批注数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowTaskCommentMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowTaskExtMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowTaskExtMapper.java new file mode 100644 index 00000000..78daae81 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowTaskExtMapper.java @@ -0,0 +1,22 @@ +package com.flow.demo.common.flow.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.flow.model.FlowTaskExt; + +import java.util.List; + +/** + * 流程任务扩展数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowTaskExtMapper extends BaseDaoMapper { + + /** + * 批量插入流程任务扩展信息列表。 + * + * @param flowTaskExtList 流程任务扩展信息列表。 + */ + void insertList(List flowTaskExtList); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowWorkOrderMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowWorkOrderMapper.java new file mode 100644 index 00000000..e91b256b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/FlowWorkOrderMapper.java @@ -0,0 +1,28 @@ +package com.flow.demo.common.flow.dao; + +import com.flow.demo.common.core.annotation.EnableDataPerm; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.flow.model.FlowWorkOrder; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 工作流工单表数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EnableDataPerm +public interface FlowWorkOrderMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param flowWorkOrderFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getFlowWorkOrderList( + @Param("flowWorkOrderFilter") FlowWorkOrder flowWorkOrderFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowCategoryMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowCategoryMapper.xml new file mode 100644 index 00000000..dae5f2d0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowCategoryMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryMapper.xml new file mode 100644 index 00000000..99974c37 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryMapper.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_flow_entry.process_definition_name = #{flowEntryFilter.processDefinitionName} + + + AND zz_flow_entry.process_definition_key = #{flowEntryFilter.processDefinitionKey} + + + AND zz_flow_entry.category_id = #{flowEntryFilter.categoryId} + + + AND zz_flow_entry.status = #{flowEntryFilter.status} + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryPublishMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryPublishMapper.xml new file mode 100644 index 00000000..c90eba57 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryPublishMapper.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryPublishVariableMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryPublishVariableMapper.xml new file mode 100644 index 00000000..7b864175 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryPublishVariableMapper.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + INSERT INTO zz_flow_entry_publish_variable VALUES + + (#{item.variableId}, + #{item.entryPublishId}, + #{item.variableName}, + #{item.showName}, + #{item.variableType}, + #{item.bindDatasourceId}, + #{item.bindRelationId}, + #{item.bindColumnId}, + #{item.builtin}) + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryVariableMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryVariableMapper.xml new file mode 100644 index 00000000..a9910c5c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowEntryVariableMapper.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_flow_entry_variable.entry_id = #{flowEntryVariableFilter.entryId} + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowTaskCommentMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowTaskCommentMapper.xml new file mode 100644 index 00000000..61cfb2b9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowTaskCommentMapper.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowTaskExtMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowTaskExtMapper.xml new file mode 100644 index 00000000..e2599500 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowTaskExtMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + INSERT INTO zz_flow_task_ext VALUES + + (#{item.processDefinitionId}, + #{item.taskId}, + #{item.operationListJson}, + #{item.variableListJson}, + #{item.assigneeListJson}, + #{item.groupType}) + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowWorkOrderMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowWorkOrderMapper.xml new file mode 100644 index 00000000..0b6f367a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dao/mapper/FlowWorkOrderMapper.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_flow_work_order.deleted_flag = ${@com.flow.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + + + + AND zz_flow_work_order.process_definition_key = #{flowWorkOrderFilter.processDefinitionKey} + + + AND zz_flow_work_order.flow_status = #{flowWorkOrderFilter.flowStatus} + + + AND zz_flow_work_order.create_time >= #{flowWorkOrderFilter.createTimeStart} + + + AND zz_flow_work_order.create_time <= #{flowWorkOrderFilter.createTimeEnd} + + + AND zz_flow_work_order.create_user_id = #{flowWorkOrderFilter.createUserId} + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowCategoryDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowCategoryDto.java new file mode 100644 index 00000000..3a2dfca7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowCategoryDto.java @@ -0,0 +1,41 @@ +package com.flow.demo.common.flow.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 流程分类的Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowCategoryDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long categoryId; + + /** + * 显示名称。 + */ + @NotBlank(message = "数据验证失败,显示名称不能为空!") + private String name; + + /** + * 分类编码。 + */ + @NotBlank(message = "数据验证失败,分类编码不能为空!") + private String code; + + /** + * 实现顺序。 + */ + @NotNull(message = "数据验证失败,实现顺序不能为空!") + private Integer showOrder; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowEntryDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowEntryDto.java new file mode 100644 index 00000000..733be510 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowEntryDto.java @@ -0,0 +1,77 @@ +package com.flow.demo.common.flow.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.flow.model.constant.FlowBindFormType; +import com.flow.demo.common.flow.model.constant.FlowEntryStatus; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 流程的Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowEntryDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键不能为空!", groups = {UpdateGroup.class}) + private Long entryId; + + /** + * 流程名称。 + */ + @NotBlank(message = "数据验证失败,流程名称不能为空!") + private String processDefinitionName; + + /** + * 流程标识Key。 + */ + @NotBlank(message = "数据验证失败,流程标识Key不能为空!") + private String processDefinitionKey; + + /** + * 流程分类。 + */ + @NotNull(message = "数据验证失败,流程分类不能为空!") + private Long categoryId; + + /** + * 流程状态。 + */ + @ConstDictRef(constDictClass = FlowEntryStatus.class, message = "数据验证失败,工作流状态为无效值!") + private Integer status; + + /** + * 流程定义的xml。 + */ + private String bpmnXml; + + /** + * 绑定表单类型。 + */ + @ConstDictRef(constDictClass = FlowBindFormType.class, message = "数据验证失败,工作流绑定表单类型为无效值!") + @NotNull(message = "数据验证失败,工作流绑定表单类型不能为空!") + private Integer bindFormType; + + /** + * 在线表单的页面Id。 + */ + private Long pageId; + + /** + * 在线表单Id。 + */ + private Long defaultFormId; + + /** + * 在线表单的缺省路由名称。 + */ + private String defaultRouterName; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowEntryVariableDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowEntryVariableDto.java new file mode 100644 index 00000000..8913c1ed --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowEntryVariableDto.java @@ -0,0 +1,70 @@ +package com.flow.demo.common.flow.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.flow.model.constant.FlowVariableType; +import lombok.Data; + +import javax.validation.constraints.*; + +/** + * 流程变量Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowEntryVariableDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long variableId; + + /** + * 流程Id。 + */ + @NotNull(message = "数据验证失败,流程Id不能为空!") + private Long entryId; + + /** + * 变量名。 + */ + @NotBlank(message = "数据验证失败,变量名不能为空!") + private String variableName; + + /** + * 显示名。 + */ + @NotBlank(message = "数据验证失败,显示名不能为空!") + private String showName; + + /** + * 流程变量类型。 + */ + @ConstDictRef(constDictClass = FlowVariableType.class, message = "数据验证失败,流程变量类型为无效值!") + @NotNull(message = "数据验证失败,流程变量类型不能为空!") + private Integer variableType; + + /** + * 绑定数据源Id。 + */ + private Long bindDatasourceId; + + /** + * 绑定数据源关联Id。 + */ + private Long bindRelationId; + + /** + * 绑定字段Id。 + */ + private Long bindColumnId; + + /** + * 是否内置。 + */ + @NotNull(message = "数据验证失败,是否内置不能为空!") + private Boolean builtin; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowTaskCommentDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowTaskCommentDto.java new file mode 100644 index 00000000..dcca41b7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowTaskCommentDto.java @@ -0,0 +1,33 @@ +package com.flow.demo.common.flow.dto; + +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 流程任务的批注。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowTaskCommentDto { + + /** + * 流程任务触发按钮类型,内置值可参考FlowTaskButton。 + */ + @NotNull(message = "数据验证失败,任务的审批类型不能为空!") + private String approvalType; + + /** + * 流程任务的批注内容。 + */ + @NotBlank(message = "数据验证失败,任务审批内容不能为空!") + private String comment; + + /** + * 委托指定人,比如加签、转办等。 + */ + private String delegateAssginee; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowWorkOrderDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowWorkOrderDto.java new file mode 100644 index 00000000..ee9ecffa --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/dto/FlowWorkOrderDto.java @@ -0,0 +1,28 @@ +package com.flow.demo.common.flow.dto; + +import lombok.Data; + +/** + * 工作流工单Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowWorkOrderDto { + + /** + * 流程状态。 + */ + private Integer flowStatus; + + /** + * createTime 范围过滤起始值(>=)。 + */ + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + private String createTimeEnd; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/exception/FlowOperationException.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/exception/FlowOperationException.java new file mode 100644 index 00000000..d615c2a9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/exception/FlowOperationException.java @@ -0,0 +1,35 @@ +package com.flow.demo.common.flow.exception; + +/** + * 流程操作异常。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class FlowOperationException extends RuntimeException { + + /** + * 构造函数。 + */ + public FlowOperationException() { + + } + + /** + * 构造函数。 + * + * @param throwable 引发异常对象。 + */ + public FlowOperationException(Throwable throwable) { + super(throwable); + } + + /** + * 构造函数。 + * + * @param msg 错误信息。 + */ + public FlowOperationException(String msg) { + super(msg); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/DeptPostLeaderListener.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/DeptPostLeaderListener.java new file mode 100644 index 00000000..cd517eb4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/DeptPostLeaderListener.java @@ -0,0 +1,34 @@ +package com.flow.demo.common.flow.listener; + +import com.flow.demo.common.core.util.ApplicationContextHolder; +import com.flow.demo.common.flow.constant.FlowConstant; +import com.flow.demo.common.flow.service.FlowApiService; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.task.service.delegate.DelegateTask; + +import java.util.Map; + +/** + * 当用户任务的候选组为本部门领导岗位时,该监听器会在任务创建时,获取当前流程实例发起人的部门领导。 + * 并将其指派为当前任务的候选组。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class DeptPostLeaderListener implements TaskListener { + + private final FlowApiService flowApiService = ApplicationContextHolder.getBean(FlowApiService.class); + + @Override + public void notify(DelegateTask delegateTask) { + HistoricProcessInstance instance = + flowApiService.getHistoricProcessInstance(delegateTask.getProcessInstanceId()); + Map variables = delegateTask.getVariables(); + if (variables.get(FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR) == null) { + delegateTask.setAssignee(variables.get(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR).toString()); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/UpDeptPostLeaderListener.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/UpDeptPostLeaderListener.java new file mode 100644 index 00000000..4be3035e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/UpDeptPostLeaderListener.java @@ -0,0 +1,34 @@ +package com.flow.demo.common.flow.listener; + +import com.flow.demo.common.core.util.ApplicationContextHolder; +import com.flow.demo.common.flow.constant.FlowConstant; +import com.flow.demo.common.flow.service.FlowApiService; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.task.service.delegate.DelegateTask; + +import java.util.Map; + +/** + * 当用户任务的候选组为上级部门领导岗位时,该监听器会在任务创建时,获取当前流程实例发起人的部门领导。 + * 并将其指派为当前任务的候选组。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class UpDeptPostLeaderListener implements TaskListener { + + private final FlowApiService flowApiService = ApplicationContextHolder.getBean(FlowApiService.class); + + @Override + public void notify(DelegateTask delegateTask) { + HistoricProcessInstance instance = + flowApiService.getHistoricProcessInstance(delegateTask.getProcessInstanceId()); + Map variables = delegateTask.getVariables(); + if (variables.get(FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR) == null) { + delegateTask.setAssignee(variables.get(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR).toString()); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/UpdateFlowStatusListener.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/UpdateFlowStatusListener.java new file mode 100644 index 00000000..871248c4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/listener/UpdateFlowStatusListener.java @@ -0,0 +1,31 @@ +package com.flow.demo.common.flow.listener; + +import cn.hutool.core.util.StrUtil; +import com.flow.demo.common.core.util.ApplicationContextHolder; +import com.flow.demo.common.flow.service.FlowWorkOrderService; +import com.flow.demo.common.flow.constant.FlowTaskStatus; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.delegate.DelegateExecution; +import org.flowable.engine.delegate.ExecutionListener; + +/** + * 流程实例监听器,在流程实例结束的时候更新流程工单表的审批状态字段。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class UpdateFlowStatusListener implements ExecutionListener { + + private final FlowWorkOrderService flowWorkOrderService = + ApplicationContextHolder.getBean(FlowWorkOrderService.class); + + @Override + public void notify(DelegateExecution execution) { + if (!StrUtil.equals("end", execution.getEventName())) { + return; + } + String processInstanceId = execution.getProcessInstanceId(); + flowWorkOrderService.updateFlowStatusByProcessInstanceId(processInstanceId, FlowTaskStatus.FINISHED); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowCategory.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowCategory.java new file mode 100644 index 00000000..f5114eca --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowCategory.java @@ -0,0 +1,74 @@ +package com.flow.demo.common.flow.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.flow.vo.FlowCategoryVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.Date; + +/** + * 流程分类的实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_flow_category") +public class FlowCategory { + + /** + * 主键Id。 + */ + @TableId(value = "category_id") + private Long categoryId; + + /** + * 显示名称。 + */ + @TableField(value = "name") + private String name; + + /** + * 分类编码。 + */ + @TableField(value = "code") + private String code; + + /** + * 实现顺序。 + */ + @TableField(value = "show_order") + private Integer showOrder; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + @Mapper + public interface FlowCategoryModelMapper extends BaseModelMapper { + } + public static final FlowCategoryModelMapper INSTANCE = Mappers.getMapper(FlowCategoryModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntry.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntry.java new file mode 100644 index 00000000..342747a4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntry.java @@ -0,0 +1,155 @@ +package com.flow.demo.common.flow.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationOneToOne; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.flow.vo.FlowEntryVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.Date; + +/** + * 流程的实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_flow_entry") +public class FlowEntry { + + /** + * 主键。 + */ + @TableId(value = "entry_id") + private Long entryId; + + /** + * 流程名称。 + */ + @TableField(value = "process_definition_name") + private String processDefinitionName; + + /** + * 流程标识Key。 + */ + @TableField(value = "process_definition_key") + private String processDefinitionKey; + + /** + * 流程分类。 + */ + @TableField(value = "category_id") + private Long categoryId; + + /** + * 工作流部署的发布主版本Id。 + */ + @TableField(value = "main_entry_publish_id") + private Long mainEntryPublishId; + + /** + * 最新发布时间。 + */ + @TableField(value = "lastest_publish_time") + private Date lastestPublishTime; + + /** + * 流程状态。 + */ + @TableField(value = "status") + private Integer status; + + /** + * 流程定义的xml。 + */ + @TableField(value = "bpmn_xml") + private String bpmnXml; + + /** + * 绑定表单类型。 + */ + @TableField(value = "bind_form_type") + private Integer bindFormType; + + /** + * 在线表单的页面Id。 + */ + @TableField(value = "page_id") + private Long pageId; + + /** + * 在线表单Id。 + */ + @TableField(value = "default_form_id") + private Long defaultFormId; + + /** + * 静态表单的缺省路由名称。 + */ + @TableField(value = "default_router_name") + private String defaultRouterName; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + @TableField(exist = false) + private FlowEntryPublish mainFlowEntryPublish; + + @RelationOneToOne( + masterIdField = "categoryId", + slaveServiceName = "flowCategoryService", + slaveModelClass = FlowCategory.class, + slaveIdField = "categoryId") + @TableField(exist = false) + private FlowCategory flowCategory; + + @Mapper + public interface FlowEntryModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param flowEntryVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "mainFlowEntryPublish", expression = "java(mapToBean(flowEntryVo.getMainFlowEntryPublish(), com.flow.demo.common.flow.model.FlowEntryPublish.class))") + @Mapping(target = "flowCategory", expression = "java(mapToBean(flowEntryVo.getFlowCategory(), com.flow.demo.common.flow.model.FlowCategory.class))") + @Override + FlowEntry toModel(FlowEntryVo flowEntryVo); + /** + * 转换实体对象到VO对象。 + * + * @param flowEntry 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "mainFlowEntryPublish", expression = "java(beanToMap(flowEntry.getMainFlowEntryPublish(), false))") + @Mapping(target = "flowCategory", expression = "java(beanToMap(flowEntry.getFlowCategory(), false))") + @Override + FlowEntryVo fromModel(FlowEntry flowEntry); + } + public static final FlowEntryModelMapper INSTANCE = Mappers.getMapper(FlowEntryModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryPublish.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryPublish.java new file mode 100644 index 00000000..41d621e0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryPublish.java @@ -0,0 +1,77 @@ +package com.flow.demo.common.flow.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +import java.util.Date; + +/** + * 流程发布数据的实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_flow_entry_publish") +public class FlowEntryPublish { + + /** + * 主键Id。 + */ + @TableId(value = "entry_publish_id") + private Long entryPublishId; + + /** + * 流程Id。 + */ + @TableField(value = "entry_id") + private Long entryId; + + /** + * 流程引擎的部署Id。 + */ + @TableField(value = "deploy_id") + private String deployId; + + /** + * 流程引擎中的流程定义Id。 + */ + @TableField(value = "process_definition_id") + private String processDefinitionId; + + /** + * 发布版本。 + */ + @TableField(value = "publish_version") + private Integer publishVersion; + + /** + * 激活状态。 + */ + @TableField(value = "active_status") + private Boolean activeStatus; + + /** + * 是否为主版本。 + */ + @TableField(value = "main_version") + private Boolean mainVersion; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 发布时间。 + */ + @TableField(value = "publish_time") + private Date publishTime; + + /** + * 第一个非开始节点任务的附加信息。 + */ + @TableField(value = "init_task_info") + private String initTaskInfo; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryPublishVariable.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryPublishVariable.java new file mode 100644 index 00000000..5b7ef76b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryPublishVariable.java @@ -0,0 +1,69 @@ +package com.flow.demo.common.flow.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * FlowEntryPublishVariable实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_flow_entry_publish_variable") +public class FlowEntryPublishVariable { + + /** + * 主键Id。 + */ + @TableId(value = "variable_id") + private Long variableId; + + /** + * 流程Id。 + */ + @TableField(value = "entry_publish_id") + private Long entryPublishId; + + /** + * 变量名。 + */ + @TableField(value = "variable_name") + private String variableName; + + /** + * 显示名。 + */ + @TableField(value = "show_name") + private String showName; + + /** + * 变量类型。 + */ + @TableField(value = "variable_type") + private Integer variableType; + + /** + * 绑定数据源Id。 + */ + @TableField(value = "bind_datasource_id") + private Long bindDatasourceId; + + /** + * 绑定数据源关联Id。 + */ + @TableField(value = "bind_relation_id") + private Long bindRelationId; + + /** + * 绑定字段Id。 + */ + @TableField(value = "bind_column_id") + private Long bindColumnId; + + /** + * 是否内置。 + */ + @TableField(value = "builtin") + private Boolean builtin; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryVariable.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryVariable.java new file mode 100644 index 00000000..5c43391f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowEntryVariable.java @@ -0,0 +1,86 @@ +package com.flow.demo.common.flow.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.flow.vo.FlowEntryVariableVo; +import lombok.Data; +import org.mapstruct.*; +import org.mapstruct.factory.Mappers; + +import java.util.Date; + +/** + * 流程变量实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_flow_entry_variable") +public class FlowEntryVariable { + + /** + * 主键Id。 + */ + @TableId(value = "variable_id") + private Long variableId; + + /** + * 流程Id。 + */ + @TableField(value = "entry_id") + private Long entryId; + + /** + * 变量名。 + */ + @TableField(value = "variable_name") + private String variableName; + + /** + * 显示名。 + */ + @TableField(value = "show_name") + private String showName; + + /** + * 流程变量类型。 + */ + @TableField(value = "variable_type") + private Integer variableType; + + /** + * 绑定数据源Id。 + */ + @TableField(value = "bind_datasource_id") + private Long bindDatasourceId; + + /** + * 绑定数据源关联Id。 + */ + @TableField(value = "bind_relation_id") + private Long bindRelationId; + + /** + * 绑定字段Id。 + */ + @TableField(value = "bind_column_id") + private Long bindColumnId; + + /** + * 是否内置。 + */ + @TableField(value = "builtin") + private Boolean builtin; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + @Mapper + public interface FlowEntryVariableModelMapper extends BaseModelMapper { + } + public static final FlowEntryVariableModelMapper INSTANCE = Mappers.getMapper(FlowEntryVariableModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowTaskComment.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowTaskComment.java new file mode 100644 index 00000000..0ddcff3e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowTaskComment.java @@ -0,0 +1,106 @@ +package com.flow.demo.common.flow.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.flow.vo.FlowTaskCommentVo; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.flowable.task.api.TaskInfo; +import org.mapstruct.*; +import org.mapstruct.factory.Mappers; + +import java.util.Date; + +/** + * FlowTaskComment实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@NoArgsConstructor +@TableName(value = "zz_flow_task_comment") +public class FlowTaskComment { + + /** + * 主键Id。 + */ + @TableId(value = "id") + private Long id; + + /** + * 流程实例Id。 + */ + @TableField(value = "process_instance_id") + private String processInstanceId; + + /** + * 任务Id。 + */ + @TableField(value = "task_id") + private String taskId; + + /** + * 任务标识。 + */ + @TableField(value = "task_key") + private String taskKey; + + /** + * 任务名称。 + */ + @TableField(value = "task_name") + private String taskName; + + /** + * 审批类型。 + */ + @TableField(value = "approval_type") + private String approvalType; + + /** + * 批注内容。 + */ + @TableField(value = "comment") + private String comment; + + /** + * 委托指定人,比如加签、转办等。 + */ + @TableField(value = "delegate_assignee") + private String delegateAssginee; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 创建者显示名。 + */ + @TableField(value = "create_username") + private String createUsername; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + public FlowTaskComment(TaskInfo task) { + this.fillWith(task); + } + + public void fillWith(TaskInfo task) { + this.taskId = task.getId(); + this.taskKey = task.getTaskDefinitionKey(); + this.taskName = task.getName(); + this.processInstanceId = task.getProcessInstanceId(); + } + + @Mapper + public interface FlowTaskCommentModelMapper extends BaseModelMapper { + } + public static final FlowTaskCommentModelMapper INSTANCE = Mappers.getMapper(FlowTaskCommentModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowTaskExt.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowTaskExt.java new file mode 100644 index 00000000..5b7791b6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowTaskExt.java @@ -0,0 +1,51 @@ +package com.flow.demo.common.flow.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 流程任务扩展实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_flow_task_ext") +public class FlowTaskExt { + + /** + * 流程引擎的定义Id。 + */ + @TableField(value = "process_definition_id") + private String processDefinitionId; + + /** + * 流程引擎任务Id。 + */ + @TableField(value = "task_id") + private String taskId; + + /** + * 操作列表JSON。 + */ + @TableField(value = "operation_list_json") + private String operationListJson; + + /** + * 变量列表JSON。 + */ + @TableField(value = "variable_list_json") + private String variableListJson; + + /** + * 存储多实例的assigneeList的JSON。 + */ + @TableField(value = "assignee_list_json") + private String assigneeListJson; + + /** + * 分组类型。 + */ + @TableField(value = "group_type") + private String groupType; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowWorkOrder.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowWorkOrder.java new file mode 100644 index 00000000..27114899 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/FlowWorkOrder.java @@ -0,0 +1,140 @@ +package com.flow.demo.common.flow.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.DeptFilterColumn; +import com.flow.demo.common.core.annotation.RelationConstDict; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.flow.constant.FlowTaskStatus; +import com.flow.demo.common.flow.vo.FlowWorkOrderVo; +import lombok.Data; +import org.mapstruct.*; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.Map; + +/** + * 工作流工单实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_flow_work_order") +public class FlowWorkOrder { + + /** + * 主键Id。 + */ + @TableId(value = "work_order_id") + private Long workOrderId; + + /** + * 流程定义标识。 + */ + @TableField(value = "process_definition_key") + private String processDefinitionKey; + + /** + * 流程名称。 + */ + @TableField(value = "process_definition_name") + private String processDefinitionName; + + /** + * 流程引擎的定义Id。 + */ + @TableField(value = "process_definition_id") + private String processDefinitionId; + + /** + * 流程实例Id。 + */ + @TableField(value = "process_instance_id") + private String processInstanceId; + + /** + * 在线表单的主表Id。 + */ + @TableField(value = "online_table_id") + private Long onlineTableId; + + /** + * 业务主键值。 + */ + @TableField(value = "business_key") + private String businessKey; + + /** + * 流程状态。 + */ + @TableField(value = "flow_status") + private Integer flowStatus; + + /** + * 提交用户登录名称。 + */ + @TableField(value = "submit_username") + private String submitUsername; + + /** + * 提交用户所在部门Id。 + */ + @DeptFilterColumn + @TableField(value = "dept_id") + private Long deptId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 更新者Id。 + */ + @TableField(value = "update_user_id") + private Long updateUserId; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 创建者Id。 + */ + @TableField(value = "create_user_id") + private Long createUserId; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + /** + * createTime 范围过滤起始值(>=)。 + */ + @TableField(exist = false) + private String createTimeStart; + + /** + * createTime 范围过滤结束值(<=)。 + */ + @TableField(exist = false) + private String createTimeEnd; + + @RelationConstDict( + masterIdField = "flowStatus", + constantDictClass = FlowTaskStatus.class) + @TableField(exist = false) + private Map flowStatusDictMap; + + @Mapper + public interface FlowWorkOrderModelMapper extends BaseModelMapper { + } + public static final FlowWorkOrderModelMapper INSTANCE = Mappers.getMapper(FlowWorkOrderModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowBindFormType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowBindFormType.java new file mode 100644 index 00000000..b9f13da9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowBindFormType.java @@ -0,0 +1,44 @@ +package com.flow.demo.common.flow.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 工作流绑定表单类型。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FlowBindFormType { + + /** + * 在线表单。 + */ + public static final int ONLINE_FORM = 0; + /** + * 路由表单。 + */ + public static final int ROUTER_FORM = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(ONLINE_FORM, "在线表单"); + DICT_MAP.put(ROUTER_FORM, "路由表单"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FlowBindFormType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowEntryStatus.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowEntryStatus.java new file mode 100644 index 00000000..b33e4858 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowEntryStatus.java @@ -0,0 +1,44 @@ +package com.flow.demo.common.flow.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 工作流状态。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FlowEntryStatus { + + /** + * 未发布。 + */ + public static final int UNPUBLISHED = 0; + /** + * 已发布。 + */ + public static final int PUBLISHED = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(UNPUBLISHED, "未发布"); + DICT_MAP.put(PUBLISHED, "已发布"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FlowEntryStatus() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowVariableType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowVariableType.java new file mode 100644 index 00000000..d54fa2f9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/model/constant/FlowVariableType.java @@ -0,0 +1,44 @@ +package com.flow.demo.common.flow.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 流程变量类型。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FlowVariableType { + + /** + * 流程实例变量。 + */ + public static final int INSTANCE = 0; + /** + * 任务变量。 + */ + public static final int TASK = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(INSTANCE, "流程实例变量"); + DICT_MAP.put(TASK, "任务变量"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FlowVariableType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/object/FlowTaskExtMultiInstance.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/object/FlowTaskExtMultiInstance.java new file mode 100644 index 00000000..0566206c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/object/FlowTaskExtMultiInstance.java @@ -0,0 +1,29 @@ +package com.flow.demo.common.flow.object; + +import lombok.Data; + +import java.util.List; + + +/** + * 流程任务扩展属性中,表示多实例任务的扩展对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowTaskExtMultiInstance { + + public static final String ASSIGNEE_TYPE_ASSIGNEE = "assignee"; + public static final String ASSIGNEE_TYPE_GROUPID = "groupId"; + + /** + * 指派人类型。目前支持 assignee、groupId。 + */ + private String assigneeType; + + /** + * 指派人登录名列表。 + */ + private List assigneeList; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowApiService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowApiService.java new file mode 100644 index 00000000..c7312f0c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowApiService.java @@ -0,0 +1,354 @@ +package com.flow.demo.common.flow.service; + +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.object.MyPageData; +import com.flow.demo.common.core.object.MyPageParam; +import com.flow.demo.common.flow.model.FlowTaskComment; +import com.flow.demo.common.flow.vo.FlowTaskVo; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.delegate.ExecutionListener; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.engine.history.HistoricActivityInstance; +import org.flowable.engine.history.HistoricProcessInstance; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskInfo; +import org.flowable.task.api.history.HistoricTaskInstance; + +import java.text.ParseException; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * 流程引擎API的接口封装服务。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowApiService { + + /** + * 启动流程实例。 + * + * @param processDefinitionId 流程定义Id。 + */ + void start(String processDefinitionId); + + /** + * 启动流程实例,如果当前登录用户为第一个用户任务的指派者,或者Assginee为流程启动人变量时, + * 则自动完成第一个用户任务。 + * + * @param processDefinitionId 流程定义Id。 + * @param dataId 当前流程主表的主键数据。 + * @param flowTaskComment 审批对象。 + * @param taskVariableData 流程任务的变量数据。 + * @return 新启动的流程实例。 + */ + ProcessInstance startAndTakeFirst( + String processDefinitionId, Object dataId, FlowTaskComment flowTaskComment, JSONObject taskVariableData); + + /** + * 多实例加签。 + * + * @param startTaskInstance 会签对象的发起任务实例。 + * @param multiInstanceActiveTask 正在执行的多实例任务对象。 + * @param newAssignees 新指派人,多个指派人之间逗号分隔。 + */ + void submitConsign(HistoricTaskInstance startTaskInstance, Task multiInstanceActiveTask, String newAssignees); + + /** + * 完成任务,同时提交审批数据。 + * + * @param task 工作流任务对象。 + * @param flowTaskComment 审批对象。 + * @param taskVariableData 流程任务的变量数据。 + */ + void completeTask(Task task, FlowTaskComment flowTaskComment, JSONObject taskVariableData); + + /** + * 判断当前登录用户是否为流程实例中的用户任务的指派人。或是候选人之一,如果是候选人则拾取该任务并成为指派人。 + * 如果都不是,就会返回具体的错误信息。 + * + * @param task 流程实例中的用户任务。 + * @return 调用结果。 + */ + CallResult verifyAssigneeOrCandidateAndClaim(Task task); + + /** + * 初始化并返回流程实例的变量Map。 + * @param processDefinitionId 流程定义Id。 + * @return 初始化后的流程实例变量Map。 + */ + Map initAndGetProcessInstanceVariables(String processDefinitionId); + + /** + * 判断当前登录用户是否为流程实例中的用户任务的指派人。或是候选人之一。 + * + * @param task 流程实例中的用户任务。 + * @return 是返回true,否则false。 + */ + boolean isAssigneeOrCandidate(TaskInfo task); + + /** + * 判断当前登录用户是否为流程实例的发起人。 + * + * @param processInstanceId 流程实例Id。 + * @return 是返回true,否则false。 + */ + boolean isProcessInstanceStarter(String processInstanceId); + + /** + * 为流程实例设置BusinessKey。 + * + * @param processInstanceId 流程实例Id。 + * @param dataId 通常为主表的主键Id。 + */ + void setBusinessKeyForProcessInstance(String processInstanceId, Object dataId); + + /** + * 判断指定的流程实例Id是否存在。 + * + * @param processInstanceId 流程实例Id。 + * @return 存在返回true,否则false。 + */ + boolean existActiveProcessInstance(String processInstanceId); + + /** + * 获取指定的流程实例对象。 + * + * @param processInstanceId 流程实例Id。 + * @return 流程实例对象。 + */ + ProcessInstance getProcessInstance(String processInstanceId); + + /** + * 获取流程实例的列表。 + * + * @param processInstanceIdSet 流程实例Id集合。 + * @return 流程实例列表。 + */ + List getProcessInstanceList(Set processInstanceIdSet); + + /** + * 根据流程部署Id查询流程定义对象。 + * + * @param deployId 流程部署Id。 + * @return 流程定义对象。 + */ + ProcessDefinition getProcessDefinitionByDeployId(String deployId); + + /** + * 获取流程定义的列表。 + * + * @param processDefinitionIdSet 流程定义Id集合。 + * @return 流程定义列表。 + */ + List getProcessDefinitionList(Set processDefinitionIdSet); + + /** + * 挂起流程定义对象。 + * + * @param processDefinitionId 流程定义Id。 + */ + void suspendProcessDefinition(String processDefinitionId); + + /** + * 激活流程定义对象。 + * + * @param processDefinitionId 流程定义Id。 + */ + void activateProcessDefinition(String processDefinitionId); + + /** + * 获取指定流程定义的BpmnModel。 + * + * @param processDefinitionId 流程定义Id。 + * @return 关联的BpmnModel。 + */ + BpmnModel getBpmnModelByDefinitionId(String processDefinitionId); + + /** + * 获取流程实例的变量。 + * + * @param processInstanceId 流程实例Id。 + * @param variableName 变量名。 + * @return 变量值。 + */ + Object getProcessInstanceVariable(String processInstanceId, String variableName); + + /** + * 获取指定流程实例和任务Id的当前活动任务。 + * + * @param processInstanceId 流程实例Id。 + * @param taskId 流程任务Id。 + * @return 当前流程实例的活动任务。 + */ + Task getProcessInstanceActiveTask(String processInstanceId, String taskId); + + /** + * 获取指定流程实例的当前活动任务列表。 + * + * @param processInstanceId 流程实例Id。 + * @return 当前流程实例的活动任务。 + */ + List getProcessInstanceActiveTaskList(String processInstanceId); + + /** + * 获取用户的任务列表。这其中包括当前用户作为指派人和候选人。 + * + * @param username 指派人。 + * @param definitionKey 流程定义的标识。 + * @param pageParam 分页对象。 + * @return 用户的任务列表。 + */ + MyPageData getTaskListByUserName(String username, String definitionKey, MyPageParam pageParam); + + /** + * 获取用户的任务数量。这其中包括当前用户作为指派人和候选人。 + * + * @param username 指派人。 + * @return 用户的任务数量。 + */ + long getTaskCountByUserName(String username); + + /** + * 获取流程实例Id集合的运行时任务列表。 + * + * @param processInstanceIdSet 流程实例Id集合。 + * @return 运行时任务列表。 + */ + List getTaskListByProcessInstanceIds(List processInstanceIdSet); + + /** + * 将流程任务列表数据,转换为前端可以显示的流程对象。 + * + * @param taskList 流程引擎中的任务列表。 + * @return 前端可以显示的流程任务列表。 + */ + List convertToFlowTaskList(List taskList); + + /** + * 添加流程实例结束的监听器。 + * + * @param bpmnModel 流程模型。 + * @param listenerClazz 流程监听器的Class对象。 + */ + void addProcessInstanceEndListener(BpmnModel bpmnModel, Class listenerClazz); + + /** + * 添加流程任务创建的任务监听器。 + * + * @param userTask 用户任务。 + * @param listenerClazz 任务监听器。 + */ + void addTaskCreateListener(UserTask userTask, Class listenerClazz); + + /** + * 获取流程实例的历史流程实例。 + * + * @param processInstanceId 流程实例Id。 + * @return 历史流程实例。 + */ + HistoricProcessInstance getHistoricProcessInstance(String processInstanceId); + + /** + * 获取流程实例的历史流程实例列表。 + * + * @param processInstanceIdSet 流程实例Id集合。 + * @return 历史流程实例列表。 + */ + List getHistoricProcessInstanceList(Set processInstanceIdSet); + + /** + * 查询历史流程实例的列表。 + * + * @param processDefinitionKey 流程标识名。 + * @param processDefinitionName 流程名。 + * @param startUser 流程发起用户。 + * @param beginDate 流程发起开始时间。 + * @param endDate 流程发起结束时间。 + * @param pageParam 分页对象。 + * @param finishedOnly 仅仅返回已经结束的流程。 + * @return 分页后的查询列表对象。 + * @throws ParseException 日期参数解析失败。 + */ + MyPageData getHistoricProcessInstanceList( + String processDefinitionKey, + String processDefinitionName, + String startUser, + String beginDate, + String endDate, + MyPageParam pageParam, + boolean finishedOnly) throws ParseException; + + /** + * 获取流程实例的已完成历史任务列表。 + * + * @param processInstanceId 流程实例Id。 + * @return 流程实例已完成的历史任务列表。 + */ + List getHistoricActivityInstanceList(String processInstanceId); + + /** + * 获取当前用户的历史已办理任务列表。 + * + * @param processDefinitionName 流程名。 + * @param beginDate 流程发起开始时间。 + * @param endDate 流程发起结束时间。 + * @param pageParam 分页对象。 + * @return 分页后的查询列表对象。 + * @throws ParseException 日期参数解析失败。 + */ + MyPageData getHistoricTaskInstanceFinishedList( + String processDefinitionName, + String beginDate, + String endDate, + MyPageParam pageParam) throws ParseException; + + /** + * 获取指定的历史任务实例。 + * + * @param processInstanceId 流程实例Id。 + * @param taskId 任务Id。 + * @return 历史任务实例。 + */ + HistoricTaskInstance getHistoricTaskInstance(String processInstanceId, String taskId); + + /** + * 获取流程实例的待完成任务列表。 + * + * @param processInstanceId 流程实例Id。 + * @return 流程实例待完成的任务列表。 + */ + List getHistoricUnfinishedInstanceList(String processInstanceId); + + /** + * 终止流程实例,将任务从当前节点直接流转到主流程的结束事件。 + * + * @param processInstanceId 流程实例Id。 + * @param stopReason 停止原因。 + * @param forCancel 是否由取消工单触发。 + * @return 执行结果。 + */ + CallResult stopProcessInstance(String processInstanceId, String stopReason, boolean forCancel); + + /** + * 删除流程实例。 + * + * @param processInstanceId 流程实例Id。 + */ + void deleteProcessInstance(String processInstanceId); + + /** + * 获取任务的指定本地变量。 + * + * @param taskId 任务Id。 + * @param variableName 变量名。 + * @return 变量值。 + */ + Object getTaskVariable(String taskId, String variableName); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowCategoryService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowCategoryService.java new file mode 100644 index 00000000..c9e6e3bd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowCategoryService.java @@ -0,0 +1,61 @@ +package com.flow.demo.common.flow.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.flow.model.*; + +import java.util.List; + +/** + * FlowCategory数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowCategoryService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param flowCategory 新增对象。 + * @return 返回新增对象。 + */ + FlowCategory saveNew(FlowCategory flowCategory); + + /** + * 更新数据对象。 + * + * @param flowCategory 更新的对象。 + * @param originalFlowCategory 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(FlowCategory flowCategory, FlowCategory originalFlowCategory); + + /** + * 删除指定数据。 + * + * @param categoryId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long categoryId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getFlowCategoryListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getFlowCategoryList(FlowCategory filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getFlowCategoryList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getFlowCategoryListWithRelation(FlowCategory filter, String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowEntryService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowEntryService.java new file mode 100644 index 00000000..d5650880 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowEntryService.java @@ -0,0 +1,145 @@ +package com.flow.demo.common.flow.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.flow.model.*; + +import javax.xml.stream.XMLStreamException; +import java.util.List; +import java.util.Set; + +/** + * FlowEntry数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowEntryService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param flowEntry 新增工作流对象。 + * @return 返回新增对象。 + */ + FlowEntry saveNew(FlowEntry flowEntry); + + /** + * 发布指定流程。 + * + * @param flowEntry 待发布的流程对象。 + * @param initTaskInfo 第一个非开始节点任务的附加信息。 + * @param flowTaskExtList 所有用户任务的自定义扩展数据列表。 + * @throws XMLStreamException 解析bpmn.xml的异常。 + */ + void publish(FlowEntry flowEntry, String initTaskInfo, List flowTaskExtList) throws XMLStreamException; + + /** + * 更新数据对象。 + * + * @param flowEntry 更新的对象。 + * @param originalFlowEntry 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(FlowEntry flowEntry, FlowEntry originalFlowEntry); + + /** + * 删除指定数据。 + * + * @param entryId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long entryId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getFlowEntryListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getFlowEntryList(FlowEntry filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getFlowEntryList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getFlowEntryListWithRelation(FlowEntry filter, String orderBy); + + /** + * 根据流程定义标识获取流程对象。 + * + * @param processDefinitionKey 流程定义标识。 + * @return 流程对象。 + */ + FlowEntry getFlowEntryByProcessDefinitionKey(String processDefinitionKey); + + /** + * 根据流程Id获取流程发布列表数据。 + * + * @param entryId 流程Id。 + * @return 流程关联的发布列表数据。 + */ + List getFlowEntryPublishList(Long entryId); + + /** + * 根据流程引擎中的流程定义Id集合,查询流程发布对象。 + * + * @param processDefinitionIdSet 流程引擎中的流程定义Id集合。 + * @return 查询结果。 + */ + List getFlowEntryPublishList(Set processDefinitionIdSet); + + /** + * 获取指定工作流发布版本对象。 + * + * @param entryPublishId 工作流发布对象Id。 + * @return 查询后的对象。 + */ + FlowEntryPublish getFlowEntryPublishById(Long entryPublishId); + + /** + * 获取指定流程定义Id对应的流程发布对象。 + * + * @param processDefinitionId 流程定义Id。 + * @return 流程发布对象。 + */ + FlowEntryPublish getFlowEntryPublishByDefinitionId(String processDefinitionId); + + /** + * 为指定工作流更新发布的主版本。 + * + * @param flowEntry 工作流对象。 + * @param newMainFlowEntryPublish 工作流新的发布主版本对象。 + */ + void updateFlowEntryMainVersion(FlowEntry flowEntry, FlowEntryPublish newMainFlowEntryPublish); + + /** + * 挂起指定的工作流发布对象。 + * + * @param flowEntryPublish 待挂起的工作流发布对象。 + */ + void suspendFlowEntryPublish(FlowEntryPublish flowEntryPublish); + + /** + * 激活指定的工作流发布对象。 + * + * @param flowEntryPublish 待恢复的工作流发布对象。 + */ + void activateFlowEntryPublish(FlowEntryPublish flowEntryPublish); + + /** + * 主表的关联数据验证。 + * + * @param flowEntry 最新数据对象。 + * @param originalFlowEntry 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + CallResult verifyRelatedData(FlowEntry flowEntry, FlowEntry originalFlowEntry); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowEntryVariableService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowEntryVariableService.java new file mode 100644 index 00000000..27b778a4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowEntryVariableService.java @@ -0,0 +1,68 @@ +package com.flow.demo.common.flow.service; + +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.core.base.service.IBaseService; + +import java.util.*; + +/** + * 流程变量数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowEntryVariableService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param flowEntryVariable 新增对象。 + * @return 返回新增对象。 + */ + FlowEntryVariable saveNew(FlowEntryVariable flowEntryVariable); + + /** + * 更新数据对象。 + * + * @param flowEntryVariable 更新的对象。 + * @param originalFlowEntryVariable 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(FlowEntryVariable flowEntryVariable, FlowEntryVariable originalFlowEntryVariable); + + /** + * 删除指定数据。 + * + * @param variableId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long variableId); + + /** + * 删除指定流程Id的所有变量。 + * + * @param entryId 流程Id。 + */ + void removeByEntryId(Long entryId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getFlowEntryVariableListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getFlowEntryVariableList(FlowEntryVariable filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getFlowEntryVariableList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getFlowEntryVariableListWithRelation(FlowEntryVariable filter, String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowTaskCommentService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowTaskCommentService.java new file mode 100644 index 00000000..86ab12f9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowTaskCommentService.java @@ -0,0 +1,31 @@ +package com.flow.demo.common.flow.service; + +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.core.base.service.IBaseService; + +import java.util.*; + +/** + * 流程任务批注数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowTaskCommentService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param flowTaskComment 新增对象。 + * @return 返回新增对象。 + */ + FlowTaskComment saveNew(FlowTaskComment flowTaskComment); + + /** + * 查询指定流程实例Id下的所有审批任务的批注。 + * + * @param processInstanceId 流程实例Id。 + * @return 查询结果集。 + */ + List getFlowTaskCommentList(String processInstanceId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowTaskExtService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowTaskExtService.java new file mode 100644 index 00000000..b2f749de --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowTaskExtService.java @@ -0,0 +1,38 @@ +package com.flow.demo.common.flow.service; + +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.core.base.service.IBaseService; + +import java.util.List; + +/** + * 流程任务扩展数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowTaskExtService extends IBaseService { + + /** + * 批量插入流程任务扩展信息列表。 + * + * @param flowTaskExtList 流程任务扩展信息列表。 + */ + void saveBatch(List flowTaskExtList); + + /** + * 查询指定的流程任务扩展对象。 + * @param processDefinitionId 流程引擎的定义Id。 + * @param taskId 流程引擎的任务Id。 + * @return 查询结果。 + */ + FlowTaskExt getByProcessDefinitionIdAndTaskId(String processDefinitionId, String taskId); + + /** + * 查询指定的流程定义的任务扩展对象。 + * + * @param processDefinitionId 流程引擎的定义Id。 + * @return 查询结果。 + */ + List getByProcessDefinitionId(String processDefinitionId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowWorkOrderService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowWorkOrderService.java new file mode 100644 index 00000000..4a023270 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/FlowWorkOrderService.java @@ -0,0 +1,76 @@ +package com.flow.demo.common.flow.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.flow.model.FlowWorkOrder; +import org.flowable.engine.runtime.ProcessInstance; + +import java.util.*; + +/** + * 工作流工单表数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface FlowWorkOrderService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param instance 流程实例对象。 + * @param dataId 流程实例的BusinessKey。 + * @param onlineTableId 在线数据表的主键Id。 + * @return 新增的工作流工单对象。 + */ + FlowWorkOrder saveNew(ProcessInstance instance, Object dataId, Long onlineTableId); + + /** + * 删除指定数据。 + * + * @param workOrderId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long workOrderId); + + /** + * 删除指定流程实例Id的关联工单。 + * + * @param processInstanceId 流程实例Id。 + */ + void removeByProcessInstanceId(String processInstanceId); + + /** + * 获取工作流工单单表查询结果。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getFlowWorkOrderList(FlowWorkOrder filter, String orderBy); + + /** + * 获取工作流工单列表及其关联字典数据。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getFlowWorkOrderListWithRelation(FlowWorkOrder filter, String orderBy); + + /** + * 根据业务主键,查询是否存在指定的工单。 + * + * @param businessKey 业务数据主键Id。 + * @param unfinished 是否为没有结束工单。 + * @return 存在返回true,否则false。 + */ + boolean existByBusinessKey(Object businessKey, boolean unfinished); + + /** + * 根据流程实例Id,更新流程状态。 + * + * @param processInstanceId 流程实例Id。 + * @param flowStatus 新的流程状态值。 + */ + void updateFlowStatusByProcessInstanceId(String processInstanceId, int flowStatus); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowApiServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowApiServiceImpl.java new file mode 100644 index 00000000..3ea338db --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowApiServiceImpl.java @@ -0,0 +1,615 @@ +package com.flow.demo.common.flow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.object.MyPageData; +import com.flow.demo.common.core.object.MyPageParam; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.flow.constant.FlowConstant; +import com.flow.demo.common.flow.constant.FlowApprovalType; +import com.flow.demo.common.flow.constant.FlowTaskStatus; +import com.flow.demo.common.flow.model.FlowEntryPublish; +import com.flow.demo.common.flow.model.FlowTaskComment; +import com.flow.demo.common.flow.model.FlowTaskExt; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.flow.util.BaseFlowDeptPostExtHelper; +import com.flow.demo.common.flow.util.FlowCustomExtFactory; +import com.flow.demo.common.flow.vo.FlowTaskVo; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.model.*; +import org.flowable.bpmn.model.Process; +import org.flowable.common.engine.impl.identity.Authentication; +import org.flowable.engine.*; +import org.flowable.engine.delegate.ExecutionListener; +import org.flowable.engine.delegate.TaskListener; +import org.flowable.engine.history.*; +import org.flowable.engine.repository.ProcessDefinition; +import org.flowable.engine.runtime.ProcessInstance; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskInfo; +import org.flowable.task.api.TaskQuery; +import org.flowable.task.api.history.HistoricTaskInstance; +import org.flowable.task.api.history.HistoricTaskInstanceQuery; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; +import java.util.stream.Collectors; + +@Slf4j +@Service("flowApiService") +public class FlowApiServiceImpl implements FlowApiService { + + @Autowired + private RepositoryService repositoryService; + @Autowired + private RuntimeService runtimeService; + @Autowired + private TaskService taskService; + @Autowired + private HistoryService historyService; + @Autowired + private FlowEntryService flowEntryService; + @Autowired + private FlowTaskCommentService flowTaskCommentService; + @Autowired + private FlowTaskExtService flowTaskExtService; + @Autowired + private FlowWorkOrderService flowWorkOrderService; + @Autowired + private FlowCustomExtFactory flowCustomExtFactory; + + @Transactional(rollbackFor = Exception.class) + @Override + public void start(String processDefinitionId) { + String loginName = TokenData.takeFromRequest().getLoginName(); + Map variableMap = new HashMap<>(4); + variableMap.put(FlowConstant.PROC_INSTANCE_INITIATOR_VAR, loginName); + variableMap.put(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR, loginName); + Authentication.setAuthenticatedUserId(loginName); + runtimeService.startProcessInstanceById(processDefinitionId, null, variableMap); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public ProcessInstance startAndTakeFirst( + String processDefinitionId, Object dataId, FlowTaskComment flowTaskComment, JSONObject taskVariableData) { + String loginName = TokenData.takeFromRequest().getLoginName(); + Authentication.setAuthenticatedUserId(loginName); + // 设置流程变量。 + Map variableMap = this.initAndGetProcessInstanceVariables(processDefinitionId); + // 根据当前流程的主版本,启动一个流程实例,同时将businessKey参数设置为主表主键值。 + ProcessInstance instance = runtimeService.startProcessInstanceById( + processDefinitionId, dataId.toString(), variableMap); + // 获取流程启动后的第一个任务。 + Task task = taskService.createTaskQuery().processInstanceId(instance.getId()).active().singleResult(); + if (StrUtil.equalsAny(task.getAssignee(), loginName, FlowConstant.START_USER_NAME_VAR)) { + // 按照规则,调用该方法的用户,就是第一个任务的assignee,因此默认会自动执行complete。 + flowTaskComment.fillWith(task); + this.completeTask(task, flowTaskComment, taskVariableData); + } + return instance; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void submitConsign(HistoricTaskInstance startTaskInstance, Task multiInstanceActiveTask, String newAssignees) { + JSONArray assigneeArray = JSON.parseArray(newAssignees); + for (int i = 0; i < assigneeArray.size(); i++) { + Map variables = new HashMap<>(2); + variables.put("assignee", assigneeArray.getString(i)); + variables.put(FlowConstant.MULTI_SIGN_START_TASK_VAR, startTaskInstance.getId()); + runtimeService.addMultiInstanceExecution( + multiInstanceActiveTask.getTaskDefinitionKey(), multiInstanceActiveTask.getProcessInstanceId(), variables); + } + FlowTaskComment flowTaskComment = new FlowTaskComment(); + flowTaskComment.fillWith(startTaskInstance); + flowTaskComment.setApprovalType(FlowApprovalType.MULTI_CONSIGN); + String loginName = TokenData.takeFromRequest().getLoginName(); + String comment = String.format("用户 [%s] 加签 [%s]。", loginName, newAssignees); + flowTaskComment.setComment(comment); + flowTaskCommentService.saveNew(flowTaskComment); + return; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void completeTask(Task task, FlowTaskComment flowTaskComment, JSONObject taskVariableData) { + if (flowTaskComment != null) { + // 这里处理多实例会签逻辑。 + if (flowTaskComment.getApprovalType().equals(FlowApprovalType.MULTI_SIGN)) { + String loginName = TokenData.takeFromRequest().getLoginName(); + String assigneeList = taskVariableData.getString(FlowConstant.MULTI_ASSIGNEE_LIST_VAR); + Assert.notNull(taskVariableData); + Assert.notNull(assigneeList); + taskVariableData.put(FlowConstant.MULTI_AGREE_COUNT_VAR, 0); + taskVariableData.put(FlowConstant.MULTI_REFUSE_COUNT_VAR, 0); + taskVariableData.put(FlowConstant.MULTI_ABSTAIN_COUNT_VAR, 0); + taskVariableData.put(FlowConstant.MULTI_SIGN_NUM_OF_INSTANCES_VAR, 0); + taskVariableData.put(FlowConstant.MULTI_SIGN_START_TASK_VAR, task.getId()); + String comment = String.format("用户 [%s] 会签 [%s]。", loginName, assigneeList); + flowTaskComment.setComment(comment); + } + // 处理转办。 + if (FlowApprovalType.TRANSFER.equals(flowTaskComment.getApprovalType())) { + taskService.setAssignee(task.getId(), flowTaskComment.getDelegateAssginee()); + flowTaskComment.fillWith(task); + flowTaskCommentService.saveNew(flowTaskComment); + return; + } + if (taskVariableData == null) { + taskVariableData = new JSONObject(); + } + this.handleMultiInstanceApprovalType( + task.getExecutionId(), flowTaskComment.getApprovalType(), taskVariableData); + taskVariableData.put(FlowConstant.OPERATION_TYPE_VAR, flowTaskComment.getApprovalType()); + taskService.complete(task.getId(), taskVariableData); + flowTaskComment.fillWith(task); + flowTaskCommentService.saveNew(flowTaskComment); + } else { + taskService.complete(task.getId(), taskVariableData); + } + } + + @Transactional(rollbackFor = Exception.class) + @Override + public CallResult verifyAssigneeOrCandidateAndClaim(Task task) { + String errorMessage; + String loginName = TokenData.takeFromRequest().getLoginName(); + // 这里必须先执行拾取操作,如果当前用户是候选人,特别是对于分布式场景,更是要先完成候选人的拾取。 + if (task.getAssignee() == null) { + // 没有指派人 + if (!this.isAssigneeOrCandidate(task)) { + errorMessage = "数据验证失败,当前用户不是该待办任务的候选人,请刷新后重试!"; + return CallResult.error(errorMessage); + } + // 作为候选人主动拾取任务。 + taskService.claim(task.getId(), loginName); + } else { + if (!task.getAssignee().equals(loginName)) { + errorMessage = "数据验证失败,当前用户不是该待办任务的指派人,请刷新后重试!"; + return CallResult.error(errorMessage); + } + } + return CallResult.ok(); + } + + @Override + public Map initAndGetProcessInstanceVariables(String processDefinitionId) { + TokenData tokenData = TokenData.takeFromRequest(); + String loginName = tokenData.getLoginName(); + // 设置流程变量。 + Map variableMap = new HashMap<>(4); + variableMap.put(FlowConstant.PROC_INSTANCE_INITIATOR_VAR, loginName); + variableMap.put(FlowConstant.PROC_INSTANCE_START_USER_NAME_VAR, loginName); + List flowTaskExtList = flowTaskExtService.getByProcessDefinitionId(processDefinitionId); + boolean hasDeptPostLeader = false; + boolean hasUpDeptPostLeader = false; + for (FlowTaskExt flowTaskExt : flowTaskExtList) { + if (StrUtil.equals(flowTaskExt.getGroupType(), FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER)) { + hasUpDeptPostLeader = true; + } else if (StrUtil.equals(flowTaskExt.getGroupType(), FlowConstant.GROUP_TYPE_DEPT_POST_LEADER)) { + hasDeptPostLeader = true; + } + } + // 如果流程图的配置中包含部门岗位相关的变量(如:部门领导和上级领导审批),flowDeptPostExtHelper就不能为null。 + // 这个需要子类去实现 BaseFlowDeptPostExtHelper 接口,并注册到FlowCustomExtFactory的工厂中。 + BaseFlowDeptPostExtHelper flowDeptPostExtHelper = flowCustomExtFactory.getFlowDeptPostExtHelper(); + if (hasUpDeptPostLeader) { + Assert.notNull(flowDeptPostExtHelper); + Long upLeaderDeptPostId = flowDeptPostExtHelper.getUpLeaderDeptPostId(tokenData.getDeptId()); + variableMap.put(FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR, upLeaderDeptPostId); + } + if (hasDeptPostLeader) { + Assert.notNull(flowDeptPostExtHelper); + Long leaderDeptPostId = flowDeptPostExtHelper.getLeaderDeptPostId(tokenData.getDeptId()); + variableMap.put(FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR, leaderDeptPostId); + } + return variableMap; + } + + @Override + public boolean isAssigneeOrCandidate(TaskInfo task) { + String loginName = TokenData.takeFromRequest().getLoginName(); + if (StrUtil.isNotBlank(task.getAssignee())) { + return StrUtil.equals(loginName, task.getAssignee()); + } + TaskQuery query = taskService.createTaskQuery(); + this.buildCandidateCondition(query, loginName); + return query.active().count() != 0; + } + + @Override + public boolean isProcessInstanceStarter(String processInstanceId) { + String loginName = TokenData.takeFromRequest().getLoginName(); + return historyService.createHistoricProcessInstanceQuery() + .processInstanceId(processInstanceId).startedBy(loginName).count() != 0; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void setBusinessKeyForProcessInstance(String processInstanceId, Object dataId) { + runtimeService.updateBusinessKey(processInstanceId, dataId.toString()); + } + + @Override + public boolean existActiveProcessInstance(String processInstanceId) { + return runtimeService.createProcessInstanceQuery() + .processInstanceId(processInstanceId).active().count() != 0; + } + + @Override + public ProcessInstance getProcessInstance(String processInstanceId) { + return runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + } + + @Override + public Task getProcessInstanceActiveTask(String processInstanceId, String taskId) { + TaskQuery query = taskService.createTaskQuery().processInstanceId(processInstanceId); + if (StrUtil.isNotBlank(taskId)) { + query.taskId(taskId); + } + return query.active().singleResult(); + } + + @Override + public List getProcessInstanceActiveTaskList(String processInstanceId) { + return taskService.createTaskQuery().processInstanceId(processInstanceId).list(); + } + + @Override + public MyPageData getTaskListByUserName(String username, String definitionKey, MyPageParam pageParam) { + TaskQuery query = taskService.createTaskQuery().active(); + if (StrUtil.isNotBlank(definitionKey)) { + query.processDefinitionKey(definitionKey); + } + this.buildCandidateCondition(query, username); + query.orderByTaskCreateTime().desc(); + long totalCount = query.count(); + int firstResult = (pageParam.getPageNum() - 1) * pageParam.getPageSize(); + List taskList = query.listPage(firstResult, pageParam.getPageSize()); + return new MyPageData<>(taskList, totalCount); + } + + @Override + public long getTaskCountByUserName(String username) { + return taskService.createTaskQuery().taskCandidateOrAssigned(username).active().count(); + } + + @Override + public List getTaskListByProcessInstanceIds(List processInstanceIdSet) { + return taskService.createTaskQuery().processInstanceIdIn(processInstanceIdSet).active().list(); + } + + @Override + public List getProcessInstanceList(Set processInstanceIdSet) { + return runtimeService.createProcessInstanceQuery().processInstanceIds(processInstanceIdSet).list(); + } + + @Override + public List getProcessDefinitionList(Set processDefinitionIdSet) { + return repositoryService.createProcessDefinitionQuery().processDefinitionIds(processDefinitionIdSet).list(); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void suspendProcessDefinition(String processDefinitionId) { + repositoryService.suspendProcessDefinitionById(processDefinitionId); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void activateProcessDefinition(String processDefinitionId) { + repositoryService.activateProcessDefinitionById(processDefinitionId); + } + + @Override + public BpmnModel getBpmnModelByDefinitionId(String processDefinitionId) { + return repositoryService.getBpmnModel(processDefinitionId); + } + + @Override + public ProcessDefinition getProcessDefinitionByDeployId(String deployId) { + return repositoryService.createProcessDefinitionQuery().deploymentId(deployId).singleResult(); + } + + @Override + public Object getProcessInstanceVariable(String processInstanceId, String variableName) { + return runtimeService.getVariable(processInstanceId, variableName); + } + + @Override + public List convertToFlowTaskList(List taskList) { + List flowTaskVoList = new LinkedList<>(); + if (CollUtil.isEmpty(taskList)) { + return flowTaskVoList; + } + Set processDefinitionIdSet = taskList.stream() + .map(Task::getProcessDefinitionId).collect(Collectors.toSet()); + Set procInstanceIdSet = taskList.stream() + .map(Task::getProcessInstanceId).collect(Collectors.toSet()); + List flowEntryPublishList = + flowEntryService.getFlowEntryPublishList(processDefinitionIdSet); + Map flowEntryPublishMap = + flowEntryPublishList.stream().collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c)); + List instanceList = this.getProcessInstanceList(procInstanceIdSet); + Map instanceMap = + instanceList.stream().collect(Collectors.toMap(ProcessInstance::getId, c -> c)); + List definitionList = this.getProcessDefinitionList(processDefinitionIdSet); + Map definitionMap = + definitionList.stream().collect(Collectors.toMap(ProcessDefinition::getId, c -> c)); + for (Task task : taskList) { + FlowTaskVo flowTaskVo = new FlowTaskVo(); + flowTaskVo.setTaskId(task.getId()); + flowTaskVo.setTaskName(task.getName()); + flowTaskVo.setTaskKey(task.getTaskDefinitionKey()); + flowTaskVo.setTaskFormKey(task.getFormKey()); + flowTaskVo.setEntryId(flowEntryPublishMap.get(task.getProcessDefinitionId()).getEntryId()); + ProcessDefinition processDefinition = definitionMap.get(task.getProcessDefinitionId()); + flowTaskVo.setProcessDefinitionId(processDefinition.getId()); + flowTaskVo.setProcessDefinitionName(processDefinition.getName()); + flowTaskVo.setProcessDefinitionKey(processDefinition.getKey()); + flowTaskVo.setProcessDefinitionVersion(processDefinition.getVersion()); + ProcessInstance processInstance = instanceMap.get(task.getProcessInstanceId()); + flowTaskVo.setProcessInstanceId(processInstance.getId()); + Object initiator = this.getProcessInstanceVariable( + processInstance.getId(), FlowConstant.PROC_INSTANCE_INITIATOR_VAR); + flowTaskVo.setProcessInstanceInitiator(initiator.toString()); + flowTaskVo.setProcessInstanceStartTime(processInstance.getStartTime()); + flowTaskVoList.add(flowTaskVo); + } + return flowTaskVoList; + } + + @Override + public void addProcessInstanceEndListener(BpmnModel bpmnModel, Class listenerClazz) { + Assert.notNull(listenerClazz); + Process process = bpmnModel.getMainProcess(); + FlowableListener activitiListener = new FlowableListener(); + activitiListener.setEvent("end"); + activitiListener.setImplementationType("class"); + activitiListener.setImplementation(listenerClazz.getName()); + process.getExecutionListeners().add(activitiListener); + } + + @Override + public void addTaskCreateListener(UserTask userTask, Class listenerClazz) { + Assert.notNull(listenerClazz); + FlowableListener activitiListener = new FlowableListener(); + activitiListener.setEvent("create"); + activitiListener.setImplementationType("class"); + activitiListener.setImplementation(listenerClazz.getName()); + userTask.getTaskListeners().add(activitiListener); + } + + @Override + public HistoricProcessInstance getHistoricProcessInstance(String processInstanceId) { + return historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult(); + } + + @Override + public List getHistoricProcessInstanceList(Set processInstanceIdSet) { + return historyService.createHistoricProcessInstanceQuery().processInstanceIds(processInstanceIdSet).list(); + } + + @Override + public MyPageData getHistoricProcessInstanceList( + String processDefinitionKey, + String processDefinitionName, + String startUser, + String beginDate, + String endDate, + MyPageParam pageParam, + boolean finishedOnly) throws ParseException { + HistoricProcessInstanceQuery query = historyService.createHistoricProcessInstanceQuery(); + if (StrUtil.isNotBlank(processDefinitionKey)) { + query.processDefinitionKey(processDefinitionKey); + } + if (StrUtil.isNotBlank(processDefinitionName)) { + query.processDefinitionName(processDefinitionName); + } + if (StrUtil.isNotBlank(startUser)) { + query.startedBy(startUser); + } + if (StrUtil.isNotBlank(beginDate)) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + query.startedAfter(sdf.parse(beginDate)); + } + if (StrUtil.isNotBlank(endDate)) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + query.startedBefore(sdf.parse(endDate)); + } + if (finishedOnly) { + query.finished(); + } + query.orderByProcessInstanceStartTime().desc(); + long totalCount = query.count(); + int firstResult = (pageParam.getPageNum() - 1) * pageParam.getPageSize(); + List instanceList = query.listPage(firstResult, pageParam.getPageSize()); + return new MyPageData<>(instanceList, totalCount); + } + + @Override + public MyPageData getHistoricTaskInstanceFinishedList( + String processDefinitionName, + String beginDate, + String endDate, + MyPageParam pageParam) throws ParseException { + String loginName = TokenData.takeFromRequest().getLoginName(); + HistoricTaskInstanceQuery query = historyService.createHistoricTaskInstanceQuery() + .taskAssignee(loginName) + .finished(); + if (StrUtil.isNotBlank(processDefinitionName)) { + query.processDefinitionName(processDefinitionName); + } + if (StrUtil.isNotBlank(beginDate)) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + query.taskCompletedAfter(sdf.parse(beginDate)); + } + if (StrUtil.isNotBlank(endDate)) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + query.taskCompletedBefore(sdf.parse(endDate)); + } + query.orderByHistoricTaskInstanceEndTime().desc(); + long totalCount = query.count(); + int firstResult = (pageParam.getPageNum() - 1) * pageParam.getPageSize(); + List instanceList = query.listPage(firstResult, pageParam.getPageSize()); + return new MyPageData<>(instanceList, totalCount); + } + + @Override + public List getHistoricActivityInstanceList(String processInstanceId) { + return historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).list(); + } + + @Override + public HistoricTaskInstance getHistoricTaskInstance(String processInstanceId, String taskId) { + return historyService.createHistoricTaskInstanceQuery() + .processInstanceId(processInstanceId).taskId(taskId).singleResult(); + } + + @Override + public List getHistoricUnfinishedInstanceList(String processInstanceId) { + return historyService.createHistoricActivityInstanceQuery() + .processInstanceId(processInstanceId).unfinished().list(); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public CallResult stopProcessInstance(String processInstanceId, String stopReason, boolean forCancel) { + List taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).active().list(); + if (CollUtil.isEmpty(taskList)) { + return CallResult.error("数据验证失败,当前流程尚未开始或已经结束!"); + } + for (Task task : taskList) { + String currActivityId = task.getTaskDefinitionKey(); + BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId()); + FlowNode currFlow = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currActivityId); + if (currFlow == null) { + List subProcessList = + bpmnModel.getMainProcess().findFlowElementsOfType(SubProcess.class); + for (SubProcess subProcess : subProcessList) { + FlowElement flowElement = subProcess.getFlowElement(currActivityId); + if (flowElement != null) { + currFlow = (FlowNode) flowElement; + break; + } + } + } + EndEvent endEvent = + bpmnModel.getMainProcess().findFlowElementsOfType(EndEvent.class, false).get(0); + if (!(currFlow.getParentContainer().equals(endEvent.getParentContainer()))) { + return CallResult.error("数据验证失败,不能从子流程直接中止!"); + } + // 保存原有的输出方向。 + List oriSequenceFlows = Lists.newArrayList(); + oriSequenceFlows.addAll(currFlow.getOutgoingFlows()); + // 清空原有方向。 + currFlow.getOutgoingFlows().clear(); + // 建立新方向。 + SequenceFlow newSequenceFlow = new SequenceFlow(); + String uuid = UUID.randomUUID().toString().replace("-", ""); + newSequenceFlow.setId(uuid); + newSequenceFlow.setSourceFlowElement(currFlow); + newSequenceFlow.setTargetFlowElement(endEvent); + currFlow.setOutgoingFlows(CollUtil.newArrayList(newSequenceFlow)); + // 完成任务并跳转到新方向。 + taskService.complete(task.getId()); + FlowTaskComment taskComment = new FlowTaskComment(task); + taskComment.setApprovalType(FlowApprovalType.STOP); + taskComment.setComment(stopReason); + flowTaskCommentService.saveNew(taskComment); + // 回复原有输出方向。 + currFlow.setOutgoingFlows(oriSequenceFlows); + } + int status = FlowTaskStatus.STOPPED; + if (forCancel) { + status = FlowTaskStatus.CANCELLED; + } + flowWorkOrderService.updateFlowStatusByProcessInstanceId(processInstanceId, status); + return CallResult.ok(); + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void deleteProcessInstance(String processInstanceId) { + historyService.deleteHistoricProcessInstance(processInstanceId); + flowWorkOrderService.removeByProcessInstanceId(processInstanceId); + } + + @Override + public Object getTaskVariable(String taskId, String variableName) { + return taskService.getVariable(taskId, variableName); + } + + private void handleMultiInstanceApprovalType(String executionId, String approvalType, JSONObject taskVariableData) { + if (StrUtil.isBlank(approvalType)) { + return; + } + if (StrUtil.equalsAny(approvalType, + FlowApprovalType.MULTI_AGREE, + FlowApprovalType.MULTI_REFUSE, + FlowApprovalType.MULTI_ABSTAIN)) { + Map variables = runtimeService.getVariables(executionId); + Integer agreeCount = (Integer) variables.get(FlowConstant.MULTI_AGREE_COUNT_VAR); + Integer refuseCount = (Integer) variables.get(FlowConstant.MULTI_REFUSE_COUNT_VAR); + Integer abstainCount = (Integer) variables.get(FlowConstant.MULTI_ABSTAIN_COUNT_VAR); + Integer nrOfInstances = (Integer) variables.get(FlowConstant.NUMBER_OF_INSTANCES_VAR); + taskVariableData.put(FlowConstant.MULTI_AGREE_COUNT_VAR, agreeCount); + taskVariableData.put(FlowConstant.MULTI_REFUSE_COUNT_VAR, refuseCount); + taskVariableData.put(FlowConstant.MULTI_ABSTAIN_COUNT_VAR, abstainCount); + taskVariableData.put(FlowConstant.MULTI_SIGN_NUM_OF_INSTANCES_VAR, nrOfInstances); + switch (approvalType) { + case FlowApprovalType.MULTI_AGREE: + if (agreeCount == null) { + agreeCount = 0; + } + taskVariableData.put(FlowConstant.MULTI_AGREE_COUNT_VAR, agreeCount + 1); + break; + case FlowApprovalType.MULTI_REFUSE: + if (refuseCount == null) { + refuseCount = 0; + } + taskVariableData.put(FlowConstant.MULTI_REFUSE_COUNT_VAR, refuseCount + 1); + break; + case FlowApprovalType.MULTI_ABSTAIN: + if (abstainCount == null) { + abstainCount = 0; + } + taskVariableData.put(FlowConstant.MULTI_ABSTAIN_COUNT_VAR, abstainCount + 1); + break; + default: + break; + } + } + } + + private void buildCandidateCondition(TaskQuery query, String loginName) { + Set groupIdSet = new HashSet<>(); + // NOTE: 目前已经支持部门和岗位,如果今后需要支持角色,可将角色Id也加到groupIdSet中即可。 + // 需要注意的是,部门Id、部门岗位Id,或者其他类型的分组Id,他们之间一定不能重复。 + TokenData tokenData = TokenData.takeFromRequest(); + Object deptId = tokenData.getDeptId(); + if (deptId != null) { + groupIdSet.add(deptId.toString()); + } + String deptPostIds = tokenData.getDeptPostIds(); + if (StrUtil.isNotBlank(deptPostIds)) { + groupIdSet.addAll(Arrays.asList(StrUtil.split(deptPostIds, ","))); + } + if (CollUtil.isNotEmpty(groupIdSet)) { + query.or().taskCandidateGroupIn(groupIdSet).taskCandidateOrAssigned(loginName).endOr(); + } else { + query.taskCandidateOrAssigned(loginName); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowCategoryServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowCategoryServiceImpl.java new file mode 100644 index 00000000..549d29ce --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowCategoryServiceImpl.java @@ -0,0 +1,129 @@ +package com.flow.demo.common.flow.service.impl; + +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.github.pagehelper.Page; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.flow.dao.*; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.flow.service.*; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +/** + * FlowCategory数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("flowCategoryService") +public class FlowCategoryServiceImpl extends BaseService implements FlowCategoryService { + + @Autowired + private FlowCategoryMapper flowCategoryMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return flowCategoryMapper; + } + + /** + * 保存新增对象。 + * + * @param flowCategory 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public FlowCategory saveNew(FlowCategory flowCategory) { + flowCategory.setCategoryId(idGenerator.nextLongId()); + TokenData tokenData = TokenData.takeFromRequest(); + flowCategory.setUpdateUserId(tokenData.getUserId()); + flowCategory.setCreateUserId(tokenData.getUserId()); + Date now = new Date(); + flowCategory.setUpdateTime(now); + flowCategory.setCreateTime(now); + flowCategoryMapper.insert(flowCategory); + return flowCategory; + } + + /** + * 更新数据对象。 + * + * @param flowCategory 更新的对象。 + * @param originalFlowCategory 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(FlowCategory flowCategory, FlowCategory originalFlowCategory) { + flowCategory.setUpdateUserId(TokenData.takeFromRequest().getUserId()); + flowCategory.setCreateUserId(originalFlowCategory.getCreateUserId()); + flowCategory.setUpdateTime(new Date()); + flowCategory.setCreateTime(originalFlowCategory.getCreateTime()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + UpdateWrapper uw = + this.createUpdateQueryForNullValue(flowCategory, flowCategory.getCategoryId()); + return flowCategoryMapper.update(flowCategory, uw) == 1; + } + + /** + * 删除指定数据。 + * + * @param categoryId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long categoryId) { + return flowCategoryMapper.deleteById(categoryId) == 1; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getFlowCategoryListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getFlowCategoryList(FlowCategory filter, String orderBy) { + return flowCategoryMapper.getFlowCategoryList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getFlowCategoryList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getFlowCategoryListWithRelation(FlowCategory filter, String orderBy) { + List resultList = flowCategoryMapper.getFlowCategoryList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowEntryServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowEntryServiceImpl.java new file mode 100644 index 00000000..e70b4c65 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowEntryServiceImpl.java @@ -0,0 +1,422 @@ +package com.flow.demo.common.flow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Assert; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.github.pagehelper.Page; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.flow.util.BaseFlowDeptPostExtHelper; +import com.flow.demo.common.flow.util.FlowCustomExtFactory; +import com.flow.demo.common.flow.constant.FlowConstant; +import com.flow.demo.common.flow.dao.*; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.flow.model.constant.FlowEntryStatus; +import com.flow.demo.common.flow.model.constant.FlowVariableType; +import com.flow.demo.common.flow.listener.UpdateFlowStatusListener; +import lombok.Cleanup; +import lombok.extern.slf4j.Slf4j; +import org.flowable.bpmn.converter.BpmnXMLConverter; +import org.flowable.bpmn.model.BpmnModel; +import org.flowable.bpmn.model.FlowElement; +import org.flowable.bpmn.model.UserTask; +import org.flowable.engine.RepositoryService; +import org.flowable.engine.repository.Deployment; +import org.flowable.engine.repository.ProcessDefinition; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.stream.Collectors; + +/** + * FlowEntry数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("flowEntryService") +public class FlowEntryServiceImpl extends BaseService implements FlowEntryService { + + @Autowired + private FlowEntryMapper flowEntryMapper; + @Autowired + private FlowEntryPublishMapper flowEntryPublishMapper; + @Autowired + private FlowEntryPublishVariableMapper flowEntryPublishVariableMapper; + @Autowired + private FlowEntryVariableService flowEntryVariableService; + @Autowired + private FlowCategoryService flowCategoryService; + @Autowired + private FlowTaskExtService flowTaskExtService; + @Autowired + private FlowApiService flowApiService; + @Autowired + private FlowCustomExtFactory flowCustomExtFactory; + @Autowired + private RepositoryService repositoryService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return flowEntryMapper; + } + + /** + * 保存新增对象。 + * + * @param flowEntry 新增工作流对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public FlowEntry saveNew(FlowEntry flowEntry) { + flowEntry.setEntryId(idGenerator.nextLongId()); + flowEntry.setStatus(FlowEntryStatus.UNPUBLISHED); + TokenData tokenData = TokenData.takeFromRequest(); + flowEntry.setUpdateUserId(tokenData.getUserId()); + flowEntry.setCreateUserId(tokenData.getUserId()); + Date now = new Date(); + flowEntry.setUpdateTime(now); + flowEntry.setCreateTime(now); + flowEntryMapper.insert(flowEntry); + this.insertBuiltinEntryVariables(flowEntry.getEntryId()); + return flowEntry; + } + + /** + * 发布指定流程。 + * + * @param flowEntry 待发布的流程对象。 + * @param initTaskInfo 第一个非开始节点任务的附加信息。 + * @param flowTaskExtList 所有用户任务的自定义扩展数据列表。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void publish(FlowEntry flowEntry, String initTaskInfo, List flowTaskExtList) throws XMLStreamException { + FlowCategory flowCategory = flowCategoryService.getById(flowEntry.getCategoryId()); + InputStream xmlStream = new ByteArrayInputStream( + flowEntry.getBpmnXml().getBytes(StandardCharsets.UTF_8)); + @Cleanup XMLStreamReader reader = XMLInputFactory.newInstance().createXMLStreamReader(xmlStream); + BpmnXMLConverter converter = new BpmnXMLConverter(); + BpmnModel bpmnModel = converter.convertToBpmnModel(reader); + flowApiService.addProcessInstanceEndListener(bpmnModel, UpdateFlowStatusListener.class); + Collection elementList = bpmnModel.getMainProcess().getFlowElements(); + Map elementMap = + elementList.stream().filter(e -> e instanceof UserTask).collect(Collectors.toMap(FlowElement::getId, c -> c)); + if (CollUtil.isNotEmpty(flowTaskExtList)) { + BaseFlowDeptPostExtHelper flowDeptPostExtHelper = flowCustomExtFactory.getFlowDeptPostExtHelper(); + for (FlowTaskExt t : flowTaskExtList) { + UserTask userTask = (UserTask) elementMap.get(t.getTaskId()); + // 如果流程图中包含部门领导审批和上级部门领导审批的选项,就需要注册 FlowCustomExtFactory 工厂中的 + // BaseFlowDeptPostExtHelper 对象,该注册操作需要业务模块中实现。 + if (StrUtil.equals(t.getGroupType(), FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER)) { + userTask.setCandidateGroups( + CollUtil.newArrayList("${" + FlowConstant.GROUP_TYPE_UP_DEPT_POST_LEADER_VAR + "}")); + Assert.notNull(flowDeptPostExtHelper); + flowApiService.addTaskCreateListener(userTask, flowDeptPostExtHelper.getUpDeptPostLeaderListener()); + } else if (StrUtil.equals(t.getGroupType(), FlowConstant.GROUP_TYPE_DEPT_POST_LEADER)) { + userTask.setCandidateGroups( + CollUtil.newArrayList("${" + FlowConstant.GROUP_TYPE_DEPT_POST_LEADER_VAR + "}")); + Assert.notNull(flowDeptPostExtHelper); + flowApiService.addTaskCreateListener(userTask, flowDeptPostExtHelper.getDeptPostLeaderListener()); + } + } + } + Deployment deploy = repositoryService.createDeployment() + .addBpmnModel(flowEntry.getProcessDefinitionKey() + ".bpmn", bpmnModel) + .name(flowEntry.getProcessDefinitionName()) + .key(flowEntry.getProcessDefinitionKey()) + .category(flowCategory.getCode()) + .deploy(); + ProcessDefinition processDefinition = flowApiService.getProcessDefinitionByDeployId(deploy.getId()); + FlowEntryPublish flowEntryPublish = new FlowEntryPublish(); + flowEntryPublish.setEntryPublishId(idGenerator.nextLongId()); + flowEntryPublish.setEntryId(flowEntry.getEntryId()); + flowEntryPublish.setProcessDefinitionId(processDefinition.getId()); + flowEntryPublish.setDeployId(processDefinition.getDeploymentId()); + flowEntryPublish.setPublishVersion(processDefinition.getVersion()); + flowEntryPublish.setActiveStatus(true); + flowEntryPublish.setMainVersion(flowEntry.getStatus().equals(FlowEntryStatus.UNPUBLISHED)); + flowEntryPublish.setCreateUserId(TokenData.takeFromRequest().getUserId()); + flowEntryPublish.setPublishTime(new Date()); + flowEntryPublish.setInitTaskInfo(initTaskInfo); + flowEntryPublishMapper.insert(flowEntryPublish); + FlowEntry updatedFlowEntry = new FlowEntry(); + updatedFlowEntry.setEntryId(flowEntry.getEntryId()); + updatedFlowEntry.setStatus(FlowEntryStatus.PUBLISHED); + updatedFlowEntry.setLastestPublishTime(new Date()); + // 对于从未发布过的工作,第一次发布的时候会将本地发布置位主版本。 + if (flowEntry.getStatus().equals(FlowEntryStatus.UNPUBLISHED)) { + updatedFlowEntry.setMainEntryPublishId(flowEntryPublish.getEntryPublishId()); + } + flowEntryMapper.updateById(updatedFlowEntry); + FlowEntryVariable flowEntryVariableFilter = new FlowEntryVariable(); + flowEntryVariableFilter.setEntryId(flowEntry.getEntryId()); + List flowEntryVariableList = + flowEntryVariableService.getFlowEntryVariableList(flowEntryVariableFilter, null); + if (CollUtil.isNotEmpty(flowTaskExtList)) { + flowTaskExtList.forEach(t -> t.setProcessDefinitionId(processDefinition.getId())); + flowTaskExtService.saveBatch(flowTaskExtList); + } + this.insertEntryPublishVariables(flowEntryVariableList, flowEntryPublish.getEntryPublishId()); + } + + /** + * 更新数据对象。 + * + * @param flowEntry 更新的对象。 + * @param originalFlowEntry 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(FlowEntry flowEntry, FlowEntry originalFlowEntry) { + flowEntry.setUpdateUserId(TokenData.takeFromRequest().getUserId()); + flowEntry.setCreateUserId(originalFlowEntry.getCreateUserId()); + flowEntry.setUpdateTime(new Date()); + flowEntry.setCreateTime(originalFlowEntry.getCreateTime()); + flowEntry.setPageId(originalFlowEntry.getPageId()); + return flowEntryMapper.updateById(flowEntry) == 1; + } + + /** + * 删除指定数据。 + * + * @param entryId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long entryId) { + if (flowEntryMapper.deleteById(entryId) != 1) { + return false; + } + flowEntryVariableService.removeByEntryId(entryId); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getFlowEntryListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getFlowEntryList(FlowEntry filter, String orderBy) { + return flowEntryMapper.getFlowEntryList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getFlowEntryList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getFlowEntryListWithRelation(FlowEntry filter, String orderBy) { + List resultList = flowEntryMapper.getFlowEntryList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + Set mainEntryPublishIdSet = resultList.stream().filter(e -> e.getMainEntryPublishId() != null) + .map(FlowEntry::getMainEntryPublishId).collect(Collectors.toSet()); + if (CollUtil.isNotEmpty(mainEntryPublishIdSet)) { + List mainEntryPublishList = + flowEntryPublishMapper.selectBatchIds(mainEntryPublishIdSet); + MyModelUtil.makeOneToOneRelation(FlowEntry.class, resultList, FlowEntry::getMainEntryPublishId, + mainEntryPublishList, FlowEntryPublish::getEntryPublishId, "mainFlowEntryPublish"); + } + return resultList; + } + + @Override + public FlowEntry getFlowEntryByProcessDefinitionKey(String processDefinitionKey) { + FlowEntry filter = new FlowEntry(); + filter.setProcessDefinitionKey(processDefinitionKey); + return flowEntryMapper.selectOne(new LambdaQueryWrapper<>(filter)); + } + + /** + * 根据流程Id获取流程发布列表数据。 + * + * @param entryId 流程Id。 + * @return 流程关联的发布列表数据。 + */ + @Override + public List getFlowEntryPublishList(Long entryId) { + FlowEntryPublish filter = new FlowEntryPublish(); + filter.setEntryId(entryId); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(filter); + queryWrapper.orderByDesc(FlowEntryPublish::getEntryPublishId); + return flowEntryPublishMapper.selectList(queryWrapper); + } + + /** + * 根据流程引擎中的流程定义Id集合,查询流程发布对象。 + * + * @param processDefinitionIdSet 流程引擎中的流程定义Id集合。 + * @return 查询结果。 + */ + @Override + public List getFlowEntryPublishList(Set processDefinitionIdSet) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(FlowEntryPublish::getProcessDefinitionId, processDefinitionIdSet); + return flowEntryPublishMapper.selectList(queryWrapper); + } + + /** + * 获取指定工作流发布版本对象。同时同步修改工作流对象中冗余状态字段。 + * + * @param entryPublishId 工作流发布对象Id。 + * @return 查询后的对象。 + */ + @Override + public FlowEntryPublish getFlowEntryPublishById(Long entryPublishId) { + return flowEntryPublishMapper.selectById(entryPublishId); + } + + /** + * 获取指定流程定义Id对应的流程发布对象。 + * + * @param processDefinitionId 流程定义Id。 + * @return 流程发布对象。 + */ + @Override + public FlowEntryPublish getFlowEntryPublishByDefinitionId(String processDefinitionId) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(FlowEntryPublish::getProcessDefinitionId, processDefinitionId); + return flowEntryPublishMapper.selectOne(queryWrapper); + } + + /** + * 为指定工作流切换发布的主版本。 + * + * @param flowEntry 工作流对象。 + * @param newMainFlowEntryPublish 工作流新的发布主版本对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void updateFlowEntryMainVersion(FlowEntry flowEntry, FlowEntryPublish newMainFlowEntryPublish) { + FlowEntryPublish oldMainFlowEntryPublish = + flowEntryPublishMapper.selectById(flowEntry.getMainEntryPublishId()); + oldMainFlowEntryPublish.setMainVersion(false); + flowEntryPublishMapper.updateById(oldMainFlowEntryPublish); + newMainFlowEntryPublish.setMainVersion(true); + flowEntryPublishMapper.updateById(newMainFlowEntryPublish); + FlowEntry updatedEntry = new FlowEntry(); + updatedEntry.setEntryId(flowEntry.getEntryId()); + updatedEntry.setMainEntryPublishId(newMainFlowEntryPublish.getEntryPublishId()); + flowEntryMapper.updateById(updatedEntry); + } + + /** + * 挂起指定的工作流发布对象。同时同步修改工作流对象中冗余状态字段。 + * + * @param flowEntryPublish 待挂起的工作流发布对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void suspendFlowEntryPublish(FlowEntryPublish flowEntryPublish) { + FlowEntryPublish updatedEntryPublish = new FlowEntryPublish(); + updatedEntryPublish.setEntryPublishId(flowEntryPublish.getEntryPublishId()); + updatedEntryPublish.setActiveStatus(false); + flowEntryPublishMapper.updateById(updatedEntryPublish); + flowApiService.suspendProcessDefinition(flowEntryPublish.getProcessDefinitionId()); + } + + /** + * 激活指定的工作流发布对象。 + * + * @param flowEntryPublish 待恢复的工作流发布对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void activateFlowEntryPublish(FlowEntryPublish flowEntryPublish) { + FlowEntryPublish updatedEntryPublish = new FlowEntryPublish(); + updatedEntryPublish.setEntryPublishId(flowEntryPublish.getEntryPublishId()); + updatedEntryPublish.setActiveStatus(true); + flowEntryPublishMapper.updateById(updatedEntryPublish); + flowApiService.activateProcessDefinition(flowEntryPublish.getProcessDefinitionId()); + } + + /** + * 主表的关联数据验证。 + * + * @param flowEntry 最新数据对象。 + * @param originalFlowEntry 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + @Override + public CallResult verifyRelatedData(FlowEntry flowEntry, FlowEntry originalFlowEntry) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + if (this.needToVerify(flowEntry, originalFlowEntry, FlowEntry::getCategoryId) + && !flowCategoryService.existId(flowEntry.getCategoryId())) { + return CallResult.error(String.format(errorMessageFormat, "流程类别Id")); + } + return CallResult.ok(); + } + + private void insertBuiltinEntryVariables(Long entryId) { + Date now = new Date(); + FlowEntryVariable operationTypeVariable = new FlowEntryVariable(); + operationTypeVariable.setVariableId(idGenerator.nextLongId()); + operationTypeVariable.setEntryId(entryId); + operationTypeVariable.setVariableName(FlowConstant.OPERATION_TYPE_VAR); + operationTypeVariable.setShowName("审批类型"); + operationTypeVariable.setVariableType(FlowVariableType.TASK); + operationTypeVariable.setBuiltin(true); + operationTypeVariable.setCreateTime(now); + flowEntryVariableService.saveNew(operationTypeVariable); + FlowEntryVariable startUserNameVariable = new FlowEntryVariable(); + startUserNameVariable.setVariableId(idGenerator.nextLongId()); + startUserNameVariable.setEntryId(entryId); + startUserNameVariable.setVariableName("startUserName"); + startUserNameVariable.setShowName("流程启动用户"); + startUserNameVariable.setVariableType(FlowVariableType.INSTANCE); + startUserNameVariable.setBuiltin(true); + startUserNameVariable.setCreateTime(now); + flowEntryVariableService.saveNew(startUserNameVariable); + } + + private void insertEntryPublishVariables(List entryVariableList, Long entryPublishId) { + if (CollUtil.isEmpty(entryVariableList)) { + return; + } + List entryPublishVariableList = + MyModelUtil.copyCollectionTo(entryVariableList, FlowEntryPublishVariable.class); + for (FlowEntryPublishVariable variable : entryPublishVariableList) { + variable.setVariableId(idGenerator.nextLongId()); + variable.setEntryPublishId(entryPublishId); + } + flowEntryPublishVariableMapper.insertList(entryPublishVariableList); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowEntryVariableServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowEntryVariableServiceImpl.java new file mode 100644 index 00000000..744e49b7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowEntryVariableServiceImpl.java @@ -0,0 +1,131 @@ +package com.flow.demo.common.flow.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.flow.dao.*; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 流程变量数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("flowEntryVariableService") +public class FlowEntryVariableServiceImpl extends BaseService implements FlowEntryVariableService { + + @Autowired + private FlowEntryVariableMapper flowEntryVariableMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return flowEntryVariableMapper; + } + + /** + * 保存新增对象。 + * + * @param flowEntryVariable 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public FlowEntryVariable saveNew(FlowEntryVariable flowEntryVariable) { + flowEntryVariable.setVariableId(idGenerator.nextLongId()); + flowEntryVariable.setCreateTime(new Date()); + flowEntryVariableMapper.insert(flowEntryVariable); + return flowEntryVariable; + } + + /** + * 更新数据对象。 + * + * @param flowEntryVariable 更新的对象。 + * @param originalFlowEntryVariable 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(FlowEntryVariable flowEntryVariable, FlowEntryVariable originalFlowEntryVariable) { + flowEntryVariable.setCreateTime(originalFlowEntryVariable.getCreateTime()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + UpdateWrapper uw = this.createUpdateQueryForNullValue(flowEntryVariable, flowEntryVariable.getVariableId()); + return flowEntryVariableMapper.update(flowEntryVariable, uw) == 1; + } + + /** + * 删除指定数据。 + * + * @param variableId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long variableId) { + return flowEntryVariableMapper.deleteById(variableId) == 1; + } + + /** + * 删除指定流程Id的所有变量。 + * + * @param entryId 流程Id。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void removeByEntryId(Long entryId) { + flowEntryVariableMapper.delete( + new LambdaQueryWrapper().eq(FlowEntryVariable::getEntryId, entryId)); + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getFlowEntryVariableListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getFlowEntryVariableList(FlowEntryVariable filter, String orderBy) { + return flowEntryVariableMapper.getFlowEntryVariableList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getFlowEntryVariableList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getFlowEntryVariableListWithRelation(FlowEntryVariable filter, String orderBy) { + List resultList = flowEntryVariableMapper.getFlowEntryVariableList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowTaskCommentServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowTaskCommentServiceImpl.java new file mode 100644 index 00000000..9bc99f6b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowTaskCommentServiceImpl.java @@ -0,0 +1,74 @@ +package com.flow.demo.common.flow.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.flow.dao.*; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 流程任务批注数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("flowTaskCommentService") +public class FlowTaskCommentServiceImpl extends BaseService implements FlowTaskCommentService { + + @Autowired + private FlowTaskCommentMapper flowTaskCommentMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return flowTaskCommentMapper; + } + + /** + * 保存新增对象。 + * + * @param flowTaskComment 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public FlowTaskComment saveNew(FlowTaskComment flowTaskComment) { + flowTaskComment.setId(idGenerator.nextLongId()); + TokenData tokenData = TokenData.takeFromRequest(); + flowTaskComment.setCreateUserId(tokenData.getUserId()); + flowTaskComment.setCreateUsername(tokenData.getShowName()); + flowTaskComment.setCreateTime(new Date()); + flowTaskCommentMapper.insert(flowTaskComment); + return flowTaskComment; + } + + /** + * 查询指定流程实例Id下的所有审批任务的批注。 + * + * @param processInstanceId 流程实例Id。 + * @return 查询结果集。 + */ + @Override + public List getFlowTaskCommentList(String processInstanceId) { + LambdaQueryWrapper queryWrapper = + new LambdaQueryWrapper().eq(FlowTaskComment::getProcessInstanceId, processInstanceId); + queryWrapper.orderByAsc(FlowTaskComment::getId); + return flowTaskCommentMapper.selectList(queryWrapper); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowTaskExtServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowTaskExtServiceImpl.java new file mode 100644 index 00000000..0085c27d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowTaskExtServiceImpl.java @@ -0,0 +1,62 @@ +package com.flow.demo.common.flow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.flow.demo.common.flow.service.*; +import com.flow.demo.common.flow.dao.*; +import com.flow.demo.common.flow.model.*; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 流程任务扩展数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("flowTaskExtService") +public class FlowTaskExtServiceImpl extends BaseService implements FlowTaskExtService { + + @Autowired + private FlowTaskExtMapper flowTaskExtMapper; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return flowTaskExtMapper; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void saveBatch(List flowTaskExtList) { + if (CollUtil.isNotEmpty(flowTaskExtList)) { + flowTaskExtMapper.insertList(flowTaskExtList); + } + } + + @Override + public FlowTaskExt getByProcessDefinitionIdAndTaskId(String processDefinitionId, String taskId) { + FlowTaskExt filter = new FlowTaskExt(); + filter.setProcessDefinitionId(processDefinitionId); + filter.setTaskId(taskId); + return flowTaskExtMapper.selectOne(new QueryWrapper<>(filter)); + } + + @Override + public List getByProcessDefinitionId(String processDefinitionId) { + FlowTaskExt filter = new FlowTaskExt(); + filter.setProcessDefinitionId(processDefinitionId); + return flowTaskExtMapper.selectList(new QueryWrapper<>(filter)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowWorkOrderServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowWorkOrderServiceImpl.java new file mode 100644 index 00000000..8e83db58 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/service/impl/FlowWorkOrderServiceImpl.java @@ -0,0 +1,136 @@ +package com.flow.demo.common.flow.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.flow.constant.FlowTaskStatus; +import com.flow.demo.common.flow.dao.FlowWorkOrderMapper; +import com.flow.demo.common.flow.model.FlowWorkOrder; +import com.flow.demo.common.flow.service.FlowWorkOrderService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import lombok.extern.slf4j.Slf4j; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 工作流工单表数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("flowWorkOrderService") +public class FlowWorkOrderServiceImpl extends BaseService implements FlowWorkOrderService { + + @Autowired + private FlowWorkOrderMapper flowWorkOrderMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return flowWorkOrderMapper; + } + + /** + * 保存新增对象。 + * + * @param instance 流程实例对象。 + * @param dataId 流程实例的BusinessKey。 + * @param onlineTableId 在线数据表的主键Id。 + * @return 新增的工作流工单对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public FlowWorkOrder saveNew(ProcessInstance instance, Object dataId, Long onlineTableId) { + TokenData tokenData = TokenData.takeFromRequest(); + Date now = new Date(); + FlowWorkOrder flowWorkOrder = new FlowWorkOrder(); + flowWorkOrder.setWorkOrderId(idGenerator.nextLongId()); + flowWorkOrder.setProcessDefinitionKey(instance.getProcessDefinitionKey()); + flowWorkOrder.setProcessDefinitionName(instance.getProcessDefinitionName()); + flowWorkOrder.setProcessDefinitionId(instance.getProcessDefinitionId()); + flowWorkOrder.setProcessInstanceId(instance.getId()); + flowWorkOrder.setBusinessKey(dataId.toString()); + flowWorkOrder.setOnlineTableId(onlineTableId); + flowWorkOrder.setFlowStatus(FlowTaskStatus.SUBMITTED); + flowWorkOrder.setSubmitUsername(tokenData.getLoginName()); + flowWorkOrder.setDeptId(tokenData.getDeptId()); + flowWorkOrder.setCreateUserId(tokenData.getUserId()); + flowWorkOrder.setUpdateUserId(tokenData.getUserId()); + flowWorkOrder.setCreateTime(now); + flowWorkOrder.setUpdateTime(now); + flowWorkOrder.setDeletedFlag(GlobalDeletedFlag.NORMAL); + flowWorkOrderMapper.insert(flowWorkOrder); + return flowWorkOrder; + } + + /** + * 删除指定数据。 + * + * @param workOrderId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long workOrderId) { + return flowWorkOrderMapper.deleteById(workOrderId) == 1; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void removeByProcessInstanceId(String processInstanceId) { + FlowWorkOrder filter = new FlowWorkOrder(); + filter.setProcessInstanceId(processInstanceId); + super.removeBy(filter); + } + + @Override + public List getFlowWorkOrderList(FlowWorkOrder filter, String orderBy) { + return flowWorkOrderMapper.getFlowWorkOrderList(filter, orderBy); + } + + @Override + public List getFlowWorkOrderListWithRelation(FlowWorkOrder filter, String orderBy) { + List resultList = flowWorkOrderMapper.getFlowWorkOrderList(filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly()); + return resultList; + } + + @Override + public boolean existByBusinessKey(Object businessKey, boolean unfinished) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(FlowWorkOrder::getBusinessKey, businessKey.toString()); + if (unfinished) { + queryWrapper.notIn(FlowWorkOrder::getFlowStatus, + FlowTaskStatus.FINISHED, FlowTaskStatus.CANCELLED, FlowTaskStatus.STOPPED); + } + return flowWorkOrderMapper.selectCount(queryWrapper) > 0; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void updateFlowStatusByProcessInstanceId(String processInstanceId, int flowStatus) { + FlowWorkOrder flowWorkOrder = new FlowWorkOrder(); + flowWorkOrder.setFlowStatus(flowStatus); + if (FlowTaskStatus.FINISHED != flowStatus) { + flowWorkOrder.setUpdateTime(new Date()); + flowWorkOrder.setUpdateUserId(TokenData.takeFromRequest().getUserId()); + } + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(FlowWorkOrder::getProcessInstanceId, processInstanceId); + flowWorkOrderMapper.update(flowWorkOrder, queryWrapper); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/BaseFlowDeptPostExtHelper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/BaseFlowDeptPostExtHelper.java new file mode 100644 index 00000000..0aeae641 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/BaseFlowDeptPostExtHelper.java @@ -0,0 +1,75 @@ +package com.flow.demo.common.flow.util; + +import com.flow.demo.common.flow.listener.DeptPostLeaderListener; +import com.flow.demo.common.flow.listener.UpDeptPostLeaderListener; +import org.flowable.engine.delegate.TaskListener; + +/** + * 工作流与部门岗位相关的自定义扩展接口,需要业务模块自行实现该接口。也可以根据实际需求扩展该接口的方法。 + * 目前支持的主键类型为字符型和长整型,所以这里提供了两套实现接口。可根据实际情况实现其中一套即可。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface BaseFlowDeptPostExtHelper { + + /** + * 根据(字符型)部门Id,获取当前用户部门领导所有的部门岗位Id。 + * + * @param deptId 用户所在部门Id。 + * @return 当前用户部门领导所有的部门岗位Id。 + */ + default String getLeaderDeptPostId(String deptId) { + return null; + } + + /** + * 根据(字符型)部门Id,获取当前用户上级部门领导所有的部门岗位Id。 + * + * @param deptId 用户所在部门Id。 + * @return 当前用户上级部门领导所有的部门岗位Id。 + */ + default String getUpLeaderDeptPostId(String deptId) { + return null; + } + + /** + * 根据(长整型)部门Id,获取当前用户部门领导所有的部门岗位Id。 + * + * @param deptId 用户所在部门Id。 + * @return 当前用户部门领导所有的部门岗位Id。 + */ + default Long getLeaderDeptPostId(Long deptId) { + return null; + } + + /** + * 根据(长整型)部门Id,获取当前用户上级部门领导所有的部门岗位Id。 + * + * @param deptId 用户所在部门Id。 + * @return 当前用户上级部门领导所有的部门岗位Id。 + */ + default Long getUpLeaderDeptPostId(Long deptId) { + return null; + } + + /** + * 获取任务执行人是当前部门领导岗位的任务监听器。 + * 通常会在没有找到领导部门岗位Id的时候,为当前任务指定其他的指派人、候选人或候选组。 + * + * @return 任务监听器。 + */ + default Class getDeptPostLeaderListener() { + return DeptPostLeaderListener.class; + } + + /** + * 获取任务执行人是上级部门领导岗位的任务监听器。 + * 通常会在没有找到领导部门岗位Id的时候,为当前任务指定其他的指派人、候选人或候选组。 + * + * @return 任务监听器。 + */ + default Class getUpDeptPostLeaderListener() { + return UpDeptPostLeaderListener.class; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/FlowCustomExtFactory.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/FlowCustomExtFactory.java new file mode 100644 index 00000000..3fed4503 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/FlowCustomExtFactory.java @@ -0,0 +1,33 @@ +package com.flow.demo.common.flow.util; + +import org.springframework.stereotype.Component; + +/** + * 工作流自定义扩展工厂类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Component +public class FlowCustomExtFactory { + + private BaseFlowDeptPostExtHelper flowDeptPostExtHelper; + + /** + * 获取业务模块自行实现的部门岗位扩展帮助实现类。 + * + * @return 业务模块自行实现的部门岗位扩展帮助实现类。 + */ + public BaseFlowDeptPostExtHelper getFlowDeptPostExtHelper() { + return flowDeptPostExtHelper; + } + + /** + * 注册业务模块自行实现的部门岗位扩展帮助实现类。 + * + * @param helper 业务模块自行实现的部门岗位扩展帮助实现类。 + */ + public void registerFlowDeptPostExtHelper(BaseFlowDeptPostExtHelper helper) { + this.flowDeptPostExtHelper = helper; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/FlowOperationHelper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/FlowOperationHelper.java new file mode 100644 index 00000000..dc793f5b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/util/FlowOperationHelper.java @@ -0,0 +1,248 @@ +package com.flow.demo.common.flow.util; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.ResponseResult; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.flow.constant.FlowConstant; +import com.flow.demo.common.flow.constant.FlowTaskStatus; +import com.flow.demo.common.flow.dto.FlowWorkOrderDto; +import com.flow.demo.common.flow.model.FlowEntry; +import com.flow.demo.common.flow.model.FlowEntryPublish; +import com.flow.demo.common.flow.model.FlowWorkOrder; +import com.flow.demo.common.flow.model.constant.FlowEntryStatus; +import com.flow.demo.common.flow.service.FlowApiService; +import com.flow.demo.common.flow.service.FlowEntryService; +import com.flow.demo.common.flow.vo.FlowWorkOrderVo; +import com.flow.demo.common.flow.vo.TaskInfoVo; +import lombok.extern.slf4j.Slf4j; +import org.flowable.task.api.Task; +import org.flowable.task.api.TaskInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 工作流操作的通用帮助对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Component +public class FlowOperationHelper { + + @Autowired + private FlowEntryService flowEntryService; + @Autowired + private FlowApiService flowApiService; + + /** + * 验证并获取流程对象。 + * + * @param processDefinitionKey 流程引擎的流程定义标识。 + * @return 流程对象。 + */ + public ResponseResult verifyAndGetFlowEntry(String processDefinitionKey) { + String errorMessage; + FlowEntry flowEntry = flowEntryService.getFlowEntryByProcessDefinitionKey(processDefinitionKey); + if (flowEntry == null) { + errorMessage = "数据验证失败,该流程并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!flowEntry.getStatus().equals(FlowEntryStatus.PUBLISHED)) { + errorMessage = "数据验证失败,该流程尚未发布,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + FlowEntryPublish flowEntryPublish = + flowEntryService.getFlowEntryPublishById(flowEntry.getMainEntryPublishId()); + flowEntry.setMainFlowEntryPublish(flowEntryPublish); + return ResponseResult.success(flowEntry); + } + + /** + * 验证并获取流程的实时任务信息。 + * + * @param task 流程引擎的任务对象。 + * @return 任务信息对象。 + */ + public ResponseResult verifyAndGetRuntimeTaskInfo(Task task) { + String errorMessage; + if (task == null) { + errorMessage = "数据验证失败,指定的任务Id,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!flowApiService.isAssigneeOrCandidate(task)) { + errorMessage = "数据验证失败,当前用户不是指派人也不是候选人之一!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (StrUtil.isBlank(task.getFormKey())) { + errorMessage = "数据验证失败,指定任务的formKey属性不存在,请重新修改流程图!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + TaskInfoVo taskInfo = JSON.parseObject(task.getFormKey(), TaskInfoVo.class); + taskInfo.setTaskKey(task.getTaskDefinitionKey()); + return ResponseResult.success(taskInfo); + } + + /** + * 验证并获取启动任务的对象信息。 + * + * @param flowEntryPublish 流程发布对象。 + * @param checkStarter 是否检查发起用户。 + * @return 第一个可执行的任务信息。 + */ + public ResponseResult verifyAndGetInitialTaskInfo( + FlowEntryPublish flowEntryPublish, boolean checkStarter) { + String errorMessage; + if (StrUtil.isBlank(flowEntryPublish.getInitTaskInfo())) { + errorMessage = "数据验证失败,当前流程发布的数据中,没有包含初始任务信息!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + TaskInfoVo taskInfo = JSON.parseObject(flowEntryPublish.getInitTaskInfo(), TaskInfoVo.class); + if (checkStarter) { + String loginName = TokenData.takeFromRequest().getLoginName(); + if (!StrUtil.equalsAny(taskInfo.getAssignee(), loginName, FlowConstant.START_USER_NAME_VAR)) { + errorMessage = "数据验证失败,该工作流第一个用户任务的指派人并非当前用户,不能执行该操作!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + return ResponseResult.success(taskInfo); + } + + /** + * 判断当前用户是否有当前流程实例的数据上传或下载权限。 + * 如果taskId为空,则验证当前用户是否为当前流程实例的发起人,否则判断是否为当前任务的指派人或候选人。 + * + * @param processInstanceId 流程实例Id。 + * @param taskId 流程任务Id。 + * @return 验证结果。 + */ + public ResponseResult verifyUploadOrDownloadPermission(String processInstanceId, String taskId) { + String errorMessage; + if (StrUtil.isBlank(taskId)) { + if (!flowApiService.isProcessInstanceStarter(processInstanceId)) { + errorMessage = "数据验证失败,当前用户并非指派人或候选人,因此没有权限下载!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + } else { + TaskInfo task = flowApiService.getProcessInstanceActiveTask(processInstanceId, taskId); + if (task == null) { + task = flowApiService.getHistoricTaskInstance(processInstanceId, taskId); + if (task == null) { + errorMessage = "数据验证失败,指定任务Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + } + if (!flowApiService.isAssigneeOrCandidate(task)) { + errorMessage = "数据验证失败,当前用户并非指派人或候选人,因此没有权限下载!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + } + return ResponseResult.success(); + } + + /** + * 根据已有的过滤对象,补充添加缺省过滤条件。如流程标识、创建用户等。 + * + * @param filterDto 工单过滤对象。 + * @param processDefinitionKey 流程标识。 + * @return 创建并转换后的流程工单过滤对象。 + */ + public FlowWorkOrder makeWorkOrderFilter(FlowWorkOrderDto filterDto, String processDefinitionKey) { + FlowWorkOrder filter = MyModelUtil.copyTo(filterDto, FlowWorkOrder.class); + if (filter == null) { + filter = new FlowWorkOrder(); + } + filter.setProcessDefinitionKey(processDefinitionKey); + filter.setCreateUserId(TokenData.takeFromRequest().getUserId()); + return filter; + } + + /** + * 组装工作流工单列表中的流程任务数据。 + * + * @param flowWorkOrderVoList 工作流工单列表。 + */ + public void buildWorkOrderTaskInfo(List flowWorkOrderVoList) { + if (CollUtil.isEmpty(flowWorkOrderVoList)) { + return; + } + Set definitionIdSet = + flowWorkOrderVoList.stream().map(FlowWorkOrderVo::getProcessDefinitionId).collect(Collectors.toSet()); + List flowEntryPublishList = flowEntryService.getFlowEntryPublishList(definitionIdSet); + Map flowEntryPublishMap = + flowEntryPublishList.stream().collect(Collectors.toMap(FlowEntryPublish::getProcessDefinitionId, c -> c)); + for (FlowWorkOrderVo flowWorkOrderVo : flowWorkOrderVoList) { + FlowEntryPublish flowEntryPublish = flowEntryPublishMap.get(flowWorkOrderVo.getProcessDefinitionId()); + flowWorkOrderVo.setInitTaskInfo(flowEntryPublish.getInitTaskInfo()); + } + List unfinishedProcessInstanceIds = flowWorkOrderVoList.stream() + .filter(c -> !c.getFlowStatus().equals(FlowTaskStatus.FINISHED)) + .map(FlowWorkOrderVo::getProcessInstanceId) + .collect(Collectors.toList()); + if (CollUtil.isEmpty(unfinishedProcessInstanceIds)) { + return; + } + List taskList = flowApiService.getTaskListByProcessInstanceIds(unfinishedProcessInstanceIds); + Map> taskMap = + taskList.stream().collect(Collectors.groupingBy(Task::getProcessInstanceId)); + for (FlowWorkOrderVo flowWorkOrderVo : flowWorkOrderVoList) { + List instanceTaskList = taskMap.get(flowWorkOrderVo.getProcessInstanceId()); + if (instanceTaskList == null) { + continue; + } + JSONArray taskArray = new JSONArray(); + for (Task task : instanceTaskList) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("taskId", task.getId()); + jsonObject.put("taskName", task.getName()); + jsonObject.put("taskKey", task.getTaskDefinitionKey()); + jsonObject.put("assignee", task.getAssignee()); + taskArray.add(jsonObject); + } + flowWorkOrderVo.setRuntimeTaskInfoList(taskArray); + } + } + + /** + * 组装工作流工单中的业务数据。 + * + * @param workOrderVoList 工单列表。 + * @param dataList 业务数据列表。 + * @param idGetter 获取业务对象主键字段的返回方法。 + * @param 业务主对象类型。 + * @param 业务主对象的主键字段类型。 + */ + public void buildWorkOrderBusinessData( + List workOrderVoList, List dataList, Function idGetter) { + if (CollUtil.isEmpty(dataList)) { + return; + } + Map dataMap = dataList.stream().collect(Collectors.toMap(idGetter, c -> c)); + K id = idGetter.apply(dataList.get(0)); + for (FlowWorkOrderVo flowWorkOrderVo : workOrderVoList) { + Object dataId = flowWorkOrderVo.getBusinessKey(); + if (id instanceof Long) { + dataId = Long.valueOf(flowWorkOrderVo.getBusinessKey()); + } else if (id instanceof Integer) { + dataId = Integer.valueOf(flowWorkOrderVo.getBusinessKey()); + } + T data = dataMap.get(dataId); + if (data != null) { + flowWorkOrderVo.setMasterData(BeanUtil.beanToMap(data)); + } + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowCategoryVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowCategoryVo.java new file mode 100644 index 00000000..9c36f2bd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowCategoryVo.java @@ -0,0 +1,55 @@ +package com.flow.demo.common.flow.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * 流程分类的Vo对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowCategoryVo { + + /** + * 主键Id。 + */ + private Long categoryId; + + /** + * 显示名称。 + */ + private String name; + + /** + * 分类编码。 + */ + private String code; + + /** + * 实现顺序。 + */ + private Integer showOrder; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 创建者Id。 + */ + private Long createUserId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryPublishVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryPublishVo.java new file mode 100644 index 00000000..7bf65df9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryPublishVo.java @@ -0,0 +1,50 @@ +package com.flow.demo.common.flow.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * 流程发布信息的Vo对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowEntryPublishVo { + + /** + * 主键Id。 + */ + private Long entryPublishId; + + /** + * 发布版本。 + */ + private Integer publishVersion; + + /** + * 流程引擎中的流程定义Id。 + */ + private String processDefinitionId; + + /** + * 激活状态。 + */ + private Boolean activeStatus; + + /** + * 是否为主版本。 + */ + private Boolean mainVersion; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 发布时间。 + */ + private Date publishTime; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryVariableVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryVariableVo.java new file mode 100644 index 00000000..2e33adfc --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryVariableVo.java @@ -0,0 +1,65 @@ +package com.flow.demo.common.flow.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * 流程变量Vo对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowEntryVariableVo { + + /** + * 主键Id。 + */ + private Long variableId; + + /** + * 流程Id。 + */ + private Long entryId; + + /** + * 变量名。 + */ + private String variableName; + + /** + * 显示名。 + */ + private String showName; + + /** + * 变量类型。 + */ + private Integer variableType; + + /** + * 绑定数据源Id。 + */ + private Long bindDatasourceId; + + /** + * 绑定数据源关联Id。 + */ + private Long bindRelationId; + + /** + * 绑定字段Id。 + */ + private Long bindColumnId; + + /** + * 是否内置。 + */ + private Boolean builtin; + + /** + * 创建时间。 + */ + private Date createTime; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryVo.java new file mode 100644 index 00000000..f9f893a6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowEntryVo.java @@ -0,0 +1,112 @@ +package com.flow.demo.common.flow.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 流程的Vo对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowEntryVo { + + /** + * 主键Id。 + */ + private Long entryId; + + /** + * 流程名称。 + */ + private String processDefinitionName; + + /** + * 流程标识Key。 + */ + private String processDefinitionKey; + + /** + * 流程分类。 + */ + private Long categoryId; + + /** + * 工作流部署的发布主版本Id。 + */ + private Long mainEntryPublishId; + + /** + * 最新发布时间。 + */ + private Date lastestPublishTime; + + /** + * 流程状态。 + */ + private Integer status; + + /** + * 流程定义的xml。 + */ + private String bpmnXml; + + /** + * 绑定表单类型。 + */ + private Integer bindFormType; + + /** + * 在线表单的页面Id。 + */ + private Long pageId; + + /** + * 在线表单Id。 + */ + private Long defaultFormId; + + /** + * 在线表单的缺省路由名称。 + */ + private String defaultRouterName; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * categoryId 的一对一关联数据对象,数据对应类型为FlowCategoryVo。 + */ + private Map flowCategory; + + /** + * mainEntryPublishId 的一对一关联数据对象,数据对应类型为FlowEntryPublishVo。 + */ + private Map mainFlowEntryPublish; + + /** + * 关联的在线表单列表。 + */ + private List> formList; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowTaskCommentVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowTaskCommentVo.java new file mode 100644 index 00000000..d73f0fb5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowTaskCommentVo.java @@ -0,0 +1,70 @@ +package com.flow.demo.common.flow.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * FlowTaskCommentVO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowTaskCommentVo { + + /** + * 主键Id。 + */ + private Long id; + + /** + * 流程实例Id。 + */ + private String processInstanceId; + + /** + * 任务Id。 + */ + private String taskId; + + /** + * 任务标识。 + */ + private String taskKey; + + /** + * 任务名称。 + */ + private String taskName; + + /** + * 审批类型。 + */ + private String approvalType; + + /** + * 批注内容。 + */ + private String comment; + + /** + * 委托指定人,比如加签、转办等。 + */ + private String delegateAssginee; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * 创建者显示名。 + */ + private String createUsername; + + /** + * 创建时间。 + */ + private Date createTime; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowTaskVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowTaskVo.java new file mode 100644 index 00000000..9818892f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowTaskVo.java @@ -0,0 +1,75 @@ +package com.flow.demo.common.flow.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * 流程任务Vo对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowTaskVo { + + /** + * 流程任务Id。 + */ + private String taskId; + + /** + * 流程任务名称。 + */ + private String taskName; + + /** + * 流程任务标识。 + */ + private String taskKey; + + /** + * 任务的表单信息。 + */ + private String taskFormKey; + + /** + * 流程Id。 + */ + private Long entryId; + + /** + * 流程定义Id。 + */ + private String processDefinitionId; + + /** + * 流程定义名称。 + */ + private String processDefinitionName; + + /** + * 流程定义标识。 + */ + private String processDefinitionKey; + + /** + * 流程定义版本。 + */ + private Integer processDefinitionVersion; + + /** + * 流程实例Id。 + */ + private String processInstanceId; + + /** + * 流程实例发起人。 + */ + private String processInstanceInitiator; + + /** + * 流程实例创建时间。 + */ + private Date processInstanceStartTime; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowWorkOrderVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowWorkOrderVo.java new file mode 100644 index 00000000..6d213db5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/FlowWorkOrderVo.java @@ -0,0 +1,108 @@ +package com.flow.demo.common.flow.vo; + +import com.alibaba.fastjson.JSONArray; +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 工作流工单VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class FlowWorkOrderVo { + + /** + * 主键Id。 + */ + private Long workOrderId; + + /** + * 流程定义标识。 + */ + private String processDefinitionKey; + + /** + * 流程名称。 + */ + private String processDefinitionName; + + /** + * 流程引擎的定义Id。 + */ + private String processDefinitionId; + + /** + * 流程实例Id。 + */ + private String processInstanceId; + + /** + * 在线表单的主表Id。 + */ + private Long onlineTableId; + + /** + * 业务主键值。 + */ + private String businessKey; + + /** + * 流程状态。 + */ + private Integer flowStatus; + + /** + * 提交用户登录名称。 + */ + private String submitUsername; + + /** + * 提交用户所在部门Id。 + */ + private Long deptId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 更新者Id。 + */ + private Long updateUserId; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 创建者Id。 + */ + private Long createUserId; + + /** + * flowStatus 常量字典关联数据。 + */ + private Map flowStatusDictMap; + + /** + * FlowEntryPublish对象中的同名字段。 + */ + private String initTaskInfo; + + /** + * 当前实例的运行时任务列表。 + * 正常情况下只有一个,在并行网关下可能存在多个。 + */ + private JSONArray runtimeTaskInfoList; + + /** + * 业务主表数据。 + */ + private Map masterData; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/TaskInfoVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/TaskInfoVo.java new file mode 100644 index 00000000..585ff88e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/java/com/flow/demo/common/flow/vo/TaskInfoVo.java @@ -0,0 +1,67 @@ +package com.flow.demo.common.flow.vo; + +import com.alibaba.fastjson.JSONObject; +import lombok.Data; + +import java.util.List; + +/** + * 流程任务信息Vo对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class TaskInfoVo { + + /** + * 流程节点任务类型。具体值可参考FlowTaskType常量值。 + */ + private Integer taskType; + + /** + * 指定人。 + */ + private String assignee; + + /** + * 任务标识。 + */ + private String taskKey; + + /** + * 是否分配给当前登录用户的标记。 + * 当该值为true时,登录用户启动流程时,就自动完成了第一个用户任务。 + */ + private Boolean assignedMe; + + /** + * 动态表单Id。 + */ + private Long formId; + + /** + * 静态表单路由。 + */ + private String routerName; + + /** + * 候选组类型。 + */ + private String groupType; + + /** + * 只读标记。 + */ + private Boolean readOnly; + + /** + * 前端所需的操作列表。 + */ + List operationList; + + /** + * 任务节点的自定义变量列表。 + */ + List variableList; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/resources/META-INF/spring.factories b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..b6a8bca9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-flow/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.flow.demo.common.flow.config.FlowAutoConfig \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/pom.xml new file mode 100644 index 00000000..f942612c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/pom.xml @@ -0,0 +1,43 @@ + + + + common + com.flow.demo + 1.0.0 + + 4.0.0 + + common-log + 1.0.0 + common-log + jar + + + + com.flow.demo + common-sequence + 1.0.0 + + + + + + + src/main/resources + + **/*.* + + false + + + src/main/java + + **/*.xml + + false + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/annotation/OperationLog.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/annotation/OperationLog.java new file mode 100644 index 00000000..7be072a4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/annotation/OperationLog.java @@ -0,0 +1,33 @@ +package com.flow.demo.common.log.annotation; + +import com.flow.demo.common.log.model.constant.SysOperationLogType; + +import java.lang.annotation.*; + +/** + * 操作日志记录注解。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface OperationLog { + + /** + * 描述。 + */ + String description() default ""; + + /** + * 操作类型。 + */ + int type() default SysOperationLogType.OTHER; + + /** + * 是否保存应答结果。 + * 对于类似导出和文件下载之类的接口,该参与应该设置为false。 + */ + boolean saveResponse() default true; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/aop/OperationLogAspect.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/aop/OperationLogAspect.java new file mode 100644 index 00000000..32b2d492 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/aop/OperationLogAspect.java @@ -0,0 +1,251 @@ +package com.flow.demo.common.log.aop; + +import cn.hutool.core.collection.CollUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.constant.ApplicationConstant; +import com.flow.demo.common.core.object.ResponseResult; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.core.util.ContextUtil; +import com.flow.demo.common.core.util.IpUtil; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.log.annotation.OperationLog; +import com.flow.demo.common.log.config.OperationLogProperties; +import com.flow.demo.common.log.model.SysOperationLog; +import com.flow.demo.common.log.model.constant.SysOperationLogType; +import com.flow.demo.common.log.service.SysOperationLogService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.*; +import org.aspectj.lang.reflect.MethodSignature; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; +import java.util.*; + +/** + * 操作日志记录处理AOP对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Aspect +@Component +@Order(1) +@Slf4j +public class OperationLogAspect { + + @Value("${spring.application.name}") + private String serviceName; + @Autowired + private SysOperationLogService operationLogService; + @Autowired + private OperationLogProperties properties; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 错误信息、请求参数和应答结果字符串的最大长度。 + */ + private final static int MAX_LENGTH = 2000; + + /** + * 所有controller方法。 + */ + @Pointcut("execution(public * com.flow.demo..controller..*(..))") + public void operationLogPointCut() { + // 空注释,避免sonar警告 + } + + @Around("operationLogPointCut()") + public Object around(ProceedingJoinPoint joinPoint) throws Throwable { + // 计时。 + long start = System.currentTimeMillis(); + HttpServletRequest request = ContextUtil.getHttpRequest(); + HttpServletResponse response = ContextUtil.getHttpResponse(); + String traceId = this.getTraceId(request); + request.setAttribute(ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId); + // 将流水号通过应答头返回给前端,便于问题精确定位。 + response.setHeader(ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId); + MDC.put(ApplicationConstant.HTTP_HEADER_TRACE_ID, traceId); + TokenData tokenData = TokenData.takeFromRequest(); + // 为log4j2日志设定变量,使日志可以输出更多有价值的信息。 + if (tokenData != null) { + MDC.put("sessionId", tokenData.getSessionId()); + MDC.put("userId", tokenData.getUserId().toString()); + } + String[] parameterNames = this.getParameterNames(joinPoint); + Object[] args = joinPoint.getArgs(); + JSONObject jsonArgs = new JSONObject(); + for (int i = 0; i < args.length; i++) { + Object arg = args[i]; + if (this.isNormalArgs(arg)) { + String parameterName = parameterNames[i]; + jsonArgs.put(parameterName, arg); + } + } + String params = jsonArgs.toJSONString(); + SysOperationLog operationLog = null; + OperationLog operationLogAnnotation = null; + boolean saveOperationLog = properties.isEnabled(); + if (saveOperationLog) { + operationLogAnnotation = getOperationLogAnnotation(joinPoint); + saveOperationLog = (operationLogAnnotation != null); + } + if (saveOperationLog) { + operationLog = this.buildSysOperationLog(operationLogAnnotation, joinPoint, params, traceId, tokenData); + } + Object result; + log.info("开始请求,url={}, reqData={}", request.getRequestURI(), params); + try { + // 调用原来的方法 + result = joinPoint.proceed(); + String respData = result == null ? "null" : JSON.toJSONString(result); + Long elapse = System.currentTimeMillis() - start; + if (saveOperationLog) { + this.operationLogPostProcess(operationLogAnnotation, respData, operationLog, result); + } + log.info("请求完成, url={},elapse={}ms, respData={}", request.getRequestURI(), elapse, respData); + } catch (Exception e) { + if (saveOperationLog) { + operationLog.setSuccess(false); + operationLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, MAX_LENGTH)); + } + log.error("请求报错,url={}, reqData={}, error={}", request.getRequestURI(), params, e.getMessage()); + throw e; + } finally { + if (saveOperationLog) { + operationLog.setElapse(System.currentTimeMillis() - start); + operationLogService.saveNewAsync(operationLog); + } + } + return result; + } + + private SysOperationLog buildSysOperationLog( + OperationLog operationLogAnnotation, + ProceedingJoinPoint joinPoint, + String params, + String traceId, + TokenData tokenData) { + HttpServletRequest request = ContextUtil.getHttpRequest(); + SysOperationLog operationLog = new SysOperationLog(); + operationLog.setLogId(idGenerator.nextLongId()); + operationLog.setTraceId(traceId); + operationLog.setDescription(operationLogAnnotation.description()); + operationLog.setOperationType(operationLogAnnotation.type()); + operationLog.setServiceName(this.serviceName); + operationLog.setApiClass(joinPoint.getTarget().getClass().getName()); + operationLog.setApiMethod(operationLog.getApiClass() + "." + joinPoint.getSignature().getName()); + operationLog.setRequestMethod(request.getMethod()); + operationLog.setRequestUrl(request.getRequestURI()); + if (tokenData != null) { + operationLog.setRequestIp(tokenData.getLoginIp()); + } else { + operationLog.setRequestIp(IpUtil.getRemoteIpAddress(request)); + } + operationLog.setOperationTime(new Date()); + if (params != null) { + if (params.length() <= MAX_LENGTH) { + operationLog.setRequestArguments(params); + } else { + operationLog.setRequestArguments(StringUtils.substring(params, 0, MAX_LENGTH)); + } + } + if (tokenData != null) { + // 对于非多租户系统,该值为空可以忽略。 + operationLog.setTenantId(tokenData.getTenantId()); + operationLog.setSessionId(tokenData.getSessionId()); + operationLog.setOperatorId(tokenData.getUserId()); + operationLog.setOperatorName(tokenData.getLoginName()); + } + return operationLog; + } + + private void operationLogPostProcess( + OperationLog operationLogAnnotation, String respData, SysOperationLog operationLog, Object result) { + if (operationLogAnnotation.saveResponse()) { + if (respData.length() <= MAX_LENGTH) { + operationLog.setResponseResult(respData); + } else { + operationLog.setResponseResult(StringUtils.substring(respData, 0, MAX_LENGTH)); + } + } + // 处理大部分返回ResponseResult的接口。 + if (!(result instanceof ResponseResult)) { + if (ContextUtil.hasRequestContext()) { + operationLog.setSuccess(ContextUtil.getHttpResponse().getStatus() == HttpServletResponse.SC_OK); + } + return; + } + ResponseResult responseResult = (ResponseResult) result; + operationLog.setSuccess(responseResult.isSuccess()); + if (!responseResult.isSuccess()) { + operationLog.setErrorMsg(responseResult.getErrorMessage()); + } + if (operationLog.getOperationType().equals(SysOperationLogType.LOGIN)) { + // 对于登录操作,由于在调用登录方法之前,没有可用的TokenData。 + // 因此如果登录成功,可再次通过TokenData.takeFromRequest()获取TokenData。 + if (operationLog.getSuccess()) { + // 这里为了保证LoginController.doLogin方法,一定将TokenData存入Request.Attribute之中, + // 我们将不做空值判断,一旦出错,开发者可在调试时立刻发现异常,并根据这里的注释进行修复。 + TokenData tokenData = TokenData.takeFromRequest(); + // 对于非多租户系统,为了保证代码一致性,仍可保留对tenantId的赋值代码。 + operationLog.setTenantId(tokenData.getTenantId()); + operationLog.setSessionId(tokenData.getSessionId()); + operationLog.setOperatorId(tokenData.getUserId()); + operationLog.setOperatorName(tokenData.getLoginName()); + } else { + HttpServletRequest request = ContextUtil.getHttpRequest(); + // 登录操作需要特殊处理,无论是登录成功还是失败,都要记录operator_name字段。 + operationLog.setOperatorName(request.getParameter("loginName")); + } + } + } + + private String[] getParameterNames(ProceedingJoinPoint joinPoint) { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + return methodSignature.getParameterNames(); + } + + private OperationLog getOperationLogAnnotation(JoinPoint joinPoint) throws Exception { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + return method.getAnnotation(OperationLog.class); + } + + private String getTraceId(HttpServletRequest request) { + // 获取请求流水号。 + // 对于微服务系统,为了保证traceId在全调用链的唯一性,因此在网关的过滤器中创建了该值。 + String traceId = request.getHeader(ApplicationConstant.HTTP_HEADER_TRACE_ID); + if (StringUtils.isBlank(traceId)) { + traceId = MyCommonUtil.generateUuid(); + } + return traceId; + } + + private boolean isNormalArgs(Object o) { + if (o instanceof List) { + List list = (List) o; + if (CollUtil.isNotEmpty(list)) { + return !(list.get(0) instanceof MultipartFile); + } + } + return !(o instanceof HttpServletRequest) + && !(o instanceof HttpServletResponse) + && !(o instanceof MultipartFile); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/config/CommonLogAutoConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/config/CommonLogAutoConfig.java new file mode 100644 index 00000000..ca0eab7f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/config/CommonLogAutoConfig.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.log.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +/** + * common-log模块的自动配置引导类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EnableConfigurationProperties({OperationLogProperties.class}) +public class CommonLogAutoConfig { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/config/OperationLogProperties.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/config/OperationLogProperties.java new file mode 100644 index 00000000..f7c08276 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/config/OperationLogProperties.java @@ -0,0 +1,20 @@ +package com.flow.demo.common.log.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 操作日志的配置类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ConfigurationProperties(prefix = "common-log.operation-log") +public class OperationLogProperties { + + /** + * 是否采集操作日志。 + */ + private boolean enabled = true; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/dao/SysOperationLogMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/dao/SysOperationLogMapper.java new file mode 100644 index 00000000..ab3a0ac2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/dao/SysOperationLogMapper.java @@ -0,0 +1,34 @@ +package com.flow.demo.common.log.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.log.model.SysOperationLog; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 系统操作日志对应的数据访问对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysOperationLogMapper extends BaseDaoMapper { + + /** + * 批量插入。 + * + * @param operationLogList 操作日志列表。 + */ + void insertList(List operationLogList); + + /** + * 根据过滤条件和排序规则,查询操作日志。 + * + * @param sysOperationLogFilter 操作日志的过滤对象。 + * @param orderBy 排序规则。 + * @return 查询列表。 + */ + List getSysOperationLogList( + @Param("sysOperationLogFilter") SysOperationLog sysOperationLogFilter, + @Param("orderBy") String orderBy); +} \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/dao/mapper/SysOperationLogMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/dao/mapper/SysOperationLogMapper.xml new file mode 100644 index 00000000..3ed7752d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/dao/mapper/SysOperationLogMapper.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_sys_operation_log.operation_type = #{sysOperationLogFilter.operationType} + + + + AND zz_sys_operation_log.request_url LIKE #{safeRequestUrl} + + + AND zz_sys_operation_log.trace_id = #{sysOperationLogFilter.traceId} + + + AND zz_sys_operation_log.success = #{sysOperationLogFilter.success} + + + + AND zz_sys_operation_log.operator_name LIKE #{safeOperatorName} + + + AND zz_sys_operation_log.elapse >= #{sysOperationLogFilter.elapseMin} + + + AND zz_sys_operation_log.elapse <= #{sysOperationLogFilter.elapseMax} + + + AND zz_sys_operation_log.operation_time >= #{sysOperationLogFilter.operationTimeStart} + + + AND zz_sys_operation_log.operation_time <= #{sysOperationLogFilter.operationTimeEnd} + + + + + + INSERT INTO zz_sys_operation_log VALUES + + ( + #{item.logId}, + #{item.description}, + #{item.operationType}, + #{item.serviceName}, + #{item.apiClass}, + #{item.apiMethod}, + #{item.sessionId}, + #{item.traceId}, + #{item.elapse}, + #{item.requestMethod}, + #{item.requestUrl}, + #{item.requestArguments}, + #{item.responseResult}, + #{item.requestIp}, + #{item.success}, + #{item.errorMsg}, + #{item.tenantId}, + #{item.operatorId}, + #{item.operatorName}, + #{item.operationTime} + ) + + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/model/SysOperationLog.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/model/SysOperationLog.java new file mode 100644 index 00000000..bf382eca --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/model/SysOperationLog.java @@ -0,0 +1,170 @@ +package com.flow.demo.common.log.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.TenantFilterColumn; +import lombok.Data; + +import java.util.Date; + +/** + * 操作日志记录表 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName("zz_sys_operation_log") +public class SysOperationLog { + + /** + * 主键Id。 + */ + @TableId(value = "log_id") + private Long logId; + + /** + * 日志描述。 + */ + @TableField(value = "description") + private String description; + + /** + * 操作类型。 + * 常量值定义可参考SysOperationLogType对象。 + */ + @TableField(value = "operation_type") + private Integer operationType; + + /** + * 接口所在服务名称。 + * 通常为spring.application.name配置项的值。 + */ + @TableField(value = "service_name") + private String serviceName; + + /** + * 调用的controller全类名。 + * 之所以为独立字段,是为了便于查询和统计接口的调用频度。 + */ + @TableField(value = "api_class") + private String apiClass; + + /** + * 调用的controller中的方法。 + * 格式为:接口类名 + "." + 方法名。 + */ + @TableField(value = "api_method") + private String apiMethod; + + /** + * 用户会话sessionId。 + * 主要是为了便于统计,以及跟踪查询定位问题。 + */ + @TableField(value = "session_id") + private String sessionId; + + /** + * 每次请求的Id。 + * 对于微服务之间的调用,在同一个请求的调用链中,该值是相同的。 + */ + @TableField(value = "trace_id") + private String traceId; + + /** + * 调用时长。 + */ + @TableField(value = "elapse") + private Long elapse; + + /** + * HTTP 请求方法,如GET。 + */ + @TableField(value = "request_method") + private String requestMethod; + + /** + * HTTP 请求地址。 + */ + @TableField(value = "request_url") + private String requestUrl; + + /** + * controller接口参数。 + */ + @TableField(value = "request_arguments") + private String requestArguments; + + /** + * controller应答结果。 + */ + @TableField(value = "response_result") + private String responseResult; + + /** + * 请求IP。 + */ + @TableField(value = "request_ip") + private String requestIp; + + /** + * 应答状态。 + */ + @TableField(value = "success") + private Boolean success; + + /** + * 错误信息。 + */ + @TableField(value = "error_msg") + private String errorMsg; + + /** + * 租户Id。 + * 仅用于多租户系统,是便于进行对租户的操作查询和统计分析。 + */ + @TenantFilterColumn + @TableField(value = "tenant_id") + private Long tenantId; + + /** + * 操作员Id。 + */ + @TableField(value = "operator_id") + private Long operatorId; + + /** + * 操作员名称。 + */ + @TableField(value = "operator_name") + private String operatorName; + + /** + * 操作时间。 + */ + @TableField(value = "operation_time") + private Date operationTime; + + /** + * 调用时长最小值。 + */ + @TableField(exist = false) + private Long elapseMin; + + /** + * 调用时长最大值。 + */ + @TableField(exist = false) + private Long elapseMax; + + /** + * 操作开始时间。 + */ + @TableField(exist = false) + private String operationTimeStart; + + /** + * 操作结束时间。 + */ + @TableField(exist = false) + private String operationTimeEnd; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/model/constant/SysOperationLogType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/model/constant/SysOperationLogType.java new file mode 100644 index 00000000..1fdc5a04 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/model/constant/SysOperationLogType.java @@ -0,0 +1,149 @@ +package com.flow.demo.common.log.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 操作日志类型常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class SysOperationLogType { + + /** + * 其他。 + */ + public static final int OTHER = -1; + /** + * 登录。 + */ + public static final int LOGIN = 0; + /** + * 登出。 + */ + public static final int LOGOUT = 5; + /** + * 新增。 + */ + public static final int ADD = 10; + /** + * 修改。 + */ + public static final int UPDATE = 15; + /** + * 删除。 + */ + public static final int DELETE = 20; + /** + * 新增多对多关联。 + */ + public static final int ADD_M2M = 25; + /** + * 移除多对多关联。 + */ + public static final int DELETE_M2M = 30; + /** + * 查询。 + */ + public static final int LIST = 35; + /** + * 分组查询。 + */ + public static final int LIST_WITH_GROUP = 40; + /** + * 导出。 + */ + public static final int EXPORT = 45; + /** + * 上传。 + */ + public static final int UPLOAD = 50; + /** + * 下载。 + */ + public static final int DOWNLOAD = 55; + /** + * 重置缓存。 + */ + public static final int RELOAD_CACHE = 60; + /** + * 发布。 + */ + public static final int PUBLISH = 65; + /** + * 取消发布。 + */ + public static final int UNPUBLISH = 70; + /** + * 暂停。 + */ + public static final int SUSPEND = 75; + /** + * 恢复。 + */ + public static final int RESUME = 80; + /** + * 启动流程。 + */ + public static final int START_PROCESS = 100; + /** + * 停止流程。 + */ + public static final int STOP_PROCESS = 105; + /** + * 删除流程。 + */ + public static final int DELETE_PROCESS = 110; + /** + * 取消流程。 + */ + public static final int CANCEL_PROCESS = 115; + /** + * 提交任务。 + */ + public static final int SUBMIT_TASK = 120; + + private static final Map DICT_MAP = new HashMap<>(15); + static { + DICT_MAP.put(OTHER, "其他"); + DICT_MAP.put(LOGIN, "登录"); + DICT_MAP.put(LOGOUT, "登出"); + DICT_MAP.put(ADD, "新增"); + DICT_MAP.put(UPDATE, "修改"); + DICT_MAP.put(DELETE, "删除"); + DICT_MAP.put(ADD_M2M, "新增多对多关联"); + DICT_MAP.put(DELETE_M2M, "移除多对多关联"); + DICT_MAP.put(LIST, "查询"); + DICT_MAP.put(LIST_WITH_GROUP, "分组查询"); + DICT_MAP.put(EXPORT, "导出"); + DICT_MAP.put(UPLOAD, "上传"); + DICT_MAP.put(DOWNLOAD, "下载"); + DICT_MAP.put(RELOAD_CACHE, "重置缓存"); + DICT_MAP.put(PUBLISH, "发布"); + DICT_MAP.put(UNPUBLISH, "取消发布"); + DICT_MAP.put(SUSPEND, "暂停"); + DICT_MAP.put(RESUME, "恢复"); + DICT_MAP.put(START_PROCESS, "启动流程"); + DICT_MAP.put(STOP_PROCESS, "停止流程"); + DICT_MAP.put(DELETE_PROCESS, "删除流程"); + DICT_MAP.put(CANCEL_PROCESS, "取消流程"); + DICT_MAP.put(SUBMIT_TASK, "提交任务"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private SysOperationLogType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/service/SysOperationLogService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/service/SysOperationLogService.java new file mode 100644 index 00000000..77edbcc6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/service/SysOperationLogService.java @@ -0,0 +1,45 @@ +package com.flow.demo.common.log.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.log.model.SysOperationLog; + +import java.util.List; + +/** + * 操作日志服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface SysOperationLogService extends IBaseService { + + /** + * 异步的插入一条新操作日志。 + * + * @param operationLog 操作日志对象。 + */ + void saveNewAsync(SysOperationLog operationLog); + + /** + * 插入一条新操作日志。 + * + * @param operationLog 操作日志对象。 + */ + void saveNew(SysOperationLog operationLog); + + /** + * 批量插入。 + * + * @param sysOperationLogList 操作日志列表。 + */ + void batchSave(List sysOperationLogList); + + /** + * 根据过滤条件和排序规则,查询操作日志。 + * + * @param filter 操作日志的过滤对象。 + * @param orderBy 排序规则。 + * @return 查询列表。 + */ + List getSysOperationLogList(SysOperationLog filter, String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/service/impl/SysOperationLogServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/service/impl/SysOperationLogServiceImpl.java new file mode 100644 index 00000000..0f39a673 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/java/com/flow/demo/common/log/service/impl/SysOperationLogServiceImpl.java @@ -0,0 +1,84 @@ +package com.flow.demo.common.log.service.impl; + +import com.flow.demo.common.core.annotation.MyDataSource; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.constant.ApplicationConstant; +import com.flow.demo.common.log.dao.SysOperationLogMapper; +import com.flow.demo.common.log.model.SysOperationLog; +import com.flow.demo.common.log.service.SysOperationLogService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 操作日志服务实现类。 + * 这里需要重点解释下MyDataSource注解。在单数据源服务中,由于没有DataSourceAspect的切面类,所以该注解不会 + * 有任何作用和影响。然而在多数据源情况下,由于每个服务都有自己的DataSourceType常量对象,表示不同的数据源。 + * 而common-log在公用模块中,不能去依赖业务服务,因此这里给出了一个固定值。我们在业务的DataSourceType中,也要 + * 使用该值ApplicationConstant.OPERATION_LOG_DATASOURCE_TYPE,去关联操作日志所需的数据源配置。 + * + * @author Jerry + * @date 2021-06-06 + */ +@MyDataSource(ApplicationConstant.OPERATION_LOG_DATASOURCE_TYPE) +@Service +public class SysOperationLogServiceImpl extends BaseService implements SysOperationLogService { + + @Autowired + private SysOperationLogMapper sysOperationLogMapper; + + @Override + protected BaseDaoMapper mapper() { + return sysOperationLogMapper; + } + + /** + * 异步插入一条新操作日志。通常用于在橙单中创建的单体工程服务。 + * + * @param operationLog 操作日志对象。 + */ + @Async + @Transactional(rollbackFor = Exception.class) + @Override + public void saveNewAsync(SysOperationLog operationLog) { + sysOperationLogMapper.insert(operationLog); + } + + /** + * 插入一条新操作日志。 + * + * @param operationLog 操作日志对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void saveNew(SysOperationLog operationLog) { + sysOperationLogMapper.insert(operationLog); + } + + /** + * 批量插入。通常用于在橙单中创建的微服务工程服务。 + * + * @param sysOperationLogList 操作日志列表。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void batchSave(List sysOperationLogList) { + sysOperationLogMapper.insertList(sysOperationLogList); + } + + /** + * 根据过滤条件和排序规则,查询操作日志。 + * + * @param filter 操作日志的过滤对象。 + * @param orderBy 排序规则。 + * @return 查询列表。 + */ + @Override + public List getSysOperationLogList(SysOperationLog filter, String orderBy) { + return sysOperationLogMapper.getSysOperationLogList(filter, orderBy); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/resources/META-INF/spring.factories b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..f8856ec0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-log/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.flow.demo.common.log.config.CommonLogAutoConfig \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/pom.xml new file mode 100644 index 00000000..f79838d1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/pom.xml @@ -0,0 +1,43 @@ + + + + common + com.flow.demo + 1.0.0 + + 4.0.0 + + common-online-api + 1.0.0 + common-online-api + jar + + + + com.flow.demo + common-online + 1.0.0 + + + + + + + src/main/resources + + **/*.* + + false + + + src/main/java + + **/*.xml + + false + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/config/OnlineApiAutoConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/config/OnlineApiAutoConfig.java new file mode 100644 index 00000000..b4d2e47f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/config/OnlineApiAutoConfig.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.online.api.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +/** + * common-online-api模块的自动配置引导类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EnableConfigurationProperties({OnlineApiProperties.class}) +public class OnlineApiAutoConfig { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/config/OnlineApiProperties.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/config/OnlineApiProperties.java new file mode 100644 index 00000000..e39b804b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/config/OnlineApiProperties.java @@ -0,0 +1,32 @@ +package com.flow.demo.common.online.api.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +import java.util.List; + +/** + * 在线表单API的配置对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ConfigurationProperties(prefix = "common-online-api") +public class OnlineApiProperties { + + /** + * 在线表单的URL前缀。 + */ + private String urlPrefix; + + /** + * 在线表单查看权限的URL列表。 + */ + private List viewUrlList; + + /** + * 在线表单编辑权限的URL列表。 + */ + private List editUrlList; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineColumnController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineColumnController.java new file mode 100644 index 00000000..c946cab6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineColumnController.java @@ -0,0 +1,400 @@ +package com.flow.demo.common.online.api.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.jimmyshi.beanquery.BeanQuery; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.dto.OnlineColumnDto; +import com.flow.demo.common.online.dto.OnlineColumnRuleDto; +import com.flow.demo.common.online.dto.OnlineRuleDto; +import com.flow.demo.common.online.model.*; +import com.flow.demo.common.online.object.SqlTableColumn; +import com.flow.demo.common.online.service.*; +import com.flow.demo.common.online.vo.OnlineColumnRuleVo; +import com.flow.demo.common.online.vo.OnlineColumnVo; +import com.flow.demo.common.online.vo.OnlineRuleVo; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 字段数据操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlineColumn") +public class OnlineColumnController { + + @Autowired + private OnlineColumnService onlineColumnService; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private OnlineVirtualColumnService onlineVirtualColumnService; + @Autowired + private OnlineDblinkService onlineDblinkService; + @Autowired + private OnlineRuleService onlineRuleService; + + /** + * 根据数据库表字段信息,在指定在线表中添加在线表字段对象。 + * + * @param dblinkId 数据库链接Id。 + * @param tableName 数据库表名称。 + * @param columnName 数据库表字段名。 + * @param tableId 目的表Id。 + * @return 应答结果对象。 + */ + @PostMapping("/add") + public ResponseResult add( + @MyRequestBody Long dblinkId, + @MyRequestBody String tableName, + @MyRequestBody String columnName, + @MyRequestBody Long tableId) { + OnlineDblink dblink = onlineDblinkService.getById(dblinkId); + if (dblink == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + String errorMsg; + SqlTableColumn sqlTableColumn = onlineDblinkService.getDblinkTableColumn(dblink, tableName, columnName); + if (sqlTableColumn == null) { + errorMsg = "数据验证失败,指定的数据表字段不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMsg); + } + if (!onlineTableService.existId(tableId)) { + errorMsg = "数据验证失败,指定的数据表Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMsg); + } + onlineColumnService.saveNewList(CollUtil.newLinkedList(sqlTableColumn), tableId); + return ResponseResult.success(); + } + + /** + * 更新字段数据数据。 + * + * @param onlineColumnDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody OnlineColumnDto onlineColumnDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineColumnDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineColumn onlineColumn = MyModelUtil.copyTo(onlineColumnDto, OnlineColumn.class); + OnlineColumn originalOnlineColumn = onlineColumnService.getById(onlineColumn.getColumnId()); + if (originalOnlineColumn == null) { + errorMessage = "数据验证失败,当前在线表字段并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = onlineColumnService.verifyRelatedData(onlineColumn, originalOnlineColumn); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!onlineColumnService.update(onlineColumn, originalOnlineColumn)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除字段数据数据。 + * + * @param columnId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long columnId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(columnId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + OnlineColumn originalOnlineColumn = onlineColumnService.getById(columnId); + if (originalOnlineColumn == null) { + errorMessage = "数据验证失败,当前在线表字段并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + OnlineVirtualColumn virtualColumnFilter = new OnlineVirtualColumn(); + virtualColumnFilter.setAggregationColumnId(columnId); + List virtualColumnList = + onlineVirtualColumnService.getOnlineVirtualColumnList(virtualColumnFilter, null); + if (CollUtil.isNotEmpty(virtualColumnList)) { + OnlineVirtualColumn virtualColumn = virtualColumnList.get(0); + errorMessage = "数据验证失败,数据源关联正在被虚拟字段 [" + virtualColumn.getColumnPrompt() + "] 使用,不能被删除!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineColumnService.remove(originalOnlineColumn.getTableId(), columnId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的字段数据列表。 + * + * @param onlineColumnDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlineColumnDto onlineColumnDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineColumn onlineColumnFilter = MyModelUtil.copyTo(onlineColumnDtoFilter, OnlineColumn.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineColumn.class); + List onlineColumnList = + onlineColumnService.getOnlineColumnListWithRelation(onlineColumnFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineColumnList, OnlineColumn.INSTANCE)); + } + + /** + * 查看指定字段数据对象详情。 + * + * @param columnId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long columnId) { + if (MyCommonUtil.existBlankArgument(columnId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineColumn onlineColumn = onlineColumnService.getByIdWithRelation(columnId, MyRelationParam.full()); + if (onlineColumn == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineColumnVo onlineColumnVo = OnlineColumn.INSTANCE.fromModel(onlineColumn); + return ResponseResult.success(onlineColumnVo); + } + + /** + * 将数据库中的表字段信息刷新到已经导入的在线表字段信息。 + * + * @param dblinkId 数据库链接Id。 + * @param tableName 数据库表名称。 + * @param columnName 数据库表字段名。 + * @param columnId 被刷新的在线字段Id。 + * @return 应答结果对象。 + */ + @PostMapping("/refresh") + public ResponseResult refresh( + @MyRequestBody Long dblinkId, + @MyRequestBody String tableName, + @MyRequestBody String columnName, + @MyRequestBody Long columnId) { + OnlineDblink dblink = onlineDblinkService.getById(dblinkId); + if (dblink == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + String errorMsg; + SqlTableColumn sqlTableColumn = onlineDblinkService.getDblinkTableColumn(dblink, tableName, columnName); + if (sqlTableColumn == null) { + errorMsg = "数据验证失败,指定的数据表字段不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMsg); + } + OnlineColumn onlineColumn = onlineColumnService.getById(columnId); + if (onlineColumn == null) { + errorMsg = "数据验证失败,指定的在线表字段Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMsg); + } + onlineColumnService.refresh(sqlTableColumn, onlineColumn); + return ResponseResult.success(); + } + + /** + * 列出不与指定字段数据存在多对多关系的 [验证规则] 列表数据。通常用于查看添加新 [验证规则] 对象的候选列表。 + * + * @param columnId 主表关联字段。 + * @param onlineRuleDtoFilter [验证规则] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listNotInOnlineColumnRule") + public ResponseResult> listNotInOnlineColumnRule( + @MyRequestBody Long columnId, + @MyRequestBody OnlineRuleDto onlineRuleDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doOnlineColumnRuleVerify(columnId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineRule filter = MyModelUtil.copyTo(onlineRuleDtoFilter, OnlineRule.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineRule.class); + List onlineRuleList = + onlineRuleService.getNotInOnlineRuleListByColumnId(columnId, filter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineRuleList, OnlineRule.INSTANCE)); + } + + /** + * 列出与指定字段数据存在多对多关系的 [验证规则] 列表数据。 + * + * @param columnId 主表关联字段。 + * @param onlineRuleDtoFilter [验证规则] 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listOnlineColumnRule") + public ResponseResult> listOnlineColumnRule( + @MyRequestBody Long columnId, + @MyRequestBody OnlineRuleDto onlineRuleDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doOnlineColumnRuleVerify(columnId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineRule filter = MyModelUtil.copyTo(onlineRuleDtoFilter, OnlineRule.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineRule.class); + List onlineRuleList = + onlineRuleService.getOnlineRuleListByColumnId(columnId, filter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineRuleList, OnlineRule.INSTANCE)); + } + + private ResponseResult doOnlineColumnRuleVerify(Long columnId) { + if (MyCommonUtil.existBlankArgument(columnId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!onlineColumnService.existId(columnId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } + + /** + * 批量添加字段数据和 [验证规则] 对象的多对多关联关系数据。 + * + * @param columnId 主表主键Id。 + * @param onlineColumnRuleDtoList 关联对象列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addOnlineColumnRule") + public ResponseResult addOnlineColumnRule( + @MyRequestBody Long columnId, + @MyRequestBody(elementType = OnlineColumnRuleDto.class) List onlineColumnRuleDtoList) { + if (MyCommonUtil.existBlankArgument(columnId, onlineColumnRuleDtoList)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + for (OnlineColumnRuleDto onlineColumnRule : onlineColumnRuleDtoList) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineColumnRule); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + Set ruleIdSet = + onlineColumnRuleDtoList.stream().map(OnlineColumnRuleDto::getRuleId).collect(Collectors.toSet()); + if (!onlineColumnService.existId(columnId) + || !onlineRuleService.existUniqueKeyList("ruleId", ruleIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + List onlineColumnRuleList = + MyModelUtil.copyCollectionTo(onlineColumnRuleDtoList, OnlineColumnRule.class); + onlineColumnService.addOnlineColumnRuleList(onlineColumnRuleList, columnId); + return ResponseResult.success(); + } + + /** + * 更新指定字段数据和指定 [验证规则] 的多对多关联数据。 + * + * @param onlineColumnRuleDto 对多对中间表对象。 + * @return 应答结果对象。 + */ + @PostMapping("/updateOnlineColumnRule") + public ResponseResult updateOnlineColumnRule( + @MyRequestBody OnlineColumnRuleDto onlineColumnRuleDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineColumnRuleDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineColumnRule onlineColumnRule = MyModelUtil.copyTo(onlineColumnRuleDto, OnlineColumnRule.class); + if (!onlineColumnService.updateOnlineColumnRule(onlineColumnRule)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 显示字段数据和指定 [验证规则] 的多对多关联详情数据。 + * + * @param columnId 主表主键Id。 + * @param ruleId 从表主键Id。 + * @return 应答结果对象,包括中间表详情。 + */ + @GetMapping("/viewOnlineColumnRule") + public ResponseResult viewOnlineColumnRule( + @RequestParam Long columnId, @RequestParam Long ruleId) { + if (MyCommonUtil.existBlankArgument(columnId, ruleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineColumnRule onlineColumnRule = onlineColumnService.getOnlineColumnRule(columnId, ruleId); + if (onlineColumnRule == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineColumnRuleVo onlineColumnRuleVo = MyModelUtil.copyTo(onlineColumnRule, OnlineColumnRuleVo.class); + return ResponseResult.success(onlineColumnRuleVo); + } + + /** + * 移除指定字段数据和指定 [验证规则] 的多对多关联关系。 + * + * @param columnId 主表主键Id。 + * @param ruleId 从表主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/deleteOnlineColumnRule") + public ResponseResult deleteOnlineColumnRule( + @MyRequestBody Long columnId, @MyRequestBody Long ruleId) { + if (MyCommonUtil.existBlankArgument(columnId, ruleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!onlineColumnService.removeOnlineColumnRule(columnId, ruleId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 以字典形式返回全部字段数据数据集合。字典的键值为[columnId, columnName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDict") + public ResponseResult>> listDict(OnlineColumn filter) { + List resultList = onlineColumnService.getListByFilter(filter); + return ResponseResult.success(BeanQuery.select( + "columnId as id", "columnName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDatasourceController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDatasourceController.java new file mode 100644 index 00000000..5d97ab61 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDatasourceController.java @@ -0,0 +1,205 @@ +package com.flow.demo.common.online.api.controller; + +import cn.hutool.core.collection.CollUtil; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.AddGroup; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.dto.OnlineDatasourceDto; +import com.flow.demo.common.online.model.*; +import com.flow.demo.common.online.model.constant.PageType; +import com.flow.demo.common.online.object.SqlTable; +import com.flow.demo.common.online.object.SqlTableColumn; +import com.flow.demo.common.online.service.*; +import com.flow.demo.common.online.vo.OnlineDatasourceVo; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.List; + +/** + * 数据模型操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlineDatasource") +public class OnlineDatasourceController { + + @Autowired + private OnlineDatasourceService onlineDatasourceService; + @Autowired + private OnlineFormService onlineFormService; + @Autowired + private OnlinePageService onlinePageService; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private OnlineDblinkService onlineDblinkService; + + /** + * 新增数据模型数据。 + * + * @param onlineDatasourceDto 新增对象。 + * @param pageId 关联的页面Id。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add( + @MyRequestBody OnlineDatasourceDto onlineDatasourceDto, + @MyRequestBody(required = true) Long pageId) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineDatasourceDto, Default.class, AddGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlinePage onlinePage = onlinePageService.getById(pageId); + if (onlinePage == null) { + errorMessage = "数据验证失败,页面Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineDatasource onlineDatasource = MyModelUtil.copyTo(onlineDatasourceDto, OnlineDatasource.class); + OnlineDblink onlineDblink = onlineDblinkService.getById(onlineDatasourceDto.getDblinkId()); + if (onlineDblink == null) { + errorMessage = "数据验证失败,关联的数据库链接Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SqlTable sqlTable = onlineDblinkService.getDblinkTable(onlineDblink, onlineDatasourceDto.getMasterTableName()); + if (sqlTable == null) { + errorMessage = "数据验证失败,指定的数据表名不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + // 流程表单的主表主键,不能是自增主键。 + if (onlinePage.getPageType().equals(PageType.FLOW)) { + for (SqlTableColumn tableColumn : sqlTable.getColumnList()) { + if (tableColumn.getPrimaryKey()) { + if (tableColumn.getAutoIncrement()) { + errorMessage = "数据验证失败,流程页面所关联的主表主键,不能是自增主键!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + break; + } + } + } + onlineDatasource = onlineDatasourceService.saveNew(onlineDatasource, sqlTable, pageId); + return ResponseResult.success(onlineDatasource.getDatasourceId()); + } + + /** + * 更新数据模型数据。 + * + * @param onlineDatasourceDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody OnlineDatasourceDto onlineDatasourceDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineDatasourceDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineDatasource onlineDatasource = MyModelUtil.copyTo(onlineDatasourceDto, OnlineDatasource.class); + OnlineDatasource originalOnlineDatasource = onlineDatasourceService.getById(onlineDatasource.getDatasourceId()); + if (originalOnlineDatasource == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前在线数据源并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineDatasource.getDblinkId().equals(originalOnlineDatasource.getDatasourceId())) { + errorMessage = "数据验证失败,不能修改数据库链接Id!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineDatasource.getMasterTableId().equals(originalOnlineDatasource.getDatasourceId())) { + errorMessage = "数据验证失败,不能修改主表Id!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineDatasourceService.update(onlineDatasource, originalOnlineDatasource)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除数据模型数据。 + * + * @param datasourceId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long datasourceId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(datasourceId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + OnlineDatasource originalOnlineDatasource = onlineDatasourceService.getById(datasourceId); + if (originalOnlineDatasource == null) { + errorMessage = "数据验证失败,当前数据源并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + List formList = onlineFormService.getOnlineFormListByDatasourceId(datasourceId); + if (CollUtil.isNotEmpty(formList)) { + errorMessage = "数据验证失败,当前数据源正在被 [" + formList.get(0).getFormName() + "] 表单占用,请先删除关联数据!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineDatasourceService.remove(datasourceId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的数据模型列表。 + * + * @param onlineDatasourceDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlineDatasourceDto onlineDatasourceDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineDatasource onlineDatasourceFilter = MyModelUtil.copyTo(onlineDatasourceDtoFilter, OnlineDatasource.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineDatasource.class); + List onlineDatasourceList = + onlineDatasourceService.getOnlineDatasourceListWithRelation(onlineDatasourceFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineDatasourceList, OnlineDatasource.INSTANCE)); + } + + /** + * 查看指定数据模型对象详情。 + * + * @param datasourceId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long datasourceId) { + if (MyCommonUtil.existBlankArgument(datasourceId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineDatasource onlineDatasource = + onlineDatasourceService.getByIdWithRelation(datasourceId, MyRelationParam.full()); + if (onlineDatasource == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineDatasourceVo onlineDatasourceVo = OnlineDatasource.INSTANCE.fromModel(onlineDatasource); + List tableList = onlineTableService.getOnlineTableListByDatasourceId(datasourceId); + if (CollUtil.isNotEmpty(tableList)) { + onlineDatasourceVo.setTableList(OnlineTable.INSTANCE.fromModelList(tableList)); + } + return ResponseResult.success(onlineDatasourceVo); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDatasourceRelationController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDatasourceRelationController.java new file mode 100644 index 00000000..717db701 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDatasourceRelationController.java @@ -0,0 +1,228 @@ +package com.flow.demo.common.online.api.controller; + +import cn.hutool.core.collection.CollUtil; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.AddGroup; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.dto.OnlineDatasourceRelationDto; +import com.flow.demo.common.online.model.*; +import com.flow.demo.common.online.object.SqlTable; +import com.flow.demo.common.online.object.SqlTableColumn; +import com.flow.demo.common.online.service.*; +import com.flow.demo.common.online.vo.OnlineDatasourceRelationVo; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.List; + +/** + * 数据源关联操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlineDatasourceRelation") +public class OnlineDatasourceRelationController { + + @Autowired + private OnlineDatasourceRelationService onlineDatasourceRelationService; + @Autowired + private OnlineDatasourceService onlineDatasourceService; + @Autowired + private OnlineVirtualColumnService onlineVirtualColumnService; + @Autowired + private OnlineDblinkService onlineDblinkService; + @Autowired + private OnlineFormService onlineFormService; + + /** + * 新增数据关联数据。 + * + * @param onlineDatasourceRelationDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody OnlineDatasourceRelationDto onlineDatasourceRelationDto) { + String errorMessage = MyCommonUtil.getModelValidationError( + onlineDatasourceRelationDto, Default.class, AddGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineDatasourceRelation onlineDatasourceRelation = + MyModelUtil.copyTo(onlineDatasourceRelationDto, OnlineDatasourceRelation.class); + OnlineDatasource onlineDatasource = + onlineDatasourceService.getById(onlineDatasourceRelationDto.getDatasourceId()); + if (onlineDatasource == null) { + errorMessage = "数据验证失败,关联的数据源Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineDblink onlineDblink = onlineDblinkService.getById(onlineDatasource.getDblinkId()); + SqlTable slaveTable = onlineDblinkService.getDblinkTable( + onlineDblink, onlineDatasourceRelationDto.getSlaveTableName()); + if (slaveTable == null) { + errorMessage = "数据验证失败,指定的数据表不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + SqlTableColumn slaveColumn = null; + for (SqlTableColumn column : slaveTable.getColumnList()) { + if (column.getColumnName().equals(onlineDatasourceRelationDto.getSlaveColumnName())) { + slaveColumn = column; + break; + } + } + if (slaveColumn == null) { + errorMessage = "数据验证失败,指定的数据表字段 [" + onlineDatasourceRelationDto.getSlaveColumnName() + "] 不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = + onlineDatasourceRelationService.verifyRelatedData(onlineDatasourceRelation, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + onlineDatasourceRelation = onlineDatasourceRelationService.saveNew(onlineDatasourceRelation, slaveTable, slaveColumn); + return ResponseResult.success(onlineDatasourceRelation.getRelationId()); + } + + /** + * 更新数据关联数据。 + * + * @param onlineDatasourceRelationDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody OnlineDatasourceRelationDto onlineDatasourceRelationDto) { + String errorMessage = MyCommonUtil.getModelValidationError( + onlineDatasourceRelationDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineDatasourceRelation onlineDatasourceRelation = + MyModelUtil.copyTo(onlineDatasourceRelationDto, OnlineDatasourceRelation.class); + OnlineDatasourceRelation originalOnlineDatasourceRelation = + onlineDatasourceRelationService.getById(onlineDatasourceRelation.getRelationId()); + if (originalOnlineDatasourceRelation == null) { + errorMessage = "数据验证失败,当前数据源关联并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineDatasourceRelationDto.getRelationType().equals(originalOnlineDatasourceRelation.getRelationType())) { + errorMessage = "数据验证失败,不能修改关联类型!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineDatasourceRelationDto.getSlaveTableId().equals(originalOnlineDatasourceRelation.getSlaveTableId())) { + errorMessage = "数据验证失败,不能修改从表Id!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineDatasourceRelationDto.getDatasourceId().equals(originalOnlineDatasourceRelation.getDatasourceId())) { + errorMessage = "数据验证失败,不能修改数据源Id!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = onlineDatasourceRelationService + .verifyRelatedData(onlineDatasourceRelation, originalOnlineDatasourceRelation); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!onlineDatasourceRelationService.update(onlineDatasourceRelation, originalOnlineDatasourceRelation)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除数据关联数据。 + * + * @param relationId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long relationId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(relationId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + OnlineDatasourceRelation originalOnlineDatasourceRelation = onlineDatasourceRelationService.getById(relationId); + if (originalOnlineDatasourceRelation == null) { + errorMessage = "数据验证失败,当前数据源关联并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + OnlineVirtualColumn virtualColumnFilter = new OnlineVirtualColumn(); + virtualColumnFilter.setRelationId(relationId); + List virtualColumnList = + onlineVirtualColumnService.getOnlineVirtualColumnList(virtualColumnFilter, null); + if (CollUtil.isNotEmpty(virtualColumnList)) { + OnlineVirtualColumn virtualColumn = virtualColumnList.get(0); + errorMessage = "数据验证失败,数据源关联正在被虚拟字段 [" + virtualColumn.getColumnPrompt() + "] 使用,不能被删除!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + List formList = + onlineFormService.getOnlineFormListByTableId(originalOnlineDatasourceRelation.getSlaveTableId()); + if (CollUtil.isNotEmpty(formList)) { + errorMessage = "数据验证失败,当前数据源关联正在被 [" + formList.get(0).getFormName() + "] 表单占用,请先删除关联数据!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineDatasourceRelationService.remove(relationId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的数据关联列表。 + * + * @param onlineDatasourceRelationDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分 页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlineDatasourceRelationDto onlineDatasourceRelationDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineDatasourceRelation onlineDatasourceRelationFilter = + MyModelUtil.copyTo(onlineDatasourceRelationDtoFilter, OnlineDatasourceRelation.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineDatasourceRelation.class); + List onlineDatasourceRelationList = + onlineDatasourceRelationService.getOnlineDatasourceRelationListWithRelation(onlineDatasourceRelationFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineDatasourceRelationList, OnlineDatasourceRelation.INSTANCE)); + } + + /** + * 查看指定数据关联对象详情。 + * + * @param relationId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long relationId) { + if (MyCommonUtil.existBlankArgument(relationId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineDatasourceRelation onlineDatasourceRelation = + onlineDatasourceRelationService.getByIdWithRelation(relationId, MyRelationParam.full()); + if (onlineDatasourceRelation == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineDatasourceRelationVo onlineDatasourceRelationVo = + OnlineDatasourceRelation.INSTANCE.fromModel(onlineDatasourceRelation); + return ResponseResult.success(onlineDatasourceRelationVo); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDblinkController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDblinkController.java new file mode 100644 index 00000000..4d7631c7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDblinkController.java @@ -0,0 +1,92 @@ +package com.flow.demo.common.online.api.controller; + +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.MyOrderParam; +import com.flow.demo.common.core.object.MyPageData; +import com.flow.demo.common.core.object.MyPageParam; +import com.flow.demo.common.core.object.ResponseResult; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.online.dto.OnlineDblinkDto; +import com.flow.demo.common.online.model.OnlineDblink; +import com.flow.demo.common.online.object.SqlTable; +import com.flow.demo.common.online.object.SqlTableColumn; +import com.flow.demo.common.online.service.OnlineDblinkService; +import com.flow.demo.common.online.vo.OnlineDblinkVo; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 数据库链接操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlineDblink") +public class OnlineDblinkController { + + @Autowired + private OnlineDblinkService onlineDblinkService; + + /** + * 列出符合过滤条件的数据库链接列表。 + * + * @param onlineDblinkDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlineDblinkDto onlineDblinkDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineDblink onlineDblinkFilter = MyModelUtil.copyTo(onlineDblinkDtoFilter, OnlineDblink.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineDblink.class); + List onlineDblinkList = + onlineDblinkService.getOnlineDblinkListWithRelation(onlineDblinkFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineDblinkList, OnlineDblink.INSTANCE)); + } + + /** + * 获取指定数据库链接下的所有动态表单依赖的数据表列表。 + * + * @param dblinkId 数据库链接Id。 + * @return 所有动态表单依赖的数据表列表 + */ + @GetMapping("/listDblinkTables") + public ResponseResult> listDblinkTables(@RequestParam Long dblinkId) { + OnlineDblink dblink = onlineDblinkService.getById(dblinkId); + if (dblink == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(onlineDblinkService.getDblinkTableList(dblink)); + } + + /** + * 获取指定数据库链接下,指定数据表的所有字段信息。 + * + * @param dblinkId 数据库链接Id。 + * @param tableName 表名。 + * @return 该表的所有字段列表。 + */ + @GetMapping("/listDblinkTableColumns") + public ResponseResult> listDblinkTableColumns( + @RequestParam Long dblinkId, @RequestParam String tableName) { + OnlineDblink dblink = onlineDblinkService.getById(dblinkId); + if (dblink == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(onlineDblinkService.getDblinkTableColumnList(dblink, tableName)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDictController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDictController.java new file mode 100644 index 00000000..58811075 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineDictController.java @@ -0,0 +1,156 @@ +package com.flow.demo.common.online.api.controller; + +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.dto.OnlineDictDto; +import com.flow.demo.common.online.model.OnlineDict; +import com.flow.demo.common.online.service.OnlineDictService; +import com.flow.demo.common.online.vo.OnlineDictVo; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.List; + +/** + * 在线表单字典操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlineDict") +public class OnlineDictController { + + @Autowired + private OnlineDictService onlineDictService; + + /** + * 新增在线表单字典数据。 + * + * @param onlineDictDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody OnlineDictDto onlineDictDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineDictDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineDict onlineDict = MyModelUtil.copyTo(onlineDictDto, OnlineDict.class); + // 验证关联Id的数据合法性 + CallResult callResult = onlineDictService.verifyRelatedData(onlineDict, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + onlineDict = onlineDictService.saveNew(onlineDict); + return ResponseResult.success(onlineDict.getDictId()); + } + + /** + * 更新在线表单字典数据。 + * + * @param onlineDictDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody OnlineDictDto onlineDictDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineDictDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineDict onlineDict = MyModelUtil.copyTo(onlineDictDto, OnlineDict.class); + OnlineDict originalOnlineDict = onlineDictService.getById(onlineDict.getDictId()); + if (originalOnlineDict == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前在线字典并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = onlineDictService.verifyRelatedData(onlineDict, originalOnlineDict); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!onlineDictService.update(onlineDict, originalOnlineDict)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除在线表单字典数据。 + * + * @param dictId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long dictId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(dictId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + OnlineDict originalOnlineDict = onlineDictService.getById(dictId); + if (originalOnlineDict == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前在线字典并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineDictService.remove(dictId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的在线表单字典列表。 + * + * @param onlineDictDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlineDictDto onlineDictDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineDict onlineDictFilter = MyModelUtil.copyTo(onlineDictDtoFilter, OnlineDict.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineDict.class); + List onlineDictList = onlineDictService.getOnlineDictListWithRelation(onlineDictFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineDictList, OnlineDict.INSTANCE)); + } + + /** + * 查看指定在线表单字典对象详情。 + * + * @param dictId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long dictId) { + if (MyCommonUtil.existBlankArgument(dictId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineDict onlineDict = onlineDictService.getByIdWithRelation(dictId, MyRelationParam.full()); + if (onlineDict == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineDictVo onlineDictVo = OnlineDict.INSTANCE.fromModel(onlineDict); + return ResponseResult.success(onlineDictVo); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineFormController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineFormController.java new file mode 100644 index 00000000..07b32746 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineFormController.java @@ -0,0 +1,257 @@ +package com.flow.demo.common.online.api.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.json.JSONObject; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.dto.OnlineFormDto; +import com.flow.demo.common.online.model.*; +import com.flow.demo.common.online.service.*; +import com.flow.demo.common.online.vo.OnlineFormVo; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 在线表单操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlineForm") +public class OnlineFormController { + + @Autowired + private OnlineFormService onlineFormService; + @Autowired + private OnlineDatasourceService onlineDatasourceService; + @Autowired + private OnlineDatasourceRelationService onlineDatasourceRelationService; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private OnlineColumnService onlineColumnService; + @Autowired + private OnlineVirtualColumnService onlineVirtualColumnService; + @Autowired + private OnlineDictService onlineDictService; + @Autowired + private OnlineRuleService onlineRuleService; + + /** + * 新增在线表单数据。 + * + * @param onlineFormDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody OnlineFormDto onlineFormDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineFormDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineForm onlineForm = MyModelUtil.copyTo(onlineFormDto, OnlineForm.class); + // 验证关联Id的数据合法性 + CallResult callResult = onlineFormService.verifyRelatedData(onlineForm, null); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + Set datasourceIdSet = null; + if (CollUtil.isNotEmpty(onlineFormDto.getDatasourceIdList())) { + datasourceIdSet = new HashSet<>(onlineFormDto.getDatasourceIdList()); + if (!onlineDatasourceService.existAllPrimaryKeys(datasourceIdSet)) { + errorMessage = "数据验证失败,当前在线表单包含不存在的数据源Id!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + onlineForm = onlineFormService.saveNew(onlineForm, datasourceIdSet); + return ResponseResult.success(onlineForm.getFormId()); + } + + /** + * 更新在线表单数据。 + * + * @param onlineFormDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody OnlineFormDto onlineFormDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineFormDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineForm onlineForm = MyModelUtil.copyTo(onlineFormDto, OnlineForm.class); + OnlineForm originalOnlineForm = onlineFormService.getById(onlineForm.getFormId()); + if (originalOnlineForm == null) { + errorMessage = "数据验证失败,当前在线表单并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + // 验证关联Id的数据合法性 + CallResult callResult = onlineFormService.verifyRelatedData(onlineForm, originalOnlineForm); + if (!callResult.isSuccess()) { + errorMessage = callResult.getErrorMessage(); + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + Set datasourceIdSet = null; + if (CollUtil.isNotEmpty(onlineFormDto.getDatasourceIdList())) { + datasourceIdSet = new HashSet<>(onlineFormDto.getDatasourceIdList()); + if (!onlineDatasourceService.existAllPrimaryKeys(datasourceIdSet)) { + errorMessage = "数据验证失败,当前在线表单包含不存在的数据源Id!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + if (!onlineFormService.update(onlineForm, originalOnlineForm, datasourceIdSet)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除在线表单数据。 + * + * @param formId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long formId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(formId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + OnlineForm originalOnlineForm = onlineFormService.getById(formId); + if (originalOnlineForm == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前在线表单并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineFormService.remove(formId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的在线表单列表。 + * + * @param onlineFormDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlineFormDto onlineFormDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineForm onlineFormFilter = MyModelUtil.copyTo(onlineFormDtoFilter, OnlineForm.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineForm.class); + List onlineFormList = + onlineFormService.getOnlineFormListWithRelation(onlineFormFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineFormList, OnlineForm.INSTANCE)); + } + + /** + * 查看指定在线表单对象详情。 + * + * @param formId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long formId) { + if (MyCommonUtil.existBlankArgument(formId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineForm onlineForm = onlineFormService.getByIdWithRelation(formId, MyRelationParam.full()); + if (onlineForm == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineFormVo onlineFormVo = OnlineForm.INSTANCE.fromModel(onlineForm); + List formDatasourceList = onlineFormService.getFormDatasourceListByFormId(formId); + if (CollUtil.isNotEmpty(formDatasourceList)) { + onlineFormVo.setDatasourceIdList(formDatasourceList.stream() + .map(OnlineFormDatasource::getDatasourceId).collect(Collectors.toList())); + } + return ResponseResult.success(onlineFormVo); + } + + /** + * 获取指定在线表单对象在前端渲染时所需的所有数据对象。 + * + * @param formId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/render") + public ResponseResult render(@RequestParam Long formId) { + if (MyCommonUtil.existBlankArgument(formId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineForm onlineForm = onlineFormService.getByIdWithRelation(formId, MyRelationParam.full()); + if (onlineForm == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineFormVo onlineFormVo = OnlineForm.INSTANCE.fromModel(onlineForm); + JSONObject jsonObject = new JSONObject(); + jsonObject.putOpt("onlineForm", onlineFormVo); + List formDatasourceList = onlineFormService.getFormDatasourceListByFormId(formId); + if (CollUtil.isEmpty(formDatasourceList)) { + return ResponseResult.success(jsonObject); + } + Set datasourceIdSet = formDatasourceList.stream() + .map(OnlineFormDatasource::getDatasourceId).collect(Collectors.toSet()); + List onlineDatasourceList = onlineDatasourceService.getOnlineDatasourceList(datasourceIdSet); + jsonObject.putOpt("onlineDatasourceList", onlineDatasourceList); + List onlineDatasourceRelationList = + onlineDatasourceRelationService.getOnlineDatasourceRelationListByDatasourceIds(datasourceIdSet, null); + if (CollUtil.isNotEmpty(onlineDatasourceRelationList)) { + jsonObject.putOpt("onlineDatasourceRelationList", onlineDatasourceRelationList); + } + List onlineDatasourceTableList = + onlineDatasourceService.getOnlineDatasourceTableList(datasourceIdSet); + if (CollUtil.isNotEmpty(onlineDatasourceTableList)) { + Set tableIdSet = onlineDatasourceTableList.stream() + .map(OnlineDatasourceTable::getTableId).collect(Collectors.toSet()); + List onlineTableList = onlineTableService.getOnlineTableList(tableIdSet); + jsonObject.putOpt("onlineTableList", onlineTableList); + List onlineColumnList = onlineColumnService.getOnlineColumnListByTableIds(tableIdSet); + jsonObject.putOpt("onlineColumnList", onlineColumnList); + List virtualColumnList = + onlineVirtualColumnService.getOnlineVirtualColumnListByTableIds(tableIdSet); + jsonObject.putOpt("onlineVirtualColumnList", virtualColumnList); + Set dictIdSet = onlineColumnList.stream() + .filter(c -> c.getDictId() != null).map(OnlineColumn::getDictId).collect(Collectors.toSet()); + if (CollUtil.isNotEmpty(dictIdSet)) { + List onlineDictList = onlineDictService.getOnlineDictList(dictIdSet); + if (CollUtil.isNotEmpty(onlineDictList)) { + jsonObject.putOpt("onlineDictList", onlineDictList); + } + } + Set columnIdSet = onlineColumnList.stream().map(OnlineColumn::getColumnId).collect(Collectors.toSet()); + List colunmRuleList = onlineRuleService.getOnlineColumnRuleListByColumnIds(columnIdSet); + if (CollUtil.isNotEmpty(colunmRuleList)) { + jsonObject.putOpt("onlineColumnRuleList", colunmRuleList); + } + } + return ResponseResult.success(jsonObject); + } + +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlinePageController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlinePageController.java new file mode 100644 index 00000000..6fbd7429 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlinePageController.java @@ -0,0 +1,343 @@ +package com.flow.demo.common.online.api.controller; + +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.dto.OnlineDatasourceDto; +import com.flow.demo.common.online.dto.OnlinePageDatasourceDto; +import com.flow.demo.common.online.dto.OnlinePageDto; +import com.flow.demo.common.online.model.OnlineDatasource; +import com.flow.demo.common.online.model.OnlinePage; +import com.flow.demo.common.online.model.OnlinePageDatasource; +import com.flow.demo.common.online.model.constant.PageStatus; +import com.flow.demo.common.online.service.OnlineDatasourceService; +import com.flow.demo.common.online.service.OnlineFormService; +import com.flow.demo.common.online.service.OnlinePageService; +import com.flow.demo.common.online.vo.OnlineDatasourceVo; +import com.flow.demo.common.online.vo.OnlinePageDatasourceVo; +import com.flow.demo.common.online.vo.OnlinePageVo; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 在线表单页面操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlinePage") +public class OnlinePageController { + + @Autowired + private OnlinePageService onlinePageService; + @Autowired + private OnlineFormService onlineFormService; + @Autowired + private OnlineDatasourceService onlineDatasourceService; + + /** + * 新增在线表单页面数据。 + * + * @param onlinePageDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody OnlinePageDto onlinePageDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlinePageDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlinePage onlinePage = MyModelUtil.copyTo(onlinePageDto, OnlinePage.class); + onlinePage = onlinePageService.saveNew(onlinePage); + return ResponseResult.success(onlinePage.getPageId()); + } + + /** + * 更新在线表单页面数据。 + * + * @param onlinePageDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody OnlinePageDto onlinePageDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlinePageDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlinePage onlinePage = MyModelUtil.copyTo(onlinePageDto, OnlinePage.class); + OnlinePage originalOnlinePage = onlinePageService.getById(onlinePage.getPageId()); + if (originalOnlinePage == null) { + errorMessage = "数据验证失败,当前页面对象并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlinePage.getPageType().equals(originalOnlinePage.getPageType())) { + errorMessage = "数据验证失败,页面类型不能修改!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlinePageService.update(onlinePage, originalOnlinePage)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 更新在线表单页面对象的发布状态字段。 + * + * @param pageId 待更新的页面对象主键Id。 + * @param published 发布状态。 + * @return 应答结果对象。 + */ + @PostMapping("/updatePublished") + public ResponseResult updateStatus( + @MyRequestBody(required = true) Long pageId, + @MyRequestBody(required = true) Boolean published) { + String errorMessage; + // 验证关联Id的数据合法性 + OnlinePage originalOnlinePage = onlinePageService.getById(pageId); + if (originalOnlinePage == null) { + errorMessage = "数据验证失败,当前页面对象并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!published.equals(originalOnlinePage.getPublished())) { + if (published && !originalOnlinePage.getStatus().equals(PageStatus.FORM_DESIGN)) { + errorMessage = "数据验证失败,当前页面状态不为 [设计] 状态,因此不能发布!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + onlinePageService.updatePublished(pageId, published); + } + return ResponseResult.success(); + } + + /** + * 删除在线表单页面数据。 + * + * @param pageId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long pageId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(pageId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + OnlinePage originalOnlinePage = onlinePageService.getById(pageId); + if (originalOnlinePage == null) { + errorMessage = "数据验证失败,当前页面对象并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlinePageService.remove(pageId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的在线表单页面列表。 + * + * @param onlinePageDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlinePageDto onlinePageDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlinePage onlinePageFilter = MyModelUtil.copyTo(onlinePageDtoFilter, OnlinePage.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlinePage.class); + List onlinePageList = onlinePageService.getOnlinePageListWithRelation(onlinePageFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlinePageList, OnlinePage.INSTANCE)); + } + + /** + * 获取系统中配置的所有Page和表单的列表。 + * + * @return 系统中配置的所有Page和表单的列表。 + */ + @PostMapping("/listAllPageAndForm") + public ResponseResult listAllPageAndForm() { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("pageList", onlinePageService.getAllList()); + jsonObject.put("formList", onlineFormService.getAllList()); + return ResponseResult.success(jsonObject); + } + + /** + * 查看指定在线表单页面对象详情。 + * + * @param pageId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long pageId) { + if (MyCommonUtil.existBlankArgument(pageId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlinePage onlinePage = onlinePageService.getByIdWithRelation(pageId, MyRelationParam.full()); + if (onlinePage == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlinePageVo onlinePageVo = OnlinePage.INSTANCE.fromModel(onlinePage); + return ResponseResult.success(onlinePageVo); + } + + /** + * 列出不与指定在线表单页面存在多对多关系的在线数据源列表数据。通常用于查看添加新在线数据源对象的候选列表。 + * + * @param pageId 主表关联字段。 + * @param onlineDatasourceDtoFilter 在线数据源过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listNotInOnlinePageDatasource") + public ResponseResult> listNotInOnlinePageDatasource( + @MyRequestBody Long pageId, + @MyRequestBody OnlineDatasourceDto onlineDatasourceDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doOnlinePageDatasourceVerify(pageId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineDatasource filter = MyModelUtil.copyTo(onlineDatasourceDtoFilter, OnlineDatasource.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineDatasource.class); + List onlineDatasourceList = + onlineDatasourceService.getNotInOnlineDatasourceListByPageId(pageId, filter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineDatasourceList, OnlineDatasource.INSTANCE)); + } + + /** + * 列出与指定在线表单页面存在多对多关系的在线数据源列表数据。 + * + * @param pageId 主表关联字段。 + * @param onlineDatasourceDtoFilter 在线数据源过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,返回符合条件的数据列表。 + */ + @PostMapping("/listOnlinePageDatasource") + public ResponseResult> listOnlinePageDatasource( + @MyRequestBody Long pageId, + @MyRequestBody OnlineDatasourceDto onlineDatasourceDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + ResponseResult verifyResult = this.doOnlinePageDatasourceVerify(pageId); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineDatasource filter = MyModelUtil.copyTo(onlineDatasourceDtoFilter, OnlineDatasource.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineDatasource.class); + List onlineDatasourceList = + onlineDatasourceService.getOnlineDatasourceListByPageId(pageId, filter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineDatasourceList, OnlineDatasource.INSTANCE)); + } + + /** + * 批量添加在线表单页面和在线数据源对象的多对多关联关系数据。 + * + * @param pageId 主表主键Id。 + * @param onlinePageDatasourceDtoList 关联对象列表。 + * @return 应答结果对象。 + */ + @PostMapping("/addOnlinePageDatasource") + public ResponseResult addOnlinePageDatasource( + @MyRequestBody Long pageId, + @MyRequestBody(value = "onlinePageDatasourceList", elementType = OnlinePageDatasourceDto.class) List onlinePageDatasourceDtoList) { + if (MyCommonUtil.existBlankArgument(pageId, onlinePageDatasourceDtoList)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + for (OnlinePageDatasourceDto onlinePageDatasource : onlinePageDatasourceDtoList) { + String errorMessage = MyCommonUtil.getModelValidationError(onlinePageDatasource); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + Set datasourceIdSet = + onlinePageDatasourceDtoList.stream().map(OnlinePageDatasourceDto::getDatasourceId).collect(Collectors.toSet()); + if (!onlinePageService.existId(pageId) + || !onlineDatasourceService.existUniqueKeyList("datasourceId", datasourceIdSet)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + List onlinePageDatasourceList = + MyModelUtil.copyCollectionTo(onlinePageDatasourceDtoList, OnlinePageDatasource.class); + onlinePageService.addOnlinePageDatasourceList(onlinePageDatasourceList, pageId); + return ResponseResult.success(); + } + + /** + * 显示在线表单页面和指定数据源的多对多关联详情数据。 + * + * @param pageId 主表主键Id。 + * @param datasourceId 从表主键Id。 + * @return 应答结果对象,包括中间表详情。 + */ + @GetMapping("/viewOnlinePageDatasource") + public ResponseResult viewOnlinePageDatasource( + @RequestParam Long pageId, @RequestParam Long datasourceId) { + if (MyCommonUtil.existBlankArgument(pageId, datasourceId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlinePageDatasource onlinePageDatasource = onlinePageService.getOnlinePageDatasource(pageId, datasourceId); + if (onlinePageDatasource == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlinePageDatasourceVo onlinePageDatasourceVo = MyModelUtil.copyTo(onlinePageDatasource, OnlinePageDatasourceVo.class); + return ResponseResult.success(onlinePageDatasourceVo); + } + + /** + * 移除指定在线表单页面和指定数据源的多对多关联关系。 + * + * @param pageId 主表主键Id。 + * @param datasourceId 从表主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/deleteOnlinePageDatasource") + public ResponseResult deleteOnlinePageDatasource( + @MyRequestBody Long pageId, @MyRequestBody Long datasourceId) { + if (MyCommonUtil.existBlankArgument(pageId, datasourceId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!onlinePageService.removeOnlinePageDatasource(pageId, datasourceId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + private ResponseResult doOnlinePageDatasourceVerify(Long pageId) { + if (MyCommonUtil.existBlankArgument(pageId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + if (!onlinePageService.existId(pageId)) { + return ResponseResult.error(ErrorCodeEnum.INVALID_RELATED_RECORD_ID); + } + return ResponseResult.success(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineRuleController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineRuleController.java new file mode 100644 index 00000000..2eb66557 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineRuleController.java @@ -0,0 +1,144 @@ +package com.flow.demo.common.online.api.controller; + +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.dto.OnlineRuleDto; +import com.flow.demo.common.online.model.OnlineRule; +import com.flow.demo.common.online.service.OnlineRuleService; +import com.flow.demo.common.online.vo.OnlineRuleVo; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.List; + +/** + * 验证规则操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlineRule") +public class OnlineRuleController { + + @Autowired + private OnlineRuleService onlineRuleService; + + /** + * 新增验证规则数据。 + * + * @param onlineRuleDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody OnlineRuleDto onlineRuleDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineRuleDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineRule onlineRule = MyModelUtil.copyTo(onlineRuleDto, OnlineRule.class); + onlineRule = onlineRuleService.saveNew(onlineRule); + return ResponseResult.success(onlineRule.getRuleId()); + } + + /** + * 更新验证规则数据。 + * + * @param onlineRuleDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody OnlineRuleDto onlineRuleDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineRuleDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineRule onlineRule = MyModelUtil.copyTo(onlineRuleDto, OnlineRule.class); + OnlineRule originalOnlineRule = onlineRuleService.getById(onlineRule.getRuleId()); + if (originalOnlineRule == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前在线字段规则并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineRuleService.update(onlineRule, originalOnlineRule)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除验证规则数据。 + * + * @param ruleId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long ruleId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(ruleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + OnlineRule originalOnlineRule = onlineRuleService.getById(ruleId); + if (originalOnlineRule == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前在线字段规则并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineRuleService.remove(ruleId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的验证规则列表。 + * + * @param onlineRuleDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlineRuleDto onlineRuleDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineRule onlineRuleFilter = MyModelUtil.copyTo(onlineRuleDtoFilter, OnlineRule.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineRule.class); + List onlineRuleList = onlineRuleService.getOnlineRuleListWithRelation(onlineRuleFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineRuleList, OnlineRule.INSTANCE)); + } + + /** + * 查看指定验证规则对象详情。 + * + * @param ruleId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long ruleId) { + if (MyCommonUtil.existBlankArgument(ruleId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineRule onlineRule = onlineRuleService.getByIdWithRelation(ruleId, MyRelationParam.full()); + if (onlineRule == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineRuleVo onlineRuleVo = OnlineRule.INSTANCE.fromModel(onlineRule); + return ResponseResult.success(onlineRuleVo); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineTableController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineTableController.java new file mode 100644 index 00000000..6fb5a8f2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineTableController.java @@ -0,0 +1,118 @@ +package com.flow.demo.common.online.api.controller; + +import cn.jimmyshi.beanquery.BeanQuery; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.dto.OnlineTableDto; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.service.OnlineTableService; +import com.flow.demo.common.online.vo.OnlineTableVo; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.groups.Default; +import java.util.List; +import java.util.Map; + +/** + * 数据表操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlineTable") +public class OnlineTableController { + + @Autowired + private OnlineTableService onlineTableService; + + /** + * 更新数据表数据。 + * + * @param onlineTableDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody OnlineTableDto onlineTableDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineTableDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineTable onlineTable = MyModelUtil.copyTo(onlineTableDto, OnlineTable.class); + OnlineTable originalOnlineTable = onlineTableService.getById(onlineTable.getTableId()); + if (originalOnlineTable == null) { + // NOTE: 修改下面方括号中的话述 + errorMessage = "数据验证失败,当前在线数据表并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineTableService.update(onlineTable, originalOnlineTable)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的数据表列表。 + * + * @param onlineTableDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlineTableDto onlineTableDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineTable onlineTableFilter = MyModelUtil.copyTo(onlineTableDtoFilter, OnlineTable.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineTable.class); + List onlineTableList = + onlineTableService.getOnlineTableListWithRelation(onlineTableFilter, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(onlineTableList, OnlineTable.INSTANCE)); + } + + /** + * 查看指定数据表对象详情。 + * + * @param tableId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long tableId) { + if (MyCommonUtil.existBlankArgument(tableId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineTable onlineTable = onlineTableService.getByIdWithRelation(tableId, MyRelationParam.full()); + if (onlineTable == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineTableVo onlineTableVo = OnlineTable.INSTANCE.fromModel(onlineTable); + return ResponseResult.success(onlineTableVo); + } + + /** + * 以字典形式返回全部数据表数据集合。字典的键值为[tableId, modelName]。 + * 白名单接口,登录用户均可访问。 + * + * @param filter 过滤对象。 + * @return 应答结果对象,包含的数据为 List>,map中包含两条记录,key的值分别是id和name,value对应具体数据。 + */ + @GetMapping("/listDict") + public ResponseResult>> listDict(OnlineTable filter) { + List resultList = onlineTableService.getListByFilter(filter); + return ResponseResult.success(BeanQuery.select( + "tableId as id", "modelName as name").executeFrom(resultList)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineVirtualColumnController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineVirtualColumnController.java new file mode 100644 index 00000000..e0617663 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/java/com/flow/demo/common/online/api/controller/OnlineVirtualColumnController.java @@ -0,0 +1,180 @@ +package com.flow.demo.common.online.api.controller; + +import com.github.pagehelper.page.PageMethod; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.*; +import com.flow.demo.common.core.constant.*; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.dto.OnlineVirtualColumnDto; +import com.flow.demo.common.online.model.OnlineVirtualColumn; +import com.flow.demo.common.online.model.constant.VirtualType; +import com.flow.demo.common.online.service.OnlineVirtualColumnService; +import com.flow.demo.common.online.vo.OnlineVirtualColumnVo; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.*; +import javax.validation.groups.Default; + +/** + * 虚拟字段操作控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@RequestMapping("${common-online-api.urlPrefix}/onlineVirtualColumn") +public class OnlineVirtualColumnController { + + @Autowired + private OnlineVirtualColumnService onlineVirtualColumnService; + + /** + * 新增虚拟字段数据。 + * + * @param onlineVirtualColumnDto 新增对象。 + * @return 应答结果对象,包含新增对象主键Id。 + */ + @PostMapping("/add") + public ResponseResult add(@MyRequestBody OnlineVirtualColumnDto onlineVirtualColumnDto) { + String errorMessage = MyCommonUtil.getModelValidationError(onlineVirtualColumnDto); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineVirtualColumn onlineVirtualColumn = + MyModelUtil.copyTo(onlineVirtualColumnDto, OnlineVirtualColumn.class); + ResponseResult verifyResult = this.doVerify(onlineVirtualColumn, null); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + onlineVirtualColumn = onlineVirtualColumnService.saveNew(onlineVirtualColumn); + return ResponseResult.success(onlineVirtualColumn.getVirtualColumnId()); + } + + /** + * 更新虚拟字段数据。 + * + * @param onlineVirtualColumnDto 更新对象。 + * @return 应答结果对象。 + */ + @PostMapping("/update") + public ResponseResult update(@MyRequestBody OnlineVirtualColumnDto onlineVirtualColumnDto) { + String errorMessage = MyCommonUtil.getModelValidationError( + onlineVirtualColumnDto, Default.class, UpdateGroup.class); + if (errorMessage != null) { + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineVirtualColumn onlineVirtualColumn = + MyModelUtil.copyTo(onlineVirtualColumnDto, OnlineVirtualColumn.class); + OnlineVirtualColumn originalOnlineVirtualColumn = + onlineVirtualColumnService.getById(onlineVirtualColumn.getVirtualColumnId()); + if (originalOnlineVirtualColumn == null) { + errorMessage = "数据验证失败,当前虚拟字段并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + ResponseResult verifyResult = this.doVerify(onlineVirtualColumn, originalOnlineVirtualColumn); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + if (!onlineVirtualColumnService.update(onlineVirtualColumn, originalOnlineVirtualColumn)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除虚拟字段数据。 + * + * @param virtualColumnId 删除对象主键Id。 + * @return 应答结果对象。 + */ + @PostMapping("/delete") + public ResponseResult delete(@MyRequestBody Long virtualColumnId) { + String errorMessage; + if (MyCommonUtil.existBlankArgument(virtualColumnId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + // 验证关联Id的数据合法性 + OnlineVirtualColumn originalOnlineVirtualColumn = onlineVirtualColumnService.getById(virtualColumnId); + if (originalOnlineVirtualColumn == null) { + errorMessage = "数据验证失败,当前虚拟字段并不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + if (!onlineVirtualColumnService.remove(virtualColumnId)) { + errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!"; + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); + } + return ResponseResult.success(); + } + + /** + * 列出符合过滤条件的虚拟字段列表。 + * + * @param onlineVirtualColumnDtoFilter 过滤对象。 + * @param orderParam 排序参数。 + * @param pageParam 分页参数。 + * @return 应答结果对象,包含查询结果集。 + */ + @PostMapping("/list") + public ResponseResult> list( + @MyRequestBody OnlineVirtualColumnDto onlineVirtualColumnDtoFilter, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + OnlineVirtualColumn onlineVirtualColumnFilter = + MyModelUtil.copyTo(onlineVirtualColumnDtoFilter, OnlineVirtualColumn.class); + String orderBy = MyOrderParam.buildOrderBy(orderParam, OnlineVirtualColumn.class); + List onlineVirtualColumnList = + onlineVirtualColumnService.getOnlineVirtualColumnListWithRelation(onlineVirtualColumnFilter, orderBy); + MyPageData pageData = + MyPageUtil.makeResponseData(onlineVirtualColumnList, OnlineVirtualColumn.INSTANCE); + return ResponseResult.success(pageData); + } + + /** + * 查看指定虚拟字段对象详情。 + * + * @param virtualColumnId 指定对象主键Id。 + * @return 应答结果对象,包含对象详情。 + */ + @GetMapping("/view") + public ResponseResult view(@RequestParam Long virtualColumnId) { + if (MyCommonUtil.existBlankArgument(virtualColumnId)) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineVirtualColumn onlineVirtualColumn = + onlineVirtualColumnService.getByIdWithRelation(virtualColumnId, MyRelationParam.full()); + if (onlineVirtualColumn == null) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineVirtualColumnVo onlineVirtualColumnVo = + OnlineVirtualColumn.INSTANCE.fromModel(onlineVirtualColumn); + return ResponseResult.success(onlineVirtualColumnVo); + } + + private ResponseResult doVerify( + OnlineVirtualColumn virtualColumn, OnlineVirtualColumn originalVirtualColumn) { + if (!virtualColumn.getVirtualType().equals(VirtualType.AGGREGATION)) { + return ResponseResult.success(); + } + if (MyCommonUtil.existBlankArgument( + virtualColumn.getAggregationColumnId(), + virtualColumn.getAggregationTableId(), + virtualColumn.getDatasourceId(), + virtualColumn.getRelationId(), + virtualColumn.getAggregationType())) { + String errorMessage = "数据验证失败,数据源、关联关系、聚合表、聚合字段和聚合类型,均不能为空!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + CallResult verifyResult = onlineVirtualColumnService.verifyRelatedData(virtualColumn, null); + if (!verifyResult.isSuccess()) { + return ResponseResult.errorFrom(verifyResult); + } + return ResponseResult.success(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/resources/META-INF/spring.factories b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..ebe5596f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online-api/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.flow.demo.common.online.api.config.OnlineApiAutoConfig \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/pom.xml new file mode 100644 index 00000000..4bdf4c27 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/pom.xml @@ -0,0 +1,63 @@ + + + + common + com.flow.demo + 1.0.0 + + 4.0.0 + + common-online + 1.0.0 + common-online + jar + + + + com.flow.demo + common-core + 1.0.0 + + + com.flow.demo + common-datafilter + 1.0.0 + + + com.flow.demo + common-redis + 1.0.0 + + + com.flow.demo + common-sequence + 1.0.0 + + + com.flow.demo + common-log + 1.0.0 + + + + + + + src/main/resources + + **/*.* + + false + + + src/main/java + + **/*.xml + + false + + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/config/OnlineAutoConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/config/OnlineAutoConfig.java new file mode 100644 index 00000000..6c93a151 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/config/OnlineAutoConfig.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.online.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +/** + * common-online模块的自动配置引导类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EnableConfigurationProperties({OnlineProperties.class}) +public class OnlineAutoConfig { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/config/OnlineProperties.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/config/OnlineProperties.java new file mode 100644 index 00000000..67adc368 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/config/OnlineProperties.java @@ -0,0 +1,30 @@ +package com.flow.demo.common.online.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 在线表单的配置对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ConfigurationProperties(prefix = "common-online") +public class OnlineProperties { + + /** + * 仅以该前缀开头的数据表才会成为动态表单的候选数据表,如: zz_。如果为空,则所有表均可被选。 + */ + private String tablePrefix; + + /** + * 在线表单业务操作的URL前缀。 + */ + private String operationUrlPrefix; + + /** + * 上传文件的根路径。 + */ + private String uploadFileBaseDir; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/controller/OnlineOperationController.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/controller/OnlineOperationController.java new file mode 100644 index 00000000..bdc5d113 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/controller/OnlineOperationController.java @@ -0,0 +1,786 @@ +package com.flow.demo.common.online.controller; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.CharUtil; +import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.annotation.MyRequestBody; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.*; +import com.flow.demo.common.core.util.ContextUtil; +import com.flow.demo.common.core.util.MyCommonUtil; +import com.flow.demo.common.core.util.MyPageUtil; +import com.flow.demo.common.online.util.OnlineOperationHelper; +import com.flow.demo.common.online.dto.OnlineFilterDto; +import com.flow.demo.common.online.model.*; +import com.flow.demo.common.online.model.constant.DictType; +import com.flow.demo.common.online.model.constant.RelationType; +import com.flow.demo.common.online.object.ColumnData; +import com.flow.demo.common.online.service.*; +import com.flow.demo.common.online.util.OnlineConstant; +import com.github.pagehelper.page.PageMethod; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 在线操作接口的控制器类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@RestController +@ConditionalOnProperty(name = "common-online.operationEnabled", havingValue = "true") +@RequestMapping("${common-online.operationUrlPrefix}/onlineOperation") +public class OnlineOperationController { + + @Autowired + private OnlineOperationService onlineOperationService; + @Autowired + private OnlineDictService onlineDictService; + @Autowired + private OnlineDatasourceService onlineDatasourceService; + @Autowired + private OnlineDatasourceRelationService onlineDatasourceRelationService; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private OnlineOperationHelper onlineOperationHelper; + + /** + * 新增数据接口。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 主表的数据源Id。 + * @param masterData 主表新增数据。 + * @param slaveData 一对多从表新增数据列表。 + * @return 应答结果。 + */ + @PostMapping("/addDatasource/{datasourceVariableName}") + public ResponseResult addDatasource( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @MyRequestBody(required = true) Long datasourceId, + @MyRequestBody(required = true) JSONObject masterData, + @MyRequestBody JSONObject slaveData) throws IOException { + String errorMessage; + // 验证数据源的合法性,同时获取主表对象。 + ResponseResult datasourceResult = + onlineOperationHelper.verifyAndGetDatasource(datasourceId); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + OnlineDatasource datasource = datasourceResult.getData(); + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + OnlineTable masterTable = datasource.getMasterTable(); + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(masterTable, masterData, false, null); + if (!columnDataListResult.isSuccess()) { + return ResponseResult.errorFrom(columnDataListResult); + } + if (slaveData == null) { + onlineOperationService.saveNew(masterTable, columnDataListResult.getData()); + } else { + ResponseResult>>> slaveDataListResult = + onlineOperationHelper.buildSlaveDataList(datasourceId, slaveData); + if (!slaveDataListResult.isSuccess()) { + return ResponseResult.errorFrom(slaveDataListResult); + } + onlineOperationService.saveNewAndSlaveRelation( + masterTable, columnDataListResult.getData(), slaveDataListResult.getData()); + } + return ResponseResult.success(); + } + + /** + * 新增一对多从表数据接口。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 主表的数据源Id。 + * @param relationId 一对多的关联Id。 + * @param slaveData 一对多从表的新增数据列表。 + * @return 应答结果。 + */ + @PostMapping("/addOneToManyRelation/{datasourceVariableName}") + public ResponseResult addOneToManyRelation( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @MyRequestBody(required = true) Long datasourceId, + @MyRequestBody(required = true) Long relationId, + @MyRequestBody(required = true) JSONObject slaveData) { + String errorMessage; + OnlineDatasource datasource = onlineDatasourceService.getById(datasourceId); + if (datasource == null) { + errorMessage = "数据验证失败,数据源Id并不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + ResponseResult relationResult = + onlineOperationHelper.verifyAndGetOneToManyRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + return ResponseResult.errorFrom(relationResult); + } + OnlineDatasourceRelation relation = relationResult.getData(); + OnlineTable slaveTable = relation.getSlaveTable(); + // 拆解主表和一对多关联从表的输入参数,并构建出数据表的待插入数据列表。 + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(slaveTable, slaveData, false, null); + if (!columnDataListResult.isSuccess()) { + return ResponseResult.errorFrom(columnDataListResult); + } + onlineOperationService.saveNew(slaveTable, columnDataListResult.getData()); + return ResponseResult.success(); + } + + /** + * 更新主数据接口。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 主表数据源Id。 + * @param masterData 表数据。这里没有包含的字段将视为NULL。 + * @return 应该结果。 + */ + @PostMapping("/updateDatasource/{datasourceVariableName}") + public ResponseResult updateDatasource( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @MyRequestBody(required = true) Long datasourceId, + @MyRequestBody(required = true) JSONObject masterData) { + String errorMessage; + ResponseResult datasourceResult = + onlineOperationHelper.verifyAndGetDatasource(datasourceId); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + OnlineDatasource datasource = datasourceResult.getData(); + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + OnlineTable masterTable = datasource.getMasterTable(); + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(masterTable, masterData, true, null); + if (!columnDataListResult.isSuccess()) { + return ResponseResult.errorFrom(columnDataListResult); + } + if (!onlineOperationService.update(masterTable, columnDataListResult.getData())) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 更新一对多关联数据接口。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 主表数据源Id。 + * @param relationId 一对多关联Id。 + * @param slaveData 一对多关联从表数据。这里没有包含的字段将视为NULL。 + * @return 应该结果。 + */ + @PostMapping("/updateOneToManyRelation/{datasourceVariableName}") + public ResponseResult updateOneToManyRelation( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @MyRequestBody(required = true) Long datasourceId, + @MyRequestBody(required = true) Long relationId, + @MyRequestBody(required = true) JSONObject slaveData) { + String errorMessage; + OnlineDatasource datasource = onlineDatasourceService.getById(datasourceId); + if (datasource == null) { + errorMessage = "数据验证失败,数据源Id并不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + ResponseResult relationResult = + onlineOperationHelper.verifyAndGetOneToManyRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + return ResponseResult.errorFrom(relationResult); + } + OnlineTable slaveTable = relationResult.getData().getSlaveTable(); + ResponseResult> columnDataListResult = + onlineOperationHelper.buildTableData(slaveTable, slaveData, true, null); + if (!columnDataListResult.isSuccess()) { + return ResponseResult.errorFrom(columnDataListResult); + } + if (!onlineOperationService.update(slaveTable, columnDataListResult.getData())) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除主数据接口。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 主表数据源Id。 + * @param dataId 待删除的数据表主键Id。 + * @return 应该结果。 + */ + @PostMapping("/deleteDatasource/{datasourceVariableName}") + public ResponseResult deleteDatasource( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @MyRequestBody(required = true) Long datasourceId, + @MyRequestBody(required = true) String dataId) { + String errorMessage; + ResponseResult datasourceResult = + onlineOperationHelper.verifyAndGetDatasource(datasourceId); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + OnlineDatasource datasource = datasourceResult.getData(); + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + OnlineTable masterTable = datasource.getMasterTable(); + ResponseResult> relationListResult = + onlineOperationHelper.verifyAndGetRelationList(datasourceId, RelationType.ONE_TO_MANY); + if (!relationListResult.isSuccess()) { + return ResponseResult.errorFrom(relationListResult); + } + List relationList = relationListResult.getData(); + if (!onlineOperationService.delete(masterTable, relationList, dataId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 删除一对多关联表单条数据接口。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 主表数据源Id。 + * @param relationId 一对多关联Id。 + * @param dataId 一对多关联表主键Id。 + * @return 应该结果。 + */ + @PostMapping("/deleteOneToManyRelation/{datasourceVariableName}") + public ResponseResult deleteOneToManyRelation( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @MyRequestBody(required = true) Long datasourceId, + @MyRequestBody(required = true) Long relationId, + @MyRequestBody(required = true) String dataId) { + String errorMessage; + OnlineDatasource datasource = onlineDatasourceService.getById(datasourceId); + if (datasource == null) { + errorMessage = "数据验证失败,数据源Id并不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + ResponseResult relationResult = + onlineOperationHelper.verifyAndGetOneToManyRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + return ResponseResult.errorFrom(relationResult); + } + OnlineDatasourceRelation relation = relationResult.getData(); + if (!onlineOperationService.delete(relation.getSlaveTable(), null, dataId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + return ResponseResult.success(); + } + + /** + * 根据数据源Id为动态表单查询数据详情。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 数据源Id。 + * @param dataId 数据主键Id。 + * @return 详情结果。 + */ + @GetMapping("/viewByDatasourceId/{datasourceVariableName}") + public ResponseResult> viewByDatasourceId( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @RequestParam Long datasourceId, + @RequestParam String dataId) { + String errorMessage; + // 验证数据源及其关联 + ResponseResult datasourceResult = + onlineOperationHelper.verifyAndGetDatasource(datasourceId); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + OnlineDatasource datasource = datasourceResult.getData(); + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + OnlineTable masterTable = datasource.getMasterTable(); + ResponseResult> relationListResult = + onlineOperationHelper.verifyAndGetRelationList(datasourceId, null); + if (!relationListResult.isSuccess()) { + return ResponseResult.errorFrom(relationListResult); + } + List allRelationList = relationListResult.getData(); + List oneToOneRelationList = allRelationList.stream() + .filter(r -> r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList()); + Map result = + onlineOperationService.getMasterData(masterTable, oneToOneRelationList, allRelationList, dataId); + return ResponseResult.success(result); + } + + /** + * 根据数据源关联Id为动态表单查询数据详情。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 数据源Id。 + * @param relationId 一对多关联Id。 + * @param dataId 一对多关联数据主键Id。 + * @return 详情结果。 + */ + @GetMapping("/viewByOneToManyRelationId/{datasourceVariableName}") + public ResponseResult> viewByOneToManyRelationId( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @RequestParam Long datasourceId, + @RequestParam Long relationId, + @RequestParam String dataId) { + String errorMessage; + OnlineDatasource datasource = onlineDatasourceService.getById(datasourceId); + if (datasource == null) { + errorMessage = "数据验证失败,数据源Id并不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + ResponseResult relationResult = + onlineOperationHelper.verifyAndGetOneToManyRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + return ResponseResult.errorFrom(relationResult); + } + OnlineDatasourceRelation relation = relationResult.getData(); + Map result = onlineOperationService.getSlaveData(relation, dataId); + return ResponseResult.success(result); + } + + /** + * 为数据源主表字段下载文件。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 数据源Id。 + * @param dataId 附件所在记录的主键Id。 + * @param fieldName 数据表字段名。 + * @param asImage 是否为图片文件。 + * @param response Http 应答对象。 + */ + @GetMapping("/downloadDatasource/{datasourceVariableName}") + public void downloadDatasource( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @RequestParam Long datasourceId, + @RequestParam(required = false) String dataId, + @RequestParam String fieldName, + @RequestParam String filename, + @RequestParam Boolean asImage, + HttpServletResponse response) throws Exception { + if (MyCommonUtil.existBlankArgument(fieldName, filename, asImage)) { + response.setStatus(HttpServletResponse.SC_BAD_REQUEST); + return; + } + ResponseResult datasourceResult = + onlineOperationHelper.verifyAndGetDatasource(datasourceId); + if (!datasourceResult.isSuccess()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.errorFrom(datasourceResult)); + return; + } + OnlineDatasource datasource = datasourceResult.getData(); + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION)); + return; + } + OnlineTable masterTable = datasource.getMasterTable(); + onlineOperationHelper.doDownload(masterTable, dataId, fieldName, filename, asImage, response); + } + + /** + * 为数据源一对多关联的从表字段下载文件。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 数据源Id。 + * @param relationId 数据源的一对多关联Id。 + * @param dataId 附件所在记录的主键Id。 + * @param fieldName 数据表字段名。 + * @param asImage 是否为图片文件。 + * @param response Http 应答对象。 + */ + @GetMapping("/downloadOneToManyRelation/{datasourceVariableName}") + public void downloadOneToManyRelation( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @RequestParam Long datasourceId, + @RequestParam Long relationId, + @RequestParam(required = false) String dataId, + @RequestParam String fieldName, + @RequestParam String filename, + @RequestParam Boolean asImage, + HttpServletResponse response) throws Exception { + String errorMessage; + OnlineDatasource datasource = onlineDatasourceService.getById(datasourceId); + if (datasource == null) { + errorMessage = "数据验证失败,数据源Id并不存在!"; + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage)); + return; + } + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION)); + return; + } + ResponseResult relationResult = + onlineOperationHelper.verifyAndGetOneToManyRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.errorFrom(relationResult)); + return; + } + OnlineTable slaveTable = relationResult.getData().getSlaveTable(); + onlineOperationHelper.doDownload(slaveTable, dataId, fieldName, filename, asImage, response); + } + + /** + * 为数据源主表字段上传文件。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 数据源Id。 + * @param fieldName 数据表字段名。 + * @param asImage 是否为图片文件。 + * @param uploadFile 上传文件对象。 + */ + @PostMapping("/uploadDatasource/{datasourceVariableName}") + public void uploadDatasource( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @RequestParam Long datasourceId, + @RequestParam String fieldName, + @RequestParam Boolean asImage, + @RequestParam("uploadFile") MultipartFile uploadFile) throws Exception { + String errorMessage; + ResponseResult datasourceResult = + onlineOperationHelper.verifyAndGetDatasource(datasourceId); + if (!datasourceResult.isSuccess()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.errorFrom(datasourceResult)); + return; + } + OnlineDatasource datasource = datasourceResult.getData(); + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION)); + return; + } + OnlineTable masterTable = datasource.getMasterTable(); + onlineOperationHelper.doUpload(masterTable, fieldName, asImage, uploadFile); + } + + /** + * 为数据源一对多关联的从表字段上传文件。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 数据源Id。 + * @param relationId 数据源的一对多关联Id。 + * @param fieldName 数据表字段名。 + * @param asImage 是否为图片文件。 + * @param uploadFile 上传文件对象。 + */ + @PostMapping("/uploadOneToManyRelation/{datasourceVariableName}") + public void uploadOneToManyRelation( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @RequestParam Long datasourceId, + @RequestParam Long relationId, + @RequestParam String fieldName, + @RequestParam Boolean asImage, + @RequestParam("uploadFile") MultipartFile uploadFile) throws Exception { + String errorMessage; + OnlineDatasource datasource = onlineDatasourceService.getById(datasourceId); + if (datasource == null) { + errorMessage = "数据验证失败,数据源Id并不存在!"; + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage)); + return; + } + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION)); + return; + } + ResponseResult relationResult = + onlineOperationHelper.verifyAndGetOneToManyRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, ResponseResult.errorFrom(relationResult)); + return; + } + OnlineTable slaveTable = relationResult.getData().getSlaveTable(); + onlineOperationHelper.doUpload(slaveTable, fieldName, asImage, uploadFile); + } + + /** + * 根据数据源Id,以及接口参数,为动态表单查询数据列表。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 数据源Id。 + * @param filterDtoList 多虑数据对象列表。 + * @param orderParam 排序对象。 + * @param pageParam 分页对象。 + * @return 查询结果。 + */ + @PostMapping("/listByDatasourceId/{datasourceVariableName}") + public ResponseResult>> listByDatasourceId( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @MyRequestBody(required = true) Long datasourceId, + @MyRequestBody(elementType = OnlineFilterDto.class) List filterDtoList, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + String errorMessage; + // 1. 验证数据源及其关联 + ResponseResult datasourceResult = + onlineOperationHelper.verifyAndGetDatasource(datasourceId); + if (!datasourceResult.isSuccess()) { + return ResponseResult.errorFrom(datasourceResult); + } + OnlineDatasource datasource = datasourceResult.getData(); + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + OnlineTable masterTable = datasource.getMasterTable(); + ResponseResult> relationListResult = + onlineOperationHelper.verifyAndGetRelationList(datasourceId, null); + if (!relationListResult.isSuccess()) { + return ResponseResult.errorFrom(relationListResult); + } + List allRelationList = relationListResult.getData(); + // 2. 验证数据过滤对象中的表名和字段,确保没有sql注入。 + ResponseResult filterDtoListResult = this.verifyFilterDtoList(filterDtoList); + if (!filterDtoListResult.isSuccess()) { + return ResponseResult.errorFrom(filterDtoListResult); + } + // 3. 解析排序参数,同时确保没有sql注入。 + Map tableMap = new HashMap<>(4); + tableMap.put(masterTable.getTableName(), masterTable); + List oneToOneRelationList = relationListResult.getData().stream() + .filter(r -> r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList()); + if (CollUtil.isNotEmpty(oneToOneRelationList)) { + Map relationTableMap = oneToOneRelationList.stream() + .map(OnlineDatasourceRelation::getSlaveTable).collect(Collectors.toMap(OnlineTable::getTableName, c -> c)); + tableMap.putAll(relationTableMap); + } + ResponseResult orderByResult = this.makeOrderBy(orderParam, masterTable, tableMap); + if (!orderByResult.isSuccess()) { + return ResponseResult.errorFrom(orderByResult); + } + String orderBy = orderByResult.getData(); + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List> resultList = onlineOperationService.getMasterDataList( + masterTable, oneToOneRelationList, allRelationList, filterDtoList, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 根据数据源Id和数据源关联Id,以及接口参数,为动态表单查询该一对多关联的数据列表。 + * + * @param datasourceVariableName 数据源名称。 + * @param datasourceId 数据源Id。 + * @param relationId 数据源的一对多关联Id。 + * @param filterDtoList 多虑数据对象列表。 + * @param orderParam 排序对象。 + * @param pageParam 分页对象。 + * @return 查询结果。 + */ + @PostMapping("/listByOneToManyRelationId/{datasourceVariableName}") + public ResponseResult>> listByOneToManyRelationId( + @PathVariable("datasourceVariableName") String datasourceVariableName, + @MyRequestBody(required = true) Long datasourceId, + @MyRequestBody(required = true) Long relationId, + @MyRequestBody(elementType = OnlineFilterDto.class) List filterDtoList, + @MyRequestBody MyOrderParam orderParam, + @MyRequestBody MyPageParam pageParam) { + String errorMessage; + OnlineDatasource datasource = onlineDatasourceService.getById(datasourceId); + if (datasource == null) { + errorMessage = "数据验证失败,数据源Id并不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!datasource.getVariableName().equals(datasourceVariableName)) { + ContextUtil.getHttpResponse().setStatus(HttpServletResponse.SC_FORBIDDEN); + return ResponseResult.error(ErrorCodeEnum.NO_OPERATION_PERMISSION); + } + ResponseResult relationResult = + onlineOperationHelper.verifyAndGetOneToManyRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + return ResponseResult.errorFrom(relationResult); + } + OnlineDatasourceRelation relation = relationResult.getData(); + OnlineTable slaveTable = relation.getSlaveTable(); + // 验证数据过滤对象中的表名和字段,确保没有sql注入。 + ResponseResult filterDtoListResult = this.verifyFilterDtoList(filterDtoList); + if (!filterDtoListResult.isSuccess()) { + return ResponseResult.errorFrom(filterDtoListResult); + } + Map tableMap = new HashMap<>(1); + tableMap.put(slaveTable.getTableName(), slaveTable); + if (CollUtil.isNotEmpty(orderParam)) { + for (MyOrderParam.OrderInfo orderInfo : orderParam) { + orderInfo.setFieldName(StrUtil.removePrefix(orderInfo.getFieldName(), + relation.getVariableName() + OnlineConstant.RELATION_TABLE_COLUMN_SEPARATOR)); + } + } + ResponseResult orderByResult = this.makeOrderBy(orderParam, slaveTable, tableMap); + if (!orderByResult.isSuccess()) { + return ResponseResult.errorFrom(orderByResult); + } + String orderBy = orderByResult.getData(); + // 分页。 + if (pageParam != null) { + PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize()); + } + List> resultList = + onlineOperationService.getSlaveDataList(relation, filterDtoList, orderBy); + return ResponseResult.success(MyPageUtil.makeResponseData(resultList)); + } + + /** + * 查询字典数据,并以字典的约定方式,返回数据结果集。 + * + * @param dictId 字典Id。 + * @param filterDtoList 字典的过滤对象列表。 + * @return 字典数据列表。 + */ + @PostMapping("/listDict") + public ResponseResult>> listDict( + @MyRequestBody(required = true) Long dictId, + @MyRequestBody(elementType = OnlineFilterDto.class) List filterDtoList) { + String errorMessage; + OnlineDict dict = onlineDictService.getById(dictId); + if (dict == null) { + errorMessage = "数据验证失败,字典Id并不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!dict.getDictType().equals(DictType.TABLE)) { + errorMessage = "数据验证失败,该接口仅支持数据表字典!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (CollUtil.isNotEmpty(filterDtoList)) { + for (OnlineFilterDto filter : filterDtoList) { + if (!this.checkTableAndColumnName(filter.getColumnName())) { + errorMessage = "数据验证失败,过滤字段名 [" + + filter.getColumnName() + " ] 包含 (数字、字母和下划线) 之外的非法字符!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + } + List> resultList = onlineOperationService.getDictDataList(dict, filterDtoList); + return ResponseResult.success(resultList); + } + + private ResponseResult verifyFilterDtoList(List filterDtoList) { + if (CollUtil.isEmpty(filterDtoList)) { + return ResponseResult.success(); + } + String errorMessage; + for (OnlineFilterDto filter : filterDtoList) { + if (!this.checkTableAndColumnName(filter.getTableName())) { + errorMessage = "数据验证失败,过滤表名 [" + + filter.getColumnName() + " ] 包含 (数字、字母和下划线) 之外的非法字符!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + if (!this.checkTableAndColumnName(filter.getColumnName())) { + errorMessage = "数据验证失败,过滤字段名 [" + + filter.getColumnName() + " ] 包含 (数字、字母和下划线) 之外的非法字符!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + return ResponseResult.success(); + } + + private boolean checkTableAndColumnName(String name) { + if (StrUtil.isBlank(name)) { + return true; + } + for (int i = 0; i < name.length(); i++) { + char c = name.charAt(i); + if (!CharUtil.isLetterOrNumber(c) && !CharUtil.equals('_', c, false)) { + return false; + } + } + return true; + } + + private ResponseResult makeOrderBy( + MyOrderParam orderParam, OnlineTable masterTable, Map tableMap) { + if (CollUtil.isEmpty(orderParam)) { + return ResponseResult.success(null); + } + String errorMessage; + StringBuilder sb = new StringBuilder(128); + for (int i = 0; i < orderParam.size(); i++) { + MyOrderParam.OrderInfo orderInfo = orderParam.get(i); + boolean found = false; + String[] orderArray = StrUtil.splitToArray(orderInfo.getFieldName(), '.'); + // 如果没有前缀,我们就可以默认为主表的字段。 + if (orderArray.length == 1) { + for (OnlineColumn column : masterTable.getColumnMap().values()) { + if (column.getColumnName().equals(orderArray[0])) { + sb.append(masterTable.getTableName()).append(".").append(column.getColumnName()); + if (!orderInfo.getAsc()) { + sb.append(" DESC"); + } + if (i != orderParam.size() - 1) { + sb.append(", "); + } + found = true; + break; + } + } + if (!found) { + errorMessage = "数据验证失败,排序字段 [" + + orderInfo.getFieldName() + "] 在主表 [" + masterTable.getTableName() + "] 中并不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } else { + String tableName = orderArray[0]; + String columnName = orderArray[1]; + OnlineTable table = tableMap.get(tableName); + if (table == null) { + errorMessage = "数据验证失败,排序字段 [" + + orderInfo.getFieldName() + "] 的数据表 [" + tableName + "] 并不属于当前数据源!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + for (OnlineColumn column : table.getColumnMap().values()) { + if (column.getColumnName().equals(columnName)) { + sb.append(tableName).append(".").append(columnName); + if (!orderInfo.getAsc()) { + sb.append(" DESC"); + } + if (i != orderParam.size() - 1) { + sb.append(", "); + } + found = true; + break; + } + } + if (!found) { + errorMessage = "数据验证失败,排序字段 [" + + orderInfo.getFieldName() + "] 在数据表 [" + tableName + "] 中并不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + } + return ResponseResult.success(sb.toString()); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineColumnMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineColumnMapper.java new file mode 100644 index 00000000..60f7c604 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineColumnMapper.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineColumn; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 字段数据数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineColumnMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param onlineColumnFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlineColumnList( + @Param("onlineColumnFilter") OnlineColumn onlineColumnFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineColumnRuleMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineColumnRuleMapper.java new file mode 100644 index 00000000..f411c5a5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineColumnRuleMapper.java @@ -0,0 +1,25 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineColumnRule; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Set; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineColumnRuleMapper extends BaseDaoMapper { + + /** + * 获取指定字段Id关联的字段规则对象列表,同时还关联了每个OnlineRule对象。 + * + * @param columnIdSet 字段Id集合。 + * @return 关联的字段规则对象列表。 + */ + List getOnlineColumnRuleListByColumnIds(@Param("columnIdSet") Set columnIdSet); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceMapper.java new file mode 100644 index 00000000..5df3ad52 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceMapper.java @@ -0,0 +1,61 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineDatasource; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Set; + +/** + * 数据模型数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineDatasourceMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param onlineDatasourceFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlineDatasourceList( + @Param("onlineDatasourceFilter") OnlineDatasource onlineDatasourceFilter, @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表数据列表。 + * + * @param pageId 关联主表Id。 + * @param onlineDatasourceFilter 从表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 从表数据列表。 + */ + List getOnlineDatasourceListByPageId( + @Param("pageId") Long pageId, + @Param("onlineDatasourceFilter") OnlineDatasource onlineDatasourceFilter, + @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表中没有和主表建立关联关系的数据列表。 + * + * @param pageId 关联主表Id。 + * @param onlineDatasourceFilter 过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 与主表没有建立关联的从表数据列表。 + */ + List getNotInOnlineDatasourceListByPageId( + @Param("pageId") Long pageId, + @Param("onlineDatasourceFilter") OnlineDatasource onlineDatasourceFilter, + @Param("orderBy") String orderBy); + + /** + * 根据在线表单Id集合,获取关联的在线数据源对象列表。 + * + * @param formIdSet 在线表单Id集合。 + * @return 与参数表单Id关联的数据源列表。 + */ + List getOnlineDatasourceListByFormIds(@Param("formIdSet") Set formIdSet); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceRelationMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceRelationMapper.java new file mode 100644 index 00000000..a29cf4c1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceRelationMapper.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineDatasourceRelation; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 数据关联数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineDatasourceRelationMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlineDatasourceRelationList( + @Param("filter") OnlineDatasourceRelation filter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceTableMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceTableMapper.java new file mode 100644 index 00000000..5ff316d0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDatasourceTableMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineDatasourceTable; + +/** + * 数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineDatasourceTableMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDblinkMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDblinkMapper.java new file mode 100644 index 00000000..a63f8c30 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDblinkMapper.java @@ -0,0 +1,113 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineDblink; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.util.List; +import java.util.Map; + +/** + * 数据库链接数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineDblinkMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param onlineDblinkFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlineDblinkList( + @Param("onlineDblinkFilter") OnlineDblink onlineDblinkFilter, @Param("orderBy") String orderBy); + + /** + * 获取当前数据库链接下的所有用于动态表单的表。 + * + * @param prefix 动态表单所使用的表的前缀。如果为空,则返回所有数据表。 + * @return 所有用于动态表单的表。 + */ + @Select("") + List> getTableListWithPrefix(@Param("prefix") String prefix); + + /** + * 获取当前数据库链接下指定数据库表的数据。 + * + * @param tableName 数据库表名。 + * @return 表数据。 + */ + @Select("SELECT \n" + + " table_name tableName, \n" + + " table_comment tableComment, \n" + + " create_time createTime \n" + + "FROM \n" + + " information_schema.tables \n" + + "WHERE table_schema = (SELECT database()) AND table_name = #{tableName}") + Map getTableByName(@Param("tableName") String tableName); + + /** + * 获取指定表的字段列表。 + * + * @param tableName 指定的表名。 + * @return 指定表的字段列表。 + */ + @Select("SELECT \n" + + " column_name columnName, \n" + + " data_type columnType, \n" + + " column_type fullColumnType, \n" + + " column_comment columnComment, \n" + + " CASE WHEN column_key = 'PRI' THEN 1 ELSE 0 END AS primaryKey, \n" + + " is_nullable nullable, \n" + + " ordinal_position columnShowOrder, \n" + + " extra, \n" + + " CHARACTER_MAXIMUM_LENGTH stringPrecision, \n" + + " numeric_precision numericPrecision, \n" + + " COLUMN_DEFAULT columnDefault \n" + + "FROM information_schema.columns \n" + + "WHERE table_name = #{tableName} \n" + + " AND table_schema = (SELECT database()) ORDER BY ordinal_position") + List> getTableColumnList(@Param("tableName") String tableName); + + /** + * 获取指定表的字段对象。 + * + * @param tableName 指定的表名。 + * @param columnName 指定的字段名。 + * @return 指定表的字段。 + */ + @Select("SELECT \n" + + " column_name columnName, \n" + + " data_type columnType, \n" + + " column_type fullColumnType, \n" + + " column_comment columnComment, \n" + + " CASE WHEN column_key = 'PRI' THEN 1 ELSE 0 END AS primaryKey, \n" + + " is_nullable nullable, \n" + + " ordinal_position columnShowOrder, \n" + + " extra, \n" + + " CHARACTER_MAXIMUM_LENGTH stringPrecision, \n" + + " numeric_precision numericPrecision, \n" + + " COLUMN_DEFAULT columnDefault \n" + + "FROM information_schema.columns \n" + + "WHERE table_name = #{tableName} \n" + + " AND column_name = #{columnName} \n" + + " AND table_schema = (SELECT database()) ORDER BY ordinal_position") + Map getTableColumnByName( + @Param("tableName") String tableName, @Param("columnName") String columnName); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDictMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDictMapper.java new file mode 100644 index 00000000..96699b58 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineDictMapper.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineDict; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 在线表单字典数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineDictMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param onlineDictFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlineDictList( + @Param("onlineDictFilter") OnlineDict onlineDictFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineFormDatasourceMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineFormDatasourceMapper.java new file mode 100644 index 00000000..c4511783 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineFormDatasourceMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineFormDatasource; + +/** + * 在线表单与数据源多对多关联的数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineFormDatasourceMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineFormMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineFormMapper.java new file mode 100644 index 00000000..d1ee9853 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineFormMapper.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineForm; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 在线表单数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineFormMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param onlineFormFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlineFormList( + @Param("onlineFormFilter") OnlineForm onlineFormFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineOperationMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineOperationMapper.java new file mode 100644 index 00000000..429832cc --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineOperationMapper.java @@ -0,0 +1,228 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.online.dto.OnlineFilterDto; +import com.flow.demo.common.online.object.ColumnData; +import com.flow.demo.common.online.object.JoinTableInfo; +import org.apache.ibatis.annotations.*; + +import java.util.List; +import java.util.Map; + +/** + * 在线表单运行时数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Mapper +public interface OnlineOperationMapper { + + /** + * 插入新数据。 + * + * @param tableName 数据表名。 + * @param columnNames 字段名列表。 + * @param columnValueList 字段值列表。 + */ + @Insert("") + void insert( + @Param("tableName") String tableName, + @Param("columnNames") String columnNames, + @Param("columnValueList") List columnValueList); + + /** + * 更新表数据。 + * + * @param tableName 数据表名。 + * @param updateColumnList 更新字段列表。 + * @param whereColumnList 过滤字段列表。 + * @param dataPermFilter 数据权限过滤字符串。 + * @return 更新行数。 + */ + @Update("") + int update( + @Param("tableName") String tableName, + @Param("updateColumnList") List updateColumnList, + @Param("whereColumnList") List whereColumnList, + @Param("dataPermFilter") String dataPermFilter); + + /** + * 删除指定数据。 + * + * @param tableName 表名。 + * @param filterList SQL过滤条件列表。 + * @param dataPermFilter 数据权限过滤字符串。 + * @return 删除行数。 + */ + @Delete("") + int delete( + @Param("tableName") String tableName, + @Param("filterList") List filterList, + @Param("dataPermFilter") String dataPermFilter); + + /** + * 执行动态查询,并返回查询结果集。 + * + * @param masterTableName 主表名称。 + * @param joinInfoList 关联表信息列表。 + * @param selectFields 返回字段列表,逗号分隔。 + * @param filterList SQL过滤条件列表。 + * @param dataPermFilter 数据权限过滤字符串。 + * @param orderBy 排序字符串。 + * @return 查询结果集。 + */ + @Select("") + List> getList( + @Param("masterTableName") String masterTableName, + @Param("joinInfoList") List joinInfoList, + @Param("selectFields") String selectFields, + @Param("filterList") List filterList, + @Param("dataPermFilter") String dataPermFilter, + @Param("orderBy") String orderBy); + + /** + * 以字典键值对的方式返回数据。 + * + * @param tableName 表名称。 + * @param selectFields 返回字段列表,逗号分隔。 + * @param filterList SQL过滤条件列表。 + * @param dataPermFilter 数据权限过滤字符串。 + * @return 查询结果集。 + */ + @Select("") + List> getDictList( + @Param("tableName") String tableName, + @Param("selectFields") String selectFields, + @Param("filterList") List filterList, + @Param("dataPermFilter") String dataPermFilter); + + /** + * 根据指定的表名、显示字段列表、过滤条件字符串和分组字段,返回聚合计算后的查询结果。 + * + * @param selectTable 表名称。 + * @param selectFields 返回字段列表,逗号分隔。 + * @param whereClause SQL常量形式的条件从句。 + * @param groupBy 分组字段列表,逗号分隔。 + * @return 对象可选字段Map列表。 + */ + @Select("") + List> getGroupedListByCondition( + @Param("selectTable") String selectTable, + @Param("selectFields") String selectFields, + @Param("whereClause") String whereClause, + @Param("groupBy") String groupBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlinePageDatasourceMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlinePageDatasourceMapper.java new file mode 100644 index 00000000..44a337dd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlinePageDatasourceMapper.java @@ -0,0 +1,13 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlinePageDatasource; + +/** + * 在线表单页面和数据源关联对象的数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlinePageDatasourceMapper extends BaseDaoMapper { +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlinePageMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlinePageMapper.java new file mode 100644 index 00000000..720ce089 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlinePageMapper.java @@ -0,0 +1,35 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlinePage; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 在线表单页面数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlinePageMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param onlinePageFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlinePageList( + @Param("onlinePageFilter") OnlinePage onlinePageFilter, @Param("orderBy") String orderBy); + + /** + /** + * 根据数据源Id,返回使用该数据源的OnlinePage对象。 + * + * @param datasourceId 数据源Id。 + * @return 使用该数据源的页面列表。 + */ + List getOnlinePageListByDatasourceId(@Param("datasourceId") Long datasourceId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineRuleMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineRuleMapper.java new file mode 100644 index 00000000..b49a07c2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineRuleMapper.java @@ -0,0 +1,52 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineRule; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 验证规则数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineRuleMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param onlineRuleFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlineRuleList( + @Param("onlineRuleFilter") OnlineRule onlineRuleFilter, @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表数据列表。 + * + * @param columnId 关联主表Id。 + * @param onlineRuleFilter 从表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 从表数据列表。 + */ + List getOnlineRuleListByColumnId( + @Param("columnId") Long columnId, + @Param("onlineRuleFilter") OnlineRule onlineRuleFilter, + @Param("orderBy") String orderBy); + + /** + * 根据关联主表Id,获取关联从表中没有和主表建立关联关系的数据列表。 + * + * @param columnId 关联主表Id。 + * @param onlineRuleFilter 过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 与主表没有建立关联的从表数据列表。 + */ + List getNotInOnlineRuleListByColumnId( + @Param("columnId") Long columnId, + @Param("onlineRuleFilter") OnlineRule onlineRuleFilter, + @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineTableMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineTableMapper.java new file mode 100644 index 00000000..de884fe2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineTableMapper.java @@ -0,0 +1,34 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineTable; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 数据表数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineTableMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param onlineTableFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlineTableList( + @Param("onlineTableFilter") OnlineTable onlineTableFilter, @Param("orderBy") String orderBy); + + /** + * 根据数据源Id,获取该数据源及其关联所引用的数据表列表。 + * + * @param datasourceId 指定的数据源Id。 + * @return 该数据源及其关联所引用的数据表列表。 + */ + List getOnlineTableListByDatasourceId(@Param("datasourceId") Long datasourceId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineVirtualColumnMapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineVirtualColumnMapper.java new file mode 100644 index 00000000..9df5f715 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/OnlineVirtualColumnMapper.java @@ -0,0 +1,26 @@ +package com.flow.demo.common.online.dao; + +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.online.model.OnlineVirtualColumn; +import org.apache.ibatis.annotations.Param; + +import java.util.*; + +/** + * 虚拟字段数据操作访问接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineVirtualColumnMapper extends BaseDaoMapper { + + /** + * 获取过滤后的对象列表。 + * + * @param onlineVirtualColumnFilter 主表过滤对象。 + * @param orderBy 排序字符串,order by从句的参数。 + * @return 对象列表。 + */ + List getOnlineVirtualColumnList( + @Param("onlineVirtualColumnFilter") OnlineVirtualColumn onlineVirtualColumnFilter, @Param("orderBy") String orderBy); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineColumnMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineColumnMapper.xml new file mode 100644 index 00000000..f225b2f2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineColumnMapper.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_online_column.table_id = #{onlineColumnFilter.tableId} + + + AND zz_online_column.column_name = #{onlineColumnFilter.columnName} + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineColumnRuleMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineColumnRuleMapper.xml new file mode 100644 index 00000000..c148f826 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineColumnRuleMapper.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceMapper.xml new file mode 100644 index 00000000..a0cae58a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceMapper.xml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_online_datasource.datasource_name = #{onlineDatasourceFilter.datasourceName} + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceRelationMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceRelationMapper.xml new file mode 100644 index 00000000..db15bdea --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceRelationMapper.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_online_datasource_relation.relation_name = #{filter.relationName} + + + AND zz_online_datasource_relation.datasource_id = #{filter.datasourceId} + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceTableMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceTableMapper.xml new file mode 100644 index 00000000..950cd44d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDatasourceTableMapper.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDblinkMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDblinkMapper.xml new file mode 100644 index 00000000..934d9c55 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDblinkMapper.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDictMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDictMapper.xml new file mode 100644 index 00000000..4edf13c3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineDictMapper.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_online_dict.dict_name = #{onlineDictFilter.dictName} + + + AND zz_online_dict.dict_type = #{onlineDictFilter.dictType} + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineFormDatasourceMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineFormDatasourceMapper.xml new file mode 100644 index 00000000..238817c1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineFormDatasourceMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineFormMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineFormMapper.xml new file mode 100644 index 00000000..1b149915 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineFormMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_online_form.page_id = #{onlineFormFilter.pageId} + + + AND zz_online_form.form_code = #{onlineFormFilter.formCode} + + + AND zz_online_form.form_name = #{onlineFormFilter.formName} + + + AND zz_online_form.form_type = #{onlineFormFilter.formType} + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlinePageDatasourceMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlinePageDatasourceMapper.xml new file mode 100644 index 00000000..717508a7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlinePageDatasourceMapper.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlinePageMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlinePageMapper.xml new file mode 100644 index 00000000..b1544811 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlinePageMapper.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_online_page.page_code = #{onlinePageFilter.pageCode} + + + AND zz_online_page.page_name = #{onlinePageFilter.pageName} + + + AND zz_online_page.page_type = #{onlinePageFilter.pageType} + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineRuleMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineRuleMapper.xml new file mode 100644 index 00000000..c4e90699 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineRuleMapper.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + AND zz_online_rule.deleted_flag = ${@com.flow.demo.common.core.constant.GlobalDeletedFlag@NORMAL} + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineTableMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineTableMapper.xml new file mode 100644 index 00000000..d940a3d3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineTableMapper.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + AND zz_online_table.table_name = #{onlineTableFilter.tableName} + + + AND zz_online_table.model_name = #{onlineTableFilter.modelName} + + + AND zz_online_table.dblink_id = #{onlineTableFilter.dblinkId} + + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineVirtualColumnMapper.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineVirtualColumnMapper.xml new file mode 100644 index 00000000..7a5ca29c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dao/mapper/OnlineVirtualColumnMapper.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + AND zz_online_virtual_column.datasource_id = #{onlineVirtualColumnFilter.datasourceId} + + + AND zz_online_virtual_column.relation_id = #{onlineVirtualColumnFilter.relationId} + + + AND zz_online_virtual_column.table_id = #{onlineVirtualColumnFilter.tableId} + + + AND zz_online_virtual_column.aggregation_column_id = #{onlineVirtualColumnFilter.aggregationColumnId} + + + AND zz_online_virtual_column.virtual_type = #{onlineVirtualColumnFilter.virtualType} + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineColumnDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineColumnDto.java new file mode 100644 index 00000000..50f33bf5 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineColumnDto.java @@ -0,0 +1,137 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.model.constant.FieldFilterType; +import com.flow.demo.common.online.model.constant.FieldKind; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 在线表单数据表字段Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineColumnDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long columnId; + + /** + * 字段名。 + */ + @NotBlank(message = "数据验证失败,字段名不能为空!") + private String columnName; + + /** + * 数据表Id。 + */ + @NotNull(message = "数据验证失败,数据表Id不能为空!") + private Long tableId; + + /** + * 数据表中的字段类型。 + */ + @NotBlank(message = "数据验证失败,数据表中的字段类型不能为空!") + private String columnType; + + /** + * 数据表中的完整字段类型(包括了精度和刻度)。 + */ + @NotBlank(message = "数据验证失败,数据表中的完整字段类型(包括了精度和刻度)不能为空!") + private String fullColumnType; + + /** + * 是否为主键。 + */ + @NotNull(message = "数据验证失败,是否为主键不能为空!") + private Boolean primaryKey; + + /** + * 是否是自增主键(0: 不是 1: 是)。 + */ + @NotNull(message = "数据验证失败,是否是自增主键(0: 不是 1: 是)不能为空!") + private Boolean autoIncrement; + + /** + * 是否可以为空 (0: 不可以为空 1: 可以为空)。 + */ + @NotNull(message = "数据验证失败,是否可以为空 (0: 不可以为空 1: 可以为空)不能为空!") + private Boolean nullable; + + /** + * 缺省值。 + */ + private String columnDefault; + + /** + * 字段在数据表中的显示位置。 + */ + @NotNull(message = "数据验证失败,字段在数据表中的显示位置不能为空!") + private Integer columnShowOrder; + + /** + * 数据表中的字段注释。 + */ + private String columnComment; + + /** + * 对象映射字段名称。 + */ + @NotBlank(message = "数据验证失败,对象映射字段名称不能为空!") + private String objectFieldName; + + /** + * 对象映射字段类型。 + */ + @NotBlank(message = "数据验证失败,对象映射字段类型不能为空!") + private String objectFieldType; + + /** + * 过滤类型字段。 + */ + @NotNull(message = "数据验证失败,过滤类型字段不能为空!", groups = {UpdateGroup.class}) + @ConstDictRef(constDictClass = FieldFilterType.class, message = "数据验证失败,过滤类型字段为无效值!") + private Integer filterType; + + /** + * 是否是主键的父Id。 + */ + @NotNull(message = "数据验证失败,是否是主键的父Id不能为空!") + private Boolean parentKey; + + /** + * 是否部门过滤字段。 + */ + @NotNull(message = "数据验证失败,是否部门过滤字段标记不能为空!") + private Boolean deptFilter; + + /** + * 是否用户过滤字段。 + */ + @NotNull(message = "数据验证失败,是否用户过滤字段标记不能为空!") + private Boolean userFilter; + + /** + * 字段类别。 + */ + @ConstDictRef(constDictClass = FieldKind.class, message = "数据验证失败,字段类别为无效值!") + private Integer fieldKind; + + /** + * 包含的文件文件数量,0表示无限制。 + */ + private Integer maxFileCount; + + /** + * 字典Id。 + */ + private Long dictId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineColumnRuleDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineColumnRuleDto.java new file mode 100644 index 00000000..c31e2fc1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineColumnRuleDto.java @@ -0,0 +1,33 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 在线表单数据表字段规则和字段多对多关联Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineColumnRuleDto { + + /** + * 字段Id。 + */ + @NotNull(message = "数据验证失败,字段Id不能为空!", groups = {UpdateGroup.class}) + private Long columnId; + + /** + * 规则Id。 + */ + @NotNull(message = "数据验证失败,规则Id不能为空!", groups = {UpdateGroup.class}) + private Long ruleId; + + /** + * 规则属性数据。 + */ + private String propDataJson; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDatasourceDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDatasourceDto.java new file mode 100644 index 00000000..33ad6147 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDatasourceDto.java @@ -0,0 +1,54 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.AddGroup; +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 在线表单的数据源Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineDatasourceDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long datasourceId; + + /** + * 数据源名称。 + */ + @NotBlank(message = "数据验证失败,数据源名称不能为空!") + private String datasourceName; + + /** + * 数据源变量名,会成为数据访问url的一部分。 + */ + @NotBlank(message = "数据验证失败,数据源变量名不能为空!") + private String variableName; + + /** + * 主表所在的数据库链接Id。 + */ + @NotNull(message = "数据验证失败,数据库链接Id不能为空!") + private Long dblinkId; + + /** + * 主表Id。 + */ + @NotNull(message = "数据验证失败,主表Id不能为空!", groups = {UpdateGroup.class}) + private Long masterTableId; + + /** + * 主表表名。 + */ + @NotBlank(message = "数据验证失败,主表名不能为空!", groups = {AddGroup.class}) + private String masterTableName; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDatasourceRelationDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDatasourceRelationDto.java new file mode 100644 index 00000000..67ed71df --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDatasourceRelationDto.java @@ -0,0 +1,93 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.AddGroup; +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.model.constant.RelationType; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 在线表单的数据源关联Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineDatasourceRelationDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long relationId; + + /** + * 关联名称。 + */ + @NotBlank(message = "数据验证失败,关联名称不能为空!") + private String relationName; + + /** + * 变量名。 + */ + @NotBlank(message = "数据验证失败,变量名不能为空!") + private String variableName; + + /** + * 主数据源Id。 + */ + @NotNull(message = "数据验证失败,主数据源Id不能为空!") + private Long datasourceId; + + /** + * 关联类型。 + */ + @NotNull(message = "数据验证失败,关联类型不能为空!") + @ConstDictRef(constDictClass = RelationType.class, message = "数据验证失败,关联类型为无效值!") + private Integer relationType; + + /** + * 主表关联字段Id。 + */ + @NotNull(message = "数据验证失败,主表关联字段Id不能为空!") + private Long masterColumnId; + + /** + * 从表Id。 + */ + @NotNull(message = "数据验证失败,从表Id不能为空!", groups = {UpdateGroup.class}) + private Long slaveTableId; + + /** + * 从表名。 + */ + @NotBlank(message = "数据验证失败,从表名不能为空!", groups = {AddGroup.class}) + private String slaveTableName; + + /** + * 从表关联字段Id。 + */ + @NotNull(message = "数据验证失败,从表关联字段Id不能为空!", groups = {UpdateGroup.class}) + private Long slaveColumnId; + + /** + * 从表字段名。 + */ + @NotBlank(message = "数据验证失败,从表字段名不能为空!", groups = {AddGroup.class}) + private String slaveColumnName; + + /** + * 是否级联删除标记。 + */ + @NotNull(message = "数据验证失败,是否级联删除标记不能为空!") + private Boolean cascadeDelete; + + /** + * 是否左连接标记。 + */ + @NotNull(message = "数据验证失败,是否左连接标记不能为空!") + private Boolean leftJoin; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDblinkDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDblinkDto.java new file mode 100644 index 00000000..51ef2337 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDblinkDto.java @@ -0,0 +1,46 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 在线表单数据表所在数据库链接Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineDblinkDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long dblinkId; + + /** + * 链接中文名称。 + */ + @NotBlank(message = "数据验证失败,链接中文名称不能为空!") + private String dblinkName; + + /** + * 链接英文名称。 + */ + @NotBlank(message = "数据验证失败,链接英文名称不能为空!") + private String variableName; + + /** + * 链接描述。 + */ + private String dblinkDesc; + + /** + * 数据源配置常量。 + */ + @NotNull(message = "数据验证失败,数据源配置常量不能为空!") + private Integer dblinkConfigConstant; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDictDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDictDto.java new file mode 100644 index 00000000..af259020 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineDictDto.java @@ -0,0 +1,104 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.model.constant.DictType; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 在线表单关联的字典Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineDictDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long dictId; + + /** + * 字典名称。 + */ + @NotBlank(message = "数据验证失败,字典名称不能为空!") + private String dictName; + + /** + * 字典类型。 + */ + @NotNull(message = "数据验证失败,字典类型不能为空!") + @ConstDictRef(constDictClass = DictType.class, message = "数据验证失败,字典类型为无效值!") + private Integer dictType; + + /** + * 数据库链接Id。 + */ + private Long dblinkId; + + /** + * 字典表名称。 + */ + private String tableName; + + /** + * 字典表键字段名称。 + */ + private String keyColumnName; + + /** + * 字典表父键字段名称。 + */ + private String parentKeyColumnName; + + /** + * 字典值字段名称。 + */ + private String valueColumnName; + + /** + * 逻辑删除字段。 + */ + private String deletedColumnName; + + /** + * 用户过滤滤字段名称。 + */ + private String userFilterColumnName; + + /** + * 部门过滤字段名称。 + */ + private String deptFilterColumnName; + + /** + * 租户过滤字段名称。 + */ + private String tenantFilterColumnName; + + /** + * 是否树形标记。 + */ + @NotNull(message = "数据验证失败,是否树形标记不能为空!") + private Boolean treeFlag; + + /** + * 获取字典数据的url。 + */ + private String dictListUrl; + + /** + * 根据主键id批量获取字典数据的url。 + */ + private String dictIdsUrl; + + /** + * 字典的JSON数据。 + */ + private String dictDataJson; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineFilterDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineFilterDto.java new file mode 100644 index 00000000..cd141aab --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineFilterDto.java @@ -0,0 +1,51 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.online.model.constant.FieldFilterType; +import lombok.Data; + +import java.util.Set; + +/** + * 在线表单数据过滤参数对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineFilterDto { + + /** + * 表名。 + */ + private String tableName; + + /** + * 过滤字段名。 + */ + private String columnName; + + /** + * 过滤值。 + */ + private Object columnValue; + + /** + * 范围比较的最小值。 + */ + private Object columnValueStart; + + /** + * 范围比较的最大值。 + */ + private Object columnValueEnd; + + /** + * 仅当操作符为IN的时候使用。 + */ + private Set columnValueList; + + /** + * 过滤类型,参考FieldFilterType常量对象。缺省值就是等于过滤了。 + */ + private Integer filterType = FieldFilterType.EQUAL_FILTER; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineFormDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineFormDto.java new file mode 100644 index 00000000..ee1e07d2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineFormDto.java @@ -0,0 +1,79 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.model.constant.FormKind; +import com.flow.demo.common.online.model.constant.FormType; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 在线表单Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineFormDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long formId; + + /** + * 页面id。 + */ + @NotNull(message = "数据验证失败,页面id不能为空!") + private Long pageId; + + /** + * 表单编码。 + */ + private String formCode; + + /** + * 表单名称。 + */ + @NotBlank(message = "数据验证失败,表单名称不能为空!") + private String formName; + + /** + * 表单类别。 + */ + @NotNull(message = "数据验证失败,表单类别不能为空!") + @ConstDictRef(constDictClass = FormKind.class, message = "数据验证失败,表单类别为无效值!") + private Integer formKind; + + /** + * 表单类型。 + */ + @NotNull(message = "数据验证失败,表单类型不能为空!") + @ConstDictRef(constDictClass = FormType.class, message = "数据验证失败,表单类型为无效值!") + private Integer formType; + + /** + * 表单主表id。 + */ + @NotNull(message = "数据验证失败,表单主表id不能为空!") + private Long masterTableId; + + /** + * 当前表单关联的数据源Id集合。 + */ + private List datasourceIdList; + + /** + * 表单组件JSON。 + */ + private String widgetJson; + + /** + * 表单参数JSON。 + */ + private String paramsJson; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlinePageDatasourceDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlinePageDatasourceDto.java new file mode 100644 index 00000000..1a134ef7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlinePageDatasourceDto.java @@ -0,0 +1,34 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 在线表单页面和数据源多对多关联Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlinePageDatasourceDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long id; + + /** + * 页面主键Id。 + */ + @NotNull(message = "数据验证失败,页面主键Id不能为空!") + private Long pageId; + + /** + * 数据源主键Id。 + */ + @NotNull(message = "数据验证失败,数据源主键Id不能为空!") + private Long datasourceId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlinePageDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlinePageDto.java new file mode 100644 index 00000000..c7af4bf1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlinePageDto.java @@ -0,0 +1,51 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.model.constant.PageStatus; +import com.flow.demo.common.online.model.constant.PageType; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 在线表单所在页面Dto对象。这里我们可以把页面理解为表单的容器。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlinePageDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long pageId; + + /** + * 页面编码。 + */ + private String pageCode; + + /** + * 页面名称。 + */ + @NotBlank(message = "数据验证失败,页面名称不能为空!") + private String pageName; + + /** + * 页面类型。 + */ + @NotNull(message = "数据验证失败,页面类型不能为空!") + @ConstDictRef(constDictClass = PageType.class, message = "数据验证失败,页面类型为无效值!") + private Integer pageType; + + /** + * 页面编辑状态。 + */ + @NotNull(message = "数据验证失败,状态不能为空!") + @ConstDictRef(constDictClass = PageStatus.class, message = "数据验证失败,状态为无效值!") + private Integer status; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineRuleDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineRuleDto.java new file mode 100644 index 00000000..630a8148 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineRuleDto.java @@ -0,0 +1,49 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; +import com.flow.demo.common.online.model.constant.RuleType; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 在线表单数据表字段验证规则Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineRuleDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long ruleId; + + /** + * 规则名称。 + */ + @NotBlank(message = "数据验证失败,规则名称不能为空!") + private String ruleName; + + /** + * 规则类型。 + */ + @NotNull(message = "数据验证失败,规则类型不能为空!") + @ConstDictRef(constDictClass = RuleType.class, message = "数据验证失败,规则类型为无效值!") + private Integer ruleType; + + /** + * 内置规则标记。 + */ + @NotNull(message = "数据验证失败,内置规则标记不能为空!") + private Boolean builtin; + + /** + * 自定义规则的正则表达式。 + */ + private String pattern; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineTableDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineTableDto.java new file mode 100644 index 00000000..0a7fc0fb --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineTableDto.java @@ -0,0 +1,41 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.validator.UpdateGroup; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 在线表单的数据表Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineTableDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long tableId; + + /** + * 表名称。 + */ + @NotBlank(message = "数据验证失败,表名称不能为空!") + private String tableName; + + /** + * 实体名称。 + */ + @NotBlank(message = "数据验证失败,实体名称不能为空!") + private String modelName; + + /** + * 数据库链接Id。 + */ + @NotNull(message = "数据验证失败,数据库链接Id不能为空!") + private Long dblinkId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineVirtualColumnDto.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineVirtualColumnDto.java new file mode 100644 index 00000000..fe4545fa --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/dto/OnlineVirtualColumnDto.java @@ -0,0 +1,88 @@ +package com.flow.demo.common.online.dto; + +import com.flow.demo.common.core.constant.AggregationType; +import com.flow.demo.common.core.validator.ConstDictRef; +import com.flow.demo.common.core.validator.UpdateGroup; + +import com.flow.demo.common.online.model.constant.VirtualType; +import lombok.Data; + +import javax.validation.constraints.*; + +/** + * 在线数据表虚拟字段Dto对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineVirtualColumnDto { + + /** + * 主键Id。 + */ + @NotNull(message = "数据验证失败,主键Id不能为空!", groups = {UpdateGroup.class}) + private Long virtualColumnId; + + /** + * 所在表Id。 + */ + private Long tableId; + + /** + * 字段名称。 + */ + @NotBlank(message = "数据验证失败,字段名称不能为空!") + private String objectFieldName; + + /** + * 属性类型。 + */ + @NotBlank(message = "数据验证失败,属性类型不能为空!") + private String objectFieldType; + + /** + * 字段提示名。 + */ + @NotBlank(message = "数据验证失败,字段提示名不能为空!") + private String columnPrompt; + + /** + * 虚拟字段类型(0: 聚合)。 + */ + @ConstDictRef(constDictClass = VirtualType.class, message = "数据验证失败,虚拟字段类型为无效值!") + @NotNull(message = "数据验证失败,虚拟字段类型(0: 聚合)不能为空!") + private Integer virtualType; + + /** + * 关联数据源Id。 + */ + @NotNull(message = "数据验证失败,关联数据源Id不能为空!") + private Long datasourceId; + + /** + * 关联Id。 + */ + private Long relationId; + + /** + * 聚合字段所在关联表Id。 + */ + private Long aggregationTableId; + + /** + * 关联表聚合字段Id。 + */ + private Long aggregationColumnId; + + /** + * 聚合类型(0: sum 1: count 2: avg 3: min 4: max)。 + */ + @ConstDictRef(constDictClass = AggregationType.class, message = "数据验证失败,虚拟字段聚合计算类型为无效值!") + private Integer aggregationType; + + /** + * 存储过滤条件的json。 + */ + private String whereClauseJson; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineColumn.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineColumn.java new file mode 100644 index 00000000..9302e50f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineColumn.java @@ -0,0 +1,196 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationConstDict; +import com.flow.demo.common.core.annotation.RelationOneToOne; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.model.constant.FieldKind; +import com.flow.demo.common.online.vo.OnlineColumnVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单数据表字段实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_column") +public class OnlineColumn { + + /** + * 主键Id。 + */ + @TableId(value = "column_id") + private Long columnId; + + /** + * 字段名。 + */ + @TableField(value = "column_name") + private String columnName; + + /** + * 数据表Id。 + */ + @TableField(value = "table_id") + private Long tableId; + + /** + * 数据表中的字段类型。 + */ + @TableField(value = "column_type") + private String columnType; + + /** + * 数据表中的完整字段类型(包括了精度和刻度)。 + */ + @TableField(value = "full_column_type") + private String fullColumnType; + + /** + * 是否为主键。 + */ + @TableField(value = "primary_key") + private Boolean primaryKey; + + /** + * 是否是自增主键(0: 不是 1: 是)。 + */ + @TableField(value = "auto_increment") + private Boolean autoIncrement; + + /** + * 是否可以为空 (0: 不可以为空 1: 可以为空)。 + */ + @TableField(value = "nullable") + private Boolean nullable; + + /** + * 缺省值。 + */ + @TableField(value = "column_default") + private String columnDefault; + + /** + * 字段在数据表中的显示位置。 + */ + @TableField(value = "column_show_order") + private Integer columnShowOrder; + + /** + * 数据表中的字段注释。 + */ + @TableField(value = "column_comment") + private String columnComment; + + /** + * 对象映射字段名称。 + */ + @TableField(value = "object_field_name") + private String objectFieldName; + + /** + * 对象映射字段类型。 + */ + @TableField(value = "object_field_type") + private String objectFieldType; + + /** + * 过滤字段类型。 + */ + @TableField(value = "filter_type") + private Integer filterType; + + /** + * 是否是主键的父Id。 + */ + @TableField(value = "parent_key") + private Boolean parentKey; + + /** + * 是否部门过滤字段。 + */ + @TableField(value = "dept_filter") + private Boolean deptFilter; + + /** + * 是否用户过滤字段。 + */ + @TableField(value = "user_filter") + private Boolean userFilter; + + /** + * 字段类别。 + */ + @TableField(value = "field_kind") + private Integer fieldKind; + + /** + * 包含的文件文件数量,0表示无限制。 + */ + @TableField(value = "max_file_count") + private Integer maxFileCount; + + /** + * 字典Id。 + */ + @TableField(value = "dict_id") + private Long dictId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + @RelationConstDict( + masterIdField = "fieldKind", + constantDictClass = FieldKind.class) + @TableField(exist = false) + private Map fieldKindDictMap; + + @RelationOneToOne( + masterIdField = "dictId", + slaveServiceName = "OnlineDictService", + slaveIdField = "dictId", + slaveModelClass = OnlineDict.class, + loadSlaveDict = false) + @TableField(exist = false) + private OnlineDict dictInfo; + + @Mapper + public interface OnlineColumnModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param onlineColumnVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "dictInfo", expression = "java(mapToBean(onlineColumnVo.getDictInfo(), com.flow.demo.common.online.model.OnlineDict.class))") + @Override + OnlineColumn toModel(OnlineColumnVo onlineColumnVo); + /** + * 转换实体对象到VO对象。 + * + * @param onlineColumn 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "dictInfo", expression = "java(beanToMap(onlineColumn.getDictInfo(), false))") + @Override + OnlineColumnVo fromModel(OnlineColumn onlineColumn); + } + public static final OnlineColumnModelMapper INSTANCE = Mappers.getMapper(OnlineColumnModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineColumnRule.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineColumnRule.java new file mode 100644 index 00000000..53de264b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineColumnRule.java @@ -0,0 +1,36 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 在线表单数据表字段规则和字段多对多关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_column_rule") +public class OnlineColumnRule { + + /** + * 字段Id。 + */ + @TableField(value = "column_id") + private Long columnId; + + /** + * 规则Id。 + */ + @TableField(value = "rule_id") + private Long ruleId; + + /** + * 规则属性数据。 + */ + @TableField(value = "prop_data_json") + private String propDataJson; + + @TableField(exist = false) + private OnlineRule onlineRule; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasource.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasource.java new file mode 100644 index 00000000..14a8dea4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasource.java @@ -0,0 +1,107 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationDict; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.vo.OnlineDatasourceVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单的数据源实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_datasource") +public class OnlineDatasource { + + /** + * 主键Id。 + */ + @TableId(value = "datasource_id") + private Long datasourceId; + + /** + * 数据源名称。 + */ + @TableField(value = "datasource_name") + private String datasourceName; + + /** + * 数据源变量名,会成为数据访问url的一部分。 + */ + @TableField(value = "variable_name") + private String variableName; + + /** + * 数据库链接Id。 + */ + @TableField(value = "dblink_id") + private Long dblinkId; + + /** + * 主表Id。 + */ + @TableField(value = "master_table_id") + private Long masterTableId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * datasourceId 的多对多关联表数据对象。 + */ + @TableField(exist = false) + private OnlinePageDatasource onlinePageDatasource; + + @RelationDict( + masterIdField = "masterTableId", + slaveServiceName = "onlineTableService", + slaveModelClass = OnlineTable.class, + slaveIdField = "tableId", + slaveNameField = "tableName") + @TableField(exist = false) + private Map masterTableIdDictMap; + + @TableField(exist = false) + private OnlineTable masterTable; + + @Mapper + public interface OnlineDatasourceModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param onlineDatasourceVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "onlinePageDatasource", expression = "java(mapToBean(onlineDatasourceVo.getOnlinePageDatasource(), com.flow.demo.common.online.model.OnlinePageDatasource.class))") + @Override + OnlineDatasource toModel(OnlineDatasourceVo onlineDatasourceVo); + /** + * 转换实体对象到VO对象。 + * + * @param onlineDatasource 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "onlinePageDatasource", expression = "java(beanToMap(onlineDatasource.getOnlinePageDatasource(), false))") + @Override + OnlineDatasourceVo fromModel(OnlineDatasource onlineDatasource); + } + public static final OnlineDatasourceModelMapper INSTANCE = Mappers.getMapper(OnlineDatasourceModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasourceRelation.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasourceRelation.java new file mode 100644 index 00000000..3fc589aa --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasourceRelation.java @@ -0,0 +1,187 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationConstDict; +import com.flow.demo.common.core.annotation.RelationDict; +import com.flow.demo.common.core.annotation.RelationOneToOne; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.model.constant.RelationType; +import com.flow.demo.common.online.vo.OnlineDatasourceRelationVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单的数据源关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_datasource_relation") +public class OnlineDatasourceRelation { + + /** + * 主键Id。 + */ + @TableId(value = "relation_id") + private Long relationId; + + /** + * 关联名称。 + */ + @TableField(value = "relation_name") + private String relationName; + + /** + * 变量名。 + */ + @TableField(value = "variable_name") + private String variableName; + + /** + * 主数据源Id。 + */ + @TableField(value = "datasource_id") + private Long datasourceId; + + /** + * 关联类型。 + */ + @TableField(value = "relation_type") + private Integer relationType; + + /** + * 主表关联字段Id。 + */ + @TableField(value = "master_column_id") + private Long masterColumnId; + + /** + * 从表Id。 + */ + @TableField(value = "slave_table_id") + private Long slaveTableId; + + /** + * 从表关联字段Id。 + */ + @TableField(value = "slave_column_id") + private Long slaveColumnId; + + /** + * 删除主表的时候是否级联删除一对一和一对多的从表数据,多对多只是删除关联,不受到这个标记的影响。。 + */ + @TableField(value = "cascade_delete") + private Boolean cascadeDelete; + + /** + * 是否左连接。 + */ + @TableField(value = "left_join") + private Boolean leftJoin; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + @RelationOneToOne( + masterIdField = "masterColumnId", + slaveServiceName = "onlineColumnService", + slaveModelClass = OnlineColumn.class, + slaveIdField = "columnId") + @TableField(exist = false) + private OnlineColumn masterColumn; + + @RelationOneToOne( + masterIdField = "slaveTableId", + slaveServiceName = "onlineTableService", + slaveModelClass = OnlineTable.class, + slaveIdField = "tableId") + @TableField(exist = false) + private OnlineTable slaveTable; + + @RelationOneToOne( + masterIdField = "slaveColumnId", + slaveServiceName = "onlineColumnService", + slaveModelClass = OnlineColumn.class, + slaveIdField = "columnId") + @TableField(exist = false) + private OnlineColumn slaveColumn; + + @RelationDict( + masterIdField = "masterColumnId", + slaveServiceName = "onlineColumnService", + equalOneToOneRelationField = "onlineColumn", + slaveModelClass = OnlineColumn.class, + slaveIdField = "columnId", + slaveNameField = "columnName") + @TableField(exist = false) + private Map masterColumnIdDictMap; + + @RelationDict( + masterIdField = "slaveTableId", + slaveServiceName = "onlineTableService", + equalOneToOneRelationField = "onlineTable", + slaveModelClass = OnlineTable.class, + slaveIdField = "tableId", + slaveNameField = "modelName") + @TableField(exist = false) + private Map slaveTableIdDictMap; + + @RelationDict( + masterIdField = "slaveColumnId", + slaveServiceName = "onlineColumnService", + equalOneToOneRelationField = "onlineColumn", + slaveModelClass = OnlineColumn.class, + slaveIdField = "columnId", + slaveNameField = "columnName") + @TableField(exist = false) + private Map slaveColumnIdDictMap; + + @RelationConstDict( + masterIdField = "relationType", + constantDictClass = RelationType.class) + @TableField(exist = false) + private Map relationTypeDictMap; + + @Mapper + public interface OnlineDatasourceRelationModelMapper + extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param onlineDatasourceRelationVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "masterColumn", expression = "java(mapToBean(onlineDatasourceRelationVo.getMasterColumn(), com.flow.demo.common.online.model.OnlineColumn.class))") + @Mapping(target = "slaveTable", expression = "java(mapToBean(onlineDatasourceRelationVo.getSlaveTable(), com.flow.demo.common.online.model.OnlineTable.class))") + @Mapping(target = "slaveColumn", expression = "java(mapToBean(onlineDatasourceRelationVo.getSlaveColumn(), com.flow.demo.common.online.model.OnlineColumn.class))") + @Override + OnlineDatasourceRelation toModel(OnlineDatasourceRelationVo onlineDatasourceRelationVo); + /** + * 转换实体对象到VO对象。 + * + * @param onlineDatasourceRelation 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "masterColumn", expression = "java(beanToMap(onlineDatasourceRelation.getMasterColumn(), false))") + @Mapping(target = "slaveTable", expression = "java(beanToMap(onlineDatasourceRelation.getSlaveTable(), false))") + @Mapping(target = "slaveColumn", expression = "java(beanToMap(onlineDatasourceRelation.getSlaveColumn(), false))") + @Override + OnlineDatasourceRelationVo fromModel(OnlineDatasourceRelation onlineDatasourceRelation); + } + public static final OnlineDatasourceRelationModelMapper INSTANCE = Mappers.getMapper(OnlineDatasourceRelationModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasourceTable.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasourceTable.java new file mode 100644 index 00000000..911c33b6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDatasourceTable.java @@ -0,0 +1,39 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 数据源及其关联所引用的数据表实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_datasource_table") +public class OnlineDatasourceTable { + + /** + * 主键Id。 + */ + @TableId(value = "id") + private Long id; + + /** + * 数据源Id。 + */ + @TableField(value = "datasource_id") + private Long datasourceId; + + /** + * 数据源关联Id。 + */ + @TableField(value = "relation_id") + private Long relationId; + + /** + * 数据表Id。 + */ + @TableField(value = "table_id") + private Long tableId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDblink.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDblink.java new file mode 100644 index 00000000..32658f20 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDblink.java @@ -0,0 +1,62 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.vo.OnlineDblinkVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.Date; + +/** + * 在线表单数据表所在数据库链接实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_dblink") +public class OnlineDblink { + + /** + * 主键Id。 + */ + @TableId(value = "dblink_id") + private Long dblinkId; + + /** + * 链接中文名称。 + */ + @TableField(value = "dblink_name") + private String dblinkName; + + /** + * 链接英文名称。 + */ + @TableField(value = "variable_name") + private String variableName; + + /** + * 链接描述。 + */ + @TableField(value = "dblink_desc") + private String dblinkDesc; + + /** + * 数据源配置常量。 + */ + @TableField(value = "dblink_config_constant") + private Integer dblinkConfigConstant; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + @Mapper + public interface OnlineDblinkModelMapper extends BaseModelMapper { + } + public static final OnlineDblinkModelMapper INSTANCE = Mappers.getMapper(OnlineDblinkModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDict.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDict.java new file mode 100644 index 00000000..f5c79dde --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineDict.java @@ -0,0 +1,169 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationConstDict; +import com.flow.demo.common.core.annotation.RelationDict; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.model.constant.DictType; +import com.flow.demo.common.online.vo.OnlineDictVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单关联的字典实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_dict") +public class OnlineDict { + + /** + * 主键Id。 + */ + @TableId(value = "dict_id") + private Long dictId; + + /** + * 字典名称。 + */ + @TableField(value = "dict_name") + private String dictName; + + /** + * 字典类型。 + */ + @TableField(value = "dict_type") + private Integer dictType; + + /** + * 数据库链接Id。 + */ + @TableField(value = "dblink_id") + private Long dblinkId; + + /** + * 字典表名称。 + */ + @TableField(value = "table_name") + private String tableName; + + /** + * 字典表键字段名称。 + */ + @TableField(value = "key_column_name") + private String keyColumnName; + + /** + * 字典表父键字段名称。 + */ + @TableField(value = "parent_key_column_name") + private String parentKeyColumnName; + + /** + * 字典值字段名称。 + */ + @TableField(value = "value_column_name") + private String valueColumnName; + + /** + * 逻辑删除字段。 + */ + @TableField(value = "deleted_column_name") + private String deletedColumnName; + + /** + * 用户过滤滤字段名称。 + */ + @TableField(value = "user_filter_column_name") + private String userFilterColumnName; + + /** + * 部门过滤字段名称。 + */ + @TableField(value = "dept_filter_column_name") + private String deptFilterColumnName; + + /** + * 租户过滤字段名称。 + */ + @TableField(value = "tenant_filter_column_name") + private String tenantFilterColumnName; + + /** + * 是否树形标记。 + */ + @TableField(value = "tree_flag") + private Boolean treeFlag; + + /** + * 获取字典数据的url。 + */ + @TableField(value = "dict_list_url") + private String dictListUrl; + + /** + * 根据主键id批量获取字典数据的url。 + */ + @TableField(value = "dict_ids_url") + private String dictIdsUrl; + + /** + * 字典的JSON数据。 + */ + @TableField(value = "dict_data_json") + private String dictDataJson; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + @RelationConstDict( + masterIdField = "dictType", + constantDictClass = DictType.class) + @TableField(exist = false) + private Map dictTypeDictMap; + + @RelationDict( + masterIdField = "dblinkId", + slaveServiceName = "onlineDblinkService", + slaveModelClass = OnlineDblink.class, + slaveIdField = "dblinkId", + slaveNameField = "dblinkName") + @TableField(exist = false) + private Map dblinkIdDictMap; + + @Mapper + public interface OnlineDictModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param onlineDictVo 域对象。 + * @return 实体对象。 + */ + @Override + OnlineDict toModel(OnlineDictVo onlineDictVo); + /** + * 转换实体对象到VO对象。 + * + * @param onlineDict 实体对象。 + * @return 域对象。 + */ + @Override + OnlineDictVo fromModel(OnlineDict onlineDict); + } + public static final OnlineDictModelMapper INSTANCE = Mappers.getMapper(OnlineDictModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineForm.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineForm.java new file mode 100644 index 00000000..bacec6ed --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineForm.java @@ -0,0 +1,138 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.*; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.model.constant.FormType; +import com.flow.demo.common.online.vo.OnlineFormVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_form") +public class OnlineForm { + + /** + * 主键Id。 + */ + @TableId(value = "form_id") + private Long formId; + + /** + * 页面id。 + */ + @TableField(value = "page_id") + private Long pageId; + + /** + * 表单编码。 + */ + @TableField(value = "form_code") + private String formCode; + + /** + * 表单名称。 + */ + @TableField(value = "form_name") + private String formName; + + /** + * 表单类别。 + */ + @TableField(value = "form_kind") + private Integer formKind; + + /** + * 表单类型。 + */ + @TableField(value = "form_type") + private Integer formType; + + /** + * 表单主表id。 + */ + @TableField(value = "master_table_id") + private Long masterTableId; + + /** + * 表单组件JSON。 + */ + @TableField(value = "widget_json") + private String widgetJson; + + /** + * 表单参数JSON。 + */ + @TableField(value = "params_json") + private String paramsJson; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + @RelationOneToOne( + masterIdField = "masterTableId", + slaveServiceName = "onlineTableService", + slaveModelClass = OnlineTable.class, + slaveIdField = "tableId") + @TableField(exist = false) + private OnlineTable onlineTable; + + @RelationDict( + masterIdField = "masterTableId", + slaveServiceName = "onlineTableService", + equalOneToOneRelationField = "onlineTable", + slaveModelClass = OnlineTable.class, + slaveIdField = "tableId", + slaveNameField = "modelName") + @TableField(exist = false) + private Map masterTableIdDictMap; + + @RelationConstDict( + masterIdField = "formType", + constantDictClass = FormType.class) + @TableField(exist = false) + private Map formTypeDictMap; + + @Mapper + public interface OnlineFormModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param onlineFormVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "onlineTable", expression = "java(mapToBean(onlineFormVo.getOnlineTable(), com.flow.demo.common.online.model.OnlineTable.class))") + @Override + OnlineForm toModel(OnlineFormVo onlineFormVo); + /** + * 转换实体对象到VO对象。 + * + * @param onlineForm 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "onlineTable", expression = "java(beanToMap(onlineForm.getOnlineTable(), false))") + @Override + OnlineFormVo fromModel(OnlineForm onlineForm); + } + public static final OnlineFormModelMapper INSTANCE = Mappers.getMapper(OnlineFormModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineFormDatasource.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineFormDatasource.java new file mode 100644 index 00000000..45e39a96 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineFormDatasource.java @@ -0,0 +1,33 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 在线表单和数据源多对多关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_form_datasource") +public class OnlineFormDatasource { + + /** + * 主键Id。 + */ + @TableId(value = "id") + private Long id; + + /** + * 表单Id。 + */ + @TableField(value = "form_id") + private Long formId; + + /** + * 数据源Id。 + */ + @TableField(value = "datasource_id") + private Long datasourceId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlinePage.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlinePage.java new file mode 100644 index 00000000..3907f114 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlinePage.java @@ -0,0 +1,106 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationConstDict; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.model.constant.PageStatus; +import com.flow.demo.common.online.model.constant.PageType; +import com.flow.demo.common.online.vo.OnlinePageVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单所在页面实体对象。这里我们可以把页面理解为表单的容器。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_page") +public class OnlinePage { + + /** + * 主键Id。 + */ + @TableId(value = "page_id") + private Long pageId; + + /** + * 页面编码。 + */ + @TableField(value = "page_code") + private String pageCode; + + /** + * 页面名称。 + */ + @TableField(value = "page_name") + private String pageName; + + /** + * 页面类型。 + */ + @TableField(value = "page_type") + private Integer pageType; + + /** + * 页面编辑状态。 + */ + @TableField(value = "status") + private Integer status; + + /** + * 是否发布。 + */ + @TableField(value = "published") + private Boolean published; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + @RelationConstDict( + masterIdField = "pageType", + constantDictClass = PageType.class) + @TableField(exist = false) + private Map pageTypeDictMap; + + @RelationConstDict( + masterIdField = "status", + constantDictClass = PageStatus.class) + @TableField(exist = false) + private Map statusDictMap; + + @Mapper + public interface OnlinePageModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param onlinePageVo 域对象。 + * @return 实体对象。 + */ + @Override + OnlinePage toModel(OnlinePageVo onlinePageVo); + /** + * 转换实体对象到VO对象。 + * + * @param onlinePage 实体对象。 + * @return 域对象。 + */ + @Override + OnlinePageVo fromModel(OnlinePage onlinePage); + } + public static final OnlinePageModelMapper INSTANCE = Mappers.getMapper(OnlinePageModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlinePageDatasource.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlinePageDatasource.java new file mode 100644 index 00000000..15850387 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlinePageDatasource.java @@ -0,0 +1,33 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; + +/** + * 在线表单页面和数据源多对多关联实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_page_datasource") +public class OnlinePageDatasource { + + /** + * 主键Id。 + */ + @TableId(value = "id") + private Long id; + + /** + * 页面主键Id。 + */ + @TableField(value = "page_id") + private Long pageId; + + /** + * 数据源主键Id。 + */ + @TableField(value = "datasource_id") + private Long datasourceId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineRule.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineRule.java new file mode 100644 index 00000000..c4a9eb65 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineRule.java @@ -0,0 +1,109 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationConstDict; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.model.constant.RuleType; +import com.flow.demo.common.online.vo.OnlineRuleVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单数据表字段验证规则实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_rule") +public class OnlineRule { + + /** + * 主键Id。 + */ + @TableId(value = "rule_id") + private Long ruleId; + + /** + * 规则名称。 + */ + @TableField(value = "rule_name") + private String ruleName; + + /** + * 规则类型。 + */ + @TableField(value = "rule_type") + private Integer ruleType; + + /** + * 内置规则标记。 + */ + @TableField(value = "builtin") + private Boolean builtin; + + /** + * 自定义规则的正则表达式。 + */ + @TableField(value = "pattern") + private String pattern; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + /** + * 逻辑删除标记字段(1: 正常 -1: 已删除)。 + */ + @TableLogic + @TableField(value = "deleted_flag") + private Integer deletedFlag; + + /** + * ruleId 的多对多关联表数据对象。 + */ + @TableField(exist = false) + private OnlineColumnRule onlineColumnRule; + + @RelationConstDict( + masterIdField = "ruleType", + constantDictClass = RuleType.class) + @TableField(exist = false) + private Map ruleTypeDictMap; + + @Mapper + public interface OnlineRuleModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param onlineRuleVo 域对象。 + * @return 实体对象。 + */ + @Mapping(target = "onlineColumnRule", expression = "java(mapToBean(onlineRuleVo.getOnlineColumnRule(), com.flow.demo.common.online.model.OnlineColumnRule.class))") + @Override + OnlineRule toModel(OnlineRuleVo onlineRuleVo); + /** + * 转换实体对象到VO对象。 + * + * @param onlineRule 实体对象。 + * @return 域对象。 + */ + @Mapping(target = "onlineColumnRule", expression = "java(beanToMap(onlineRule.getOnlineColumnRule(), false))") + @Override + OnlineRuleVo fromModel(OnlineRule onlineRule); + } + public static final OnlineRuleModelMapper INSTANCE = Mappers.getMapper(OnlineRuleModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineTable.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineTable.java new file mode 100644 index 00000000..fc15fc4e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineTable.java @@ -0,0 +1,107 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.annotation.RelationOneToMany; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.vo.OnlineTableVo; +import lombok.Data; +import org.mapstruct.Mapper; +import org.mapstruct.factory.Mappers; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 在线表单的数据表实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_table") +public class OnlineTable { + + /** + * 主键Id。 + */ + @TableId(value = "table_id") + private Long tableId; + + /** + * 表名称。 + */ + @TableField(value = "table_name") + private String tableName; + + /** + * 实体名称。 + */ + @TableField(value = "model_name") + private String modelName; + + /** + * 数据库链接Id。 + */ + @TableField(value = "dblink_id") + private Long dblinkId; + + /** + * 更新时间。 + */ + @TableField(value = "update_time") + private Date updateTime; + + /** + * 创建时间。 + */ + @TableField(value = "create_time") + private Date createTime; + + @RelationOneToMany( + masterIdField = "tableId", + slaveServiceName = "onlineColumnService", + slaveModelClass = OnlineColumn.class, + slaveIdField = "tableId") + @TableField(exist = false) + private List columnList; + + /** + * 该字段会被缓存,因此在线表单执行操作时可以从缓存中读取该数据,并可基于columnId进行快速检索。 + */ + @TableField(exist = false) + private Map columnMap; + + /** + * 当前表的主键字段,该字段仅仅用于动态表单运行时的SQL拼装。 + */ + @TableField(exist = false) + private OnlineColumn primaryKeyColumn; + + /** + * 当前表的逻辑删除字段,该字段仅仅用于动态表单运行时的SQL拼装。 + */ + @TableField(exist = false) + private OnlineColumn logicDeleteColumn; + + @Mapper + public interface OnlineTableModelMapper extends BaseModelMapper { + /** + * 转换Vo对象到实体对象。 + * + * @param onlineTableVo 域对象。 + * @return 实体对象。 + */ + @Override + OnlineTable toModel(OnlineTableVo onlineTableVo); + /** + * 转换实体对象到VO对象。 + * + * @param onlineTable 实体对象。 + * @return 域对象。 + */ + @Override + OnlineTableVo fromModel(OnlineTable onlineTable); + } + public static final OnlineTableModelMapper INSTANCE = Mappers.getMapper(OnlineTableModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineVirtualColumn.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineVirtualColumn.java new file mode 100644 index 00000000..fe75be35 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/OnlineVirtualColumn.java @@ -0,0 +1,96 @@ +package com.flow.demo.common.online.model; + +import com.baomidou.mybatisplus.annotation.*; +import com.flow.demo.common.core.base.mapper.BaseModelMapper; +import com.flow.demo.common.online.vo.OnlineVirtualColumnVo; +import lombok.Data; +import org.mapstruct.*; +import org.mapstruct.factory.Mappers; + +/** + * 在线数据表虚拟字段实体对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@TableName(value = "zz_online_virtual_column") +public class OnlineVirtualColumn { + + /** + * 主键Id。 + */ + @TableId(value = "virtual_column_id") + private Long virtualColumnId; + + /** + * 所在表Id。 + */ + @TableField(value = "table_id") + private Long tableId; + + /** + * 字段名称。 + */ + @TableField(value = "object_field_name") + private String objectFieldName; + + /** + * 属性类型。 + */ + @TableField(value = "object_field_type") + private String objectFieldType; + + /** + * 字段提示名。 + */ + @TableField(value = "column_prompt") + private String columnPrompt; + + /** + * 虚拟字段类型(0: 聚合)。 + */ + @TableField(value = "virtual_type") + private Integer virtualType; + + /** + * 关联数据源Id。 + */ + @TableField(value = "datasource_id") + private Long datasourceId; + + /** + * 关联Id。 + */ + @TableField(value = "relation_id") + private Long relationId; + + /** + * 聚合字段所在关联表Id。 + */ + @TableField(value = "aggregation_table_id") + private Long aggregationTableId; + + /** + * 关联表聚合字段Id。 + */ + @TableField(value = "aggregation_column_id") + private Long aggregationColumnId; + + /** + * 聚合类型(0: count 1: sum 2: avg 3: max 4:min)。 + */ + @TableField(value = "aggregation_type") + private Integer aggregationType; + + /** + * 存储过滤条件的json。 + */ + @TableField(value = "where_clause_json") + private String whereClauseJson; + + @Mapper + public interface OnlineVirtualColumnModelMapper extends BaseModelMapper { + } + public static final OnlineVirtualColumnModelMapper INSTANCE = Mappers.getMapper(OnlineVirtualColumnModelMapper.class); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/DictType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/DictType.java new file mode 100644 index 00000000..0a2b1271 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/DictType.java @@ -0,0 +1,54 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 在线表单字典类型常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class DictType { + + /** + * 数据表字典。 + */ + public static final int TABLE = 1; + /** + * URL字典。 + */ + public static final int URL = 5; + /** + * 常量字典。 + */ + public static final int CONST = 10; + /** + * 自定义字典。 + */ + public static final int CUSTOM = 15; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(TABLE, "数据表字典"); + DICT_MAP.put(URL, "URL字典"); + DICT_MAP.put(CONST, "静态字典"); + DICT_MAP.put(CUSTOM, "自定义字典"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private DictType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FieldFilterType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FieldFilterType.java new file mode 100644 index 00000000..7163970b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FieldFilterType.java @@ -0,0 +1,59 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 字段过滤类型常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FieldFilterType { + + /** + * 无过滤。 + */ + public static final int NO_FILTER = 0; + /** + * 等于过滤。 + */ + public static final int EQUAL_FILTER = 1; + /** + * 范围过滤。 + */ + public static final int RANGE_FILTER = 2; + /** + * 模糊过滤。 + */ + public static final int LIKE_FILTER = 3; + /** + * IN LIST列表过滤。 + */ + public static final int IN_LIST_FILTER = 4; + + private static final Map DICT_MAP = new HashMap<>(9); + static { + DICT_MAP.put(NO_FILTER, "无过滤"); + DICT_MAP.put(EQUAL_FILTER, "等于过滤"); + DICT_MAP.put(RANGE_FILTER, "范围过滤"); + DICT_MAP.put(LIKE_FILTER, "模糊过滤"); + DICT_MAP.put(IN_LIST_FILTER, "IN LIST列表过滤"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FieldFilterType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FieldKind.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FieldKind.java new file mode 100644 index 00000000..8d19b2d1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FieldKind.java @@ -0,0 +1,74 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 字段类别常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FieldKind { + + /** + * 文件上传字段。 + */ + public static final int UPLOAD = 1; + /** + * 图片上传字段。 + */ + public static final int UPLOAD_IMAGE = 2; + /** + * 富文本字段。 + */ + public static final int RICH_TEXT = 3; + /** + * 创建时间字段。 + */ + public static final int CREATE_TIME = 20; + /** + * 创建人字段。 + */ + public static final int CREATE_USER_ID = 21; + /** + * 更新时间字段。 + */ + public static final int UPDATE_TIME = 22; + /** + * 更新人字段。 + */ + public static final int UPDATE_USER_ID = 23; + /** + * 逻辑删除字段。 + */ + public static final int LOGIC_DELETE = 31; + + private static final Map DICT_MAP = new HashMap<>(9); + static { + DICT_MAP.put(UPLOAD, "文件上传字段"); + DICT_MAP.put(UPLOAD_IMAGE, "图片上传字段"); + DICT_MAP.put(RICH_TEXT, "富文本字段"); + DICT_MAP.put(CREATE_TIME, "创建时间字段"); + DICT_MAP.put(CREATE_USER_ID, "创建人字段"); + DICT_MAP.put(UPDATE_TIME, "更新时间字段"); + DICT_MAP.put(UPDATE_USER_ID, "更新人字段"); + DICT_MAP.put(LOGIC_DELETE, "逻辑删除字段"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FieldKind() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FormKind.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FormKind.java new file mode 100644 index 00000000..976484e2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FormKind.java @@ -0,0 +1,44 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 表单类别常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FormKind { + + /** + * 弹框。 + */ + public static final int DIALOG = 1; + /** + * 跳页。 + */ + public static final int NEW_PAGE = 5; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(DIALOG, "弹框列表"); + DICT_MAP.put(NEW_PAGE, "跳页类别"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FormKind() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FormType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FormType.java new file mode 100644 index 00000000..edc7b018 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/FormType.java @@ -0,0 +1,54 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 表单类型常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class FormType { + + /** + * 查询表单。 + */ + public static final int QUERY = 1; + /** + * 编辑表单。 + */ + public static final int FORM = 5; + /** + * 流程表单。 + */ + public static final int FLOW = 10; + /** + * 流程工单表单。 + */ + public static final int FLOW_WORK_ORDER = 11; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(QUERY, "查询表单"); + DICT_MAP.put(FORM, "编辑表单"); + DICT_MAP.put(FLOW, "流程表单"); + DICT_MAP.put(FLOW_WORK_ORDER, "流程工单表单"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private FormType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/PageStatus.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/PageStatus.java new file mode 100644 index 00000000..6d62b1ef --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/PageStatus.java @@ -0,0 +1,49 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 页面状态常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class PageStatus { + + /** + * 编辑基础信息。 + */ + public static final int BASIC = 0; + /** + * 编辑数据模型。 + */ + public static final int DATASOURCE = 1; + /** + * 设计表单。 + */ + public static final int FORM_DESIGN = 2; + + private static final Map DICT_MAP = new HashMap<>(4); + static { + DICT_MAP.put(BASIC, "编辑基础信息"); + DICT_MAP.put(DATASOURCE, "编辑数据模型"); + DICT_MAP.put(FORM_DESIGN, "设计表单"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private PageStatus() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/PageType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/PageType.java new file mode 100644 index 00000000..bd21054a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/PageType.java @@ -0,0 +1,49 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 页面类型常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class PageType { + + /** + * 业务页面。 + */ + public static final int BIZ = 1; + /** + * 统计页面。 + */ + public static final int STATS = 5; + /** + * 流程页面。 + */ + public static final int FLOW = 10; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(BIZ, "业务页面"); + DICT_MAP.put(STATS, "统计页面"); + DICT_MAP.put(FLOW, "流程页面"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private PageType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/RelationType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/RelationType.java new file mode 100644 index 00000000..e5c52693 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/RelationType.java @@ -0,0 +1,44 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 关联类型常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class RelationType { + + /** + * 一对一关联。 + */ + public static final int ONE_TO_ONE = 0; + /** + * 一对多关联。 + */ + public static final int ONE_TO_MANY = 1; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(ONE_TO_ONE, "一对一关联"); + DICT_MAP.put(ONE_TO_MANY, "一对多关联"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private RelationType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/RuleType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/RuleType.java new file mode 100644 index 00000000..d0fb9069 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/RuleType.java @@ -0,0 +1,69 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 验证规则类型常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class RuleType { + + /** + * 只允许整数。 + */ + public static final int INTEGER_ONLY = 1; + /** + * 只允许数字。 + */ + public static final int DIGITAL_ONLY = 2; + /** + * 只允许英文字符。 + */ + public static final int LETTER_ONLY = 3; + /** + * 范围验证。 + */ + public static final int RANGE = 4; + /** + * 邮箱格式验证。 + */ + public static final int EMAIL = 5; + /** + * 手机格式验证。 + */ + public static final int MOBILE = 6; + /** + * 自定义验证。 + */ + public static final int CUSTOM = 100; + + private static final Map DICT_MAP = new HashMap<>(7); + static { + DICT_MAP.put(INTEGER_ONLY, "只允许整数"); + DICT_MAP.put(DIGITAL_ONLY, "只允许数字"); + DICT_MAP.put(LETTER_ONLY, "只允许英文字符"); + DICT_MAP.put(RANGE, "范围验证"); + DICT_MAP.put(EMAIL, "邮箱格式验证"); + DICT_MAP.put(MOBILE, "手机格式验证"); + DICT_MAP.put(CUSTOM, "自定义验证"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private RuleType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/VirtualType.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/VirtualType.java new file mode 100644 index 00000000..a1cef356 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/model/constant/VirtualType.java @@ -0,0 +1,39 @@ +package com.flow.demo.common.online.model.constant; + +import java.util.HashMap; +import java.util.Map; + +/** + * 在线表单虚拟字段类型常量字典对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +public final class VirtualType { + + /** + * 聚合。 + */ + public static final int AGGREGATION = 0; + + private static final Map DICT_MAP = new HashMap<>(2); + static { + DICT_MAP.put(AGGREGATION, "聚合"); + } + + /** + * 判断参数是否为当前常量字典的合法值。 + * + * @param value 待验证的参数值。 + * @return 合法返回true,否则false。 + */ + public static boolean isValid(Integer value) { + return value != null && DICT_MAP.containsKey(value); + } + + /** + * 私有构造函数,明确标识该常量类的作用。 + */ + private VirtualType() { + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/ColumnData.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/ColumnData.java new file mode 100644 index 00000000..a15b4954 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/ColumnData.java @@ -0,0 +1,28 @@ +package com.flow.demo.common.online.object; + +import com.flow.demo.common.online.model.OnlineColumn; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 表字段数据对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class ColumnData { + + /** + * 在线表字段对象。 + */ + private OnlineColumn column; + + /** + * 字段值。 + */ + private Object columnValue; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/JoinTableInfo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/JoinTableInfo.java new file mode 100644 index 00000000..91a1c34e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/JoinTableInfo.java @@ -0,0 +1,28 @@ +package com.flow.demo.common.online.object; + +import lombok.Data; + +/** + * 连接表信息对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class JoinTableInfo { + + /** + * 是否左连接。 + */ + private Boolean leftJoin; + + /** + * 连接表表名。 + */ + private String joinTableName; + + /** + * 连接条件。 + */ + private String joinCondition; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/SqlTable.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/SqlTable.java new file mode 100644 index 00000000..47c23750 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/SqlTable.java @@ -0,0 +1,41 @@ +package com.flow.demo.common.online.object; + +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * 数据库中的表对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SqlTable { + + /** + * 表名称。 + */ + private String tableName; + + /** + * 表注释。 + */ + private String tableComment; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * 关联的字段列表。 + */ + private List columnList; + + /** + * 数据库链接Id。 + */ + private Long dblinkId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/SqlTableColumn.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/SqlTableColumn.java new file mode 100644 index 00000000..ae87c443 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/object/SqlTableColumn.java @@ -0,0 +1,73 @@ +package com.flow.demo.common.online.object; + +import lombok.Data; + +/** + * 数据库中的表字段对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class SqlTableColumn { + + /** + * 表字段名。 + */ + private String columnName; + + /** + * 表字段类型。 + */ + private String columnType; + + /** + * 表字段全类型。 + */ + private String fullColumnType; + + /** + * 字段注释。 + */ + private String columnComment; + + /** + * 是否为主键。 + */ + private Boolean primaryKey; + + /** + * 是否自动增长。 + */ + private Boolean autoIncrement; + + /** + * 是否可以为空值。 + */ + private Boolean nullable; + + /** + * 字段顺序。 + */ + private Integer columnShowOrder; + + /** + * 附件信息。 + */ + private String extra; + + /** + * 字符型字段精度。 + */ + private Long stringPrecision; + + /** + * 数值型字段精度。 + */ + private Integer numericPrecision; + + /** + * 缺省值。 + */ + private Object columnDefault; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineColumnService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineColumnService.java new file mode 100644 index 00000000..03a7e5a0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineColumnService.java @@ -0,0 +1,150 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.online.model.OnlineColumn; +import com.flow.demo.common.online.model.OnlineColumnRule; +import com.flow.demo.common.online.object.SqlTableColumn; + +import java.util.List; +import java.util.Set; + +/** + * 字段数据数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineColumnService extends IBaseService { + + /** + * 保存新增数据表字段列表。 + * + * @param columnList 新增数据表字段对象列表。 + * @param onlineTableId 在线表对象的主键Id。 + * @return 插入的在线表字段数据。 + */ + List saveNewList(List columnList, Long onlineTableId); + + /** + * 更新数据对象。 + * + * @param onlineColumn 更新的对象。 + * @param originalOnlineColumn 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(OnlineColumn onlineColumn, OnlineColumn originalOnlineColumn); + + /** + * 刷新数据库表字段的数据到在线表字段。 + * + * @param sqlTableColumn 源数据库表字段对象。 + * @param onlineColumn 被刷新的在线表字段对象。 + */ + void refresh(SqlTableColumn sqlTableColumn, OnlineColumn onlineColumn); + + /** + * 删除指定数据。 + * + * @param tableId 表Id。 + * @param columnId 字段Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long tableId, Long columnId); + + /** + * 批量添加多对多关联关系。 + * + * @param onlineColumnRuleList 多对多关联表对象集合。 + * @param columnId 主表Id。 + */ + void addOnlineColumnRuleList(List onlineColumnRuleList, Long columnId); + + /** + * 更新中间表数据。 + * + * @param onlineColumnRule 中间表对象。 + * @return 更新成功与否。 + */ + boolean updateOnlineColumnRule(OnlineColumnRule onlineColumnRule); + + /** + * 获取中间表数据。 + * + * @param columnId 主表Id。 + * @param ruleId 从表Id。 + * @return 中间表对象。 + */ + OnlineColumnRule getOnlineColumnRule(Long columnId, Long ruleId); + + /** + * 移除单条多对多关系。 + * + * @param columnId 主表Id。 + * @param ruleId 从表Id。 + * @return 成功返回true,否则false。 + */ + boolean removeOnlineColumnRule(Long columnId, Long ruleId); + + /** + * 当前服务的支持表为从表,根据主表的主键Id,删除一对多的从表数据。 + * + * @param tableId 主表主键Id。 + * @return 删除数量。 + */ + int removeByTableId(Long tableId); + + /** + * 删除指定数据表Id集合中的表字段。 + * + * @param tableIdSet 待删除的数据表Id集合。 + */ + void removeByTableIdSet(Set tableIdSet); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineColumnListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineColumnList(OnlineColumn filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineColumnList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineColumnListWithRelation(OnlineColumn filter, String orderBy); + + /** + * 获取指定数据表Id集合的字段对象列表。 + * + * @param tableIdSet 指定的数据表Id集合。 + * @return 数据表Id集合所包含的字段对象列表。 + */ + List getOnlineColumnListByTableIds(Set tableIdSet); + + /** + * 根据表Id和字段列名获取指定字段。 + * + * @param tableId 字段所在表Id。 + * @param columnName 字段名。 + * @return 查询出的字段对象。 + */ + OnlineColumn getOnlineColumnByTableIdAndColumnName(Long tableId, String columnName); + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param onlineColumn 最新数据对象。 + * @param originalOnlineColumn 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + CallResult verifyRelatedData(OnlineColumn onlineColumn, OnlineColumn originalOnlineColumn); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDatasourceRelationService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDatasourceRelationService.java new file mode 100644 index 00000000..4a35e2db --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDatasourceRelationService.java @@ -0,0 +1,97 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.online.model.OnlineDatasourceRelation; +import com.flow.demo.common.online.object.SqlTable; +import com.flow.demo.common.online.object.SqlTableColumn; + +import java.util.List; +import java.util.Set; + +/** + * 数据关联数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineDatasourceRelationService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param relation 新增对象。 + * @param slaveSqlTable 新增的关联从数据表对象。 + * @param slaveSqlColumn 新增的关联从数据表对象。 + * @return 返回新增对象。 + */ + OnlineDatasourceRelation saveNew( + OnlineDatasourceRelation relation, SqlTable slaveSqlTable, SqlTableColumn slaveSqlColumn); + + /** + * 更新数据对象。 + * + * @param relation 更新的对象。 + * @param originalRelation 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(OnlineDatasourceRelation relation, OnlineDatasourceRelation originalRelation); + + /** + * 删除指定数据。 + * + * @param relationId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long relationId); + + /** + * 当前服务的支持表为从表,根据主表的主键Id,删除一对多的从表数据。 + * + * @param datasourceId 主表主键Id。 + * @return 删除数量。 + */ + int removeByDatasourceId(Long datasourceId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineDatasourceRelationListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineDatasourceRelationListByDatasourceIds( + OnlineDatasourceRelation filter, String orderBy); + + /** + * 获取指定数据源Id集合下的所有数据源关联列表。 + * + * @param datasourceIdSet 数据源Id集合。 + * @param relationType 关联类型,如果为空,则查询全部类型。 + * @return 指定数据源下的所有关联列表。 + */ + List getOnlineDatasourceRelationListByDatasourceIds( + Set datasourceIdSet, Integer relationType); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineDatasourceRelationList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineDatasourceRelationListWithRelation( + OnlineDatasourceRelation filter, String orderBy); + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param relation 最新数据对象。 + * @param originalRelation 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + CallResult verifyRelatedData(OnlineDatasourceRelation relation, OnlineDatasourceRelation originalRelation); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDatasourceService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDatasourceService.java new file mode 100644 index 00000000..8712f9d7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDatasourceService.java @@ -0,0 +1,110 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.online.model.OnlineDatasource; +import com.flow.demo.common.online.model.OnlineDatasourceTable; +import com.flow.demo.common.online.object.SqlTable; + +import java.util.List; +import java.util.Set; + +/** + * 数据模型数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineDatasourceService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param onlineDatasource 新增对象。 + * @param sqlTable 新增的数据表对象。 + * @param pageId 关联的页面Id。 + * @return 返回新增对象。 + */ + OnlineDatasource saveNew(OnlineDatasource onlineDatasource, SqlTable sqlTable, Long pageId); + + /** + * 更新数据对象。 + * + * @param onlineDatasource 更新的对象。 + * @param originalOnlineDatasource 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(OnlineDatasource onlineDatasource, OnlineDatasource originalOnlineDatasource); + + /** + * 删除指定数据。 + * + * @param datasourceId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long datasourceId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineDatasourceListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineDatasourceList(OnlineDatasource filter, String orderBy); + + /** + * 查询指定数据源Id集合的数据源列表。 + * + * @param datasourceIdSet 数据源Id集合。 + * @return 查询结果集。 + */ + List getOnlineDatasourceList(Set datasourceIdSet); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineDatasourceList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineDatasourceListWithRelation(OnlineDatasource filter, String orderBy); + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param pageId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getNotInOnlineDatasourceListByPageId(Long pageId, OnlineDatasource filter, String orderBy); + + /** + * 在多对多关系中,当前Service的数据表为从表,返回与指定主表主键Id存在对多对关系的列表。 + * + * @param pageId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineDatasourceListByPageId(Long pageId, OnlineDatasource filter, String orderBy); + + /** + * 获取指定数据源Id集合所关联的在线表关联数据。 + * + * @param datasourceIdSet 数据源Id集合。 + * @return 数据源和数据表的多对多关联列表。 + */ + List getOnlineDatasourceTableList(Set datasourceIdSet); + + /** + * 根据在线表单Id集合,获取关联的在线数据源对象列表。 + * + * @param readFormIdSet 在线表单Id集合。 + * @return 与参数表单Id关联的数据源列表。 + */ + List getOnlineDatasourceListByFormIds(Set readFormIdSet); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDblinkService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDblinkService.java new file mode 100644 index 00000000..5875e3ab --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDblinkService.java @@ -0,0 +1,74 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.online.model.OnlineDblink; +import com.flow.demo.common.online.object.SqlTable; +import com.flow.demo.common.online.object.SqlTableColumn; + +import java.util.List; + +/** + * 数据库链接数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineDblinkService extends IBaseService { + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineDblinkListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineDblinkList(OnlineDblink filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineDblinkList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineDblinkListWithRelation(OnlineDblink filter, String orderBy); + + /** + * 获取指定DBLink下面的全部数据表。 + * + * @param dblink 数据库链接对象。 + * @return 全部数据表列表。 + */ + List getDblinkTableList(OnlineDblink dblink); + + /** + * 获取指定DBLink下,指定表名的数据表对象,及其关联字段列表。 + * + * @param dblink 数据库链接对象。 + * @param tableName 数据库中的数据表名。 + * @return 数据表对象。 + */ + SqlTable getDblinkTable(OnlineDblink dblink, String tableName); + + /** + * 获取指定DBLink下,指定表名的字段列表。 + * + * @param dblink 数据库链接对象。 + * @param tableName 数据库中的数据表名。 + * @return 表的字段列表。 + */ + List getDblinkTableColumnList(OnlineDblink dblink, String tableName); + + /** + * 获取指定DBLink下,指定表的字段对象。 + * + * @param dblink 数据库链接对象。 + * @param tableName 数据库中的数据表名。 + * @param columnName 数据库中的数据表的字段名。 + * @return 表的字段对象。 + */ + SqlTableColumn getDblinkTableColumn(OnlineDblink dblink, String tableName, String columnName); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDictService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDictService.java new file mode 100644 index 00000000..14a49258 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineDictService.java @@ -0,0 +1,80 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.online.model.OnlineDict; + +import java.util.List; +import java.util.Set; + +/** + * 在线表单字典数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineDictService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param onlineDict 新增对象。 + * @return 返回新增对象。 + */ + OnlineDict saveNew(OnlineDict onlineDict); + + /** + * 更新数据对象。 + * + * @param onlineDict 更新的对象。 + * @param originalOnlineDict 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(OnlineDict onlineDict, OnlineDict originalOnlineDict); + + /** + * 删除指定数据。 + * + * @param dictId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long dictId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineDictListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineDictList(OnlineDict filter, String orderBy); + + /** + * 根据指定字典Id集合返回字段对象数据列表。 + * + * @param dictIdSet 字典Id集合。 + * @return 查询后的字典对象列表。 + */ + List getOnlineDictList(Set dictIdSet); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineDictList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineDictListWithRelation(OnlineDict filter, String orderBy); + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param onlineDict 最新数据对象。 + * @param originalOnlineDict 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + CallResult verifyRelatedData(OnlineDict onlineDict, OnlineDict originalOnlineDict); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineFormService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineFormService.java new file mode 100644 index 00000000..78179871 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineFormService.java @@ -0,0 +1,115 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.online.model.OnlineForm; +import com.flow.demo.common.online.model.OnlineFormDatasource; + +import java.util.List; +import java.util.Set; + +/** + * 在线表单数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineFormService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param onlineForm 新增对象。 + * @param datasourceIdSet 在线表单关联的数据源Id集合。 + * @return 返回新增对象。 + */ + OnlineForm saveNew(OnlineForm onlineForm, Set datasourceIdSet); + + /** + * 更新数据对象。 + * + * @param onlineForm 更新的对象。 + * @param originalOnlineForm 原有数据对象。 + * @param datasourceIdSet 在线表单关联的数据源Id集合。 + * @return 成功返回true,否则false。 + */ + boolean update(OnlineForm onlineForm, OnlineForm originalOnlineForm, Set datasourceIdSet); + + /** + * 删除指定数据。 + * + * @param formId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long formId); + + /** + * 根据PageId,删除其所属的所有表单,以及表单关联的数据源数据。 + * + * @param pageId 指定的pageId。 + * @return 删除数量。 + */ + int removeByPageId(Long pageId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineFormListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineFormList(OnlineForm filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineFormList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineFormListWithRelation(OnlineForm filter, String orderBy); + + /** + * 获取使用指定数据表的表单列表。 + * + * @param tableId 数据表Id。 + * @return 使用该数据表的表单列表。 + */ + List getOnlineFormListByTableId(Long tableId); + + /** + * 获取指定表单的数据源列表。 + * + * @param formId 指定的表单。 + * @return 表单和数据源的多对多关联对象列表。 + */ + List getFormDatasourceListByFormId(Long formId); + + /** + * 查询正在使用当前数据源的表单。 + * + * @param datasourceId 数据源Id。 + * @return 正在使用当前数据源的表单列表。 + */ + List getOnlineFormListByDatasourceId(Long datasourceId); + + /** + * 查询指定PageId集合的在线表单列表。 + * + * @param pageIdSet 页面Id集合。 + * @return 在线表单集合。 + */ + List getOnlineFormListByPageIds(Set pageIdSet); + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param onlineForm 最新数据对象。 + * @param originalOnlineForm 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + CallResult verifyRelatedData(OnlineForm onlineForm, OnlineForm originalOnlineForm); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineOperationService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineOperationService.java new file mode 100644 index 00000000..d7f491a4 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineOperationService.java @@ -0,0 +1,142 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.online.dto.OnlineFilterDto; +import com.flow.demo.common.online.model.OnlineColumn; +import com.flow.demo.common.online.model.OnlineDatasourceRelation; +import com.flow.demo.common.online.model.OnlineDict; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.object.ColumnData; + +import java.util.List; +import java.util.Map; + +/** + * 在线表单运行时操作的数据服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineOperationService { + + /** + * 待插入的所有表数据。 + * + * @param table 在线表对象。 + * @param columnDataList 数据字段列表。 + * @return 主键值。由于自增主键不能获取插入后的主键值,因此返回NULL。 + */ + Object saveNew(OnlineTable table, List columnDataList); + + /** + * 待插入的主表数据和多个从表数据。 + * + * @param masterTable 主表在线表对象。 + * @param columnDataList 主表数据字段数据。 + * @param slaveDataListMap 多个从表的数据字段数据。 + * @return 主表的主键值。由于自增主键不能获取插入后的主键值,因此返回NULL。 + */ + Object saveNewAndSlaveRelation( + OnlineTable masterTable, + List columnDataList, + Map>> slaveDataListMap); + + /** + * 更新表数据。 + * + * @param table 在线表对象。 + * @param columnDataList 单条表数据的字段数据列表。 + * @return true 更新成功,否则false。 + */ + boolean update(OnlineTable table, List columnDataList); + + /** + * 更新流程字段的状态。 + * + * @param table 数据表。 + * @param dataId 主键Id。 + * @param column 更新字段。 + * @param dataValue 新的数据值。 + * @return true 更新成功,否则false。 + */ + boolean updateColumn(OnlineTable table, String dataId, OnlineColumn column, T dataValue); + + /** + * 删除主表数据,及其需要级联删除的一对多关联从表数据。 + * + * @param table 表对象。 + * @param relationList 一对多关联对象列表。 + * @param dataId 主表主键Id值。 + * @return true 删除成功,否则false。 + */ + boolean delete(OnlineTable table, List relationList, String dataId); + + /** + * 强制删除数据,不会指定逻辑删除,只会物理删除。 + * + * @param table 在线表对象。 + * @param column 指定的字段。 + * @param columnValue 指定字段的值。 + */ + void forceDelete(OnlineTable table, OnlineColumn column, String columnValue); + + /** + * 从数据源和一对一数据源关联中,动态获取数据。 + * + * @param table 主表对象。 + * @param oneToOneRelationList 数据源一对一关联列表。 + * @param allRelationList 数据源全部关联列表。 + * @param dataId 主表主键Id值。 + * @return 查询结果。 + */ + Map getMasterData( + OnlineTable table, + List oneToOneRelationList, + List allRelationList, + String dataId); + + /** + * 从一对多数据源关联中,动态获取数据。 + * + * @param relation 一对多数据源关联对象。 + * @param dataId 一对多关联数据主键Id值。 + * @return 查询结果。 + */ + Map getSlaveData(OnlineDatasourceRelation relation, String dataId); + + /** + * 从数据源和一对一数据源关联中,动态获取数据列表。 + * + * @param table 主表对象。 + * @param oneToOneRelationList 数据源一对一关联列表。 + * @param allRelationList 数据源全部关联列表。 + * @param filterList 过滤参数列表。 + * @param orderBy 排序字符串。 + * @return 查询结果集。 + */ + List> getMasterDataList( + OnlineTable table, + List oneToOneRelationList, + List allRelationList, + List filterList, + String orderBy); + + /** + * 从一对多数据源关联中,动态获取数据列表。 + * + * @param relation 一对多数据源关联对象。 + * @param filterList 过滤参数列表。 + * @param orderBy 排序字符串。 + * @return 查询结果集。 + */ + List> getSlaveDataList( + OnlineDatasourceRelation relation, List filterList, String orderBy); + + /** + * 从字典对象指向的数据表中查询数据,并根据参数进行数据过滤。 + * + * @param dict 字典对象。 + * @param filterList 过滤参数列表。 + * @return 查询结果集。 + */ + List> getDictDataList(OnlineDict dict, List filterList); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlinePageService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlinePageService.java new file mode 100644 index 00000000..1e90ceb6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlinePageService.java @@ -0,0 +1,112 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.online.model.OnlinePage; +import com.flow.demo.common.online.model.OnlinePageDatasource; + +import java.util.List; + +/** + * 在线表单页面数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlinePageService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param onlinePage 新增对象。 + * @return 返回新增对象。 + */ + OnlinePage saveNew(OnlinePage onlinePage); + + /** + * 更新数据对象。 + * + * @param onlinePage 更新的对象。 + * @param originalOnlinePage 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(OnlinePage onlinePage, OnlinePage originalOnlinePage); + + /** + * 更新页面对象的发布状态。 + * + * @param pageId 页面对象Id。 + * @param published 新的状态。 + */ + void updatePublished(Long pageId, Boolean published); + + /** + * 删除指定数据,及其包含的表单和数据源等。 + * + * @param pageId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long pageId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlinePageListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlinePageList(OnlinePage filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlinePageList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlinePageListWithRelation(OnlinePage filter, String orderBy); + + /** + * 批量添加多对多关联关系。 + * + * @param onlinePageDatasourceList 多对多关联表对象集合。 + * @param pageId 主表Id。 + */ + void addOnlinePageDatasourceList(List onlinePageDatasourceList, Long pageId); + + /** + * 获取中间表数据。 + * + * @param pageId 主表Id。 + * @param datasourceId 从表Id。 + * @return 中间表对象。 + */ + OnlinePageDatasource getOnlinePageDatasource(Long pageId, Long datasourceId); + + /** + * 获取在线页面和数据源中间表数据列表。 + * + * @param pageId 主表Id。 + * @return 在线页面和数据源中间表对象列表。 + */ + List getOnlinePageDatasourceListByPageId(Long pageId); + + /** + * 根据数据源Id,返回使用该数据源的OnlinePage对象。 + * + * @param datasourceId 数据源Id。 + * @return 使用该数据源的页面列表。 + */ + List getOnlinePageListByDatasourceId(Long datasourceId); + + /** + * 移除单条多对多关系。 + * + * @param pageId 主表Id。 + * @param datasourceId 从表Id。 + * @return 成功返回true,否则false。 + */ + boolean removeOnlinePageDatasource(Long pageId, Long datasourceId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineRuleService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineRuleService.java new file mode 100644 index 00000000..98e49da9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineRuleService.java @@ -0,0 +1,91 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.online.model.OnlineColumnRule; +import com.flow.demo.common.online.model.OnlineRule; + +import java.util.List; +import java.util.Set; + +/** + * 验证规则数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineRuleService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param onlineRule 新增对象。 + * @return 返回新增对象。 + */ + OnlineRule saveNew(OnlineRule onlineRule); + + /** + * 更新数据对象。 + * + * @param onlineRule 更新的对象。 + * @param originalOnlineRule 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(OnlineRule onlineRule, OnlineRule originalOnlineRule); + + /** + * 删除指定数据。 + * + * @param ruleId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long ruleId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineRuleListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineRuleList(OnlineRule filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineRuleList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineRuleListWithRelation(OnlineRule filter, String orderBy); + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param columnId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getNotInOnlineRuleListByColumnId(Long columnId, OnlineRule filter, String orderBy); + + /** + * 在多对多关系中,当前Service的数据表为从表,返回与指定主表主键Id存在对多对关系的列表。 + * + * @param columnId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineRuleListByColumnId(Long columnId, OnlineRule filter, String orderBy); + + /** + * 返回指定字段Id列表关联的字段规则对象列表。 + * + * @param columnIdSet 指定的字段Id列表。 + * @return 关联的字段规则对象列表。 + */ + List getOnlineColumnRuleListByColumnIds(Set columnIdSet); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineTableService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineTableService.java new file mode 100644 index 00000000..560abef7 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineTableService.java @@ -0,0 +1,95 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.object.SqlTable; + +import java.util.List; +import java.util.Set; + +/** + * 数据表数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineTableService extends IBaseService { + + /** + * 基于数据库表保存新增对象。 + * + * @param sqlTable 数据库表对象。 + * @return 返回新增对象。 + */ + OnlineTable saveNewFromSqlTable(SqlTable sqlTable); + + /** + * 更新数据对象。 + * + * @param onlineTable 更新的对象。 + * @param originalOnlineTable 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(OnlineTable onlineTable, OnlineTable originalOnlineTable); + + /** + * 删除指定表及其关联的字段数据。 + * + * @param tableId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long tableId); + + /** + * 删除指定数据表Id集合中的表,及其关联字段。 + * + * @param tableIdSet 待删除的数据表Id集合。 + */ + void removeByTableIdSet(Set tableIdSet); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineTableListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineTableList(OnlineTable filter, String orderBy); + + /** + * 获取指定在线表Id集合的对象列表。 + * + * @param tableIdSet 主键Id集合。 + * @return 指定的数据表对象列表。 + */ + List getOnlineTableList(Set tableIdSet); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineTableList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineTableListWithRelation(OnlineTable filter, String orderBy); + + /** + * 根据数据源Id,获取该数据源及其关联所引用的数据表列表。 + * + * @param datasourceId 指定的数据源Id。 + * @return 该数据源及其关联所引用的数据表列表。 + */ + List getOnlineTableListByDatasourceId(Long datasourceId); + + /** + * 从缓存中获取指定的表数据及其关联字段列表。优先从缓存中读取,如果不存在则从数据库中读取,并同步到缓存。 + * 该接口方法仅仅用户在线表单的动态数据操作接口,而非在线表单的配置接口。 + * + * @param tableId 表主键Id。 + * @return 查询后的在线表对象。 + */ + OnlineTable getOnlineTableFromCache(Long tableId); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineVirtualColumnService.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineVirtualColumnService.java new file mode 100644 index 00000000..fc8a617b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/OnlineVirtualColumnService.java @@ -0,0 +1,78 @@ +package com.flow.demo.common.online.service; + +import com.flow.demo.common.core.base.service.IBaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.online.model.OnlineVirtualColumn; + +import java.util.*; + +/** + * 虚拟字段数据操作服务接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface OnlineVirtualColumnService extends IBaseService { + + /** + * 保存新增对象。 + * + * @param onlineVirtualColumn 新增对象。 + * @return 返回新增对象。 + */ + OnlineVirtualColumn saveNew(OnlineVirtualColumn onlineVirtualColumn); + + /** + * 更新数据对象。 + * + * @param onlineVirtualColumn 更新的对象。 + * @param originalOnlineVirtualColumn 原有数据对象。 + * @return 成功返回true,否则false。 + */ + boolean update(OnlineVirtualColumn onlineVirtualColumn, OnlineVirtualColumn originalOnlineVirtualColumn); + + /** + * 删除指定数据。 + * + * @param virtualColumnId 主键Id。 + * @return 成功返回true,否则false。 + */ + boolean remove(Long virtualColumnId); + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineVirtualColumnListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineVirtualColumnList(OnlineVirtualColumn filter, String orderBy); + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineVirtualColumnList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + List getOnlineVirtualColumnListWithRelation(OnlineVirtualColumn filter, String orderBy); + + /** + * 根据数据表的集合,查询关联的虚拟字段数据列表。 + * @param tableIdSet 在线数据表Id集合。 + * @return 关联的虚拟字段数据列表。 + */ + List getOnlineVirtualColumnListByTableIds(Set tableIdSet); + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param virtualColumn 最新数据对象。 + * @param originalVirtualColumn 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + CallResult verifyRelatedData(OnlineVirtualColumn virtualColumn, OnlineVirtualColumn originalVirtualColumn); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineColumnServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineColumnServiceImpl.java new file mode 100644 index 00000000..2b69fdca --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineColumnServiceImpl.java @@ -0,0 +1,361 @@ +package com.flow.demo.common.online.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.util.RedisKeyUtil; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.dao.OnlineColumnMapper; +import com.flow.demo.common.online.dao.OnlineColumnRuleMapper; +import com.flow.demo.common.online.model.OnlineColumn; +import com.flow.demo.common.online.model.OnlineColumnRule; +import com.flow.demo.common.online.model.constant.FieldFilterType; +import com.flow.demo.common.online.object.SqlTableColumn; +import com.flow.demo.common.online.service.OnlineColumnService; +import com.flow.demo.common.online.service.OnlineTableService; +import com.github.pagehelper.Page; +import com.google.common.base.CaseFormat; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; + +/** + * 字段数据数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlineColumnService") +public class OnlineColumnServiceImpl extends BaseService implements OnlineColumnService { + + @Autowired + private OnlineColumnMapper onlineColumnMapper; + @Autowired + private OnlineColumnRuleMapper onlineColumnRuleMapper; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private IdGeneratorWrapper idGenerator; + @Autowired + private RedissonClient redissonClient; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlineColumnMapper; + } + + /** + * 保存新增数据表字段列表。 + * + * @param columnList 新增数据表字段对象列表。 + * @param onlineTableId 在线表对象的主键Id。 + * @return 插入的在线表字段数据。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public List saveNewList(List columnList, Long onlineTableId) { + List onlineColumnList = new LinkedList<>(); + if (CollUtil.isEmpty(columnList)) { + return onlineColumnList; + } + for (SqlTableColumn column : columnList) { + OnlineColumn onlineColumn = new OnlineColumn(); + BeanUtil.copyProperties(column, onlineColumn, false); + onlineColumn.setColumnId(idGenerator.nextLongId()); + onlineColumn.setTableId(onlineTableId); + this.setDefault(onlineColumn); + onlineColumnMapper.insert(onlineColumn); + onlineColumnList.add(onlineColumn); + } + return onlineColumnList; + } + + /** + * 更新数据对象。 + * + * @param onlineColumn 更新的对象。 + * @param originalOnlineColumn 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlineColumn onlineColumn, OnlineColumn originalOnlineColumn) { + this.evictTableCache(onlineColumn.getTableId()); + onlineColumn.setUpdateTime(new Date()); + onlineColumn.setCreateTime(originalOnlineColumn.getCreateTime()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + UpdateWrapper uw = this.createUpdateQueryForNullValue(onlineColumn, onlineColumn.getColumnId()); + return onlineColumnMapper.update(onlineColumn, uw) == 1; + } + + /** + * 刷新数据库表字段的数据到在线表字段。 + * + * @param sqlTableColumn 源数据库表字段对象。 + * @param onlineColumn 被刷新的在线表字段对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void refresh(SqlTableColumn sqlTableColumn, OnlineColumn onlineColumn) { + this.evictTableCache(onlineColumn.getTableId()); + BeanUtil.copyProperties(sqlTableColumn, onlineColumn, false); + onlineColumnMapper.updateById(onlineColumn); + } + + /** + * 删除指定数据。 + * + * @param tableId 表Id。 + * @param columnId 字段Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long tableId, Long columnId) { + this.evictTableCache(tableId); + return onlineColumnMapper.deleteById(columnId) == 1; + } + + /** + * 当前服务的支持表为从表,根据主表的主键Id,删除一对多的从表数据。 + * + * @param tableId 主表主键Id。 + * @return 删除数量。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int removeByTableId(Long tableId) { + OnlineColumn deletedObject = new OnlineColumn(); + deletedObject.setTableId(tableId); + return onlineColumnMapper.delete(new QueryWrapper<>(deletedObject)); + } + + /** + * 删除指定数据表Id集合中的表字段。 + * + * @param tableIdSet 待删除的数据表Id集合。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void removeByTableIdSet(Set tableIdSet) { + onlineColumnMapper.delete(new QueryWrapper().lambda().in(OnlineColumn::getTableId, tableIdSet)); + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineColumnListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineColumnList(OnlineColumn filter, String orderBy) { + return onlineColumnMapper.getOnlineColumnList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineColumnList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineColumnListWithRelation(OnlineColumn filter, String orderBy) { + List resultList = onlineColumnMapper.getOnlineColumnList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 获取指定数据表Id集合的字段对象列表。 + * + * @param tableIdSet 指定的数据表Id集合。 + * @return 数据表Id集合所包含的字段对象列表。 + */ + @Override + public List getOnlineColumnListByTableIds(Set tableIdSet) { + return onlineColumnMapper.selectList( + new QueryWrapper().lambda().in(OnlineColumn::getTableId, tableIdSet)); + } + + /** + * 根据表Id和字段列名获取指定字段。 + * + * @param tableId 字段所在表Id。 + * @param columnName 字段名。 + * @return 查询出的字段对象。 + */ + @Override + public OnlineColumn getOnlineColumnByTableIdAndColumnName(Long tableId, String columnName) { + OnlineColumn filter = new OnlineColumn(); + filter.setTableId(tableId); + filter.setColumnName(columnName); + return onlineColumnMapper.selectOne(new QueryWrapper<>(filter)); + } + + /** + * 批量添加多对多关联关系。 + * + * @param onlineColumnRuleList 多对多关联表对象集合。 + * @param columnId 主表Id。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void addOnlineColumnRuleList(List onlineColumnRuleList, Long columnId) { + for (OnlineColumnRule onlineColumnRule : onlineColumnRuleList) { + onlineColumnRule.setColumnId(columnId); + onlineColumnRuleMapper.insert(onlineColumnRule); + } + } + + /** + * 更新中间表数据。 + * + * @param onlineColumnRule 中间表对象。 + * @return 更新成功与否。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean updateOnlineColumnRule(OnlineColumnRule onlineColumnRule) { + OnlineColumnRule filter = new OnlineColumnRule(); + filter.setColumnId(onlineColumnRule.getColumnId()); + filter.setRuleId(onlineColumnRule.getRuleId()); + UpdateWrapper uw = + BaseService.createUpdateQueryForNullValue(onlineColumnRule, OnlineColumnRule.class); + uw.setEntity(filter); + return onlineColumnRuleMapper.update(onlineColumnRule, uw) > 0; + } + + /** + * 获取中间表数据。 + * + * @param columnId 主表Id。 + * @param ruleId 从表Id。 + * @return 中间表对象。 + */ + @Override + public OnlineColumnRule getOnlineColumnRule(Long columnId, Long ruleId) { + OnlineColumnRule filter = new OnlineColumnRule(); + filter.setColumnId(columnId); + filter.setRuleId(ruleId); + return onlineColumnRuleMapper.selectOne(new QueryWrapper<>(filter)); + } + + /** + * 移除单条多对多关系。 + * + * @param columnId 主表Id。 + * @param ruleId 从表Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean removeOnlineColumnRule(Long columnId, Long ruleId) { + OnlineColumnRule filter = new OnlineColumnRule(); + filter.setColumnId(columnId); + filter.setRuleId(ruleId); + return onlineColumnRuleMapper.delete(new QueryWrapper<>(filter)) > 0; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param onlineColumn 最新数据对象。 + * @param originalOnlineColumn 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + @Override + public CallResult verifyRelatedData(OnlineColumn onlineColumn, OnlineColumn originalOnlineColumn) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是一对多的验证 + if (this.needToVerify(onlineColumn, originalOnlineColumn, OnlineColumn::getTableId) + && !onlineTableService.existId(onlineColumn.getTableId())) { + return CallResult.error(String.format(errorMessageFormat, "数据表Id")); + } + return CallResult.ok(); + } + + private void setDefault(OnlineColumn onlineColumn) { + String objectFieldName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, onlineColumn.getColumnName()); + onlineColumn.setObjectFieldName(objectFieldName); + String objectFieldType = convertToJavaType(onlineColumn.getColumnType()); + onlineColumn.setObjectFieldType(objectFieldType); + onlineColumn.setFilterType(FieldFilterType.NO_FILTER); + onlineColumn.setParentKey(false); + onlineColumn.setDeptFilter(false); + onlineColumn.setUserFilter(false); + Date now = new Date(); + onlineColumn.setUpdateTime(now); + onlineColumn.setCreateTime(now); + } + + private void evictTableCache(Long tableId) { + String tableIdKey = RedisKeyUtil.makeOnlineTableKey(tableId); + redissonClient.getBucket(tableIdKey).delete(); + } + + private String convertToJavaType(String columnType) { + if ("varchar".equals(columnType) + || "char".equals(columnType) + || "text".equals(columnType) + || "longtext".equals(columnType) + || "mediumtext".equals(columnType) + || "tinytext".equals(columnType)) { + return "String"; + } + if ("int".equals(columnType) + || "mediumint".equals(columnType) + || "smallint".equals(columnType) + || "tinyint".equals(columnType)) { + return "Integer"; + } + if ("bit".equals(columnType)) { + return "Boolean"; + } + if ("bigint".equals(columnType)) { + return "Long"; + } + if ("decimal".equals(columnType)) { + return "BigDecimal"; + } + if ("float".equals(columnType) + || "double".equals(columnType)) { + return "Double"; + } + if ("date".equals(columnType) + || "datetime".equals(columnType) + || "timestamp".equals(columnType) + || "time".equals(columnType)) { + return "Date"; + } + if ("blob".equals(columnType)) { + return "byte[]"; + } + throw new RuntimeException("Unsupported Data Type"); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDatasourceRelationServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDatasourceRelationServiceImpl.java new file mode 100644 index 00000000..713b2c70 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDatasourceRelationServiceImpl.java @@ -0,0 +1,255 @@ +package com.flow.demo.common.online.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.dao.OnlineDatasourceRelationMapper; +import com.flow.demo.common.online.dao.OnlineDatasourceTableMapper; +import com.flow.demo.common.online.model.OnlineColumn; +import com.flow.demo.common.online.model.OnlineDatasourceRelation; +import com.flow.demo.common.online.model.OnlineDatasourceTable; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.object.SqlTable; +import com.flow.demo.common.online.object.SqlTableColumn; +import com.flow.demo.common.online.service.OnlineColumnService; +import com.flow.demo.common.online.service.OnlineDatasourceRelationService; +import com.flow.demo.common.online.service.OnlineDatasourceService; +import com.flow.demo.common.online.service.OnlineTableService; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** + * 数据源关联数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlineDatasourceRelationService") +public class OnlineDatasourceRelationServiceImpl + extends BaseService implements OnlineDatasourceRelationService { + + @Autowired + private OnlineDatasourceRelationMapper onlineDatasourceRelationMapper; + @Autowired + private OnlineDatasourceTableMapper onlineDatasourceTableMapper; + @Autowired + private OnlineDatasourceService onlineDatasourceService; + @Autowired + private OnlineColumnService onlineColumnService; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlineDatasourceRelationMapper; + } + + /** + * 保存新增对象。 + * + * @param relation 新增对象。 + * @param slaveSqlTable 新增的关联从数据表对象。 + * @param slaveSqlColumn 新增的关联从数据表对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public OnlineDatasourceRelation saveNew( + OnlineDatasourceRelation relation, SqlTable slaveSqlTable, SqlTableColumn slaveSqlColumn) { + // 查找数据源关联的数据表,判断当前关联的从表,是否已经存在于zz_online_datasource_table中了。 + // 对于同一个数据源及其关联,同一个数据表只会被创建一次,如果已经和当前数据源的其他Relation, + // 作为从表绑定了,怎么就可以直接使用这个OnlineTable了,否则就会为这个SqlTable,创建对应的OnlineTable。 + List datasourceTableList = + onlineTableService.getOnlineTableListByDatasourceId(relation.getDatasourceId()); + OnlineTable relationSlaveTable = null; + OnlineColumn relationSlaveColumn = null; + for (OnlineTable onlineTable : datasourceTableList) { + if (onlineTable.getTableName().equals(slaveSqlTable.getTableName())) { + relationSlaveTable = onlineTable; + relationSlaveColumn = onlineColumnService.getOnlineColumnByTableIdAndColumnName( + onlineTable.getTableId(), slaveSqlColumn.getColumnName()); + break; + } + } + if (relationSlaveTable == null) { + relationSlaveTable = onlineTableService.saveNewFromSqlTable(slaveSqlTable); + for (OnlineColumn onlineColumn : relationSlaveTable.getColumnList()) { + if (onlineColumn.getColumnName().equals(slaveSqlColumn.getColumnName())) { + relationSlaveColumn = onlineColumn; + break; + } + } + } + relation.setRelationId(idGenerator.nextLongId()); + relation.setSlaveTableId(relationSlaveTable.getTableId()); + relation.setSlaveColumnId(relationSlaveColumn.getColumnId()); + Date now = new Date(); + relation.setUpdateTime(now); + relation.setCreateTime(now); + onlineDatasourceRelationMapper.insert(relation); + OnlineDatasourceTable datasourceTable = new OnlineDatasourceTable(); + datasourceTable.setId(idGenerator.nextLongId()); + datasourceTable.setDatasourceId(relation.getDatasourceId()); + datasourceTable.setRelationId(relation.getRelationId()); + datasourceTable.setTableId(relation.getSlaveTableId()); + onlineDatasourceTableMapper.insert(datasourceTable); + return relation; + } + + /** + * 更新数据对象。 + * + * @param relation 更新的对象。 + * @param originalRelation 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlineDatasourceRelation relation, OnlineDatasourceRelation originalRelation) { + relation.setUpdateTime(new Date()); + relation.setCreateTime(originalRelation.getCreateTime()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + UpdateWrapper uw = + this.createUpdateQueryForNullValue(relation, relation.getRelationId()); + return onlineDatasourceRelationMapper.update(relation, uw) == 1; + } + + /** + * 删除指定数据。 + * + * @param relationId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long relationId) { + if (onlineDatasourceRelationMapper.deleteById(relationId) != 1) { + return false; + } + OnlineDatasourceTable filter = new OnlineDatasourceTable(); + filter.setRelationId(relationId); + QueryWrapper queryWrapper = new QueryWrapper<>(filter); + OnlineDatasourceTable datasourceTable = onlineDatasourceTableMapper.selectOne(queryWrapper); + onlineDatasourceTableMapper.delete(queryWrapper); + filter = new OnlineDatasourceTable(); + filter.setDatasourceId(datasourceTable.getDatasourceId()); + filter.setTableId(datasourceTable.getTableId()); + // 不在有引用该表的时候,可以删除该数据源关联引用的从表了。 + if (onlineDatasourceTableMapper.selectCount(new QueryWrapper<>(filter)) == 0) { + onlineTableService.remove(datasourceTable.getTableId()); + } + return true; + } + + /** + * 当前服务的支持表为从表,根据主表的主键Id,删除一对多的从表数据。 + * + * @param datasourceId 主表主键Id。 + * @return 删除数量。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int removeByDatasourceId(Long datasourceId) { + OnlineDatasourceRelation deletedObject = new OnlineDatasourceRelation(); + deletedObject.setDatasourceId(datasourceId); + return onlineDatasourceRelationMapper.delete(new QueryWrapper<>(deletedObject)); + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineDatasourceRelationListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDatasourceRelationListByDatasourceIds( + OnlineDatasourceRelation filter, String orderBy) { + return onlineDatasourceRelationMapper.getOnlineDatasourceRelationList(filter, orderBy); + } + + /** + * 获取指定数据源Id集合下的所有数据源关联列表。 + * + * @param datasourceIdSet 数据源Id集合。 + * @param relationType 关联类型,如果为空,则查询全部类型。 + * @return 指定数据源下的所有关联列表。 + */ + @Override + public List getOnlineDatasourceRelationListByDatasourceIds( + Set datasourceIdSet, Integer relationType) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.lambda().in(OnlineDatasourceRelation::getDatasourceId, datasourceIdSet); + if (relationType != null) { + queryWrapper.lambda().eq(OnlineDatasourceRelation::getRelationType, relationType); + } + return onlineDatasourceRelationMapper.selectList(queryWrapper); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineDatasourceRelationList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDatasourceRelationListWithRelation( + OnlineDatasourceRelation filter, String orderBy) { + List resultList = + onlineDatasourceRelationMapper.getOnlineDatasourceRelationList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param relation 最新数据对象。 + * @param originalRelation 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + @Override + public CallResult verifyRelatedData( + OnlineDatasourceRelation relation, OnlineDatasourceRelation originalRelation) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + if (this.needToVerify(relation, originalRelation, OnlineDatasourceRelation::getMasterColumnId) + && !onlineColumnService.existId(relation.getMasterColumnId())) { + return CallResult.error(String.format(errorMessageFormat, "主表关联字段Id")); + } + if (this.needToVerify(relation, originalRelation, OnlineDatasourceRelation::getSlaveTableId) + && !onlineTableService.existId(relation.getSlaveTableId())) { + return CallResult.error(String.format(errorMessageFormat, "从表Id")); + } + if (this.needToVerify(relation, originalRelation, OnlineDatasourceRelation::getSlaveColumnId) + && !onlineColumnService.existId(relation.getSlaveColumnId())) { + return CallResult.error(String.format(errorMessageFormat, "从表关联字段Id")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDatasourceServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDatasourceServiceImpl.java new file mode 100644 index 00000000..f753e008 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDatasourceServiceImpl.java @@ -0,0 +1,238 @@ +package com.flow.demo.common.online.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.dao.OnlineDatasourceMapper; +import com.flow.demo.common.online.dao.OnlineDatasourceTableMapper; +import com.flow.demo.common.online.dao.OnlinePageDatasourceMapper; +import com.flow.demo.common.online.model.OnlineDatasource; +import com.flow.demo.common.online.model.OnlineDatasourceTable; +import com.flow.demo.common.online.model.OnlinePageDatasource; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.object.SqlTable; +import com.flow.demo.common.online.service.OnlineDatasourceRelationService; +import com.flow.demo.common.online.service.OnlineDatasourceService; +import com.flow.demo.common.online.service.OnlineTableService; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 数据模型数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlineDatasourceService") +public class OnlineDatasourceServiceImpl extends BaseService implements OnlineDatasourceService { + + @Autowired + private OnlineDatasourceMapper onlineDatasourceMapper; + @Autowired + private OnlinePageDatasourceMapper onlinePageDatasourceMapper; + @Autowired + private OnlineDatasourceTableMapper onlineDatasourceTableMapper; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private OnlineDatasourceRelationService onlineDatasourceRelationService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlineDatasourceMapper; + } + + /** + * 保存新增对象。 + * + * @param onlineDatasource 新增对象。 + * @param sqlTable 新增的数据表对象。 + * @param pageId 关联的页面Id。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public OnlineDatasource saveNew(OnlineDatasource onlineDatasource, SqlTable sqlTable, Long pageId) { + OnlineTable onlineTable = onlineTableService.saveNewFromSqlTable(sqlTable); + onlineDatasource.setDatasourceId(idGenerator.nextLongId()); + onlineDatasource.setMasterTableId(onlineTable.getTableId()); + Date now = new Date(); + onlineDatasource.setUpdateTime(now); + onlineDatasource.setCreateTime(now); + onlineDatasourceMapper.insert(onlineDatasource); + OnlineDatasourceTable datasourceTable = new OnlineDatasourceTable(); + datasourceTable.setId(idGenerator.nextLongId()); + datasourceTable.setDatasourceId(onlineDatasource.getDatasourceId()); + datasourceTable.setTableId(onlineDatasource.getMasterTableId()); + onlineDatasourceTableMapper.insert(datasourceTable); + OnlinePageDatasource onlinePageDatasource = new OnlinePageDatasource(); + onlinePageDatasource.setId(idGenerator.nextLongId()); + onlinePageDatasource.setPageId(pageId); + onlinePageDatasource.setDatasourceId(onlineDatasource.getDatasourceId()); + onlinePageDatasourceMapper.insert(onlinePageDatasource); + return onlineDatasource; + } + + /** + * 更新数据对象。 + * + * @param onlineDatasource 更新的对象。 + * @param originalOnlineDatasource 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlineDatasource onlineDatasource, OnlineDatasource originalOnlineDatasource) { + onlineDatasource.setUpdateTime(new Date()); + onlineDatasource.setCreateTime(originalOnlineDatasource.getCreateTime()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + UpdateWrapper uw = + this.createUpdateQueryForNullValue(onlineDatasource, onlineDatasource.getDatasourceId()); + return onlineDatasourceMapper.update(onlineDatasource, uw) == 1; + } + + /** + * 删除指定数据。 + * + * @param datasourceId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long datasourceId) { + if (onlineDatasourceMapper.deleteById(datasourceId) == 0) { + return false; + } + onlineDatasourceRelationService.removeByDatasourceId(datasourceId); + // 开始删除多对多父表的关联 + OnlinePageDatasource onlinePageDatasource = new OnlinePageDatasource(); + onlinePageDatasource.setDatasourceId(datasourceId); + onlinePageDatasourceMapper.delete(new QueryWrapper<>(onlinePageDatasource)); + OnlineDatasourceTable filter = new OnlineDatasourceTable(); + filter.setDatasourceId(datasourceId); + QueryWrapper queryWrapper = new QueryWrapper<>(filter); + List datasourceTableList = onlineDatasourceTableMapper.selectList(queryWrapper); + onlineDatasourceTableMapper.delete(queryWrapper); + Set tableIdSet = datasourceTableList.stream() + .map(OnlineDatasourceTable::getTableId).collect(Collectors.toSet()); + onlineTableService.removeByTableIdSet(tableIdSet); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineDatasourceListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDatasourceList(OnlineDatasource filter, String orderBy) { + return onlineDatasourceMapper.getOnlineDatasourceList(filter, orderBy); + } + + /** + * 查询指定数据源Id集合的数据源列表。 + * + * @param datasourceIdSet 数据源Id集合。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDatasourceList(Set datasourceIdSet) { + return onlineDatasourceMapper.selectBatchIds(datasourceIdSet); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineDatasourceList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDatasourceListWithRelation(OnlineDatasource filter, String orderBy) { + List resultList = onlineDatasourceMapper.getOnlineDatasourceList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param pageId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getNotInOnlineDatasourceListByPageId(Long pageId, OnlineDatasource filter, String orderBy) { + List resultList = + onlineDatasourceMapper.getNotInOnlineDatasourceListByPageId(pageId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly()); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回与指定主表主键Id存在对多对关系的列表。 + * + * @param pageId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDatasourceListByPageId(Long pageId, OnlineDatasource filter, String orderBy) { + List resultList = + onlineDatasourceMapper.getOnlineDatasourceListByPageId(pageId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly()); + return resultList; + } + + /** + * 获取指定数据源Id集合所关联的在线表关联数据。 + * + * @param datasourceIdSet 数据源Id集合。 + * @return 数据源和数据表的多对多关联列表。 + */ + @Override + public List getOnlineDatasourceTableList(Set datasourceIdSet) { + return onlineDatasourceTableMapper.selectList(new QueryWrapper() + .lambda().in(OnlineDatasourceTable::getDatasourceId, datasourceIdSet)); + } + + /** + * 根据在线表单Id集合,获取关联的在线数据源对象列表。 + * + * @param formIdSet 在线表单Id集合。 + * @return 与参数表单Id关联的数据源列表。 + */ + @Override + public List getOnlineDatasourceListByFormIds(Set formIdSet) { + return onlineDatasourceMapper.getOnlineDatasourceListByFormIds(formIdSet); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDblinkServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDblinkServiceImpl.java new file mode 100644 index 00000000..79cb2740 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDblinkServiceImpl.java @@ -0,0 +1,205 @@ +package com.flow.demo.common.online.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.config.DataSourceContextHolder; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.config.OnlineProperties; +import com.flow.demo.common.online.dao.OnlineDblinkMapper; +import com.flow.demo.common.online.model.OnlineDblink; +import com.flow.demo.common.online.object.SqlTable; +import com.flow.demo.common.online.object.SqlTableColumn; +import com.flow.demo.common.online.service.OnlineDblinkService; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.io.Serializable; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 数据库链接数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlineDblinkService") +public class OnlineDblinkServiceImpl extends BaseService implements OnlineDblinkService { + + @Autowired + private OnlineDblinkMapper onlineDblinkMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + @Autowired + private OnlineProperties onlineProperties; + + private Map dblinkMap; + + @PostConstruct + public void loadAllDblink() { + List dblinkList = super.getAllList(); + this.dblinkMap = dblinkList.stream().collect(Collectors.toMap(OnlineDblink::getDblinkId, c -> c)); + } + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlineDblinkMapper; + } + + /** + * 根据主键Id,从本地缓存中读取数据库链接信息。 + * 这里之所以不考虑缓存补偿,是因为如果出现新的用于在线表单的数据库链接,我们也需要修改当前服务的多数据源配置才能正常工作, + * 否则新OnlineDblink的ConstantType,没法保证正常的数据源切换。 + * + * @param dblinkId 数据库链接Id。 + * @return 查询到的OnlineDblink对象。 + */ + @Override + public OnlineDblink getById(Serializable dblinkId) { + return dblinkMap.get(dblinkId); + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineDblinkListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDblinkList(OnlineDblink filter, String orderBy) { + return onlineDblinkMapper.getOnlineDblinkList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineDblinkList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDblinkListWithRelation(OnlineDblink filter, String orderBy) { + List resultList = onlineDblinkMapper.getOnlineDblinkList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 获取指定DBLink下面的全部数据表。 + * + * @param dblink 数据库链接对象。 + * @return 全部数据表列表。 + */ + @Override + public List getDblinkTableList(OnlineDblink dblink) { + Integer originalType = DataSourceContextHolder.setDataSourceType(dblink.getDblinkConfigConstant()); + try { + List> resultList = + onlineDblinkMapper.getTableListWithPrefix(onlineProperties.getTablePrefix()); + List tableList = new LinkedList<>(); + resultList.forEach(r -> { + SqlTable sqlTable = BeanUtil.mapToBean(r, SqlTable.class, false, null); + sqlTable.setDblinkId(dblink.getDblinkId()); + tableList.add(sqlTable); + }); + return tableList; + } finally { + DataSourceContextHolder.unset(originalType); + } + } + + /** + * X + * 获取指定DBLink下,指定表名的数据表对象,及其关联字段列表。 + * + * @param dblink 数据库链接对象。 + * @param tableName 数据库中的数据表名。 + * @return 数据表对象。 + */ + @Override + public SqlTable getDblinkTable(OnlineDblink dblink, String tableName) { + Integer originalType = DataSourceContextHolder.setDataSourceType(dblink.getDblinkConfigConstant()); + try { + Map result = onlineDblinkMapper.getTableByName(tableName); + if (result == null) { + return null; + } + SqlTable sqlTable = BeanUtil.mapToBean(result, SqlTable.class, false, null); + sqlTable.setDblinkId(dblink.getDblinkId()); + sqlTable.setColumnList(getDblinkTableColumnList(dblink, tableName)); + return sqlTable; + } finally { + DataSourceContextHolder.unset(originalType); + } + } + + /** + * 获取指定DBLink下,指定表名的字段列表。 + * + * @param dblink 数据库链接对象。 + * @param tableName 表名。 + * @return 表的字段列表。 + */ + @Override + public List getDblinkTableColumnList(OnlineDblink dblink, String tableName) { + Integer originalType = DataSourceContextHolder.setDataSourceType(dblink.getDblinkConfigConstant()); + try { + List> resultList = onlineDblinkMapper.getTableColumnList(tableName); + List columnList = new LinkedList<>(); + resultList.forEach(r -> { + SqlTableColumn sqlTableColumn = + BeanUtil.mapToBean(r, SqlTableColumn.class, false, null); + sqlTableColumn.setAutoIncrement("auto_increment".equals(sqlTableColumn.getExtra())); + columnList.add(sqlTableColumn); + }); + return columnList; + } finally { + DataSourceContextHolder.unset(originalType); + } + } + + /** + * 获取指定DBLink下,指定表的字段对象。 + * + * @param dblink 数据库链接对象。 + * @param tableName 数据库中的数据表名。 + * @param columnName 数据库中的数据表的字段名。 + * @return 表的字段对象。 + */ + @Override + public SqlTableColumn getDblinkTableColumn(OnlineDblink dblink, String tableName, String columnName) { + Integer originalType = DataSourceContextHolder.setDataSourceType(dblink.getDblinkConfigConstant()); + try { + Map result = onlineDblinkMapper.getTableColumnByName(tableName, columnName); + if (result == null) { + return null; + } + SqlTableColumn sqlTableColumn = + BeanUtil.mapToBean(result, SqlTableColumn.class, false, null); + sqlTableColumn.setAutoIncrement("auto_increment".equals(sqlTableColumn.getExtra())); + return sqlTableColumn; + } finally { + DataSourceContextHolder.unset(originalType); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDictServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDictServiceImpl.java new file mode 100644 index 00000000..b7b9a4da --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineDictServiceImpl.java @@ -0,0 +1,157 @@ +package com.flow.demo.common.online.service.impl; + +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.dao.OnlineDictMapper; +import com.flow.demo.common.online.model.OnlineDict; +import com.flow.demo.common.online.service.OnlineDblinkService; +import com.flow.demo.common.online.service.OnlineDictService; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** + * 在线表单字典数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlineDictService") +public class OnlineDictServiceImpl extends BaseService implements OnlineDictService { + + @Autowired + private OnlineDictMapper onlineDictMapper; + @Autowired + private OnlineDblinkService dblinkService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlineDictMapper; + } + + /** + * 保存新增对象。 + * + * @param onlineDict 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public OnlineDict saveNew(OnlineDict onlineDict) { + onlineDict.setDictId(idGenerator.nextLongId()); + Date now = new Date(); + onlineDict.setUpdateTime(now); + onlineDict.setCreateTime(now); + onlineDictMapper.insert(onlineDict); + return onlineDict; + } + + /** + * 更新数据对象。 + * + * @param onlineDict 更新的对象。 + * @param originalOnlineDict 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlineDict onlineDict, OnlineDict originalOnlineDict) { + onlineDict.setUpdateTime(new Date()); + onlineDict.setCreateTime(originalOnlineDict.getCreateTime()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + UpdateWrapper uw = this.createUpdateQueryForNullValue(onlineDict, onlineDict.getDictId()); + return onlineDictMapper.update(onlineDict, uw) == 1; + } + + /** + * 删除指定数据。 + * + * @param dictId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long dictId) { + return onlineDictMapper.deleteById(dictId) == 1; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineDictListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDictList(OnlineDict filter, String orderBy) { + return onlineDictMapper.getOnlineDictList(filter, orderBy); + } + + /** + * 根据指定字典Id集合返回字段对象数据列表。 + * + * @param dictIdSet 字典Id集合。 + * @return 查询后的字典对象列表。 + */ + @Override + public List getOnlineDictList(Set dictIdSet) { + return onlineDictMapper.selectBatchIds(dictIdSet); + } + + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineDictList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineDictListWithRelation(OnlineDict filter, String orderBy) { + List resultList = onlineDictMapper.getOnlineDictList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param onlineDict 最新数据对象。 + * @param originalOnlineDict 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + @Override + public CallResult verifyRelatedData(OnlineDict onlineDict, OnlineDict originalOnlineDict) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(onlineDict, originalOnlineDict, OnlineDict::getDblinkId) + && !dblinkService.existId(onlineDict.getDblinkId())) { + return CallResult.error(String.format(errorMessageFormat, "数据库链接主键id")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineFormServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineFormServiceImpl.java new file mode 100644 index 00000000..ecf17d60 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineFormServiceImpl.java @@ -0,0 +1,262 @@ +package com.flow.demo.common.online.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.dao.OnlineFormDatasourceMapper; +import com.flow.demo.common.online.dao.OnlineFormMapper; +import com.flow.demo.common.online.model.OnlineForm; +import com.flow.demo.common.online.model.OnlineFormDatasource; +import com.flow.demo.common.online.service.OnlineFormService; +import com.flow.demo.common.online.service.OnlinePageService; +import com.flow.demo.common.online.service.OnlineTableService; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 在线表单数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlineFormService") +public class OnlineFormServiceImpl extends BaseService implements OnlineFormService { + + @Autowired + private OnlineFormMapper onlineFormMapper; + @Autowired + private OnlineFormDatasourceMapper onlineFormDatasourceMapper; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private OnlinePageService onlinePageService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlineFormMapper; + } + + /** + * 保存新增对象。 + * + * @param onlineForm 新增对象。 + * @param datasourceIdSet 在线表单关联的数据源Id集合。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public OnlineForm saveNew(OnlineForm onlineForm, Set datasourceIdSet) { + onlineForm.setFormId(idGenerator.nextLongId()); + Date now = new Date(); + onlineForm.setUpdateTime(now); + onlineForm.setCreateTime(now); + onlineFormMapper.insert(onlineForm); + if (CollUtil.isNotEmpty(datasourceIdSet)) { + for (Long datasourceId : datasourceIdSet) { + OnlineFormDatasource onlineFormDatasource = new OnlineFormDatasource(); + onlineFormDatasource.setId(idGenerator.nextLongId()); + onlineFormDatasource.setFormId(onlineForm.getFormId()); + onlineFormDatasource.setDatasourceId(datasourceId); + onlineFormDatasourceMapper.insert(onlineFormDatasource); + } + } + return onlineForm; + } + + /** + * 更新数据对象。 + * + * @param onlineForm 更新的对象。 + * @param originalOnlineForm 原有数据对象。 + * @param datasourceIdSet 在线表单关联的数据源Id集合。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlineForm onlineForm, OnlineForm originalOnlineForm, Set datasourceIdSet) { + onlineForm.setUpdateTime(new Date()); + onlineForm.setCreateTime(originalOnlineForm.getCreateTime()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + UpdateWrapper uw = this.createUpdateQueryForNullValue(onlineForm, onlineForm.getFormId()); + if (onlineFormMapper.update(onlineForm, uw) != 1) { + return false; + } + OnlineFormDatasource formDatasourceFilter = new OnlineFormDatasource(); + formDatasourceFilter.setFormId(onlineForm.getFormId()); + onlineFormDatasourceMapper.delete(new QueryWrapper<>(formDatasourceFilter)); + if (CollUtil.isNotEmpty(datasourceIdSet)) { + for (Long datasourceId : datasourceIdSet) { + OnlineFormDatasource onlineFormDatasource = new OnlineFormDatasource(); + onlineFormDatasource.setId(idGenerator.nextLongId()); + onlineFormDatasource.setFormId(onlineForm.getFormId()); + onlineFormDatasource.setDatasourceId(datasourceId); + onlineFormDatasourceMapper.insert(onlineFormDatasource); + } + } + return true; + } + + /** + * 删除指定数据。 + * + * @param formId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long formId) { + if (onlineFormMapper.deleteById(formId) != 1) { + return false; + } + OnlineFormDatasource formDatasourceFilter = new OnlineFormDatasource(); + formDatasourceFilter.setFormId(formId); + onlineFormDatasourceMapper.delete(new QueryWrapper<>(formDatasourceFilter)); + return true; + } + + /** + * 根据PageId,删除其所属的所有表单,以及表单关联的数据源数据。 + * + * @param pageId 指定的pageId。 + * @return 删除数量。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public int removeByPageId(Long pageId) { + OnlineForm filter = new OnlineForm(); + filter.setPageId(pageId); + List formList = onlineFormMapper.selectList(new QueryWrapper<>(filter)); + Set formIdSet = formList.stream().map(OnlineForm::getFormId).collect(Collectors.toSet()); + if (CollUtil.isNotEmpty(formIdSet)) { + onlineFormDatasourceMapper.delete( + new QueryWrapper().lambda().in(OnlineFormDatasource::getFormId, formIdSet)); + } + return onlineFormMapper.delete(new QueryWrapper<>(filter)); + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineFormListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineFormList(OnlineForm filter, String orderBy) { + return onlineFormMapper.getOnlineFormList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineFormList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineFormListWithRelation(OnlineForm filter, String orderBy) { + List resultList = onlineFormMapper.getOnlineFormList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 获取使用指定数据表的表单列表。 + * + * @param tableId 数据表Id。 + * @return 使用该数据表的表单列表。 + */ + @Override + public List getOnlineFormListByTableId(Long tableId) { + OnlineForm filter = new OnlineForm(); + filter.setMasterTableId(tableId); + return onlineFormMapper.selectList(new QueryWrapper<>(filter)); + } + + /** + * 获取指定表单的数据源列表。 + * + * @param formId 指定的表单。 + * @return 表单和数据源的多对多关联对象列表。 + */ + @Override + public List getFormDatasourceListByFormId(Long formId) { + return onlineFormDatasourceMapper.selectList( + new QueryWrapper().lambda().eq(OnlineFormDatasource::getFormId, formId)); + } + + /** + * 查询正在使用当前数据源的表单。 + * + * @param datasourceId 数据源Id。 + * @return 正在使用当前数据源的表单列表。 + */ + @Override + public List getOnlineFormListByDatasourceId(Long datasourceId) { + List formDatasourceList = onlineFormDatasourceMapper.selectList( + new QueryWrapper().lambda().eq(OnlineFormDatasource::getDatasourceId, datasourceId)); + if (CollUtil.isEmpty(formDatasourceList)) { + return new LinkedList<>(); + } + Collection formIdSet = formDatasourceList.stream() + .map(OnlineFormDatasource::getFormId).collect(Collectors.toSet()); + return onlineFormMapper.selectList( + new QueryWrapper().lambda().in(OnlineForm::getFormId, formIdSet)); + } + + @Override + public List getOnlineFormListByPageIds(Set pageIdSet) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(OnlineForm::getPageId, pageIdSet); + return onlineFormMapper.selectList(queryWrapper); + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param onlineForm 最新数据对象。 + * @param originalOnlineForm 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + @Override + public CallResult verifyRelatedData(OnlineForm onlineForm, OnlineForm originalOnlineForm) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + //这里是基于字典的验证。 + if (this.needToVerify(onlineForm, originalOnlineForm, OnlineForm::getMasterTableId) + && !onlineTableService.existId(onlineForm.getMasterTableId())) { + return CallResult.error(String.format(errorMessageFormat, "表单主表id")); + } + //这里是一对多的验证 + if (this.needToVerify(onlineForm, originalOnlineForm, OnlineForm::getPageId) + && !onlinePageService.existId(onlineForm.getPageId())) { + return CallResult.error(String.format(errorMessageFormat, "页面id")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineOperationServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineOperationServiceImpl.java new file mode 100644 index 00000000..b649e4a2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineOperationServiceImpl.java @@ -0,0 +1,973 @@ +package com.flow.demo.common.online.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.core.map.MapUtil; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.flow.demo.common.core.annotation.MyDataSourceResolver; +import com.flow.demo.common.core.constant.AggregationType; +import com.flow.demo.common.core.exception.NoDataPermException; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.object.MyWhereCriteria; +import com.flow.demo.common.core.object.TokenData; +import com.flow.demo.common.core.object.Tuple2; +import com.flow.demo.common.core.util.RedisKeyUtil; +import com.flow.demo.common.datafilter.constant.DataPermRuleType; +import com.flow.demo.common.datafilter.config.DataFilterProperties; +import com.flow.demo.common.online.model.constant.*; +import com.flow.demo.common.online.service.OnlineVirtualColumnService; +import com.flow.demo.common.online.util.OnlineOperationHelper; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.util.OnlineDataSourceResolver; +import com.flow.demo.common.online.util.OnlineConstant; +import com.flow.demo.common.online.dao.OnlineOperationMapper; +import com.flow.demo.common.online.dto.OnlineFilterDto; +import com.flow.demo.common.online.model.*; +import com.flow.demo.common.online.object.ColumnData; +import com.flow.demo.common.online.object.JoinTableInfo; +import com.flow.demo.common.online.service.OnlineDictService; +import com.flow.demo.common.online.service.OnlineOperationService; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Multimap; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.redisson.api.RBucket; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.*; +import java.util.stream.Collectors; + +/** + * 在线表单运行时数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@MyDataSourceResolver(resolver = OnlineDataSourceResolver.class) +@Slf4j +@Service("onlineOperationService") +public class OnlineOperationServiceImpl implements OnlineOperationService { + + @Autowired + private OnlineOperationMapper onlineOperationMapper; + @Autowired + private OnlineDictService onlineDictService; + @Autowired + private OnlineVirtualColumnService onlineVirtualColumnService; + @Autowired + private OnlineOperationHelper onlineOperationHelper; + @Autowired + private IdGeneratorWrapper idGenerator; + @Autowired + private RedissonClient redissonClient; + @Autowired + private DataFilterProperties dataFilterProperties; + + /** + * 聚合返回数据中,聚合键的常量字段名。 + * 如select groupColumn groupedKey, max(aggregationColumn) aggregatedValue。 + */ + public static final String KEY_NAME = "groupedKey"; + /** + * 聚合返回数据中,聚合值的常量字段名。 + * 如select groupColumn groupedKey, max(aggregationColumn) aggregatedValue。 + */ + public static final String VALUE_NAME = "aggregatedValue"; + + @Transactional(rollbackFor = Exception.class) + @Override + public Object saveNew(OnlineTable table, List columnDataList) { + String tableName = table.getTableName(); + String columnNames = this.makeColumnNames(columnDataList); + List columnValueList = new LinkedList<>(); + Object id = null; + // 这里逐个处理每一行数据,特别是非自增主键、createUserId、createTime、逻辑删除等特殊属性的字段。 + for (ColumnData columnData : columnDataList) { + if (!columnData.getColumn().getAutoIncrement()) { + this.makeupColumnValue(columnData); + columnValueList.add(columnData.getColumnValue()); + if (columnData.getColumn().getPrimaryKey()) { + id = columnData.getColumnValue(); + } + } + } + onlineOperationMapper.insert(tableName, columnNames, columnValueList); + return id; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public Object saveNewAndSlaveRelation( + OnlineTable masterTable, + List columnDataList, + Map>> slaveDataListMap) { + Object id = this.saveNew(masterTable, columnDataList); + // 迭代多个一对多关联。 + for (Map.Entry>> entry : slaveDataListMap.entrySet()) { + Long masterColumnId = entry.getKey().getMasterColumnId(); + ColumnData masterColumnData = null; + for (ColumnData columnData : columnDataList) { + if (columnData.getColumn().getColumnId().equals(masterColumnId)) { + masterColumnData = columnData; + break; + } + } + Long slaveColumnId = entry.getKey().getSlaveColumnId(); + // 迭代一对多关联中的数据集合 + for (List slaveColumnDataList : entry.getValue()) { + // 迭代一对多关联记录的字段列表。 + for (ColumnData slaveColumnData : slaveColumnDataList) { + if (slaveColumnData.getColumn().getColumnId().equals(slaveColumnId)) { + slaveColumnData.setColumnValue(masterColumnData.getColumnValue()); + break; + } + } + this.saveNew(entry.getKey().getSlaveTable(), slaveColumnDataList); + } + } + return id; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlineTable table, List columnDataList) { + String tableName = table.getTableName(); + List updateColumnList = new LinkedList<>(); + List whereColumnList = new LinkedList<>(); + for (ColumnData columnData : columnDataList) { + this.makeupColumnValue(columnData); + // 对于以下几种类型的字段,忽略更新。 + if (columnData.getColumn().getPrimaryKey() + || ObjectUtil.equal(columnData.getColumn().getFieldKind(), FieldKind.LOGIC_DELETE)) { + whereColumnList.add(columnData); + continue; + } + if (ObjectUtil.notEqual(columnData.getColumn().getFieldKind(), FieldKind.CREATE_TIME) + && ObjectUtil.notEqual(columnData.getColumn().getFieldKind(), FieldKind.CREATE_USER_ID)) { + updateColumnList.add(columnData); + } + } + if (CollUtil.isEmpty(updateColumnList)) { + return true; + } + String dataPermFilter = this.buildDataPermFilter(table); + return onlineOperationMapper.update(tableName, updateColumnList, whereColumnList, dataPermFilter) == 1; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public boolean updateColumn(OnlineTable table, String dataId, OnlineColumn column, T dataValue) { + List whereColumnList = new LinkedList<>(); + if (table.getLogicDeleteColumn() != null) { + ColumnData logicDeleteColumnData = new ColumnData(); + logicDeleteColumnData.setColumn(table.getLogicDeleteColumn()); + logicDeleteColumnData.setColumnValue(GlobalDeletedFlag.NORMAL); + whereColumnList.add(logicDeleteColumnData); + } + ColumnData primaryKeyColumnData = new ColumnData(); + primaryKeyColumnData.setColumn(table.getPrimaryKeyColumn()); + primaryKeyColumnData.setColumnValue( + onlineOperationHelper.convertToTypeValue(table.getPrimaryKeyColumn(), dataId)); + whereColumnList.add(primaryKeyColumnData); + List updateColumnList = new LinkedList<>(); + ColumnData updateColumnData = new ColumnData(); + updateColumnData.setColumn(column); + updateColumnData.setColumnValue(dataValue); + updateColumnList.add(updateColumnData); + List filterList = + this.makeDefaultFilter(table, table.getPrimaryKeyColumn(), dataId); + String dataPermFilter = this.buildDataPermFilter(table); + return onlineOperationMapper.update( + table.getTableName(), updateColumnList, whereColumnList, dataPermFilter) == 1; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public boolean delete(OnlineTable table, List relationList, String dataId) { + Map masterData = null; + if (CollUtil.isNotEmpty(relationList)) { + for (OnlineDatasourceRelation relation : relationList) { + if (relation.getCascadeDelete() + && !relation.getMasterColumnId().equals(table.getPrimaryKeyColumn().getColumnId())) { + masterData = getMasterData(table, null, null, dataId); + break; + } + } + } + List filterList = + this.makeDefaultFilter(table, table.getPrimaryKeyColumn(), dataId); + String dataPermFilter = this.buildDataPermFilter(table); + if (table.getLogicDeleteColumn() == null) { + if (onlineOperationMapper.delete(table.getTableName(), filterList, dataPermFilter) != 1) { + return false; + } + } else { + if (!this.doLogicDelete(table, table.getPrimaryKeyColumn(), dataId, dataPermFilter)) { + return false; + } + } + if (CollUtil.isEmpty(relationList)) { + return true; + } + for (OnlineDatasourceRelation relation : relationList) { + if (!relation.getCascadeDelete()) { + continue; + } + OnlineTable slaveTable = relation.getSlaveTable(); + OnlineColumn slaveColumn = + relation.getSlaveTable().getColumnMap().get(relation.getSlaveColumnId()); + String columnValue = dataId; + if (!relation.getMasterColumnId().equals(table.getPrimaryKeyColumn().getColumnId())) { + OnlineColumn relationMasterColumn = table.getColumnMap().get(relation.getMasterColumnId()); + columnValue = masterData.get(relationMasterColumn.getColumnName()).toString(); + } + if (slaveTable.getLogicDeleteColumn() == null) { + List slaveFilterList = + this.makeDefaultFilter(relation.getSlaveTable(), slaveColumn, columnValue); + onlineOperationMapper.delete(slaveTable.getTableName(), slaveFilterList, null); + } else { + this.doLogicDelete(slaveTable, slaveColumn, columnValue, null); + } + } + return true; + } + + @Transactional(rollbackFor = Exception.class) + @Override + public void forceDelete(OnlineTable table, OnlineColumn column, String columnValue) { + List filterList = this.makeDefaultFilter(table, column, columnValue); + onlineOperationMapper.delete(table.getTableName(), filterList, null); + } + + @Override + public Map getMasterData( + OnlineTable table, + List oneToOneRelationList, + List allRelationList, + String dataId) { + List filterList = + this.makeDefaultFilter(table, table.getPrimaryKeyColumn(), dataId); + // 组件表关联数据。 + List joinInfoList = this.makeJoinInfoList(table, oneToOneRelationList); + // 拼接关联表的select fields字段。 + String selectFields = this.makeSelectFields(table, oneToOneRelationList); + String dataPermFilter = this.buildDataPermFilter(table); + List> resultList = onlineOperationMapper.getList( + table.getTableName(), joinInfoList, selectFields, filterList, dataPermFilter, null); + this.buildDataListWithDict(resultList, table, oneToOneRelationList); + if (CollUtil.isEmpty(resultList)) { + return null; + } + if (CollUtil.isNotEmpty(allRelationList)) { + // 针对一对多和多对多关联,计算虚拟聚合字段。 + List toManyRelationList = allRelationList.stream() + .filter(r -> !r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList()); + this.buildVirtualColumn(resultList, table, toManyRelationList); + } + return resultList.get(0); + } + + @Override + public Map getSlaveData(OnlineDatasourceRelation relation, String dataId) { + OnlineTable slaveTable = relation.getSlaveTable(); + List filterList = + this.makeDefaultFilter(slaveTable, slaveTable.getPrimaryKeyColumn(), dataId); + // 拼接关联表的select fields字段。 + String selectFields = this.makeSelectFields(slaveTable, relation.getVariableName()); + String dataPermFilter = this.buildDataPermFilter(slaveTable); + List> resultList = onlineOperationMapper.getList( + slaveTable.getTableName(), null, selectFields, filterList, dataPermFilter, null); + this.buildDataListWithDict(resultList, slaveTable, relation.getVariableName()); + return CollUtil.isEmpty(resultList) ? null : resultList.get(0); + } + + @Override + public List> getMasterDataList( + OnlineTable table, + List oneToOneRelationList, + List allRelationList, + List filterList, + String orderBy) { + // 如果主表中包含逻辑删除,需要在这里补充到过滤字段中。 + if (table.getLogicDeleteColumn() != null) { + if (filterList == null) { + filterList = new LinkedList<>(); + } + OnlineFilterDto filter = new OnlineFilterDto(); + filter.setTableName(table.getTableName()); + filter.setColumnName(table.getLogicDeleteColumn().getColumnName()); + filter.setColumnValue(GlobalDeletedFlag.NORMAL); + filterList.add(filter); + } + // 组件表关联数据。 + List joinInfoList = this.makeJoinInfoList(table, oneToOneRelationList); + // 拼接关联表的select fields字段。 + String selectFields = this.makeSelectFields(table, oneToOneRelationList); + String dataPermFilter = this.buildDataPermFilter(table); + List> resultList = onlineOperationMapper.getList( + table.getTableName(), joinInfoList, selectFields, filterList, dataPermFilter, orderBy); + this.buildDataListWithDict(resultList, table, oneToOneRelationList); + // 针对一对多和多对多关联,计算虚拟聚合字段。 + if (CollUtil.isNotEmpty(allRelationList)) { + List toManyRelationList = allRelationList.stream() + .filter(r -> !r.getRelationType().equals(RelationType.ONE_TO_ONE)).collect(Collectors.toList()); + this.buildVirtualColumn(resultList, table, toManyRelationList); + } + return resultList; + } + + @Override + public List> getSlaveDataList( + OnlineDatasourceRelation relation, List filterList, String orderBy) { + OnlineTable slaveTable = relation.getSlaveTable(); + // 如果主表中包含逻辑删除,需要在这里补充到过滤字段中。 + if (slaveTable.getLogicDeleteColumn() != null) { + if (filterList == null) { + filterList = new LinkedList<>(); + } + OnlineFilterDto filter = new OnlineFilterDto(); + filter.setTableName(slaveTable.getTableName()); + filter.setColumnName(slaveTable.getLogicDeleteColumn().getColumnName()); + filter.setColumnValue(GlobalDeletedFlag.NORMAL); + filterList.add(filter); + } + // 拼接关联表的select fields字段。 + String selectFields = this.makeSelectFields(slaveTable, relation.getVariableName()); + String dataPermFilter = this.buildDataPermFilter(slaveTable); + List> resultList = onlineOperationMapper.getList( + slaveTable.getTableName(), null, selectFields, filterList, dataPermFilter, orderBy); + this.buildDataListWithDict(resultList, slaveTable, relation.getVariableName()); + return resultList; + } + + @Override + public List> getDictDataList(OnlineDict dict, List filterList) { + if (StrUtil.isNotEmpty(dict.getDeletedColumnName())) { + if (filterList == null) { + filterList = new LinkedList<>(); + } + OnlineFilterDto filter = new OnlineFilterDto(); + filter.setColumnName(dict.getDeletedColumnName()); + filter.setColumnValue(GlobalDeletedFlag.NORMAL); + filterList.add(filter); + } + String selectFields = this.makeDictSelectFields(dict, false); + String dataPermFilter = this.buildDataPermFilter( + dict.getTableName(), dict.getDeptFilterColumnName(), dict.getUserFilterColumnName()); + return onlineOperationMapper.getDictList(dict.getTableName(), selectFields, filterList, dataPermFilter); + } + + private void buildVirtualColumn( + List> resultList, OnlineTable table, List relationList) { + if (CollUtil.isEmpty(resultList) || CollUtil.isEmpty(relationList)) { + return; + } + OnlineVirtualColumn virtualColumnFilter = new OnlineVirtualColumn(); + virtualColumnFilter.setTableId(table.getTableId()); + virtualColumnFilter.setVirtualType(VirtualType.AGGREGATION); + List virtualColumnList = + onlineVirtualColumnService.getOnlineVirtualColumnList(virtualColumnFilter, null); + if (CollUtil.isEmpty(virtualColumnList)) { + return; + } + Map relationMap = + relationList.stream().collect(Collectors.toMap(OnlineDatasourceRelation::getRelationId, r -> r)); + for (OnlineVirtualColumn virtualColumn : virtualColumnList) { + OnlineDatasourceRelation relation = relationMap.get(virtualColumn.getRelationId()); + if (relation.getRelationType().equals(RelationType.ONE_TO_MANY)) { + this.doBuildVirtualColumnForOneToMany(table, resultList, virtualColumn, relation); + } + } + } + + private void doBuildVirtualColumnForOneToMany( + OnlineTable masterTable, + List> resultList, + OnlineVirtualColumn virtualColumn, + OnlineDatasourceRelation relation) { + String slaveTableName = relation.getSlaveTable().getTableName(); + OnlineColumn slaveColumn = + relation.getSlaveTable().getColumnMap().get(relation.getSlaveColumnId()); + String slaveColumnName = slaveColumn.getColumnName(); + OnlineColumn aggregationColumn = + relation.getSlaveTable().getColumnMap().get(virtualColumn.getAggregationColumnId()); + String aggregationColumnName = aggregationColumn.getColumnName(); + Tuple2 selectAndGroupByTuple = makeSelectListAndGroupByClause( + slaveTableName, slaveColumnName, slaveTableName, aggregationColumnName, virtualColumn.getAggregationType()); + String selectList = selectAndGroupByTuple.getFirst(); + String groupBy = selectAndGroupByTuple.getSecond(); + // 开始组装过滤从句。 + List criteriaList = new LinkedList<>(); + // 1. 组装主表数据对从表的过滤条件。 + MyWhereCriteria inlistFilter = new MyWhereCriteria(); + OnlineColumn masterColumn = masterTable.getColumnMap().get(relation.getMasterColumnId()); + String masterColumnName = masterColumn.getColumnName(); + Set masterIdSet = resultList.stream() + .map(r -> r.get(masterColumnName)).filter(Objects::nonNull).collect(Collectors.toSet()); + inlistFilter.setCriteria( + slaveTableName, slaveColumnName, slaveColumn.getObjectFieldType(), MyWhereCriteria.OPERATOR_IN, masterIdSet); + criteriaList.add(inlistFilter); + // 2. 从表逻辑删除字段过滤。 + if (relation.getSlaveTable().getLogicDeleteColumn() != null) { + MyWhereCriteria deleteFilter = new MyWhereCriteria(); + deleteFilter.setCriteria( + slaveTableName, + relation.getSlaveTable().getLogicDeleteColumn().getColumnName(), + relation.getSlaveTable().getLogicDeleteColumn().getObjectFieldType(), + MyWhereCriteria.OPERATOR_EQUAL, + GlobalDeletedFlag.NORMAL); + criteriaList.add(deleteFilter); + } + if (StrUtil.isNotBlank(virtualColumn.getWhereClauseJson())) { + List whereClauseList = + JSONArray.parseArray(virtualColumn.getWhereClauseJson(), VirtualColumnWhereClause.class); + if (CollUtil.isNotEmpty(whereClauseList)) { + for (VirtualColumnWhereClause whereClause : whereClauseList) { + MyWhereCriteria whereClauseFilter = new MyWhereCriteria(); + OnlineColumn c = relation.getSlaveTable().getColumnMap().get(whereClause.getColumnId()); + whereClauseFilter.setCriteria( + slaveTableName, + c.getColumnName(), + c.getObjectFieldType(), + whereClause.getOperatorType(), + whereClause.getValue()); + criteriaList.add(whereClauseFilter); + } + } + } + String criteriaString = MyWhereCriteria.makeCriteriaString(criteriaList); + List> aggregationMapList = + onlineOperationMapper.getGroupedListByCondition(slaveTableName, selectList, criteriaString, groupBy); + this.doMakeAggregationData(resultList, aggregationMapList, masterColumnName, virtualColumn.getObjectFieldName()); + } + + private void doMakeAggregationData( + List> resultList, + List> aggregationMapList, + String masterColumnName, + String virtualColumnName) { + // 根据获取的分组聚合结果集,绑定到主表总的关联字段。 + if (CollectionUtils.isEmpty(aggregationMapList)) { + return; + } + Map relatedMap = new HashMap<>(aggregationMapList.size()); + for (Map map : aggregationMapList) { + relatedMap.put(map.get(KEY_NAME), map.get(VALUE_NAME)); + } + for (Map dataObject : resultList) { + Object masterIdValue = dataObject.get(masterColumnName); + if (masterIdValue != null) { + Object value = relatedMap.get(masterIdValue); + if (value != null) { + dataObject.put(virtualColumnName, value); + } + } + } + } + + private Tuple2 makeSelectListAndGroupByClause( + String groupTableName, + String groupColumnName, + String aggregationTableName, + String aggregationColumnName, + Integer aggregationType) { + String aggregationFunc = AggregationType.getAggregationFunction(aggregationType); + // 构建Select List + // 如:r_table.master_id groupedKey, SUM(r_table.aggr_column) aggregated_value + StringBuilder groupedSelectList = new StringBuilder(128); + groupedSelectList.append(groupTableName) + .append(".") + .append(groupColumnName) + .append(" ") + .append(KEY_NAME) + .append(", ") + .append(aggregationFunc) + .append("(") + .append(aggregationTableName) + .append(".") + .append(aggregationColumnName) + .append(") ") + .append(VALUE_NAME) + .append(" "); + StringBuilder groupBy = new StringBuilder(64); + groupBy.append(groupTableName).append(".").append(groupColumnName); + return new Tuple2<>(groupedSelectList.toString(), groupBy.toString()); + } + + private void buildDataListWithDict( + List> resultList, OnlineTable slaveTable, String relationVariableName) { + if (CollUtil.isEmpty(resultList)) { + return; + } + Set dictIdSet = new HashSet<>(); + // 先找主表字段对字典的依赖。 + Multimap dictColumnMap = LinkedHashMultimap.create(); + for (OnlineColumn column : slaveTable.getColumnMap().values()) { + if (column.getDictId() != null) { + dictIdSet.add(column.getDictId()); + dictColumnMap.put(column.getDictId(), + relationVariableName + OnlineConstant.RELATION_TABLE_COLUMN_SEPARATOR + column.getColumnName()); + } + } + this.doBuildDataListWithDict(resultList, dictIdSet, dictColumnMap); + } + + private void buildDataListWithDict( + List> resultList, OnlineTable masterTable, List relationList) { + if (CollUtil.isEmpty(resultList)) { + return; + } + Set dictIdSet = new HashSet<>(); + // 先找主表字段对字典的依赖。 + Multimap dictColumnMap = LinkedHashMultimap.create(); + for (OnlineColumn column : masterTable.getColumnMap().values()) { + if (column.getDictId() != null) { + dictIdSet.add(column.getDictId()); + dictColumnMap.put(column.getDictId(), column.getColumnName()); + } + } + // 再找关联表字段对字典的依赖。 + if (CollUtil.isNotEmpty(relationList)) { + for (OnlineDatasourceRelation relation : relationList) { + for (OnlineColumn column : relation.getSlaveTable().getColumnMap().values()) { + if (column.getDictId() != null) { + dictIdSet.add(column.getDictId()); + dictColumnMap.put(column.getDictId(), + relation.getVariableName() + OnlineConstant.RELATION_TABLE_COLUMN_SEPARATOR + column.getColumnName()); + } + } + } + } + this.doBuildDataListWithDict(resultList, dictIdSet, dictColumnMap); + } + + private void doBuildDataListWithDict( + List> resultList, Set dictIdSet, Multimap dictColumnMap) { + if (CollUtil.isEmpty(dictIdSet)) { + return; + } + List dictList = onlineDictService.getOnlineDictList(dictIdSet) + .stream().filter(d -> d.getDictType() == DictType.TABLE).collect(Collectors.toList()); + for (OnlineDict dict : dictList) { + Collection columnNameList = dictColumnMap.get(dict.getDictId()); + for (String columnName : columnNameList) { + Set dictIdDataSet = new HashSet<>(); + for (Map result : resultList) { + Object dictIdData = result.get(columnName); + if (ObjectUtil.isNotEmpty(dictIdData)) { + dictIdDataSet.add(dictIdData); + } + } + if (CollUtil.isEmpty(dictIdDataSet)) { + continue; + } + String selectFields = this.makeDictSelectFields(dict, true); + List filterList = new LinkedList<>(); + if (StrUtil.isNotBlank(dict.getDeletedColumnName())) { + OnlineFilterDto filter = new OnlineFilterDto(); + filter.setColumnName(dict.getDeletedColumnName()); + filter.setColumnValue(GlobalDeletedFlag.NORMAL); + filterList.add(filter); + } + OnlineFilterDto inlistFilter = new OnlineFilterDto(); + inlistFilter.setColumnName(dict.getKeyColumnName()); + inlistFilter.setColumnValueList(dictIdDataSet); + inlistFilter.setFilterType(FieldFilterType.IN_LIST_FILTER); + filterList.add(inlistFilter); + List> dictResultList = + onlineOperationMapper.getDictList(dict.getTableName(), selectFields, filterList, null); + if (CollUtil.isEmpty(dictResultList)) { + continue; + } + Map dictResultMap = new HashMap<>(dictResultList.size()); + for (Map dictResult : dictResultList) { + dictResultMap.put(dictResult.get("id"), dictResult.get("name")); + } + String dictKeyName = columnName + "__DictMap"; + for (Map result : resultList) { + Object dictIdData = result.get(columnName); + Object dictNameData = dictResultMap.get(dictIdData); + Map dictMap = new HashMap<>(2); + dictMap.put("id", dictIdData); + dictMap.put("name", dictNameData); + result.put(dictKeyName, dictMap); + } + } + } + } + + private List makeJoinInfoList( + OnlineTable masterTable, List relationList) { + if (CollUtil.isEmpty(relationList)) { + return null; + } + Map masterTableColumnMap = masterTable.getColumnMap(); + List joinInfoList = new LinkedList<>(); + for (OnlineDatasourceRelation relation : relationList) { + JoinTableInfo joinInfo = new JoinTableInfo(); + joinInfo.setLeftJoin(relation.getLeftJoin()); + joinInfo.setJoinTableName(relation.getSlaveTable().getTableName()); + // 根据配置动态拼接JOIN的关联条件,同时要考虑从表的逻辑删除过滤。 + OnlineColumn masterColumn = masterTableColumnMap.get(relation.getMasterColumnId()); + OnlineColumn slaveColumn = relation.getSlaveTable().getColumnMap().get(relation.getSlaveColumnId()); + StringBuilder conditionBuilder = new StringBuilder(64); + conditionBuilder + .append(masterTable.getTableName()) + .append(".") + .append(masterColumn.getColumnName()) + .append(" = ") + .append(relation.getSlaveTable().getTableName()) + .append(".") + .append(slaveColumn.getColumnName()); + if (relation.getSlaveTable().getLogicDeleteColumn() != null) { + conditionBuilder + .append(" AND ") + .append(relation.getSlaveTable().getTableName()) + .append(".") + .append(relation.getSlaveTable().getLogicDeleteColumn().getColumnName()) + .append(" = ") + .append(GlobalDeletedFlag.NORMAL); + } + joinInfo.setJoinCondition(conditionBuilder.toString()); + joinInfoList.add(joinInfo); + } + return joinInfoList; + } + + private String makeSelectFields(OnlineTable slaveTable, String relationVariableName) { + StringBuilder selectFieldBuider = new StringBuilder(512); + // 拼装主表的select fields字段。 + for (OnlineColumn column : slaveTable.getColumnMap().values()) { + OnlineColumn deletedColumn = slaveTable.getLogicDeleteColumn(); + if (deletedColumn != null && StrUtil.equals(column.getColumnName(), deletedColumn.getColumnName())) { + continue; + } + if (this.castToInteger(column)) { + selectFieldBuider + .append("CAST(") + .append(slaveTable.getTableName()) + .append(".") + .append(column.getColumnName()) + .append(" AS SIGNED) ") + .append(relationVariableName) + .append(OnlineConstant.RELATION_TABLE_COLUMN_SEPARATOR) + .append(column.getColumnName()) + .append(","); + } else { + selectFieldBuider + .append(slaveTable.getTableName()) + .append(".") + .append(column.getColumnName()) + .append(" ") + .append(relationVariableName) + .append(OnlineConstant.RELATION_TABLE_COLUMN_SEPARATOR) + .append(column.getColumnName()) + .append(","); + } + } + return selectFieldBuider.substring(0, selectFieldBuider.length() - 1); + } + + private String makeSelectFields(OnlineTable masterTable, List relationList) { + StringBuilder selectFieldBuider = new StringBuilder(512); + if (CollUtil.isNotEmpty(relationList)) { + for (OnlineDatasourceRelation relation : relationList) { + OnlineTable slaveTable = relation.getSlaveTable(); + Collection columnList = slaveTable.getColumnMap().values(); + for (OnlineColumn column : columnList) { + OnlineColumn deletedColumn = slaveTable.getLogicDeleteColumn(); + if (deletedColumn != null && StrUtil.equals(column.getColumnName(), deletedColumn.getColumnName())) { + continue; + } + if (this.castToInteger(column)) { + selectFieldBuider + .append("CAST(") + .append(slaveTable.getTableName()) + .append(".") + .append(column.getColumnName()) + .append(" AS SIGNED) ") + .append(relation.getVariableName()) + .append(OnlineConstant.RELATION_TABLE_COLUMN_SEPARATOR) + .append(column.getColumnName()) + .append(","); + } else { + selectFieldBuider + .append(slaveTable.getTableName()) + .append(".") + .append(column.getColumnName()) + .append(" ") + .append(relation.getVariableName()) + .append(OnlineConstant.RELATION_TABLE_COLUMN_SEPARATOR) + .append(column.getColumnName()) + .append(","); + } + } + } + } + // 拼装主表的select fields字段。 + for (OnlineColumn column : masterTable.getColumnMap().values()) { + OnlineColumn deletedColumn = masterTable.getLogicDeleteColumn(); + if (deletedColumn != null && StrUtil.equals(column.getColumnName(), deletedColumn.getColumnName())) { + continue; + } + if (this.castToInteger(column)) { + selectFieldBuider + .append("CAST(") + .append(masterTable.getTableName()) + .append(".") + .append(column.getColumnName()) + .append(" AS SIGNED) ") + .append(column.getColumnName()) + .append(","); + } else { + selectFieldBuider + .append(masterTable.getTableName()) + .append(".") + .append(column.getColumnName()) + .append(","); + } + } + return selectFieldBuider.substring(0, selectFieldBuider.length() - 1); + } + + private String makeDictSelectFields(OnlineDict onlineDict, boolean ignoreParentId) { + StringBuilder sb = new StringBuilder(128); + sb.append(onlineDict.getKeyColumnName()).append(" id, "); + sb.append(onlineDict.getValueColumnName()).append(" name"); + if (!ignoreParentId && onlineDict.getTreeFlag()) { + sb.append(", ").append(onlineDict.getParentKeyColumnName()).append(" parentId"); + } + return sb.toString(); + } + + private boolean castToInteger(OnlineColumn column) { + return "tinyint(1)".equals(column.getFullColumnType()); + } + + private String makeColumnNames(List columnDataList) { + StringBuilder sb = new StringBuilder(512); + for (ColumnData columnData : columnDataList) { + if (columnData.getColumn().getAutoIncrement()) { + continue; + } + sb.append(columnData.getColumn().getColumnName()).append(","); + } + return sb.substring(0, sb.length() - 1); + } + + private void makeupColumnValue(ColumnData columnData) { + if (columnData.getColumn().getAutoIncrement()) { + return; + } + if (columnData.getColumn().getPrimaryKey()) { + if (columnData.getColumnValue() == null) { + if ("Long".equals(columnData.getColumn().getObjectFieldType())) { + columnData.setColumnValue(idGenerator.nextLongId()); + } else { + columnData.setColumnValue(idGenerator.nextStringId()); + } + } + } else if (columnData.getColumn().getFieldKind() != null) { + switch (columnData.getColumn().getFieldKind()) { + case FieldKind.CREATE_TIME: + case FieldKind.UPDATE_TIME: + columnData.setColumnValue(new Date()); + break; + case FieldKind.CREATE_USER_ID: + case FieldKind.UPDATE_USER_ID: + columnData.setColumnValue(TokenData.takeFromRequest().getUserId()); + break; + case FieldKind.LOGIC_DELETE: + columnData.setColumnValue(GlobalDeletedFlag.NORMAL); + break; + default: + break; + } + } + } + + private List makeDefaultFilter(OnlineTable table, OnlineColumn column, String columnValue) { + List filterList = new LinkedList<>(); + OnlineFilterDto dataIdFilter = new OnlineFilterDto(); + dataIdFilter.setTableName(table.getTableName()); + dataIdFilter.setColumnName(column.getColumnName()); + dataIdFilter.setColumnValue(onlineOperationHelper.convertToTypeValue(column, columnValue)); + filterList.add(dataIdFilter); + if (table.getLogicDeleteColumn() != null) { + OnlineFilterDto filter = new OnlineFilterDto(); + filter.setTableName(table.getTableName()); + filter.setColumnName(table.getLogicDeleteColumn().getColumnName()); + filter.setColumnValue(GlobalDeletedFlag.NORMAL); + filterList.add(filter); + } + return filterList; + } + + private boolean doLogicDelete( + OnlineTable table, OnlineColumn filterColumn, String filterColumnValue, String dataPermFilter) { + List updateColumnList = new LinkedList<>(); + ColumnData logicDeleteColumnData = new ColumnData(); + logicDeleteColumnData.setColumn(table.getLogicDeleteColumn()); + logicDeleteColumnData.setColumnValue(GlobalDeletedFlag.DELETED); + updateColumnList.add(logicDeleteColumnData); + List whereColumnList = new LinkedList<>(); + ColumnData relationSlaveColumnData = new ColumnData(); + relationSlaveColumnData.setColumn(filterColumn); + relationSlaveColumnData.setColumnValue( + onlineOperationHelper.convertToTypeValue(filterColumn, filterColumnValue)); + whereColumnList.add(relationSlaveColumnData); + return onlineOperationMapper.update( + table.getTableName(), updateColumnList, whereColumnList, dataPermFilter) != 0; + } + + private String buildDataPermFilter(String tableName, String deptFilterColumnName, String userFilterColumnName) { + if (!dataFilterProperties.getEnabledDataPermFilter()) { + return null; + } + return processDataPerm(tableName, deptFilterColumnName, userFilterColumnName); + } + + private String buildDataPermFilter(OnlineTable table) { + if (!dataFilterProperties.getEnabledDataPermFilter()) { + return null; + } + String deptFilterColumnName = null; + String userFilterColumnName = null; + for (OnlineColumn column : table.getColumnMap().values()) { + if (column.getDeptFilter()) { + deptFilterColumnName = column.getColumnName(); + } + if (column.getUserFilter()) { + userFilterColumnName = column.getColumnName(); + } + } + return processDataPerm(table.getTableName(), deptFilterColumnName, userFilterColumnName); + } + + private String processDataPerm(String tableName, String deptFilterColumnName, String userFilterColumnName) { + TokenData tokenData = TokenData.takeFromRequest(); + if (Boolean.TRUE.equals(tokenData.getIsAdmin())) { + return null; + } + String dataPermSessionKey = + RedisKeyUtil.makeSessionDataPermIdKey(tokenData.getSessionId()); + RBucket bucket = redissonClient.getBucket(dataPermSessionKey); + String dataPermData = bucket.get(); + if (StrUtil.isBlank(dataPermData)) { + throw new NoDataPermException("No Related DataPerm found."); + } + Map dataPermMap = new HashMap<>(8); + for (Map.Entry entry : JSON.parseObject(dataPermData).entrySet()) { + dataPermMap.put(Integer.valueOf(entry.getKey()), entry.getValue().toString()); + } + if (MapUtil.isEmpty(dataPermMap)) { + throw new NoDataPermException("No Related DataPerm found."); + } + if (dataPermMap.containsKey(DataPermRuleType.TYPE_ALL)) { + return null; + } + return doProcessDataPerm(tableName, deptFilterColumnName, userFilterColumnName, dataPermMap); + } + + private String doProcessDataPerm( + String tableName, String deptFilterColumnName, String userFilterColumnName, Map dataPermMap) { + List criteriaList = new LinkedList<>(); + for (Map.Entry entry : dataPermMap.entrySet()) { + String filterClause = processDataPermRule( + tableName, deptFilterColumnName, userFilterColumnName, entry.getKey(), entry.getValue()); + if (StrUtil.isNotBlank(filterClause)) { + criteriaList.add(filterClause); + } + } + if (CollUtil.isEmpty(criteriaList)) { + return null; + } + StringBuilder filterBuilder = new StringBuilder(128); + filterBuilder.append("("); + filterBuilder.append(CollUtil.join(criteriaList, " OR ")); + filterBuilder.append(")"); + return filterBuilder.toString(); + } + + private String processDataPermRule( + String tableName, String deptFilterColumnName, String userFilterColumnName, Integer ruleType, String deptIds) { + TokenData tokenData = TokenData.takeFromRequest(); + StringBuilder filter = new StringBuilder(128); + if (ruleType == DataPermRuleType.TYPE_USER_ONLY) { + if (StrUtil.isNotBlank(userFilterColumnName)) { + if (dataFilterProperties.getAddTableNamePrefix()) { + filter.append(tableName).append("."); + } + filter.append(userFilterColumnName) + .append(" = ") + .append(tokenData.getUserId()); + } + } else { + if (StrUtil.isNotBlank(deptFilterColumnName)) { + if (ruleType == DataPermRuleType.TYPE_DEPT_ONLY) { + if (dataFilterProperties.getAddTableNamePrefix()) { + filter.append(tableName).append("."); + } + filter.append(deptFilterColumnName) + .append(" = ") + .append(tokenData.getDeptId()); + } else if (ruleType == DataPermRuleType.TYPE_DEPT_AND_CHILD_DEPT) { + filter.append(" EXISTS ") + .append("(SELECT 1 FROM ") + .append(dataFilterProperties.getDeptRelationTablePrefix()) + .append("sys_dept_relation WHERE ") + .append(dataFilterProperties.getDeptRelationTablePrefix()) + .append("sys_dept_relation.parent_dept_id = ") + .append(tokenData.getDeptId()) + .append(" AND "); + if (dataFilterProperties.getAddTableNamePrefix()) { + filter.append(tableName).append("."); + } + filter.append(deptFilterColumnName) + .append(" = ") + .append(dataFilterProperties.getDeptRelationTablePrefix()) + .append("sys_dept_relation.dept_id) "); + } else if (ruleType == DataPermRuleType.TYPE_MULTI_DEPT_AND_CHILD_DEPT) { + filter.append(" EXISTS ") + .append("(SELECT 1 FROM ") + .append(dataFilterProperties.getDeptRelationTablePrefix()) + .append("sys_dept_relation WHERE ") + .append(dataFilterProperties.getDeptRelationTablePrefix()) + .append("sys_dept_relation.parent_dept_id IN (") + .append(deptIds) + .append(") AND "); + if (dataFilterProperties.getAddTableNamePrefix()) { + filter.append(tableName).append("."); + } + filter.append(deptFilterColumnName) + .append(" = ") + .append(dataFilterProperties.getDeptRelationTablePrefix()) + .append("sys_dept_relation.dept_id) "); + } else if (ruleType == DataPermRuleType.TYPE_CUSTOM_DEPT_LIST) { + if (dataFilterProperties.getAddTableNamePrefix()) { + filter.append(tableName).append("."); + } + filter.append(deptFilterColumnName) + .append(" IN (") + .append(deptIds) + .append(") "); + } + } + } + return filter.toString(); + } + + @Data + static class VirtualColumnWhereClause { + private Long tableId; + private Long columnId; + private Integer operatorType; + private Object value; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlinePageServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlinePageServiceImpl.java new file mode 100644 index 00000000..1bf0f4c9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlinePageServiceImpl.java @@ -0,0 +1,233 @@ +package com.flow.demo.common.online.service.impl; + +import cn.hutool.core.collection.CollUtil; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.online.service.OnlineDatasourceService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.dao.OnlinePageDatasourceMapper; +import com.flow.demo.common.online.dao.OnlinePageMapper; +import com.flow.demo.common.online.model.OnlinePage; +import com.flow.demo.common.online.model.OnlinePageDatasource; +import com.flow.demo.common.online.model.constant.PageStatus; +import com.flow.demo.common.online.service.OnlineFormService; +import com.flow.demo.common.online.service.OnlinePageService; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +/** + * 在线表单页面数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlinePageService") +public class OnlinePageServiceImpl extends BaseService implements OnlinePageService { + + @Autowired + private OnlinePageMapper onlinePageMapper; + @Autowired + private OnlinePageDatasourceMapper onlinePageDatasourceMapper; + @Autowired + private OnlineFormService onlineFormService; + @Autowired + private OnlineDatasourceService onlineDatasourceService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlinePageMapper; + } + + /** + * 保存新增对象。 + * + * @param onlinePage 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public OnlinePage saveNew(OnlinePage onlinePage) { + onlinePage.setPageId(idGenerator.nextLongId()); + Date now = new Date(); + onlinePage.setUpdateTime(now); + onlinePage.setCreateTime(now); + onlinePage.setPublished(false); + MyModelUtil.setDefaultValue(onlinePage, "status", PageStatus.BASIC); + onlinePageMapper.insert(onlinePage); + return onlinePage; + } + + /** + * 更新数据对象。 + * + * @param onlinePage 更新的对象。 + * @param originalOnlinePage 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlinePage onlinePage, OnlinePage originalOnlinePage) { + onlinePage.setUpdateTime(new Date()); + onlinePage.setCreateTime(originalOnlinePage.getCreateTime()); + onlinePage.setPublished(originalOnlinePage.getPublished()); + // 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。 + UpdateWrapper uw = this.createUpdateQueryForNullValue(onlinePage, onlinePage.getPageId()); + return onlinePageMapper.update(onlinePage, uw) == 1; + } + + /** + * 更新页面对象的发布状态。 + * + * @param pageId 页面对象Id。 + * @param published 新的状态。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void updatePublished(Long pageId, Boolean published) { + OnlinePage onlinePage = new OnlinePage(); + onlinePage.setPageId(pageId); + onlinePage.setPublished(published); + onlinePageMapper.updateById(onlinePage); + } + + /** + * 删除指定数据,及其包含的表单和数据源等。 + * + * @param pageId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long pageId) { + if (onlinePageMapper.deleteById(pageId) == 0) { + return false; + } + // 开始删除关联表单。 + onlineFormService.removeByPageId(pageId); + // 先获取出关联的表单和数据源。 + OnlinePageDatasource pageDatasourceFilter = new OnlinePageDatasource(); + pageDatasourceFilter.setPageId(pageId); + List pageDatasourceList = + onlinePageDatasourceMapper.selectList(new QueryWrapper<>(pageDatasourceFilter)); + if (CollUtil.isNotEmpty(pageDatasourceList)) { + for (OnlinePageDatasource pageDatasource : pageDatasourceList) { + onlineDatasourceService.remove(pageDatasource.getDatasourceId()); + } + } + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlinePageListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlinePageList(OnlinePage filter, String orderBy) { + return onlinePageMapper.getOnlinePageList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlinePageList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlinePageListWithRelation(OnlinePage filter, String orderBy) { + List resultList = onlinePageMapper.getOnlinePageList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 批量添加多对多关联关系。 + * + * @param onlinePageDatasourceList 多对多关联表对象集合。 + * @param pageId 主表Id。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void addOnlinePageDatasourceList(List onlinePageDatasourceList, Long pageId) { + for (OnlinePageDatasource onlinePageDatasource : onlinePageDatasourceList) { + onlinePageDatasource.setPageId(pageId); + onlinePageDatasourceMapper.insert(onlinePageDatasource); + } + } + + /** + * 获取中间表数据。 + * + * @param pageId 主表Id。 + * @param datasourceId 从表Id。 + * @return 中间表对象。 + */ + @Override + public OnlinePageDatasource getOnlinePageDatasource(Long pageId, Long datasourceId) { + OnlinePageDatasource filter = new OnlinePageDatasource(); + filter.setPageId(pageId); + filter.setDatasourceId(datasourceId); + return onlinePageDatasourceMapper.selectOne(new QueryWrapper<>(filter)); + } + + @Override + public List getOnlinePageDatasourceListByPageId(Long pageId) { + OnlinePageDatasource filter = new OnlinePageDatasource(); + filter.setPageId(pageId); + return onlinePageDatasourceMapper.selectList(new QueryWrapper<>(filter)); + } + + /** + * 根据数据源Id,返回使用该数据源的OnlinePage对象。 + * + * @param datasourceId 数据源Id。 + * @return 使用该数据源的页面列表。 + */ + @Override + public List getOnlinePageListByDatasourceId(Long datasourceId) { + return onlinePageMapper.getOnlinePageListByDatasourceId(datasourceId); + } + + /** + * 移除单条多对多关系。 + * + * @param pageId 主表Id。 + * @param datasourceId 从表Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean removeOnlinePageDatasource(Long pageId, Long datasourceId) { + OnlinePageDatasource filter = new OnlinePageDatasource(); + filter.setPageId(pageId); + filter.setDatasourceId(datasourceId); + return onlinePageDatasourceMapper.delete(new QueryWrapper<>(filter)) > 0; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineRuleServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineRuleServiceImpl.java new file mode 100644 index 00000000..da468e9c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineRuleServiceImpl.java @@ -0,0 +1,181 @@ +package com.flow.demo.common.online.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.constant.GlobalDeletedFlag; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.util.MyModelUtil; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.dao.OnlineColumnRuleMapper; +import com.flow.demo.common.online.dao.OnlineRuleMapper; +import com.flow.demo.common.online.model.OnlineColumnRule; +import com.flow.demo.common.online.model.OnlineRule; +import com.flow.demo.common.online.service.OnlineRuleService; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.Set; + +/** + * 验证规则数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlineRuleService") +public class OnlineRuleServiceImpl extends BaseService implements OnlineRuleService { + + @Autowired + private OnlineRuleMapper onlineRuleMapper; + @Autowired + private OnlineColumnRuleMapper onlineColumnRuleMapper; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlineRuleMapper; + } + + /** + * 保存新增对象。 + * + * @param onlineRule 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public OnlineRule saveNew(OnlineRule onlineRule) { + onlineRule.setRuleId(idGenerator.nextLongId()); + Date now = new Date(); + onlineRule.setUpdateTime(now); + onlineRule.setCreateTime(now); + onlineRule.setDeletedFlag(GlobalDeletedFlag.NORMAL); + MyModelUtil.setDefaultValue(onlineRule, "pattern", ""); + onlineRuleMapper.insert(onlineRule); + return onlineRule; + } + + /** + * 更新数据对象。 + * + * @param onlineRule 更新的对象。 + * @param originalOnlineRule 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlineRule onlineRule, OnlineRule originalOnlineRule) { + onlineRule.setUpdateTime(new Date()); + onlineRule.setCreateTime(originalOnlineRule.getCreateTime()); + UpdateWrapper uw = this.createUpdateQueryForNullValue(onlineRule, onlineRule.getRuleId()); + return onlineRuleMapper.update(onlineRule, uw) == 1; + } + + /** + * 删除指定数据。 + * + * @param ruleId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long ruleId) { + if (onlineRuleMapper.deleteById(ruleId) == 0) { + return false; + } + // 开始删除多对多父表的关联 + OnlineColumnRule onlineColumnRule = new OnlineColumnRule(); + onlineColumnRule.setRuleId(ruleId); + onlineColumnRuleMapper.delete(new QueryWrapper<>(onlineColumnRule)); + return true; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineRuleListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineRuleList(OnlineRule filter, String orderBy) { + return onlineRuleMapper.getOnlineRuleList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineRuleList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineRuleListWithRelation(OnlineRule filter, String orderBy) { + List resultList = onlineRuleMapper.getOnlineRuleList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回不与指定主表主键Id存在对多对关系的列表。 + * + * @param columnId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getNotInOnlineRuleListByColumnId(Long columnId, OnlineRule filter, String orderBy) { + List resultList = + onlineRuleMapper.getNotInOnlineRuleListByColumnId(columnId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly()); + return resultList; + } + + /** + * 在多对多关系中,当前Service的数据表为从表,返回与指定主表主键Id存在对多对关系的列表。 + * + * @param columnId 主表主键Id。 + * @param filter 从表的过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineRuleListByColumnId(Long columnId, OnlineRule filter, String orderBy) { + List resultList = + onlineRuleMapper.getOnlineRuleListByColumnId(columnId, filter, orderBy); + this.buildRelationForDataList(resultList, MyRelationParam.dictOnly()); + return resultList; + } + + /** + * 返回指定字段Id列表关联的字段规则对象列表。 + * + * @param columnIdSet 指定的字段Id列表。 + * @return 关联的字段规则对象列表。 + */ + @Override + public List getOnlineColumnRuleListByColumnIds(Set columnIdSet) { + return onlineColumnRuleMapper.getOnlineColumnRuleListByColumnIds(columnIdSet); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineTableServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineTableServiceImpl.java new file mode 100644 index 00000000..2de6c033 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineTableServiceImpl.java @@ -0,0 +1,236 @@ +package com.flow.demo.common.online.service.impl; + +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSON; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.util.RedisKeyUtil; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.flow.demo.common.online.dao.OnlineTableMapper; +import com.flow.demo.common.online.model.OnlineColumn; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.model.constant.FieldKind; +import com.flow.demo.common.online.object.SqlTable; +import com.flow.demo.common.online.service.OnlineColumnService; +import com.flow.demo.common.online.service.OnlineTableService; +import com.github.pagehelper.Page; +import com.google.common.base.CaseFormat; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RBucket; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 数据表数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlineTableService") +public class OnlineTableServiceImpl extends BaseService implements OnlineTableService { + + @Autowired + private OnlineTableMapper onlineTableMapper; + @Autowired + private OnlineColumnService onlineColumnService; + @Autowired + private IdGeneratorWrapper idGenerator; + @Autowired + private RedissonClient redissonClient; + + /** + * 在线对象表的缺省缓存时间(小时)。 + */ + private static final int DEFAULT_CACHED_TABLE_HOURS = 168; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlineTableMapper; + } + + /** + * 基于数据库表保存新增对象。 + * + * @param sqlTable 数据库表对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public OnlineTable saveNewFromSqlTable(SqlTable sqlTable) { + OnlineTable onlineTable = new OnlineTable(); + onlineTable.setDblinkId(sqlTable.getDblinkId()); + onlineTable.setTableId(idGenerator.nextLongId()); + onlineTable.setTableName(sqlTable.getTableName()); + String modelName = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, sqlTable.getTableName()); + onlineTable.setModelName(modelName); + Date now = new Date(); + onlineTable.setUpdateTime(now); + onlineTable.setCreateTime(now); + onlineTableMapper.insert(onlineTable); + List columnList = onlineColumnService.saveNewList(sqlTable.getColumnList(), onlineTable.getTableId()); + onlineTable.setColumnList(columnList); + return onlineTable; + } + + /** + * 更新数据对象。 + * + * @param onlineTable 更新的对象。 + * @param originalOnlineTable 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlineTable onlineTable, OnlineTable originalOnlineTable) { + this.evictTableCache(onlineTable.getTableId()); + onlineTable.setUpdateTime(new Date()); + onlineTable.setCreateTime(originalOnlineTable.getCreateTime()); + UpdateWrapper uw = this.createUpdateQueryForNullValue(onlineTable, onlineTable.getTableId()); + return onlineTableMapper.update(onlineTable, uw) == 1; + } + + /** + * 删除指定表及其关联的字段数据。 + * + * @param tableId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long tableId) { + if (onlineTableMapper.deleteById(tableId) == 0) { + return false; + } + this.evictTableCache(tableId); + onlineColumnService.removeByTableId(tableId); + return true; + } + + /** + * 删除指定数据表Id集合中的表,及其关联字段。 + * + * @param tableIdSet 待删除的数据表Id集合。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public void removeByTableIdSet(Set tableIdSet) { + tableIdSet.forEach(this::evictTableCache); + onlineTableMapper.delete( + new QueryWrapper().lambda().in(OnlineTable::getTableId, tableIdSet)); + onlineColumnService.removeByTableIdSet(tableIdSet); + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineTableListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineTableList(OnlineTable filter, String orderBy) { + return onlineTableMapper.getOnlineTableList(filter, orderBy); + } + + /** + * 获取指定在线表Id集合的对象列表。 + * + * @param tableIdSet 主键Id集合。 + * @return 指定的数据表对象列表。 + */ + @Override + public List getOnlineTableList(Set tableIdSet) { + return onlineTableMapper.selectBatchIds(tableIdSet); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineTableList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineTableListWithRelation(OnlineTable filter, String orderBy) { + List resultList = onlineTableMapper.getOnlineTableList(filter, orderBy); + // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 + // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 根据数据源Id,获取该数据源及其关联所引用的数据表列表。 + * + * @param datasourceId 指定的数据源Id。 + * @return 该数据源及其关联所引用的数据表列表。 + */ + @Override + public List getOnlineTableListByDatasourceId(Long datasourceId) { + return onlineTableMapper.getOnlineTableListByDatasourceId(datasourceId); + } + + /** + * 从缓存中获取指定的表数据及其关联字段列表。优先从缓存中读取,如果不存在则从数据库中读取,并同步到缓存。 + * 该接口方法仅仅用户在线表单的动态数据操作接口,而非在线表单的配置接口。 + * + * @param tableId 表主键Id。 + * @return 查询后的在线表对象。 + */ + @Override + public OnlineTable getOnlineTableFromCache(Long tableId) { + String redisKey = RedisKeyUtil.makeOnlineTableKey(tableId); + RBucket tableBucket = redissonClient.getBucket(redisKey); + if (tableBucket.isExists()) { + String tableInfo = tableBucket.get(); + return JSON.parseObject(tableInfo, OnlineTable.class); + } + OnlineTable table = this.getByIdWithRelation(tableId, MyRelationParam.full()); + if (table == null) { + return null; + } + for (OnlineColumn column : table.getColumnList()) { + if (column.getPrimaryKey()) { + table.setPrimaryKeyColumn(column); + continue; + } + if (ObjectUtil.equal(column.getFieldKind(), FieldKind.LOGIC_DELETE)) { + table.setLogicDeleteColumn(column); + } + } + Map columnMap = + table.getColumnList().stream().collect(Collectors.toMap(OnlineColumn::getColumnId, c -> c)); + table.setColumnMap(columnMap); + table.setColumnList(null); + tableBucket.set(JSON.toJSONString(table)); + tableBucket.expire(DEFAULT_CACHED_TABLE_HOURS, TimeUnit.HOURS); + return table; + } + + private void evictTableCache(Long tableId) { + String tableIdKey = RedisKeyUtil.makeOnlineTableKey(tableId); + redissonClient.getBucket(tableIdKey).delete(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineVirtualColumnServiceImpl.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineVirtualColumnServiceImpl.java new file mode 100644 index 00000000..9950641b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/service/impl/OnlineVirtualColumnServiceImpl.java @@ -0,0 +1,175 @@ +package com.flow.demo.common.online.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; +import com.flow.demo.common.core.base.dao.BaseDaoMapper; +import com.flow.demo.common.core.object.CallResult; +import com.flow.demo.common.core.object.MyRelationParam; +import com.flow.demo.common.core.base.service.BaseService; +import com.flow.demo.common.online.dao.OnlineVirtualColumnMapper; +import com.flow.demo.common.online.model.OnlineDatasource; +import com.flow.demo.common.online.model.OnlineVirtualColumn; +import com.flow.demo.common.online.model.constant.VirtualType; +import com.flow.demo.common.online.service.OnlineColumnService; +import com.flow.demo.common.online.service.OnlineDatasourceRelationService; +import com.flow.demo.common.online.service.OnlineDatasourceService; +import com.flow.demo.common.online.service.OnlineVirtualColumnService; +import com.flow.demo.common.sequence.wrapper.IdGeneratorWrapper; +import com.github.pagehelper.Page; +import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 虚拟字段数据操作服务类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Service("onlineVirtualColumnService") +public class OnlineVirtualColumnServiceImpl + extends BaseService implements OnlineVirtualColumnService { + + @Autowired + private OnlineVirtualColumnMapper onlineVirtualColumnMapper; + @Autowired + private OnlineDatasourceService onlineDatasourceService; + @Autowired + private OnlineDatasourceRelationService onlineDatasourceRelationService; + @Autowired + private OnlineColumnService onlineColumnService; + @Autowired + private IdGeneratorWrapper idGenerator; + + /** + * 返回当前Service的主表Mapper对象。 + * + * @return 主表Mapper对象。 + */ + @Override + protected BaseDaoMapper mapper() { + return onlineVirtualColumnMapper; + } + + /** + * 保存新增对象。 + * + * @param virtualColumn 新增对象。 + * @return 返回新增对象。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public OnlineVirtualColumn saveNew(OnlineVirtualColumn virtualColumn) { + virtualColumn.setVirtualColumnId(idGenerator.nextLongId()); + if (virtualColumn.getVirtualType().equals(VirtualType.AGGREGATION)) { + OnlineDatasource datasource = onlineDatasourceService.getById(virtualColumn.getDatasourceId()); + virtualColumn.setTableId(datasource.getMasterTableId()); + } + onlineVirtualColumnMapper.insert(virtualColumn); + return virtualColumn; + } + + /** + * 更新数据对象。 + * + * @param virtualColumn 更新的对象。 + * @param originalVirtualColumn 原有数据对象。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean update(OnlineVirtualColumn virtualColumn, OnlineVirtualColumn originalVirtualColumn) { + if (virtualColumn.getVirtualType().equals(VirtualType.AGGREGATION)) { + if (!virtualColumn.getDatasourceId().equals(originalVirtualColumn.getDatasourceId())) { + OnlineDatasource datasource = onlineDatasourceService.getById(virtualColumn.getDatasourceId()); + virtualColumn.setTableId(datasource.getMasterTableId()); + } + } + UpdateWrapper uw = + this.createUpdateQueryForNullValue(virtualColumn, virtualColumn.getVirtualColumnId()); + return onlineVirtualColumnMapper.update(virtualColumn, uw) == 1; + } + + /** + * 删除指定数据。 + * + * @param virtualColumnId 主键Id。 + * @return 成功返回true,否则false。 + */ + @Transactional(rollbackFor = Exception.class) + @Override + public boolean remove(Long virtualColumnId) { + return onlineVirtualColumnMapper.deleteById(virtualColumnId) == 1; + } + + /** + * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 + * 如果需要同时获取关联数据,请移步(getOnlineVirtualColumnListWithRelation)方法。 + * + * @param filter 过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineVirtualColumnList(OnlineVirtualColumn filter, String orderBy) { + return onlineVirtualColumnMapper.getOnlineVirtualColumnList(filter, orderBy); + } + + /** + * 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。 + * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 + * 如果仅仅需要获取主表数据,请移步(getOnlineVirtualColumnList),以便获取更好的查询性能。 + * + * @param filter 主表过滤对象。 + * @param orderBy 排序参数。 + * @return 查询结果集。 + */ + @Override + public List getOnlineVirtualColumnListWithRelation(OnlineVirtualColumn filter, String orderBy) { + List resultList = onlineVirtualColumnMapper.getOnlineVirtualColumnList(filter, orderBy); + int batchSize = resultList instanceof Page ? 0 : 1000; + this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); + return resultList; + } + + /** + * 根据数据表的集合,查询关联的虚拟字段数据列表。 + * @param tableIdSet 在线数据表Id集合。 + * @return 关联的虚拟字段数据列表。 + */ + @Override + public List getOnlineVirtualColumnListByTableIds(Set tableIdSet) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(OnlineVirtualColumn::getTableId, tableIdSet); + return onlineVirtualColumnMapper.selectList(queryWrapper); + } + + /** + * 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。 + * + * @param virtualColumn 最新数据对象。 + * @param originalVirtualColumn 原有数据对象。 + * @return 数据全部正确返回true,否则false。 + */ + @Override + public CallResult verifyRelatedData(OnlineVirtualColumn virtualColumn, OnlineVirtualColumn originalVirtualColumn) { + String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!"; + if (this.needToVerify(virtualColumn, originalVirtualColumn, OnlineVirtualColumn::getDatasourceId) + && !onlineDatasourceService.existId(virtualColumn.getDatasourceId())) { + return CallResult.error(String.format(errorMessageFormat, "数据源Id")); + } + if (this.needToVerify(virtualColumn, originalVirtualColumn, OnlineVirtualColumn::getRelationId) + && !onlineDatasourceRelationService.existId(virtualColumn.getRelationId())) { + return CallResult.error(String.format(errorMessageFormat, "数据源关联Id")); + } + if (this.needToVerify(virtualColumn, originalVirtualColumn, OnlineVirtualColumn::getAggregationColumnId) + && !onlineColumnService.existId(virtualColumn.getAggregationColumnId())) { + return CallResult.error(String.format(errorMessageFormat, "聚合字段Id")); + } + return CallResult.ok(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineConstant.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineConstant.java new file mode 100644 index 00000000..ec9c7329 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineConstant.java @@ -0,0 +1,15 @@ +package com.flow.demo.common.online.util; + +/** + * 在线表单使用的常量数据。。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class OnlineConstant { + + /** + * 数据源关联变量名和从表字段名之间的连接字符串。 + */ + public static final String RELATION_TABLE_COLUMN_SEPARATOR = "__"; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineDataSourceResolver.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineDataSourceResolver.java new file mode 100644 index 00000000..4b0bde89 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineDataSourceResolver.java @@ -0,0 +1,50 @@ +package com.flow.demo.common.online.util; + +import com.flow.demo.common.core.util.DataSourceResolver; +import com.flow.demo.common.online.model.OnlineDatasourceRelation; +import com.flow.demo.common.online.model.OnlineDblink; +import com.flow.demo.common.online.model.OnlineDict; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.service.OnlineDblinkService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.io.Serializable; + +/** + * 目前仅仅应用于在线表单服务对象的多数据源切换的动态解析。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Component +public class OnlineDataSourceResolver implements DataSourceResolver { + + @Autowired + private OnlineDblinkService onlineDblinkService; + + /** + * 动态解析方法。 + * 先判断第一个参数的类型,在根据具体的类型去获取dblinkId,并根据该值进行多数据源的切换。 + * + * @param arg 可选的入参。MyDataSourceResolver注解中的arg参数。 + * @param methodArgs 被织入方法的所有参数。 + * @return 返回用于多数据源切换的类型值。DataSourceResolveAspect 切面方法会根据该返回值和配置信息,进行多数据源切换。 + */ + @Override + public int resolve(String arg, Object[] methodArgs) { + Serializable id; + if (methodArgs[0] instanceof OnlineTable) { + id = ((OnlineTable) methodArgs[0]).getDblinkId(); + } else if (methodArgs[0] instanceof OnlineDict) { + id = ((OnlineDict) methodArgs[0]).getDblinkId(); + } else if (methodArgs[0] instanceof OnlineDatasourceRelation) { + id = ((OnlineDatasourceRelation) methodArgs[0]).getSlaveTable().getDblinkId(); + } else { + throw new IllegalArgumentException("动态表单操作服务方法,不支持类型 [" + + methodArgs[0].getClass().getSimpleName() + "] 作为第一个参数!"); + } + OnlineDblink dblink = onlineDblinkService.getById(id); + return dblink.getDblinkConfigConstant(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineOperationHelper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineOperationHelper.java new file mode 100644 index 00000000..680d12b9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineOperationHelper.java @@ -0,0 +1,388 @@ +package com.flow.demo.common.online.util; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.flow.demo.common.core.constant.ErrorCodeEnum; +import com.flow.demo.common.core.object.ResponseResult; +import com.flow.demo.common.core.upload.BaseUpDownloader; +import com.flow.demo.common.core.upload.UpDownloaderFactory; +import com.flow.demo.common.core.upload.UploadResponseInfo; +import com.flow.demo.common.core.upload.UploadStoreTypeEnum; +import com.flow.demo.common.online.config.OnlineProperties; +import com.flow.demo.common.online.model.OnlineColumn; +import com.flow.demo.common.online.model.OnlineDatasource; +import com.flow.demo.common.online.model.OnlineDatasourceRelation; +import com.flow.demo.common.online.model.OnlineTable; +import com.flow.demo.common.online.model.constant.FieldKind; +import com.flow.demo.common.online.model.constant.RelationType; +import com.flow.demo.common.online.object.ColumnData; +import com.flow.demo.common.online.service.OnlineDatasourceRelationService; +import com.flow.demo.common.online.service.OnlineDatasourceService; +import com.flow.demo.common.online.service.OnlineOperationService; +import com.flow.demo.common.online.service.OnlineTableService; +import com.flow.demo.common.redis.cache.SessionCacheHelper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletResponse; +import java.util.*; +import java.util.stream.Collectors; + +/** + * 在线表单操作的通用帮助对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +@Component +public class OnlineOperationHelper { + + @Autowired + private OnlineDatasourceService onlineDatasourceService; + @Autowired + private OnlineDatasourceRelationService onlineDatasourceRelationService; + @Autowired + private OnlineTableService onlineTableService; + @Autowired + private OnlineOperationService onlineOperationService; + @Autowired + private OnlineProperties onlineProperties; + @Autowired + private UpDownloaderFactory upDownloaderFactory; + @Autowired + private SessionCacheHelper cacheHelper; + + /** + * 验证并获取数据源数据。 + * + * @param datasourceId 数据源Id。 + * @return 数据源详情数据。 + */ + public ResponseResult verifyAndGetDatasource(Long datasourceId) { + String errorMessage; + OnlineDatasource datasource = onlineDatasourceService.getById(datasourceId); + if (datasource == null) { + return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST); + } + OnlineTable masterTable = onlineTableService.getOnlineTableFromCache(datasource.getMasterTableId()); + if (masterTable == null) { + errorMessage = "数据验证失败,数据源主表Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + datasource.setMasterTable(masterTable); + return ResponseResult.success(datasource); + } + + /** + * 验证并获取数据源的关联数据。 + * + * @param datasourceId 数据源Id。 + * @param relationId 数据源关联Id。 + * @return 数据源的关联详情数据。 + */ + public ResponseResult verifyAndGetRelation(Long datasourceId, Long relationId) { + String errorMessage; + OnlineDatasourceRelation relation = onlineDatasourceRelationService.getById(relationId); + if (relation == null || !relation.getDatasourceId().equals(datasourceId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + OnlineTable slaveTable = onlineTableService.getOnlineTableFromCache(relation.getSlaveTableId()); + if (slaveTable == null) { + errorMessage = "数据验证失败,数据源关联 [" + relation.getRelationName() + " ] 引用的从表不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + relation.setSlaveTable(slaveTable); + return ResponseResult.success(relation); + } + + /** + * 验证并获取数据源的一对多关联数据。 + * + * @param datasourceId 数据源Id。 + * @param relationId 数据源一对多关联Id。 + * @return 数据源的一对多关联详情数据。 + */ + public ResponseResult verifyAndGetOneToManyRelation(Long datasourceId, Long relationId) { + String errorMessage; + OnlineDatasourceRelation relation = onlineDatasourceRelationService.getById(relationId); + if (relation == null || !relation.getDatasourceId().equals(datasourceId)) { + return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); + } + if (!relation.getRelationType().equals(RelationType.ONE_TO_MANY)) { + errorMessage = "数据验证失败,数据源关联 [" + relation.getRelationName() + " ] 不是一对多关联,不能调用该接口!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + OnlineTable slaveTable = onlineTableService.getOnlineTableFromCache(relation.getSlaveTableId()); + if (slaveTable == null) { + errorMessage = "数据验证失败,数据源关联 [" + relation.getRelationName() + " ] 引用的从表不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + relation.setSlaveTable(slaveTable); + relation.setSlaveColumn(slaveTable.getColumnMap().get(relation.getSlaveColumnId())); + return ResponseResult.success(relation); + } + + /** + * 验证并获取数据源的指定类型关联数据。 + * + * @param datasourceId 数据源Id。 + * @param relationType 数据源关联类型。 + * @return 数据源指定关联类型的关联数据详情列表。 + */ + public ResponseResult> verifyAndGetRelationList( + Long datasourceId, Integer relationType) { + String errorMessage; + Set datasourceIdSet = CollUtil.newHashSet(datasourceId); + List relationList = onlineDatasourceRelationService + .getOnlineDatasourceRelationListByDatasourceIds(datasourceIdSet, relationType); + for (OnlineDatasourceRelation relation : relationList) { + OnlineTable slaveTable = onlineTableService.getOnlineTableFromCache(relation.getSlaveTableId()); + if (slaveTable == null) { + errorMessage = "数据验证失败,数据源关联 [" + relation.getRelationName() + "] 的从表Id不存在!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + relation.setSlaveTable(slaveTable); + } + return ResponseResult.success(relationList); + } + + /** + * 构建在线表的数据记录。 + * + * @param table 在线数据表对象。 + * @param tableData 在线数据表数据。 + * @param forUpdate 是否为更新。 + * @param ignoreSetColumnId 忽略设置的字段Id。 + * @return 在线表的数据记录。 + */ + public ResponseResult> buildTableData( + OnlineTable table, JSONObject tableData, boolean forUpdate, Long ignoreSetColumnId) { + List columnDataList = new LinkedList<>(); + String errorMessage; + for (OnlineColumn column : table.getColumnMap().values()) { + // 判断一下是否为需要自动填入的字段,如果是,这里就都暂时给空值了,后续操作会自动填补。 + // 这里还能避免一次基于tableData的查询,能快几纳秒也是好的。 + if (this.isAutoSettingField(column) || ObjectUtil.equal(column.getColumnId(), ignoreSetColumnId)) { + columnDataList.add(new ColumnData(column, null)); + continue; + } + Object value = tableData.get(column.getColumnName()); + // 对于主键数据的处理。 + if (column.getPrimaryKey()) { + // 如果是更新则必须包含主键参数。 + if (forUpdate && value == null) { + errorMessage = "数据验证失败,数据表 [" + + table.getTableName() + "] 主键字段 [" + column.getColumnName() + "] 不能为空值!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } else { + if (value == null && !column.getNullable()) { + errorMessage = "数据验证失败,数据表 [" + + table.getTableName() + "] 字段 [" + column.getColumnName() + "] 不能为空值!"; + return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); + } + } + columnDataList.add(new ColumnData(column, value)); + } + return ResponseResult.success(columnDataList); + } + + /** + * 构建多个一对多从表的数据列表。 + * + * @param datasourceId 数据源Id。 + * @param slaveData 多个一对多从表数据的JSON对象。 + * @return 构建后的多个一对多从表数据列表。 + */ + public ResponseResult>>> buildSlaveDataList( + Long datasourceId, JSONObject slaveData) { + Map>> relationDataMap = new HashMap<>(slaveData.size()); + for (String key : slaveData.keySet()) { + Long relationId = Long.parseLong(key); + ResponseResult relationResult = this.verifyAndGetRelation(datasourceId, relationId); + if (!relationResult.isSuccess()) { + return ResponseResult.errorFrom(relationResult); + } + OnlineDatasourceRelation relation = relationResult.getData(); + List> relationDataList = new LinkedList<>(); + relationDataMap.put(relation, relationDataList); + OnlineTable slaveTable = relation.getSlaveTable(); + JSONArray slaveObjectArray = slaveData.getJSONArray(key); + for (int i = 0; i < slaveObjectArray.size(); i++) { + JSONObject slaveObject = slaveObjectArray.getJSONObject(i); + ResponseResult> slaveColumnDataListResult = + this.buildTableData(slaveTable, slaveObject, false, relation.getSlaveColumnId()); + if (!slaveColumnDataListResult.isSuccess()) { + return ResponseResult.errorFrom(slaveColumnDataListResult); + } + relationDataList.add(slaveColumnDataListResult.getData()); + } + } + return ResponseResult.success(relationDataMap); + } + + /** + * 将字符型字段值转换为与参数字段类型匹配的字段值。 + * + * @param column 在线表单字段。 + * @param dataId 字符型字段值。 + * @return 转换后与参数字段类型匹配的字段值。 + */ + public Object convertToTypeValue(OnlineColumn column, String dataId) { + if ("Long".equals(column.getObjectFieldType())) { + return Long.valueOf(dataId); + } else if ("Integer".equals(column.getObjectFieldType())) { + return Integer.valueOf(dataId); + } + return dataId; + } + + /** + * 将字符型字段值集合转换为与参数字段类型匹配的字段值集合。 + * + * @param column 在线表单字段。 + * @param dataIdSet 字符型字段值集合。 + * @return 转换后与参数字段类型匹配的字段值集合。 + */ + public Set convertToTypeValue(OnlineColumn column, Set dataIdSet) { + if ("Long".equals(column.getObjectFieldType())) { + return dataIdSet.stream().map(Long::valueOf).collect(Collectors.toSet()); + } else if ("Integer".equals(column.getObjectFieldType())) { + return dataIdSet.stream().map(Integer::valueOf).collect(Collectors.toSet()); + } + return dataIdSet; + } + + /** + * 下载数据。 + * + * @param table 在线表对象。 + * @param dataId 在线表数据主键Id。 + * @param fieldName 数据表字段名。 + * @param filename 下载文件名。 + * @param asImage 是否为图片。 + * @param response HTTP 应对对象。 + */ + public void doDownload( + OnlineTable table, String dataId, String fieldName, String filename, Boolean asImage, HttpServletResponse response) { + // 使用try来捕获异常,是为了保证一旦出现异常可以返回500的错误状态,便于调试。 + // 否则有可能给前端返回的是200的错误码。 + try { + // 如果请求参数中没有包含主键Id,就判断该文件是否为当前session上传的。 + if (ObjectUtil.isEmpty(dataId)) { + if (!cacheHelper.existSessionUploadFile(filename)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN); + return; + } + } else { + Map dataMap = + onlineOperationService.getMasterData(table, null, null, dataId); + if (dataMap == null) { + ResponseResult.output(HttpServletResponse.SC_NOT_FOUND); + return; + } + String fieldJsonData = (String) dataMap.get(fieldName); + if (fieldJsonData == null) { + ResponseResult.output(HttpServletResponse.SC_BAD_REQUEST); + return; + } + if (!BaseUpDownloader.containFile(fieldJsonData, filename)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN); + return; + } + } + OnlineColumn downloadColumn = null; + for (OnlineColumn column : table.getColumnMap().values()) { + if (column.getColumnName().equals(fieldName)) { + if (asImage) { + if (ObjectUtil.notEqual(column.getFieldKind(), FieldKind.UPLOAD_IMAGE)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD)); + return; + } + } else { + if (ObjectUtil.notEqual(column.getFieldKind(), FieldKind.UPLOAD)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD)); + return; + } + } + downloadColumn = column; + break; + } + } + if (downloadColumn == null) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.INVALID_DATA_FIELD)); + return; + } + BaseUpDownloader upDownloader = upDownloaderFactory.get(UploadStoreTypeEnum.LOCAL_SYSTEM); + upDownloader.doDownload(onlineProperties.getUploadFileBaseDir(), + table.getModelName(), fieldName, filename, asImage, response); + } catch (Exception e) { + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + log.error(e.getMessage(), e); + } + } + + /** + * 上传数据。 + * + * @param table 在线表对象。 + * @param fieldName 数据表字段名。 + * @param asImage 是否为图片。 + * @param uploadFile 上传的文件。 + */ + public void doUpload(OnlineTable table, String fieldName, Boolean asImage, MultipartFile uploadFile) throws Exception { + OnlineColumn uploadColumn = null; + for (OnlineColumn column : table.getColumnMap().values()) { + if (column.getColumnName().equals(fieldName)) { + if (asImage) { + if (ObjectUtil.notEqual(column.getFieldKind(), FieldKind.UPLOAD_IMAGE)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD)); + return; + } + } else { + if (ObjectUtil.notEqual(column.getFieldKind(), FieldKind.UPLOAD)) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FIELD)); + return; + } + } + uploadColumn = column; + break; + } + } + if (uploadColumn == null) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.INVALID_DATA_FIELD)); + return; + } + BaseUpDownloader upDownloader = upDownloaderFactory.get(UploadStoreTypeEnum.LOCAL_SYSTEM); + UploadResponseInfo responseInfo = upDownloader.doUpload(null, + onlineProperties.getUploadFileBaseDir(), table.getModelName(), fieldName, asImage, uploadFile); + if (responseInfo.getUploadFailed()) { + ResponseResult.output(HttpServletResponse.SC_FORBIDDEN, + ResponseResult.error(ErrorCodeEnum.UPLOAD_FAILED, responseInfo.getErrorMessage())); + return; + } + // 动态表单的下载url和普通表单有所不同,由前端负责动态拼接。 + responseInfo.setDownloadUri(null); + cacheHelper.putSessionUploadFile(responseInfo.getFilename()); + ResponseResult.output(ResponseResult.success(responseInfo)); + } + + private boolean isAutoSettingField(OnlineColumn column) { + return (ObjectUtil.equal(column.getFieldKind(), FieldKind.CREATE_TIME) + || ObjectUtil.equal(column.getFieldKind(), FieldKind.CREATE_USER_ID) + || ObjectUtil.equal(column.getFieldKind(), FieldKind.UPDATE_TIME) + || ObjectUtil.equal(column.getFieldKind(), FieldKind.UPDATE_USER_ID) + || ObjectUtil.equal(column.getFieldKind(), FieldKind.LOGIC_DELETE)); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineUtil.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineUtil.java new file mode 100644 index 00000000..9254027f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/util/OnlineUtil.java @@ -0,0 +1,30 @@ +package com.flow.demo.common.online.util; + +/** + * 在线表单的工具类。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class OnlineUtil { + + /** + * 根据输入参数,拼接在线表单操作的查看权限字。 + * + * @param datasourceVariableName 数据源变量名。 + * @return 拼接后的在线表单操作的查看权限字。 + */ + public static String makeViewPermCode(String datasourceVariableName) { + return "online:" + datasourceVariableName + ":view"; + } + + /** + * 根据输入参数,拼接在线表单操作的编辑权限字。 + * + * @param datasourceVariableName 数据源变量名。 + * @return 拼接后的在线表单操作的编辑权限字。 + */ + public static String makeEditPermCode(String datasourceVariableName) { + return "online:" + datasourceVariableName + ":edit"; + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineColumnRuleVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineColumnRuleVo.java new file mode 100644 index 00000000..0a8c70c0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineColumnRuleVo.java @@ -0,0 +1,28 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +/** + * 在线表单数据表字段规则和字段多对多关联VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineColumnRuleVo { + + /** + * 字段Id。 + */ + private Long columnId; + + /** + * 规则Id。 + */ + private Long ruleId; + + /** + * 规则属性数据。 + */ + private String propDataJson; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineColumnVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineColumnVo.java new file mode 100644 index 00000000..ea24b4ca --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineColumnVo.java @@ -0,0 +1,136 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单数据表字段规则和字段多对多关联VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineColumnVo { + + /** + * 主键Id。 + */ + private Long columnId; + + /** + * 字段名。 + */ + private String columnName; + + /** + * 数据表Id。 + */ + private Long tableId; + + /** + * 数据表中的字段类型。 + */ + private String columnType; + + /** + * 数据表中的完整字段类型(包括了精度和刻度)。 + */ + private String fullColumnType; + + /** + * 是否为主键。 + */ + private Boolean primaryKey; + + /** + * 是否是自增主键(0: 不是 1: 是)。 + */ + private Boolean autoIncrement; + + /** + * 是否可以为空 (0: 不可以为空 1: 可以为空)。 + */ + private Boolean nullable; + + /** + * 缺省值。 + */ + private String columnDefault; + + /** + * 字段在数据表中的显示位置。 + */ + private Integer columnShowOrder; + + /** + * 数据表中的字段注释。 + */ + private String columnComment; + + /** + * 对象映射字段名称。 + */ + private String objectFieldName; + + /** + * 对象映射字段类型。 + */ + private String objectFieldType; + + /** + * 过滤类型。 + */ + private Integer filterType; + + /** + * 是否是主键的父Id。 + */ + private Boolean parentKey; + + /** + * 是否部门过滤字段。 + */ + private Boolean deptFilter; + + /** + * 是否用户过滤字段。 + */ + private Boolean userFilter; + + /** + * 字段类别。 + */ + private Integer fieldKind; + + /** + * 包含的文件文件数量,0表示无限制。 + */ + private Integer maxFileCount; + + /** + * 字典Id。 + */ + private Long dictId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * fieldKind 常量字典关联数据。 + */ + private Map fieldKindDictMap; + + /** + * dictId 的一对一关联。 + */ + private Map dictInfo; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDatasourceRelationVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDatasourceRelationVo.java new file mode 100644 index 00000000..9962d235 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDatasourceRelationVo.java @@ -0,0 +1,111 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单的数据源关联VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineDatasourceRelationVo { + + /** + * 主键Id。 + */ + private Long relationId; + + /** + * 关联名称。 + */ + private String relationName; + + /** + * 变量名。 + */ + private String variableName; + + /** + * 主数据源Id。 + */ + private Long datasourceId; + + /** + * 关联类型。 + */ + private Integer relationType; + + /** + * 主表关联字段Id。 + */ + private Long masterColumnId; + + /** + * 从表Id。 + */ + private Long slaveTableId; + + /** + * 从表关联字段Id。 + */ + private Long slaveColumnId; + + /** + * 删除主表的时候是否级联删除一对一和一对多的从表数据,多对多只是删除关联,不受到这个标记的影响。。 + */ + private Boolean cascadeDelete; + + /** + * 是否左连接。 + */ + private Boolean leftJoin; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * masterColumnId 的一对一关联数据对象,数据对应类型为OnlineColumnVo。 + */ + private Map masterColumn; + + /** + * slaveTableId 的一对一关联数据对象,数据对应类型为OnlineTableVo。 + */ + private Map slaveTable; + + /** + * slaveColumnId 的一对一关联数据对象,数据对应类型为OnlineColumnVo。 + */ + private Map slaveColumn; + + /** + * masterColumnId 字典关联数据。 + */ + private Map masterColumnIdDictMap; + + /** + * slaveTableId 字典关联数据。 + */ + private Map slaveTableIdDictMap; + + /** + * slaveColumnId 字典关联数据。 + */ + private Map slaveColumnIdDictMap; + + /** + * relationType 常量字典关联数据。 + */ + private Map relationTypeDictMap; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDatasourceVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDatasourceVo.java new file mode 100644 index 00000000..264b0488 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDatasourceVo.java @@ -0,0 +1,67 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 在线表单的数据源VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineDatasourceVo { + + /** + * 主键Id。 + */ + private Long datasourceId; + + /** + * 数据源名称。 + */ + private String datasourceName; + + /** + * 数据源变量名,会成为数据访问url的一部分。 + */ + private String variableName; + + /** + * 数据库链接Id。 + */ + private Long dblinkId; + + /** + * 主表Id。 + */ + private Long masterTableId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * datasourceId 的多对多关联表数据对象,数据对应类型为OnlinePageDatasourceVo。 + */ + private Map onlinePageDatasource; + + /** + * masterTableId 字典关联数据。 + */ + private Map masterTableIdDictMap; + + /** + * 当前数据源及其关联,引用的数据表对象列表。 + */ + private List tableList; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDblinkVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDblinkVo.java new file mode 100644 index 00000000..644b78a1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDblinkVo.java @@ -0,0 +1,45 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * 在线表单数据表所在数据库链接VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineDblinkVo { + + /** + * 主键Id。 + */ + private Long dblinkId; + + /** + * 链接中文名称。 + */ + private String dblinkName; + + /** + * 链接英文名称。 + */ + private String variableName; + + /** + * 链接描述。 + */ + private String dblinkDesc; + + /** + * 数据源配置常量。 + */ + private Integer dblinkConfigConstant; + + /** + * 创建时间。 + */ + private Date createTime; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDictVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDictVo.java new file mode 100644 index 00000000..b4d4da4d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineDictVo.java @@ -0,0 +1,116 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单关联的字典VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineDictVo { + + /** + * 主键Id。 + */ + private Long dictId; + + /** + * 字典名称。 + */ + private String dictName; + + /** + * 字典类型。 + */ + private Integer dictType; + + /** + * 数据库链接Id。 + */ + private Long dblinkId; + + /** + * 字典表名称。 + */ + private String tableName; + + /** + * 字典表键字段名称。 + */ + private String keyColumnName; + + /** + * 字典表父键字段名称。 + */ + private String parentKeyColumnName; + + /** + * 字典值字段名称。 + */ + private String valueColumnName; + + /** + * 逻辑删除字段。 + */ + private String deletedColumnName; + + /** + * 用户过滤滤字段名称。 + */ + private String userFilterColumnName; + + /** + * 部门过滤字段名称。 + */ + private String deptFilterColumnName; + + /** + * 租户过滤字段名称。 + */ + private String tenantFilterColumnName; + + /** + * 是否树形标记。 + */ + private Boolean treeFlag; + + /** + * 获取字典数据的url。 + */ + private String dictListUrl; + + /** + * 根据主键id批量获取字典数据的url。 + */ + private String dictIdsUrl; + + /** + * 字典的JSON数据。 + */ + private String dictDataJson; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * dictType 常量字典关联数据。 + */ + private Map dictTypeDictMap; + + /** + * 数据库链接Id字典关联数据。 + */ + private Map dblinkIdDictMap; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineFormVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineFormVo.java new file mode 100644 index 00000000..e3193e56 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineFormVo.java @@ -0,0 +1,92 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 在线表单VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineFormVo { + + /** + * 主键Id。 + */ + private Long formId; + + /** + * 页面Id。 + */ + private Long pageId; + + /** + * 表单编码。 + */ + private String formCode; + + /** + * 表单名称。 + */ + private String formName; + + /** + * 表单类型。 + */ + private Integer formType; + + /** + * 表单类别。 + */ + private Integer formKind; + + /** + * 表单主表Id。 + */ + private Long masterTableId; + + /** + * 表单组件JSON。 + */ + private String widgetJson; + + /** + * 表单参数JSON。 + */ + private String paramsJson; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * masterTableId 的一对一关联数据对象,数据对应类型为OnlineTableVo。 + */ + private Map onlineTable; + + /** + * masterTableId 字典关联数据。 + */ + private Map masterTableIdDictMap; + + /** + * formType 常量字典关联数据。 + */ + private Map formTypeDictMap; + + /** + * 当前表单关联的数据源Id集合。 + */ + private List datasourceIdList; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlinePageDatasourceVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlinePageDatasourceVo.java new file mode 100644 index 00000000..669ff6de --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlinePageDatasourceVo.java @@ -0,0 +1,28 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +/** + * 在线表单页面和数据源多对多关联VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlinePageDatasourceVo { + + /** + * 主键Id。 + */ + private Long id; + + /** + * 页面主键Id。 + */ + private Long pageId; + + /** + * 数据源主键Id。 + */ + private Long datasourceId; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlinePageVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlinePageVo.java new file mode 100644 index 00000000..efec4989 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlinePageVo.java @@ -0,0 +1,66 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单所在页面VO对象。这里我们可以把页面理解为表单的容器。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlinePageVo { + + /** + * 主键Id。 + */ + private Long pageId; + + /** + * 页面编码。 + */ + private String pageCode; + + /** + * 页面名称。 + */ + private String pageName; + + /** + * 页面类型。 + */ + private Integer pageType; + + /** + * 页面编辑状态。 + */ + private Integer status; + + /** + * 是否发布。 + */ + private Boolean published; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * pageType 常量字典关联数据。 + */ + private Map pageTypeDictMap; + + /** + * status 常量字典关联数据。 + */ + private Map statusDictMap; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineRuleVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineRuleVo.java new file mode 100644 index 00000000..b3739a3b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineRuleVo.java @@ -0,0 +1,61 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +import java.util.Date; +import java.util.Map; + +/** + * 在线表单数据表字段验证规则VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineRuleVo { + + /** + * 主键Id。 + */ + private Long ruleId; + + /** + * 规则名称。 + */ + private String ruleName; + + /** + * 规则类型。 + */ + private Integer ruleType; + + /** + * 内置规则标记。 + */ + private Boolean builtin; + + /** + * 自定义规则的正则表达式。 + */ + private String pattern; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 创建时间。 + */ + private Date createTime; + + /** + * ruleId 的多对多关联表数据对象,数据对应类型为OnlineColumnRuleVo。 + */ + private Map onlineColumnRule; + + /** + * ruleType 常量字典关联数据。 + */ + private Map ruleTypeDictMap; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineTableVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineTableVo.java new file mode 100644 index 00000000..9ef43d88 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineTableVo.java @@ -0,0 +1,45 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +import java.util.Date; + +/** + * 在线表单的数据表VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineTableVo { + + /** + * 主键Id。 + */ + private Long tableId; + + /** + * 表名称。 + */ + private String tableName; + + /** + * 实体名称。 + */ + private String modelName; + + /** + * 数据库链接Id。 + */ + private Long dblinkId; + + /** + * 更新时间。 + */ + private Date updateTime; + + /** + * 创建时间。 + */ + private Date createTime; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineVirtualColumnVo.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineVirtualColumnVo.java new file mode 100644 index 00000000..eb4c3d05 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/java/com/flow/demo/common/online/vo/OnlineVirtualColumnVo.java @@ -0,0 +1,73 @@ +package com.flow.demo.common.online.vo; + +import lombok.Data; + +/** + * 在线数据表虚拟字段VO对象。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +public class OnlineVirtualColumnVo { + + /** + * 主键Id。 + */ + private Long virtualColumnId; + + /** + * 所在表Id。 + */ + private Long tableId; + + /** + * 字段名称。 + */ + private String objectFieldName; + + /** + * 属性类型。 + */ + private String objectFieldType; + + /** + * 字段提示名。 + */ + private String columnPrompt; + + /** + * 虚拟字段类型(0: 聚合)。 + */ + private Integer virtualType; + + /** + * 关联数据源Id。 + */ + private Long datasourceId; + + /** + * 关联Id。 + */ + private Long relationId; + + /** + * 聚合字段所在关联表Id。 + */ + private Long aggregationTableId; + + /** + * 关联表聚合字段Id。 + */ + private Long aggregationColumnId; + + /** + * 聚合类型(0: count 1: sum 2: avg 3: max 4:min)。 + */ + private Integer aggregationType; + + /** + * 存储过滤条件的json。 + */ + private String whereClauseJson; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/resources/META-INF/spring.factories b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..bc04bebf --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-online/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.flow.demo.common.online.config.OnlineAutoConfig \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/pom.xml new file mode 100644 index 00000000..68795430 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/pom.xml @@ -0,0 +1,29 @@ + + + + common + com.flow.demo + 1.0.0 + + 4.0.0 + + common-redis + 1.0.0 + common-redis + jar + + + + com.flow.demo + common-core + 1.0.0 + + + org.redisson + redisson + ${redisson.version} + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedisDictionaryCache.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedisDictionaryCache.java new file mode 100644 index 00000000..55d61179 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedisDictionaryCache.java @@ -0,0 +1,412 @@ +package com.flow.demo.common.redis.cache; + +import com.alibaba.fastjson.JSON; +import com.flow.demo.common.core.cache.DictionaryCache; +import com.flow.demo.common.core.constant.ApplicationConstant; +import com.flow.demo.common.core.exception.RedisCacheAccessException; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; +import org.redisson.api.RMap; +import org.redisson.api.RedissonClient; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 字典数据Redis缓存对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class RedisDictionaryCache implements DictionaryCache { + + /** + * redisson客户端。 + */ + protected final RedissonClient redissonClient; + /** + * 数据存储对象。 + */ + protected final RMap dataMap; + /** + * 字典值对象类型。 + */ + protected final Class valueClazz; + /** + * 由于大部分场景是读取操作,所以使用读写锁提高并发的伸缩性。 + */ + protected final ReadWriteLock lock; + /** + * 获取字典主键数据的函数对象。 + */ + protected final Function idGetter; + /** + * 超时时长。单位毫秒。 + */ + protected static final long TIMEOUT = 2000L; + + /** + * 当前对象的构造器函数。 + * + * @param redissonClient Redisson的客户端对象。 + * @param dictionaryName 字典表的名称。等同于redis hash对象的key。 + * @param valueClazz 值对象的Class对象。 + * @param idGetter 获取当前类主键字段值的函数对象。 + * @param 字典主键类型。 + * @param 字典对象类型 + * @return 实例化后的字典内存缓存对象。 + */ + public static RedisDictionaryCache create( + RedissonClient redissonClient, + String dictionaryName, + Class valueClazz, + Function idGetter) { + if (idGetter == null) { + throw new IllegalArgumentException("IdGetter can't be NULL."); + } + return new RedisDictionaryCache<>(redissonClient, dictionaryName, valueClazz, idGetter); + } + + /** + * 构造函数。 + * + * @param redissonClient Redisson的客户端对象。 + * @param dictionaryName 字典表的名称。等同于redis hash对象的key。确保全局唯一。 + * @param valueClazz 值对象的Class对象。 + * @param idGetter 获取当前类主键字段值的函数对象。 + */ + public RedisDictionaryCache( + RedissonClient redissonClient, + String dictionaryName, + Class valueClazz, + Function idGetter) { + this.redissonClient = redissonClient; + this.dataMap = redissonClient.getMap(dictionaryName + ApplicationConstant.DICT_CACHE_NAME_SUFFIX); + this.lock = new ReentrantReadWriteLock(); + this.valueClazz = valueClazz; + this.idGetter = idGetter; + } + + /** + * 按照数据插入的顺序返回全部字典对象的列表。 + * + * @return 全部字段数据列表。 + */ + @Override + public List getAll() { + Collection dataList; + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataList = dataMap.readAllValues(); + } finally { + // 如果上面的操作时间超过redisson.lockWatchdogTimeout的时长, + // redis会将与该锁关联的键删除,此后调用unlock的时候,就会抛出运行时异常。 + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::getAll] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + if (CollectionUtils.isEmpty(dataList)) { + return new LinkedList<>(); + } + return dataList.stream() + .map(data -> JSON.parseObject(data, valueClazz)) + .collect(Collectors.toCollection(LinkedList::new)); + } + + /** + * 获取缓存中与键列表对应的对象列表。 + * + * @param keys 主键集合。 + * @return 对象列表。 + */ + @Override + public List getInList(Set keys) { + if (CollectionUtils.isEmpty(keys)) { + return new LinkedList<>(); + } + Collection dataList; + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataList = dataMap.getAll(keys).values(); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::getInList] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + if (dataList == null) { + return new LinkedList<>(); + } + return dataList.stream() + .map(data -> JSON.parseObject(data, valueClazz)) + .collect(Collectors.toCollection(LinkedList::new)); + } + + /** + * 从缓存中获取指定的数据。 + * + * @param id 数据的key。 + * @return 获取到的数据,如果没有返回null。 + */ + @Override + public V get(K id) { + if (id == null) { + return null; + } + String data; + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + data = dataMap.get(id); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::get] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + if (data == null) { + return null; + } + return JSON.parseObject(data, valueClazz); + } + + /** + * 获取缓存中数据条目的数量。 + * + * @return 返回缓存的数据数量。 + */ + @Override + public int getCount() { + return dataMap.size(); + } + + /** + * 将参数List中的数据保存到缓存中,同时保证getAll返回的数据列表,与参数列表中数据项的顺序保持一致。 + * + * @param dataList 待缓存的数据列表。 + */ + @Override + public void putAll(List dataList) { + if (CollectionUtils.isEmpty(dataList)) { + return; + } + Map map = dataList.stream() + .collect(Collectors.toMap(idGetter, JSON::toJSONString)); + String exceptionMessage; + try { + if (lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.putAll(map, 1000); + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::putAll] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } + + /** + * 将数据存入缓存。 + * + * @param id 通常为字典数据的主键。 + * @param data 字典数据对象。 + */ + @Override + public void put(K id, V data) { + if (id == null || data == null) { + return; + } + String exceptionMessage; + try { + if (lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.fastPut(id, JSON.toJSONString(data)); + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::put] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } + + /** + * 重新加载,先清空原有数据,在执行putAll的操作。 + * + * @param dataList 待缓存的数据列表。 + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + @Override + public void reload(List dataList, boolean force) { + Map map = null; + if (CollectionUtils.isNotEmpty(dataList)) { + map = dataList.stream().collect(Collectors.toMap(idGetter, JSON::toJSONString)); + } + String exceptionMessage; + try { + if (lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + // 如果不强制刷新,需要先判断缓存中是否存在数据。 + if (!force && this.getCount() > 0) { + return; + } + dataMap.clear(); + if (map != null) { + dataMap.putAll(map, 1000); + } + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::reload] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } + + /** + * 删除缓存中指定的键。 + * + * @param id 待删除数据的主键。 + * @return 返回被删除的对象,如果主键不存在,返回null。 + */ + @Override + public V invalidate(K id) { + if (id == null) { + return null; + } + String data; + String exceptionMessage; + try { + if (lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + data = dataMap.remove(id); + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::invalidate] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + if (data == null) { + return null; + } + return JSON.parseObject(data, valueClazz); + } + + /** + * 删除缓存中,参数列表中包含的键。 + * + * @param keys 待删除数据的主键集合。 + */ + @SuppressWarnings("unchecked") + @Override + public void invalidateSet(Set keys) { + if (CollectionUtils.isEmpty(keys)) { + return; + } + Object[] keyArray = keys.toArray(new Object[]{}); + String exceptionMessage; + try { + if (lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.fastRemove((K[]) keyArray); + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::invalidateSet] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } + + /** + * 清空缓存。 + */ + @Override + public void invalidateAll() { + String exceptionMessage; + try { + if (lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.clear(); + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::invalidateAll] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedisTreeDictionaryCache.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedisTreeDictionaryCache.java new file mode 100644 index 00000000..8dc48708 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedisTreeDictionaryCache.java @@ -0,0 +1,354 @@ +package com.flow.demo.common.redis.cache; + +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import com.flow.demo.common.core.constant.ApplicationConstant; +import com.flow.demo.common.core.exception.RedisCacheAccessException; +import com.google.common.collect.LinkedListMultimap; +import com.google.common.collect.Multimap; +import org.apache.commons.collections4.CollectionUtils; +import org.redisson.api.RListMultimap; +import org.redisson.api.RedissonClient; + +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 树形字典数据Redis缓存对象。 + * + * @param 字典表主键类型。 + * @param 字典表对象类型。 + * @author Jerry + * @date 2021-06-06 + */ +@Slf4j +public class RedisTreeDictionaryCache extends RedisDictionaryCache { + + /** + * 树形数据存储对象。 + */ + private final RListMultimap allTreeMap; + /** + * 获取字典父主键数据的函数对象。 + */ + protected final Function parentIdGetter; + + /** + * 当前对象的构造器函数。 + * + * @param redissonClient Redisson的客户端对象。 + * @param dictionaryName 字典表的名称。等同于redis hash对象的key。 + * @param valueClazz 值对象的Class对象。 + * @param idGetter 获取当前类主键字段值的函数对象。 + * @param parentIdGetter 获取当前类父主键字段值的函数对象。 + * @param 字典主键类型。 + * @param 字典对象类型 + * @return 实例化后的树形字典内存缓存对象。 + */ + public static RedisTreeDictionaryCache create( + RedissonClient redissonClient, + String dictionaryName, + Class valueClazz, + Function idGetter, + Function parentIdGetter) { + if (idGetter == null) { + throw new IllegalArgumentException("IdGetter can't be NULL."); + } + if (parentIdGetter == null) { + throw new IllegalArgumentException("ParentIdGetter can't be NULL."); + } + return new RedisTreeDictionaryCache<>( + redissonClient, dictionaryName, valueClazz, idGetter, parentIdGetter); + } + + /** + * 构造函数。 + * + * @param redissonClient Redisson的客户端对象。 + * @param dictionaryName 字典表的名称。等同于redis hash对象的key。 + * @param valueClazz 值对象的Class对象。 + * @param idGetter 获取当前类主键字段值的函数对象。 + * @param parentIdGetter 获取当前类父主键字段值的函数对象。 + */ + public RedisTreeDictionaryCache( + RedissonClient redissonClient, + String dictionaryName, + Class valueClazz, + Function idGetter, + Function parentIdGetter) { + super(redissonClient, dictionaryName, valueClazz, idGetter); + this.allTreeMap = redissonClient.getListMultimap( + dictionaryName + ApplicationConstant.TREE_DICT_CACHE_NAME_SUFFIX); + this.parentIdGetter = parentIdGetter; + } + + /** + * 获取该父主键的子数据列表。 + * + * @param parentId 父主键Id。如果parentId为null,则返回所有一级节点数据。 + * @return 子数据列表。 + */ + public List getListByParentId(K parentId) { + List dataList; + String exceptionMessage; + try { + if (lock.readLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataList = allTreeMap.get(parentId); + } finally { + lock.readLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisTreeDictionaryCache::getListByParentId] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + if (CollectionUtils.isEmpty(dataList)) { + return new LinkedList<>(); + } + List resultList = new LinkedList<>(); + dataList.forEach(data -> resultList.add(JSON.parseObject(data, valueClazz))); + return resultList; + } + + /** + * 将参数List中的数据保存到缓存中,同时保证getAll返回的数据列表,与参数列表中数据项的顺序保持一致。 + * + * @param dataList 待缓存的数据列表。 + */ + @Override + public void putAll(List dataList) { + if (CollectionUtils.isEmpty(dataList)) { + return; + } + // 锁外执行数据结构组装,降低锁的粒度,提高并发性。 + Map map = dataList.stream() + .collect(Collectors.toMap(idGetter, JSON::toJSONString)); + Multimap treeMap = LinkedListMultimap.create(); + for (V data : dataList) { + treeMap.put(parentIdGetter.apply(data), JSON.toJSONString(data)); + } + Set>> entries = treeMap.asMap().entrySet(); + String exceptionMessage; + try { + if (this.lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.putAll(map, 1000); + for (Map.Entry> entry : entries) { + allTreeMap.removeAll(entry.getKey()); + allTreeMap.putAll(entry.getKey(), entry.getValue()); + } + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisTreeDictionaryCache::putAll] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } + + /** + * 将数据存入缓存。 + * + * @param id 通常为字典数据的主键。 + * @param data 字典数据对象。 + */ + @Override + public void put(K id, V data) { + if (id == null || data == null) { + return; + } + String stringData = JSON.toJSONString(data); + K parentId = parentIdGetter.apply(data); + String exceptionMessage; + try { + if (this.lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + String oldData = dataMap.put(id, stringData); + if (oldData != null) { + allTreeMap.remove(parentId, oldData); + } + allTreeMap.put(parentId, stringData); + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisTreeDictionaryCache::put] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } + + /** + * 行为等同于接口中的描述。这里之所以重写,是因为不确定redisson的读写锁, + * 是否为可重入锁。 + * + * @param dataList 待缓存的数据列表。 + * @param force true则强制刷新,如果false,当缓存中存在数据时不刷新。 + */ + @Override + public void reload(List dataList, boolean force) { + // 锁外执行数据结构组装,降低锁的粒度,提高并发性。 + Map map = null; + Set>> entries = null; + if (CollectionUtils.isNotEmpty(dataList)) { + map = dataList.stream().collect(Collectors.toMap(idGetter, JSON::toJSONString)); + Multimap treeMap = LinkedListMultimap.create(); + for (V data : dataList) { + treeMap.put(parentIdGetter.apply(data), JSON.toJSONString(data)); + } + entries = treeMap.asMap().entrySet(); + } + String exceptionMessage; + try { + if (lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + // 如果不强制刷新,需要先判断缓存中是否存在数据。 + if (!force && this.getCount() > 0) { + return; + } + dataMap.clear(); + allTreeMap.clear(); + if (map != null) { + dataMap.putAll(map, 1000); + for (Map.Entry> entry : entries) { + allTreeMap.removeAll(entry.getKey()); + allTreeMap.putAll(entry.getKey(), entry.getValue()); + } + } + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisDictionaryCache::reload] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } + + /** + * 删除缓存中指定的键。 + * + * @param id 待删除数据的主键。 + * @return 返回被删除的对象,如果主键不存在,返回null。 + */ + @Override + public V invalidate(K id) { + if (id == null) { + return null; + } + V data = null; + String exceptionMessage; + try { + if (this.lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + String stringData = dataMap.remove(id); + if (stringData != null) { + data = JSON.parseObject(stringData, valueClazz); + K parentId = parentIdGetter.apply(data); + allTreeMap.remove(parentId, stringData); + } + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisTreeDictionaryCache::invalidate] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + return data; + } + + /** + * 删除缓存中,参数列表中包含的键。 + * + * @param keys 待删除数据的主键集合。 + */ + @Override + public void invalidateSet(Set keys) { + if (CollectionUtils.isEmpty(keys)) { + return; + } + String exceptionMessage; + try { + if (lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + keys.forEach(id -> { + if (id != null) { + String stringData = dataMap.remove(id); + if (stringData != null) { + K parentId = parentIdGetter.apply(JSON.parseObject(stringData, valueClazz)); + allTreeMap.remove(parentId, stringData); + } + } + }); + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisTreeDictionaryCache::invalidateSet] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } + + /** + * 清空缓存。 + */ + @Override + public void invalidateAll() { + String exceptionMessage; + try { + if (lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { + try { + dataMap.clear(); + allTreeMap.clear(); + } finally { + lock.writeLock().unlock(); + } + } else { + throw new TimeoutException(); + } + } catch (Exception e) { + exceptionMessage = String.format( + "LOCK Operation of [RedisTreeDictionaryCache::invalidateAll] encountered EXCEPTION [%s] for DICT [%s].", + e.getClass().getSimpleName(), valueClazz.getSimpleName()); + log.warn(exceptionMessage); + throw new RedisCacheAccessException(exceptionMessage, e); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedissonCacheConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedissonCacheConfig.java new file mode 100644 index 00000000..8a49fc05 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/RedissonCacheConfig.java @@ -0,0 +1,67 @@ +package com.flow.demo.common.redis.cache; + +import com.google.common.collect.Maps; +import org.redisson.api.RedissonClient; +import org.redisson.spring.cache.CacheConfig; +import org.redisson.spring.cache.RedissonSpringCacheManager; +import org.springframework.cache.CacheManager; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Map; + +/** + * 使用Redisson作为Redis的分布式缓存库。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +@EnableCaching +public class RedissonCacheConfig { + + private static final int DEFAULT_TTL = 3600000; + + /** + * 定义cache名称、超时时长(毫秒)。 + */ + public enum CacheEnum { + /** + * session下上传文件名的缓存(时间是24小时)。 + */ + UPLOAD_FILENAME_CACHE(86400000), + /** + * 缺省全局缓存(时间是24小时)。 + */ + GLOBAL_CACHE(86400000); + + /** + * 缓存的时长(单位:毫秒) + */ + private int ttl = DEFAULT_TTL; + + CacheEnum() { + } + + CacheEnum(int ttl) { + this.ttl = ttl; + } + + public int getTtl() { + return ttl; + } + } + + /** + * 初始化缓存配置。 + */ + @Bean + CacheManager cacheManager(RedissonClient redissonClient) { + Map config = Maps.newHashMap(); + for (CacheEnum c : CacheEnum.values()) { + config.put(c.name(), new CacheConfig(c.getTtl(), 0)); + } + return new RedissonSpringCacheManager(redissonClient, config); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/SessionCacheHelper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/SessionCacheHelper.java new file mode 100644 index 00000000..bc0f0ff3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/cache/SessionCacheHelper.java @@ -0,0 +1,74 @@ +package com.flow.demo.common.redis.cache; + +import com.flow.demo.common.core.object.TokenData; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.Cache; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.Set; + +/** + * Session数据缓存辅助类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@SuppressWarnings("unchecked") +@Component +public class SessionCacheHelper { + + @Autowired + private CacheManager cacheManager; + + /** + * 缓存当前session内,上传过的文件名。 + * + * @param filename 通常是本地存储的文件名,而不是上传时的原始文件名。 + */ + public void putSessionUploadFile(String filename) { + if (filename != null) { + Set sessionUploadFileSet = null; + Cache cache = cacheManager.getCache(RedissonCacheConfig.CacheEnum.UPLOAD_FILENAME_CACHE.name()); + Cache.ValueWrapper valueWrapper = cache.get(TokenData.takeFromRequest().getSessionId()); + if (valueWrapper != null) { + sessionUploadFileSet = (Set) valueWrapper.get(); + } + if (sessionUploadFileSet == null) { + sessionUploadFileSet = new HashSet<>(); + } + sessionUploadFileSet.add(filename); + cache.put(TokenData.takeFromRequest().getSessionId(), sessionUploadFileSet); + } + } + + /** + * 判断参数中的文件名,是否有当前session上传。 + * + * @param filename 通常是本地存储的文件名,而不是上传时的原始文件名。 + * @return true表示该文件是由当前session上传并存储在本地的,否则false。 + */ + public boolean existSessionUploadFile(String filename) { + if (filename == null) { + return false; + } + Cache cache = cacheManager.getCache(RedissonCacheConfig.CacheEnum.UPLOAD_FILENAME_CACHE.name()); + Cache.ValueWrapper valueWrapper = cache.get(TokenData.takeFromRequest().getSessionId()); + if (valueWrapper == null) { + return false; + } + return ((Set) valueWrapper.get()).contains(filename); + } + + /** + * 清除当前session的所有缓存数据。 + * + * @param sessionId 当前会话的SessionId。 + */ + public void removeAllSessionCache(String sessionId) { + for (RedissonCacheConfig.CacheEnum c : RedissonCacheConfig.CacheEnum.values()) { + cacheManager.getCache(c.name()).evict(sessionId); + } + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/config/RedissonConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/config/RedissonConfig.java new file mode 100644 index 00000000..f9ed1c91 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/java/com/flow/demo/common/redis/config/RedissonConfig.java @@ -0,0 +1,102 @@ +package com.flow.demo.common.redis.config; + +import cn.hutool.core.util.ArrayUtil; +import cn.hutool.core.util.StrUtil; +import com.flow.demo.common.core.exception.InvalidRedisModeException; +import org.redisson.Redisson; +import org.redisson.api.RedissonClient; +import org.redisson.config.Config; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Redisson配置类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Configuration +@ConditionalOnProperty(name = "redis.redisson.enabled", havingValue = "true") +public class RedissonConfig { + + @Value("${redis.redisson.lockWatchdogTimeout}") + private Integer lockWatchdogTimeout; + + @Value("${redis.redisson.mode}") + private String mode; + + /** + * 仅仅用于sentinel模式。 + */ + @Value("${redis.redisson.masterName:}") + private String masterName; + + @Value("${redis.redisson.address}") + private String address; + + @Value("${redis.redisson.timeout}") + private Integer timeout; + + @Value("${redis.redisson.password:}") + private String password; + + @Value("${redis.redisson.pool.poolSize}") + private Integer poolSize; + + @Value("${redis.redisson.pool.minIdle}") + private Integer minIdle; + + @Bean + public RedissonClient redissonClient() { + if (StrUtil.isBlank(password)) { + password = null; + } + Config config = new Config(); + if ("single".equals(mode)) { + config.setLockWatchdogTimeout(lockWatchdogTimeout) + .useSingleServer() + .setPassword(password) + .setAddress(address) + .setConnectionPoolSize(poolSize) + .setConnectionMinimumIdleSize(minIdle) + .setConnectTimeout(timeout); + } else if ("cluster".equals(mode)) { + String[] clusterAddresses = StrUtil.splitToArray(address, ','); + config.setLockWatchdogTimeout(lockWatchdogTimeout) + .useClusterServers() + .setPassword(password) + .addNodeAddress(clusterAddresses) + .setConnectTimeout(timeout) + .setMasterConnectionPoolSize(poolSize); + } else if ("sentinel".equals(mode)) { + String[] sentinelAddresses = StrUtil.splitToArray(address, ','); + config.setLockWatchdogTimeout(lockWatchdogTimeout) + .useSentinelServers() + .setPassword(password) + .setMasterName(masterName) + .addSentinelAddress(sentinelAddresses) + .setConnectTimeout(timeout) + .setMasterConnectionPoolSize(poolSize); + } else if ("master-slave".equals(mode)) { + String[] masterSlaveAddresses = StrUtil.splitToArray(address, ','); + if (masterSlaveAddresses.length == 1) { + throw new IllegalArgumentException( + "redis.redisson.address MUST have multiple redis addresses for master-slave mode."); + } + String[] slaveAddresses = new String[masterSlaveAddresses.length - 1]; + ArrayUtil.copy(masterSlaveAddresses, 1, slaveAddresses, 0, slaveAddresses.length); + config.setLockWatchdogTimeout(lockWatchdogTimeout) + .useMasterSlaveServers() + .setPassword(password) + .setMasterAddress(masterSlaveAddresses[0]) + .addSlaveAddress(slaveAddresses) + .setConnectTimeout(timeout) + .setMasterConnectionPoolSize(poolSize); + } else { + throw new InvalidRedisModeException(mode); + } + return Redisson.create(config); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/resources/META-INF/spring.factories b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..029891f9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-redis/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.flow.demo.common.redis.config.RedissonConfig \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/pom.xml new file mode 100644 index 00000000..3cde959c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/pom.xml @@ -0,0 +1,24 @@ + + + + common + com.flow.demo + 1.0.0 + + 4.0.0 + + common-sequence + 1.0.0 + common-sequence + jar + + + + com.flow.demo + common-core + 1.0.0 + + + \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/config/IdGeneratorAutoConfig.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/config/IdGeneratorAutoConfig.java new file mode 100644 index 00000000..d933ff02 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/config/IdGeneratorAutoConfig.java @@ -0,0 +1,14 @@ +package com.flow.demo.common.sequence.config; + +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +/** + * common-sequence模块的自动配置引导类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@EnableConfigurationProperties({IdGeneratorProperties.class}) +public class IdGeneratorAutoConfig { + +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/config/IdGeneratorProperties.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/config/IdGeneratorProperties.java new file mode 100644 index 00000000..9d844b06 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/config/IdGeneratorProperties.java @@ -0,0 +1,20 @@ +package com.flow.demo.common.sequence.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * common-sequence模块的配置类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Data +@ConfigurationProperties(prefix = "sequence") +public class IdGeneratorProperties { + + /** + * 基础版生成器所需的WorkNode参数值。仅当advanceIdGenerator为false时生效。 + */ + private Integer snowflakeWorkNode = 1; +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/generator/BasicIdGenerator.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/generator/BasicIdGenerator.java new file mode 100644 index 00000000..8e852116 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/generator/BasicIdGenerator.java @@ -0,0 +1,48 @@ +package com.flow.demo.common.sequence.generator; + +import cn.hutool.core.lang.Snowflake; +import cn.hutool.core.util.IdUtil; + +/** + * 基础版snowflake计算工具类。 + * 和SnowflakeIdGenerator相比,相同点是均为基于Snowflake算法的生成器。不同点在于当前类的 + * WorkNodeId是通过配置文件静态指定的。而SnowflakeIdGenerator的WorkNodeId是由zk生成的。 + * + * @author Jerry + * @date 2021-06-06 + */ +public class BasicIdGenerator implements MyIdGenerator { + + private final Snowflake snowflake; + + /** + * 构造函数。 + * + * @param workNode 工作节点。 + */ + public BasicIdGenerator(Integer workNode) { + snowflake = IdUtil.createSnowflake(workNode, 0); + } + + /** + * 获取基于Snowflake算法的数值型Id。 + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + @Override + public long nextLongId() { + return this.snowflake.nextId(); + } + + /** + * 获取基于Snowflake算法的字符串Id。 + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + @Override + public String nextStringId() { + return this.snowflake.nextIdStr(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/generator/MyIdGenerator.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/generator/MyIdGenerator.java new file mode 100644 index 00000000..aed14393 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/generator/MyIdGenerator.java @@ -0,0 +1,24 @@ +package com.flow.demo.common.sequence.generator; + +/** + * 分布式Id生成器的统一接口。 + * + * @author Jerry + * @date 2021-06-06 + */ +public interface MyIdGenerator { + + /** + * 获取数值型分布式Id。 + * + * @return 生成后的Id。 + */ + long nextLongId(); + + /** + * 获取字符型分布式Id。 + * + * @return 生成后的Id。 + */ + String nextStringId(); +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/wrapper/IdGeneratorWrapper.java b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/wrapper/IdGeneratorWrapper.java new file mode 100644 index 00000000..8c90af4a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/java/com/flow/demo/common/sequence/wrapper/IdGeneratorWrapper.java @@ -0,0 +1,52 @@ +package com.flow.demo.common.sequence.wrapper; + +import com.flow.demo.common.sequence.config.IdGeneratorProperties; +import com.flow.demo.common.sequence.generator.BasicIdGenerator; +import com.flow.demo.common.sequence.generator.MyIdGenerator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +/** + * 分布式Id生成器的封装类。该对象可根据配置选择不同的生成器实现类。 + * + * @author Jerry + * @date 2021-06-06 + */ +@Component +public class IdGeneratorWrapper { + + @Autowired + private IdGeneratorProperties properties; + /** + * Id生成器接口对象。 + */ + private MyIdGenerator idGenerator; + + /** + * 今后如果支持更多Id生成器时,可以在该函数内实现不同生成器的动态选择。 + */ + @PostConstruct + public void init() { + idGenerator = new BasicIdGenerator(properties.getSnowflakeWorkNode()); + } + + /** + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + public long nextLongId() { + return idGenerator.nextLongId(); + } + + /** + * 由于底层实现为synchronized方法,因此计算过程串行化,且线程安全。 + * + * @return 计算后的全局唯一Id。 + */ + public String nextStringId() { + return idGenerator.nextStringId(); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/resources/META-INF/spring.factories b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..5a44fb00 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/common-sequence/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +com.flow.demo.common.sequence.config.IdGeneratorAutoConfig \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/common/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/common/pom.xml new file mode 100644 index 00000000..fe16716c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/common/pom.xml @@ -0,0 +1,25 @@ + + + + com.flow.demo + DemoFlow + 1.0.0 + + 4.0.0 + + common + pom + + + common-core + common-log + common-datafilter + common-online + common-online-api + common-flow-online + common-flow + common-redis + common-sequence + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/pom.xml b/orange-demo-flowable/orange-demo-flowable-service/pom.xml new file mode 100644 index 00000000..af832d75 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/pom.xml @@ -0,0 +1,210 @@ + + + 4.0.0 + + com.flow.demo + DemoFlow + 1.0.0 + DemoFlow + pom + + + 2.3.10.RELEASE + Cairo-SR8 + 2.3.1 + UTF-8 + 1.8 + 1.8 + 1.8 + DemoFlow + + 4.4 + 1.8 + 4.1.2 + 5.6.4 + 0.9.1 + 1.2.76 + 1.1.5 + 3.0.2 + 1.4.2.Final + 1.18.20 + 3.4.3 + 6.2.0.Final + 6.6.0 + + 1.2.6 + 3.4.2 + 1.3.0 + 3.15.4 + 2.0.0 + + + + application-webadmin + common + + + + + + org.springframework.boot + spring-boot-starter-web + + + spring-boot-starter-logging + org.springframework.boot + + + + + + org.springframework.boot + spring-boot-starter-freemarker + + + + javax.servlet + javax.servlet-api + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.springframework.boot + spring-boot-starter-cache + + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.springframework.security + spring-security-crypto + + + + org.springframework.boot + spring-boot-starter-actuator + + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin.version} + + + + org.hibernate + hibernate-validator + ${hibernate-validator.version} + + + + org.mapstruct + mapstruct + ${mapstruct.version} + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + provided + + + + org.projectlombok + lombok + provided + + + + com.lmax + disruptor + ${disruptor.version} + + + + org.springframework.plugin + spring-plugin-core + 2.0.0.RELEASE + + + org.springframework.plugin + spring-plugin-metadata + 2.0.0.RELEASE + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + mysql + mysql-connector-java + 8.0.22 + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + io.spring.platform + platform-bom + ${spring-platform.version} + pom + import + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + ${maven.compiler.target} + ${maven.compiler.source} + UTF-8 + + + org.projectlombok + lombok + ${lombok.version} + + + org.projectlombok + lombok-mapstruct-binding + 0.2.0 + + + org.mapstruct + mapstruct-processor + ${mapstruct.version} + + + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/db-scripts/zzdemo-online.sql b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/db-scripts/zzdemo-online.sql new file mode 100644 index 00000000..1a83707f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/db-scripts/zzdemo-online.sql @@ -0,0 +1,7977 @@ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for ACT_EVT_LOG +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_EVT_LOG`; +CREATE TABLE `ACT_EVT_LOG` ( + `LOG_NR_` bigint(20) NOT NULL AUTO_INCREMENT, + `TYPE_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TIME_STAMP_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `DATA_` longblob, + `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL, + `IS_PROCESSED_` tinyint(4) DEFAULT '0', + PRIMARY KEY (`LOG_NR_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_GE_BYTEARRAY +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_GE_BYTEARRAY`; +CREATE TABLE `ACT_GE_BYTEARRAY` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `BYTES_` longblob, + `GENERATED_` tinyint(4) DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_FK_BYTEARR_DEPL` (`DEPLOYMENT_ID_`), + CONSTRAINT `ACT_FK_BYTEARR_DEPL` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `ACT_RE_DEPLOYMENT` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_GE_BYTEARRAY +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('1a075ec9-1c4e-11ec-94ee-5ef70686b817', 1, 'flowLeave.bpmn', '1a075ec8-1c4e-11ec-94ee-5ef70686b817', 0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C646566696E6974696F6E7320786D6C6E733D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A7873693D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612D696E7374616E63652220786D6C6E733A7873643D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612220786D6C6E733A666C6F7761626C653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E2220786D6C6E733A62706D6E64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F44492220786D6C6E733A6F6D6764633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A6F6D6764693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A62706D6E323D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A64633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220747970654C616E67756167653D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D61222065787072657373696F6E4C616E67756167653D22687474703A2F2F7777772E77332E6F72672F313939392F585061746822207461726765744E616D6573706163653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E222069643D226469616772616D5F666C6F774C6561766522207873693A736368656D614C6F636174696F6E3D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2042504D4E32302E787364223E0A20203C70726F636573732069643D22666C6F774C6561766522206E616D653D22E8AFB7E58187E794B3E8AFB72220697345786563757461626C653D2274727565223E0A202020203C657874656E73696F6E456C656D656E74733E0A2020202020203C666C6F7761626C653A657865637574696F6E4C697374656E6572206576656E743D22656E642220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E557064617465466C6F775374617475734C697374656E6572223E3C2F666C6F7761626C653A657865637574696F6E4C697374656E65723E0A202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C73746172744576656E742069643D224576656E745F316339756B6B71223E3C2F73746172744576656E743E0A202020203C757365725461736B2069643D2241637469766974795F3073633279756622206E616D653D22E8AFB7E58187E5BD95E585A52220666C6F7761626C653A61737369676E65653D22247B7374617274557365724E616D657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934353431313335343236373634382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A66616C73652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383733363935353822206C6162656C3D22E68F90E4BAA42220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F303566793977682220736F757263655265663D224576656E745F316339756B6B7122207461726765745265663D2241637469766974795F30736332797566223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F316A773575323022206E616D653D22E983A8E997A8E9A286E5AFBCE5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22247B64657074506F73744C65616465727D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934353431313335343236373634382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550545F504F53545F4C45414445522671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A7461736B4C697374656E6572206576656E743D226372656174652220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E44657074506F73744C65616465724C697374656E6572223E3C2F666C6F7761626C653A7461736B4C697374656E65723E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383733383937333422206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383733393331313622206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30706D653076722220736F757263655265663D2241637469766974795F3073633279756622207461726765745265663D2241637469766974795F316A7735753230223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F306F6C7861747622206E616D653D224852E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303936343232313835353630303634302220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934353431313335343236373634382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B504F53542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383831343737323722206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383831353130363922206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3168626F62333722206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F316A773575323022207461726765745265663D2241637469766974795F306F6C78617476223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C656E644576656E742069643D224576656E745F30346279787237223E3C2F656E644576656E743E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30736F3831306122206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F306F6C7861747622207461726765745265663D224576656E745F30346279787237223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3031326864347622206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F316A773575323022207461726765745265663D2241637469766974795F30736332797566223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3164706E797A3622206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F306F6C7861747622207461726765745265663D2241637469766974795F30736332797566223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A20203C2F70726F636573733E0A20203C62706D6E64693A42504D4E4469616772616D2069643D2242504D4E4469616772616D5F666C6F774C65617665223E0A202020203C62706D6E64693A42504D4E506C616E652062706D6E456C656D656E743D22666C6F774C65617665222069643D2242504D4E506C616E655F666C6F774C65617665223E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F316339756B6B71222069643D2242504D4E53686170655F4576656E745F316339756B6B71223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223133322E302220793D223332322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30736332797566222069643D2242504D4E53686170655F41637469766974795F30736332797566223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223232302E302220793D223330302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F316A7735753230222069643D2242504D4E53686170655F41637469766974795F316A7735753230223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223338302E302220793D223330302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F306F6C78617476222069643D2242504D4E53686170655F41637469766974795F306F6C78617476223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223534302E302220793D223330302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F30346279787237222069643D2242504D4E53686170655F4576656E745F30346279787237223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223730322E302220793D223332322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30313268643476222069643D2242504D4E456467655F466C6F775F30313268643476223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223433302E302220793D223330302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223433302E302220793D223237302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223237302E302220793D223237302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223237302E302220793D223330302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223333392E302220793D223235322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30736F38313061222069643D2242504D4E456467655F466C6F775F30736F38313061223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223634302E302220793D223334302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223730322E302220793D223334302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D223636302E302220793D223332322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F3168626F623337222069643D2242504D4E456467655F466C6F775F3168626F623337223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223438302E302220793D223334302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223534302E302220793D223334302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D223439392E302220793D223332322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30706D65307672222069643D2242504D4E456467655F466C6F775F30706D65307672223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223332302E302220793D223334302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223338302E302220793D223334302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30356679397768222069643D2242504D4E456467655F466C6F775F30356679397768223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223136382E302220793D223334302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223232302E302220793D223334302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F3164706E797A36222069643D2242504D4E456467655F466C6F775F3164706E797A36223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223539302E302220793D223338302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223539302E302220793D223432302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223237302E302220793D223432302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223237302E302220793D223338302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223431392E302220793D223430322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A202020203C2F62706D6E64693A42504D4E506C616E653E0A20203C2F62706D6E64693A42504D4E4469616772616D3E0A3C2F646566696E6974696F6E733E, 0); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('1ba32d21-1c51-11ec-94ee-5ef70686b817', 1, 'flowContract.bpmn', '1ba32d20-1c51-11ec-94ee-5ef70686b817', 0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C646566696E6974696F6E7320786D6C6E733D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A7873693D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612D696E7374616E63652220786D6C6E733A7873643D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612220786D6C6E733A666C6F7761626C653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E2220786D6C6E733A62706D6E64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F44492220786D6C6E733A6F6D6764633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A6F6D6764693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A62706D6E323D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A64633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220747970654C616E67756167653D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D61222065787072657373696F6E4C616E67756167653D22687474703A2F2F7777772E77332E6F72672F313939392F585061746822207461726765744E616D6573706163653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E222069643D226469616772616D5F666C6F77436F6E747261637422207873693A736368656D614C6F636174696F6E3D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2042504D4E32302E787364223E0A20203C70726F636573732069643D22666C6F77436F6E747261637422206E616D653D22E59088E5908CE5AEA1E689B92220697345786563757461626C653D2274727565223E0A202020203C657874656E73696F6E456C656D656E74733E0A2020202020203C666C6F7761626C653A657865637574696F6E4C697374656E6572206576656E743D22656E642220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E557064617465466C6F775374617475734C697374656E6572223E3C2F666C6F7761626C653A657865637574696F6E4C697374656E65723E0A202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C73746172744576656E742069643D224576656E745F3170736D697364223E3C2F73746172744576656E743E0A202020203C757365725461736B2069643D2241637469766974795F306E796C61317222206E616D653D22E59088E5908CE5BD95E585A52220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935343932303334383934363433322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A66616C73652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839363537313222206C6162656C3D22E68F90E4BAA42220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F303063657865612220736F757263655265663D224576656E745F3170736D69736422207461726765745265663D2241637469766974795F306E796C613172223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3175637268353222206E616D653D22E4B89AE58AA1E983A8E9A286E5AFBCE5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22247B64657074506F73744C65616465727D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935343932303334383934363433322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550545F504F53545F4C45414445522671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A7461736B4C697374656E6572206576656E743D226372656174652220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E44657074506F73744C65616465724C697374656E6572223E3C2F666C6F7761626C653A7461736B4C697374656E65723E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839373234353522206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30346B63616A632220736F757263655265663D2241637469766974795F306E796C61317222207461726765745265663D2241637469766974795F31756372683532223E3C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30323666766E712220736F757263655265663D2241637469766974795F3175637268353222207461726765745265663D22476174657761795F30396364787466223E3C2F73657175656E6365466C6F773E0A202020203C706172616C6C656C476174657761792069643D22476174657761795F30396364787466223E3C2F706172616C6C656C476174657761793E0A202020203C757365725461736B2069643D2241637469766974795F3133386D346E6E22206E616D653D22E5B7A5E7A88BE983A8E5AEA1E689B92220666C6F7761626C653A63616E64696461746555736572733D2261646D696E2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353139343939313937323335322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839373831303122206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F307A7A307539672220736F757263655265663D22476174657761795F3039636478746622207461726765745265663D2241637469766974795F3133386D346E6E223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F30746D336D706822206E616D653D22E980A0E4BBB7E983A8E5AEA1E689B92220666C6F7761626C653A61737369676E65653D2261646D696E2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353139343939313937323335322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839383233373722206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F317978716265302220736F757263655265663D22476174657761795F3039636478746622207461726765745265663D2241637469766974795F30746D336D7068223E3C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31323465387A332220736F757263655265663D2241637469766974795F3133386D346E6E22207461726765745265663D22476174657761795F306F79366F666C223E3C2F73657175656E6365466C6F773E0A202020203C706172616C6C656C476174657761792069643D22476174657761795F306F79366F666C223E3C2F706172616C6C656C476174657761793E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3175766A3364732220736F757263655265663D2241637469766974795F30746D336D706822207461726765745265663D22476174657761795F306F79366F666C223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3179757579696522206E616D653D22E8B4A2E58AA1E983A8E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303936343531393339353333323039362C313434303936343531393339313133373739322220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353132373739303833333636342671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B504F53542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383930333738313422206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383930343234383922206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F316B79686E6C7A2220736F757263655265663D22476174657761795F306F79366F666C22207461726765745265663D2241637469766974795F31797575796965223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3039386E63767722206E616D653D22E6B395E58AA1E983A8E4BC9AE7ADBE2220666C6F7761626C653A61737369676E65653D22247B61737369676E65657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353030313039333439323733362671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383931393036363222206C6162656C3D22E5908CE6848F2220747970653D226D756C74695F6167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383931393734303622206C6162656C3D22E68B92E7BB9D2220747970653D226D756C74695F726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C6D756C7469496E7374616E63654C6F6F7043686172616374657269737469637320697353657175656E7469616C3D2266616C73652220666C6F7761626C653A636F6C6C656374696F6E3D2261737369676E65654C6973742220666C6F7761626C653A656C656D656E745661726961626C653D2261737369676E6565223E0A20202020202020203C636F6D706C6574696F6E436F6E646974696F6E3E247B6E724F66496E7374616E636573203D3D206E724F66436F6D706C65746564496E7374616E6365737D3C2F636F6D706C6574696F6E436F6E646974696F6E3E0A2020202020203C2F6D756C7469496E7374616E63654C6F6F704368617261637465726973746963733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3064693671613622206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F3179757579696522207461726765745265663D2241637469766974795F31656577743031223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C6578636C7573697665476174657761792069643D22476174657761795F316D356672757A223E3C2F6578636C7573697665476174657761793E0A202020203C73657175656E6365466C6F772069643D22466C6F775F306A7976317A622220736F757263655265663D2241637469766974795F3039386E63767722207461726765745265663D22476174657761795F316D356672757A223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F316833706E787922206E616D653D22E680BBE7BB8FE79086E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303931313431303538313231333431362220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935343932303334383934363433322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383934343935303822206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383934353238353022206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31663879786F7622206E616D653D22E5908CE6848FE4BABAE695B0E5A4A7E4BA8E3430252220736F757263655265663D22476174657761795F316D356672757A22207461726765745265663D2241637469766974795F316833706E7879223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6D756C74694167726565436F756E74202F206E724F66496E7374616E636573203E20302E347D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C656E644576656E742069643D224576656E745F3132616A6F3364223E3C2F656E644576656E743E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31613371636C6D22206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F316833706E787922207461726765745265663D224576656E745F3132616A6F3364223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F306C6C6F79353622206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F3179757579696522207461726765745265663D2241637469766974795F306E796C613172223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3165657774303122206E616D653D22E6B395E58AA1E983A8E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303936343338373937393339393136382220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353030313039333439323733362671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B504F53542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383933333730323422206C6162656C3D22E4BC9AE7ADBE2220747970653D226D756C74695F7369676E222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383933343139303122206C6162656C3D22E58AA0E7ADBE2220747970653D226D756C74695F636F6E7369676E222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F307A6D736E33782220736F757263655265663D2241637469766974795F3165657774303122207461726765745265663D2241637469766974795F3039386E637677223E3C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3176737269766222206E616D653D22E5908CE6848FE4BABAE695B0E5B08FE4BA8E3430252220736F757263655265663D22476174657761795F316D356672757A22207461726765745265663D2241637469766974795F306E796C613172223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6D756C74694167726565436F756E74202F206E724F66496E7374616E636573203C3D20302E347D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F316D323430366622206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F316833706E787922207461726765745265663D2241637469766974795F306E796C613172223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A20203C2F70726F636573733E0A20203C62706D6E64693A42504D4E4469616772616D2069643D2242504D4E4469616772616D5F666C6F77436F6E7472616374223E0A202020203C62706D6E64693A42504D4E506C616E652062706D6E456C656D656E743D22666C6F77436F6E7472616374222069643D2242504D4E506C616E655F666C6F77436F6E7472616374223E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F3170736D697364222069643D2242504D4E53686170655F4576656E745F3170736D697364223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D2239322E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F306E796C613172222069643D2242504D4E53686170655F41637469766974795F306E796C613172223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223138302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31756372683532222069643D2242504D4E53686170655F41637469766974795F31756372683532223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223334302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F30396364787466222069643D2242504D4E53686170655F476174657761795F30396364787466223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D223530352E302220793D223330352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F3133386D346E6E222069643D2242504D4E53686170655F41637469766974795F3133386D346E6E223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223636302E302220793D223136302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30746D336D7068222069643D2242504D4E53686170655F41637469766974795F30746D336D7068223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223636302E302220793D223339302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F306F79366F666C222069643D2242504D4E53686170655F476174657761795F306F79366F666C223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D223835352E302220793D223330352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31797575796965222069643D2242504D4E53686170655F41637469766974795F31797575796965223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313030302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F3039386E637677222069643D2242504D4E53686170655F41637469766974795F3039386E637677223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313336302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F316D356672757A222069643D2242504D4E53686170655F476174657761795F316D356672757A223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D22313531352E302220793D223330352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F316833706E7879222069643D2242504D4E53686170655F41637469766974795F316833706E7879223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313637302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F3132616A6F3364222069643D2242504D4E53686170655F4576656E745F3132616A6F3364223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D22313836322E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31656577743031222069643D2242504D4E53686170655F41637469766974795F31656577743031223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313139302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F316D3234303666222069643D2242504D4E456467655F466C6F775F316D3234303666223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313732302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313732302E302220793D223534302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223231302E302220793D223534302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223231302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223935342E302220793D223532322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31767372697662222069643D2242504D4E456467655F466C6F775F31767372697662223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313534302E302220793D223330352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313534302E302220793D223133302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223133302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223239302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2238392E302220783D223834312E302220793D223131322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F307A6D736E3378222069643D2242504D4E456467655F466C6F775F307A6D736E3378223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313239302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313336302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F306C6C6F793536222069643D2242504D4E456467655F466C6F775F306C6C6F793536223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313035302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313035302E302220793D223530302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223530302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223632392E302220793D223438322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31613371636C6D222069643D2242504D4E456467655F466C6F775F31613371636C6D223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313737302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313836322E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D22313830352E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31663879786F76222069643D2242504D4E456467655F466C6F775F31663879786F76223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313536352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313637302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2238392E302220783D22313537332E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F306A7976317A62222069643D2242504D4E456467655F466C6F775F306A7976317A62223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313436302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313531352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30646936716136222069643D2242504D4E456467655F466C6F775F30646936716136223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313130302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313139302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D22313133342E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F316B79686E6C7A222069643D2242504D4E456467655F466C6F775F316B79686E6C7A223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223930352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313030302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F3175766A336473222069643D2242504D4E456467655F466C6F775F3175766A336473223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223736302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223335352E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31323465387A33222069643D2242504D4E456467655F466C6F775F31323465387A33223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223736302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223330352E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31797871626530222069643D2242504D4E456467655F466C6F775F31797871626530223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223335352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223636302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F307A7A30753967222069643D2242504D4E456467655F466C6F775F307A7A30753967223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223330352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223636302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30323666766E71222069643D2242504D4E456467655F466C6F775F30323666766E71223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223434302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223530352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30346B63616A63222069643D2242504D4E456467655F466C6F775F30346B63616A63223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223238302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223334302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30306365786561222069643D2242504D4E456467655F466C6F775F30306365786561223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223132382E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223138302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A202020203C2F62706D6E64693A42504D4E506C616E653E0A20203C2F62706D6E64693A42504D4E4469616772616D3E0A3C2F646566696E6974696F6E733E, 0); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('1bbbe542-1c51-11ec-94ee-5ef70686b817', 1, 'flowContract.flowContract.png', '1ba32d20-1c51-11ec-94ee-5ef70686b817', 0x89504E470D0A1A0A0000000D4948445200000774000002260806000000AB78BB71000069854944415478DAECDD07981D55D938F05014AC34FB5F6CE0A7D83F15151B114114145009D98426862F8496DD0D298A88A11B5BB27743899F48533F0145098A81ECBD1702482F22016921B484D02142820AF39F77D859EE6E76934DB26576F7F77B9EF3E496B96577DF9C79CF79E7CC0C1B06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000834CE389D52D1B7FF6D757AC6ABBC9D32E7FCD4127565FDDDDE7279D587D93DF2E000000000000402A8AA9F5A5CA5F56D6F2826B7A7B7C6373F93BD11A9ACBB736942A67B4DD2F951B3A7BFFC6E66A7D7DA97A40C7C70F3CE9B24D1A9A2BA7C7EBEA9BAB7BA5EFF5C7A953A7AE9B3E76F7CABE6FFD8CF2E7D36D4FE9ECB9F4BDFEB7CB9FA3A9F2B3EEFE4EE27B747CECD0D2851BACF858F5AD63675DF7325104000000000000F48AD6C2EA8D8DCD977EB0B316CFC536B16D43A9B2736373A5B1A154BEB9A1B9BA5BD64A953BD3FB07C6739DBD7F7DA932A9B1A9BA6FC7C763756F1466EB9BAA273496AACDF5A5F2110DD3E7BD397DEC9186A6F2D4688DA5F22756785DA9B26D146E3BFBAC6CD570FEBD9BCA13E3FDF3FB8796CA5B74DC7ECAACB91BA5DBDC54DF5C1D993D9024EBA4F74F4ADBC28652F5C2F83EAD3FC3F8F899D3CFBE62C439E7AC973DD65CD9B1A1A97A717E1F000000000000A0C76505DD52E5F286A6CA842850B66F5951F4F2D8A6B1A9B247AC9E6D2C5516A48FDD17B75BDB03F9EDC6A66A5DC7F7AF6FAA9E5C5FAA4EE9F8F884A6CA4EE9FBDC92B6246D8BE273D2CF189BFE5B6E2D10DF7E68A9E57DB16DAC988DEDE3766D4137FD8EDF1B3BEB825776F67365DFB7A97274573FF7D4D3AA1B3694AAF3E2F30F69BEF49DADEF77707A7F4EB652B8A9F2DD585D9C1579D39FB1F16773364D9F9B3BBEA9FA81F14D97BE3BBD7DFDC1335B36134100000000000040AFC90BBA71EDDAFA1995F7B46F2D6FCC0BBAB16DC3F44BB74AEFFFAAA1543EADB6353695CFCA8BAF1DC5AAD6F435F7765CC97A48F3C56FA92F956F489F3B3BDDE6BAACF0DB54F9657ABBE5B099E5B7C7E7BCF41E2D9F8BC75BDFEFA5826E9CF2B9A932F6C5EF56DD380AB3794BDFFB90F4F999B58FC536B1EDD4A9D5F51B4AD5D9E9F3A7A6EDE1EC435E2CDCDE1D9F1577EB9B2BBB3496AAE7642B899BCBB7B6AEE65D38F1E48BDE90BEF69AF477F321D103000000000000F4AABCA03B79DAE5AF7971A56C143AB362E7A22880B62BE83697B78B226CDA7E52DB62B56A3CD7F1BDA3E819AB70EB9BABE7D53757BE59FB5CEB299B87D7972AC74D28553F35E1C44B374FB7AD66AB669BAAFB37962A47E5DBA6B79BD2F718D37ABBADA09BBEFFD6F1FED9ED99D5AF66D7E47DA95D9A3EF7B7768FC569A15F2CDCA6B7ABD3E33B3436952F88D71FD65C7D6F149EDBBE5F536542FA593FCA3EB3B9FC9DF8191A4BE5AFC5B57ED3D7EE9EBEC767C63755BEE81ABA00000000000040AFC90BBA87962E7C6D1453F3C7A3B89A3F575BD06D68AE5C15C5D6DA966E7375C7826E9CB6B8BEB9F2E76C75ED89D52DA3C01A2B63F3E71B4BE52FA5AFBB287DFDE3E9BFBF8FCF8EE26876AAE452E5A986E9D58FC476F54D73DF969DD6B975756DC76BE8C6678F6F2A7FBAE3CFD5D529971B9BCBE3D2D73C9D1574E354D3A5CAF5F533CA9F6F2DD6FEA9F6E78FF768F7DA52F598F4E73C36AEB91B2B86E37B64A76506000000000000E80DED0BBA95875E3A9572E5A18E05DDFA52657CACAACD56ACA6B763E56C763DD9E6F257EA9BAB7BD5BE6F3CD758AA36E7F71B9A2BC7A7AFF9CB4127565FFDD236D5735EBC5E6EB9A1A1A93CB575BBCFA49FF9EFC6E92DEFCAEE972A3F6D6CAE1C54F3BEED0BBA4DE5BDD336A3E3CFD5554137BEEF84A6962F448BEBF4A6AF3D344EA3DC5A38BE2ABB7E6EFAF3E4B7DB3E2756E596AAB363856FFADEBF8B4275FAF34C8ADF8528020000000000007A455EB48DDBD929966B5A142FE314CBD93633CB1F4DB7BBECD052798B28764EFCF145AFCAAE7B3BB3658728A8C6E98DE314C88D3F9BB36943A9FC87B87E6DED8ADCECFD63756B5C3777FABC3767F7A3185BAA2C4FDB7FEA4BD50362556E5CAF367DFDA8EC74C9E97687962EDCA0B6B01A85E3C652E5E7F9FD58D53B76D605AFECF8734511B8F6B4CD1DBD781DDDCAD238D574DB6B4AD5E6F4B3EF8855BBB5D7046E3D75F4B551F4CEEE972A47A6F77F9BFE7B5B5C0B581401000000000000BD62CAACB91BD59E6A3917D79BCDAE7F5B2ADF90AD4A2D55B78FD5B1AD85D039F5A5CA9551088E7F273455769A50AA7CB86166CB3651EC8CE26C579FD7D854199B3E3F2556C6C6F568E3D4CB07CF6CD92C5E97ADD8CD4FB53CB36587FAA6EA096DAF9BDEF2AE28A0468BD32377F9FECDD58F67A7802E55FE1EA7525EDDDF47ED0AE2B6DFC5F44BB7EA58B88D9FB7B6180C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014445D5D5DA2699AA6699AA6699AA6699AA6699AD6D3CDEC2B00400F1574FD1600000000809E64DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205C0109424C9CB172C5870CE95575EF9AF72B99CCC9D3B57EBE396FEDE5F98376FDEA24AA5B2AB88040000BA62DE1100406205C010B460C18273E7CD9B972C59B22459B66C59F2DC73CF697DDCE2F71EBFFF4B2EB9E4A9B973E7EE2C2A010080CE987704009058013004C5CADC28262AACF67F5BBC78F1A373E7CEBD46540200009D31EF080020B10260088AD32C5B995B9C95BA73E7CE5D2E2A010080CE987704009058013004C5355C15538BD3E2EF212A010080CE98770400905801300475B7A0FBCF2717270BAE3D2D99DF7274D6E2763CA608ABA00B0000F40DF38E0000122B0086A0EE1474973EF16072CB45DF4FFEF6E749ED5A3C16CF29C42AE8020000BDCFBC230080C40A8021A83B05DDFBE7CF5EA1989BB707E65FA010ABA00B0000F401F38E0000122B0086A0EE14746FAB4EEBB2A01BCF29C42AE8020000BDCFBC230080C40A8021A83B05DD5BE64EEDB2A01BCF29C42AE8020000BDCFBC230080C40A8021484157411700001818CC3B020048AC001882BA53D09DDF72749705DD784E215641170000E87DE61D01002456000C41DD29E8DE79C5CC2E0BBAF19C42AC822E0000D0FBCC3B020048AC001882BA53D07DECC19B935B2EFEC18AA75B4E1F8BE714621574010080DE67DE1100406205C010D49D826EB47BAE3B7385826E3CA608ABA00B0000F40DF38E0000122B0086A06E1574972F4FEEFCEBC92B9E6E397D2C9E538855D00500007A9F7947000089150043D0AA0ABA4B9F7830B9E38AE62EAFA11BCFC5368AB10ABA000040EF32EF080020B1026008EAB2A0BB7C79B2F8CE4AF2F739877759CCCD5B6C13DB5AADABA00B0000F41EF38E0000122B0086A0CE0ABAAB5A956BB5AE822E0000D0F7CC3B020048AC0018823A2BE8766755EECA56EB2ACC2AE80200003DCFBC230080C40A8021A8B382EE9A1673F3A630ABA00B0000F43CF38E0000122B0086A02EAFA1AB29E80200008562DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000CAEFD51356DC357B59D82AE822E00003060C679C60B0000122B0006D3FEA8B5ADB4B0ABA0ABA00B00000C9C719EDF020080C40A8041B43FEAD03A2DEC2AE82AE802000003679CE7B7000020B1026010ED8FBA68ED0ABB0ABA0ABA0000C0C019E7F92D000048AC001844FBA355B4ACB0ABA0ABA00B00000C9C719EDF020080C40A1862FD95A615B1A0BB6CD9B264E9D2A5ABDC6ED1A245C96DB7DDB65AEFBD64C992E4CA2BAFECF2F9471E7924993F7F7E767BE1C285C9934F3E997D9F7FFCE31FDDFA4E6BDBC4E4E06FF63E000098770400905801E8AF28CC2997CF3AEBACE4A73FFD6997EDF4D34FCFB6BBFCF2CB937DF7DD37F9D8C73E96BCE215AF480E3AE8A0E4FDEF7F7FF2BEF7BDAF5D5BBE7C79B278F1E2E4B2CB2E4B76DB6DB7E4831FFC60763BDAF7BFFFFD76DBC6674771F684134E686B3BEFBC73B2EEBAEB26C71E7B6CBBC7EFBCF3CEEC7BFCFAD7BF4E5EFFFAD767B737DA68A3E4ECB3CF4E1E7CF0C1F8BF925C77DD7556E8A2DF0500403E090020B102D05FD1337FDF95157273BD5DD0DD6FBFFD92ADB7DE3A6B1FF8C007B2C268FC9B3F16DF2DB6AB56ABC92EBBEC92ACB3CE3AC911471C915C73CD35D9B651F43DEFBCF392638E3926BB1FAB65CF3CF3CCEC76C7B6CF3EFB249FFDEC67931FFFF8C7D9FDD9B36727E79E7B6EB2FEFAEB275FFEF297BB6CB1ED85175E98DC7DF7DDC9E4C993938D37DE382997CB0ABAE8770100904F020048AC00F457F4DEDF776585DC5C5F9E72394E5B9C7E6472F3CD3777FADCF9E79F9FAD9E3DFEF8E3936BAFBD36DBF6C0030F4C8E3BEEB8E480030E682BE8C6F651783DFAE8A3B315BBDB6DB75D72EAA9A726DFFEF6B793BDF6DA2BF9D18F7E94ADB27DE69967928B2EBA285BE97BCF3DF7642D4EB71CEF138FE78F7DF8C31F4EAEB8E28A64FAF4E9C9061B6C901595DFFBDEF76605DD33CE3823DB265E3375EAD4649B6DB6E9F4FB2BE8A2DF0500403E090020B102D05FB13A7FDF951672734529E8C64ADC57BDEA55D9F3AF7DED6B939FFCE427C937BEF18D766DF7DD77CF0AB877DC714756E07DC73BDE91ADC08DD79C72CA29593137DA873EF4A1AC109CBF779C467958272B7AF3169F5DBB6DED2997E3F9CF7DEE73D9BFF1FDC68D1B977DBE822EFA5D0000E4930000122B00FD15BDAE2805DD6853A64CC99E9F38716252A954B2026EC7162B69C78F1FDF696176871D7648468D1A956CB5D55659C1B7B648BBE9A69B26D75F7F7D766AE5D8360AC1717F8B2DB658A1A01B05E538CD731474E35ABB717DDF784D7CB6532EA3DF0500403E090020B102D05FD1678A52D08D55AF1B6EB861F6FCCB5EF6B2AC307BF8E18767D7C58DC71A1B1BB3FB37DD7453B64A77D6AC59C949279DD4D62EB8E082B6532E5F7DF5D5C9CB5FFEF2E4BEFBEE5BAD15BA71BDDC38FD723CF695AF7CC53574D1EF0200209F0400905801E8AFE85F4529E846E176E79D774ED65B6FBDE4A8A38ECA56C8C6E98D77D96597EC3563C68C490E3AE8A0B6ED63BBCD37DF3CBBD6EDC61B6F9C1560F3826E3C1FD7CD9D366D5A5B4177934D3649AEBAEAAA64F6ECD9D9FBFDE637BFC9EED7AED08D6BF86EBFFDF6C9EB5EF7BAB6532E772CE8FEF39FFF54D045BF0B00807C1200406205A0BFA26F14A5A07BDC71C76505D328D456ABD5E4E1871FCE0ABABBEDB65BF69AFDF6DB6F8582EE9C3973B2DB871C72485B4177DB6DB74D264F9E9C6CB6D9665931766DAFA1DBB1A0BBC71E7BB4DB5E4117FD2E0000F2490000891580FE8A5ED39B05DDD34F3F3D2BB0E66DEBADB7CE0AA39FF8C427DA3DFECB5FFE3279F6D967DB0AB551D08D42EA8C193392830F3E387BCD09279C90DDCFBF6F6CB7DD76DB257BEEB967F29EF7BCA7ADA01BD7D9FDC217BE9015831F7BECB16CDB2BAFBC323B6573ACAEBDF3CE3BB3F7BBF6DA6BB3FBF1BE2D2D2DD9760F3DF450B63A380ABAF17C7CC6473EF29164D75D77CD5E3373E6CCE4DDEF7E77D2D4D4A4A08B7E170000F9240080C40A407F45EFEBCD82EE25975C921C79E491AB6C7941B5B6A01BA758FEE4273FB9423BFEF8E3DBB6FBEA57BF9A156EE3F4CA1D4FB9DC555BB87061569CBDF1C61B5778EE17BFF845F6DCD7BFFEF5EC9ABC6F7DEB5BB3F72F97CB59113A9E7BCB5BDE92CC9F3F5F4117FD2E0000F2490000891580FE8ADED797A75CEE4EBBF7DE7BBB759DDABBEEBA2B59BA7469DBCADA458B16258B172FCEFE5DD9EB9E79E699E49A6BAE697B6D6D8BCF8DF788DBCB972F5FE1F9A79E7AAAD3C71574D1EF0200209F0400905801E8AFE815452BE80EF5A6A0ABDF050000F9240080C40A407F451B055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF28A872B9FCC2B265CB14530BD0D2BFC3A2B973E72E1795FA5D0000904F020048AC00F45764E6CD9BB768C992250AAA0568F7DE7BEF6FE7CE9D7B8DA8D4EF0200807C1200406205A0BF2253A95476BDE4924B9E5ABC78F1A356EAF6DBCADCC50B172EFCCDDCB973EF4BDBCEA252BF0B0000F2490000891580FE8A3651448C95A1697B2EAEE1AAF5797BAEF5F7AF98ABDF050000F9240080C40A407F05A0DF0500403E090020B102D05F01A0DF0500403E090020B102D05F01E8770100904F020020B102F45700E8770100904F020048AC00F45700FA5D0000904F020048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B00FD15807E170000F9240000122B407F05807E170000F9240080C40A407F05A0DF0500403E090080C40AD05F01A0DF0500403E090020B102D05F01E8770100403E090020B102D05F01E8770100904F020048AC00F45700E8770100904F020048AC00F45700FA5D0000E493000048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B407F05807E170000F9240080C40A407F05A0DFF55B0000403E090020B102D05F01E8770100904F020020B102F45700E8770100904F020048AC00F45700FA5D0000E493000048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B00FD15807E170000F9240000122B407F05807E170000F9240080C40A407F05A0DF0500403E090080C40AD05F01A0DF0500403E090020B102D05F01E8770100403E090020B102F457FA2B00FD2E0000F2490000891580FE0A00FD2E0000F2490000891580FE0A40BF0B00807C1200008915A0BF0240BF0B00807C1200406205A0BF02D0EF0200209F944F020048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B00FD15807E170000F9240000122B407F05807E170000F9240080C40A407F05A0DF0500403E0900C0AA93A86A2452AB6855BF29C0401000FD2E0000F2490080BE4FA28677A3A03BDC6F0A30100440BF0B00807C1200A07F12A9AAD5B980812000FA5D0000E4930000C54CA4865B9D0B180802A0DF0500403E090050DC64AA6A752E602008807E170000F92400403193A9E156E702068200E8770100904F02001437A1AA5A9D0B180802A0DF0500403E090050CC846AB8D5B980812000FA5D0000E4930000C54DAAAA122BC0401000FD2E0000F2490080622655C3255680812000FA5D0000E49300C0A09324C9CB172C5870CE95575EF9AF72B99CCC9D3B7740B648AC06EA774F7FEF2FCC9B376F51A552D955FCCDD5C49F812000FA5DE493F249C4BDB817A79A38954FA25FD3F46B00B97427746EDA09264B962C49962D5B963CF7DC735A1FB7F8BDC7EFFF924B2E792ADD31ED2CFE34F1672008807E17F9A47C12712FEEC5A9264EE593E8D734FD1A40268E288A4ED00EA1FFDBE2C58B1F4D7744D7883F4DFC190802A0DF453E299F44DC8B7B71AA8953F924FA354DBF069089D34338A2A8384718A53BA2E5E24F137F068200E877914FCA2711F7E25E9C6AE2543E897E4DD3AF0164E2DCF37602C569F1F7107F9AF833100440BF8B7C523E89B817F7E25413A7F249F46B9A7E0D60B57644FF7C7271B2E0DAD392F92D47672D6EC763761E7644E24FFC61200850A03EB61AFDEC2A5AD56F4A3E299F944F8A7B4DDC8B53718A713CFA35FD1AC0A0DA112D7DE2C1E4968BBE9FFCEDCF93DAB5782C9EB303B123127FE20F03418082F4B1C3BB51D01DEE37259F944FCA27C5BD7815F7E2549C621C8F7E4DBF0630A87644F7CF9FBDC24E286F0FCCBFC00EC48E48FC893F0C04018AD4CF56ADCE954FCA27E593E25EDC8B7B71AA8953E378F46BFA358021B523BAAD3AADCB1D513C6707624724FEC41F06820005EA67875B9D2B9F944FCA27C5BDB817F7E25413A7C6F1E8D7F46B00436A4774CBDCA95DEE88E2393B103B22F127FE30100428585F5BB53A573E299F944F8A7B712FEEC5A9264E8DE3D1AFE9D700EC88EC88EC88C49FF8C34010A0987DED70AB73E593F249F9A4B817F7E25E9C6AE2D4381EFD9A7E0D60C8EC88E6B71CDDE58E289EB303B123127FE20F03418002F6B755AB73E593F249F9A4B817F7E25E9C6AE2D4381EFD9A7E0D6048EC88EEBC6266973BA278CE0EC48E48FC893F0C04010AD8DF0EB73A573E299F944F8A7B712FEEC5A9264E8DE3D1AFE9D70086C48EE8B1076F4E6EB9F8072B9E26227D2C9EB303B123127FE20F03418082F6B955FDAE7C523E299F14F7E25EDC8B53712A4E8DE3D1AFE9D70006FD8E28DA3DD79DB9C28E281EB3F3B023127FE20F03418002F7B9C3478C18A1DF954FCA27E593E25EDC8B7B712A4E318E47BFA65F0318E43BA2E5CB933BFF7AF28AA789481F8BE7EC40EC88C49FF8A3DBB66D1D086EEB5701D037FDEE861B6EA8DF954FCA27E593E25EDC8B7B712A4E318E47BFA65F0318BC3BA2A54F3C98DC71457397E7FE8FE7621B3B113B22F127FE58F520306D4BD236B1F55F834100FD2EF249F924E25EDC8B53712A4EE593E8D734FD1AC01AEE88962F4F16DF5949FE3EE7F02E7742798B6D625B4719D911893FF1C72A0781DB76711F00FD2EF249F924E25EDC8B53712A4EE593E8D734FD1A40F77644AB3A9AC851467644E24FFCB15683C0553D0E807E17F9A47C12712FEEC5A93815A7F249F46B9A7E0DA0EB1D51778E265AD9514676287644E24FFCD1EDC19EC120807E17F9A47C12712FEEC5A93815A7F249F46B9A7E0D60F576446BBA13CA9B1D8A1D91F8137FACD620CF601040BF8B7C523E89B817F7E2549C8A53F924FA354DBF06D0FD1D91664724FEC41F7D3608341804D0EF229F944F22EEC5BD38D5C4A97C12FD9AA65F1B34BEF5AD6F6D5C5757B7FBC891234BE9BFE5B4DD93B667D396B4FE1BF7CBADCFEF1EDBFBAD0D414F3DF5D4A6B367CF3E7AE6CC997F3BEAA8A31E9D3265CAB2030F3CF085089471E3C6FD7BE2C4894F7FEF7BDFBBEFE8A38FBE60D2A4495F4E5FB28E1D911D801D91F8D32442FD3808341804D0EF229F944F1640E389D52D1B7FF6D757887BCD384A9C8A53F9E460C927BBBB6F9B3CEDF2D71C7462F5D5DD7D7ED289D537ADECFD0E2D5DF8DA29B3E66EA45FD3F46B033FF75C1DA3468DDAA1AEAEEEBCB43DD75ABCED6E8BEDCF8BD7DB250D01575F7DF5B81933663C78C001072453A64C49CE3DF7DCE4FAEBAF4FEEBEFBEEE4B1C71E4B42FC1BF7E3F1787EF2E4C92F8C1933E6B94993265D347AF4E87749B0353B22F127FEE8A741A0E202807E17F9A47CB287C484737DA9F29795B57C523ABD3DBEB1B9FC9D680DCDE55B1B4A9533DAEE97CA0DE25E338E12A7E2543E59847CB2B7F76D8DCDD5FAFA52F5808E8F1F78D2659B3434574E8FD7D53757F74ADFEB8F53A74E5D377DECEE957DDFF80EF5A5F2219D3D97BED7FF76F97334557ED6DDDF497C8F8E8F1D5ABA7083151FABBE75ECACEB5EA65FD3AFC93D7BCFA851A3B6A9ABABBB6A358BB85DB5ABE2FDEC9E06A19B6FBE79A7934E3A69D1D8B16393DFFFFEF7C9238F3C92AC8ED83E5E3766CC987F3536369E9306CAEB24D89A1D91F8137FF4D2202EA9698A0B00FA5DE493F2C95ED03AF97C6363F3A51FECACC573B1CD8B93CA959D1B9B2B8D0DA5F2CD0DCDD5DDB256AADC99DE3F309E13F79A71943815A7433E9FECCBF7E9B77D5B7DA932A9B1A9BA6FC7C763F560FA9A53EA9BAA273496AACDF5A5F2110DD3E7BD397DEC9186A6F2D4688DA5F22756785DA97278637379BFCE3E2B5B95987FEFA6F2C478FFFCFEA1A5F2161DB78F95BEE93637D5375747BE98E127EBA4F74F4ADBC28652F5C2F83EAD3FC3F8F899D3CFBE62C439E7AC973DD65CD9B1A1A97A717E5FBFA65F937BF6AC6F7DEB5B1B8E1C39F2C4BABABA173A16661B1A1A925FFFFAD72B5D7819CFC7769D14755F88F78DF7B7AB1A04D2BFFB7A175E78E1EC28E49E71C619C9D2A54B93B511AF8FF74903E4D9BDF6DA6B3709B626C1167FE28F5E18BC75A7B0A0B800A0DF453E299F5CDB49B552E5F286A6CA8498C46DDFB289E3CB639BC6A6CA1EB1C2A8B15459903E765FDC6E6D0FE4B71B9BAA75E25E338E12A7E27448E793FDF57E7DBA6FAB6FAA9E5C5FAA4EE9F8F884A6CA4EE9FBDC92B6246D8BE273D2CF189BFE5B6E2D40DD7E68A9E57DF54D73DFD6582A7F296FE9E3673796AAC7D43E76D8CCF2DB3BBE7FF67D9B2A4777F5734F3DADBA6143A93A2F3EFF90E64BDF198FA53FF3C1E9FD39D94AE1A6CA7763757156E44D7FC6C69FCDD9347D6EEEF8A6EA07C6375DFAEEF4F6F507CF6CD94CBFA65F937BF6BCBABABACD478D1AF5B7DA42ECE8D1A39359B366250F3CF0C06AD5E762FB785DBCBE4361F7A6F81CBBAC012CFDFB6E7CD65967DD71F0C107270B162C487A52BCDFD8B163978D1933E62809B626C1167FE28F1E1EB475B7B0A0B800A0DF453E299F5CCB49B5B8BE5FFD8CCA7BDAB79637E6936AD9A4F0F44BB74AEFFFAAA1543EADB6353695CF8A096A71AF19478953713AE4F3C922BC6FAFEFDB62556BFA9A7B3BAE643DA4F9E2B7D497CA37BC58A0AD5C97157E9B2ABF4C6FB74481363EE7C5D7B77CAEA1A932ADAD952A8F6545AB9AC7D2D77EB6617A75E328CCE62D4ECB9C6E3BB3F6B1D826DE73EAD4EAFA0DA5EAECF4F953D3F6706B61609D170B622D9F8BBBF5CD955D1A4BD573B295C4CDE55B5B57F32E9C78F2456F485F7B4DFABBF9907E4DBF26F7EC79A3468D7A6FDA1EAC2DBE4E9B362DB9FFFEFBD7AA3E17AF8FF7E950D4BD3F3ECFAE6B008A626EA9547AE288238E489E78E289A437C4FB4E9932E5D97DF6D9E74C09B626C1167FE28F1E1CACAD4E6141710140BF8B7C523EB916936A93A75DFE9A175713C564703621BC282689DB4DAA3597B78B89EAB4FDA4B6C58A9E784EDC6BC651E2549C0EF97CB210EFDF9BFBB6287AC62ADCFAE6EA79F5CD956FD63ED77A4AD8E1F5A5CA71134AD54F4D38F1D2CDD36DABD9AAD9A6EAFE8DA5CA0A8BA226942EFDEF749BBBD26DFE1AA7576EF75933AB5FCDAEC9FB52BB34DDF66FED1E8BD3CEBE58B84D6F57A7C777686C2A5F10AF3FACB9FADE283CB77DBFA6CA84F43BFC286EC73548E367682C95BF16D7FA4D5FBB7BFA1E9F19DF54F9A26BE8EAD7E49E3DA77565EE83B5AB7267CF9EDDA335BA78BF0EAB75EFB752778089D32C9F75D65977463137FED3F6A678FF8913273EB9E79E7B7E4F82AD49B0C59FF8A3870669AB5B58505C00D0EF229F944FAEE1A4DAA1A50B5F1B13CE6D93BEA54A357FAE7652ADA1B972554C48D7B6749BAB157435E328712A4E07753EB94EDAF66DFD776D74F63E3D9E4FF6D6BE2D4E5B5CDF5CF973AC788DE26B145863656CFE7CEBE9932F4A5FFF78FAEFEFE3B3A3389A9D3AB65479AA617AF5231DBF6BAC98CD4E3DDB5CF94C145857F6737575CAE5C6E6F2B8F4FD9FCE0ABA712ADB52E5FAFA19E5CFB7166BFF54FBF3C77B74F8FC63D29FF3D8B8E66EAC246E2895FF373B2DB37E4DBF26F75C6B714DDBDAD32CEFB7DF7EC98D37DED82B35BA78DF78FFDAD32FBBA6EE0012D7CC3DE490437A6D656E672B75F7DF7FFFA7D340D94582AD49B0C59FF8A30706676B5258505C00D0EF229F944FAEF1A45AE5A1974E675779A8E3A45A7DA9323E561E65AB7AD2DB8DA54A5376CDBDE6F257EA9BAB7B897BCD384A9C8AD341994F46F1F5D4D61CF1D4616B5ED45DD9FBF4683ED95BFBB678AEB1546DCEEF3734578E4F5FF397834EACBEFAA56DAAE7BC78BDDC72434353796AEB769F493FF3DF8DD35BDED5EEFD9AAA7551C4CA4FDD1CA7914D3FE3F0AE7EAEAE0ABAF17D2734B57C215A5CA737FDDC43E334CA71ADDE288665D7CF4D7F9EFC76DBF78F55B9A5EAEC58E19BBEF7EFA2509DFE3C93E277A15FD3AFC93DD7DEC891234FAC5D99DB5BC5DCDAA26EED4ADDF87CBBB30120FDC3ED3C76ECD81EBF666E77AEA9BBD75E7B3D3162C488D74BB03509B6F8137FACE5A06C4D0B0B8A0B807E57BF8B7C523EB99A936AD9C46E9CE6AEA6C5046F9CE62EDB6666F9A3E976971D5A2A6F1113C2137F7CD1ABB26B03CE6CD9A1A1A93C234E01593FA3656B71AF19478953713AE8F2C97D3BE4896B52D4AD2DE6E66D9FDECA277B7ADFD6F8B3399B3694CA7F88EBD7D6AEC8CDDE3F56B7C67573A7CF7B7376BFA9BC77BADDF2B4FDA7BE543D2056E5C6F56AD3D78FCA4E979C6E17AB76D3CF2BA58FDD91BF2E4C9D7ACECB5B4FA3FCDBB1B32E7865C79FABB1B9725067A76D7EE9F5711DDDCAD238956DDB6B4AD5E6EC734A95EB6BAF39DA7AEAE86BA3A896DD2F558E8CCF4DFFBD2DAE05AC5FD3AFC93DD7CEA851A3B6A9ABAB7B3E2FAE5E70C1057D52A38BCFA959A5FB7C7C0F9956C19D74D2498BCE38E38CA43F9C7CF2C98BD2406992606B126CF127FE1415D67230B6368505C50540BFABDF453E299FEC8629B3E66E547BBABBB609EA5265E7EC1A81A5F20DD9CA9D5275FBC65265DBD6C9E239F5A5CA95311917FF4E68AAEC34A154F970C3CC966DC4BD661C254EC5E9A0CB273B2BC6AE4E51B7B3D7FFA28BD7F7483ED9D3FBB628764671B6ABCF6B6CAA8C4D9F9F122B63E37AB471EAE58367B66C16AFCB56ECB69E6A390A51F54DD5131A9A2B93D3ED4E8D025567EFD7D054F96EED698FD3DB1FCF4E315BAAFC3D4EA5BCBABF8FDA15C46D9F31FDD2AD3A166EE3E7AD2D06EBD7F46B72CF3557575777555E589D366D5A9FD6E8E2F36A8ABA57C9B40AECEAABAF1E17AB739F7EFAE97E29E8C6E7EEBDF7DE4F8D1E3DFA5D126C4D822DFEC49F41E05ABCC7DA1616141700FDAE7E17F9A47C52DC8B37712F4E3571BAF679DC9A167557A7983B74F2C9245947BFA6E9D706AF3DF6D863FBDA532DDF7FFFFD7D5AA38BCFAB3DF5727C1F7F95829A3163C683E79D775ED29FCE3CF3CCBBD340996547A4D911893FF16710D8CF8505C50540BFABDF453E299F14F79AB817A79A385DFBFC6D758BBA6B52CC954FEAD734FDDA80575757775E5E4C9D356B56BFD4E8E2736B56E99EE7AF52404F3FFDF466E3C68D4B1E7EF8E17E2DE8A69FFF9FD1A3472FA9BDC8BA1D91664724FEC49F41603F15160C0601FDAE7E17F9E480CB2707DB785ADC6BC651E2549C0E8A7CB2BB45DDB529E6CA27F56B9ABC73C01A3D7AF426757575CFE5C5D4BE5E9D5BBB4AB7A6A0FB5C7C2F7F9D82F9D39FFE74D49429539222D87FFFFD17A681F2E981F07B4BBF67356DC3ED8824D8E24F33C0EB7E4CF6C160AB270B0B0683C0509F7CD3EF0E62F2C9C1954F3EF4D043EFBCEFBEFB6EB9E1861B9E3BF2C8238F1F3E7CF8FAA25CDC1B4789534D9C16681CBFAAA26E4F1473E593FA354DDE3920E33F7D7EF7BC90DAD0D0D0AF35BAF8FC9AA2EEEEFE8205D3DCDCFCF773CF3DB71005DD534E39E5A634487E3840FE23E641BDD2FF907644126CF1A70D91826EB762B20F06593D5D583018040613FD2EF2C941964FA6C3E8F5EEB8E38EE9CB972F7F3E1F57A7DBFDFBECB3CF7E70BFFDF6FBB44817F7C651E25413A7051AC77755D45D7758CF1573E593FA354DDE39E0E23F7DBC39DFEE57BFFA55BFD6E8E2F36BBE73B3BF60C11C75D4518F5E7FFDF58528E8CE9B37EFE6912347CE1E60FF1157FA1FD28E48822DFEB42156D0EDEE80B0B70657BD51583018040603FD2EF2C941964FDE73CF3DDB2E59B2A4CB6B272D5CB8F05FD3A64D3B77C488111B8978716F1C254E35715A90717C6745DDDB87F56C31573EA95FD3E49D032AFE478D1A55C99FBFEEBAEBFAB546179F9F7F97F85EFE82053379F2E4650B162C284441F7F6DB6F8F532E5F3B40FF2376FA1FD28E48822DFEB4215AD05D5992DE9B83AADE2A2C180C0203997E17F9E420CA2753AFB9EBAEBBFEFCFCF3CFAF728CFD422A7DCDD2C6C6C67D45BDB8378E12A79A382DC838BEB3A26E4F1773E593FA354DDE3960E23FFDF7BEFCF1FEAED5C5E7D77CC7FBFC050B66DCB8712F3CFEF8E38528E83EF6D8634BD320797080FF476CF71FD28E48822DFEB4215ED0ED98A47467309514A0190C0283857E17F9E4206A575E7965F2D4534F2D5BDDB1F6134F3CF1AF534E39E5FA112346BC53DC8B7BE32871AA89D35E18C7AFAE38CD72C795B9B7B73EDE1FF930FA354DDED99FF1FF4C7EBFBF6B75F1F9352B749FF6172C98BDF7DE3BF9F7BFFF5D88826EFA3D9EEE46800FA8D6DF3BA2679E7926EB7CE3DFFEF8FCA79F7E3A3AFEC2EC88065B7CF566FCC5DFEDFEFBEFCF6EDF7BEFBD2BFD3BC6913B0F3CF0C02ADF73D1A245C96DB7DDD6ADCF8FF77BF8E1877B2D16962C5992FDDFE8EAF9471E7924993F7F7E767BE1C285C9934F3E992C5BB62CF9C73FFE912C5DBA54FCAD414B13B964C30D378C41DAC455EC9A8A5C5818D6FAFD6330F84A59045070AF6CEDAF067CBF3BD4F7A143753C1379D7E2C58BFB24F7ECCF1CB1BB2D7E9E9FFCE427C9A38F3EBADA63ED784DBC564C1723EE9F7DF6D9151EBBFBEEBB93871E7AA84FC75C0321EE8DA356DE86529CAE6A7EEB89279E58E1B3632E23E6A5CC37F5C9387E75AC6C85EEA9C37A7685AE7CD2FE7785D6B1FFB9E69A6B92E5CB97AFB0DD3DF7DCD3ABDF43DEA975D6FABB56179F5FF37DFE635AA5600E38E0807F1765856EDA49DD350856E816E65411D1C97FE52B5FC912A29D76DA29BBDF31B17DCF7BDEB3CA9617F5E2FCE95B6EB965A7EDC4134FECF43B6CBBEDB6C997BEF4A5E49FFFFCA723260758FCFDE637BF495EF39AD764B737D86083E4DC73CFED74BB18CCBDF9CD6F4E3EFAD18F26BFFEF5AFDBB5D881C736311177D9659725BBEDB65BF2C10F7E30BB1DEDFBDFFF7EF2BEF7BDAFAD9D75D6596D83C04D36D924F9AFFFFAAFEC3DB6D9669B76DB456B6E6ECEB6FDF18F7FBCC273B52D4F7022013AE18413DADACE3BEF9CACBBEEBAC9B1C71EDBEEF13BEFBC33DB3EBEFFEB5FFFFAECF6461B6D949C7DF6D9C9830F3E98FD7F8AFF0B8E2C5FB3981C66A518405FD3EF52D8F14C4C9ED5E66DEF7FFFFBB349AAFCF9FFFEEFFF4E66CC98D1ABB9671172C4D569E79D775EB2FFFEFB5F5CA9541E79E185179EEFC630FB3FE9EFE3B7DFFEF6B7FF9EFE5D2FB442B7FFE33E62EEAD6F7D6B72FEF9E7B77BFCBDEF7D6FF2C31FFEB04FC65C032DEEADD01D9A71DAB158BBE38E3B663117FFC63C66C7CF9F3C7972B2CE3AEB24A79D765AF6995124D9628B2D92CF7FFEF36DDFE3861B6E10A7BD378E5F9B62EEEDBD5CD4954FEAD7DADA05175C90BCEC652F6B2BA4461F147177D14517B5DBEEEF7FFF7BD6A7C4F3D1AF44DF56DBA64D9BD6969B8D1F3FBEAD1D70C0019DCE4FC60131F24EF1DF55FCC74A582B74E996C30E3BECE9A25C43F7D65B6FBD6E005F43B75017738F24F9B39FFD6CF28E77BC239933674EF2F6B7BF3DBB1F47FEE4DBDC75D75DD90EE088238E4866CE9CB9423BFCF0C3B3E763BBFCA8A05FFDEA57C9E9A79FDEAEBDE52D6F498E3BEEB84EBFC75FFFFAD7E495AF7C653269D22405DD01127FF951B8DD29E8C6D1AF51B48F3879E73BDF99B588B9B8BFFEFAEB67C94A6C77E69967763A79BBCF3EFB64711945D9B83F7BF6EC6C122FDEF3939FFC64F2C52F7E31D975D75DB3D79F7AEAA9592C8D1D3B36BB9D272E13274ECC0ABF31E0AB6DDFFDEE77B3F7CC8FC68DEF1FDFE9CB5FFE72972DB6BFF0C20BB3EF1D83C18D37DE382997CB0ABA3D18937D3098722D4700FD2E03643C73C9259724AF7AD5AB92E9D3A76793F91147318E89D510D1B6DA6AAB64EAD4A96D676DE98DDCB30839E29AE493A3468DDA23FD9DA5C3BB250F7735BE7EFEF9E76F9C366DDAB9E9DFF581D85ED41723EE63BCF5ED6F7F3B8BBB18D7444C45DB6CB3CDB2F8CEEFC7CA1871AFA03B94E334FF2EF7DD775FF2894F7C225B4C103F731469E37EED6ADC58B010F3059B6FBE79561C897FE3A0A078AF982F887F63C142A95412A7FD3B8EEFAC981BD7CC5DB793C77BAAA82B9FD4AFB53BF0248AB3EF7EF7BBB3A26CDCDE7AEBAD93B7BDED6DD9EDDA33101C7AE8A1C9C73FFEF1ECF6D5575F9D1D64182DCE761A31FAF39FFF3C7BEE97BFFC65F2A94F7D2AEBEBF6D8638F6C6153CC67467137F69DF17C6C1FAB82E59DE2BFABF8770D5DBAED88238EB8FFFAEBAF2F4441B7A5A5A53C72E4C8D903EC3FE2CA929D7E29E8C60E288EDE89A4353F3544FC478C9DD51BDFF8C6B6231DF3826E9C02218A671D5B9E48E705DDFC68CCCE92EFAE0ABAD17EFAD39F661335DD39ED8E8160FFC6DF8D37DE98C54E14413B2BE8C6113AF1FC2DB7DC92155E6340F4A637BD2979C52B5E916CB7DD7659C2317CF8F064D34D375DE1C8B648428E3EFAE8EC1426B16D0C0A6380B8D75E7B253FFAD18FB2F78D53271D7FFCF1D9E7C6F67FF8C31FB2F78ACF89E42A622DB68BDBF9CF1605DD612B59F1931774E3FBC4AA8F7C82308EC41BD67A045EFED8873FFCE1E48A2BAEC82615E3678E23F122E623693AE38C33B26DE23531B118AB866FBEF9661311AB19937D30A8EAADC282412030D0E97729DC78260ABA3149B5E79E7BC6D1FF6D93FA1DF3B9830F3EB8D772CF22E4886B9A4F8E183162A3F47777729AB73FF99FFFFCE7D99AA1F5D3D75D77DDE9E9730FA47FDB93623B115F9CB88F03A5A358F5FBDFFF3E99376F5E7656AD68AF7EF5ABB3B8CAEFC744AEB81FF205DD211DA751548EF88B988BD5BCF9D9E3A2C0FB810F7C203BAB57535353F6F9279D7452566C8E79A71D76D8215B2117FFC6FBC79C40ED5C9838EDB7717C57C5DC7556F2FCDA1675E593FAB5762D8AA0115B7160481C3898B798331F5653248DB35C461FF3BBDFFD2E3B80E4B7BFFD6DF6F8B5D75E9BF56B71C048ED299AE360957C0E75DF7DF7CD0E6889D7BDFCE52F4FBEF6B5AFB51574E59DE2BFABF81F356A5425DF2EE2B03FC5E7D7ACD0ADF80B164CFA9FFF8228D414C1B1C71E7B5E1A283F1C20FF11BB95ECF47541F7C0030FCC3AF548B2DFF08637B4DB3945721D3B9778BEB1B1B1ADA01BA74FE86C856EECB486B51674E368C7889358911B4716D5B638A54E4CC2C4F3713EFF8EDF294EA513EFD3D0D0A0A05BF0F88B5363478CFCE94F7FEAB4A0FBC73FFE311B08E5A7C28B23C462703761C28476936EDFFBDEF7B25393E4C9CD1D77DC910DA822A189F7896D4E39E5946CC016ED431FFA5016BBF9299423AEA64C99920DDAE2678855B971C45C0CFCE200814888E2142979413756895F7AE9A5C955575DD5AEC50AF1389AEEFFFEEFFFDA4E55326C25C5DF78EFFC77D1F1B426F1FCE73EF7B9ECDF384061DCB871D9CF652262F562B20F0657BD5158300804060BFD2E851ACF7456D08D2242ACD2CDCF1614078EC6A9367B2BF72C428EB8B6F9E4C891233F555F5F7F6BEAA1C71F7FFCB2F4F71313427F8BC7457AF1E23E0A4FB18230C63CDD3995ADB81F92055D719A6E3B66CC98ECF9287EC41C40EC2FF216D774CD0B30071D7450DB2AE158CCF03FFFF33FD9F651CC8D9F21560EC7FC96F9A67E1DC7AFAA98BBB2EDD6B4A82B9FD4AF7559D08D79EE8E97251C5653D0FDCE77BE93DDFFC8473E92EDF7E23221B1AF8BF9D1E807D75B6FBD6CDE320E3E89BE27F2D6384B40A552C90E4E8C8552A3468DCAE655A3F03AACB5A02BEF14FF2BD9A6392FA2C61952FB537C7E4D11BAD95FB060D2CE67C7C99327BF50807AEEBF478F1E7D731A249F1E4CBFDFBE2EE846121D45D738C2274E25D3B1C5E3B182370A5D7941F7A69B6ECAFE83C64E2A6F23468CC81E1FD65AD0FDCB5FFE929D3227AEA112FF46012D9E8B9592713F7668F16F5E64ABBDC87C24D0F94EAF76B5AF826E31E36F975D76C906449D157463601583A3782C8E847DDDEB5E97C5416C174785C5EA8938A5485C1B221E8FA3D96205783CD659921247CC468213071CC4A02E3F0A2E068F91C0449214D7CA8D09BEF85E710AA6386237066F79AC453CC7D16A5D254291F044BCE789501C49176725882386E3F9F8B9E27E1C9DD731697AED6B5F9B1DF010EF11D7B3B8FCF2CBB3D7C49172E2AFB093F63D5D58300804F4BBFADD21ADAF0BBAB1222B5653C541A3717DB3FC1ABABD957B162147EC897C72F8F0E1EBA73FDBE4745CF748FC1BF7456F71C7F17149A258DDB8DF7EFB65A7668C1613B37196ADFC7EC4A0B8378E1ACA711A0769476CC6E945E3A0F38E2D56ECC62AE298BB8A224A7CD728B2C425C7E260F458C91B67FDFA7FFFEFFF659F110596983313A77D9EAF75B798BBB2ED57B7A82B9FD4AFADB4A01BF39BD1C7E52DE6AD87D51474E37BE407A8C4B572E394CA71204ABE6024E64CA3801BFBCA934F3EB95D7F1607A7C42ADBB83E6E9CB5E090430E59A1A02BEFA4A3F477B97B5E448D4571FDA9BEBEFE859A82EEEEFE3A053375EAD475D3C1F373715DA2FEF4C0030F5C9106C8E2F83E76446BD7E2C2E9F9D18D9DB5FCC2EAB505DD28E28E1E3D3A3B75431C49142B236B0BBAB17D5C943D4E2911473C46812C9E8BA390E2A88D986C89A26FC7EF123BC4D8E9C5ED8F7DEC63D9648D826EB1E32F56674771BE634137928818A4FDF9CF7FCE1E9B3F7F7E56F88D98895335C7B525E2344B71F46DB4385D48C44C9C9E398EC69D356B5656A8CD5B1464F3D32AC5B528E208DA187045CB0F2C8855E551AC8DB889826E0CC06210981774E328B4486062B0164955DE2226E3144C91E8445CE631DCDDA3E0E29A14917CC5633128740DDD01555CE8C9C2824120A0DFD5EF9A58EB8382EEEEBBEFDE36911605DDB804473C16638FBCA0DB5BB9671172C49ECC2707DB787A308FE36312374E3B1B13C6F9E96AE376DE5A5A5AC4BD71D4908ED3D81F44D1388ABD2B6B7110508CFB77DA69A764D75D77ED349EBFFAD5AF263BEEB863DB7C8638EDB37C72758BB92B7B5D778BBAF249FD5A972DE607637E316F7156BFE83BF2FBB5AB5D639E3C169AC4429238702572D5FAFAFAB616B96A7EF681DA532E478137FAB3CF7CE633D9FC653E1F1FFB4D79275D49E36D93BABABAE7F2426A1CB4D41FE2736B8AB9CFC5F7F2D729A04993265D14477AF4A7638E39E6376990CCB2235AFB16097074EC71947BEC6CF21609723C1ECF7756D08D899328EC47A2DD5941374E7D16D740896DE3A8C9782EB68B626EEDD143B5897FECB8A2D816F723C18ED5BA7194A5826E71E32F0AFEF1B7FDC10F7ED0AEA01B1D794CB8C56999F36DF3235DBB6A471C7144DBB671A4ECE69B6F9E2543F13E918CE483B6783E4EA31447BDC5ED5B6FBD358BC558911BDBC4D16C9160C5D1C0175F7C715B41B7B36BAC75D6E288E23C698A23832306E348DE782E0AD771BFF628B8F3CF3F3FD97EFBEDB302767E5A938E4953EDEF41FC15AAB8D0538505834040BFABDF6558DF147463E23F0E2A1CD6BA42214E2D17078ED616747B33F7ECEF1C513E39F4C6F1F901D2718ADA38CD78C4685C7A262E611463ECDA31B3B817F743354EE3524F871D7658D6E2D24FF119713BE6B7629570DC8E4B30C5294FF3B37DEDBDF7DED92AB7D8774401378ABD71EDCB28D4E4DB89D33ECB27D7B498BBB2D7AFAAA82B9FD4AFADB4C5A5DC629F17FD4DB55ACD56BFFEFCE73FCF9E8B53287FEB5BDFCA6EFFE217BF688BBB583012796A1C1812B9692C3C89DBDFF8C637DA5D433756ECC6D903E27ADD71204C5C82302E8918B7A3DD7EFBEDF6BFAC545D5DDD797931350E7EEA0FF1B93505DDF3FC550A6AF4E8D1EF1A3366CCBF22D1E90F4F3CF1C43569803C1CDFC38EA8E70ABA8F3FFE78BBC7E3FEB09514746B93A4CE0ABA0F3DF4505B012D12EE61ADE7EDDF6CB3CDB29D51EDC5E0E300812802C6D194B5DF217644714467BCB7826E71E32F8E5A8D84A6B6A01BAB5EF3D8C95B1C311B2D56CD464213AFCB1F8B6BDEC660AF76D03667CE9CEC761468F3415B5CCF2612AA88A3484CE2F94F7FFAD3D9445E9C82241295E9D3A7275FFCE217B3EF112B70E328DC485CA2CF7AECB1C7B2442B2602E3F425713F6235E2330E2688FBB1DDDA5EA7A263D2B4C71E7B747A2083F8EBF7C9FC9E282C180402FA5DFD2E7D309E89DC2A563C449E181359C71C734C7600DFA9A79E9A3DDFB1A0DB5BB9677FE788F2C9A1378E8F49B298208EDB471E796416538F3EFA68763FC6D85FFFFAD7C5BDB817A7ADDB4781245E93FFBCB12A381616445C76FCCEF159B14238B65D7FFDF5B3B981B8966E9CFAD47C539FE793FB0E5BF3626EAEB3A2EE3EF249FDDA9AB4587D1BFD532C14897FE394ECD10745DF13972F8CDBD16FDC73CF3DD94293782CE64163FF16672288F788B9D128D2D6BE6F1C8C985FD736FAAF38D824E6BFA3FF8C330EC4ED68711D5EFB5F5626FD7B6E9F17536385785FAFD28DCF1B356A54DBE996E3FBF8AB14586363E339717A94FE907EF6D9699034D911F56C41F79BDFFC66ED1115D9A920867551D08D9D415C003E6F7124661C5D14CFC72996E37A24B103D972CB2DB3CE3C767EC35A4FB91CA7998895B7FFBFBD7B01B2ABAE0F072E8F2AA01544B04E112B288DC58A967690581DA3680B858A74389C3D09221A0151C8EE461E02A504860E0F11D8DD84470B96E2C08838541019FC6FF65E12B1415E02F29077082621101E2148122A9CFFF91E73334BD8BC36DCDD7BEE7E3E33DFD9DD7BEF3E38F9F2FB7E7FF77BCFB97139DC287031708BE63A5E01D918A435225ED519979C885717350A99816EEBE45FBC3AADF1CAB1680AA2F188CFA3D189F7B369DC178F8B8D59BC5A2C365FD1F0C4136F313C7DF4D147CBF7A58957B935DE5BA2B1698B8D545C3E3986AF8D4D5BE4E5673FFBD9F255B6F1FDF1D878C56FBCE236DEAB397E5EBCF7F32EBBEC5236409167F1FD8D4B8545C4ABDCE27D72E2318B162D2ABF3FF2332EED34F8BF2F7E4EB1DE94AF606B9C897CDB6DB7955FC799E9B1316CBC78E1D4534F2D733EEE8FBF3D5EF4D0B87C53BC322F7E573C0129FF5A6EB8B0B183059B40C0BA6BDD6584F6337169CE9D77DE39DF7DF7DDCB27D3E22D5AA2BF8A5E2C2ED319BD60A3DF6A66EF39DA3DA27E726CE57D3C511CFBE5C89338F331F65CF1E285344DCB4B2BC68B58637F7DCF3DF7C87B793FE6F3349EBF8AF7548FDF1DC3E218F8C615B8DEF39EF794EF4DD9384B78C18205E573585FF9CA57CA2B7DC5202686BBF1364CF17C46FCCCB83F9EAC96A723D64F0E1EC60E6798BB213F473F695D5B679C78E289E5D501E284A45887E28CDCF87D71C598B81265D4C4380969DAB469E55501A3378D752EAE1A106B4FD4C6786E34D6C3F83C22DE06EEA28B2E2AD798B85265AC4571824C449CEDDB380338A25157D55FD6A6A3A3E396C62C27AE563192E2F70D9A25DDE25FA3C52549B27DB1D0BC1CC3BB9174FBEDB7C7A5969F8EDFAF10BDB903DDC30F3FBC7C1F93461C76D8616B1CE8AEFE33A2B98EFBE2520F51E8EEBEFBEEF2558E71099B934E3AA9BC2F9E60699C951B85250A4A5C96394ECD8FC63C9AFAA1FEBEE79F7FBE1CCC35F3BD4B14A2E1E55F6CBCC68F1FBFCE88C7C5ABC2A29988C17D343F8D57CA466EC4C6EF9FFFF99FCB01FEE04D5B5C92249A9C688656BFACD2EA1103DBB80453BCA74EE461FC9EB82D9AA368B462B0BCFAFB60C4654D8E38E288557F436C20D7F4DFDA18FAC61389ABDFD7B8B44ABCE2389AB8F7BDEF7DE5DF1D9BD13DF6D86355FE375EA127FF5A6AB8B03183059B40C0BA6BDD6504F733F1FE8B7BEEB967D9B3C50B45A3CF8C3322E26A3F9153F12458E3C9FA66F79EA3D923EA27C756DE47EE449E44BEC6BE2AAE8E153975ECB1C7967BE9C8A75D77DDB53C2352DECBFBB19EA771E65B9C58102FEC8EEF993C7972F93BBFFFFDEF976FCB14CF7B350624F1A2F075450CA7E5E988F693317C3DE42DC31FE6AECFCFD14F5AD7D62BE28CD6783FDCF83C5E9C122FF668EC6362681A2733C573E431588DB35EE3B9F4461F9A2449F97EBBAB479C1C37F877FCF6B7BF2D9FC31C2AE28428F59775C9B26C7C4747C7AB8DC16AFCDB8F84F83D8386B9AFC6DFE15FA3028AE6E94B471C71C4B218B88D84A79F7E7A5691204F14F14585E8CD8B785F90386371F02590079FC9B874E9D2558F8B274C1A5F0F8E38CB3186FB430D65A3118F57CC479E8CD67BE12A44AD917F7166F75003FBA1722306AE8D5C8B5799C560365E00101FD7F4F31B6778473EAE9E9F6BFB9BE23D73D6F69846FEC759E243E57F346FF1B7C5E743FD7FB464C992216F977F2D315C18EE60C12610B0EE5A7719E17E327AAAA1DEFB2BFAACB86FF5BD48B37BCFD1EA11F593636F1F15EF0DBAB6FB07E7A9BC97F7F274CD35C4F34D6DD34F56E5F7D146CFA3C71AD7B834FC68AD1BEA2F4349D374C6E04B2FC7C0BF99E2E70FBED472FC7EFF0A153279F2E4538F3FFEF897E37FDA662A169CFB8B84BCAD4896131422A1C1967FF28F376973369CC1824D20807517FDA47E12792FEFE5A990A7A3D34FB6F2EFC1BA665D63441D7AE8A15B747474DCD518B0C65B0D346BA81B3FB7F87DAF0E3A3BF7AEF8FDFE152AE690430EB9FC98638E79A15967EA3EFDF4D337C530B748904B1422A110C93FF9C79BB849DBD0C1824D20807517FDA47E12792FEFE5A990A7A3D74FB6DACFC7BA26AC6BA3AAA3A363C7229E1C7CA6EE75D75DF7A6CEE8E2E70D3E3377E5EFDBD1D1AFA84993269D3479F2E417DFECF7D45DF99EB9F3DAFDCC5C854821927F4223342A9BB50D192CD804025877D14FEA2791F7F25E9E0A793ABAFD642BFC5CAC6BC2BAD652B22CFBF0E0A16EC459679D953FF9E4931B359F8BEF8F9F33F8E7C6EF89DFE7A8575CBCB7EDC1071FFCFC85175EB820AEE5BE315E78E1855F7577775F55FCCCA7DBF93D7315228548FE09F937AA9BC1F51D2CD804025877D14FEA2791F7F25E9E0A793AFAFDE468FD3CAC6BC2BAD6D2569EA97BD7E0E16B9CAD7BF1C517E7BFFBDDEF36683E178F8FEF5BEDACDC7CE5CF77666EBB28FE81B72BFE417BBEFCE52F2FB9ECB2CB1E7DE69967FE6F03F2E4FFE6CF9FFFCB534F3DF5CA9583DC9EF8790A915088E49FFCA3499BB7F5192CD804025877D14FEA2791F7F25E9E0A79DA1AFDE448FE1CAC6BC2BA5629F19EB6699ACEE8E8E8587D109B777575E5575C71457EC71D77E48F3EFA68FEECB3CF9643B9F8185FC7ED717F6767E71BBE377E5EFC5CEF99DBA6264E9CB873F18F7C7196654F1F76D8614F5C74D145BF9E3D7BF63D0F3EF8E0BCC58B17BF54E4C9D2A79F7EFAB1FBEEBBEFF6E27FF6FED34F3FFD9AE27BEE29BEE7A9F8BEF87E85482844F24FFE31CA9B389B4000EB2EFA49FD24F25EDECB53214FF59358D78475AD32B22C1BDFD1D171CB1083D9E1C42DF1F31CD5B16193830E3AE8EF8B7FF033D234BDAEF8C7BF75D0B5BCE3E3AD717BDC1F8F8BC72B440A804224FF8446A8053683368100D65DF493FA49E4BDBC97A7429EEA27B1AE09EB5A256559F6858E8E8E6B8A58B18143DC78FC35F1FD8E2228440A91FC13F2AF953783368100D65DF493FA49E4BDBC97A7429EEA27B1AE09EB5AE51D7AE8A1DB7474741C98A6696FF171A088C78B7879E5F0F6E5955F0FACBCFFC078BCA3060A914224FF84FC6BF5CDA04D20807517FDA47E12792FEFE5A990A7FA49AC6BC2BA06A0102944F24FC8BF16DC0CDA04025877D14FEA2791F7F25E9E0A79AA9FC4BA26AC6B000A914224FF84FC6BC1CDA04D20807517FDA47E12792FEFE5A990A7FA49AC6BC2BA06A0102944F24FC8BF16DC0CDA04025877D14FEA2791F7F25E9E0A79AA9FC4BA26AC6B000A914224FF84FC6BC1CDE031368100D65DF493FA49E4BDBC97A7AD112FBDF4527EEFBDF7961F37E67679AA9FC4BA26AC6B000A914224FF84FC6B93CD604747476E13083032C68D1BD7B9C5165B5877F593423F29EF85BC97A76B8C18CE167F72F971636E97A7EDBB8F7F8B612EEAAF750D40211206BAFEDDE5DFD8B272A00BC0C8ACB9F52449ACBBFA49A19F94F742DECB53035D36C6560E01EAAF750D40211206BA42FE8DADE182E30C3032EBED84587357C60447443F29F493F25EC87B796AA00BA8BFEA2F8042241422F927FF589F0183E30C3032EB6D7DD040B7EE88E827857E52DE0B792F4F0D7401F557FD055088844224FFE41FEB3360709C019ABFD60E3E3BD759BAFA49A19F94F742DECB53035D40FD557F011422A110C93FF9C77A0F191C6780E6AFB5F52106BACED2D54F0AFDA4BC17F25E9E1AE802EAAFFA0BA010098548FEC93FD63964709C019ABBCE0E7576AEB374F593423F29EF85BC97A706BA80FAABFE0228444221927FF28FF51A3438CE00CD5D67EB6B19E83A4B573F29F493F25EC87B796AA00BA8BFEA2F8042241422F927FF58EBA0C1710668DE1ABBB6B3739DA5AB9F14FA49792FE4BD3C35D005D45FF5174021120A91FC937FAC73D8E03803346F8DADAFC740D759BAFA49A19F94F742DECB53035D40FD557F011422A110C93FF9C71A870D8E33807517FDA47E12792FEFE5A981AE3C05EB9AB0AE0128440A91FC13F2CF600100EBAE7E52E827E5BD90F7F2D440579E82FAABFE0254DAC0C0C06BCB962D53045A208A7F870545215A2EFF84FC335800C0BA8B7E523F89BC97F7F2D440579E82754D58D7004AB367CF5EB068D12285A005E289279EF86151886E957F42FE192C0060DD453FA99F44DECB7B793A32F1D24B2F95C3D9F8B831B7CB53B0AE09EB1A40D3D46AB5FD6FBAE9A6250B172E5C5CA557182D5FBEBC9D5E51B470EEDCB9571645685E11FBCA3F21FF0C1600B0EE32B6FAC9050B16E827B18F92F7F254C853B0AEE93BAD6B006B168B5FBCA2A5881571EDF9568FFFFCCFFFCC274D9AB4EAEBCB2FBF3C8F27EAAAF0B7AF2156AC3CFEFBCABFFE5CC83F830500ACBB8CA57E72CE9C39F939E79C935F73CD35FA49ECA3E4BD3C15F214AC6BFA4EEB1A40F52549F28E8E8E8EF9699AFE7ED09374754FD4015561BD02B0EE42439EE7EF58B264C9B2C58B17E793274FFEB923020080BE1380CAEBE8E838379E942BE20F871E7AE816C5C7092BBF8E98E008011558C70C1600ACBB507AE491477E96AF54ABD59EC9B2EC20470500007D27009595A6E9EE31C86D0C708BAF2735CECE5D197547096875060B00D65D088F3FFEF8675E7DF5D5C6F36AF96BAFBDF6EAC9279FBC284992AD1D1D0000F49D0054CEB469D336EDE8E8B875D0F036CFB2ECCEC15F3B4B17A802830500EB2EE479BED9A2458B9ECE5713B74D9A34E942470800007D2700959365D9D1430C6F870A67E9022DCD6001C0BA0B0F3DF4D079F91A5C79E5952FA469BAA7A3040080BE1380CA489264878E8E8E25EB39D075962ED0D20C1600ACBB8C6D0B172EFCC0F2E5CB5F5DD3136B7FF8C31F5E9E3265CAFD13264CD8DCD1020040DF094025A469FAE30D18E63A4B176869060B00D65DC6B679F3E6DD9BAFC3FDF7DFFF549665C7395A0000E83B016879699AEEB781C35C67E9022DCD6001C0BACBD89524C96677DE79E78A753DB1F6DC73CFFDA2C8DD67E2F18E1A0000FA4E005A5A514C0E2BE2BFD234BDB1F87867114F3A4B17A8F8BA66B00060DD650C3BF9E493FF7DC58A15FFB796E7D55EECEEEEAE39530200007D27009515EFA77BF0C1078F4BD3F463071D74D0E78B8F933C510754680DB35E01587719C3E23DCAAEBAEAAAF96B7A56EDF6DB6FBFACC8DBBBBD97190000FA4E002A2949922D8B22F3F2EAB77BA20EA80AEB15807517BEFAD5AF7E72EEDCB9AFACFEA4DAABAFBEFAEB499326FD2E4DD33D1D250000F49D00545292243B7574743CBEFAED9EA803AAC27A0560DD8570D659675DFD5A61D0F36A7F88DB8A9CBDC0D1010040DF0940651545E69345CC19E2764FD4015559C7AC5700D65D8817AB6EDDDFDFBFB4F1ACDAC2850B7F58E4EBEFE276470700007D27009595A6E9BF14C5E69AD56FF7441D5015D62B00EB2E347476761EF2FCF3CFBFB278F1E2FC6B5FFBDA6FB22C3BC851010040DF0940A51585E69B435D0AC21375405558AF00ACBB30D845175D74C739E79C9317B97A83A3010080BE1380CA2B8ACD69699AFEDB10B77BA20EA8CA3A66BD02B0EEC22A4992EC14791A1F1D0D0000F49D00545E5170FEA388C387B8DD13754055D631EB15807517E4290000FA4E00DA539AA6D71545E78B0A11A07106C0BA8B3C0500007D2700AD57706E9D3871E21E0A11A07106C0BA8B3C0500007D2700AD5770E62549F27E8508D0385365799EBFF5B1C71EFBD19C39735E191818C8FBFBFBC5084771DC5F9B3D7BF6825AADB6BF8CB4EE823C050040DF09006F5EC1599124C95B152240E34C953DF6D86357CF9E3D3B5FB46851BE6CD9B27CC58A156284238E7B1CFF9B6EBA69497F7FFFBEB2D2BA0BF21400007D27006CA42449B62D0ACE730A11A071A6EAE2CCDC18261AAC8E7E2C5CB870717F7FFFADB2D2BA0BF21400007D27006CA42CCB3E52149CFB152240E34CD5C565969D99DB3A67EAF6F7F72F9795D65D90A70000E83B0160E38BCD5E5996D5142240E34CD5C57BB81AA6B64EC4BF87ACB4EE823C050040DF09001B294DD34945C1B942210234CE54DDFA0E745F7A6161FED86DFF95DF37F3B432E2F3B8CD10D64017EB2EF2140000F49D00B49C2CCBBE5DC4F7142240E34CD5ADCF4077E9F3F3F37B7F7E727EF7CF8E7D5DC46D719F41AC812ED65DE4290000E83B0168B562F3DD344D8F5588008D3355B73E03DD27EFBBEE0DC3DC46FCEEBE9F1AC41AE862DD459E020080BE1380962B363F28E2CB0A11A071A6EAD667A0FB40FDAC350E74E33E8358035DACBBC8530000D07702D052B22CEB2FE20B0A11A071A6EAD667A07B6FFFB4350E74E33E8358035DACBBC8530000D07702D06AC5E63793264DFAA84204689CA93A035D035DACBB204F0100D07702D08EC5E6992449B65788008D3355B73E03DDFB669EB6C6816EDC67106BA08B7517790A0000FA4E005AC6E1871FFE2745B179A5F874138508D0385375EB33D07DF897D3D738D08DFB0C620D74B1EE224F010040DF0940CB48926487A2D8CC5788008D33ED607D06BACFCEBF27BFF7FF9DF2C6CB2D17B7C57D06B106BA587791A70000A0EF04A0950ACDDF1571874204689C6907EB33D08D78FCF6CBDF30D08DDB0C610D74B1EE224F010040DF09404B49D374BFA2D85CAF10011A67DAC17A0D74972FCF1FFEDF0BDF78B9E5E2B6B8CF20D64017EB2EF2140000F49D00B48C2CCBBE5E149B4B142240E34C3B58D74077E9F3F3F3877ED9B7C6F7D08DFBE23186B106BA587791A70000A0EF04A0550ACDBF665976BA4204689C69076B1CE82E5F9E2F7CB896FFE6C613D738CC6D443C261EEB6C5D035DACBBC8530000D07702D00A85667A9AA647294480C6997630D440775D67E53A5BD74017EB2EF2140000F49D00B4AC344D7F5C149B03152240E34C3B186AA0BB3E67E5AEED6C5D8359035DACBBC8530000D07702309A85E6E62CCB3EA510011A67DAC15003DDE10E731B61306BA08B7517790A0000FA4E0046B3D03C9224C987142240E34C3B58E37BE80A035DACBBC8530000D0770250D142F3529224EF5088008D33EDC040D74017EB2EC8530000F49D00B48D18E4C64057210234CEB40B035D035DACBB204F0100D07702D036E252CB71C9658508D038D32E0C740D74B1EE823C050040DF09403B15994F1771B34204689C691706BA06BA5877419E0200A0EF04A06DA4699A1485E66A8508D038D32E0C740D74B1EE823C050040DF0940DBC8B2ECE8A2D0F4294480C6997661A06BA08B7517E4290000FA4E00DAA9C8FC7B9AA627294480C6997661A06BA08B7517E4290000FA4E00DAA9C85C5AC4648508D038D32E0C740D74B1EE823C050040DF0940DB48D3F46745A1D957210234CEB40B035D035DACBB204F0100D07702D04E45E68E891327FEAD4204689C691706BA06BA5877419E0200A0EF04A09D8ACCFC2449765088008D33EDC240D74017EB2EC8530000F49D00B48569D3A66D5A149957264C98B0B94204689C691706BA06BA5877419E0200A0EF04A02D2449B27D51649E5188008D33EDC440D74017EB2EC8530000F49D00B4852CCB762B8ACC6F142240E34C45FE7DEB454C58D7E30C740D74B1EE823C050040DF09405B48D3F41FB22CEB5788008D3355F9F75D196B1DEC1AE81AE862DD05790A0080BE1380B690A6E9214591B95C210234CE54E5DF77B51872B06BA06BA08B7517E4290000FA4E00DA429665C71571B64204689CA9CABFEF1AE275835D035D035DACBB204F0100D07702D02E05E6DC344DA72A4480C699AAFCFBAE23CAC1AE81AE812ED65D90A70000E83B01689702736511131522A09D1A67219A3DD05DB264C91B6E5BB46851FEC8238F0CF9F8279F7CF2755F3FF1C413F90B2FBC30E463172C58903FF0C0031BF4F7C4EF9E3367CE1AEF7FE69967F2FBEEBBAFFC7CEEDCB9E5EF5EB66C59FEDBDFFE365FBA7469D307BA72B2FD43F5C1136B0000A0EF04A049B22CAB15F139850880AA6C8C46FB92CB3104DD6EBBEDF2EBAEBBAEFC7AC68C19F917BFF8C5BCA7A727DF7DF7DDDFF0F8DFFFFEF7F94E3BED944F9D3AB5FCFAFAEBAF8F9A9A7FE10B5F78DDE3162E5C98FFE217BFC8BFF4A52FE51FFDE847CBCF234E3EF9E47CD75D775D153FF8C10FCAE1EC19679CB12AF6DD77DF7CD34D37CD4F3FFDF4D7DDFEF0C30F973FFB8A2BAEC8B7DF7EFBF2F3ADB7DE3ABFEAAAABF2F9F3E7977FC7EDB7DFEE0C5D604CD40F470100007D2700552D30F72749B2AB4204405536466B1BE43634FB0CDD18CEBEF5AD6FCD67CE9C590E6B8B5F996FBEF9E6E5C72DB6D822FFF33FFFF3558FBDF0C20BCBDB7FFEF39FE78B172FCE77DC71C7FC2B5FF94AFEA77FFAA7E510B8F1B8CB2FBFBC7CDCEA71C82187E49FFAD4A7F2EF7EF7BBE5D73148BEFAEAABCBDFB7F7DE7BAF31E2B137DC7043FEE8A38FE6C71D775CBECD36DBE403030306BAC098AD1F8E020000FA4E00AA5A609E4B92645B850880AA6C8CD636C86D1889F7D0FDFEF7BF9FDF7CF3CDF9565B6D95FFE4273FC93B3B3BF371E3C69567D5362E7F1C97338E01EEBBDFFDEEFCA9A79E2A07B371F66DDC7EC925979467D59E75D659AB7E660C5E4F3BEDB47CF9F2E5F9E73EF7B9FCD24B2FCDBFF6B5AFE5071F7C707EF6D9679767D9C619BF311CFEC8473E923FFEF8E365C4EF7BCBCAA171E3B68F7DEC63F92F7FF9CBFCBCF3CECBDFF6B6B7E59B6CB249FEE10F7FB81CE8FEF77FFF77F998F89E69D3A6E5E3C78FCFEFB9E71E035DA0ADEB87A3000080BE1380CAD9679F7DDE561498E50A110015DA18AD7590DBD0CC816E0C4D4F39E5943262581AC3DABFFCCBBF2C87AD71766E7C1E71FEF9E79767E0167F4EFEAE77BDABBC5CF2DBDFFEF6BCAFAFAFFC39F7DE7B6F7EC001079443DD134F3C317FE8A187F2238E3822FFC0073E509E811BDF77D1451795C3DC88DD76DB2D3FF2C82357FD1D7119E5B70C71466F23BEF7BDEFBDEEB1832FB91CF77FFAD39F2E3FC6DFF48D6F7CA3FCFD06BA401BD70FEB100000FA4E00AA274992F71705669E420440BB69E64037CE9ADD6BAFBD565DD2F8DC73CF2D07B28323CEBABDFBEEBBF32CCBF2F7BCE73DE525988F39E698F27BE352C9F1734E3AE9A4F22CDC6BAEB9A63C9376CA9429430E66E3BD76E3E7FCD55FFD5539F01D3CA4DD76DB6DF33BEEB8A3FC3BE2B131088EAF3FF8C10FBE61A0FBCE77BEB3FC5D31D08DF7DA8DB38BE37BE277BBE432D0EEEC670000D0770250D5E2F289226E5588006837CDBEE4F2C2850BCB61E8C30F3F5C9E35FB962186B0F1B818AEC659BA8DF7D48DF7BF8DF7DE1D3CD06DFCCCB8CCF2C5175F9C5F70C105ABE2A73FFDE9AA4B2EFFEA57BF2ABF77DEBC791B74866EBC5F6E5C7E396EDB679F7DBC872E3056F73ED6210000F49D00544F9AA6FB1705E65A8508807633D203DD2449CAF7B68D38E18413560D7423A64F9FBE6AA01B97688ECB310F35D08DD86CB3CDCAF7DC8DF7BADD669B6DCA016C63A01BF7C7FBE636DE733706BA7129E75B6EB9A51C14C7DF73E59557965F0F3E43F7DA6BAFCD3FFFF9CFE7DB6DB7DDAA4B2EAF3ED07DE9A5970C7481B6663F030080BE13804ACAB2EC88A2C05CAC1001D06E9A3DD08DCB2917BF26BFEBAEBBCA816E9C39FB677FF667656CB5D5566B1CE87EFDEB5FCFF7DF7FFFB50E746FBCF1C6F2F3A38E3A6AD540F7339FF94C7EDC71C795EFD71BC3D88D7D0FDDD507BA071D74D0EB1E6FA00BB41BFB190000F49D0054B5B89C9265D9A90A1100EDA69903DD1884EEB0C30EE519B43BEFBC73F9BEB69D9D9DF9F1C71F5F9E9DFB9DEF7C273FF3CC33CBCB2D0F1EE83EF0C003F9965B6E595E82796D03DDB86DD2A449F9B871E3560D740F3CF0C0FCB39FFD6CFE8D6F7C237FF6D967CBC7CE993327EFEEEE2ECFAE8D33858BFFECFCB6DB6E2BBF3EE38C33F2993367968F7BEAA9A7F2534F3DB51CE8C6FDF13B3EFEF18F9783E5F89EF8FB76D96597557F97812ED0A67B1FEB100000FA4E002A595C2E4CD3F44885088076D3CC816E9CED1AC3D6175E78A1BC84725C1E79DB6DB7CDDFFEF6B7E75B6CB1C5AA98366DDAEB06BA31308D41EACB2FBFBC6AA0BBD75E7BBD61A0BBDF7EFB9583DBB8BCF2EA975C5E53CC9D3BB71CCEFEFAD7BF7EC37D975C724979DF01071C50BE27EFFBDEF7BEF2E70F0C0CE47BECB147795FFC7DF7DD779F812ED0CE7B1FEB100000FA4E00AA274DD3FF290ACC010A1100EDA6D9975C5EB468D17A3F76C99225E559B2AB7F5F9C49FBE28B2FBEEEB18F3CF248BE74E9D25567D62E58B0A07CBFDEF8B8B6DF11EFDD7BEBADB7AEFADEC111BF277E467CBE7CF9F221FFBEA16E37D005DA89FD0C0000FA4E00AA5A5CE66459365E2102A0DD347BA02B0C7481CAED7DAC430000E83B01A86471793C49929D142200DA8D81AE812E80FD0C0000FA4E00DAA1B82C4B92644B8508807663A06BA00B603F030080BE13804A4B9264EBA2B82C518800684706BA06BA00F6330000E83B01A8B42449C615C5E5418508807664A06BA00B603F030080BE1380AA1796095996CD528800684706BA06BA00F6330000E83B01A8B4344D8BDAD2F1438508807664A06BA00B603F030080BE13804ACBB2ACAB88F3152200DA9181AE812E80FD0C0000FA4E00AA5E58CE4CD3F43B0A1100EDC840D74017C07E0600007D2700552F2C971571A84204403B32D035D005B09F010040DF0940A5A5697A6396657B2B4400B423035D035D00FB190000F49D0054BDB0DC3571E2C48F2B4400B423035D035D00FB190000F49D0054BDB03C9524C97B152200DA9181AE812E80FD0C0000FA4E002A2B4992CD8AC2F24A7C548800684706BA06BA00F6330000E83B01A8AC383337CED0558800685706BA06BA00F6330000E83B01A87251F99B780F5D8508807665A06BA00B603F030080BE1380CA4AD3749F226E548800685706BA06BA00F6330000E83B01A8AC344DBF5A1496FF528800685706BA06BA00F6330000E83B01A8AC2CCB4E28E20C8508807665A06BA00B603F030080BE13802A17959E344D3B152200DA9581AE812E80FD0C0000FA4E00AA5C54AE2A22558800685706BA06BA00F6330000E83B01A8AC2CCB6615F1198508807665A06BA00B603F030080BE13802A179507932419A71001D0AE0C740D7401EC670000D0770250E5A2B2244992AD152200DA9581AE812E80FD0C0000FA4E002A2949922D8BA2F2B24204403B33D035D005B09F010040DF0940252549B25351541E5788006867030303AF2D5BB6CC30B505A2F87758D0DFDFBF5C5602A3C97E0600007D2700552A289F2C628E4204403B9B3D7BF682458B1619A8B6403CF1C4133FECEFEFBF555602A3BC0FB29F010040DF094035A469FA2F4551B9462102A09DD56AB5FD6FBAE9A6250B172E5CEC4CDD513B3377E1DCB973AFECEFEF9F57C4BEB212184DF6330000E83B01A88C2CCBBE5914950B142200DA5D0C11E3CCD02256C47BB88A118F152B8FBF612E30EAEC670000D0770250A582725A9AA6FFA61001000063681F643F030080BE1380CA1494FF28E270850800001843FB20FB190000F49D0054439AA6D71545E58B0A1100003056D8CF0000A0EF04A04A05E5D6891327EEA11001000063681F643F030080BE1380CA1494794992BC5F21020000C6D03EC87E0600007D27009529282B922479AB420400008CA17D90FD0C0000FA4E005A5F9224DB1605E53985080000184BEC670000D07702500959967DA42828F72B440000C058623F030080BE1380AA1493BDB22CAB29440000C018DB0BD9CF0000A0EF04A0F5A5693AA928285728440000C058623F030080BE13804AC8B2ECDB457C4F21020000C612FB190000F49D0054A5987C374DD363152200464AF2A31F6DF6ED73EADBADF38179BEC9D1BD37BCB3F1E53767D4DFE1E801F026EE85EC670000D07702508962F28322BEAC10013052BACF1DD8A1ABB77E5D7CDED5533BADABB776EDE0E8EEA9EF5DDED7579FD0DD53FB71E3FB3A7B07EEEC9A3E73FCF117F76F3D6D5A7D734712808DDC0BD9CF0000A0EF04A0F56559D65FC41714220046C2B133EAEFEDECABFD63575F6DD6949EFA5F77F5D606E2EBA9BDB58F35E2C80B7EF1AE786CF198CBBAFAEA5F8ACFA7F6D4FEA9AB77E0A1E2F1D717B1B4B8EFEF1D4D003686FD0C0000FA4E00AA524C7E3369D2A48F2A44008C84CEDEDA2145CCE9EAAD2DEEECAB5FD3DD5B9B39B5B7BE67D779F50F447C7BFAC05FC4E3E2F2CA5DBD03F7744EAFEFD7D9539B513CFEC1F231D3678E8F21B02309C09BB017B29F010040DF0940258AC93349926CAF10013052065F723906BA5DBD0357FFF16CDC227A6BCF94B7F7D53B3B7B6B0FC459B99DBD038715B7BFD8D957FB590C8263A05BC47C4712808DDC0BD9CF0000A0EF04A0B51D7EF8E17F521493578A4F375188001829E5A596FB6A8F96EF97DB5B9B1903DEC67DF13EB9F1B1FBDC1BB72D3E3FAAB8FFECF8BA78EC6DE5C7BEDAACC15F03C070D9CF0000A0EF04A0E52549B243514C867D86934204C086EAEAAB9DDCD55BFFDFB8EC725C56F98F67E8D62E2D3EF644149F3F158F3BBA77E083C5631676F70E9CD9DD57EB2E6EBF3BCEEA2D3ECE5BF971AEA309C0C6B09F010040DF0940150AC9DF1571874204C0481A7CC9E5F2F2C97DF5099DE7D7C6454CE999B54BDC3EA567E0935D3DF56F759E3F73B7A37B6F78E7EA67E41ED5376BA7E2F19F703401B09F010040DF0940DB4AD374BFA2985CAF100130923A7BFADF3FF83D74BB7B07F6983A63D68E8DE83AAFBE4DF78CFA87BAFAEAA7C499BC5D3D03E7C7A598E332CC8D9FD1D5533FA9B86F8AA30980FD0C0000FA4E00DA5696655F2F8AC9250A110023656AEFACBFE9EAADDD15C3DAF8BAABA7765AF1F54F0647676FFD88AEBE817DBA7AEB9362B8BBF2712714F7FDAA71B9E6E2F32BBF357DE6BB1D5100EC670000D07702D0CE85E45FB32C3B5D21020000C6E07EC87E0600007D27002D5F48A6A7697A94420400008CC1FD90FD0C0000FA4E005A5B9AA63F2E8AC9810A11000030D6D8CF0000A0EF04A00A85E4E62CCB3EA51001000063703F643F030080BE1380962F248F2449F221850800001883FB21FB190000F49D00B47C21792949927728440000C018DC0FD9CF0000A0EF04A075C5203706BA0A1100003016D9CF0000A0EF04A0A5C5A596E392CB0A1100003016D9CF0000A0EF04A0D58BC8A78BB879630B91104208218410425435EC0C01001881E7E2F59D000C4F9AA6495148AE76240000000000A0390C740118B62CCB8E2E0A499F23010000000000CD61A00BC0C614917F4FD3F424470200000000009AC34017808D2922971631D991000000000080E630D00560D8D234FD595148F675240000000000A0390C7401D8982272C7C48913FFD691000000000080E630D00560638AC8FC24497670240000000000A0390C7401189669D3A66D5A149157264C98B0B9A3010000000000CD61A00BC0B02449B27D51449E71240000000000A0790C740118962CCB762B8AC86F1C090000000000681E035D0086254DD37FC8B2ACDF91000000000080E631D0056058D2343DA42822973B120000000000D03C06BA000C4B9665C71571B623010000000000CD63A00BC0700BC8B9699A4E75240000000000A0790C7401186E01B9B288898E040000000000348F812E00C3926559AD88CF39120000000000D03C06BA000CB780DC9F24C9AE8E040000000000348F812E00C32D20CF2549B2AD23010000000000CD63A00BC006DB679F7DDE561490E58E0400000000003497812E001B2C4992F71705649E23010000000000CD65A00BC0708AC7278AB8D591000000000080E632D0056083A569BA7F5140AE7524000060F4253FFAD166DF3EA7BEDD3A1F98E79B1CDD7BC33B1B5F7E7346FD1D8E1E0000B43E035D0036589665471405E46247020000465FF7B9033B74F5D6AF8BCFBB7A6AA775F5D6AE1D1CDD3DF5BDCBFBFAEA13BA7B6A3F6E7C5F67EFC09D5DD3678E3FFEE2FEADA74DAB6FEE480200406B32D0056038C5E3942CCB4E7524000060741D3BA3FEDECEBEDA3F76F5D5664DE9A9FF75576F6D20BE9EDA5BFB58238EBCE017EF8AC7168FB9ACABAFFEA5F87C6A4FED9FBA7A071E2A1E7F7D114B8BFBFEDED1040080D664A00BC0708AC785699A1EE9480000C0E8EAECAD1D52C49CAEDEDAE2CEBEFA35DDBDB599537BEB7B769D57FF40C4B7A70FFC453C2E2EAFDCD53B704FE7F4FA7E9D3DB519C5E31F2C1F337DE6F818023B920000D0BA0C7401D860699AFE4F51400E7024000060F40DBEE4720C74BB7A07AEFEE3D9B845F4D69E296FEFAB7776F6D61E88B3723B7B070E2B6E7FB1B3AFF6B31804C740B788F98E240000B426035D0086533CE6645936DE91000080D1575E6AB9AFF668F97EB9BDB59931E06DDC17EF931B1FBBCFBD71DBE2F3A38AFBCF8EAF8BC7DE567EECABCD1AFC350000D07A0C7401184EF1783C49929D1C090000185D5D7DB593BB7AEBFF1B975D8ECB2AFFF10CDDDAA5C5C79E88E2F3A7E27147F70E7CB078CCC2EEDE8133BBFB6ADDC5ED77C759BDC5C7792B3FCE75340100A03519E802309CE2B12C49922D1D090000187D832FB95C5E3EB9AF3EA1F3FCDAB888293DB37689DBA7F40C7CB2ABA7FEADCEF367EE7674EF0DEF5CFD8CDCA3FA66ED543CFE138E260000B41E035D00364892245B17C5638923010000ADA1B3A7FFFD83DF43B7BB77608FA93366EDD888AEF3EADB74CFA87FA8ABAF7E4A9CC9DBD533707E5C8A392EC3DCF8195D3DF5938AFBA6389A0000D07A0C7401D82049928C2B8AC7838E0400008CBEA9BDB3FEA6ABB776570C6BE3EBAE9EDA69C5D73F191C9DBDF523BAFA06F6E9EAAD4F8AE1EECAC79D50DCF7ABC6E59A8BCFAFFCD6F499EF76440100A0F518E802B0A18563429665B31C090000000000683E035D0036489AA645EDE8F8A123010000000000CD67A00BC006C9B2ACAB88F31D090000000000683E035D0036B4709C99A6E9771C090000000000683E035D0036B4705C56C4A18E040000000000349F812E001B244DD31BB32CDBDB91000000000080E633D00560430BC75D13274EFCB823010000000000CD67A00BC086168EA7922479AF23010000000000CD67A00BC07A9B366DDAA6513884104208218410420821841042083172614201C0060D751D050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C6BAFF0FC6E57D9A0AC9FE2D0000000049454E44AE426082, 1); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('1bc2071a-1c4e-11ec-94ee-5ef70686b817', 1, 'flowLeave.flowLeave.png', '1a075ec8-1c4e-11ec-94ee-5ef70686b817', 0x89504E470D0A1A0A0000000D49484452000002EC000001AE0806000000CB5853060000264E4944415478DAEDDD0B9C54E57D37708D36CDDB98A889E99B3635D126692ECDA579DB246ADA4AD3A44D344D6CEB822BEA0BA251A3B2BB08F2E63534604D52125ADD5950FC3469BC2434684B13BC44033B2318EF888A4A2A5E4004969B229008A8CBE9F33FEE2103EE220BBBECECF2FD7E3EFFCFEECC9C9D59CEFE39CF6F9E79E6CC7EFB010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F42375D75D77C005932A87BDE68659B6FFF9A59BDF5C5CFCCA94CA41F61E0000F4B2A67F697D4763A93233BE6F6C2E5FDC582AFFA4BA9A9A2B9FCB6F6BA90C6A6A2EFF47F1730DA5D6F98D93671F3DF6CA59078F1F5F39D09E0400801E36664AE5ED0D2DE5BF6E6C29CF19D95CF9500AE8AD717954A9FCD1A2CEB9FCF6435F09ECE5AB52683F21BE1FD55C3EAEB1D4BA286D7F63AA8DE9B64FD99B0000D0C31A4AE5D352DD9542F7DA8696CA8CA65279F6A852E5A8C64B2B47445D30B9F55DB15D2C7F49017D41C3E4CA171A9ACB53D2F68FE5DB4C9E7D74847C7B1200007A49F5929808EC29985FFFCA6C7AAA52794D7E7D4BA52105FB5FC4AC7A43A9F5CC74FD868696F24D11F423B0A75A6E4F0200402FC897C2B4949FCCD7ABA7C01E01BEB82DD6A9BF12EA6F794BFAFEBC74FBB7E372DAF6BEFC6B4B794EF5650000A007A5C03DAEB154B93396C5C4B2975766D8CBDF4B5F9BA3D2F72B63BBF34BADEF4EDBB435955AFFA9A9A5DC94AE7F2866E5D3D7A51D5F97D89B0000D00BB63B4B4C2C6F69A90C6AB8ACFCBEA891CD73DE1BD78F6C6E3DA6B1B9726EC365B33F12A776DC7146FDBC963947A6ED3F696F0200400F6B689EF5CEEA35EC4DA5D64F8C9A32E7F0A21A2FAD1CD234A5F29E14E4BF9EBF41B5B9F5B2582A13CB648AFB4861FEA274DB487B1300007AD0A8D29C8F3596CA0F46187F2578E7E761FF717535942A6735B6B47E3E85FAA111DE3BB6FB6ABAED9E62394DFA7EDAB99367BFD51E05000000000000000000000000000000000000000000000000800E279D7452A6545F96FF850000AF11D8ED05F41F0080C004FA0F00406042FF0100084CA0FF00000426F41F0080C02430A1FF00000426D07F00000213FA0F00406002FD07002030A1FF000004268109FD0700203081FE03001098D07F00000213F480458B167D79D2A449595D5DDD91F6060080C04E0DC9B2ECA0F5EBD76F5ABB766D3662C4885BED110000819D1AF2C4134FDC94752897CB6BEAEBEB07DB2B0000023B3560F1E2C5C7B6B7B717793DDBBA756BFBB871E356D5D5D51D6CEF000008ECF4A194CF0F58B56AD5EA6C0771DDD0A143AFB08700000476FAD0A2458B2ECDBA306DDAB4E7870C197294BD0400ECCBE1BC1201FD35AA624FD11BDADADA8ED8BC79737B5781FDE5975F7E61E4C8910B070D1A74A0BD0500ECAB817DD02E04F641F614BD61E9D2A58F64AF61E1C2852BEBEBEB2FB4B700807D39B457CCAEB3B7D5D5D51D307FFEFC2DAF15D89F7BEEB9DB531FAE89EDED3500605F0DEC83CCAED317C68D1BF78D2D5BB6BCB493BCBEA1A9A9A96C861D0010DA3B9F6537BB4EAF8AB5E9D3A74F5FDE555A9F376FDE55A90F1FB2861D0010D83B9F651F64CFD0DB860F1F7ECC92254B5EDC31ACB7B7B73F3074E8D065CE120300F0EBD05E31BB4E5F983871E2F55B93EA13C4C475A90F2FB77700007E1DD807995DA72FC4279ACE9A356B6391D6DBDADA7E947A70994F3A0500787568AFF8E024FA424343C369EBD6AD7B71EDDAB5D9E9A79FFE707D7DFD607B0500E0D5817D90C04E5F993A75EAFD93264D8A57786EB63700801E9765D9EB9F7AEAA9EBEEBAEBAE175B5B5BB359B366F5CB8AC0DE5F7FF7B4DFB7CE9D3B7745B95CFE92FEEB7F7FBF193366E4FD175FF59FFE53FA0FA0C7A5C1EAFA74B0CC56AD5A956DDAB429DBB2658BDACB15FB3DF6FF6DB7DDB63E0D60C7EBBFFE572B56ACD07FFA4FE93F80DE11334B71B03470F47DB5B5B5AD4D03D6BDFA4FE93FFDA7FF00D8265E0636B3543B334D69C0DAACFF94FED37FFA0F806D620DA1C1A2762AFE1EFA4FE93FFDA7FF00E8F680F5CBE7DBB2A7EEFB7EF6E8EC8BF38AEFE33A838C014BFFE93FFDA7F41F401F0F581BD72DCF1EB9755CF6D04D63B6ABB82E6E33D018B0F49FFED37F4AFF01F4E180F5CCA3335F355815B5ECD11B0C34062CFDA7FFF49FD27F007D3960FDA232B1CB012B6E33D018B0F49FFED37F4AFF01F4E180F5C8ACF15D0E58719B81C680A5FFF49FFE53FA0FC08065C0D27FFA4FFFE93FFD0720B07756715684AE06ACB8CD4063C0D27FFA4FFF29FD07D08703D6E3774CEE72C08ADB0C34062CFDA7FFF49FD27F007D38603DBB7C41F6C8CFBEFEEA9783D375719B81C680A5FFF49FFE53FA0FA00F07ACA8C5F3AE79D58015D719640C58FA4FFFE93FA5FF00FA7AC0DABC397BFCCE2B5EFD7270BA2E6E33D018B0F49FFED37F4AFF01F4D180159FE4B7E88E962ED770C66D3EEDCF80A5FFF49FFE53FA0F606F0F589B37676D8F97B3876FF9FF5D0E5645C536B1ADD9260396FED37FFA4FE93F80BD3060BDD6AC92D9260396FED37FFA4FFFE93F803E1CB07665566967B34D061E0396FED37FFA4FE93F805E1CB07677B02ACAC063C0D27FFA4FFF29FD07D08B03963260E93FFDA7FF94FEAB4DC3860D3BE4A4934E3A71C89021A5F4B535D5E2542FA4CA3ABEC6E5D68EDB4F8CEDED356ACEFAF5EBDF3273E6CC8B274F9EFCD0840913D68E1D3B76D339E79CB3351AF9ECB3CF7E69F4E8D11B2EBAE8A2A5175F7CF10D63C68CF95CFA91FD05760385014BFFA9DAE8BFA62995F734FDCB9DFF4BFFE9BF7DA107BBA3BEBEFEB329CBCC48B5A5239CEF6AC5F633E2E7A544FADC3DF7DC73F665975DB6FCACB3CECA5248CFAEBFFEFAECFEFBEFCF9E7CF2C9ECD9679FCD427C8DCB717DDC7EE185176E1D3162C49614DC6F3DF9E4937F5F6057062CFDA7FF7AC657A6540E6A28957FBAB38A6D62DBF4FDC8A696D6FF17D5D8D2BAB0B154BE7ADBE5526BA3FED37F03B5077731A81F9D02F7DDDD0CE95DD5DD717F52237BDD82050B8EBBFCF2CB577CF9CB5FCEFEF33FFF335BB3664DD61DB17DFC5C0AEE2F3635355D971AF930814909ECFA4FFFED99732EBFFDD0C696F2034D2D733EDC59C56DB14D6C9BC2D1F14D2DE5A6148C1634B6544EC8AB547E3C5D3E276ED37FFA6FA0F6E0CE0C1B36EC0D43860C999242F6D61D8377636363F6C31FFE70A71393717B6CD74968DF1AF71BF72F45D2EB525F1E70F3CD37CF8CA07EF5D557671B376ECCF644FC7CDC4F6AE0174E39E59413042625B0EB3FFDB78761A954FE79637379546373E567DB57EBE8B82DB6696A2E0F4EC1E9C9A652F9A974DDD2F8BEA39615DF3735574ED27FFA6F20F6605752A83EBCBEBEFEA1EAA07DF2C92767575E7965B66CD9B26EE59BD83E7E2E7E7E87E0FE603C8E44496F86F543AEBDF6DA45E79E7B6EF6D4534F653D29EE2F3D09D83462C48809029312D8F59FFEDBB3B034664AE5ED0D9795DFB77DCDFEDF4558CA67372F9DF38174F9078DA5D6EF57575373EBB5E797667F50FFE9BF81DA839D4941FDFDA9965787EB89132766CF3CF3CC1EE59BF8F9B89F1D42FB33F1789225BD12D64BA5D2BAAF7DED6BD9BA75EBB2DE10F73B76ECD8174E3BEDB46B042625B0EB3FFDB7FB61E9C2893F7F53FABAA2B15499F94AA5EF2FAD1CB25D586A69FD7443A9757EAA49D595B6B93F6ED37FFA6FA0F6601733EBCBAB67D567CE9CD9A31927EE6F87D9F667CCB4D3D361FD806BAFBDF6F108EBF19FBB37C5FD8F1E3DFAF9A143875E243029815DFFE9BFDD0B4BE7976E7E730A49738BEBD37595E2B6EAB0D4D852BEBBA9549E505D699B7B0476FD37907BB05AAC29AF5E06337CF8F0EC81071EE8958C13F71BF75FBD3CC69A767A4CAC593FEFBCF37A6D66BDB399F633CE3863436AE42F0A4C4A60D77FFA6F77C35279E5AF97199457EE1896E20C1D8D2D954171468EFC6C1DA572F3C8E639EF4D41E9F30D2D9553F49FFE1BA83D58ADE30DA6DB66D67B2BAC5787F6EA99F6787C49933D961AEBF87883694FAF59DF9535EDA79C72CABABABABAB7094C4A60D77FFAAF7B61299FBD8CE50755B55F96ED1FCB0FF26D26B7FE9FB4DDEDE7975ADF1D339CA3BF73EB1B1B9A2B57344C9EFDD9C6E6D6CBD26D0F355C36FBE3FA4FFF0DC41E2C749CBAB1BD08CF37DC70C35EC938F13855B3ECED4EF9C81E8B5337C6595CFAC215575CB1223572B3C0A40476FDA7FF76CDD82B671D5CBD0CA16A39C2F1A91E89B014A1A9A954F94C53A97CECF8F19503D3F5B73494CA7745C88AAFA39ACBC78D2A953FDA3879F6D1FA4FFF0DC41E2C549F673DDE18BA37EDF046D4BB254E765B7C2852CCAE6FD8B0A14F027B3CEEA9A79EBA7E207EB892014B60D77F4AFF29FDD777060F1EFC99EAA5307B7A3698DD397B4CF5D298F87D244F764B7C82E98C1933B2BE74CD35D73C991AF94A03963260E93FFDA7FF94FEEBC1D9F51945588EF3A5F78578DCAA59F6199227DDB661C386B79E7DF6D9D9EAD5ABFB34B0A7C77F393D035D357EFCF8D719B094014BFFED8BFDE7F8A7F45FCF4AB9E2D01490B71461796FCFAE57CFB25705F62DF17B49A074CB8D37DE3861ECD8B1592D38E38C3396A4463EA69F3C63AFA41A64C012D8F59FDAD3FE5BB972E5914B972E7D64FEFCF95BFEE11FFEE19B83060D3A50FF29FDB7E77D986E3FB108CA8D8D8D7D9A71E2F1AB42FB891228DDD2D2D2F2F0F5D75F5F13817DEAD4A9F131BEFFD44F0E14C57FBA9D1E300C5802BBFE535DF55F7CF6C5A2458B2EDDBC79737BD56754BC347DFAF4E5C3870F3F46FF29FDB7677D98AE6F29B6FBC10F7ED0A719271EBFEA776E9140E996091326ACBDFFFEFB6B22B0CF9D3B77C190214366F6B3C0B4D30386014B60D77FAAB3FE5BBC78F1B1AB56ADEA722DE292254B5E9C3871E2F575757507EB3FA5FF76AF0FEBEBEBCBC5EDF3E6CDEBD38C138F5FFC2EF17B49A074CB85175EB8696F9F7BBD2B8F3DF6582C89B9AF9F06A64E0F18062C815DFFA9EAFE4BDEF4C4134FDCD4DEDEFE9AC7C4AD49FA998D4D4D4DFF57FF29FDD7FD3E4C5F9716D7F775D689C7AFFA1D974AA074CBD9679FBDF5B9E79EAB89C0FEECB3CF6E4C4DBCBC9F07A6ED0E18062C815DFFA9A2EEBAEBAE6CFDFAF59B76E353A15F9C3A75EAFD75757547EA3FB5AFF75F37FBF057C5E5BECE3AF1F85533EC1B2450BAE5D4534FCD5E7AE9A59A08ECE9F7D8B00BFF01FB55F5C580B569D3A66CF3E6CDDB5DB76CD9B26CD1A245AFDA36B6EBECFA9EAA38C77E1A206A66C01A68FDB5B7FB6FC58A15D92F7EF18B5DDA76E1C285792FEECAB6D19F71A6AADEFABBAF5AB52A0F2B5DDDBE66CD9AECD1471FCDBF5FB26449F6FCF3CFE7BFFB7FFFF77F671B376EECB17D3769D2A46CEDDAB5DD3E36C6CFC4CF3AFEF56DD5421FE9BFDDAFBECE3AF1F855BFCFCB1228DD72D65967BD542B33ECE960F7C4009861EFF39784070F1E9CD5D5D5E541F9FCF3CFCFCE3DF7DCEC939FFC64F6BBBFFBBBF9F75177DE7967BEED8D37DE981D70C001D971C71D977DF0831FCC2B6EFFC33FFCC36D972378C5B6B1FEEE3DEF794FA73565CA944E7F97638F3D36FBABBFFAABEC97BFFCA519F67EDC7F6D6D6DD9EDB7DF9E9D70C209D9873FFCE1FCFBA871E3C66DEB93A86BAFBD36DF3E4E61F65BBFF55BD937BFF9CD3CC07CF6B39F7D55C536B16DBC4C7CE8A187667FF0077F900783A38F3E7ABBFB8C6A6969C9B7FDCE77BEF3AADBAAAB0845F198DFFAD6B7B6D5F1C71F9FBDEE75AFCB2EB9E492EDAE7FFCF1C7F3ED7FF8C31F666F7BDBDBF2EF0F3EF8E06CFAF4E9D9F2E5CBA357F2BEEFA9FE8BCFBB38E38C337E562E97D76CDDBAB57D170E8B2FA77DFFA3D34F3FFDE1F477BDB91FCCB00FA82531B5DA47FB7AFF75A70F6326DB0C3B03C205175CB0A156D6B0A76038AF1FAF61AF99375DCD9D3B373BECB0C3B211234664718EFDBFFFFBBFCFDEFFFEF7E703497C7FE2892766F3E7CFCFB7FD9BBFF99B3C70C740F4B9CF7D2EFBCC673E936F13C16BF2E4C9F940536C1BB347F12EF7ABAEBA6ABB8A2702DFF8C6373AFD5DE2894104B73163C608ECFDB8FFAEB9E69ABC1776ACD34E3B2DFBD33FFDD33C48C7E5993367E683526CFFF5AF7F3D7BC31BDE90DD73CF3DDB859B388D6C6CFBD8638FE5B38FF1A42E9E50FEE55FFE65F6A52F7D29FFD9EF7DEF7B79DFC42730C7F745D8193D7A741EECA33FABEBAB5FFD6A7E9FF18A4E6C1767BE3AF0C003F39EEEAA62FB9B6FBE397BF2C927B30B2FBC303BE49043B2D6D6D65E0D5A45FFA5C17A707AB2B36A676FFA6B6F6F7F20DEF497FEAECB627BC7BFEED7CF7EF6B3FC6F187D575CD7D0D0905FF7D0430F6DBBBDA8DFF88DDFC87EE7777E276B6E6EAEE93EDAD7FBAF3B7D680D3B03C6D7BEF6B5676AE52C31B367CF6EED876789A9C9D39AC5AC78CC60C60CE7073EF0813CAC47788AEFFFE88FFE68DBCC66CCAE7FE52B5FC9037BCC7A46688A59D49831FFF6B7BFBD5D608F8AE0DF5970EB2AB047FDF33FFF73F6C637BE315FF620B0F7DFFE8B3072F1C517E7CBA83EFDE94FE741FAF4D34FCF4E39E594BC57A2C77EF5AB5F658F3CF248DE13D15F0F3EF8E0ABEEE789279ED816D8A33FDFF4A637E5F7FD5FFFF55FD95BDEF296EC7DEF7B5FF6CE77BE33DF26EE33BE2FFE1D11D83BEBBFA28AC07EEBADB7E6AF122D5EBC38AF58C610B7C7F5C5751FFDE847B33BEEB823BBF4D24BB3DFFCCDDFCCF6DF7FFFBCBF23685D7DF5D5F936F133E3C78FCF67FD172C58D0A3FD1767DF183A74E815D3A64D7BFEE5975F7EA1EA50B82185BBABD26DCBD2DFF6F21A3F4B4C4D9FD631FEDE5D05F6E8CDE2F6CF7FFEF3590AA7F9DFFA1DEF78477E5DF469ADF6D1BEDE7FDDE943678961C04807911B6AE53CEC975C72C98C7E741EF69AFCE09098F17CF39BDF9C5704A00F7DE84379FDF66FFF761E9A8BCB3123999EACE503C9A851A3F2C01EE1E84FFEE44FF201ED139FF8C4B68A60F5F4D34FE7B34D31A3FE6FFFF66FDB55CC48A5837B7E7BACDBDCF1778A2700F138F1A111027BFFECBF789FC359679D951D71C411F9DF39FE9E53A74ECDC37AD4473EF291EC9C73CEC9B72D027BF44C67F7551DD863663E7A2866DD63A94DFCBE31ABFEF18F7F3C0FF1F164EFF5AF7F7D76C30D376C0BECF18ACE9C3973B2BBEFBE7BBB8A5773A27FFFFDDFFF7DDBF2849D85FBB8EFE277DA712943DCFE677FF667F9D7F87F13AF54F5C47B3D3AEBBF2143861C95FECFA5E7D80B573EF7DC73B7A7FF8F11301E8AEBF5DFDE09ECD5B79F77DE79F975B1E4AB56FB685FEFBFEEF4A1F3B03360A481F2AFD3C0B8B516DE737AF2C9272FE82F9F74BAABF6F68015CB0F62008901226676628DF117BFF8C5ED2AEDE7FCE5E058FA12B3414560FFBBBFFBBB3C18C5128333CF3C735BDD7BEFBDD94F7FFAD3ECC8238FCC7EEFF77E2FFF1AA1291E23663FE372CC2CC5D7225815156F508C359F3150C53611D604F6FED77F23478EEC34ACC4AB32F5F5F5F92B3711E8BB1BD8E34D79975F7E79DEB3312B196BD5CF38E38CBC4F63A94DCCDCC72B43455F7DFFFBDFCF7BB6ABF01421A9787F4684A798B18F571063C942DC1E4F36E2F2BBDFFDEE5705AD78921B6B7CE33E628DF2CF7FFEF3FC6762F6B4B7FB2F3E5932EDC70BD3F16F4D7CED2F9F34D95F027BF4502C55898A27803B06F678552766D9FFFCCFFF3C5F0213CBAE8A37EED7621FE9BF6E85FA9AF9A4D3F4C468AB4F3A654F66D85F9706C82D718686BEB46CD9B23B5203B7C5EF2330ED594560890122DE741AB34511AA8B99D098ED89977C63BB58EA920ECCD905175C9007F618C862608A3307C5CFFFEDDFFE6D1E8E6EBAE9A67CFB9885FAD8C73E962F75281E2396B9C4AC41ACFD8C50BFE3EF1241FDA8A38ECABFFFE33FFEE37C265E60EF7FFD17E1E5CA2BAFCCC3755111A28B2531F14431FA67E9D2A5DD0AECB17D2CD18A7AFBDBDF9EF75BF44804F658D71E67A628027BCC4C46E8F9F18F7F9CCFA21715FD17AF1A45388A1E2C9E14EEEACC68AC338E650DC5D288BDB1867D67C763FDD7F3813D82781CE7A2E238B463608F801EE13BBE8FDBE3CDCFD521BCD6FA48FFEDBA934F3EF9D0942DB6144139968AF68578DCAAB0BE257E2F09946E1B3366CCAD3123D097FEF11FFF715A6AE22B05A69E0BECB13C25027BCC1815CB6422FC14813D2AD62217813DC2751C5462D6334276BCA12A5EDE2DCEF012670A89801FE12A6654E33162194384F5EA59A6A262362A1E2F02565C8E3015B3EDB17C4160EF7FFD17EF7738FCF0C3F399F098A98C505204F6B83DD6FAC63AE0EE04F6E2FD1631611033EA717FD1B371D6A25842106F0A2C027B2CF7DA59702A6AF8F0E1DB82569C7D26FA2DDE0C1BB74D9B362DBF5C3D33FA939FFC247FB375BC51BBABB37BF4D4598EF45FED2E8989BF711CF7E272BCE1BE3AB0D75A1FE9BF6ECFB2CF28C2724C3CF48578DCAAC03E43F264779F81FEFE8811235E8C376CF58575EBD6DD9B1A7875FC1E06AC9E0BEC11CC23BCC4A012CB15A2FEE22FFEA2CBC05E049E52A9B46D594DAC192EB65DB972E5B6D014616DBF8EF5996F7DEB5BF341ADFADCEFF1043096C0C4291DAB7FB718D06226B5B337231AB06A3FB0DF72CB2DDBD6F916813DCEF212EBCDA30F22A07437B01F73CC31F913C3787527C24DBC792FDEFC1CFD1333E8B1EC26C24E1C9F9E7DF6D9ECBBDFFD6EBE8421965BC5E5E8CBB8BF786218978B379EEEC9DAE31D83569C2AB5B327A5FA6FE004F6B82DCE977ED04107E567282AFAB316FB48FF754FDAEF9F29C2722C09DDDBB3ECF178F5F5F5DB96C3C4EF2379B2DB9A9A9AAE8B77B4F785F4D8D35313371BB07AA6FEF55FFF351F20E2C014213D5EA68D0129CEF011B3E65D05F678B35FAC7B8F99A2787361DC47CCA4C77AF772B99C0F44710AC8F83715A7438B25313100C6CC792C6188F31647C88A59F758D65084A7EA0F16F9D4A73E95CF42C5DA780356FF0AECD12FB164A558F31B813D4E131A4F04E3159A08CC3B0BECF1C133C529228BA52BF14A502C4988F745C4A9F1E24C1CEF7DEF7BF32777D153F158B174A6B88F0852EF7AD7BBF26DE2FEE2E7F7EB3873C78E9FEA988E2DF9AC669C273BB6B9EFBEFBF2CBF1FF61F6ECD9DB9E884E983021EFEFB83DFE9DF12A529C62B2986D8DC72A4EF5A7FFFA4F60DFD5D33A56DF1E7FE7B82E8E95B5DA47FA6FB766D9EF2E0273BC12B837C5E355CDAEDF2D71B247EAEAEADE366CD8B017F6F6794AE7CD9B174B6156C7E31BB07AEEE3A7239C1733A1F1A6C0F83ECEEAB15FC7DAF4CE027BBCF934CE8B1DA13CCECF1E813A96C044908FC12D3E842996CB5C74D145F9FD44C02A66D563808A812996CDC44B7F11EA5E78E1854E7FBF75EBD6E561AC581B6FC0EA3F81FD0B5FF8421ECC63F9CB8E4B628ADA59608F3734C76DC5FB1A8A8A401E4B6D626D7CBC22144FF6E2BAF874C678D258F473F52C7DDC573C21DDAFE3FCD911F6BBFADD8B50FFC0030FBCEAB698B12FFE5FC4D29B786375FC1BE35CDA7196A4A2D78B4FB0D47FFD27B0F774D54A1FE9BFEE4BE3E0D1296BB417C139FE467B433C4E55586F8FDF43E2648FA581F78434006E8A40B537AC5EBD7A4E6AE0A7537DD180D53B1501BAF844C93847765CAEBE3D668C62963C66D6231C151F135FDC1E01BEFA0D58C52CF9C30F3F9C07EFFE36E00A4CBB5F11928B4F128DD9C4E897E8A7A26F8A8A6DA23FAA974855F753CCC27776FFC5AB31316BBEE3AC7C57BF532C3788B375EC6C9BA2F7E30968671F0F1F33A5C5FF8BCE7EE778F37667D7EBBF7D2FB0D74A1FE9BFDD3364C89029D54B63E289576F8AFBAF5E0A138F2F69D263468C183161ECD8B12FC47FEEDE940E5C0BD37F98FB52337FD580A50C58FA4FFFE93FA5FF7AD3B061C3DE9082F38345808EF778F556688FFB4D8FD75E35BBFE603CBE94498F3AEDB4D3AE193D7AF4F3BD35D3BE7AF5EADB22ACA706FEAE014B19B0F49FFED37F4AFFED0D29771C9EEA99EA99F638FB4F4F8AFBAB9E59EF78BCC3A54B7AC5D0A1432F1A3162C4869E5ED3DEB1667DE9409F59376019B0F49FD27FFA4FFFD59E943FDE5F1DDA8B37A2EEE9D963E2E7777883691ED6E3F1EC757AFB99E8174F39E59475575C71C58A58B3B7279E7FFEF97B3ACE06B37A20AF59376019B0F49FD27FFA4FFFF58B99F607ABC375CCB6C74913E27D5CDDFCE0C7FCE7769855CF3AEEDFCC3A7BED99E86171CAC5534F3D75FD55575DF5E49A356B5EEA461FBFB47CF9F23B264C9830AD23A837C7FD19B094014BFFE93FFDA7F45F5F8A35E51D6F44DD3168678D8D8DF979F5E34DED7106AA78B37C88AF7139AE8FDB1B1A1A5EF5B3717F71BFD6ACD327E2438DE2934853E05E7DE699673E3D75EAD407E6CE9DBBE0B1C71E5BBA76EDDA5FA63EDEB87AF5EAA71E7DF4D179E9A030EB924B2E99917E6641FA9995F17303F143910C58062CFDA7F49FFED37FFD7E62F2E8EAF3B4EF61DDEDD48DD48AFD070F1EFCA9D490DF4ACF2067A6E6BCB76A2D587CBD37AE8FDB63BBD87E5FDE59062C0396FE53FA4FE9BF7E11DC3F9B32CC8C545BBA19D263FB19F1F3F62218B094014BFFE93FFDA7F45F2F1B366CD82129809F3864C89052FADA9A6A71AA173AC2F90B1D975B3B6E3F31B6B7D7C080A50C58FA4FFFE93FA5FF000C58062CFDA7F49FFED37F0002BB3260E93FFDA7FF94FE033060290396FED37FFA4F09EC00062C0396FE53FA4FFFE93F0003963260E93FFDA7FF94FE03306019B0F49FD27FFA4FFF0108ECCA80A5FFF49FFE53FA0FC080A50C58FA4FFFE93F25B00318B00C58FA4FE93FFDA7FF000C58CA80A5FFF49FFE53FA0FC08065C0D27F4AFFE93FFD0720B02B0396FED37FFA4FE93F0003963260E93FFDA7FF94C00E60C03260E93FA5FFF49FFE033060290396FED37FFA4FE93F000396014BFF29FDA7FFF41FC0BEA9B5B575EBA64D9B0C163550E9EFB0220D589BF59FD27FFA4FFF01B0CDDCB97357AC5AB5CA805103F5F4D34FFF280D58F7EA3FA5FFF49FFE03609B72B9FCA5DB6EBB6D7D5B5BDB5A334D7D36B3D4B664C9926969B05A9AEA78FDA7F49FFEEB4EAD58B142FF010C7471908C998D545B620D617FAB6BAEB9263BE9A493B2FEF8BB77D4968EFD7FBCFE9B9529FDA7FF76BDEEBAEBAE6CD2A449D98C1933F41F00B52B85F54A04767B02D897645976D0FAF5EB37AD5DBB361B3162C4ADF60800B51AD6074558EFA841F608B0AF78E289276ECA3A94CBE535F5F5F583ED15006A31B057AA027BC51E01F6058B172F3EB6BDBDBDC8EBD9D6AD5BDBC78D1BB7AAAEAEEE607B07805A0AEBD5B3EB66D9817D42CAE707AC5AB56A75B683B86EE8D0A157D84300D45260AF7412D8CDB20303DAA2458B2ECDBA306DDAB4E7870C197294BD04402D84F5CE66D7CDB203035A5B5BDB119B376F6EEF2AB0BFFCF2CB2F8C1C3972E1A041830EB4B700E8EBC05ED9496037CB0E0C484B972E7D247B0D0B172E5C595F5F7FA1BD05405F86F59DCDAE9B650706A4BABABA03E6CF9FBFE5B502FB73CF3D777B3A06AE89EDED3500FA2AB0577621B09B6507069C71E3C67D63CB962D2FED24AF6F686A6A2A9B6107A01643BC0F4E0206BC589B3E7DFAF4E55DA5F579F3E65D958E870F59C30E80C00ED047860F1F7ECC92254B5EDC31ACB7B7B73F3074E8D065CE120380C00ED0C7264E9C78FDD6A4FA0431715D3A165E6EEF0020B003F4B1F844D359B3666D2CD27A5B5BDB8FD27170994F3A05406007A8110D0D0DA7AD5BB7EEC5B56BD766A79F7EFAC3F5F5F583ED15000476801A3275EAD4FB274D9A1467C6BAD9DE00406007A83175757547C6F12FBEDA1B0008EC008E7F0060C00270FC03C08005E0F80700062C00C73F003060018E7F0060C062DF5377DD75075C30A972D86B6E9865FB9F5FBAF9CDC5C5AF4CA91C64EFE1F80700062C7A59D3BFB4BEA3B1549919DF3736972F6E2C957F525D4DCD95CFE5B7B55406353597FFA3F8B98652EBFCC6C9B38F1E7BE5AC83C78FAF1C684FE2F8078001CB80450F1B33A5F2F68696F25F37B694E78C6CAE7C2805F4D6B83CAA54FE6851E75C7EFBA1AF04F6F25529B49F10DF8F6A2E1FD7586A5D94B6BF31D5C674DBA7EC4D1CFF00306019B0E8610DA5F269A9EE4AA17B6D434B654653A93C7B54A97254E3A59523A22E98DCFAAED82E96BFA480BEA06172E50B0DCDE52969FBC7F26D26CF3E3A42BE3D89E31F0018B0E825D54B6222B0A7607EFD2BB3E9A94AE535F9F52D958614EC7F11B3EA0DA5D633D3F51B1A5ACA3745D08FC09E6AB93D89E31F00062C0316BD205F0AD3527E325FAF9E027B04F8E2B658A7FE4AA8BFE52DE9FBF3D2EDDF8ECB69DBFBF2AF2DE539D597C1F10F000316F4A014B8C735962A77C6B29858F6F2CA0C7BF97BE96B7354FA7E656C777EA9F5DD699BB6A652EB3F35B5949BD2F50FC5AC7CFABAB4E3EB127B13C73F000C58062C7AC176678989E52D2D95410D9795DF1735B279CE7BE3FA91CDADC7343657CE6DB86CF647E2D48E3BCEA89FD732E7C8B4FD27ED4D1CFF003060410F6B689EF5CEEA35EC4DA5D64F8C9A32E7F0A21A2FAD1CD234A5F29E14E4BF9EBF41B5B9F5B2582A13CB648AFB4861FEA274DB487B13C73F000C58D0834695E67CACB1547E30C2F82BC13B3F0FFB8FABABA15439ABB1A5F5F329D40F8DF0DEB1DD57D36DF714CB69D2F7D3CE9D3CFBADF6288E7F0018B0001CFF00C08005E0F80700062C00C73F000C58008E7F0060C00270FC03C080652F008E7F0060C00270FC0300031680E31F00036CC0524AA97DB58C0200000000000000000000000000000000000000000000000000000C58FF03917BBCBB083969330000000049454E44AE426082, 1); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('1d1dbf35-1c51-11ec-94ee-5ef70686b817', 1, 'flowSubmit.bpmn', '1d1dbf34-1c51-11ec-94ee-5ef70686b817', 0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C646566696E6974696F6E7320786D6C6E733D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A7873693D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612D696E7374616E63652220786D6C6E733A7873643D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612220786D6C6E733A666C6F7761626C653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E2220786D6C6E733A62706D6E64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F44492220786D6C6E733A6F6D6764633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A6F6D6764693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A62706D6E323D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A64633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220747970654C616E67756167653D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D61222065787072657373696F6E4C616E67756167653D22687474703A2F2F7777772E77332E6F72672F313939392F585061746822207461726765744E616D6573706163653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E222069643D226469616772616D5F666C6F775375626D697422207873693A736368656D614C6F636174696F6E3D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2042504D4E32302E787364223E0A20203C70726F636573732069643D22666C6F775375626D697422206E616D653D22E68AA5E99480E794B3E8AFB72220697345786563757461626C653D2274727565223E0A202020203C657874656E73696F6E456C656D656E74733E0A2020202020203C666C6F7761626C653A657865637574696F6E4C697374656E6572206576656E743D22656E642220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E557064617465466C6F775374617475734C697374656E6572223E3C2F666C6F7761626C653A657865637574696F6E4C697374656E65723E0A202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C73746172744576656E742069643D224576656E745F31376E32727739223E3C2F73746172744576656E743E0A202020203C757365725461736B2069643D2241637469766974795F30336B6A75727422206E616D653D22E68AA5E99480E58D95E5BD95E585A52220666C6F7761626C653A61737369676E65653D22247B7374617274557365724E616D657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934373637353034313130373936382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A66616C73652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383833353236373622206C6162656C3D22E68F90E4BAA42220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30306C647661672220736F757263655265663D224576656E745F31376E3272773922207461726765745265663D2241637469766974795F30336B6A757274223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3079777866777522206E616D653D22E983A8E997A8E9A286E5AFBCE5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22247B64657074506F73744C65616465727D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934373637353034313130373936382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550545F504F53545F4C45414445522671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A7461736B4C697374656E6572206576656E743D226372656174652220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E44657074506F73744C65616465724C697374656E6572223E3C2F666C6F7761626C653A7461736B4C697374656E65723E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383833373230303322206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383833373538363622206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E0A202020202020202020203C666C6F7761626C653A666F726D5661726961626C652069643D2231343430393637353831363733343539373132223E3C2F666C6F7761626C653A666F726D5661726961626C653E0A20202020202020203C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F307839647832742220736F757263655265663D2241637469766974795F30336B6A75727422207461726765745265663D2241637469766974795F30797778667775223E3C2F73657175656E6365466C6F773E0A202020203C6578636C7573697665476174657761792069643D22476174657761795F3137397A676E70223E3C2F6578636C7573697665476174657761793E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3138703368716222206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F3079777866777522207461726765745265663D22476174657761795F3137397A676E70223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C656E644576656E742069643D224576656E745F306E766A786768223E3C2F656E644576656E743E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31716967616B7222206E616D653D22E68AA5E99480E98791E9A29DE5B08FE4BA8E313030302220736F757263655265663D22476174657761795F3137397A676E7022207461726765745265663D224576656E745F306E766A786768223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B746F74616C416D6F756E74203C3D20313030307D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3071617934387522206E616D653D22E680BBE7BB8FE79086E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303931313431303538313231333431362220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934373637353034313130373936382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383835333637373122206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383835343030383122206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F303538636D736222206E616D653D22E68AA5E99480E98791E9A29DE5A4A7E4BA8E313030302220736F757263655265663D22476174657761795F3137397A676E7022207461726765745265663D2241637469766974795F30716179343875223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B746F74616C416D6F756E74203E20313030307D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3079637838666222206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F3071617934387522207461726765745265663D224576656E745F306E766A786768223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31686D61796B6822206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F3079777866777522207461726765745265663D2241637469766974795F30336B6A757274223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30396237756E7222206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F3071617934387522207461726765745265663D2241637469766974795F30336B6A757274223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A20203C2F70726F636573733E0A20203C62706D6E64693A42504D4E4469616772616D2069643D2242504D4E4469616772616D5F666C6F775375626D6974223E0A202020203C62706D6E64693A42504D4E506C616E652062706D6E456C656D656E743D22666C6F775375626D6974222069643D2242504D4E506C616E655F666C6F775375626D6974223E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F31376E32727739222069643D2242504D4E53686170655F4576656E745F31376E32727739223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223130322E302220793D223239322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30336B6A757274222069643D2242504D4E53686170655F41637469766974795F30336B6A757274223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223139302E302220793D223237302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30797778667775222069643D2242504D4E53686170655F41637469766974795F30797778667775223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223335302E302220793D223237302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F3137397A676E70222069643D2242504D4E53686170655F476174657761795F3137397A676E70223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D223531352E302220793D223238352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F306E766A786768222069643D2242504D4E53686170655F4576656E745F306E766A786768223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223933322E302220793D223239322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30716179343875222069643D2242504D4E53686170655F41637469766974795F30716179343875223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223730302E302220793D223337302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30396237756E72222069643D2242504D4E456467655F466C6F775F30396237756E72223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223735302E302220793D223435302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223735302E302220793D223530302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223530302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223335302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223438342E302220793D223438322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31686D61796B68222069643D2242504D4E456467655F466C6F775F31686D61796B68223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223430302E302220793D223237302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223430302E302220793D223234302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223234302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223237302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223330392E302220793D223232322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30796378386662222069643D2242504D4E456467655F466C6F775F30796378386662223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223830302E302220793D223431302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223935302E302220793D223431302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223935302E302220793D223332382E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D223836342E302220793D223339322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F303538636D7362222069643D2242504D4E456467655F466C6F775F303538636D7362223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223534302E302220793D223333352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223534302E302220793D223431302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223730302E302220793D223431302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2239302E302220783D223537352E302220793D223338332E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31716967616B72222069643D2242504D4E456467655F466C6F775F31716967616B72223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223536352E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223933322E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2239302E302220783D223730342E302220793D223239322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31387033687162222069643D2242504D4E456467655F466C6F775F31387033687162223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223435302E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223531352E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D223437312E302220793D223239322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30783964783274222069643D2242504D4E456467655F466C6F775F30783964783274223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223239302E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223335302E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30306C64766167222069643D2242504D4E456467655F466C6F775F30306C64766167223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223133382E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223139302E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A202020203C2F62706D6E64693A42504D4E506C616E653E0A20203C2F62706D6E64693A42504D4E4469616772616D3E0A3C2F646566696E6974696F6E733E, 0); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('1d2ba1e6-1c51-11ec-94ee-5ef70686b817', 1, 'flowSubmit.flowSubmit.png', '1d1dbf34-1c51-11ec-94ee-5ef70686b817', 0x89504E470D0A1A0A0000000D49484452000003D2000001FE0806000000706236BA000041BD4944415478DAEDDD09981C659D3F702EEF83435C595714165DEF733D38D63FB3EB0928A0CB10270104C2722733138EA8180D2CAB1B8D24D3934070552E891C1A578E0824DD4DC20DE18620E10A2127444208920448EAFFFE6AA6673B93999C93648ECFE779DE67BAABAA8FA97EBBDEFAF6FB56D5565B010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000BD4CED15576C7BCAC8F2CE6B5D30CBB61E5498F8F6CADD13C796DF6AED010000D0E7349E53FC878642F9AAB8DDD0543AABA150FA5375696C2A7F3D9FD75CAE696C2AFDBEF2B8FA42F19E863193F71A7AFEA4ED870F2F6F674D020000D0EB9D36B6BC4B7D73E96B0DCDA529839BCA1F4BC1B918F787144A9FAC9413CEBD69C796205DBA3085E983E3F690A6D2FE0D85E28CB4FC35A92C49F3F6B136010000E8F5EA0BA52352B92D85E185F5CDE5098D85D2E42185F29E0DA3CABB4539654CF17DB15C0CE34EC1F981FA31E56FD43795C6A6E51FCD97193379AF08DFD6240000007D46F5D0EE08D229305FD9D2FB9C4AA1F45C3EBDB95C9F02F723D10B5D5F28FE479AFE627D73E9DA08E011A45399634D020000D027E443BA9B4B4FE4C743A7201DC1BA322F8E836E09DBD7ED946E9F9CE6FF2CEEA765EFCAFF3697A654DF070000805E2D05E1610D85F2AD31BC3B866FB7F448977E9DFE364549B7E7C772830AC53DD232F31A0BC5FF6E6C2E35A6E9F7472F76FA3BABF5EF4C6B130000803E6195B376C730EDE6724DFDE8D207A30C6E9AF281983EB8A9B8774353F9A4FAD1933F1197C06ADF037D72F394DDD3F25FB036010000E8F5EA9B26BDB7FA18E9C642F1F343C64ED9B5521A469577681C5B7E7F0AD83FCE4F4CD6541C1D43BE63B877E53952C83E23CD1B6C6D020000D0AB0D294CF97443A1745F84E496409C5F47FA7FAB4B7DA17C5C437371BF14B60744A86E5DEEFB69DE1D9561E1E9F6F893C64C7E87350A0000000000000000000000000000000000000000000000000000000000000000006BF19DEF7C2753942D597C0B0100801E17A4AD05D43F0000004106F50F0000409041FD030000106450FF000000041950FF0000004106D43F00004090B11650FF0000000419D43F0000004106F50F0000409041FD030000106440FD030000041950FF00000041C65A40FD0300001064E8E666CC9871ECC89123B3DADADADDAD0D000040908635C8B2ECAD8B172F5EBA70E1C26CE0C081D75B23000080200D6BF0F8E38F5F9BB52A954ACFD5D5D51D6AAD000000823474E0A9A79EDA77C58A15951C9DAD5CB972C5B061C316D4D6D66E6FED00000082345449B979DB050B163C9BB513D3060C18709E3504000008D25065C68C19A3B24E8C1F3FFE857EFDFAED692D010000DD2934972338AFA594AD29368579F3E6EDB66CD9B2159D05E9D75E7BEDE5C183074FAFA9A9D9CEDA020000BA4B90AE5987205D634DB129CC9A35EBA16C2DA64F9F3EBFAEAEEE746B0B0000E84E61BAAC379ACDADB6B676DB7BEEB967F9DA82F4F3CF3F7F53AA87CFC5F2D61A0000D05D82748DDE68B68461C386FDD7F2E5CB5F5D438E7EB1B1B1B1A4471A0000E88E61BAAC379ACD2D8E7DBEFCF2CBE77496A2A74D9B7661AA87F73B461A0000E88E41BA466F345BC251471DB5F7CC99335F691FA257AC5871EF800103663B6B370000D09DC374596F345BC2881123AE5C99549FB03BA6A57A78AEB503000074E7205DA3379A2DA1B6B676FB4993262DA9A4E879F3E65D96EAE0EC986EED000000DD3D4CE7BDD2D6049B5B7D7DFD118B162D7A65E1C285D9D1471FFD605D5DDDA1D60A0000D01382748D20CD96326EDCB8BB478E1C192322265A1B0000D0076459F6FA279F7CF28ADB6EBBED9562B1984D9A34A9479608D23DF5BDA7F5BE72EAD4A9734BA5D241EA5FCFFBFC264C9890D7BFF8ABFE0100401F9042CC9569273A5BB06041B674E9D26CF9F2E5CA662EB1DE63FDDF78E38D8B53B03940FDEB7965EEDCB9EA1F0000F415D113183BD102ED962FF3E6CD5B9882CC9DEA9FA2FE0100403716C369F544779F9EC1146496A97F8AFA070000DD581C232944749F129F87FAA7A87F0000D00B82CC4B2FCCCB9EBCEB82ECE1C967E5256EC734E1439051FFD43F000010A4DB95258BE6640F5D3F2CBBFFDAD35629312DE60920828CFAA7FE0100802053559E79F8AAD5424CA5CC7EF86A01449051FFD43F00001064AACB23E5119D06999827800832EA9FFA070000824C557968D2F04E834CCC13400419F54FFD0300004146901164D43FF50F0000D8B020136749EE2CC8C43C01449051FFD43F00001064AACA63B78CE934C8C43C01449051FFD43F00001064AACA5FE73C903D74C38F571F569BA6C53C01449051FFD43F00001064DA95A7A65DBC5A908969C28720A3FEA97FACB7375B050000BD3DC82C5B963D76EB79AB0FAB4DD3629E0022C8A87FEA1FEB6CDF5416B4FE0500A0370699258BE664336E69EEF418D59817CB0821828CFAA7FEB1CE21FA54611A00A037069965CBB2798F95B207AFFB41A721A65262995856EFA020A3FEA97FAC3544EFDBC97D00007A7290595B2FA0DE414146FD53FFD8A810BDB6E90000F4B420B32EBD806BEA1D14480419F54FFD639DC3B2300D00D01B82CC8686984A11480419F54FFD63BD42B2300D00D0D3838C22C8A87FEA1F9B2D440BD3006C90238F3C7287EF7CE73B87F4EBD7AF90FE1653792A959753C95AFFC6FD62EBFC4362796B8D4E2D5EBC78A7ABAEBAEAAC3163C6DC7FE699672E1C3A74E8D2134E38616554A8E38F3FFED5534F3DF5C533CE3863D659679D75F569A79DF6F5F490AD056901429051FF94EE55FF1AC796DFDF78CEAD6FEA23215A9866CBCAB2AD4F3DEFFABF5BEBF7327D276BAFB862DBEA69830A13DFBEA6EFEAB1E74F7B5D94CEE6378C2AEFE60380F5535757F795946D26A4B2BC3534AF6B89E527C4E3AD45DADC71C71DC78F1E3D7ACE71C71D97A5F09C5D79E595D9DD77DF9D3DF1C413D95FFFFAD72CC4DFB81FD363FEE9A79FBE72E0C081CB53A0BEBE7FFFFEFF28482B828CFAA7FE75AD13C796DF5A5F28FD794D25968965D3EDC18DCDC5EF4569682E4E6F28942E6ABB5F2836F4F2102D4CB3C5B47E4F6FCBC37273A9317DF7FE5455CE6D0BBD4DC5D10D4DE563F2DB85625DC3A8291F6E682A9DD5D854FC567A5CFFFAD1C5FFB76A489EFAF769B907A2B40FEAC32F28BF715061EA3BD3F33F34A830F9238DE75CB75363A1DC5CDF5C9E5029E9B987B47FAFF11AE931E33A0CE585E2FF74BAAD692A9DD359D06F3F6DF8F0E1DB74B4ECFA4E874D10A0F74A41F8F6F50CCF9D95DBE3F9ACD53EEC81071ED8FFDC73CF9D7BECB1C7667FF8C31FB2E79E7B2E5B1FB17C3C2E05EA571A1B1BAF48156A67414611A4D53FF5AF6B9C70EE4D3B363497EE6D6C9EF2F18E4ACC8B655A76824B07B4ECC4A71DEFE6F2C17929941E4BF74F88797D20440BD36C76A78D2DEF92BE87FBC4F7AE714CE9A329145F32A4A9B47FFDE8D207F3A09C826E4B58BCE2F5E9F6B3F123577DA1784F6353E9A074FFF296205DFE4E4C3F6564B96D1F2A4695A4F90F3614CA874489C7D4374D7A6F5B206E2E0F4CF3EF48C1FC8614A0AF48EFE189FC316326EF9596BF33C2F5C9CD37BCBBFDFB6D2C94F68DC0DCD1FF928F64A96C5B9A8AA746E0AEDC1F5428EED17EF9F83FD3F34D6E9B90655BC70F07A9CC4CEF6162FC10B041D3A18B1D79E4916FECD7AFDFD8147E57B60FC40D0D0DD9A5975EBAC60EC4981FCB7510A657C6F3C6F35BCB7D48AA1FDB4E9C38F1AA08D0175D7451B664C9926C63C4E3E37952457AF9B0C30E3B5890510469F54FFDEBA2205D28DD1C3D4BB1C3BC6AC977746F8E65D24EF9A1F98E74A1F4649A362B6EB796D995DBB1B3DE0742B430CD669502ED61E9FB35257DEF1647A08D207D4A73F94351EA0BA5D3E2BBDAB25CE9DF5380FD63E571D1A39CCF6F2EFF3C7D9707A5EFF0B1C38797B78BC09D42F30FE3F9E231F5A327BF2B2FCDE57E69DA0BE9F9CE185498F8863C6037954644801FDC54FA5204DAD826A4BFD3D2727F4DE5A62185F29E2D217EF836117ADB07E978AE63CFBFFACD1D86EAD8A6A490DFD1BCBC07BEA9744E7A8D2CDE7F657A7ABE93D2B4EBE2F5D263BFDFD85CAEDF90E9D09552D8DDB5AEAEEEFEEA00DCBF7FFFECFCF3CFCF66CF9EBD5E7927968FC7C5E3DB05EAFBE275ACEDBE11A277B8E4924B669C74D249D9934F3E9975A578BE14CE970E1C38F04C414611A4D53FF5AF6B8274F47A450FD7AA65F2BB2A413ADF296DE9FDFA6DDA49BEA0BAC48E7DF44EF5A1102D4CB359AD32B4BB3548470F6E0CD7AE1CFFDCFAC3D7C5A95C9FC2EC2F1B9B8BC7A7DBF7A5C0FAFB28E9F6D30D638A9F490179403E04BCB9F49378AEBCD7B950BE336ED737957F1A01364275F45EA779F7A7E76A4AE5E1FA31E56FA4C79C9F96F997F4BA27A6F7F3A398D6129E277FB1D273BC4A908EC33F52806FD97E947738B979CAEE9592C2FCC969FE98EA69B14CEB8F07035B427CE9E608F4AD3B975BB7FC9837F98BAD3F1C1C183F2CACF774E84229407F289539D5A177C48811D933CF3CB35179271E1FCFD32E4C3F13AF67ADF7F2105D281416FDF0873FCC162D5A946D0AF1BC43870E7DF988238EB85890510469F54FFDDBF8207DFA889BDF96FECE4D3BAD57B594743BEDD4AE12A49B8BFF960FFF2C14475697B4CCDD31AF8F8568619ACD66C8D829BBC677328E4BCEC36FCB390AFE92CA3529D0CEAB5E36C2731E68F3205DBC32026B6B68BD2B82741E2A47973E58E9D54EA17A787ABEB32BF7A3B43C4FB12E7A70D3E3E6A7DB33F26D440AD269DA67631B11BDDDFF17A44B4D117EDB07E9FAD1933F57197ADE1AC42FAC2AD1CB7EFF2AD3DA1D2292EE3F33A8507E4FDCCEDF6BA1F474DBBCA6D290F45A3F5BDFE96A135DA5B5277A4E752FF455575DD5A599279EAF5DEFF4337AA67B6F88DEF6924B2E792C4274ECF46D4AF1FCA79E7AEA0B03060C384390510469F54FFDDBB8201D67F64D3BC753AB7660CB9579D5413AEDECDE9E7646CFAC2E798F56F70CD2D52137AE00F1DDAD36FE4A101D3D8F30CD26535F280F4DA514BDC2D1331D41BAB150FC6A0CB98E137B3536957E9587EDA6C9FF9A1F075C28BD147FF31FB99A4B8508B679B88DC3355A8374F4F6E63DCF51D273E7251F4A5D1E158F6BD906948FCC7BAA53988EC336A2473C827984DDE869AE04E938AE3A3FC4A3B537B9FD31D2B17D18DC54DCBBFDFFB5A6A1DD2102747AEC9CB6E50BC56FC60F07D5DBA8788EF59DAE46D115E298E5EAE1DC471D755476EFBDF76E92CC13CF1BCF5F3DCCDB31D3BD501C137DF2C9276FB29EE88E7AA68F39E6981753853A5090510469F54FFDDBD8209DF73CB50ED92ECD6F1FA4E3ACDD0DCDE59A384B777E06EF42A96970D3940FA410BD5F1CC7D9CD43F4AFE3F7DED6BF1B1AA6D7F43CC2349B4C4743BB53F01D9BF7528F9EFC89EA6557ED912EDDDF127EF300FC742548E7C70C174A37C619B1F3E59A8A835A4F567677E52CD979682F946E8930DE12D08B0D11EAF31EECA6F249295C7FB7E52468A55FC450EFFF0BBCED827453F1F0184ABEBE413A9F5F28FDA1ED078596C07E7BFEDED336A7727B7DA7AB4D7485D6138BB5F5446FAA105D1DA6AB7BA6E3F57D0ABD48FA800F88138B75F531D1EB72CCF461871DB6A8B6B6F69D828C2248AB7FEADF8605E97C87378672579538C6308672E7CBE4C756966E8AE3326387F4D49F5FFF96FAA6F279F563267F253FDE32EDB0C730CE6E18A2C3775BC36FB61161BA3A4457CA116B795DE81271E9A9EA20DD3A64FAF2BC273805DB388958CB72B7BE290FCC79F82D5E1001B92A60FF21BEC71194F3EF782CD3543E26863CB7F67A1F1797B78A7995301DDB8638B6388EA78E20DD32ACBBF4682C1B97DE6AB944D6C4375407D4F8512D8ED1AEDC6FB94EF5EA271C8BF01D235A3AFB9FA3773CBDEEE9AB3C26DE5FA13823027FF57919D6773A6C8CD64B5CADA884DAABAFBE7AB3649E789DAA5EE9152E8DD58BC425AEE2ACDA5BC279E79D373755A826414611A4D53FF56FFD0C3D7FD2F6D543BAAB76BA63F8E64311A42350A71DD22F474F53ECB0C759705B8679A69DECF437CED63BA450FA645C16A71B86E8CE42F0FA84E98E1EFFAB4E1E2F4CD3B521BA79CAC7D3F7EC910896ADDFCD8B53B8BDB6A517397D1F9BCB3F8FCBD2B5FE18B65B0CF58EB369C731CB959EE218E21CC754C7F73D4E16966E17D754E2BBDEFAB8EBA2F739EFFD4EA1360269655E7A4F475407E1C65193FF31DE67941856DDF9FF9387F13BE2D25BEDAF6BBD2E2AD7B5DFD8E9B0A1AAAF131D2704DB9CDA9D80EC769F462F70C71D771C1FBDD12FBEF8E21609D2F1BA871F7EF8E2FEFDFBFFA320A308D2EA9FFAD767AD29C46E68985E9F102D4C03F462871E7AE897AB87746FECD9B937E46CDED543BCE3FDF8547AB8D1A347CF99306142B6255D7CF1C54FA40A75BE20A30832EA9FFA2744AF47285E5398DE90102D4C03F452296B4CA884D8B8DEF39610AF5BD52B3DC1A7D283BDF8E28BEF38FEF8E3B3679F7D768B06E9F4FAAFF5EFDF7F416F3B91842023C8A87FCABAD6BF3E7C229DF509ADEB1AA63726440BD300BD4CCA193BA6E0BABC126237776F7475AF7455905E1EEFCBA7D3435D73CD35670E1D3A34EB0E8E39E69899A942EDDD437ED12AA75223C808D2EA9FB2B1F56FFEFCF9BBCF9A35EBA17BEEB967F98F7EF4A39FD4D4D46CD75BEB641785D5B585E9AE08D1C234402F6A83D2FC432A01B6A1A1618B669E78FDAA307D884FB0876A6E6E7EF0CA2BAFEC16417ADCB871F7A5CAF4DF3DE40B5BA9FC6BFCE20A3282B4FAA77456FFD2666FDB1933668C5AB66CD98ACA76302DF7EAE5975F3EE7A8A38EDABB37D6C92E0CA99D85E96DBA30440BD300BDA40D4AD39B2BCBFDF6B7BFDDA299275EBFEA3D37FB047BA833CF3C73E1DD77DFDD2D82F4D4A9531FE8D7AFDF553DEC0BBBC62FAE202348AB7F4A47F5EFA9A79EDA77C182059D1E533373E6CC57468C1871656D6DEDF6BDA94E767138ED284C3FDAC5215A9806E8056D505D5D5DA9327FDAB4695B34F3C4EB57DE4BBC2F9F600F75FAE9A72FDDDCD78EEECCA38F3E1A43BBEFEAA15FD80EBFB8828C20ADFE29D5F52F79DBE38F3F7EED8A152BD6BA4D5C99A4C72C696C6CFC6E6FA9939B20947614A6BB3A440BD3003DBC0D4A7F6755A66FE9EC13AF5FF51E67F9047BA8E38F3F7EE5F3CF3FDF2D82F45FFFFAD725A932CDE9E15FD855BEB8828C20ADFE299572DB6DB7658B172F5EBABEDBC6458B16BD326EDCB8BB6B6B6B77EFE975721385D118CEDDBE27FAD1D6E95D4D9806E8996DD0DF2AF7B774F689D7AFEA917ED127D8431D7EF8E1D9ABAFBEDA2D82747A1F2FAEC317A147954D1D64962D5B96FDE52F7FC9962C59B2D665E34BDBD172F1F8975E7AA9C3C73CFDF4D3ABDCBFFFFEFBBBE47DC7B5C353A0D8EC41A6B7D5AFCD5DFFE6CE9D9B3DF2C823EBB4ECF4E9D3B3A54B97AED3B2B367CFCEAF1CB0A93EF7050B16E421B6B3F9CF3DF75CF6F0C30FE7B767CE9C99BDF0C20BF97B5FD7EFD6BAAEBB912347660B172E5CEF6D633C261EDBD3EB636D6D6DF6C637BE3142EEA95DD88CADA9477A5DAE33BD214EED6BDB12455194DE54B674F689D7AF7A3FAF49A43DD471C71DF76A77E9914E3BB38FF7821EE9CD3AB4360269EC3096CBE5EC8F7FFC63F6F18F7F7C95F2C52F7EB16DD9F459E7D362A73C42C3A04183621440FEF82953A664C71E7B6C76C30D37AC12A2DFF296B764BFFCE52FF3FB575F7D75B6F5D65B67F7DC73CF2AEF218EF378FFFBDFDF61193B766C87EF7BDF7DF7CDBEFAD5AF761AE0F54877AFFA376FDEBCECA69B6ECA0E3EF8E0BC0EC5ED28C3860DCB3EF2918FB4954B2EB9245F3E2EEDF0E637BF39FBC94F7E92D7B5AF7CE52BAB955826968DE14D3BEEB863F64FFFF44F79DDDC6BAFBD5679CE28CDCDCDF9B23FFFF9CF579B575D2AA1375EF3A73FFD695B39E08003B26DB6D9263BFBECB35799FED8638FE5CB5F7AE9A5D93BDFF9CEFCF6F6DB6F9F5D7EF9E5D99C3973F2EF46D4EFAEAA7F13264C88AB13DC502A959E5BB972E58A75D82CBE96D6FD65471F7DF483E9739DD8437BA4DB0FEDDED4C3BA1FDDC4615A8F34400F6C83A2E7578F345DEA94534E79B1BB1C233D7DFAF4693DF818E9CD7EB2A7E82DFBDFFFFDDF7C6731024604835D76D9250F0551E2FAE0FFF00FFF902F1B81F96D6F7B5BDBCEE5E0C183F3F0D2D4D494DFFFAFFFFAAF6CBBEDB6CB1E7AE8A17CF96BAFBD363F357F84930818713B824E3C7FDC8E505DDD9B17671FBCF0C20B5729EF7EF7BBF3E7EDE8BDDF7AEBAD79D03AEDB4D304E91E50FF2EBEF8E28E7AFBB2238E3822FB977FF997BCFEC5FDABAEBA2A6F1C62F91FFFF8C779EFE31D77DCB14A788DCBEDC5B28F3EFA68DEEB1B3FAA7CE10B5FC8BEF4A52F65071D7450FED85FFFFAD779FD881F77E27625CC9E7AEAA9793D8CC05E5DBEFFFDEFE7CF193F2CC572712582A8CF5FFFFAD73B2DB1FCC48913B3279E78223BFDF4D3B31D76D8212B168B9B344857EA5F6A340F1D366CD882359D6C6CC58A15F7C6C9C6D2E73A3B96EF2D75B20BC3686797B8EAE8ACDD5D15A68568801EDA0639469A2EF7C31FFEF099EE72D6EEC99327177BE059BBB7D8E5872294C4CE7FEC2846483EF0C003B30F7CE003F9BC9FFDEC6779CFDEE73FFFF9FCFEB9E79E9BF7C8C5FB89E1D9B366CDCA4E3AE9A42C7DFEF9E34F3CF1C4AC7FFFFE79E08EE52398BCE73DEFC9A71F76D861F93203060CC8EF47408EF9D5EFE5431FFA508741ABB3201DE517BFF845DEE31DC37A05E9EE5FFF226C9E75D659F9E104FFF66FFF9607DCA38F3E3AAF1F51DFE20797BFFDED6FF98F31F1D9472371DF7DF7ADF63C8F3FFE785B908E1EEBA8BBF1DC31A262A79D76CA3EF8C10F66EF7DEF7BF365E239E376E5FF8820BD55C743785709D2D75F7F7DF6D18F7E347BEAA9A7F212C3BA637E4CAF4CFBE4273F99DD72CB2DD9A851A3B237BCE10DF9688BA8C711A42FBAE8A27C9978CCF0E1C3F3EFD2030F3CD0A5F52FCEC69DBE53E78D1F3FFE85D75E7BEDE5AA4DE18B29BC5F98E6CD4E9FEDB93DF0ACDDEB7AF9ABAEBEF455F589C5D6769D69211AA07706E94EDB2067EDA6CBA59DC4ABBBCB75A4CF3EFBEC093DE83AD2EBB4B3B8398776FFE637BF690BD2119C2374446F60DC1F326448B6EDB6DB661FFEF087F372C51557E48F8BF010013B4ADCAFBCDF08CA1162BEFDED6F675FFBDAD7F279F137EEFFDDDFFD5D5B908EE1DF517FA2073A5EBFBAFCFDDFFF7D1EBE637E1C77DAFEBDC730E178DEE8E116A4BB77FD9B3163467E68C06EBBED967F9EF1B98D1B372E0FD1513EF1894F64279C7042BE6C2548B73FBEBEA3201D3DD95157A2973A868CC7FB8D5EE8CF7DEE7379B88E1F5B5EFFFAD7B78D80883A1D3FE4C4A108B7DF7EFB2A2546397CF6B39FCD7EF7BBDFB50DD75E53E88EE7AEBCA7F643BB637E1C16117FE3C79E18DD11EB6053D4BF7EFDFAED595F5F3F3D99FFFCF3CFDF94BEABD1D0DF1FD37B639DEC8270BAB610BDD52608D34234400F6F835C479A2E977660BF967658577687738DF5EFDFFF815499F6EE4DEB777305E9E821FCE637BF9987E577BDEB5D6D2586625796BDF3CE3BF3E1AEDFFBDEF7F29EC278DCFFFCCFFFE4C7BA964AA5D582740CA18DB0F1831FFC209F178F8BFB31BD12A4FFFCE73F67BBEFBE7BDE7B1D7F23E4C4B2D18B18F7A3A72FFE560F058F1227AC8AF01E0125968970254877DFFA178702741446E358E7BABABAFCC79908DAEB1BA4E3A45EF1A34FD4ABE80D8E63A18F39E6987C74450C198F9EEE181E5EA93F175C7041FEE34F67E138427004EA4A388E1EEE18711343B8637EFC0810F7F7D8638FD582F4DBDFFEF6FC18E6788E3896FAE69B6FCE1F13BDD69BBAFED5D4D46C97D6E3E969FBF75CFC8DFB7DA89AAE4F485DD710DD95615A8806E81D61FB904A788D4E9C2DA9BEBE7E6555903EC4A7D3430D1F3E7C9BB4E3BA3CCE98BB25CD9E3DFB965491E6C5FB1164D6AD9C77DE79794F60EC1C46E8885EBDE8058EE34DFBF5EB979D7CF2C96DC748C790D67DF6D9270FAF71DC7304D8AD5A87CE46088EE5DA07E91872BBE79E7BE6436063DEA73EF5A9FC7E048DEAA1DD31C4FCD39FFE743E9437424C2C1BC3B5E3D7B6D7BDEE7579D86EFFDEE3F5E3B9E2F63FFFF33FE73DD78274F7AD7F319CFBFCF3CFCF436FA544B8AD0CED8E910FD1731C870CAC4F908EE5A35E45891F7D2224475D88201DF538CE545D09D2D1231CA136CE0B10BDCE9512F5EC631FFB581E7EA3AE557E9459D71EE9381EBA52C7F7DB6FBFCD728CF49AB6C77DB4295A97B0BABE21BA2BC2B4100DD04BF4EFDF7FC794359657026C9CF4744B88D7AD0AD1CBE37DF9747AB0D34E3BEDFAE889D992FEF33FFF737CAA4CE70B32EB5EE28CD88D8D8DAB0DED8E634DA347B8A6A6261FD25DE9258C6341A3C73A86CEC650EC785C1CA37AD96597E561A43A4847EFF5AF7EF5ABBC4450DEAAF578E7CAB4EA701167748ED78A30143D93B16C0CD38D105DDDEB5729D13B18E1280251A5573B027E0CCF15A4BB6FFD8BBAB3EBAEBBE63DC7716C7E84CE4A908EF9714CF2881123D62B48572E93153FE4C58F41F17CF103D0FEFBEF9F0FA98EB3C85782749CD86C4DC1B8528E3AEAA8B6201D27D48B7A1527418B79E3C78FCFEF57F748FFE94F7FCABEFCE52F673BEFBC73A767EDEEAAB3CBF7B5FAD785617A4343F4C68469211AA0974959634225C44607C19610AF5B15A427F8547AFE2F34FF3870E0C0576298F096B068D1A23B53457A36DE8720B3F1C74847EF61E5E45F77DD75D72ACBBFE94D6FCA43450CAD8EF9D193173D7F7152B24A908E701D41A9522A67FB8EBFD5D363B978CEF9F3E7B7859C08575BB51E5FFA8E77BC230F33F17EAA2FFF1343B9E3D257D5EF2B824CF4487674722A41BAFB04E9EBAEBB2EBF1D61B712A4E3ACDB713C737CDE1140D73748EFBDF7DEF9C88818861DE1357EF0893378473D891EE7183E1E6136EA7A9C0C2F7EC8891392451D8EFB51FFE2F9E28799B85F39E1D8C61C23DD3E481F7AE8A11DFE28A4FE6DB630FDDD8D08D16B0AD34708D1007D476ACFBF5C09B17192DDCDDD2B1DAF575757D736AC3BDE8F4FA517686C6CBC22CE54BB25A4D7BE3C55A6264166FD4A5C33B772AC732548C7B59BE338D308CC31FD5BDFFA561E082ABDD21186E218E7E83D8CF97136E3458B166553A74ECDEFC7E57FE2B25A71F9AB4A89E012F3E27AD2D5D363A86D1C5B1D01245E37FED7E841DCAA7568777D7D7DDED31C413DAEEB1BA1287AA963D86E25EC545F422B869E47AF60F4860BD2DD3348C7B1F831F43A826C25481F72C821D9BFFEEBBFE6C3F523C8AE29482F58B0A0ED525A9521D87122BAA893717C7D5C8A2AEA64FC20143FAE44DD89D78A21E095E78800FEBEF7BD2F5F269E2F1EBF55EB19B9AB5F2B9E27466C446F725C2FBAF2C352DC8F511693274F6EFB21E8CC33CFCCEB71CC8FFF334657C4A5B8E23163C68CC95F2B2E15A7FE6DB1305D1D82372444AFCFF308D100BD58CA1CB757826C8CA4DB9CE2F5AA7AA36FF769F412B5B5B5EF3CF2C8235FDEDCD7559B366D5A0CE97E365E5F9059BF1281337608E3244973E7CECD83741CEB1CC749C709C2E278D238D1578484CA99973FF399CFE4C79D56C24E848D380372DC8E93932D5CB8B0C3EB55C7FCF8DB7E5E5C4A6BD0A041F949A3CE38E38C7CB90844955EE80826114862F8770C658910F6F2CB2F77F8FF44A08FF014215D90EE9E41FA1BDFF8461E98E38798F643BB2B654D413AAEF91CF32AC7C7574A04E5184511C75EC7B0EBF8B125A645BD8EC305E2B25BED7BB5E3B9E20467F17CF1034D84F0CEDE7B256CDF7BEFBDABCDABFC50143F3AC510F2386740FC8FF1A35265A446D4E9F83148FDDBE261FA88AD36FE7AD06B7A1E211AA097ABABABDB2B658F1595401B6DFFE610AF5315A257C4FBF069F4226987F8E0B463BA3402CDE6F0ECB3CF4E4915E9E9540E146436EC0450F1C3C7E2C58BDB7A75A3B72E8E37AD2C133D84D543ABAB1F1B41277AE7E2760496B80670673DDF715C69FC5DD3FB89D77FF0C107F340BCB92E6725C86CBEFA17E1B55207A21737EA4CFC40127FDBD797A8071DD5BBA54B97B65DABBCA3C3142ABDD6ED7BB13B7B4F31DA22CEC2BDA665A244DD8E1F9E3AAAC3F11D88FFA3F2BD683F3FBE5F1D4D57FFB64898EE4DAF07C016D2AF5FBFB1D543BCE387F64D299EBF7A4877BCBE4FA1171A3870E09943870E7D3976FA36A5B4633A3D55DCBB52A5FABE20A308D2EA9FFAC7160CB74234401F72E49147BE3105DAFB2AC1364E54BAA9C2743C6F7ABD1555BDD1F7C5EBFB147AA9238E38E2E2534F3DF5854DD533FDECB3CFDE18213A55A45F09328A20A3FEA97F6CC1902B4403F4412987EC9ACA33D53DD37142DEAE14CF57DD13DDFA7ABB5AFBBDDC800103CE183870E08B5D7DCC74EB31D1B37A7B4FB42023C8A87F8A20DDEDC3AE100DD087A53CF2A1EA305D3901D9C69ECD3B1EDFEEC46279888ED7B3D6FBCE2F35071E76D8618BCE3BEFBCB9716CE1C678E18517EE683D3BF7B3BDF9986841469051FF14F5AF478469211A804ACFF47DD5A1377AA7E324B971159AF511CBC7E3DAF54267ADCFAF27BA0FFE52B3735C9AEAF0C30F5F7CE185173EF1DC73CFBDBA1EF5E9D53973E6DC72E699678E6F0DD04DF17C828C22C8A87FEA1F5B30FC0AD100B48963965B4F40D63E00670D0D0DD9A5975E9A9FDC34AE1012274D0DF137EEC7F4985F5F5FBFDA63E3F9E2791D13DDC7F5EFDFFF1F5365383F05E167FFE33FFEE3E971E3C6DD3B75EAD4071E7DF4D1590B172E7C29D5A725CF3EFBEC930F3FFCF0B4B4B338E9ECB3CF9E901EF3407ACCFC785C3CBE2FAE3741469051FF1441BA5B8569211A800EB55E1AEBF60E02F18694DB5DE28AF6B63EF4D043F74915E3A7FDFAF5BB2A55923BAB8E2D88BF77C6F4981FCB6DB5F1D7FC1464144146FD53FFE88A302C4403B02E81FA2B29D34C4865F97A86E7587E423CDE5A0441469051FF14F5AF378469211A80F572E49147EE9082F121FDFAF52BA4BFC5549E4AA57229AB975BEF175BE71F12CB5B6B20C80832EA9FA2FEF596302D4403B0D15258AEA9EA7DAEB14640901164D43F45FDEBAD615A8806A0AB8274B92A4897AD1110640419F54F51FF7A639816A201E8AA105DD3C131D135D60C0832828CFAA7A87FBD294C0BD1007465902E7710A4F54A832023C8A87F8AFAD76BC2F4A94234005D18A26BD670A6EE1A6B0804194146FD53D4BF1E1FA663C7468806A00B8374790D415AAF340832828CFAA7A87FBD6287C77A06A0ABDA949A75B87E748D3505828C20A3FE29EA9F200D005BADB5375AAF340832828CFAA7A87F823400686740905104699FBBFA67070700B43320C828828CFAA7FE61070700ED0C08328A20A3FEA97FD8C101403B030832828CFAA708D2767000D0CE00828C20A3FE29EA9F1D1C00B433802023C8A87F8AFA67070700B43320C82882B4CF5DFDB3830300DA191064144146FD53FFB083038076067AAD62B1B872E9D2A542443728E973989B82CC32F54F51FFECE000807606BAB1A953A7CE5DB0608120D10DCAD34F3F7D590A3277AA7F8AFA67070700B433D08D954AA5836EBCF1C6C5F3E6CD5BA867708BF504CE9B3973E6F8146266A57280FAA7A87F767000403B03DD5CEC3C474F542ACBE318C99E562EBEF8E22C36183DF1BDB796E5ADEBFF00F56F52A6A87F767000403B036CFA8D45D90603B0830300DA1960DD361435B1B1682D35D60860070700ED0CC09A3714E5AA205DB646003B38006867003ADF4854F746EB9506ECE000A09DD1CE006BD948943B08D27AA5013B38006867003AD84074D41BAD571AB08303807606A0930D44790D415AAF3460070700ED0C40D5C6614DBDD17AA5013B3800686700DA6D1CCAEB10A4F54A03767000D0CE00D86000B65700A09D016C3000DB2B00D0CE00361800B657006867001B0C00DB2B00B433800D0680ED1500DA19C00603C0F60A00ED0C800D06607B0500DA19C00603B0BD0200ED0C608301607B05807606B0C100B0BD02403B03D86000D85ED1376459F6FA279F7CF28ADB6EBBED9562B1984D9A3449D9CC25ADF79553A74E9D5B2A950E5223D1CE00361800B657747329445F99425CB660C1826CE9D2A5D9F2E5CB95CD5C62BDC7FABFF1C61B17A7607D805A897606B0C100B0BDA21B8B9EE8087102ED962FF3E6CD5B9882F49D6A25DA19C00603C0F68A6E2C8673EB89EE3E3DD329482F532BD1CE00361800B6577463718CAE10DB7D4A7C1E6A25DA19C00603C0F68A5E10A45F7A615EF6E45D17640F4F3E2B2F713BA609BF8234DA19C00603C0F60A41BA5D59B2684EF6D0F5C3B2FBAF3D6D9512D3629E002C48A39D016C30006CAF10A4ABCA330F5FB55A88AE94D90F5F2D000BD26867001B0C00DB2B04E9EAF2487944A7413AE609C08234DA19C00603C0F60A41BAAA3C346978A7413AE609C08234DA19C00603C0F60A415A9016A4D1CE00361800B657B061413ACED2DD59908E7902B0208D7606B0C100B0BD4290AE2A8FDD32A6D3201DF30460411AED0C608301D0B7B75759B6F5A9E75DFF776B5BACF19C5BDF547BC515DB564F1B5498F8F698DED9638E3D7FDAEBA27436BF615479B7F579ABF17A43CF9FB4BD5AB46983F45FE73C903D74C38F571FD69DA6C53C015890463B03D86000F4E9EDD58963CB6FAD2F946ECBC37273A9B1A150FA535539B72DF43615473734958FC96F178A750DA3A67CB8A1A974566353F15BE971FDEB4717FFDFAA2179EADFA7E51E88D23EA80FBFA0FCC64185A9EF4CCFFFD0A0C2E48F349E73DD4E8D8572737D737942A5A4E71ED2FEBDA6F739B8BE503CB9C3505E28FE4F9AFFE70E4B53E99CCE827EFB69C3870FDFA6A365D7777A4F0ED2519E9A76F16A413AA609BF8234DA19C00603A04F6FAF4E1B5BDEA5A1B9B44F84DDC631A58FA6507CC990A6D2FEF5A34B1FCC83720ABA2D61F18AD7A7DBCF363417A7A7207B4F6353E9A074FFF296205DFE4E4C3F656479E7CAF3368E2DBF3FCD7FB0A1503E244A3CA6BE69D27BDB02717379609A7F470AE637A4007D457A0F4FE48F193379AFB4FC9D11AE4F6EBEE1DDEDDF6F63A1F483C6E6E2511DFD2FF1F8C6E6291F8F9242FFA9E9F9C755EE0F2A14F768BF7CFC9FE9F926B74DC8B2ADE387835466A6F730317E08D8A0E9BD21482F5B963D76EB79AB0FEB4ED3629E002C48A39D016C3000FAECF62A05DAC352889D92C2E0E208B411A44F692E7F284A7DA1745A04DD96E54AFF9EC2F61F2B8F8B1EE57C7E73F9E729B40E4AC1FAD8E1C3CBDB45E04EA1F987F17CF198FAD193DF9597E672BF34ED85F47C670C2A4C7C431EB09B4A2322C00F6E2A7D29026D84DFF4775A5AEEAFA9DC34A450DE33C27763A1F8D54A89F09EDEE77F564F3B654CF17DAB85EAA6D2A111F23BFA9FF31EF8A6D239E9B9B278FF95E9E9BD9D94A65D173DCCE9B1DF6F6C2ED76FC8F49E1EA4972C9A93CDB8A5B9D363A4635E2C23040BD26867001B0C803EBBBD5A6568776B908E1EDC18AE5D39FEB9B587F7E254AE4F61F7978DCDC5E3D3EDFB5260FD7D9474FBE98631C5CFA4803C201F02DE5CFA493C57DEEB5C28DF19B7EB9BCA3F8D001BA13A7AAFD3BCFBD37335A5F270FD98F237D263CE4FCBFC4B7ADD13D3FBF9514C6B2C4CFE621EB82B2585ECB4FC93D5D3E2310DA3CA3B9CDC3C65F74A89E1DF69D931D5D36299D61F0F06B63ED7CD11E8F39510BDCBD12B9E5EAFF5878303E38785F59EDE9383F4B265D9BCC74AD983D7FDA0D3105D29B14C2CAB775A90463B03D86000F4C9EDD590B153764DA1726E1C979C87DFE6E2F474FF2FA95C9302EDBCEA65233CE7813B0FD2C52B23B0B686D6BB2248E7A17274E983955EED14AA87A7E73BBB723F4ACBF314EBA207373D6E7EBA3DE3F41137BF2D82749AF6D9146EAF8ADEEE08D2ABBCCFC2944FA7E51F4FF36F8D61DCD5F35A83F88555257AD9EF5F655AA17440BBFFE5994185F27BE276FE5E0BA5A7DBE6359586A4C0FEB3F59DDE5383F4DA7AA1F54E0BD26867001B0C00DBAB4A002D9487A6528A5EE1E8998E20DD3284BAF8409C3CACB1A9F4AB3CC4364DFED7FC38E042E9A5F89BC2F3C8144E0BE971FB468921E09520DDD24B5C3A272FE9B9F3920FA52E8F8AC7B584D8F291794F750AD3718C75F48847308FB09BCA451D05E9FC58EA1458E398EE08FD6BFABFD634B43B44804EAF33E7FF9EBBF8CDF8E1A02A6497E339D6777A4F0DD2EBD20BBDA6DE69815890463B03D86000F4A9ED554743BB53F01D9BF7528F9EFC89EA6557ED912EDDDF127EF300FC742548E7C70C174A37C619B1F3E59A8A835A4F567677E52CD979682F946E8930DE12D08B0D11EAF31EECA6F249295C7F3702F3FF05E3F27722AC562EBFD512F84B3FD8D0209DCF2F94FED0F68342D3A4F7A6D7BB3D7FEFCDC5FD2AB7D7777A4F0DD21B1AA22B452016A4D1CE003618007D6A7B15979EAA0ED2293C7F2E3F237773697604DB388958CB72B7BE290FCC79F82D5E1001B92A60FF21827404E53816395FA6A97C4CF420B7F67A1F1797B78A7995301DC728C7B1C5713C7504E99661DDA54763D9B8F4569CD02C7FBE96D79B517D56EC3C98B70CD7BEECD8F3AF7EF36AFF5373E9C414B4CFECEC7F8EDEF1F4F8D357794CBCBF789D14F8E3ACE11B3ABD2706694590463B03D86000D85EAD6B886E9EF2F114A21F8960D91A6E2F4EE1F6DA965EE4F2767156EBB8B6743E6F5479B718EA9D9F4DBBB93C30C26AEB63AE8963AA879E3F69FBFCC45F8552714D258682B73EEEBAE87DCE7BBF53A88D405A9997DED31111845BA7FFFAD49F5FFF960E0371BBB365B786F13BE2D25BEDAF6BBD2EA2A7BC2BA60BD28A20BD89B75D71B9BBD6932162BF18B0C1006CAFA896655B5B0982B420DD7BB51E5AF2E73595CA0F56E9F6E0C6E6E2F7A2B49E14F1A2B6FB8562836FB77606B0C1006CAF409016A47BBD13CEBD69C786E6D2BD313AA6A312F3629958364E46182364E264880DCDE583F352283D96EE9FD0FEACFCDA19ED0C608301D85E81202D48F7DE201DD7748F33F2C7D9FF5729F9F5EB6F8E65F21304E6D76E2F3D99A6CD8ADBAD6576E5769C94D0375C3B03D86000B65720480BD27D22489F36B6BC4B5C837ED532F95D95201DCB368C9AF2E174FFB7F9C90EAB4A9C24B1279DF04F3B03D86000D85E21482B82F44607E9D347DCFCB6B8E45E43A17C554B49B7E30A00D541BAB9F86FF585E23D713DFAEA12272A8C79BEDDDA19C00603B0BD02415A90EE33417A5061E2DB53809E5A991ED78DAFCCAB0ED271CDF638A37F75C9CFD42F486B67001B0CC0F60A046941BAEF05E9D2FCFF1BB25D9ADF3E48C759BB1B9ACB357196EEFC0CDE8552D3E0A6291F48217ABFFAE6F261BEDDDA19C00603B0BD02415A90EE33413A6EE743B9AB4A5CFE2E8672E7CB8C297E262D77D3A042718FE8958E6BCBD73795CFAB1F33F92B0D4DC5D169DEFDF5A3277FCE375C3B03D86000B65720480BD2BDDAD0F3276D5F3DA4BB222E6795CA4311A423503716CA5F6E2C94F61D3EBCBC5D9A7E5D7DA1745B04F0F83BA4A9B4FF9042E9930D6326EFE51BAE9D016C3000DB2B10A40569D0CE00361800B65708D28A208D7606B0C100B0BD4290563641901E3E7CF8366A2DDA19C00603B0BDB2BD62D3D4AB722A358274EF08D2F3E7CFDF7DD6AC590FDD73CF3DCB7FF4A31FFDA4A6A6663BB51CED0C608301D85E4117D7ABD6B2C6402D4877EF209D65D9B63366CC18B56CD9B21559ABB4DCAB975F7EF99CA38E3A6A6F351DED0C608301D85E41D707E935066A41BAFB06E9A79E7A6ADF050B163C9B7562E6CC99AF8C1831E2CADADADAEDD578B433800D06607B055D1FA43B0CD48274F70BD2C9DB1E7FFCF16B57AC5891ADCDCA243D66496363E377D57AB433800D06607B059B2648AF12A805E9EE556EBBEDB66CF1E2C54BB3F5B468D1A257C68D1B77776D6DEDEE6A3FDA19C00603107814651396CD15A41F79E49155EEDF79E79DD9B265CB565BEEA9A79EDAA4EF63C182057958ED6CFE73CF3D973DFCF0C3F9ED993367662FBCF042B674E9D2EC2F7FF94BB664C9924DFADEE6CE9D9B8D1C39325BB870E1FAE6E8FC31F158755AE9AC686D01411A0036FC079ACD3EB4FBEAABAFCE5EF7BAD7B505D89B6EBA29DAE8ECFAEBAF5F65B9071F7C30DB7AEBADF3F9175C7041F699CF7C66953262C4887CB90913266483070F6E2BC71D775CF6918F7C64B5F2C4134FE4A1F8A73FFD695B39E08003B26DB6D9263BFBECB35799FED8638FE5CF7DE9A59766EF7CE73BF3DBDB6FBF7D76F9E5976773E6CCC9DFEFB469D336F9BA8AFFED98638EB9A1542A3DB772E5CA15EB90A15F9B376FDE65471F7DF483E9739DA8471A00411A00BA2E486F91938DCD9F3F3F0FC51FF8C007F2301CB73FF7B9CF65EF7DEF7BF3DB31BFB2ECA04183B2CF7EF6B3F9ED3BEEB8231B3D7A745E0E3FFCF03CC8FEF297BFCCE7FDE637BFC9F6DC73CF6CBBEDB6CB0E3DF4D0ECAB5FFD6AF6A52F7D290FD53BECB0433E3F968F5EF02BAFBC325FEEEB5FFF7AA725969D3871621EBC4F3FFDF4FC398AC5E21609D295938DD5D5D51D3A6CD8B0056B3AD9D88A152BEE8D938DA5CF75762CAFD60320480340D704E92D7AF9AB089F1142F7D8638FECC31FFE705B89605D1D4E6308F58E3BEE98FDFEF7BFCF3EFFF9CF67975D76593EFDAEBBEECA76DA69A7ECD39FFEF42A43C12FBEF8E2EC6D6F7B5B7EFBBBDFFD6EB6DB6EBBE58F7BFDEB5F9F7DF39BDF6C0BD2D1EBFDD18F7E341F321E257AC5B76AED0DAF4CFBE4273F99DD72CB2DD9A851A3B237BCE10D79AFF8873EF4A13C485F74D145F932F198E1C387677BEDB557F6C0030F6C96B376C7D9B8070C1870DEF8F1E35F78EDB5D75EAECAD02FA6F576619A373B7DB6E73A6B3700823400744D3BB8C600BDB983F4D34F3FBDCAF4B85F1DA4BFF7BDEFE5F73FF5A94FE501368EA13EFEF8E3F3601BA176DB6DB7CD860E1D9AFDED6F7FCB66CF9E9DFDE0073FC8DEFCE63767A552293BE28823B22F7CE10B595D5D5D1EAE23F056827465B876DCEFACFCE217BF687B5FED8776C7FC2F7EF18BF9DFB7BCE52DF97B9A3163C666BB8E74E8D7AFDF9EF5F5F5D393F9CF3FFFFC4D43860C29A5CFF6FE98AEA603204803C066B6B982F409279C909D76DA696D25026975908EF79102623E2D8E858EA1DBD1CBFCBBDFFD2E9F3F7EFCF83C3847E83DEFBCF35609C2871D7658DEAB1CC73FBFE94D6FCA4E3EF9E4D58274F46ADF7DF7DDF910EE981743BEE37EF494B70FD26F7FFBDBF363952348C7B1D437DF7C73FE98E8B5DE9CD791AE565353B35D5D5DDDE969FFE6B9F81BF7D55E00046900E88541FAF1C71FCF0E3CF0C0B612C740EFBFFFFE6DF7AB7B77FBF7EF9FF73EC7B1D34D4D4D79D8AEAFAF6F2B871C7248DBF0EEEAA1DD11AC234CEFB3CF3ED91BDFF8C6FC769438B6797D7AA4E378E808E4316DBFFDF6DBA2C7487766F8F0E1DBA8B50008D200D08B83749CBCEBAAABAECA836DB95CCE7B7B2B270D8BA1DA471E79647EFB57BFFA555BB0FDD8C73E968D193326FBC637BE911F1B1DC72CC7ED6F7FFBDBAB1C231D3DD4D75C734D76C9259764679D755676F0C107676F7DEB5BF3DB511E7DF4D1B6201DC75FDF7EFBEDF97B89D7881EEEB85FDD23FDA73FFD29FBF297BF9CEDBCF3CE9D9EB5FBA5975EDAA2411A00046900E8C5413A7A9B2304DF70C30DF9DF3FFEF18FF9B0EB7DF7DD37BBF0C20BF3DB7146ED3899D7F4E9D3F36971B6EE08B6956B39FFF6B7BFCDC371F5F3C6B0ECCA71CBEF78C73BB2534E39250FC011C0E36463713B4A1C67BDB1C748B70FD27196F0EAE505690004690010A4BBACC409C176DD75D77C3876E56461F17A37DE78637EE6EEC6C6C66C975D76C94F0E16D79A8E801DD7788EB36C474F765CDF394E2016E1B872BDE7384E79DCB871F9B0EF38DE79EEDCB9790F7794E8DDAEF47847993C7972FE3EE24CDDF15AD19B1CD78B8E501C67038FFBF19C95E5E2525C679E79661EA4637EBCE738F9D941071D943F267AC9E36CE331EC5C900640900600417A939C682C8E778EDBFDFAF5CB7BA5B76AED058EB01A67DCBEEFBEFBF2401BBDBC279E78623EDC3A96AFADADCD8FA76E5FE27254D5AFF197BFFC251F9EDD5189E3AADBBFA7993367E6AF7FEFBDF7AE36AF32BCFC5BDFFA561EECDFF39EF7E4813DAE291D97D68A79EF7EF7BBDB7ACB05690004690010A4376959BA7469F6F2CB2FE76573BD66FB1297CF8A21DF4B962C596D5E04FA79F3E6E5B7ABAF595D298B172FEE70BA200D80200D0082B4B2858A200D80200D0082B42248032048038020AD08D20008D20020482B82340082B4B5000082B4200D0082340008D282340008D20020482B82340082340008D28A200D80200D0082B42248032048038020AD08D20008D2D6020008D282340008D20020480BD2002048038020AD08D20008D20020482B82340082340008D28A200D80200D0082B422480320485B0B0020480BD20020480380202D480380200D0082B42248032048038020AD08D20008D20020482B82340082340008D28A200D80206D2D0080202D480380200D0082B4200D0082340008D28A200D80200D00DD5CB1585CB974E95221B61B94F439CC4D417A995A0980200D00DDD8D4A953E72E58B04090ED06E5E9A79FBE2C05E93BD54A00046900E8C64AA5D24137DE78E3E279F3E62DECC93DD373E7CEEDC93DD1F366CE9C393E85E859A91CA05602204803403717E12D7A4253591EC7E8F6B472DB6DB76523478ECC264C9890F5C4F7DFBADEEF14A20110A401804D2ECBB2B72E5EBC78E9C2850BB38103075E6F8D0080200D00ACC1E38F3F7E6DD6AA542A3D57575777A8B50200823400D081A79E7A6ADF152B56547274B672E5CA15C3860D5B505B5BBBBDB503008234005025E5E66D172C58F06CD64E4C1B3060C079D6100008D20040951933668CCA3A317EFCF817FAF5EBB7A7B5040082340090CC9B376FB765CB96ADE82C48BFF6DA6B2F0F1E3C787A4D4DCD76D6160008D200D0E7CD9A35EBA16C2DA64F9F3EBFAEAEEE746B0B00046900E8D36A6B6BB7BDE79E7B96AF2D483FFFFCF337A57D81E762796B0D00046900E8D3860D1BF65FCB972F7F750D39FAC5C6C6C6921E690010A40180248E7DBEFCF2CBE77496A2A74D9B7661DA0FB8DF31D20020480300AD8E3AEAA8BD67CE9CF94AFB10BD62C58A7B070C1830DB59BB0140900600DA193162C4952B93EA1376C7B4B40F70AEB50300823400D04E6D6DEDF693264D5A5249D1F3E6CDBB2CB5FFB363BAB50300823400D081FAFAFA23162D5AF4CAC2850BB3A38F3EFAC1BABABA43AD150010A401803518376EDCDD23478ECC52DB3FD1DA0000411A00588BDADADADDA3DD8FBFD6060008D20080761F0034A80080761F0034A80080761F0034A80080761F0034A80080761F00D0A00280761F00D0A00200DA7D00D0A00200DA7D00D0A00200DA7D00D0A00200DA7D00D0A00200DA7D0040830A00DA7D0040830A0068F70140830A0068F70140830A0068F70140830A7417B5575CB1ED2923CB3BAF75C12CDB7A5061E2DB2B774F1C5B7EABB507DA7D0040830A7D4EE339C57F682894AF8ADB0D4DA5B31A0AA53F5597C6A6F2D7F379CDE59AC6A6D2EF2B8FAB2F14EF69183379AFA1E74FDA7EF8F0F276D62468F701000D2AF47AA78D2DEF52DF5CFA5A437369CAE0A6F2C752702EC6FD2185D2272BE584736FDAB12548972E4C61FAE0B83DA4A9B47F43A138232D7F4D2A4BD2BC7DAC4DD0EE03001A54E8F5EA0BA52352B92D85E185F5CDE5098D85D2E42185F29E0DA3CABB4539654CF17DB15C0CE34EC1F981FA31E56FD43795C6A6E51FCD97193379AF08DFD62468F701000D2AF419D543BB2348A7C07C654BEF732A85D273F9F4E6727D0ADC8F442F747DA1F81F69FA8BF5CDA56B238047904E658E3509DA7D0040830A7D423EA4BBB9F4447E3C740AD211AC2BF3E238E896B07DDD4EE9F6C969FECFE27E5AF6AEFC6F73694AF57D40BB0F006850A1574B41785843A17C6B0CEF8EE1DB2D3DD2A55FA7BF4D51D2EDF9B1DCA042718FB4CCBCC642F1BF1B9B4B8D69FAFDD18B9DFECE6AFD3BD3DA04ED3E00A041853E6195B376C730EDE6724DFDE8D207A30C6E9AF281983EB8A9B8774353F9A4FAD1933F1197C06ADF037D72F394DDD3F25FB03641BB0F006850A1D7AB6F9AF4DEEA63A41B0BC5CF0F193B65D74A691855DEA1716CF9FD2960FF383F31595371740CF98EE1DE95E74821FB8C346FB0B509DA7D0040830ABDDA90C2944F37144AF745486E09C4F975A4FFB7BAD417CAC7353417F74B617B4084EAD6E5BE9FE6DD5119169E6E8F3F69CCE47758A3A0DD070034A800A0DD070034A80080761F0034A80080761F0034A80080761F0034A80080761F0034A80080761F00D0A00280761F00D0A00200DA7D00D8AC0DAAA2288AA2287DA7D8FB010000000000000000000000000000000000000000000000000000000000000000000072FF1FDE68C4B57D09750D0000000049454E44AE426082, 1); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('73c05224-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'hist.var-assigneeList', NULL, 0xACED00057372001E636F6D2E616C69626162612E666173746A736F6E2E4A534F4E417272617900000000000000010200014C00046C6973747400104C6A6176612F7574696C2F4C6973743B7870737200136A6176612E7574696C2E41727261794C6973747881D21D99C7619D03000149000473697A65787000000003770400000003740005757365724274000575736572437400096C65616465724C617778, NULL); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('74c066fe-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'hist.var-assigneeList', NULL, 0xACED00057372001E636F6D2E616C69626162612E666173746A736F6E2E4A534F4E417272617900000000000000010200014C00046C6973747400104C6A6176612F7574696C2F4C6973743B7870737200136A6176612E7574696C2E41727261794C6973747881D21D99C7619D03000149000473697A657870000000027704000000027400096C65616465724C6177740005757365724378, NULL); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('9d23d446-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract.bpmn', '9d23d445-1cd7-11ec-acd8-3ae4f1d3c3af', 0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C646566696E6974696F6E7320786D6C6E733D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A7873693D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612D696E7374616E63652220786D6C6E733A7873643D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612220786D6C6E733A666C6F7761626C653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E2220786D6C6E733A62706D6E64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F44492220786D6C6E733A6F6D6764633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A6F6D6764693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A62706D6E323D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A64633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220747970654C616E67756167653D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D61222065787072657373696F6E4C616E67756167653D22687474703A2F2F7777772E77332E6F72672F313939392F585061746822207461726765744E616D6573706163653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E222069643D226469616772616D5F666C6F77436F6E747261637422207873693A736368656D614C6F636174696F6E3D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2042504D4E32302E787364223E0A20203C70726F636573732069643D22666C6F77436F6E747261637422206E616D653D22E59088E5908CE5AEA1E689B92220697345786563757461626C653D2274727565223E0A202020203C657874656E73696F6E456C656D656E74733E0A2020202020203C666C6F7761626C653A657865637574696F6E4C697374656E6572206576656E743D22656E642220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E557064617465466C6F775374617475734C697374656E6572223E3C2F666C6F7761626C653A657865637574696F6E4C697374656E65723E0A202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C73746172744576656E742069643D224576656E745F3170736D697364223E3C2F73746172744576656E743E0A202020203C757365725461736B2069643D2241637469766974795F306E796C61317222206E616D653D22E59088E5908CE5BD95E585A52220666C6F7761626C653A61737369676E65653D22247B7374617274557365724E616D657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935343932303334383934363433322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A66616C73652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839363537313222206C6162656C3D22E68F90E4BAA42220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F303063657865612220736F757263655265663D224576656E745F3170736D69736422207461726765745265663D2241637469766974795F306E796C613172223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3175637268353222206E616D653D22E4B89AE58AA1E983A8E9A286E5AFBCE5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22247B64657074506F73744C65616465727D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935343932303334383934363433322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550545F504F53545F4C45414445522671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A7461736B4C697374656E6572206576656E743D226372656174652220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E44657074506F73744C65616465724C697374656E6572223E3C2F666C6F7761626C653A7461736B4C697374656E65723E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839373234353522206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30346B63616A632220736F757263655265663D2241637469766974795F306E796C61317222207461726765745265663D2241637469766974795F31756372683532223E3C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30323666766E712220736F757263655265663D2241637469766974795F3175637268353222207461726765745265663D22476174657761795F30396364787466223E3C2F73657175656E6365466C6F773E0A202020203C706172616C6C656C476174657761792069643D22476174657761795F30396364787466223E3C2F706172616C6C656C476174657761793E0A202020203C757365725461736B2069643D2241637469766974795F3133386D346E6E22206E616D653D22E5B7A5E7A88BE983A8E5AEA1E689B92220666C6F7761626C653A63616E64696461746555736572733D2261646D696E2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353139343939313937323335322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839373831303122206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F307A7A307539672220736F757263655265663D22476174657761795F3039636478746622207461726765745265663D2241637469766974795F3133386D346E6E223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F30746D336D706822206E616D653D22E980A0E4BBB7E983A8E5AEA1E689B92220666C6F7761626C653A61737369676E65653D2261646D696E2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353139343939313937323335322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839383233373722206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F317978716265302220736F757263655265663D22476174657761795F3039636478746622207461726765745265663D2241637469766974795F30746D336D7068223E3C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31323465387A332220736F757263655265663D2241637469766974795F3133386D346E6E22207461726765745265663D22476174657761795F306F79366F666C223E3C2F73657175656E6365466C6F773E0A202020203C706172616C6C656C476174657761792069643D22476174657761795F306F79366F666C223E3C2F706172616C6C656C476174657761793E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3175766A3364732220736F757263655265663D2241637469766974795F30746D336D706822207461726765745265663D22476174657761795F306F79366F666C223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3179757579696522206E616D653D22E8B4A2E58AA1E983A8E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303936343531393339353333323039362C313434303936343531393339313133373739322220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353132373739303833333636342671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B504F53542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383930333738313422206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383930343234383922206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F316B79686E6C7A2220736F757263655265663D22476174657761795F306F79366F666C22207461726765745265663D2241637469766974795F31797575796965223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3039386E63767722206E616D653D22E6B395E58AA1E983A8E4BC9AE7ADBE2220666C6F7761626C653A61737369676E65653D22247B61737369676E65657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353030313039333439323733362671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383931393036363222206C6162656C3D22E5908CE6848F2220747970653D226D756C74695F6167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383931393734303622206C6162656C3D22E68B92E7BB9D2220747970653D226D756C74695F726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C6D756C7469496E7374616E63654C6F6F7043686172616374657269737469637320697353657175656E7469616C3D2266616C73652220666C6F7761626C653A636F6C6C656374696F6E3D2261737369676E65654C6973742220666C6F7761626C653A656C656D656E745661726961626C653D2261737369676E6565223E0A20202020202020203C636F6D706C6574696F6E436F6E646974696F6E3E247B6E724F66496E7374616E636573203D3D206E724F66436F6D706C65746564496E7374616E6365737D3C2F636F6D706C6574696F6E436F6E646974696F6E3E0A2020202020203C2F6D756C7469496E7374616E63654C6F6F704368617261637465726973746963733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3064693671613622206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F3179757579696522207461726765745265663D2241637469766974795F31656577743031223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C6578636C7573697665476174657761792069643D22476174657761795F316D356672757A223E3C2F6578636C7573697665476174657761793E0A202020203C73657175656E6365466C6F772069643D22466C6F775F306A7976317A622220736F757263655265663D2241637469766974795F3039386E63767722207461726765745265663D22476174657761795F316D356672757A223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F316833706E787922206E616D653D22E680BBE7BB8FE79086E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303931313431303538313231333431362220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935343932303334383934363433322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383934343935303822206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383934353238353022206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31663879786F7622206E616D653D22E5908CE6848FE4BABAE695B0E5A4A7E4BA8E3430252220736F757263655265663D22476174657761795F316D356672757A22207461726765745265663D2241637469766974795F316833706E7879223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6D756C74694167726565436F756E74202F206E724F66496E7374616E636573203E20302E347D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C656E644576656E742069643D224576656E745F3132616A6F3364223E3C2F656E644576656E743E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31613371636C6D22206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F316833706E787922207461726765745265663D224576656E745F3132616A6F3364223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F306C6C6F79353622206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F3179757579696522207461726765745265663D2241637469766974795F306E796C613172223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3165657774303122206E616D653D22E6B395E58AA1E983A8E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303936343338373937393339393136382220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353030313039333439323733362671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B504F53542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383933333730323422206C6162656C3D22E4BC9AE7ADBE2220747970653D226D756C74695F7369676E222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383933343139303122206C6162656C3D22E58AA0E7ADBE2220747970653D226D756C74695F636F6E7369676E222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F307A6D736E33782220736F757263655265663D2241637469766974795F3165657774303122207461726765745265663D2241637469766974795F3039386E637677223E3C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3176737269766222206E616D653D22E5908CE6848FE4BABAE695B0E5B08FE4BA8E3430252220736F757263655265663D22476174657761795F316D356672757A22207461726765745265663D2241637469766974795F306E796C613172223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6D756C74694167726565436F756E74202F206E724F66496E7374616E636573203C3D20302E347D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F316D323430366622206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F316833706E787922207461726765745265663D2241637469766974795F306E796C613172223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A20203C2F70726F636573733E0A20203C62706D6E64693A42504D4E4469616772616D2069643D2242504D4E4469616772616D5F666C6F77436F6E7472616374223E0A202020203C62706D6E64693A42504D4E506C616E652062706D6E456C656D656E743D22666C6F77436F6E7472616374222069643D2242504D4E506C616E655F666C6F77436F6E7472616374223E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F3170736D697364222069643D2242504D4E53686170655F4576656E745F3170736D697364223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D2239322E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F306E796C613172222069643D2242504D4E53686170655F41637469766974795F306E796C613172223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223138302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31756372683532222069643D2242504D4E53686170655F41637469766974795F31756372683532223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223334302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F30396364787466222069643D2242504D4E53686170655F476174657761795F30396364787466223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D223530352E302220793D223330352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F3133386D346E6E222069643D2242504D4E53686170655F41637469766974795F3133386D346E6E223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223636302E302220793D223136302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30746D336D7068222069643D2242504D4E53686170655F41637469766974795F30746D336D7068223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223636302E302220793D223339302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F306F79366F666C222069643D2242504D4E53686170655F476174657761795F306F79366F666C223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D223835352E302220793D223330352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31797575796965222069643D2242504D4E53686170655F41637469766974795F31797575796965223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313030302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F3039386E637677222069643D2242504D4E53686170655F41637469766974795F3039386E637677223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313336302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F316D356672757A222069643D2242504D4E53686170655F476174657761795F316D356672757A223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D22313531352E302220793D223330352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F316833706E7879222069643D2242504D4E53686170655F41637469766974795F316833706E7879223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313637302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F3132616A6F3364222069643D2242504D4E53686170655F4576656E745F3132616A6F3364223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D22313836322E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31656577743031222069643D2242504D4E53686170655F41637469766974795F31656577743031223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313139302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F316D3234303666222069643D2242504D4E456467655F466C6F775F316D3234303666223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313732302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313732302E302220793D223534302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223231302E302220793D223534302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223231302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223935342E302220793D223532322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31767372697662222069643D2242504D4E456467655F466C6F775F31767372697662223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313534302E302220793D223330352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313534302E302220793D223133302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223133302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223239302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2238392E302220783D223834312E302220793D223131322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F307A6D736E3378222069643D2242504D4E456467655F466C6F775F307A6D736E3378223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313239302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313336302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F306C6C6F793536222069643D2242504D4E456467655F466C6F775F306C6C6F793536223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313035302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313035302E302220793D223530302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223530302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223632392E302220793D223438322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31613371636C6D222069643D2242504D4E456467655F466C6F775F31613371636C6D223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313737302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313836322E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D22313830352E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31663879786F76222069643D2242504D4E456467655F466C6F775F31663879786F76223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313536352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313637302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2238392E302220783D22313537332E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F306A7976317A62222069643D2242504D4E456467655F466C6F775F306A7976317A62223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313436302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313531352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30646936716136222069643D2242504D4E456467655F466C6F775F30646936716136223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313130302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313139302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D22313133342E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F316B79686E6C7A222069643D2242504D4E456467655F466C6F775F316B79686E6C7A223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223930352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313030302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F3175766A336473222069643D2242504D4E456467655F466C6F775F3175766A336473223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223736302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223335352E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31323465387A33222069643D2242504D4E456467655F466C6F775F31323465387A33223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223736302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223330352E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31797871626530222069643D2242504D4E456467655F466C6F775F31797871626530223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223335352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223636302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F307A7A30753967222069643D2242504D4E456467655F466C6F775F307A7A30753967223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223330352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223636302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30323666766E71222069643D2242504D4E456467655F466C6F775F30323666766E71223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223434302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223530352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30346B63616A63222069643D2242504D4E456467655F466C6F775F30346B63616A63223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223238302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223334302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30306365786561222069643D2242504D4E456467655F466C6F775F30306365786561223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223132382E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223138302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A202020203C2F62706D6E64693A42504D4E506C616E653E0A20203C2F62706D6E64693A42504D4E4469616772616D3E0A3C2F646566696E6974696F6E733E, 0); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('9edcf5f7-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract.flowContract.png', '9d23d445-1cd7-11ec-acd8-3ae4f1d3c3af', 0x89504E470D0A1A0A0000000D4948445200000774000002260806000000AB78BB71000069854944415478DAECDD07981D55D938F05014AC34FB5F6CE0A7D83F15151B114114145009D98426862F8496DD0D298A88A11B5BB27743899F48533F0145098A81ECBD1702482F22016921B484D02142820AF39F77D859EE6E76934DB26576F7F77B9EF3E496B96577DF9C79CF79E7CC0C1B06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000834CE389D52D1B7FF6D757AC6ABBC9D32E7FCD4127565FDDDDE7279D587D93DF2E000000000000402A8AA9F5A5CA5F56D6F2826B7A7B7C6373F93BD11A9ACBB736942A67B4DD2F951B3A7BFFC6E66A7D7DA97A40C7C70F3CE9B24D1A9A2BA7C7EBEA9BAB7BA5EFF5C7A953A7AE9B3E76F7CABE6FFD8CF2E7D36D4FE9ECB9F4BDFEB7CB9FA3A9F2B3EEFE4EE27B747CECD0D2851BACF858F5AD63675DF7325104000000000000F48AD6C2EA8D8DCD977EB0B316CFC536B16D43A9B2736373A5B1A154BEB9A1B9BA5BD64A953BD3FB07C6739DBD7F7DA932A9B1A9BA6FC7C763756F1466EB9BAA273496AACDF5A5F2110DD3E7BD397DEC9186A6F2D4688DA5F22756785DA9B26D146E3BFBAC6CD570FEBD9BCA13E3FDF3FB8796CA5B74DC7ECAACB91BA5DBDC54DF5C1D993D9024EBA4F74F4ADBC28652F5C2F83EAD3FC3F8F899D3CFBE62C439E7AC973DD65CD9B1A1A97A717E1F000000000000A0C76505DD52E5F286A6CA842850B66F5951F4F2D8A6B1A9B247AC9E6D2C5516A48FDD17B75BDB03F9EDC6A66A5DC7F7AF6FAA9E5C5FAA4EE9F8F884A6CA4EE9FBDC92B6246D8BE273D2CF189BFE5B6E2D10DF7E68A9E57DB16DAC988DEDE3766D4137FD8EDF1B3BEB825776F67365DFB7A97274573FF7D4D3AA1B3694AAF3E2F30F69BEF49DADEF77707A7F4EB652B8A9F2DD585D9C1579D39FB1F16773364D9F9B3BBEA9FA81F14D97BE3BBD7DFDC1335B36134100000000000040AFC90BBA71EDDAFA1995F7B46F2D6FCC0BBAB16DC3F44BB74AEFFFAAA1543EADB6353695CFCA8BAF1DC5AAD6F435F7765CC97A48F3C56FA92F956F489F3B3BDDE6BAACF0DB54F9657ABBE5B099E5B7C7E7BCF41E2D9F8BC75BDFEFA5826E9CF2B9A932F6C5EF56DD380AB3794BDFFB90F4F999B58FC536B1EDD4A9D5F51B4AD5D9E9F3A7A6EDE1EC435E2CDCDE1D9F1577EB9B2BBB3496AAE7642B899BCBB7B6AEE65D38F1E48BDE90BEF69AF477F321D103000000000000F4AABCA03B79DAE5AF7971A56C143AB362E7A22880B62BE83697B78B226CDA7E52DB62B56A3CD7F1BDA3E819AB70EB9BABE7D53757BE59FB5CEB299B87D7972AC74D28553F35E1C44B374FB7AD66AB669BAAFB37962A47E5DBA6B79BD2F718D37ABBADA09BBEFFD6F1FED9ED99D5AF66D7E47DA95D9A3EF7B7768FC569A15F2CDCA6B7ABD3E33B3436952F88D71FD65C7D6F149EDBBE5F536542FA593FCA3EB3B9FC9DF8191A4BE5AFC5B57ED3D7EE9EBEC767C63755BEE81ABA00000000000040AFC90BBA87962E7C6D1453F3C7A3B89A3F575BD06D68AE5C15C5D6DA966E7375C7826E9CB6B8BEB9F2E76C75ED89D52DA3C01A2B63F3E71B4BE52FA5AFBB287DFDE3E9BFBF8FCF8EE26876AAE452E5A986E9D58FC476F54D73DF969DD6B975756DC76BE8C6678F6F2A7FBAE3CFD5D529971B9BCBE3D2D73C9D1574E354D3A5CAF5F533CA9F6F2DD6FEA9F6E78FF768F7DA52F598F4E73C36AEB91B2B86E37B64A76506000000000000E80DED0BBA95875E3A9572E5A18E05DDFA52657CACAACD56ACA6B763E56C763DD9E6F257EA9BAB7BD5BE6F3CD758AA36E7F71B9A2BC7A7AFF9CB4127565FFDD236D5735EBC5E6EB9A1A1A93CB575BBCFA49FF9EFC6E92DEFCAEE972A3F6D6CAE1C54F3BEED0BBA4DE5BDD336A3E3CFD5554137BEEF84A6962F448BEBF4A6AF3D344EA3DC5A38BE2ABB7E6EFAF3E4B7DB3E2756E596AAB363856FFADEBF8B4275FAF34C8ADF8528020000000000007A455EB48DDBD929966B5A142FE314CBD93633CB1F4DB7BBECD052798B28764EFCF145AFCAAE7B3BB3658728A8C6E98DE314C88D3F9BB36943A9FC87B87E6DED8ADCECFD63756B5C3777FABC3767F7A3185BAA2C4FDB7FEA4BD50362556E5CAF367DFDA8EC74C9E97687962EDCA0B6B01A85E3C652E5E7F9FD58D53B76D605AFECF8734511B8F6B4CD1DBD781DDDCAD238D574DB6B4AD5E6F4B3EF8855BBB5D7046E3D75F4B551F4CEEE972A47A6F77F9BFE7B5B5C0B581401000000000000BD62CAACB91BD59E6A3917D79BCDAE7F5B2ADF90AD4A2D55B78FD5B1AD85D039F5A5CA9551088E7F273455769A50AA7CB86166CB3651EC8CE26C579FD7D854199B3E3F2556C6C6F568E3D4CB07CF6CD92C5E97ADD8CD4FB53CB36587FAA6EA096DAF9BDEF2AE28A0468BD32377F9FECDD58F67A7802E55FE1EA7525EDDDF47ED0AE2B6DFC5F44BB7EA58B88D9FB7B6180C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014445D5D5DA2699AA6699AA6699AA6699AA6699AD6D3CDEC2B00400F1574FD1600000000809E64DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205C0109424C9CB172C5870CE95575EF9AF72B99CCC9D3B57EBE396FEDE5F98376FDEA24AA5B2AB88040000BA62DE1100406205C010B460C18273E7CD9B972C59B22459B66C59F2DC73CF697DDCE2F71EBFFF4B2EB9E4A9B973E7EE2C2A010080CE987704009058013004C5CADC28262AACF67F5BBC78F1A373E7CEBD46540200009D31EF080020B10260088AD32C5B995B9C95BA73E7CE5D2E2A010080CE987704009058013004C5355C15538BD3E2EF212A010080CE98770400905801300475B7A0FBCF2717270BAE3D2D99DF7274D6E2763CA608ABA00B0000F40DF38E0000122B0086A0EE1474973EF16072CB45DF4FFEF6E749ED5A3C16CF29C42AE8020000BDCFBC230080C40A8021A83B05DDFBE7CF5EA1989BB707E65FA010ABA00B0000F401F38E0000122B0086A0EE14746FAB4EEBB2A01BCF29C42AE8020000BDCFBC230080C40A8021A83B05DD5BE64EEDB2A01BCF29C42AE8020000BDCFBC230080C40A8021484157411700001818CC3B020048AC001882BA53D09DDF72749705DD784E215641170000E87DE61D01002456000C41DD29E8DE79C5CC2E0BBAF19C42AC822E0000D0FBCC3B020048AC001882BA53D07DECC19B935B2EFEC18AA75B4E1F8BE714621574010080DE67DE1100406205C010D49D826EB47BAE3B7385826E3CA608ABA00B0000F40DF38E0000122B0086A06E1574972F4FEEFCEBC92B9E6E397D2C9E538855D00500007A9F7947000089150043D0AA0ABA4B9F7830B9E38AE62EAFA11BCFC5368AB10ABA000040EF32EF080020B1026008EAB2A0BB7C79B2F8CE4AF2F739877759CCCD5B6C13DB5AADABA00B0000F41EF38E0000122B0086A0CE0ABAAB5A956BB5AE822E0000D0F7CC3B020048AC0018823A2BE8766755EECA56EB2ACC2AE80200003DCFBC230080C40A8021A8B382EE9A1673F3A630ABA00B0000F43CF38E0000122B0086A02EAFA1AB29E80200008562DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000CAEFD51356DC357B59D82AE822E00003060C679C60B0000122B0006D3FEA8B5ADB4B0ABA0ABA00B00000C9C719EDF020080C40A8041B43FEAD03A2DEC2AE82AE802000003679CE7B7000020B1026010ED8FBA68ED0ABB0ABA0ABA0000C0C019E7F92D000048AC001844FBA355B4ACB0ABA0ABA00B00000C9C719EDF020080C40A1862FD95A615B1A0BB6CD9B264E9D2A5ABDC6ED1A245C96DB7DDB65AEFBD64C992E4CA2BAFECF2F9471E7924993F7F7E767BE1C285C9934F3E997D9F7FFCE31FDDFA4E6BDBC4E4E06FF63E000098770400905801E8AF28CC2997CF3AEBACE4A73FFD6997EDF4D34FCFB6BBFCF2CB937DF7DD37F9D8C73E96BCE215AF480E3AE8A0E4FDEF7F7FF2BEF7BDAF5D5BBE7C79B278F1E2E4B2CB2E4B76DB6DB7E4831FFC60763BDAF7BFFFFD76DBC6674771F684134E686B3BEFBC73B2EEBAEB26C71E7B6CBBC7EFBCF3CEEC7BFCFAD7BF4E5EFFFAD767B737DA68A3E4ECB3CF4E1E7CF0C1F8BF925C77DD7556E8A2DF0500403E090020B102D05FD1337FDF95157273BD5DD0DD6FBFFD92ADB7DE3A6B1FF8C007B2C268FC9B3F16DF2DB6AB56ABC92EBBEC92ACB3CE3AC911471C915C73CD35D9B651F43DEFBCF392638E3926BB1FAB65CF3CF3CCEC76C7B6CF3EFB249FFDEC67931FFFF8C7D9FDD9B36727E79E7B6EB2FEFAEB275FFEF297BB6CB1ED85175E98DC7DF7DDC9E4C993938D37DE382997CB0ABAE8770100904F020048AC00F457F4DEDF776585DC5C5F9E72394E5B9C7E6472F3CD3777FADCF9E79F9FAD9E3DFEF8E3936BAFBD36DBF6C0030F4C8E3BEEB8E480030E682BE8C6F651783DFAE8A3B315BBDB6DB75D72EAA9A726DFFEF6B793BDF6DA2BF9D18F7E94ADB27DE69967928B2EBA285BE97BCF3DF7642D4EB71CEF138FE78F7DF8C31F4EAEB8E28A64FAF4E9C9061B6C901595DFFBDEF76605DD33CE3823DB265E3375EAD4649B6DB6E9F4FB2BE8A2DF0500403E090020B102D05FB13A7FDF951672734529E8C64ADC57BDEA55D9F3AF7DED6B939FFCE427C937BEF18D766DF7DD77CF0AB877DC714756E07DC73BDE91ADC08DD79C72CA29593137DA873EF4A1AC109CBF779C467958272B7AF3169F5DBB6DED2997E3F9CF7DEE73D9BFF1FDC68D1B977DBE822EFA5D0000E4930000122B00FD15BDAE2805DD6853A64CC99E9F38716252A954B2026EC7162B69C78F1FDF696176871D7648468D1A956CB5D55659C1B7B648BBE9A69B26D75F7F7D766AE5D8360AC1717F8B2DB658A1A01B05E538CD731474E35ABB717DDF784D7CB6532EA3DF0500403E090020B102D05FD1678A52D08D55AF1B6EB861F6FCCB5EF6B2AC307BF8E18767D7C58DC71A1B1BB3FB37DD7453B64A77D6AC59C949279DD4D62EB8E082B6532E5F7DF5D5C9CB5FFEF2E4BEFBEE5BAD15BA71BDDC38FD723CF695AF7CC53574D1EF0200209F0400905801E8AFE85F4529E846E176E79D774ED65B6FBDE4A8A38ECA56C8C6E98D77D96597EC3563C68C490E3AE8A0B6ED63BBCD37DF3CBBD6EDC61B6F9C1560F3826E3C1FD7CD9D366D5A5B4177934D3649AEBAEAAA64F6ECD9D9FBFDE637BFC9EED7AED08D6BF86EBFFDF6C9EB5EF7BAB6532E772CE8FEF39FFF54D045BF0B00807C1200406205A0BFA26F14A5A07BDC71C76505D328D456ABD5E4E1871FCE0ABABBEDB65BF69AFDF6DB6F8582EE9C3973B2DB871C72485B4177DB6DB74D264F9E9C6CB6D9665931766DAFA1DBB1A0BBC71E7BB4DB5E4117FD2E0000F2490000891580FE8A5ED39B05DDD34F3F3D2BB0E66DEBADB7CE0AA39FF8C427DA3DFECB5FFE3279F6D967DB0AB551D08D42EA8C193392830F3E387BCD09279C90DDCFBF6F6CB7DD76DB257BEEB967F29EF7BCA7ADA01BD7D9FDC217BE9015831F7BECB16CDB2BAFBC323B6573ACAEBDF3CE3BB3F7BBF6DA6BB3FBF1BE2D2D2DD9760F3DF450B63A380ABAF17C7CC6473EF29164D75D77CD5E3373E6CCE4DDEF7E77D2D4D4A4A08B7E170000F9240080C40A407F45EFEBCD82EE25975C921C79E491AB6C7941B5B6A01BA758FEE4273FB9423BFEF8E3DBB6FBEA57BF9A156EE3F4CA1D4FB9DC555BB87061569CBDF1C61B5778EE17BFF845F6DCD7BFFEF5EC9ABC6F7DEB5BB3F72F97CB59113A9E7BCB5BDE92CC9F3F5F4117FD2E0000F2490000891580FE8ADED797A75CEE4EBBF7DE7BBB759DDABBEEBA2B59BA7469DBCADA458B16258B172FCEFE5DD9EB9E79E699E49A6BAE697B6D6D8BCF8DF788DBCB972F5FE1F9A79E7AAAD3C71574D1EF0200209F0400905801E8AFE815452BE80EF5A6A0ABDF050000F9240080C40A407F451B055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF28A872B9FCC2B265CB14530BD0D2BFC3A2B973E72E1795FA5D0000904F020048AC00F45764E6CD9BB768C992250AAA0568F7DE7BEF6FE7CE9D7B8DA8D4EF0200807C1200406205A0BF2253A95476BDE4924B9E5ABC78F1A356EAF6DBCADCC50B172EFCCDDCB973EF4BDBCEA252BF0B0000F2490000891580FE8A3651448C95A1697B2EAEE1AAF5797BAEF5F7AF98ABDF050000F9240080C40A407F05A0DF0500403E090020B102D05F01A0DF0500403E090020B102D05F01E8770100904F020020B102F45700E8770100904F020048AC00F45700FA5D0000904F020048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B00FD15807E170000F9240000122B407F05807E170000F9240080C40A407F05A0DF0500403E090080C40AD05F01A0DF0500403E090020B102D05F01E8770100403E090020B102D05F01E8770100904F020048AC00F45700E8770100904F020048AC00F45700FA5D0000E493000048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B407F05807E170000F9240080C40A407F05A0DFF55B0000403E090020B102D05F01E8770100904F020020B102F45700E8770100904F020048AC00F45700FA5D0000E493000048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B00FD15807E170000F9240000122B407F05807E170000F9240080C40A407F05A0DF0500403E090080C40AD05F01A0DF0500403E090020B102D05F01E8770100403E090020B102F457FA2B00FD2E0000F2490000891580FE0A00FD2E0000F2490000891580FE0A40BF0B00807C1200008915A0BF0240BF0B00807C1200406205A0BF02D0EF0200209F944F020048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B00FD15807E170000F9240000122B407F05807E170000F9240080C40A407F05A0DF0500403E0900C0AA93A86A2452AB6855BF29C0401000FD2E0000F2490080BE4FA28677A3A03BDC6F0A30100440BF0B00807C1200A07F12A9AAD5B980812000FA5D0000E4930000C54CA4865B9D0B180802A0DF0500403E090050DC64AA6A752E602008807E170000F92400403193A9E156E702068200E8770100904F02001437A1AA5A9D0B180802A0DF0500403E090050CC846AB8D5B980812000FA5D0000E4930000C54DAAAA122BC0401000FD2E0000F2490080622655C3255680812000FA5D0000E49300C0A09324C9CB172C5870CE95575EF9AF72B99CCC9D3B7740B648AC06EA774F7FEF2FCC9B376F51A552D955FCCDD5C49F812000FA5DE493F249C4BDB817A79A38954FA25FD3F46B00B97427746EDA09264B962C49962D5B963CF7DC735A1FB7F8BDC7EFFF924B2E792ADD31ED2CFE34F1672008807E17F9A47C12712FEEC5A9264EE593E8D734FD1A40268E288A4ED00EA1FFDBE2C58B1F4D7744D7883F4DFC190802A0DF453E299F44DC8B7B71AA8953F924FA354DBF069089D34338A2A8384718A53BA2E5E24F137F068200E877914FCA2711F7E25E9C6AE2543E897E4DD3AF0164E2DCF37602C569F1F7107F9AF833100440BF8B7C523E89B817F7E25413A7F249F46B9A7E0D60B57644FF7C7271B2E0DAD392F92D47672D6EC763761E7644E24FFC61200850A03EB61AFDEC2A5AD56F4A3E299F944F8A7B4DDC8B53718A713CFA35FD1AC0A0DA112D7DE2C1E4968BBE9FFCEDCF93DAB5782C9EB303B123127FE20F03418082F4B1C3BB51D01DEE37259F944FCA27C5BD7815F7E2549C621C8F7E4DBF0630A87644F7CF9FBDC24E286F0FCCBFC00EC48E48FC893F0C04018AD4CF56ADCE954FCA27E593E25EDC8B7B71AA8953E378F46BFA358021B523BAAD3AADCB1D513C6707624724FEC41F06820005EA67875B9D2B9F944FCA27C5BDB817F7E25413A7C6F1E8D7F46B00436A4774CBDCA95DEE88E2393B103B22F127FE30100428585F5BB53A573E299F944F8A7B712FEEC5A9264E8DE3D1AFE9D700EC88EC88EC88C49FF8C34010A0987DED70AB73E593F249F9A4B817F7E25E9C6AE2D4381EFD9A7E0D60C8EC88E6B71CDDE58E289EB303B123127FE20F03418002F6B755AB73E593F249F9A4B817F7E25E9C6AE2D4381EFD9A7E0D6048EC88EEBC6266973BA278CE0EC48E48FC893F0C04010AD8DF0EB73A573E299F944F8A7B712FEEC5A9264E8DE3D1AFE9D70086C48EE8B1076F4E6EB9F8072B9E26227D2C9EB303B123127FE20F03418082F6B955FDAE7C523E299F14F7E25EDC8B53712A4E8DE3D1AFE9D70006FD8E28DA3DD79DB9C28E281EB3F3B023127FE20F03418002F7B9C3478C18A1DF954FCA27E593E25EDC8B7B712A4E318E47BFA65F0318E43BA2E5CB933BFF7AF28AA789481F8BE7EC40EC88C49FF8A3DBB66D1D086EEB5701D037FDEE861B6EA8DF954FCA27E593E25EDC8B7B712A4E318E47BFA65F0318BC3BA2A54F3C98DC71457397E7FE8FE7621B3B113B22F127FE58F520306D4BD236B1F55F834100FD2EF249F924E25EDC8B53712A4EE593E8D734FD1AC01AEE88962F4F16DF5949FE3EE7F02E7742798B6D625B4719D911893FF1C72A0781DB76711F00FD2EF249F924E25EDC8B53712A4EE593E8D734FD1A40F77644AB3A9AC851467644E24FFCB15683C0553D0E807E17F9A47C12712FEEC5A93815A7F249F46B9A7E0DA0EB1D51778E265AD9514676287644E24FFCD1EDC19EC120807E17F9A47C12712FEEC5A93815A7F249F46B9A7E0D60F576446BBA13CA9B1D8A1D91F8137FACD620CF601040BF8B7C523E89B817F7E2549C8A53F924FA354DBF06D0FD1D91664724FEC41F7D3608341804D0EF229F944F22EEC5BD38D5C4A97C12FD9AA65F1B34BEF5AD6F6D5C5757B7FBC891234BE9BFE5B4DD93B667D396B4FE1BF7CBADCFEF1EDBFBAD0D414F3DF5D4A6B367CF3E7AE6CC997F3BEAA8A31E9D3265CAB2030F3CF085089471E3C6FD7BE2C4894F7FEF7BDFBBEFE8A38FBE60D2A4495F4E5FB28E1D911D801D91F8D32442FD3808341804D0EF229F944F1640E389D52D1B7FF6D757887BCD384A9C8A53F9E460C927BBBB6F9B3CEDF2D71C7462F5D5DD7D7ED289D537ADECFD0E2D5DF8DA29B3E66EA45FD3F46B033FF75C1DA3468DDAA1AEAEEEBCB43DD75ABCED6E8BEDCF8BD7DB250D01575F7DF5B81933663C78C001072453A64C49CE3DF7DCE4FAEBAF4FEEBEFBEEE4B1C71E4B42FC1BF7E3F1787EF2E4C92F8C1933E6B94993265D347AF4E87749B0353B22F127FEE8A741A0E202807E17F9A47CB287C484737DA9F29795B57C523ABD3DBEB1B9FC9D680DCDE55B1B4A9533DAEE97CA0DE25E338E12A7E2543E59847CB2B7F76D8DCDD5FAFA52F5808E8F1F78D2659B3434574E8FD7D53757F74ADFEB8F53A74E5D377DECEE957DDFF80EF5A5F2219D3D97BED7FF76F97334557ED6DDDF497C8F8E8F1D5ABA7083151FABBE75ECACEB5EA65FD3AFC93D7BCFA851A3B6A9ABABBB6A358BB85DB5ABE2FDEC9E06A19B6FBE79A7934E3A69D1D8B16393DFFFFEF7C9238F3C92AC8ED83E5E3766CC987F3536369E9306CAEB24D89A1D91F8137FF4D2202EA9698A0B00FA5DE493F2C95ED03AF97C6363F3A51FECACC573B1CD8B93CA959D1B9B2B8D0DA5F2CD0DCDD5DDB256AADC99DE3F309E13F79A71943815A7433E9FECCBF7E9B77D5B7DA932A9B1A9BA6FC7C763F560FA9A53EA9BAA273496AACDF5A5F2110DD3E7BD397DEC9186A6F2D4688DA5F22756785DA97278637379BFCE3E2B5B95987FEFA6F2C478FFFCFEA1A5F2161DB78F95BEE93637D5375747BE98E127EBA4F74F4ADBC28652F5C2F83EAD3FC3F8F899D3CFBE62C439E7AC973DD65CD9B1A1A97A717E5FBFA65F937BF6AC6F7DEB5B1B8E1C39F2C4BABABA173A16661B1A1A925FFFFAD72B5D7819CFC7769D14755F88F78DF7B7AB1A04D2BFFB7A175E78E1EC28E49E71C619C9D2A54B93B511AF8FF74903E4D9BDF6DA6B3709B626C1167FE28F5E18BC75A7B0A0B800A0DF453E299F5CDB49B552E5F286A6CA8498C46DDFB289E3CB639BC6A6CA1EB1C2A8B15459903E765FDC6E6D0FE4B71B9BAA75E25E338E12A7E27448E793FDF57E7DBA6FAB6FAA9E5C5FAA4EE9F8F884A6CA4EE9FBDC92B6246D8BE273D2CF189BFE5B6E2D40DD7E68A9E57DF54D73DFD6582A7F296FE9E3673796AAC7D43E76D8CCF2DB3BBE7FF67D9B2A4777F5734F3DADBA6143A93A2F3EFF90E64BDF198FA53FF3C1E9FD39D94AE1A6CA7763757156E44D7FC6C69FCDD9347D6EEEF8A6EA07C6375DFAEEF4F6F507CF6CD94CBFA65F937BF6BCBABABACD478D1AF5B7DA42ECE8D1A39359B366250F3CF0C06AD5E762FB785DBCBE4361F7A6F81CBBAC012CFDFB6E7CD65967DD71F0C107270B162C487A52BCDFD8B163978D1933E62809B626C1167FE28F1E1EB475B7B0A0B800A0DF453E299F5CCB49B5B8BE5FFD8CCA7BDAB79637E6936AD9A4F0F44BB74AEFFFAAA1543EADB6353695CF8A096A71AF19478953713AE4F3C922BC6FAFEFDB62556BFA9A7B3BAE643DA4F9E2B7D497CA37BC58A0AD5C97157E9B2ABF4C6FB74481363EE7C5D7B77CAEA1A932ADAD952A8F6545AB9AC7D2D77EB6617A75E328CCE62D4ECB9C6E3BB3F6B1D826DE73EAD4EAFA0DA5EAECF4F953D3F6706B61609D170B622D9F8BBBF5CD955D1A4BD573B295C4CDE55B5B57F32E9C78F2456F485F7B4DFABBF9907E4DBF26F7EC79A3468D7A6FDA1EAC2DBE4E9B362DB9FFFEFBD7AA3E17AF8FF7E950D4BD3F3ECFAE6B008A626EA9547AE288238E489E78E289A437C4FB4E9932E5D97DF6D9E74C09B626C1167FE28F1E1CACAD4E6141710140BF8B7C523EB916936A93A75DFE9A175713C564703621BC282689DB4DAA3597B78B89EAB4FDA4B6C58A9E784EDC6BC651E2549C0EF97CB210EFDF9BFBB6287AC62ADCFAE6EA79F5CD956FD63ED77A4AD8E1F5A5CA71134AD54F4D38F1D2CDD36DABD9AAD9A6EAFE8DA5CA0A8BA226942EFDEF749BBBD26DFE1AA7576EF75933AB5FCDAEC9FB52BB34DDF66FED1E8BD3CEBE58B84D6F57A7C777686C2A5F10AF3FACB9FADE283CB77DBFA6CA84F43BFC286EC73548E367682C95BF16D7FA4D5FBB7BFA1E9F19DF54F9A26BE8EAD7E49E3DA77565EE83B5AB7267CF9EDDA335BA78BF0EAB75EFB752778089D32C9F75D65977463137FED3F6A678FF8913273EB9E79E7B7E4F82AD49B0C59FF8A3870669AB5B58505C00D0EF229F944FAEE1A4DAA1A50B5F1B13CE6D93BEA54A357FAE7652ADA1B972554C48D7B6749BAB157435E328712A4E07753EB94EDAF66DFD776D74F63E3D9E4FF6D6BE2D4E5B5CDF5CF973AC788DE26B145863656CFE7CEBE9932F4A5FFF78FAEFEFE3B3A3389A9D3AB65479AA617AF5231DBF6BAC98CD4E3DDB5CF94C145857F6737575CAE5C6E6F2B8F4FD9FCE0ABA712ADB52E5FAFA19E5CFB7166BFF54FBF3C77B74F8FC63D29FF3D8B8E66EAC246E2895FF373B2DB37E4DBF26F75C6B714DDBDAD32CEFB7DF7EC98D37DED82B35BA78DF78FFDAD32FBBA6EE0012D7CC3DE490437A6D656E672B75F7DF7FFFA7D340D94582AD49B0C59FF8A30706676B5258505C00D0EF229F944FAEF1A45AE5A1974E675779A8E3A45A7DA9323E561E65AB7AD2DB8DA54A5376CDBDE6F257EA9BAB7B897BCD384A9C8AD341994F46F1F5D4D61CF1D4616B5ED45DD9FBF4683ED95BFBB678AEB1546DCEEF3734578E4F5FF397834EACBEFAA56DAAE7BC78BDDC72434353796AEB769F493FF3DF8DD35BDED5EEFD9AAA7551C4CA4FDD1CA7914D3FE3F0AE7EAEAE0ABAF17D2734B57C215A5CA737FDDC43E334CA71ADDE288665D7CF4D7F9EFC76DBF78F55B9A5EAEC58E19BBEF7EFA2509DFE3C93E277A15FD3AFC93DD7DEC891234FAC5D99DB5BC5DCDAA26EED4ADDF87CBBB30120FDC3ED3C76ECD81EBF666E77AEA9BBD75E7B3D3162C488D74BB03509B6F8137FACE5A06C4D0B0B8A0B807E57BF8B7C523EB99A936AD9C46E9CE6AEA6C5046F9CE62EDB6666F9A3E976971D5A2A6F1113C2137F7CD1ABB26B03CE6CD9A1A1A93C234E01593FA3656B71AF19478953713AE8F2C97D3BE4896B52D4AD2DE6E66D9FDECA277B7ADFD6F8B3399B3694CA7F88EBD7D6AEC8CDDE3F56B7C67573A7CF7B7376BFA9BC77BADDF2B4FDA7BE543D2056E5C6F56AD3D78FCA4E979C6E17AB76D3CF2BA58FDD91BF2E4C9D7ACECB5B4FA3FCDBB1B32E7865C79FABB1B9725067A76D7EE9F5711DDDCAD238956DDB6B4AD5E6EC734A95EB6BAF39DA7AEAE86BA3A896DD2F558E8CCF4DFFBD2DAE05AC5FD3AFC93DD7CEA851A3B6A9ABAB7B3E2FAE5E70C1057D52A38BCFA959A5FB7C7C0F9956C19D74D2498BCE38E38CA43F9C7CF2C98BD2406992606B126CF127FE1415D67230B6368505C50540BFABDF453E299FEC8629B3E66E547BBABBB609EA5265E7EC1A81A5F20DD9CA9D5275FBC65265DBD6C9E239F5A5CA95311917FF4E68AAEC34A154F970C3CC966DC4BD661C254EC5E9A0CB273B2BC6AE4E51B7B3D7FFA28BD7F7483ED9D3FBB628764671B6ABCF6B6CAA8C4D9F9F122B63E37AB471EAE58367B66C16AFCB56ECB69E6A390A51F54DD5131A9A2B93D3ED4E8D025567EFD7D054F96EED698FD3DB1FCF4E315BAAFC3D4EA5BCBABF8FDA15C46D9F31FDD2AD3A166EE3E7AD2D06EBD7F46B72CF3557575777555E589D366D5A9FD6E8E2F36A8ABA57C9B40AECEAABAF1E17AB739F7EFAE97E29E8C6E7EEBDF7DE4F8D1E3DFA5D126C4D822DFEC49F41E05ABCC7DA1616141700FDAE7E17F9A47C52DC8B37712F4E3571BAF679DC9A167557A7983B74F2C9245947BFA6E9D706AF3DF6D863FBDA532DDF7FFFFD7D5AA38BCFAB3DF5727C1F7F95829A3163C683E79D775ED29FCE3CF3CCBBD340996547A4D911893FF16710D8CF8505C50540BFABDF453E299F14F79AB817A79A385DFBFC6D758BBA6B52CC954FEAD734FDDA80575757775E5E4C9D356B56BFD4E8E2736B56E99EE7AF52404F3FFDF466E3C68D4B1E7EF8E17E2DE8A69FFF9FD1A3472FA9BDC8BA1D91664724FEC49F41603F15160C0601FDAE7E17F9E480CB2707DB785ADC6BC651E2549C0E8A7CB2BB45DDB529E6CA27F56B9ABC73C01A3D7AF426757575CFE5C5D4BE5E9D5BBB4AB7A6A0FB5C7C2F7F9D82F9D39FFE74D49429539222D87FFFFD17A681F2E981F07B4BBF67356DC3ED8824D8E24F33C0EB7E4CF6C160AB270B0B0683C0509F7CD3EF0E62F2C9C1954F3EF4D043EFBCEFBEFB6EB9E1861B9E3BF2C8238F1F3E7CF8FAA25CDC1B4789534D9C16681CBFAAA26E4F1473E593FA354DDE3920E33F7D7EF7BC90DAD0D0D0AF35BAF8FC9AA2EEEEFE8205D3DCDCFCF773CF3DB71005DD534E39E5A634487E3840FE23E641BDD2FF907644126CF1A70D91826EB762B20F06593D5D583018040613FD2EF2C941964FA6C3E8F5EEB8E38EE9CB972F7F3E1F57A7DBFDFBECB3CF7E70BFFDF6FBB44817F7C651E25413A7051AC77755D45D7758CF1573E593FA354DDE39E0E23F7DBC39DFEE57BFFA55BFD6E8E2F36BBE73B3BF60C11C75D4518F5E7FFDF58528E8CE9B37EFE6912347CE1E60FF1157FA1FD28E48822DFEB42156D0EDEE80B0B70657BD51583018040603FD2EF2C941964FDE73CF3DDB2E59B2A4CB6B272D5CB8F05FD3A64D3B77C488111B8978716F1C254E35715A90717C6745DDDB87F56C31573EA95FD3E49D032AFE478D1A55C99FBFEEBAEBFAB546179F9F7F97F85EFE82053379F2E4650B162C284441F7F6DB6F8F532E5F3B40FF2376FA1FD28E48822DFEB4215AD05D5992DE9B83AADE2A2C180C0203997E17F9E420CA2753AFB9EBAEBBFEFCFCF3CFAF728CFD422A7DCDD2C6C6C67D45BDB8378E12A79A382DC838BEB3A26E4F1773E593FA354DDE3960E23FFDF7BEFCF1FEAED5C5E7D77CC7FBFC050B66DCB8712F3CFEF8E38528E83EF6D8634BD320797080FF476CF71FD28E48822DFEB4215ED0ED98A47467309514A0190C0283857E17F9E4206A575E7965F2D4534F2D5BDDB1F6134F3CF1AF534E39E5FA112346BC53DC8B7BE32871AA89D35E18C7AFAE38CD72C795B9B7B73EDE1FF930FA354DDED99FF1FF4C7EBFBF6B75F1F9352B749FF6172C98BDF7DE3BF9F7BFFF5D88826EFA3D9EEE46800FA8D6DF3BA2679E7926EB7CE3DFFEF8FCA79F7E3A3AFEC2EC88065B7CF566FCC5DFEDFEFBEFCF6EDF7BEFBD2BFD3BC6913B0F3CF0C02ADF73D1A245C96DB7DDD6ADCF8FF77BF8E1877B2D16962C5992FDDFE8EAF9471E7924993F7F7E767BE1C285C9934F3E992C5BB62CF9C73FFE912C5DBA54FCAD414B13B964C30D378C41DAC455EC9A8A5C5818D6FAFD6330F84A59045070AF6CEDAF067CBF3BD4F7A143753C1379D7E2C58BFB24F7ECCF1CB1BB2D7E9E9FFCE427C9A38F3EBADA63ED784DBC564C1723EE9F7DF6D9151EBBFBEEBB93871E7AA84FC75C0321EE8DA356DE86529CAE6A7EEB89279E58E1B3632E23E6A5CC37F5C9387E75AC6C85EEA9C37A7685AE7CD2FE7785D6B1FFB9E69A6B92E5CB97AFB0DD3DF7DCD3ABDF43DEA975D6FABB56179F5FF37DFE635AA5600E38E0807F1765856EDA49DD350856E816E65411D1C97FE52B5FC912A29D76DA29BBDF31B17DCF7BDEB3CA9617F5E2FCE95B6EB965A7EDC4134FECF43B6CBBEDB6C997BEF4A5E49FFFFCA723260758FCFDE637BF495EF39AD764B737D86083E4DC73CFED74BB18CCBDF9CD6F4E3EFAD18F26BFFEF5AFDBB5D881C736311177D9659725BBEDB65BF2C10F7E30BB1DEDFBDFFF7EF2BEF7BDAFAD9D75D6596D83C04D36D924F9AFFFFAAFEC3DB6D9669B76DB456B6E6ECEB6FDF18F7FBCC273B52D4F7022013AE18413DADACE3BEF9CACBBEEBAC9B1C71EDBEEF13BEFBC33DB3EBEFFEB5FFFFAECF6461B6D949C7DF6D9C9830F3E98FD7F8AFF0B8E2C5FB3981C66A518405FD3EF52D8F14C4C9ED5E66DEF7FFFFBB349AAFCF9FFFEEFFF4E66CC98D1ABB9671172C4D569E79D775EB2FFFEFB5F5CA9541E79E185179EEFC630FB3FE9EFE3B7DFFEF6B7FF9EFE5D2FB442B7FFE33E62EEAD6F7D6B72FEF9E7B77BFCBDEF7D6FF2C31FFEB04FC65C032DEEADD01D9A71DAB158BBE38E3B663117FFC63C66C7CF9F3C7972B2CE3AEB24A79D765AF6995124D9628B2D92CF7FFEF36DDFE3861B6E10A7BD378E5F9B62EEEDBD5CD4954FEAD7DADA05175C90BCEC652F6B2BA4461F147177D14517B5DBEEEF7FFF7BD6A7C4F3D1AF44DF56DBA64D9BD6969B8D1F3FBEAD1D70C0019DCE4FC60131F24EF1DF55FCC74A582B74E996C30E3BECE9A25C43F7D65B6FBD6E005F43B75017738F24F9B39FFD6CF28E77BC239933674EF2F6B7BF3DBB1F47FEE4DBDC75D75DD90EE088238E4866CE9CB9423BFCF0C3B3E763BBFCA8A05FFDEA57C9E9A79FDEAEBDE52D6F498E3BEEB84EBFC75FFFFAD7E495AF7C653269D22405DD01127FF951B8DD29E8C6D1AF51B48F3879E73BDF99B588B9B8BFFEFAEB67C94A6C77E69967763A79BBCF3EFB64711945D9B83F7BF6EC6C122FDEF3939FFC64F2C52F7E31D975D75DB3D79F7AEAA9592C8D1D3B36BB9D272E13274ECC0ABF31E0AB6DDFFDEE77B3F7CC8FC68DEF1FDFE9CB5FFE72972DB6BFF0C20BB3EF1D83C18D37DE382997CB0ABA3D18937D3098722D4700FD2E03643C73C9259724AF7AD5AB92E9D3A76793F91147318E89D510D1B6DA6AAB64EAD4A96D676DE98DDCB30839E29AE493A3468DDA23FD9DA5C3BB250F7735BE7EFEF9E76F9C366DDAB9E9DFF581D85ED41723EE63BCF5ED6F7F3B8BBB18D7444C45DB6CB3CDB2F8CEEFC7CA1871AFA03B94E334FF2EF7DD775FF2894F7C225B4C103F731469E37EED6ADC58B010F3059B6FBE79561C897FE3A0A078AF982F887F63C142A95412A7FD3B8EEFAC981BD7CC5DB793C77BAAA82B9FD4AFB53BF0248AB3EF7EF7BBB3A26CDCDE7AEBAD93B7BDED6DD9EDDA33101C7AE8A1C9C73FFEF1ECF6D5575F9D1D64182DCE761A31FAF39FFF3C7BEE97BFFC65F2A94F7D2AEBEBF6D8638F6C6153CC67467137F69DF17C6C1FAB82E59DE2BFABF8770D5DBAED88238EB8FFFAEBAF2F4441B7A5A5A53C72E4C8D903EC3FE2CA929D7E29E8C60E288EDE89A4353F3544FC478C9DD51BDFF8C6B6231DF3826E9C02218A671D5B9E48E705DDFC68CCCE92EFAE0ABAD17EFAD39F661335DD39ED8E8160FFC6DF8D37DE98C54E14413B2BE8C6113AF1FC2DB7DC92155E6340F4A637BD2979C52B5E916CB7DD7659C2317CF8F064D34D375DE1C8B648428E3EFAE8EC1426B16D0C0A6380B8D75E7B253FFAD18FB2F78D53271D7FFCF1D9E7C6F67FF8C31FB2F78ACF89E42A622DB68BDBF9CF1605DD612B59F1931774E3FBC4AA8F7C82308EC41BD67A045EFED8873FFCE1E48A2BAEC82615E3678E23F122E623693AE38C33B26DE23531B118AB866FBEF9661311AB19937D30A8EAADC282412030D0E97729DC78260ABA3149B5E79E7BC6D1FF6D93FA1DF3B9830F3EB8D772CF22E4886B9A4F8E183162A3F47777729AB73FF99FFFFCE7D99AA1F5D3D75D77DDE9E9730FA47FDB93623B115F9CB88F03A5A358F5FBDFFF3E99376F5E7656AD68AF7EF5ABB3B8CAEFC744AEB81FF205DD211DA751548EF88B988BD5BCF9D9E3A2C0FB810F7C203BAB57535353F6F9279D7452566C8E79A71D76D8215B2117FFC6FBC79C40ED5C9838EDB7717C57C5DC7556F2FCDA1675E593FAB5762D8AA0115B7160481C3898B798331F5653248DB35C461FF3BBDFFD2E3B80E4B7BFFD6DF6F8B5D75E9BF56B71C048ED299AE360957C0E75DF7DF7CD0E6889D7BDFCE52F4FBEF6B5AFB51574E59DE2BFABF81F356A5425DF2EE2B03FC5E7D7ACD0ADF80B164CFA9FFF8228D414C1B1C71E7B5E1A283F1C20FF11BB95ECF47541F7C0030FCC3AF548B2DFF08637B4DB3945721D3B9778BEB1B1B1ADA01BA74FE86C856EECB486B51674E368C7889358911B4716D5B638A54E4CC2C4F3713EFF8EDF294EA513EFD3D0D0A0A05BF0F88B5363478CFCE94F7FEAB4A0FBC73FFE311B08E5A7C28B23C462703761C28476936EDFFBDEF7B25393E4C9CD1D77DC910DA822A189F7896D4E39E5946CC016ED431FFA5016BBF9299423AEA64C99920DDAE2678855B971C45C0CFCE200814888E2142979413756895F7AE9A5C955575DD5AEC50AF1389AEEFFFEEFFFDA4E55326C25C5DF78EFFC77D1F1B426F1FCE73EF7B9ECDF384061DCB871D9CF652262F562B20F0657BD5158300804060BFD2E851ACF7456D08D2242ACD2CDCF1614078EC6A9367B2BF72C428EB8B6F9E4C891233F555F5F7F6BEAA1C71F7FFCB2F4F71313427F8BC7457AF1E23E0A4FB18230C63CDD3995ADB81F92055D719A6E3B66CC98ECF9287EC41C40EC2FF216D774CD0B30071D7450DB2AE158CCF03FFFF33FD9F651CC8D9F21560EC7FC96F9A67E1DC7AFAA98BBB2EDD6B4A82B9FD4AF7559D08D79EE8E97251C5653D0FDCE77BE93DDFFC8473E92EDF7E23221B1AF8BF9D1E807D75B6FBD6CDE320E3E89BE27F2D6384B40A552C90E4E8C8552A3468DCAE655A3F03AACB5A02BEF14FF2BD9A6392FA2C61952FB537C7E4D11BAD95FB060D2CE67C7C99327BF50807AEEBF478F1E7D731A249F1E4CBFDFBE2EE846121D45D738C2274E25D3B1C5E3B182370A5D7941F7A69B6ECAFE83C64E2A6F23468CC81E1FD65AD0FDCB5FFE929D3227AEA112FF46012D9E8B9592713F7668F16F5E64ABBDC87C24D0F94EAF76B5AF826E31E36F975D76C906449D157463601583A3782C8E847DDDEB5E97C5416C174785C5EA8938A5485C1B221E8FA3D96205783CD659921247CC468213071CC4A02E3F0A2E068F91C0449214D7CA8D09BEF85E710AA6386237066F79AC453CC7D16A5D254291F044BCE789501C49176725882386E3F9F8B9E27E1C9DD731697AED6B5F9B1DF010EF11D7B3B8FCF2CBB3D7C49172E2AFB093F63D5D58300804F4BBFADD21ADAF0BBAB1222B5653C541A3717DB3FC1ABABD957B162147EC897C72F8F0E1EBA73FDBE4745CF748FC1BF7456F71C7F17149A258DDB8DF7EFB65A7668C1613B37196ADFC7EC4A0B8378E1ACA711A0769476CC6E945E3A0F38E2D56ECC62AE298BB8A224A7CD728B2C425C7E260F458C91B67FDFA7FFFEFFF659F110596983313A77D9EAF75B798BBB2ED57B7A82B9FD4AFADB4A01BF39BD1C7E52DE6AD87D51474E37BE407A8C4B572E394CA71204ABE6024E64CA3801BFBCA934F3EB95D7F1607A7C42ADBB83E6E9CB5E090430E59A1A02BEFA4A3F477B97B5E448D4571FDA9BEBEFE859A82EEEEFE3A053375EAD475D3C1F373715DA2FEF4C0030F5C9106C8E2F83E76446BD7E2C2E9F9D18D9DB5FCC2EAB505DD28E28E1E3D3A3B75431C49142B236B0BBAB17D5C943D4E2911473C46812C9E8BA390E2A88D986C89A26FC7EF123BC4D8E9C5ED8F7DEC63D9648D826EB1E32F56674771BE634137928818A4FDF9CF7FCE1E9B3F7F7E56F88D98895335C7B525E2344B71F46DB4385D48C44C9C9E398EC69D356B5656A8CD5B1464F3D32AC5B528E208DA187045CB0F2C8855E551AC8DB889826E0CC06210981774E328B4486062B0164955DE2226E3144C91E8445CE631DCDDA3E0E29A14917CC5633128740DDD01555CE8C9C2824120A0DFD5EF9A58EB8382EEEEBBEFDE36911605DDB804473C16638FBCA0DB5BB9671172C49ECC2707DB787A308FE36312374E3B1B13C6F9E96AE376DE5A5A5AC4BD71D4908ED3D81F44D1388ABD2B6B7110508CFB77DA69A764D75D77ED349EBFFAD5AF263BEEB863DB7C8638EDB37C72758BB92B7B5D778BBAF249FD5A972DE607637E316F7156BFE83BF2FBB5AB5D639E3C169AC4429238702572D5FAFAFAB616B96A7EF681DA532E478137FAB3CF7CE633D9FC653E1F1FFB4D79275D49E36D93BABABAE7F2426A1CB4D41FE2736B8AB9CFC5F7F2D729A04993265D14477AF4A7638E39E6376990CCB2235AFB16097074EC71947BEC6CF21609723C1ECF7756D08D899328EC47A2DD5941374E7D16D740896DE3A8C9782EB68B626EEDD143B5897FECB8A2D816F723C18ED5BA7194A5826E71E32F0AFEF1B7FDC10F7ED0AEA01B1D794CB8C56999F36DF3235DBB6A471C7144DBB671A4ECE69B6F9E2543F13E918CE483B6783E4EA31447BDC5ED5B6FBD358BC558911BDBC4D16C9160C5D1C0175F7C715B41B7B36BAC75D6E288E23C698A23832306E348DE782E0AD771BFF628B8F3CF3F3FD97EFBEDB302767E5A938E4953EDEF41FC15AAB8D0538505834040BFABDF6558DF147463E23F0E2A1CD6BA42214E2D17078ED616747B33F7ECEF1C513E39F4C6F1F901D2718ADA38CD78C4685C7A262E611463ECDA31B3B817F743354EE3524F871D7658D6E2D24FF119713BE6B7629570DC8E4B30C5294FF3B37DEDBDF7DED92AB7D8774401378ABD71EDCB28D4E4DB89D33ECB27D7B498BBB2D7AFAAA82B9FD4AFADB4C5A5DC629F17FD4DB55ACD56BFFEFCE73FCF9E8B53287FEB5BDFCA6EFFE217BF688BBB583012796A1C1812B9692C3C89DBDFF8C637DA5D433756ECC6D903E27ADD71204C5C82302E8918B7A3DD7EFBEDF6BFAC545D5DDD797931350E7EEA0FF1B93505DDF3FC550A6AF4E8D1EF1A3366CCBF22D1E90F4F3CF1C43569803C1CDFC38EA8E70ABA8F3FFE78BBC7E3FEB09514746B93A4CE0ABA0F3DF4505B012D12EE61ADE7EDDF6CB3CDB29D51EDC5E0E300812802C6D194B5DF217644714467BCB7826E71E32F8E5A8D84A6B6A01BAB5EF3D8C95B1C311B2D56CD464213AFCB1F8B6BDEC660AF76D03667CE9CEC761468F3415B5CCF2612AA88A3484CE2F94F7FFAD3D9445E9C82241295E9D3A7275FFCE217B3EF112B70E328DC485CA2CF7AECB1C7B2442B2602E3F425713F6235E2330E2688FBB1DDDA5EA7A263D2B4C71E7B747A2083F8EBF7C9FC9E282C180402FA5DFD2E7D309E89DC2A563C449E181359C71C734C7600DFA9A79E9A3DDFB1A0DB5BB9677FE788F2C9A1378E8F49B298208EDB471E796416538F3EFA68763FC6D85FFFFAD7C5BDB817A7ADDB4781245E93FFBCB12A381616445C76FCCEF159B14238B65D7FFDF5B3B981B8966E9CFAD47C539FE793FB0E5BF3626EAEB3A2EE3EF249FDDA9AB4587D1BFD532C14897FE394ECD10745DF13972F8CDBD16FDC73CF3DD94293782CE64163FF16672288F788B9D128D2D6BE6F1C8C985FD736FAAF38D824E6BFA3FF8C330EC4ED68711D5EFB5F5626FD7B6E9F17536385785FAFD28DCF1B356A54DBE996E3FBF8AB14586363E339717A94FE907EF6D9699034D911F56C41F79BDFFC66ED1115D9A920867551D08D9D415C003E6F7124661C5D14CFC72996E37A24B103D972CB2DB3CE3C767EC35A4FB91CA7998895B7FFBFBD7B01B2ABAE0F072E8F2AA01544B04E112B288DC58A967690581DA3680B858A74389C3D09221A0151C8EE461E02A504860E0F11D8DD84470B96E2C08838541019FC6FF65E12B1415E02F29077082621101E2148122A9CFFF91E73334BD8BC36DCDD7BEE7E3E33DFD9DD7BEF3E38F9F2FB7E7FF77BCFB97139DC287031708BE63A5E01D918A435225ED519979C885717350A99816EEBE45FBC3AADF1CAB1680AA2F188CFA3D189F7B369DC178F8B8D59BC5A2C365FD1F0C4136F313C7DF4D147CBF7A58957B935DE5BA2B1698B8D545C3E3986AF8D4D5BE4E5673FFBD9F255B6F1FDF1D878C56FBCE236DEAB397E5EBCF7F32EBBEC5236409167F1FD8D4B8545C4ABDCE27D72E2318B162D2ABF3FF2332EED34F8BF2F7E4EB1DE94AF606B9C897CDB6DB7955FC799E9B1316CBC78E1D4534F2D733EEE8FBF3D5EF4D0B87C53BC322F7E573C0129FF5A6EB8B0B183059B40C0BA6BDD6584F6337169CE9D77DE39DF7DF7DDCB27D3E22D5AA2BF8A5E2C2ED319BD60A3DF6A66EF39DA3DA27E726CE57D3C511CFBE5C89338F331F65CF1E285344DCB4B2BC68B58637F7DCF3DF7C87B793FE6F3349EBF8AF7548FDF1DC3E218F8C615B8DEF39EF794EF4DD9384B78C18205E573585FF9CA57CA2B7DC5202686BBF1364CF17C46FCCCB83F9EAC96A723D64F0E1EC60E6798BB213F473F695D5B679C78E289E5D501E284A45887E28CDCF87D71C598B81265D4C4380969DAB469E55501A3378D752EAE1A106B4FD4C6786E34D6C3F83C22DE06EEA28B2E2AD798B85265AC4571824C449CEDDB380338A25157D55FD6A6A3A3E396C62C27AE563192E2F70D9A25DDE25FA3C52549B27DB1D0BC1CC3BB9174FBEDB7C7A5969F8EDFAF10BDB903DDC30F3FBC7C1F93461C76D8616B1CE8AEFE33A2B98EFBE2520F51E8EEBEFBEEF2558E71099B934E3AA9BC2F9E60699C951B85250A4A5C96394ECD8FC63C9AFAA1FEBEE79F7FBE1CCC35F3BD4B14A2E1E55F6CBCC68F1FBFCE88C7C5ABC2A29988C17D343F8D57CA466EC4C6EF9FFFF99FCB01FEE04D5B5C92249A9C688656BFACD2EA1103DBB80453BCA74EE461FC9EB82D9AA368B462B0BCFAFB60C4654D8E38E288557F436C20D7F4DFDA18FAC61389ABDFD7B8B44ABCE2389AB8F7BDEF7DE5DF1D9BD13DF6D86355FE375EA127FF5A6AB8B03183059B40C0BA6BDD6504F733F1FE8B7BEEB967D9B3C50B45A3CF8C3322E26A3F9153F12458E3C9FA66F79EA3D923EA27C756DE47EE449E44BEC6BE2AAE8E153975ECB1C7967BE9C8A75D77DDB53C2352DECBFBB19EA771E65B9C58102FEC8EEF993C7972F93BBFFFFDEF976FCB14CF7B350624F1A2F075450CA7E5E988F693317C3DE42DC31FE6AECFCFD14F5AD7D62BE28CD6783FDCF83C5E9C122FF668EC6362681A2733C573E431588DB35EE3B9F4461F9A2449F97EBBAB479C1C37F877FCF6B7BF2D9FC31C2AE28428F59775C9B26C7C4747C7AB8DC16AFCDB8F84F83D8386B9AFC6DFE15FA3028AE6E94B471C71C4B218B88D84A79F7E7A5691204F14F14585E8CD8B785F90386371F02590079FC9B874E9D2558F8B274C1A5F0F8E38CB3186FB430D65A3118F57CC479E8CD67BE12A44AD917F7166F75003FBA1722306AE8D5C8B5799C560365E00101FD7F4F31B6778473EAE9E9F6BFB9BE23D73D6F69846FEC759E243E57F346FF1B7C5E743FD7FB464C992216F977F2D315C18EE60C12610B0EE5A7719E17E327AAAA1DEFB2BFAACB86FF5BD48B37BCFD1EA11F593636F1F15EF0DBAB6FB07E7A9BC97F7F274CD35C4F34D6DD34F56E5F7D146CFA3C71AD7B834FC68AD1BEA2F4349D374C6E04B2FC7C0BF99E2E70FBED472FC7EFF0A153279F2E4538F3FFEF897E37FDA662A169CFB8B84BCAD4896131422A1C1967FF28F376973369CC1824D20807517FDA47E12792FEFE5A990A7A3D34FB6F2EFC1BA665D63441D7AE8A15B747474DCD518B0C65B0D346BA81B3FB7F87DAF0E3A3BF7AEF8FDFE152AE690430EB9FC98638E79A15967EA3EFDF4D337C530B748904B1422A110C93FF9C79BB849DBD0C1824D20807517FDA47E12792FEFE5A990A7A3D74FB6DACFC7BA26AC6BA3AAA3A363C7229E1C7CA6EE75D75DF7A6CEE8E2E70D3E3377E5EFDBD1D1AFA84993269D3479F2E417DFECF7D45DF99EB9F3DAFDCC5C854821927F4223342A9BB50D192CD804025877D14FEA2791F7F25E9E0A793ABAFD642BFC5CAC6BC2BAD652B22CFBF0E0A16EC459679D953FF9E4931B359F8BEF8F9F33F8E7C6EF89DFE7A8575CBCB7EDC1071FFCFC85175EB820AEE5BE315E78E1855F7577775F55FCCCA7DBF93D7315228548FE09F937AA9BC1F51D2CD804025877D14FEA2791F7F25E9E0A793AFAFDE468FD3CAC6BC2BAD6D2569EA97BD7E0E16B9CAD7BF1C517E7BFFBDDEF36683E178F8FEF5BEDACDC7CE5CF77666EBB28FE81B72BFE417BBEFCE52F2FB9ECB2CB1E7DE69967FE6F03F2E4FFE6CF9FFFCB534F3DF5CA9583DC9EF8790A915088E49FFCA3499BB7F5192CD804025877D14FEA2791F7F25E9E0A79DA1AFDE448FE1CAC6BC2BA5629F19EB6699ACEE8E8E8587D109B777575E5575C71457EC71D77E48F3EFA68FEECB3CF9643B9F8185FC7ED717F6767E71BBE377E5EFC5CEF99DBA6264E9CB873F18F7C7196654F1F76D8614F5C74D145BF9E3D7BF63D0F3EF8E0BCC58B17BF54E4C9D2A79F7EFAB1FBEEBBEFF6E27FF6FED34F3FFD9AE27BEE29BEE7A9F8BEF87E85482844F24FFE31CA9B389B4000EB2EFA49FD24F25EDECB53214FF59358D78475AD32B22C1BDFD1D171CB1083D9E1C42DF1F31CD5B16193830E3AE8EF8B7FF033D234BDAEF8C7BF75D0B5BCE3E3AD717BDC1F8F8BC72B440A804224FF8446A8053683368100D65DF493FA49E4BDBC97A7429EEA27B1AE09EB5A256559F6858E8E8E6B8A58B18143DC78FC35F1FD8E2228440A91FC13F2AF953783368100D65DF493FA49E4BDBC97A7429EEA27B1AE09EB5AE51D7AE8A1DB7474741C98A6696FF171A088C78B7879E5F0F6E5955F0FACBCFFC078BCA3060A914224FF84FC6BF5CDA04D20807517FDA47E12792FEFE5A990A7FA49AC6BC2BA06A0102944F24FC8BF16DC0CDA04025877D14FEA2791F7F25E9E0A79AA9FC4BA26AC6B000A914224FF84FC6BC1CDA04D20807517FDA47E12792FEFE5A990A7FA49AC6BC2BA06A0102944F24FC8BF16DC0CDA04025877D14FEA2791F7F25E9E0A79AA9FC4BA26AC6B000A914224FF84FC6BC1CDE031368100D65DF493FA49E4BDBC97A7AD112FBDF4527EEFBDF7961F37E67679AA9FC4BA26AC6B000A914224FF84FC6B93CD604747476E13083032C68D1BD7B9C5165B5877F593423F29EF85BC97A76B8C18CE167F72F971636E97A7EDBB8F7F8B612EEAAF750D40211206BAFEDDE5DFD8B272A00BC0C8ACB9F52449ACBBFA49A19F94F742DECB53035D36C6560E01EAAF750D40211206BA42FE8DADE182E30C3032EBED84587357C60447443F29F493F25EC87B796AA00BA8BFEA2F8042241422F927FF589F0183E30C3032EB6D7DD040B7EE88E827857E52DE0B792F4F0D7401F557FD055088844224FFE41FEB3360709C019ABFD60E3E3BD759BAFA49A19F94F742DECB53035D40FD557F011422A110C93FF9C77A0F191C6780E6AFB5F52106BACED2D54F0AFDA4BC17F25E9E1AE802EAAFFA0BA010098548FEC93FD63964709C019ABBCE0E7576AEB374F593423F29EF85BC97A706BA80FAABFE0228444221927FF28FF51A3438CE00CD5D67EB6B19E83A4B573F29F493F25EC87B796AA00BA8BFEA2F8042241422F927FF58EBA0C1710668DE1ABBB6B3739DA5AB9F14FA49792FE4BD3C35D005D45FF5174021120A91FC937FAC73D8E03803346F8DADAFC740D759BAFA49A19F94F742DECB53035D40FD557F011422A110C93FF9C71A870D8E33807517FDA47E12792FEFE5A981AE3C05EB9AB0AE0128440A91FC13F2CF600100EBAE7E52E827E5BD90F7F2D440579E82FAABFE0254DAC0C0C06BCB962D53045A208A7F870545215A2EFF84FC335800C0BA8B7E523F89BC97F7F2D440579E82754D58D7004AB367CF5EB068D12285A005E289279EF86151886E957F42FE192C0060DD453FA99F44DECB7B793A32F1D24B2F95C3D9F8B831B7CB53B0AE09EB1A40D3D46AB5FD6FBAE9A6250B172E5C5CA557182D5FBEBC9D5E51B470EEDCB9571645685E11FBCA3F21FF0C1600B0EE32B6FAC9050B16E827B18F92F7F254C853B0AEE93BAD6B006B168B5FBCA2A5881571EDF9568FFFFCCFFFCC274D9AB4EAEBCB2FBF3C8F27EAAAF0B7AF2156AC3CFEFBCABFFE5CC83F830500ACBB8CA57E72CE9C39F939E79C935F73CD35FA49ECA3E4BD3C15F214AC6BFA4EEB1A40F52549F28E8E8E8EF9699AFE7ED09374754FD4015561BD02B0EE42439EE7EF58B264C9B2C58B17E793274FFEB923020080BE1380CAEBE8E838379E942BE20F871E7AE816C5C7092BBF8E98E008011558C70C1600ACBB507AE491477E96AF54ABD59EC9B2EC20470500007D27009595A6E9EE31C86D0C708BAF2735CECE5D197547096875060B00D65D088F3FFEF8675E7DF5D5C6F36AF96BAFBDF6EAC9279FBC284992AD1D1D0000F49D0054CEB469D336EDE8E8B875D0F036CFB2ECCEC15F3B4B17A802830500EB2EE479BED9A2458B9ECE5713B74D9A34E942470800007D2700959365D9D1430C6F870A67E9022DCD6001C0BA0B0F3DF4D079F91A5C79E5952FA469BAA7A3040080BE1380CA489264878E8E8E25EB39D075962ED0D20C1600ACBB8C6D0B172EFCC0F2E5CB5F5DD3136B7FF8C31F5E9E3265CAFD13264CD8DCD1020040DF094025A469FAE30D18E63A4B176869060B00D65DC6B679F3E6DD9BAFC3FDF7DFFF549665C7395A0000E83B016879699AEEB781C35C67E9022DCD6001C0BACBD89524C96677DE79E78A753DB1F6DC73CFFDA2C8DD67E2F18E1A0000FA4E005A5A514C0E2BE2BFD234BDB1F87867114F3A4B17A8F8BA66B00060DD650C3BF9E493FF7DC58A15FFB796E7D55EECEEEEAE39530200007D27009515EFA77BF0C1078F4BD3F463071D74D0E78B8F933C510754680DB35E01587719C3E23DCAAEBAEAAAF96B7A56EDF6DB6FBFACC8DBBBBD97190000FA4E002A2949922D8B22F3F2EAB77BA20EA80AEB15807517BEFAD5AF7E72EEDCB9AFACFEA4DAABAFBEFAEB499326FD2E4DD33D1D250000F49D00545292243B7574743CBEFAED9EA803AAC27A0560DD8570D659675DFD5A61D0F36A7F88DB8A9CBDC0D1010040DF0940651545E69345CC19E2764FD4015559C7AC5700D65D8817AB6EDDDFDFBFB4F1ACDAC2850B7F58E4EBEFE276470700007D27009595A6E9BF14C5E69AD56FF7441D5015D62B00EB2E347476761EF2FCF3CFBFB278F1E2FC6B5FFBDA6FB22C3BC851010040DF0940A51585E69B435D0AC21375405558AF00ACBB30D845175D74C739E79C9317B97A83A3010080BE1380CA2B8ACD69699AFEDB10B77BA20EA8CA3A66BD02B0EEC22A4992EC14791A1F1D0D0000F49D00545E5170FEA388C387B8DD13754055D631EB15807517E4290000FA4E00DA539AA6D71545E78B0A11A07106C0BA8B3C0500007D2700AD57706E9D3871E21E0A11A07106C0BA8B3C0500007D2700AD5770E62549F27E8508D0385365799EBFF5B1C71EFBD19C39735E191818C8FBFBFBC5084771DC5F9B3D7BF6825AADB6BF8CB4EE823C050040DF09006F5EC1599124C95B152240E34C953DF6D86357CF9E3D3B5FB46851BE6CD9B27CC58A156284238E7B1CFF9B6EBA69497F7FFFBEB2D2BA0BF21400007D27006CA42449B62D0ACE730A11A071A6EAE2CCDC18261AAC8E7E2C5CB870717F7FFFADB2D2BA0BF21400007D27006CA42CCB3E52149CFB152240E34CD5C565969D99DB3A67EAF6F7F72F9795D65D90A70000E83B0160E38BCD5E5996D5142240E34CD5C57BB81AA6B64EC4BF87ACB4EE823C050040DF09001B294DD34945C1B942210234CE54DDFA0E745F7A6161FED86DFF95DF37F3B432E2F3B8CD10D64017EB2EF2140000F49D00B49C2CCBBE5DC4F7142240E34CD5ADCF4077E9F3F3F37B7F7E727EF7CF8E7D5DC46D719F41AC812ED65DE4290000E83B0168B562F3DD344D8F5588008D3355B73E03DD27EFBBEE0DC3DC46FCEEBE9F1AC41AE862DD459E020080BE1380962B363F28E2CB0A11A071A6EAD667A0FB40FDAC350E74E33E8358035DACBBC8530000D07702D052B22CEB2FE20B0A11A071A6EAD667A07B6FFFB4350E74E33E8358035DACBBC8530000D07702D06AC5E63793264DFAA84204689CA93A035D035DACBB204F0100D07702D08EC5E6992449B65788008D3355B73E03DDFB669EB6C6816EDC67106BA08B7517790A0000FA4E005AC6E1871FFE2745B179A5F874138508D0385375EB33D07DF897D3D738D08DFB0C620D74B1EE224F010040DF0940CB48926487A2D8CC5788008D33ED607D06BACFCEBF27BFF7FF9DF2C6CB2D17B7C57D06B106BA587791A70000A0EF04A0950ACDDF1571874204689C6907EB33D08D78FCF6CBDF30D08DDB0C610D74B1EE224F010040DF09404B49D374BFA2D85CAF10011A67DAC17A0D74972FCF1FFEDF0BDF78B9E5E2B6B8CF20D64017EB2EF2140000F49D00B48C2CCBBE5E149B4B142240E34C3B58D74077E9F3F3F3877ED9B7C6F7D08DFBE23186B106BA587791A70000A0EF04A0550ACDBF665976BA4204689C69076B1CE82E5F9E2F7CB896FFE6C613D738CC6D443C261EEB6C5D035DACBBC8530000D07702D00A85667A9AA647294480C6997630D440775D67E53A5BD74017EB2EF2140000F49D00B4AC344D7F5C149B03152240E34C3B186AA0BB3E67E5AEED6C5D8359035DACBBC8530000D07702309A85E6E62CCB3EA510011A67DAC15003DDE10E731B61306BA08B7517790A0000FA4E0046B3D03C9224C987142240E34C3B58E37BE80A035DACBBC8530000D0770250D142F3529224EF5088008D33EDC040D74017EB2EC8530000F49D00B48D18E4C64057210234CEB40B035D035DACBB204F0100D07702D036E252CB71C9658508D038D32E0C740D74B1EE823C050040DF09403B15994F1771B34204689C691706BA06BA5877419E0200A0EF04A06DA4699A1485E66A8508D038D32E0C740D74B1EE823C050040DF0940DBC8B2ECE8A2D0F4294480C6997661A06BA08B7517E4290000FA4E00DAA9C8FC7B9AA627294480C6997661A06BA08B7517E4290000FA4E00DAA9C85C5AC4648508D038D32E0C740D74B1EE823C050040DF0940DB48D3F46745A1D957210234CEB40B035D035DACBB204F0100D07702D04E45E68E891327FEAD4204689C691706BA06BA5877419E0200A0EF04A09D8ACCFC2449765088008D33EDC240D74017EB2EC8530000F49D00B48569D3A66D5A149957264C98B0B94204689C691706BA06BA5877419E0200A0EF04A02D2449B27D51649E5188008D33EDC440D74017EB2EC8530000F49D00B4852CCB762B8ACC6F142240E34C45FE7DEB454C58D7E30C740D74B1EE823C050040DF09405B48D3F41FB22CEB5788008D3355F9F75D196B1DEC1AE81AE862DD05790A0080BE1380B690A6E9214591B95C210234CE54E5DF77B51872B06BA06BA08B7517E4290000FA4E00DA429665C71571B64204689CA9CABFEF1AE275835D035D035DACBB204F0100D07702D02E05E6DC344DA72A4480C699AAFCFBAE23CAC1AE81AE812ED65D90A70000E83B01689702736511131522A09D1A67219A3DD05DB264C91B6E5BB46851FEC8238F0CF9F8279F7CF2755F3FF1C413F90B2FBC30E463172C58903FF0C0031BF4F7C4EF9E3367CE1AEF7FE69967F2FBEEBBAFFC7CEEDCB9E5EF5EB66C59FEDBDFFE365FBA7469D307BA72B2FD43F5C1136B0000A0EF04A049B22CAB15F139850880AA6C8C46FB92CB3104DD6EBBEDF2EBAEBBAEFC7AC68C19F917BFF8C5BCA7A727DF7DF7DDDFF0F8DFFFFEF7F94E3BED944F9D3AB5FCFAFAEBAF8F9A9A7FE10B5F78DDE3162E5C98FFE217BFC8BFF4A52FE51FFDE847CBCF234E3EF9E47CD75D775D153FF8C10FCAE1EC19679CB12AF6DD77DF7CD34D37CD4F3FFDF4D7DDFEF0C30F973FFB8A2BAEC8B7DF7EFBF2F3ADB7DE3ABFEAAAABF2F9F3E7977FC7EDB7DFEE0C5D604CD40F470100007D2700552D30F72749B2AB4204405536466B1BE43634FB0CDD18CEBEF5AD6FCD67CE9C590E6B8B5F996FBEF9E6E5C72DB6D822FFF33FFFF3558FBDF0C20BCBDB7FFEF39FE78B172FCE77DC71C7FC2B5FF94AFEA77FFAA7E510B8F1B8CB2FBFBC7CDCEA71C82187E49FFAD4A7F2EF7EF7BBE5D73148BEFAEAABCBDFB7F7DE7BAF31E2B137DC7043FEE8A38FE6C71D775CBECD36DBE403030306BAC098AD1F8E020000FA4E00AA5A609E4B92645B850880AA6C8CD636C86D1889F7D0FDFEF7BF9FDF7CF3CDF9565B6D95FFE4273FC93B3B3BF371E3C69567D5362E7F1C97338E01EEBBDFFDEEFCA9A79E2A07B371F66DDC7EC925979467D59E75D659AB7E660C5E4F3BEDB47CF9F2E5F9E73EF7B9FCD24B2FCDBFF6B5AFE5071F7C707EF6D9679767D9C619BF311CFEC8473E923FFEF8E365C4EF7BCBCAA171E3B68F7DEC63F92F7FF9CBFCBCF3CECBDFF6B6B7E59B6CB249FEE10F7FB81CE8FEF77FFF77F998F89E69D3A6E5E3C78FCFEFB9E71E035DA0ADEB87A3000080BE1380CAD9679F7DDE561498E50A110015DA18AD7590DBD0CC816E0C4D4F39E5943262581AC3DABFFCCBBF2C87AD71766E7C1E71FEF9E79767E0167F4EFEAE77BDABBC5CF2DBDFFEF6BCAFAFAFFC39F7DE7B6F7EC001079443DD134F3C317FE8A187F2238E3822FFC0073E509E811BDF77D1451795C3DC88DD76DB2D3FF2C82357FD1D7119E5B70C71466F23BEF7BDEFBDEEB1832FB91CF77FFAD39F2E3FC6DFF48D6F7CA3FCFD06BA401BD70FEB100000FA4E00AA274992F71705669E420440BB69E64037CE9ADD6BAFBD565DD2F8DC73CF2D07B28323CEBABDFBEEBBF32CCBF2F7BCE73DE525988F39E698F27BE352C9F1734E3AE9A4F22CDC6BAEB9A63C9376CA9429430E66E3BD76E3E7FCD55FFD5539F01D3CA4DD76DB6DF33BEEB8A3FC3BE2B131088EAF3FF8C10FBE61A0FBCE77BEB3FC5D31D08DF7DA8DB38BE37BE277BBE432D0EEEC670000D0770250D5E2F289226E5588006837CDBEE4F2C2850BCB61E8C30F3F5C9E35FB962186B0F1B818AEC659BA8DF7D48DF7BF8DF7DE1D3CD06DFCCCB8CCF2C5175F9C5F70C105ABE2A73FFDE9AA4B2EFFEA57BF2ABF77DEBC791B74866EBC5F6E5C7E396EDB679F7DBC872E3056F73ED6210000F49D00544F9AA6FB1705E65A8508807633D203DD2449CAF7B68D38E18413560D7423A64F9FBE6AA01B97688ECB310F35D08DD86CB3CDCAF7DC8DF7BADD669B6DCA016C63A01BF7C7FBE636DE733706BA7129E75B6EB9A51C14C7DF73E59557965F0F3E43F7DA6BAFCD3FFFF9CFE7DB6DB7DDAA4B2EAF3ED07DE9A5970C7481B6663F030080BE13804ACAB2EC88A2C05CAC1001D06E9A3DD08DCB2917BF26BFEBAEBBCA816E9C39FB677FF667656CB5D5566B1CE87EFDEB5FCFF7DF7FFFB50E746FBCF1C6F2F3A38E3A6AD540F7339FF94C7EDC71C795EFD71BC3D88D7D0FDDD507BA071D74D0EB1E6FA00BB41BFB190000F49D0054B5B89C9265D9A90A1100EDA69903DD1884EEB0C30EE519B43BEFBC73F9BEB69D9D9DF9F1C71F5F9E9DFB9DEF7C273FF3CC33CBCB2D0F1EE83EF0C003F9965B6E595E82796D03DDB86DD2A449F9B871E3560D740F3CF0C0FCB39FFD6CFE8D6F7C237FF6D967CBC7CE993327EFEEEE2ECFAE8D33858BFFECFCB6DB6E2BBF3EE38C33F2993367968F7BEAA9A7F2534F3DB51CE8C6FDF13B3EFEF18F9783E5F89EF8FB76D96597557F97812ED0A67B1FEB100000FA4E002A595C2E4CD3F44885088076D3CC816E9CED1AC3D6175E78A1BC84725C1E79DB6DB7CDDFFEF6B7E75B6CB1C5AA98366DDAEB06BA31308D41EACB2FBFBC6AA0BBD75E7BBD61A0BBDF7EFB9583DBB8BCF2EA975C5E53CC9D3BB71CCEFEFAD7BF7EC37D975C724979DF01071C50BE27EFFBDEF7BEF2E70F0C0CE47BECB147795FFC7DF7DD779F812ED0CE7B1FEB100000FA4E00AA274DD3FF290ACC010A1100EDA6D9975C5EB468D17A3F76C99225E559B2AB7F5F9C49FBE28B2FBEEEB18F3CF248BE74E9D25567D62E58B0A07CBFDEF8B8B6DF11EFDD7BEBADB7AEFADEC111BF277E467CBE7CF9F221FFBEA16E37D005DA89FD0C0000FA4E00AA5A5CE66459365E2102A0DD347BA02B0C7481CAED7DAC430000E83B01A86471793C49929D142200DA8D81AE812E80FD0C0000FA4E00DAA1B82C4B92644B8508807663A06BA00B603F030080BE13804A4B9264EBA2B82C518800684706BA06BA00F6330000E83B01A8B42449C615C5E5418508807664A06BA00B603F030080BE1380AA1796095996CD528800684706BA06BA00F6330000E83B01A8B4344D8BDAD2F1438508807664A06BA00B603F030080BE13804ACBB2ACAB88F3152200DA9181AE812E80FD0C0000FA4E00AA5E58CE4CD3F43B0A1100EDC840D74017C07E0600007D2700552F2C971571A84204403B32D035D005B09F010040DF0940A5A5697A6396657B2B4400B423035D035D00FB190000F49D0054BDB0DC3571E2C48F2B4400B423035D035D00FB190000F49D0054BDB03C9524C97B152200DA9181AE812E80FD0C0000FA4E002A2B4992CD8AC2F24A7C548800684706BA06BA00F6330000E83B01A8AC383337CED0558800685706BA06BA00F6330000E83B01A87251F99B780F5D8508807665A06BA00B603F030080BE1380CA4AD3749F226E548800685706BA06BA00F6330000E83B01A8AC344DBF5A1496FF528800685706BA06BA00F6330000E83B01A8AC2CCB4E28E20C8508807665A06BA00B603F030080BE13802A17959E344D3B152200DA9581AE812E80FD0C0000FA4E00AA5C54AE2A22558800685706BA06BA00F6330000E83B01A8AC2CCB6615F1198508807665A06BA00B603F030080BE13802A179507932419A71001D0AE0C740D7401EC670000D0770250E5A2B2244992AD152200DA9581AE812E80FD0C0000FA4E002A2949922D8BA2F2B24204403B33D035D005B09F010040DF0940252549B25351541E5788006867030303AF2D5BB6CC30B505A2F87758D0DFDFBF5C5602A3C97E0600007D2700552A289F2C628E4204403B9B3D7BF682458B1619A8B6403CF1C4133FECEFEFBF555602A3BC0FB29F010040DF094035A469FA2F4551B9462102A09DD56AB5FD6FBAE9A6250B172E5CEC4CDD513B3377E1DCB973AFECEFEF9F57C4BEB212184DF6330000E83B01A88C2CCBBE5914950B142200DA5D0C11E3CCD02256C47BB88A118F152B8FBF612E30EAEC670000D0770250A582725A9AA6FFA61001000063681F643F030080BE1380CA1494FF28E270850800001843FB20FB190000F49D0054439AA6D71545E58B0A1100003056D8CF0000A0EF04A04A05E5D6891327EEA11001000063681F643F030080BE1380CA1494794992BC5F21020000C6D03EC87E0600007D27009529282B922479AB420400008CA17D90FD0C0000FA4E005A5F9224DB1605E53985080000184BEC670000D07702500959967DA42828F72B440000C058623F030080BE1380AA1493BDB22CAB29440000C018DB0BD9CF0000A0EF04A0F5A5693AA928285728440000C058623F030080BE13804AC8B2ECDB457C4F21020000C612FB190000F49D0054A5987C374DD363152200464AF2A31F6DF6ED73EADBADF38179BEC9D1BD37BCB3F1E53767D4DFE1E801F026EE85EC670000D07702508962F28322BEAC10013052BACF1DD8A1ABB77E5D7CDED5533BADABB776EDE0E8EEA9EF5DDED7579FD0DD53FB71E3FB3A7B07EEEC9A3E73FCF117F76F3D6D5A7D734712808DDC0BD9CF0000A0EF04A0F56559D65FC41714220046C2B133EAEFEDECABFD63575F6DD6949EFA5F77F5D606E2EBA9BDB58F35E2C80B7EF1AE786CF198CBBAFAEA5F8ACFA7F6D4FEA9AB77E0A1E2F1D717B1B4B8EFEF1D4D003686FD0C0000FA4E00AA524C7E3369D2A48F2A44008C84CEDEDA2145CCE9EAAD2DEEECAB5FD3DD5B9B39B5B7BE67D779F50F447C7BFAC05FC4E3E2F2CA5DBD03F7744EAFEFD7D9539B513CFEC1F231D3678E8F21B02309C09BB017B29F010040DF0940258AC93349926CAF10013052065F723906BA5DBD0357FFF16CDC227A6BCF94B7F7D53B3B7B6B0FC459B99DBD038715B7BFD8D957FB590C8263A05BC47C4712808DDC0BD9CF0000A0EF04A0B51D7EF8E17F521493578A4F375188001829E5A596FB6A8F96EF97DB5B9B1903DEC67DF13EB9F1B1FBDC1BB72D3E3FAAB8FFECF8BA78EC6DE5C7BEDAACC15F03C070D9CF0000A0EF04A0E52549B243514C867D86934204C086EAEAAB9DDCD55BFFDFB8EC725C56F98F67E8D62E2D3EF644149F3F158F3BBA77E083C5631676F70E9CD9DD57EB2E6EBF3BCEEA2D3ECE5BF971AEA309C0C6B09F010040DF0940150AC9DF1571874204C0481A7CC9E5F2F2C97DF5099DE7D7C6454CE999B54BDC3EA567E0935D3DF56F759E3F73B7A37B6F78E7EA67E41ED5376BA7E2F19F703401B09F010040DF0940DB4AD374BFA2985CAF100130923A7BFADF3FF83D74BB7B07F6983A63D68E8DE83AAFBE4DF78CFA87BAFAEAA7C499BC5D3D03E7C7A598E332CC8D9FD1D5533FA9B86F8AA30980FD0C0000FA4E00DA5696655F2F8AC9250A110023656AEFACBFE9EAADDD15C3DAF8BAABA7765AF1F54F0647676FFD88AEBE817DBA7AEB9362B8BBF2712714F7FDAA71B9E6E2F32BBF357DE6BB1D5100EC670000D07702D0CE85E45FB32C3B5D21020000C6E07EC87E0600007D27002D5F48A6A7697A94420400008CC1FD90FD0C0000FA4E005A5B9AA63F2E8AC9810A11000030D6D8CF0000A0EF04A00A85E4E62CCB3EA51001000063703F643F030080BE1380962F248F2449F221850800001883FB21FB190000F49D00B47C21792949927728440000C018DC0FD9CF0000A0EF04A075C5203706BA0A1100003016D9CF0000A0EF04A0A5C5A596E392CB0A1100003016D9CF0000A0EF04A0D58BC8A78BB879630B91104208218410425435EC0C01001881E7E2F59D000C4F9AA6495148AE76240000000000A0390C740118B62CCB8E2E0A499F23010000000000CD61A00BC0C614917F4FD3F424470200000000009AC34017808D2922971631D991000000000080E630D00560D8D234FD595148F675240000000000A0390C7401D8982272C7C48913FFD691000000000080E630D00560638AC8FC24497670240000000000A0390C7401189669D3A66D5A149157264C98B0B9A3010000000000CD61A00BC0B02449B27D51449E71240000000000A0790C740118962CCB762B8AC86F1C090000000000681E035D0086254DD37FC8B2ACDF91000000000080E631D0056058D2343DA42822973B120000000000D03C06BA000C4B9665C71571B623010000000000CD63A00BC0700BC8B9699A4E75240000000000A0790C7401186E01B9B288898E040000000000348F812E00C3926559AD88CF39120000000000D03C06BA000CB780DC9F24C9AE8E040000000000348F812E00C32D20CF2549B2AD23010000000000CD63A00BC006DB679F7DDE561490E58E0400000000003497812E001B2C4992F71705649E23010000000000CD65A00BC0708AC7278AB8D591000000000080E632D0056083A569BA7F5140AE7524000060F4253FFAD166DF3EA7BEDD3A1F98E79B1CDD7BC33B1B5F7E7346FD1D8E1E0000B43E035D0036589665471405E46247020000465FF7B9033B74F5D6AF8BCFBB7A6AA775F5D6AE1D1CDD3DF5BDCBFBFAEA13BA7B6A3F6E7C5F67EFC09D5DD3678E3FFEE2FEADA74DAB6FEE480200406B32D0056038C5E3942CCB4E7524000060741D3BA3FEDECEBEDA3F76F5D5664DE9A9FF75576F6D20BE9EDA5BFB58238EBCE017EF8AC7168FB9ACABAFFEA5F87C6A4FED9FBA7A071E2A1E7F7D114B8BFBFEDED1040080D664A00BC0708AC785699A1EE9480000C0E8EAECAD1D52C49CAEDEDAE2CEBEFA35DDBDB599537BEB7B769D57FF40C4B7A70FFC453C2E2EAFDCD53B704FE7F4FA7E9D3DB519C5E31F2C1F337DE6F818023B920000D0BA0C7401D860699AFE4F51400E7024000060F40DBEE4720C74BB7A07AEFEE3D9B845F4D69E296FEFAB7776F6D61E88B3723B7B070E2B6E7FB1B3AFF6B31804C740B788F98E240000B426035D0086533CE6645936DE91000080D1575E6AB9AFF668F97EB9BDB59931E06DDC17EF931B1FBBCFBD71DBE2F3A38AFBCF8EAF8BC7DE567EECABCD1AFC350000D07A0C7401184EF1783C49929D1C090000185D5D7DB593BB7AEBFF1B975D8ECB2AFFF10CDDDAA5C5C79E88E2F3A7E27147F70E7CB078CCC2EEDE8133BBFB6ADDC5ED77C759BDC5C7792B3FCE75340100A03519E802309CE2B12C49922D1D090000187D832FB95C5E3EB9AF3EA1F3FCDAB888293DB37689DBA7F40C7CB2ABA7FEADCEF367EE7674EF0DEF5CFD8CDCA3FA66ED543CFE138E260000B41E035D00364892245B17C5638923010000ADA1B3A7FFFD83DF43B7BB77608FA93366EDD888AEF3EADB74CFA87FA8ABAF7E4A9CC9DBD533707E5C8A392EC3DCF8195D3DF5938AFBA6389A0000D07A0C7401D82049928C2B8AC7838E0400008CBEA9BDB3FEA6ABB776570C6BE3EBAE9EDA69C5D73F191C9DBDF523BAFA06F6E9EAAD4F8AE1EECAC79D50DCF7ABC6E59A8BCFAFFCD6F499EF76440100A0F518E802B0A18563429665B31C090000000000683E035D0036489AA645EDE8F8A123010000000000CD67A00BC006C9B2ACAB88F31D090000000000683E035D0036B4709C99A6E9771C090000000000683E035D0036B4705C56C4A18E040000000000349F812E001B244DD31BB32CDBDB91000000000080E633D00560430BC75D13274EFCB823010000000000CD67A00BC086168EA7922479AF23010000000000CD67A00BC07A9B366DDAA6513884104208218410420821841042083172614201C0060D751D050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C6BAFF0FC6E57D9A0AC9FE2D0000000049454E44AE426082, 1); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('b97761b9-1c51-11ec-94ee-5ef70686b817', 1, 'flowConSign.bpmn', 'b97761b8-1c51-11ec-94ee-5ef70686b817', 0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C646566696E6974696F6E7320786D6C6E733D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A7873693D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612D696E7374616E63652220786D6C6E733A7873643D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612220786D6C6E733A666C6F7761626C653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E2220786D6C6E733A62706D6E64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F44492220786D6C6E733A6F6D6764633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A6F6D6764693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A62706D6E323D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A64633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220747970654C616E67756167653D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D61222065787072657373696F6E4C616E67756167653D22687474703A2F2F7777772E77332E6F72672F313939392F585061746822207461726765744E616D6573706163653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E222069643D226469616772616D5F666C6F77436F6E5369676E22207873693A736368656D614C6F636174696F6E3D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2042504D4E32302E787364223E0A20203C70726F636573732069643D22666C6F77436F6E5369676E22206E616D653D22E5A49AE5AE9EE4BE8BE58AA0E7ADBE2220697345786563757461626C653D2274727565223E0A202020203C657874656E73696F6E456C656D656E74733E0A2020202020203C666C6F7761626C653A657865637574696F6E4C697374656E6572206576656E743D22656E642220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E557064617465466C6F775374617475734C697374656E6572223E3C2F666C6F7761626C653A657865637574696F6E4C697374656E65723E0A202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C73746172744576656E742069643D224576656E745F3077706B6A3665223E3C2F73746172744576656E743E0A202020203C757365725461736B2069643D2241637469766974795F31786B376A346E22206E616D653D22E5BD95E585A52220666C6F7761626C653A61737369676E65653D22247B7374617274557365724E616D657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934353431313335343236373634382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A66616C73652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383936323633313922206C6162656C3D22E68F90E4BAA42220747970653D226D756C74695F7369676E222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383936333333373322206C6162656C3D22E58AA0E7ADBE2220747970653D226D756C74695F636F6E7369676E222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3131316B7970732220736F757263655265663D224576656E745F3077706B6A366522207461726765745265663D2241637469766974795F31786B376A346E223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3030366736716F22206E616D653D22E4BC9AE7ADBE2220666C6F7761626C653A61737369676E65653D22247B61737369676E65657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934353431313335343236373634382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383937333336303022206C6162656C3D22E5908CE6848F2220747970653D226D756C74695F6167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C6D756C7469496E7374616E63654C6F6F7043686172616374657269737469637320697353657175656E7469616C3D2266616C73652220666C6F7761626C653A636F6C6C656374696F6E3D2261737369676E65654C6973742220666C6F7761626C653A656C656D656E745661726961626C653D2261737369676E6565223E0A20202020202020203C636F6D706C6574696F6E436F6E646974696F6E3E247B6E724F66496E7374616E636573203D3D206E724F66436F6D706C65746564496E7374616E6365737D3C2F636F6D706C6574696F6E436F6E646974696F6E3E0A2020202020203C2F6D756C7469496E7374616E63654C6F6F704368617261637465726973746963733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F306374327969642220736F757263655265663D2241637469766974795F31786B376A346E22207461726765745265663D2241637469766974795F3030366736716F223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3070376F6D646D22206E616D653D22E5AEA1E689B92220666C6F7761626C653A61737369676E65653D2261646D696E2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934353431313335343236373634382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383936383238393522206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383936383639333922206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3035326B767A682220736F757263655265663D2241637469766974795F3030366736716F22207461726765745265663D2241637469766974795F3070376F6D646D223E3C2F73657175656E6365466C6F773E0A202020203C656E644576656E742069643D224576656E745F3165356D6D7870223E3C2F656E644576656E743E0A202020203C73657175656E6365466C6F772069643D22466C6F775F316E673571703722206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F3070376F6D646D22207461726765745265663D224576656E745F3165356D6D7870223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3030397037687922206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F3070376F6D646D22207461726765745265663D2241637469766974795F31786B376A346E223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A20203C2F70726F636573733E0A20203C62706D6E64693A42504D4E4469616772616D2069643D2242504D4E4469616772616D5F666C6F77436F6E5369676E223E0A202020203C62706D6E64693A42504D4E506C616E652062706D6E456C656D656E743D22666C6F77436F6E5369676E222069643D2242504D4E506C616E655F666C6F77436F6E5369676E223E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F3077706B6A3665222069643D2242504D4E53686170655F4576656E745F3077706B6A3665223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223130322E302220793D223330322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31786B376A346E222069643D2242504D4E53686170655F41637469766974795F31786B376A346E223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223139302E302220793D223238302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F3030366736716F222069643D2242504D4E53686170655F41637469766974795F3030366736716F223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223335302E302220793D223238302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F3070376F6D646D222069643D2242504D4E53686170655F41637469766974795F3070376F6D646D223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223531302E302220793D223238302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F3165356D6D7870222069643D2242504D4E53686170655F4576656E745F3165356D6D7870223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223637322E302220793D223330322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30303970376879222069643D2242504D4E456467655F466C6F775F30303970376879223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223536302E302220793D223238302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223536302E302220793D223233302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223233302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223238302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223338392E302220793D223231322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F316E6735717037222069643D2242504D4E456467655F466C6F775F316E6735717037223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223631302E302220793D223332302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223637322E302220793D223332302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D223633302E302220793D223330322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F3035326B767A68222069643D2242504D4E456467655F466C6F775F3035326B767A68223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223435302E302220793D223332302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223531302E302220793D223332302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30637432796964222069643D2242504D4E456467655F466C6F775F30637432796964223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223239302E302220793D223332302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223335302E302220793D223332302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F3131316B797073222069643D2242504D4E456467655F466C6F775F3131316B797073223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223133382E302220793D223332302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223139302E302220793D223332302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A202020203C2F62706D6E64693A42504D4E506C616E653E0A20203C2F62706D6E64693A42504D4E4469616772616D3E0A3C2F646566696E6974696F6E733E, 0); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('b9819aea-1c51-11ec-94ee-5ef70686b817', 1, 'flowConSign.flowConSign.png', 'b97761b8-1c51-11ec-94ee-5ef70686b817', 0x89504E470D0A1A0A0000000D49484452000002CE000001720806000000E50C5CBF00001D7A4944415478DAEDDD09749D65B92F7010541C8E80A0E2801E0E8E473DEA75A9E044970B44C185B81669485B6A4B0A051592940EF75C28A745BC9EDE5B0FCD4EC7B5BCCA209541AB16A8429BBD6999A70265924269296DD3093ADA0148BFFB3D1FD93DBBA1A12D6D93EC9DDF6FAD67ED640F49D8FCFB3D4FDEBCFBDB071C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000015A6EA861B0EBA686CE1C85DDE31490EBC2037E33DC54F7F32A1F06ECF1E00003D46C37F357FB83E57981E1FD737E62FABCFE5FF525A0D8D85EF65B735157A3534E6FF507C5C5DAE796EFDF859C78F9832F3D051A30A077B260100A858C326148EAA6BCA9F5CDF949F7D6163E173E9A0DC1C9F0FC9E5BF50ACF327DE71F86B8373FECA74783E3D3E1ED2983FA53ED73C3FBDFFCD696D486FFB86671300808A5597CBF74FEB9E74F85D5DD75498D690CBCF1A922B1C577F45E19FA32E1ADFFCB1B85F6CCB4807E57975E30B3FA86BCC4F48EFFF74769FF1B38E8F61DB33090040C52BDDAA1183733A20DFF8DAEA725AB9FCAAECFAA6425D3A603F15ABCC75B9E673D2EBD7D735E56F89813B06E7B4967A260100A868D9168DA6FC826C3F733A38C7205DBC2DF631BF365CFFEDBDE9C73F4B6FFF3FF1797ADF07B2CBA6FCECD2CF0100A022A583EFC8FA5CE1EED8AE11DB315E5B71CEFFBFF4B2312AFD7879DCEF825CF3B1E97D5A1A72CDFFD9D0946F48AF7F3456A9D3CBC56D978B3C9B000054B41DCEAA11DB2E9A0ABDEAC6E53F157561E3EC4FC4F51736367FBDBEB1F0D3BA71B3FE2D4E49D77E85F9674DB38F49EFFF35CF26000015ABAE71E6474BF73837E49ABF3A64C2ECA38B557F45E1B08609858FA703F57F642F246C6C1E175B3862FB46F16BA443F5C5E96D177A360100A8484372B3BF549FCB3F1243F16B0370761EE73F97565DAE30B8BEA9F9FBE970DD3786E8B6FBFD7B7ADB7DC56D1EE9C7537F3A7ED6119E510000000000000000000000000000000000000000000000806EECCC33CF4C9452AAA7962E00C01E0DCE9E05C0F10F00340E00C73F00340E00C73F00340E00C73F00340E00C73F00340E00C73F00340E00C73F00340E00C73F00D038001CFF00D038001CFF00D038001CFF00D038001CFF00D038001CFF00D038001CFF00D038001CFF0040E3001CFF0040E30070FC0340E30070FC0340E30070FC0340E30070FC0340E30070FC0340E30070FC0340E30070FC03008D03C0F10F008D03C0F10F008D03C0F10F008D03C0F10F008D03C0F10F008D03C0F10F008D03C0F10F00340E00C73F00340E00C73F00340E00C73F00340E804E337FFEFC73C78E1D9B5455551DE3D900C0E00CB0134992BC7BDDBA759B57AF5E9DD4D6D6DEEA1901C0E00CB013CF3EFBEC2D499B7C3EBFAAA6A6A6B767050083334089850B179ED0DADA5A9C9B936DDBB6B58E1C3972455555D5A19E1D000CCE0007645B340E5AB162C5CAA49DB8AE6FDFBE933C4300189C010EC85E107845D281A953A7AEADAEAE3ECEB3044071482EC4A0BC8B2A78A6804AD3D2D2F2CF5BB66C69ED68707EF5D557375D78E1854FF6EAD5EB60CF16003138F7DA8DC1B997670AA8348B172F7E3CD985279F7C72794D4DCD70CF1600C5E1B960B519E849AAAAAA0E9A3B77EED65D0DCE2FBDF4D21DE9717055DCDFB306C0AE569D7B7986804A3472E4C85F6CDDBAF59537989BD7373434E4AD3803D07E782E586D067A92D8BB7CFDF5D72FED686A7EF0C107AF4C8F838FDAE30C40FBC1B997D566A0A7193870E0D7172D5AF472FBA1B9B5B5F5E1BE7DFB2E71560D003A1A9E0B569B819E66CC9831376E4B959E5023AE4B8F83133D3B00743438F7B2DA0CF434F10E813367CEDC509C9A5B5A5AAE4B8F814BBC732000BB1A9E0BDE0005E869EAEAEAFAAF59B3E6E5D5AB5727679F7DF663353535BD3D2B00EC6A70EE6570067AA2C993273F3476ECD8F88BDB0CCF06C07E9624C9DB9E7BEEB91BEEB9E79E979B9B9B939933679665C5E05CAE3F7BFABC6F9B3367CEB27C3EFF43F99BA9E44FFEF6A0A64D9B961DFFE252FE00F6B3B469DC981EB492152B56249B376F4EB66EDDAA3AB9E2798FE7FFF6DB6F5F97369253E54FC99FFCED492D5BB64CFE003A43ACB4C441CB00D1F5D5D2D2B23A6D1CF7CB9F923FF9933F806E28FE3C69A5AFFBACBCA48D638BFC29F9933FF903E886628F998376F7A9F8FF217F4AFEE44FFE00CAB8716C5CDB923CF7C06F9327665D96557C1CD739D86B1CF2277FF2A7E40FD038DA6AC39AA5C9E3B78E4C1EBD65D80E15D7C56D0EF81A87FCC99FFC29F903348EB45E7862FAEB9A46B1963C719303BEC6217FF2277F4AFE008D23EAA9C2980E1B47DCE680AF71C89FFCC99F923F40E348EBF199A33A6C1C719B03BEC6217FF2277F4AFE008D43E3D038E44FFEE44FFEE40F60F71A47BC8ABCA3C611B739E06B1CF2277FF2A7E40FD038D27AE6AEF11D368EB8CD015FE3903FF9933F257F80C691D68B4BE7258FDFF61FAFFF33657A5DDCE680AF71C89FFCC99F923F40E368AB850F5EFDBAC611D739D86B1CF2277FF2A7E40FD0388AB5654BF2CCDD935EFF67CAF4BAB8CD015FE3903FF9933F257F408F6F1CF1CE58F3EF6AEA708F5FDCE6DDB3340EF9933FF953F207F4DCC6B1654BD2F24C3E79EC6FFFABC3A651ACB84FDCD7EA8BC6217FF2277F4AFE801ED53876B5CA62F545E3903FF9933FF9933FC0E09CD6EEACB2BCD1EA8B06A071C89FFCC99F923FA047348E37DB348AA501681CF2277FF2A7E40FE8118D43691CF2277FF2A7E4AF7B1A3060C061679E79E619D5D5D5B9F4B239AD85696D4A2B69BB8CCF9BDB6E3F23EEEF59A343EBD6AD7BEFF4E9D32F1B3F7EFCA3A3478F5E3D62C488CDE79F7FFEB608D479E79DF7CAD0A143D75F7CF1C58B2FBBECB29B860D1BF6BDF421071A9C1DB0350EF953F2A7E42F344C287CBCE1BFEE7E4777CB6B4D4DCD49E92C332DADAD6D43F2EE56DC7F5A3CDE94C876F7DD77DF79E3C68D5B3A78F0E0241D96931B6FBC3179E8A18792050B16242FBEF86212E2323E8FEBE3F6E1C3876FABADADDD9A0ED0B7F6E9D3E75F0CCE4AE3903FF9933F5519F9FBC984C2BBEB72F9BFBE51C57DE2BEE9C717363435FFCFA8FAA6E627EB73F9ABB67F9E6BAEEFE281F9F874F0BD770F87E58EEADEF87AA6C61E6CDEBC79A74C9C3871D9B9E79E9BFCF18F7F4C56AD5A95EC89B87F3C2E1DA05F6E6868B8210DD4911A8732B8C89FFCC99F2AEFFC9D3FF18EC3EB9BF20F3734CDFEFCCE2A6E8BFBC47DD341F9D486A67C433A24CFAB6F2A9C9E552EFF4CFAF9F9715B57E473C08001875457574F4887DD6DED07E0FAFAFAE4DA6BAF7DC305C2B83DEEB793E1795B7CDDF8FAA6C81E24CDC7413366CC981E03F355575D956CD8B021D91BF1F8F83A699036F5EBD7EF748D43195CE44FFEE44F95F9E09CCBDF59DF981F52DF58B86DC76A1E1AB7C57D1A1AF3BDD3217A41432EFF5C7ADDE2F8B8AD96143F6E682C9CD999D94C87DBA36B6A6A1E2D1D78FBF4E9934C99322559B264C91ECD3771FF785C3CBEDD00FD487C1F1365CF189A0FBBE69A6BE6FFF4A73F4D9E7BEEB9645F8AAF970EE39B6B6B6B476B1CCAE0227FF2277FAABC07E761130A47D58DCB7F6AC79AF581E2E09CAD385F31FB33E9E7BFABCF35FFB6B41A1A9BAFB92037EB5F3B3397E9C0FCE9B496960EB963C68C495E78E185BD9A6FE2F1F175DA0DCF2FC4F7335956F8D09CCBE5D65C72C925C99A356B92FD21BEEE88112336F5EFDFFF6A8D43195CE44FFEE44F95EFE03C7CCC9DFF945E2EABCF15A6BF56E9C757140EDB61706E6AFE4E5DAE796E5A634B2BBDCF43715B27AF342F2D5D659E3E7DFA3E9D71E2EBB55B7D7EC1CA73056FCFB8E69A6B9E89A139FE91ED4FF1F5870E1DBAB66FDFBE176B1CCAE0227FF2277FAA3C07E70B7233DE930ECC738AD7A7D7158AB7950ECEF54DF97B1B72F9D1A595DEE7BECE1A9C63CF71E9F68C810307260F3FFCF07E9971E2EBC6D72FDDB661CF73058A3DCD3FFBD9CFF6DB4AF3CE569E070D1AB43E0DD4691A8732B8C89FFCC99F2AD7C139BFFCBFB760E497B71F9CE3AC1AF54D855E71168DEC0C1BB97CE3858DB33F910ECDDFAF6B2AF4EB8C3CB6BD1070FB4AF3FE1A9A4B87E7D295E7F8FE26CD0A92FE0F3E355E08B8AFF734EFCE9EE77EFDFAADA9AAAA7A9FC6A10C2EF2277FF2A7CA6B70CE5694636B46491D902407C6D68CEC3EE39BFF477ABF3B2EC8351F1BABCE43FFEFADEFAA6B2C4CAA1B3FEBA4FAC6E671E96D8FD68D9BF595FD99C5B653CEB51687D89B6EBAA953669CF83E25ABCEAD4E555741E2947371D68BAE3069D2A46569A01A350E6570913FF9933F551EF91B3165E6A1A55B344AB66A9C9AD6E33138C700DD902B9CD890CB9F306A54E1E0F4FABFD5E5F2F7C4C01D97431AF3A70CC9E5BF503F7ED67E1D284BCFD31C2FE0EB4CED5E3078AF89B302C49B9BC46AF3FAF5EBBB64708EEF7BD65967ADABC43749D1380C2EF2A7E44FC95FD7E9DDBBF789A55B34F6F6EC196FE66C1BA55B36E2E7317996B97847C069D3A6255DE9EAABAF5E90066A8AC6A1340EF9933FF953F2B70F579BA71587D638DF725788EF5BB2EA3CCDE459C6D6AF5F7FC479E79D97AC5CB9B24B07E7F4FBBF9AFE46B662D4A8516FD13894C6217FF2277FAA73F35769FD37A473C5E1E9A0BAB538B476F66A73E9AA73C9E0BC357E2E136899BAF9E69B478F183122E90E060D1AB4280DD4D7CBE437D8425ABD340E838BFC29F993BF72CEDFF2E5CB8F59BC78F1E373E7CEDD7AE9A597FEEF5EBD7A1D5C29394C6F3FA3F46DB4BB52BBB7E73EC3045AA69A9A9A1EBBF1C61BBBC5E03C79F2E4787BCAFF2C937FB0C5F0BFE13F5C8DC3E0227F4AFE5477CC5FBC77C3FCF9F3AFD8B2654B6BC97B2CBC72FDF5D72F1D3870E0D72B2187E9F54DC5FBFDEE77BFEBD21927BE7FC9CFDC64022D53A3478F5EFDD0430F758BC179CE9C39F3AAABABA79759E378C37FB81A87C145FE94FCA9EE96BF850B179EB062C58A0EF7682E5AB4E8E53163C6DC585555756839E7B0A6A6265FBCFDC1071FECD21927BE7FF167899FCB045AA6860F1FBEB9B3CFDDDC91A79F7E3AB66A3C50A68D63A7FF70350E838BFC29F953DD257FA97F7AF6D9676F696D6DDD654FDE964A1FB3A1A1A1E1C7E59AC3F47271F1FAAE9E75E2FB97FC8C8B4DA065EABCF3CEDBF6D24B2F758BC1F9C5175FDC9086696999378E1DFEE16A1C0617F953F2A7BA43DD73CF3DC9BA75EB36BF8977F97D79F2E4C90F5555551D538639FC47F1F3AE9E75E2FB97AC38AF378196A9B3CE3A2B79E59557BAC5E09CFE1CEB77E31F425955A5368E38F7767A002EBB9FBBD2F25549F9FBC73FFE9135F6B8DCD9ED69F34E962C59B2C375CF3FFF7C9645F993BF7D512B56ACC832D8D1EDAB56AD4A9E78E289ECE3458B16256BD7AE4D366FDE9CFCFDEF7F4F366CD8D0ADFFDB962D5B968C1D3B3659BD7AF51EF7E6784C3CB6DCF3D8D5B34E7CFF929FE7551368991A3C78F02BDD65C5393D283D5B012BCE65F7A7CAD877F5F18F7F7CA73561C2849D3EE684134E48BEFBDDEF261B376EB4E2277F7B5D31149F7CF2C9F1FF26BB8C6352FBFB0C1F3E3C39F0C00393DFFEF6B7C9B5D75E9B0D38C71E7B6CF2ED6F7F3BFB3C6AEEDCB9F2277FBB5D3104FFF297BFDC5EA79E7A6AF296B7BC25B9FCF2CB77B8FE99679EC9EE1F197BDFFBDE977D7CE8A18726D75F7F7DB274E9D22CB7711CEDEEFFCEE2FD1A060D1A745B3E9F5FB56DDBB6D6DD68CBAFB6B4B45C77F6D9673F96FE7F9D51462BCEDB73182BBB569CD9A72EBAE8A2F5DD658FF3934F3EF96019EF712EDB17C7C42A4ABCDAF7CA2BAFDCA13EF4A10F25BFF8C52F76FA98BBEFBE3B79E73BDF990C1B36CCE02C7F7B558B172F4EBEFAD5AF66BFA8C5CF1BC3707C5EBABA1C2BCB91B7A38F3E3A1B6CE2F24B5FFA5236B07CF2939FCC2E3FF5A94F25B95C4EFEE46FB72BCE2875F0C10727DFFBDEF73AACC8D68C193392050B1664BFBC1D76D86149737373590ECEC5FCA5435BEF912347AE78A31707B6B6B63E1C2F0E4CFFBF2E89FB976B0EED71669FBBE4924B5EE82E67D598356B5673199E55A3224EC7F4E94F7F3A3BF8B7AF8E06E7A85FFDEA57C9BBDEF5AED7FDF9DCE0227FBB539B366D4AAEB8E28A6C00F9FCE73F9FBD41407190FEDCE73E971C7EF8E149636363F6A7F089132726471C714496B5934E3A29193C787076F99DEF7C27DBAAF1810F7C20B9E69A6BE44FFEF6A86EBDF5D6E4B39FFD6CB270E1C2ACE2AF1871DC8BEB8BD77DE10B5F48EEBAEBAE2CAB6F7FFBDBB3BF7AC4F132727BD5555765F789C78C1A352A39FEF8E39379F3E69545FEE26C197DFBF69D3475EAD4B5AFBEFAEAA69256BC3EFD25E0CAF4B625E9FFDB896572568D0E73E8AC1AEC73E93FF69BBACB799C2FBFFCF26965741EE78A78038058C98BFFFFB1C2FC9BDFFC6687FAE0073F98A407CFECF6D8CFD7FEB1A79F7E7AD630E2A4EE0667F9DBD3AAADADCDF21383CBDBDEF6B66C25AF58871C7248F2894F7C22BBFD273FF94976FF189A63C5E69C73CEC9EE1F4373AC3EC7B6A13FFCE10FF2277F6FAA62FBC5CE160D8A150B04A5F72DDDAA11B77FEB5BDFCA2E631121DE8577FEFCF96595BFEAEAEAE3EAEAEA9E4C2D7FE9A597EE183264480C9A8FC6F5959043E771669F1B3162C4C9C3870FDFD61D5E1BD8A74F9F79E5F2CE81BBABBB378EBFFEF5AFC931C71C937CE4231FC92E637B4634818F7EF4A3D9E7B1C2129737DD74D30E8F7BEAA9A7B2A1251A45DCE7D9679F35B8C8DF1ED5BDF7DE9BFD093CFED47DF3CD37BFAE62057AFAF4E9C9238F3C92E4F3F9E4FBDFFF7E72D04107251FFBD8C7923FFFF9CFD9CAF49FFEF4A7E4C31FFE7096D9AF7DED6BD99FD0E54FFEF674707EEF7BDF9BC45F5E238F91A5582C88CF63DB50FBC1F93DEF794FB6573806E7D80B7DE79D77668F8955E9723DFEC53B05D6D4D40C4FFBEFAAB82C97770EDCCDE1BADBBC7360FA0BCA36EF1C58192BCE6F193468D0D6952B577669A0962C5972571AA496F879348ECEAD78F14BEC178DD5BCD8BB1C4D2056F7E2B7E3B7BEF5ADD970DDFE3131301F77DC71D9C75FFEF297B3956983B3FCEDE9568D7881696CB978A38AAD1891C1534E3925F9E10F7FB8D355C11FFCE007D98B0A6FB9E516F993BFFDB2E21CFB9963DB465C17BFC495F31EE7379A072A2D837DFAF4393C9D2DB61607D6F885BC2BC4F72D199AB7C6CF65022D63C3860DBB357E83EE4A3FFFF9CFA7A6619AA271747EB5B4B424BD7AF54ABEF8C52F269FF9CC67B226107B4E63682E5D6D2956ACCAC49FD263D5AFB86A1DABCFB182687096BFDDADD8BB7CD1451765157B9463E5383E8E5FCAE2057FF1F1D0A143B79F9E2E4EFD15A7CF8C95C071E3C66583720CD5D75D775D72DA69A775781A3BF993BF5D0DCEB19F3E8E5FF1178E38FE4D9D3A35FBBC74C5F92F7FF94B72E2892726471E79648767D5E8EE6719EA69F92B59759E561C5AA74C99D225334E7CDF92C1799AC9B3FC7F23FB97DADADA97A3097585356BD6DC9F066965FC1C1A47E7D7F2E5CB93FEFDFB6F5F4939A06DDF5EBC182B9ACA962D5B76389D516CCD8895C2D2AF110DE5A8A38ECAFEACAE71C8DF9E546CCB882D18C59F75D6AC59D92F6D91BDF6F7FDCA57BE925C70C105D97DE36C0891DDD8EB1CA711F3170FF9EBEC3DCEED07E7DEBD7BEF74B141FEBA56FAFFE5C4E2D09ACE199DBEEA1CDFAFA6A666FB368DF8794C9E15A0A1A1E1867885705748BFF7F569981A358ECEAFD83B1A8DA0782AB0DB6EBB6DFB568DBABABA6C2539F68EC6F94E7FFFFBDF67034DACEEB57FD38938A5DD37BEF18D6C35E6FEFBEFD738E46FB7EABEFBEECB5E841A5B85E20D16E2745F03070E4CDEFFFEF727EF78C73BB6FF1523DEBCE1EAABAF4E7EFCE31F27DFFCE637B317B3C6101D7B4CE32C07B14A1DB717CFCC217FF2B727EFA697F6A06CB538CED71CC7BF071E7820FB3CB6B1C52F72C50586D1A34767C7CBB83D7ED98BBFD215B70F8D1F3F3E7B416B9C0946FEBAE5AAF3BDC5C175CC98319D3AE3C4F72B596DBED7C45921AAAAAADE3760C0804D9D7D9EC3F4B7F4D8A2B132BEBFC6D1F9F5E8A38F662B78F167F08B2FBE386B00F102C1E22A733488680CB19D23FED4147B99636F6A476F62112BCFDD799FA9C1A5FB9D47377E698B5FCE629F729C69E3D24B2FCDCEEA127B9ACF3DF7DCEDC34D6CDFD855CD9933C7E02C7F6FBAE2EC41710C7CF8E1875F77DBAF7FFDEBECB61FFDE847D98BA5E305D5F10B5BBC2035CE3B5E3C7616DF5950FEBA979A9A9AE3D359A3B538C0C6FFC3CE10DFA764686E8D9FC3C45941FAF5EB77FAE0C18337C700D41956AE5C393B0DD2F3699DA671748F374279ECB1C7B201B812DF26DCE0525E558E6FE92E7FE59DBFD8271F7F31DBD9DB67C70A742C20C4C7A5DBD74AF3BAB3EBE5AFFBA8AEAE9E50BA65237E41DA9FE2EB976ED188EF6FD2AC40B5B5B5A3478C18B129FE91ED4FE901E6C934B80FA4A1FA778D43691CF2277FF2A7E46F7F1A3060C021E900FB4871908D6D61FB6B788EAF9B7EBFD692D5E647E2FB9B322B54FFFEFDAF1E3A74E8DAFDB5F2BC72E5CADB63684E83F46B8D43691CF2277FF2A7E4AF33A473C7D169BD50BAF21C6753D997E2EB95AE34B77DBFA34D9715AE6FDFBE17D7D6D6AEDFD77B9EDBF6342FAEF495668D43E3903F257FF2277FDD4F3A7F7CBA74782EBE60706FCFB6118F6FF742C06C688EEFE759EF39BF999DD6AF5FBF3593264D5A167BBEF6C6DAB56BEF6B3B7BC6CA4ADED3AC71681CF2A7E44FFEE4AF2C569E1F291D7263F5395E041F6795DAC33770CB1ED76E953969FBFA569A7BE06F6647C6A9E2CE3AEBAC75575E79E58255AB56BDB2276FA3BD74E9D2BB468F1E3DB56D606E8CAFA771288D43FEE44FFE94FC75A5D873DCF682C1F6036FF6F6DC71DEEE78C3A5050B16242FBEF86236D4C4657C1ED7C7EDEDDE46BB58DBE2EBDAD3DCC3C59B93C43BFBA583EFCA73CE39E7F9C993273F3C67CE9C794F3FFDF4E2D5AB576F4CF3B461E5CA95CF3DF1C4130FA6FF38675E7EF9E5D3D2C7CC4B1FB33C1E57896F6EA271681CF2A7E44FFEE4AFEC17088F2F3DCFF35ED6BD4E39477B07F6EEDDFB1B69307E99FE46353D0DC9FD257B85E2F2FEB83E6E8FFBC5FD7BF293A571681CF2A7E44FC95F590CD027B5BD3DF7D63D1C96E3FED3E2F19E45D038340EF953F2277FF2D7630C1830E0B074103EA3BABA3A975E36A7B530AD4D6D43F2A6B6CF9BDB6E3F23EEEF59038D43E3903F257FF2277F001A87C6217F4AFEE44FFE00340EA571C89FFCC99F3238031A87D238E44FFEE44FC91FA071288DA3C7E66FE3C68DC9E38F3F9E5DEECDF5F2277F4AFE008D43691C159DBF1882D31F39BBDC9BEBE54FFE94FC011A87D2380CCE0667F953F207681C4AE330381B9CE54FC91F607076C0D638E4CFE02C7F4AFE00340E8D43FE0CCEF2E7F8277F001A87C6217F0667F973FC73FC03D038340EF93338CB9FFC39FE01681C4AE33038CB9FFC298333A071288DC3E06C70963F257F80C6A1340E83B3C159FE94FC010667A571C89FC159FE94FC01681C1A87FC199CE5CFF14FFE00DE8CE6E6E66D9B376F76D0EE0695FE7F5896368E2DF26770963FF973FC03E886E6CC99B36CC58A150EDCDDA09E7FFEF9EBD2C671BFFC75CFDAB871633604C7E5DE5C2F7FF2A7E40F2853F97CFE87B7DF7EFBBA969696D5565EBA6CA5A565D1A24553D3A6B138AD53E54FC99FFCC91F40371507ABF84D3FADADB1C74C757A6D6D7BFE4F953F79903FF9933F000000000000000000000000000000000000000000000000002ADAFF079DBE4A708996EDEC0000000049454E44AE426082, 1); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('d273a35e-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract.bpmn', 'd273a35d-1cd8-11ec-acd8-3ae4f1d3c3af', 0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C646566696E6974696F6E7320786D6C6E733D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A7873693D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612D696E7374616E63652220786D6C6E733A7873643D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612220786D6C6E733A666C6F7761626C653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E2220786D6C6E733A62706D6E64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F44492220786D6C6E733A6F6D6764633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A6F6D6764693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A62706D6E323D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A64633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220747970654C616E67756167653D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D61222065787072657373696F6E4C616E67756167653D22687474703A2F2F7777772E77332E6F72672F313939392F585061746822207461726765744E616D6573706163653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E222069643D226469616772616D5F666C6F77436F6E747261637422207873693A736368656D614C6F636174696F6E3D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2042504D4E32302E787364223E0A20203C70726F636573732069643D22666C6F77436F6E747261637422206E616D653D22E59088E5908CE5AEA1E689B92220697345786563757461626C653D2274727565223E0A202020203C657874656E73696F6E456C656D656E74733E0A2020202020203C666C6F7761626C653A657865637574696F6E4C697374656E6572206576656E743D22656E642220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E557064617465466C6F775374617475734C697374656E6572223E3C2F666C6F7761626C653A657865637574696F6E4C697374656E65723E0A202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C73746172744576656E742069643D224576656E745F3170736D697364223E3C2F73746172744576656E743E0A202020203C757365725461736B2069643D2241637469766974795F306E796C61317222206E616D653D22E59088E5908CE5BD95E585A52220666C6F7761626C653A61737369676E65653D22247B7374617274557365724E616D657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935343932303334383934363433322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A66616C73652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839363537313222206C6162656C3D22E68F90E4BAA42220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F303063657865612220736F757263655265663D224576656E745F3170736D69736422207461726765745265663D2241637469766974795F306E796C613172223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3175637268353222206E616D653D22E4B89AE58AA1E983A8E9A286E5AFBCE5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22247B64657074506F73744C65616465727D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935343932303334383934363433322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550545F504F53545F4C45414445522671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A7461736B4C697374656E6572206576656E743D226372656174652220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E44657074506F73744C65616465724C697374656E6572223E3C2F666C6F7761626C653A7461736B4C697374656E65723E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839373234353522206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30346B63616A632220736F757263655265663D2241637469766974795F306E796C61317222207461726765745265663D2241637469766974795F31756372683532223E3C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30323666766E712220736F757263655265663D2241637469766974795F3175637268353222207461726765745265663D22476174657761795F30396364787466223E3C2F73657175656E6365466C6F773E0A202020203C706172616C6C656C476174657761792069643D22476174657761795F30396364787466223E3C2F706172616C6C656C476174657761793E0A202020203C757365725461736B2069643D2241637469766974795F3133386D346E6E22206E616D653D22E5B7A5E7A88BE983A8E5AEA1E689B92220666C6F7761626C653A63616E64696461746555736572733D2261646D696E2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353139343939313937323335322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839373831303122206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F307A7A307539672220736F757263655265663D22476174657761795F3039636478746622207461726765745265663D2241637469766974795F3133386D346E6E223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F30746D336D706822206E616D653D22E980A0E4BBB7E983A8E5AEA1E689B92220666C6F7761626C653A61737369676E65653D2261646D696E2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353139343939313937323335322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383839383233373722206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F317978716265302220736F757263655265663D22476174657761795F3039636478746622207461726765745265663D2241637469766974795F30746D336D7068223E3C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31323465387A332220736F757263655265663D2241637469766974795F3133386D346E6E22207461726765745265663D22476174657761795F306F79366F666C223E3C2F73657175656E6365466C6F773E0A202020203C706172616C6C656C476174657761792069643D22476174657761795F306F79366F666C223E3C2F706172616C6C656C476174657761793E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3175766A3364732220736F757263655265663D2241637469766974795F30746D336D706822207461726765745265663D22476174657761795F306F79366F666C223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3179757579696522206E616D653D22E8B4A2E58AA1E983A8E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303936343531393339353333323039362C313434303936343531393339313133373739322220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353132373739303833333636342671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B504F53542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383930333738313422206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383930343234383922206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F316B79686E6C7A2220736F757263655265663D22476174657761795F306F79366F666C22207461726765745265663D2241637469766974795F31797575796965223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3039386E63767722206E616D653D22E6B395E58AA1E983A8E4BC9AE7ADBE2220666C6F7761626C653A61737369676E65653D22247B61737369676E65657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353030313039333439323733362671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383931393036363222206C6162656C3D22E5908CE6848F2220747970653D226D756C74695F6167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383931393734303622206C6162656C3D22E68B92E7BB9D2220747970653D226D756C74695F726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C6D756C7469496E7374616E63654C6F6F7043686172616374657269737469637320697353657175656E7469616C3D2266616C73652220666C6F7761626C653A636F6C6C656374696F6E3D2261737369676E65654C6973742220666C6F7761626C653A656C656D656E745661726961626C653D2261737369676E6565223E0A20202020202020203C636F6D706C6574696F6E436F6E646974696F6E3E247B6E724F66496E7374616E636573203D3D206E724F66436F6D706C65746564496E7374616E6365737D3C2F636F6D706C6574696F6E436F6E646974696F6E3E0A2020202020203C2F6D756C7469496E7374616E63654C6F6F704368617261637465726973746963733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3064693671613622206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F3179757579696522207461726765745265663D2241637469766974795F31656577743031223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C6578636C7573697665476174657761792069643D22476174657761795F316D356672757A223E3C2F6578636C7573697665476174657761793E0A202020203C73657175656E6365466C6F772069643D22466C6F775F306A7976317A622220736F757263655265663D2241637469766974795F3039386E63767722207461726765745265663D22476174657761795F316D356672757A223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F316833706E787922206E616D653D22E680BBE7BB8FE79086E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303931313431303538313231333431362220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935343932303334383934363433322671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383934343935303822206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383934353238353022206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31663879786F7622206E616D653D22E5908CE6848FE4BABAE695B0E5A4A7E4BA8E3430252220736F757263655265663D22476174657761795F316D356672757A22207461726765745265663D2241637469766974795F316833706E7879223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6D756C74694167726565436F756E74202F206D756C74694E756D4F66496E7374616E636573203E20302E347D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C656E644576656E742069643D224576656E745F3132616A6F3364223E3C2F656E644576656E743E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31613371636C6D22206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F316833706E787922207461726765745265663D224576656E745F3132616A6F3364223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F306C6C6F79353622206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F3179757579696522207461726765745265663D2241637469766974795F306E796C613172223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3165657774303122206E616D653D22E6B395E58AA1E983A8E5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22313434303936343338373937393339393136382220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303935353030313039333439323733362671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B504F53542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383933333730323422206C6162656C3D22E4BC9AE7ADBE2220747970653D226D756C74695F7369676E222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383933343139303122206C6162656C3D22E58AA0E7ADBE2220747970653D226D756C74695F636F6E7369676E222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F307A6D736E33782220736F757263655265663D2241637469766974795F3165657774303122207461726765745265663D2241637469766974795F3039386E637677223E3C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3176737269766222206E616D653D22E5908CE6848FE4BABAE695B0E5B08FE4BA8E3430252220736F757263655265663D22476174657761795F316D356672757A22207461726765745265663D2241637469766974795F306E796C613172223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6D756C74694167726565436F756E74202F206D756C74694E756D4F66496E7374616E636573203C3D20302E347D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F316D323430366622206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F316833706E787922207461726765745265663D2241637469766974795F306E796C613172223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A20203C2F70726F636573733E0A20203C62706D6E64693A42504D4E4469616772616D2069643D2242504D4E4469616772616D5F666C6F77436F6E7472616374223E0A202020203C62706D6E64693A42504D4E506C616E652062706D6E456C656D656E743D22666C6F77436F6E7472616374222069643D2242504D4E506C616E655F666C6F77436F6E7472616374223E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F3170736D697364222069643D2242504D4E53686170655F4576656E745F3170736D697364223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D2239322E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F306E796C613172222069643D2242504D4E53686170655F41637469766974795F306E796C613172223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223138302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31756372683532222069643D2242504D4E53686170655F41637469766974795F31756372683532223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223334302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F30396364787466222069643D2242504D4E53686170655F476174657761795F30396364787466223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D223530352E302220793D223330352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F3133386D346E6E222069643D2242504D4E53686170655F41637469766974795F3133386D346E6E223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223636302E302220793D223136302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30746D336D7068222069643D2242504D4E53686170655F41637469766974795F30746D336D7068223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223636302E302220793D223339302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F306F79366F666C222069643D2242504D4E53686170655F476174657761795F306F79366F666C223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D223835352E302220793D223330352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31797575796965222069643D2242504D4E53686170655F41637469766974795F31797575796965223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313030302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F3039386E637677222069643D2242504D4E53686170655F41637469766974795F3039386E637677223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313336302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F316D356672757A222069643D2242504D4E53686170655F476174657761795F316D356672757A223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D22313531352E302220793D223330352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F316833706E7879222069643D2242504D4E53686170655F41637469766974795F316833706E7879223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313637302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F3132616A6F3364222069643D2242504D4E53686170655F4576656E745F3132616A6F3364223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D22313836322E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31656577743031222069643D2242504D4E53686170655F41637469766974795F31656577743031223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D22313139302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F316D3234303666222069643D2242504D4E456467655F466C6F775F316D3234303666223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313732302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313732302E302220793D223534302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223231302E302220793D223534302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223231302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223935342E302220793D223532322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31767372697662222069643D2242504D4E456467655F466C6F775F31767372697662223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313534302E302220793D223330352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313534302E302220793D223133302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223133302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223239302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2238392E302220783D223834312E302220793D223131322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F307A6D736E3378222069643D2242504D4E456467655F466C6F775F307A6D736E3378223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313239302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313336302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F306C6C6F793536222069643D2242504D4E456467655F466C6F775F306C6C6F793536223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313035302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313035302E302220793D223530302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223530302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223233302E302220793D223337302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223632392E302220793D223438322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31613371636C6D222069643D2242504D4E456467655F466C6F775F31613371636C6D223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313737302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313836322E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D22313830352E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31663879786F76222069643D2242504D4E456467655F466C6F775F31663879786F76223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313536352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313637302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2238392E302220783D22313537332E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F306A7976317A62222069643D2242504D4E456467655F466C6F775F306A7976317A62223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313436302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313531352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30646936716136222069643D2242504D4E456467655F466C6F775F30646936716136223E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313130302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313139302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D22313133342E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F316B79686E6C7A222069643D2242504D4E456467655F466C6F775F316B79686E6C7A223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223930352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D22313030302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F3175766A336473222069643D2242504D4E456467655F466C6F775F3175766A336473223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223736302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223335352E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31323465387A33222069643D2242504D4E456467655F466C6F775F31323465387A33223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223736302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223838302E302220793D223330352E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31797871626530222069643D2242504D4E456467655F466C6F775F31797871626530223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223335352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223636302E302220793D223433302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F307A7A30753967222069643D2242504D4E456467655F466C6F775F307A7A30753967223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223330352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223533302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223636302E302220793D223230302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30323666766E71222069643D2242504D4E456467655F466C6F775F30323666766E71223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223434302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223530352E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30346B63616A63222069643D2242504D4E456467655F466C6F775F30346B63616A63223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223238302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223334302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30306365786561222069643D2242504D4E456467655F466C6F775F30306365786561223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223132382E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223138302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A202020203C2F62706D6E64693A42504D4E506C616E653E0A20203C2F62706D6E64693A42504D4E4469616772616D3E0A3C2F646566696E6974696F6E733E, 0); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('d28a86bf-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract.flowContract.png', 'd273a35d-1cd8-11ec-acd8-3ae4f1d3c3af', 0x89504E470D0A1A0A0000000D4948445200000774000002260806000000AB78BB71000069854944415478DAECDD07981D55D938F05014AC34FB5F6CE0A7D83F15151B114114145009D98426862F8496DD0D298A88A11B5BB27743899F48533F0145098A81ECBD1702482F22016921B484D02142820AF39F77D859EE6E76934DB26576F7F77B9EF3E496B96577DF9C79CF79E7CC0C1B06000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000834CE389D52D1B7FF6D757AC6ABBC9D32E7FCD4127565FDDDDE7279D587D93DF2E000000000000402A8AA9F5A5CA5F56D6F2826B7A7B7C6373F93BD11A9ACBB736942A67B4DD2F951B3A7BFFC6E66A7D7DA97A40C7C70F3CE9B24D1A9A2BA7C7EBEA9BAB7BA5EFF5C7A953A7AE9B3E76F7CABE6FFD8CF2E7D36D4FE9ECB9F4BDFEB7CB9FA3A9F2B3EEFE4EE27B747CECD0D2851BACF858F5AD63675DF7325104000000000000F48AD6C2EA8D8DCD977EB0B316CFC536B16D43A9B2736373A5B1A154BEB9A1B9BA5BD64A953BD3FB07C6739DBD7F7DA932A9B1A9BA6FC7C763756F1466EB9BAA273496AACDF5A5F2110DD3E7BD397DEC9186A6F2D4688DA5F22756785DA9B26D146E3BFBAC6CD570FEBD9BCA13E3FDF3FB8796CA5B74DC7ECAACB91BA5DBDC54DF5C1D993D9024EBA4F74F4ADBC28652F5C2F83EAD3FC3F8F899D3CFBE62C439E7AC973DD65CD9B1A1A97A717E1F000000000000A0C76505DD52E5F286A6CA842850B66F5951F4F2D8A6B1A9B247AC9E6D2C5516A48FDD17B75BDB03F9EDC6A66A5DC7F7AF6FAA9E5C5FAA4EE9F8F884A6CA4EE9FBDC92B6246D8BE273D2CF189BFE5B6E2D10DF7E68A9E57DB16DAC988DEDE3766D4137FD8EDF1B3BEB825776F67365DFB7A97274573FF7D4D3AA1B3694AAF3E2F30F69BEF49DADEF77707A7F4EB652B8A9F2DD585D9C1579D39FB1F16773364D9F9B3BBEA9FA81F14D97BE3BBD7DFDC1335B36134100000000000040AFC90BBA71EDDAFA1995F7B46F2D6FCC0BBAB16DC3F44BB74AEFFFAAA1543EADB6353695CFCA8BAF1DC5AAD6F435F7765CC97A48F3C56FA92F956F489F3B3BDDE6BAACF0DB54F9657ABBE5B099E5B7C7E7BCF41E2D9F8BC75BDFEFA5826E9CF2B9A932F6C5EF56DD380AB3794BDFFB90F4F999B58FC536B1EDD4A9D5F51B4AD5D9E9F3A7A6EDE1EC435E2CDCDE1D9F1577EB9B2BBB3496AAE7642B899BCBB7B6AEE65D38F1E48BDE90BEF69AF477F321D103000000000000F4AABCA03B79DAE5AF7971A56C143AB362E7A22880B62BE83697B78B226CDA7E52DB62B56A3CD7F1BDA3E819AB70EB9BABE7D53757BE59FB5CEB299B87D7972AC74D28553F35E1C44B374FB7AD66AB669BAAFB37962A47E5DBA6B79BD2F718D37ABBADA09BBEFFD6F1FED9ED99D5AF66D7E47DA95D9A3EF7B7768FC569A15F2CDCA6B7ABD3E33B3436952F88D71FD65C7D6F149EDBBE5F536542FA593FCA3EB3B9FC9DF8191A4BE5AFC5B57ED3D7EE9EBEC767C63755BEE81ABA00000000000040AFC90BBA87962E7C6D1453F3C7A3B89A3F575BD06D68AE5C15C5D6DA966E7375C7826E9CB6B8BEB9F2E76C75ED89D52DA3C01A2B63F3E71B4BE52FA5AFBB287DFDE3E9BFBF8FCF8EE26876AAE452E5A986E9D58FC476F54D73DF969DD6B975756DC76BE8C6678F6F2A7FBAE3CFD5D529971B9BCBE3D2D73C9D1574E354D3A5CAF5F533CA9F6F2DD6FEA9F6E78FF768F7DA52F598F4E73C36AEB91B2B86E37B64A76506000000000000E80DED0BBA95875E3A9572E5A18E05DDFA52657CACAACD56ACA6B763E56C763DD9E6F257EA9BAB7BD5BE6F3CD758AA36E7F71B9A2BC7A7AFF9CB4127565FFDD236D5735EBC5E6EB9A1A1A93CB575BBCFA49FF9EFC6E92DEFCAEE972A3F6D6CAE1C54F3BEED0BBA4DE5BDD336A3E3CFD5554137BEEF84A6962F448BEBF4A6AF3D344EA3DC5A38BE2ABB7E6EFAF3E4B7DB3E2756E596AAB363856FFADEBF8B4275FAF34C8ADF8528020000000000007A455EB48DDBD929966B5A142FE314CBD93633CB1F4DB7BBECD052798B28764EFCF145AFCAAE7B3BB3658728A8C6E98DE314C88D3F9BB36943A9FC87B87E6DED8ADCECFD63756B5C3777FABC3767F7A3185BAA2C4FDB7FEA4BD50362556E5CAF367DFDA8EC74C9E97687962EDCA0B6B01A85E3C652E5E7F9FD58D53B76D605AFECF8734511B8F6B4CD1DBD781DDDCAD238D574DB6B4AD5E6F4B3EF8855BBB5D7046E3D75F4B551F4CEEE972A47A6F77F9BFE7B5B5C0B581401000000000000BD62CAACB91BD59E6A3917D79BCDAE7F5B2ADF90AD4A2D55B78FD5B1AD85D039F5A5CA9551088E7F273455769A50AA7CB86166CB3651EC8CE26C579FD7D854199B3E3F2556C6C6F568E3D4CB07CF6CD92C5E97ADD8CD4FB53CB36587FAA6EA096DAF9BDEF2AE28A0468BD32377F9FECDD58F67A7802E55FE1EA7525EDDDF47ED0AE2B6DFC5F44BB7EA58B88D9FB7B6180C00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014445D5D5DA2699AA6699AA6699AA6699AA6699AD6D3CDEC2B00400F1574FD1600000000809E64DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205000000001494794700008915000000005050E61D0100245600000000404199770400905801000000000565DE1100406205C0109424C9CB172C5870CE95575EF9AF72B99CCC9D3B57EBE396FEDE5F98376FDEA24AA5B2AB88040000BA62DE1100406205C010B460C18273E7CD9B972C59B22459B66C59F2DC73CF697DDCE2F71EBFFF4B2EB9E4A9B973E7EE2C2A010080CE987704009058013004C5CADC28262AACF67F5BBC78F1A373E7CEBD46540200009D31EF080020B10260088AD32C5B995B9C95BA73E7CE5D2E2A010080CE987704009058013004C5355C15538BD3E2EF212A010080CE98770400905801300475B7A0FBCF2717270BAE3D2D99DF7274D6E2763CA608ABA00B0000F40DF38E0000122B0086A0EE1474973EF16072CB45DF4FFEF6E749ED5A3C16CF29C42AE8020000BDCFBC230080C40A8021A83B05DDFBE7CF5EA1989BB707E65FA010ABA00B0000F401F38E0000122B0086A0EE14746FAB4EEBB2A01BCF29C42AE8020000BDCFBC230080C40A8021A83B05DD5BE64EEDB2A01BCF29C42AE8020000BDCFBC230080C40A8021484157411700001818CC3B020048AC001882BA53D09DDF72749705DD784E215641170000E87DE61D01002456000C41DD29E8DE79C5CC2E0BBAF19C42AC822E0000D0FBCC3B020048AC001882BA53D07DECC19B935B2EFEC18AA75B4E1F8BE714621574010080DE67DE1100406205C010D49D826EB47BAE3B7385826E3CA608ABA00B0000F40DF38E0000122B0086A06E1574972F4FEEFCEBC92B9E6E397D2C9E538855D00500007A9F7947000089150043D0AA0ABA4B9F7830B9E38AE62EAFA11BCFC5368AB10ABA000040EF32EF080020B1026008EAB2A0BB7C79B2F8CE4AF2F739877759CCCD5B6C13DB5AADABA00B0000F41EF38E0000122B0086A0CE0ABAAB5A956BB5AE822E0000D0F7CC3B020048AC0018823A2BE8766755EECA56EB2ACC2AE80200003DCFBC230080C40A8021A8B382EE9A1673F3A630ABA00B0000F43CF38E0000122B0086A02EAFA1AB29E80200008562DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000C410ABA0ABA0000C0C060DE1100406205C010A4A0ABA00B00000C0CE61D01002456000CAEFD51356DC357B59D82AE822E00003060C679C60B0000122B0006D3FEA8B5ADB4B0ABA0ABA00B00000C9C719EDF020080C40A8041B43FEAD03A2DEC2AE82AE802000003679CE7B7000020B1026010ED8FBA68ED0ABB0ABA0ABA0000C0C019E7F92D000048AC001844FBA355B4ACB0ABA0ABA00B00000C9C719EDF020080C40A1862FD95A615B1A0BB6CD9B264E9D2A5ABDC6ED1A245C96DB7DDB65AEFBD64C992E4CA2BAFECF2F9471E7924993F7F7E767BE1C285C9934F3E997D9F7FFCE31FDDFA4E6BDBC4E4E06FF63E000098770400905801E8AF28CC2997CF3AEBACE4A73FFD6997EDF4D34FCFB6BBFCF2CB937DF7DD37F9D8C73E96BCE215AF480E3AE8A0E4FDEF7F7FF2BEF7BDAF5D5BBE7C79B278F1E2E4B2CB2E4B76DB6DB7E4831FFC60763BDAF7BFFFFD76DBC6674771F684134E686B3BEFBC73B2EEBAEB26C71E7B6CBBC7EFBCF3CEEC7BFCFAD7BF4E5EFFFAD767B737DA68A3E4ECB3CF4E1E7CF0C1F8BF925C77DD7556E8A2DF0500403E090020B102D05FD1337FDF95157273BD5DD0DD6FBFFD92ADB7DE3A6B1FF8C007B2C268FC9B3F16DF2DB6AB56ABC92EBBEC92ACB3CE3AC911471C915C73CD35D9B651F43DEFBCF392638E3926BB1FAB65CF3CF3CCEC76C7B6CF3EFB249FFDEC67931FFFF8C7D9FDD9B36727E79E7B6EB2FEFAEB275FFEF297BB6CB1ED85175E98DC7DF7DDC9E4C993938D37DE382997CB0ABAE8770100904F020048AC00F457F4DEDF776585DC5C5F9E72394E5B9C7E6472F3CD3777FADCF9E79F9FAD9E3DFEF8E3936BAFBD36DBF6C0030F4C8E3BEEB8E480030E682BE8C6F651783DFAE8A3B315BBDB6DB75D72EAA9A726DFFEF6B793BDF6DA2BF9D18F7E94ADB27DE69967928B2EBA285BE97BCF3DF7642D4EB71CEF138FE78F7DF8C31F4EAEB8E28A64FAF4E9C9061B6C901595DFFBDEF76605DD33CE3823DB265E3375EAD4649B6DB6E9F4FB2BE8A2DF0500403E090020B102D05FB13A7FDF951672734529E8C64ADC57BDEA55D9F3AF7DED6B939FFCE427C937BEF18D766DF7DD77CF0AB877DC714756E07DC73BDE91ADC08DD79C72CA29593137DA873EF4A1AC109CBF779C467958272B7AF3169F5DBB6DED2997E3F9CF7DEE73D9BFF1FDC68D1B977DBE822EFA5D0000E4930000122B00FD15BDAE2805DD6853A64CC99E9F38716252A954B2026EC7162B69C78F1FDF696176871D7648468D1A956CB5D55659C1B7B648BBE9A69B26D75F7F7D766AE5D8360AC1717F8B2DB658A1A01B05E538CD731474E35ABB717DDF784D7CB6532EA3DF0500403E090020B102D05FD1678A52D08D55AF1B6EB861F6FCCB5EF6B2AC307BF8E18767D7C58DC71A1B1BB3FB37DD7453B64A77D6AC59C949279DD4D62EB8E082B6532E5F7DF5D5C9CB5FFEF2E4BEFBEE5BAD15BA71BDDC38FD723CF695AF7CC53574D1EF0200209F0400905801E8AFE85F4529E846E176E79D774ED65B6FBDE4A8A38ECA56C8C6E98D77D96597EC3563C68C490E3AE8A0B6ED63BBCD37DF3CBBD6EDC61B6F9C1560F3826E3C1FD7CD9D366D5A5B4177934D3649AEBAEAAA64F6ECD9D9FBFDE637BFC9EED7AED08D6BF86EBFFDF6C9EB5EF7BAB6532E772CE8FEF39FFF54D045BF0B00807C1200406205A0BFA26F14A5A07BDC71C76505D328D456ABD5E4E1871FCE0ABABBEDB65BF69AFDF6DB6F8582EE9C3973B2DB871C72485B4177DB6DB74D264F9E9C6CB6D9665931766DAFA1DBB1A0BBC71E7BB4DB5E4117FD2E0000F2490000891580FE8A5ED39B05DDD34F3F3D2BB0E66DEBADB7CE0AA39FF8C427DA3DFECB5FFE3279F6D967DB0AB551D08D42EA8C193392830F3E387BCD09279C90DDCFBF6F6CB7DD76DB257BEEB967F29EF7BCA7ADA01BD7D9FDC217BE9015831F7BECB16CDB2BAFBC323B6573ACAEBDF3CE3BB3F7BBF6DA6BB3FBF1BE2D2D2DD9760F3DF450B63A380ABAF17C7CC6473EF29164D75D77CD5E3373E6CCE4DDEF7E77D2D4D4A4A08B7E170000F9240080C40A407F45EFEBCD82EE25975C921C79E491AB6C7941B5B6A01BA758FEE4273FB9423BFEF8E3DBB6FBEA57BF9A156EE3F4CA1D4FB9DC555BB87061569CBDF1C61B5778EE17BFF845F6DCD7BFFEF5EC9ABC6F7DEB5BB3F72F97CB59113A9E7BCB5BDE92CC9F3F5F4117FD2E0000F2490000891580FE8ADED797A75CEE4EBBF7DE7BBB759DDABBEEBA2B59BA7469DBCADA458B16258B172FCEFE5DD9EB9E79E699E49A6BAE697B6D6D8BCF8DF788DBCB972F5FE1F9A79E7AAAD3C71574D1EF0200209F0400905801E8AFE815452BE80EF5A6A0ABDF050000F9240080C40A407F451B055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF2828055D055DF4BB0000C8270100245600FA2B0A4A41574117FD2E0000F2490000891580FE8A8252D055D045BF0B00807C1200406205A0BFA2A014741574D1EF0200209F0400905801E8AF28A872B9FCC2B265CB14530BD0D2BFC3A2B973E72E1795FA5D0000904F020048AC00F45764E6CD9BB768C992250AAA0568F7DE7BEF6FE7CE9D7B8DA8D4EF0200807C1200406205A0BF2253A95476BDE4924B9E5ABC78F1A356EAF6DBCADCC50B172EFCCDDCB973EF4BDBCEA252BF0B0000F2490000891580FE8A3651448C95A1697B2EAEE1AAF5797BAEF5F7AF98ABDF050000F9240080C40A407F05A0DF0500403E090020B102D05F01A0DF0500403E090020B102D05F01E8770100904F020020B102F45700E8770100904F020048AC00F45700FA5D0000904F020048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B00FD15807E170000F9240000122B407F05807E170000F9240080C40A407F05A0DF0500403E090080C40AD05F01A0DF0500403E090020B102D05F01E8770100403E090020B102D05F01E8770100904F020048AC00F45700E8770100904F020048AC00F45700FA5D0000E493000048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B407F05807E170000F9240080C40A407F05A0DFF55B0000403E090020B102D05F01E8770100904F020020B102F45700E8770100904F020048AC00F45700FA5D0000E493000048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B00FD15807E170000F9240000122B407F05807E170000F9240080C40A407F05A0DF0500403E090080C40AD05F01A0DF0500403E090020B102D05F01E8770100403E090020B102F457FA2B00FD2E0000F2490000891580FE0A00FD2E0000F2490000891580FE0A40BF0B00807C1200008915A0BF0240BF0B00807C1200406205A0BF02D0EF0200209F944F020048AC00FD1500FA5D0000E4930000122B00FD15807E170000E4930000122B00FD15807E170000F9240000122B407F05807E170000F9240080C40A407F05A0DF0500403E0900C0AA93A86A2452AB6855BF29C0401000FD2E0000F2490080BE4FA28677A3A03BDC6F0A30100440BF0B00807C1200A07F12A9AAD5B980812000FA5D0000E4930000C54CA4865B9D0B180802A0DF0500403E090050DC64AA6A752E602008807E170000F92400403193A9E156E702068200E8770100904F02001437A1AA5A9D0B180802A0DF0500403E090050CC846AB8D5B980812000FA5D0000E4930000C54DAAAA122BC0401000FD2E0000F2490080622655C3255680812000FA5D0000E49300C0A09324C9CB172C5870CE95575EF9AF72B99CCC9D3B7740B648AC06EA774F7FEF2FCC9B376F51A552D955FCCDD5C49F812000FA5DE493F249C4BDB817A79A38954FA25FD3F46B00B97427746EDA09264B962C49962D5B963CF7DC735A1FB7F8BDC7EFFF924B2E792ADD31ED2CFE34F1672008807E17F9A47C12712FEEC5A9264EE593E8D734FD1A40268E288A4ED00EA1FFDBE2C58B1F4D7744D7883F4DFC190802A0DF453E299F44DC8B7B71AA8953F924FA354DBF069089D34338A2A8384718A53BA2E5E24F137F068200E877914FCA2711F7E25E9C6AE2543E897E4DD3AF0164E2DCF37602C569F1F7107F9AF833100440BF8B7C523E89B817F7E25413A7F249F46B9A7E0D60B57644FF7C7271B2E0DAD392F92D47672D6EC763761E7644E24FFC61200850A03EB61AFDEC2A5AD56F4A3E299F944F8A7B4DDC8B53718A713CFA35FD1AC0A0DA112D7DE2C1E4968BBE9FFCEDCF93DAB5782C9EB303B123127FE20F03418082F4B1C3BB51D01DEE37259F944FCA27C5BD7815F7E2549C621C8F7E4DBF0630A87644F7CF9FBDC24E286F0FCCBFC00EC48E48FC893F0C04018AD4CF56ADCE954FCA27E593E25EDC8B7B71AA8953E378F46BFA358021B523BAAD3AADCB1D513C6707624724FEC41F06820005EA67875B9D2B9F944FCA27C5BDB817F7E25413A7C6F1E8D7F46B00436A4774CBDCA95DEE88E2393B103B22F127FE30100428585F5BB53A573E299F944F8A7B712FEEC5A9264E8DE3D1AFE9D700EC88EC88EC88C49FF8C34010A0987DED70AB73E593F249F9A4B817F7E25E9C6AE2D4381EFD9A7E0D60C8EC88E6B71CDDE58E289EB303B123127FE20F03418002F6B755AB73E593F249F9A4B817F7E25E9C6AE2D4381EFD9A7E0D6048EC88EEBC6266973BA278CE0EC48E48FC893F0C04010AD8DF0EB73A573E299F944F8A7B712FEEC5A9264E8DE3D1AFE9D70086C48EE8B1076F4E6EB9F8072B9E26227D2C9EB303B123127FE20F03418082F6B955FDAE7C523E299F14F7E25EDC8B53712A4E8DE3D1AFE9D70006FD8E28DA3DD79DB9C28E281EB3F3B023127FE20F03418002F7B9C3478C18A1DF954FCA27E593E25EDC8B7B712A4E318E47BFA65F0318E43BA2E5CB933BFF7AF28AA789481F8BE7EC40EC88C49FF8A3DBB66D1D086EEB5701D037FDEE861B6EA8DF954FCA27E593E25EDC8B7B712A4E318E47BFA65F0318BC3BA2A54F3C98DC71457397E7FE8FE7621B3B113B22F127FE58F520306D4BD236B1F55F834100FD2EF249F924E25EDC8B53712A4EE593E8D734FD1AC01AEE88962F4F16DF5949FE3EE7F02E7742798B6D625B4719D911893FF1C72A0781DB76711F00FD2EF249F924E25EDC8B53712A4EE593E8D734FD1A40F77644AB3A9AC851467644E24FFCB15683C0553D0E807E17F9A47C12712FEEC5A93815A7F249F46B9A7E0DA0EB1D51778E265AD9514676287644E24FFCD1EDC19EC120807E17F9A47C12712FEEC5A93815A7F249F46B9A7E0D60F576446BBA13CA9B1D8A1D91F8137FACD620CF601040BF8B7C523E89B817F7E2549C8A53F924FA354DBF06D0FD1D91664724FEC41F7D3608341804D0EF229F944F22EEC5BD38D5C4A97C12FD9AA65F1B34BEF5AD6F6D5C5757B7FBC891234BE9BFE5B4DD93B667D396B4FE1BF7CBADCFEF1EDBFBAD0D414F3DF5D4A6B367CF3E7AE6CC997F3BEAA8A31E9D3265CAB2030F3CF085089471E3C6FD7BE2C4894F7FEF7BDFBBEFE8A38FBE60D2A4495F4E5FB28E1D911D801D91F8D32442FD3808341804D0EF229F944F1640E389D52D1B7FF6D757887BCD384A9C8A53F9E460C927BBBB6F9B3CEDF2D71C7462F5D5DD7D7ED289D537ADECFD0E2D5DF8DA29B3E66EA45FD3F46B033FF75C1DA3468DDAA1AEAEEEBCB43DD75ABCED6E8BEDCF8BD7DB250D01575F7DF5B81933663C78C001072453A64C49CE3DF7DCE4FAEBAF4FEEBEFBEEE4B1C71E4B42FC1BF7E3F1787EF2E4C92F8C1933E6B94993265D347AF4E87749B0353B22F127FEE8A741A0E202807E17F9A47CB287C484737DA9F29795B57C523ABD3DBEB1B9FC9D680DCDE55B1B4A9533DAEE97CA0DE25E338E12A7E2543E59847CB2B7F76D8DCDD5FAFA52F5808E8F1F78D2659B3434574E8FD7D53757F74ADFEB8F53A74E5D377DECEE957DDFF80EF5A5F2219D3D97BED7FF76F97334557ED6DDDF497C8F8E8F1D5ABA7083151FABBE75ECACEB5EA65FD3AFC93D7BCFA851A3B6A9ABABBB6A358BB85DB5ABE2FDEC9E06A19B6FBE79A7934E3A69D1D8B16393DFFFFEF7C9238F3C92AC8ED83E5E3766CC987F3536369E9306CAEB24D89A1D91F8137FF4D2202EA9698A0B00FA5DE493F2C95ED03AF97C6363F3A51FECACC573B1CD8B93CA959D1B9B2B8D0DA5F2CD0DCDD5DDB256AADC99DE3F309E13F79A71943815A7433E9FECCBF7E9B77D5B7DA932A9B1A9BA6FC7C763F560FA9A53EA9BAA273496AACDF5A5F2110DD3E7BD397DEC9186A6F2D4688DA5F22756785DA97278637379BFCE3E2B5B95987FEFA6F2C478FFFCFEA1A5F2161DB78F95BEE93637D5375747BE98E127EBA4F74F4ADBC28652F5C2F83EAD3FC3F8F899D3CFBE62C439E7AC973DD65CD9B1A1A97A717E5FBFA65F937BF6AC6F7DEB5B1B8E1C39F2C4BABABA173A16661B1A1A925FFFFAD72B5D7819CFC7769D14755F88F78DF7B7AB1A04D2BFFB7A175E78E1EC28E49E71C619C9D2A54B93B511AF8FF74903E4D9BDF6DA6B3709B626C1167FE28F5E18BC75A7B0A0B800A0DF453E299F5CDB49B552E5F286A6CA8498C46DDFB289E3CB639BC6A6CA1EB1C2A8B15459903E765FDC6E6D0FE4B71B9BAA75E25E338E12A7E27448E793FDF57E7DBA6FAB6FAA9E5C5FAA4EE9F8F884A6CA4EE9FBDC92B6246D8BE273D2CF189BFE5B6E2D40DD7E68A9E57DF54D73DFD6582A7F296FE9E3673796AAC7D43E76D8CCF2DB3BBE7FF67D9B2A4777F5734F3DADBA6143A93A2F3EFF90E64BDF198FA53FF3C1E9FD39D94AE1A6CA7763757156E44D7FC6C69FCDD9347D6EEEF8A6EA07C6375DFAEEF4F6F507CF6CD94CBFA65F937BF6BCBABABACD478D1AF5B7DA42ECE8D1A39359B366250F3CF0C06AD5E762FB785DBCBE4361F7A6F81CBBAC012CFDFB6E7CD65967DD71F0C107270B162C487A52BCDFD8B163978D1933E62809B626C1167FE28F1E1EB475B7B0A0B800A0DF453E299F5CCB49B5B8BE5FFD8CCA7BDAB79637E6936AD9A4F0F44BB74AEFFFAAA1543EADB6353695CF8A096A71AF19478953713AE4F3C922BC6FAFEFDB62556BFA9A7B3BAE643DA4F9E2B7D497CA37BC58A0AD5C97157E9B2ABF4C6FB74481363EE7C5D7B77CAEA1A932ADAD952A8F6545AB9AC7D2D77EB6617A75E328CCE62D4ECB9C6E3BB3F6B1D826DE73EAD4EAFA0DA5EAECF4F953D3F6706B61609D170B622D9F8BBBF5CD955D1A4BD573B295C4CDE55B5B57F32E9C78F2456F485F7B4DFABBF9907E4DBF26F7EC79A3468D7A6FDA1EAC2DBE4E9B362DB9FFFEFBD7AA3E17AF8FF7E950D4BD3F3ECFAE6B008A626EA9547AE288238E489E78E289A437C4FB4E9932E5D97DF6D9E74C09B626C1167FE28F1E1CACAD4E6141710140BF8B7C523EB916936A93A75DFE9A175713C564703621BC282689DB4DAA3597B78B89EAB4FDA4B6C58A9E784EDC6BC651E2549C0EF97CB210EFDF9BFBB6287AC62ADCFAE6EA79F5CD956FD63ED77A4AD8E1F5A5CA71134AD54F4D38F1D2CDD36DABD9AAD9A6EAFE8DA5CA0A8BA226942EFDEF749BBBD26DFE1AA7576EF75933AB5FCDAEC9FB52BB34DDF66FED1E8BD3CEBE58B84D6F57A7C777686C2A5F10AF3FACB9FADE283CB77DBFA6CA84F43BFC286EC73548E367682C95BF16D7FA4D5FBB7BFA1E9F19DF54F9A26BE8EAD7E49E3DA77565EE83B5AB7267CF9EDDA335BA78BF0EAB75EFB752778089D32C9F75D65977463137FED3F6A678FF8913273EB9E79E7B7E4F82AD49B0C59FF8A3870669AB5B58505C00D0EF229F944FAEE1A4DAA1A50B5F1B13CE6D93BEA54A357FAE7652ADA1B972554C48D7B6749BAB157435E328712A4E07753EB94EDAF66DFD776D74F63E3D9E4FF6D6BE2D4E5B5CDF5CF973AC788DE26B145863656CFE7CEBE9932F4A5FFF78FAEFEFE3B3A3389A9D3AB65479AA617AF5231DBF6BAC98CD4E3DDB5CF94C145857F6737575CAE5C6E6F2B8F4FD9FCE0ABA712ADB52E5FAFA19E5CFB7166BFF54FBF3C77B74F8FC63D29FF3D8B8E66EAC246E2895FF373B2DB37E4DBF26F75C6B714DDBDAD32CEFB7DF7EC98D37DED82B35BA78DF78FFDAD32FBBA6EE0012D7CC3DE490437A6D656E672B75F7DF7FFFA7D340D94582AD49B0C59FF8A30706676B5258505C00D0EF229F944FAEF1A45AE5A1974E675779A8E3A45A7DA9323E561E65AB7AD2DB8DA54A5376CDBDE6F257EA9BAB7B897BCD384A9C8AD341994F46F1F5D4D61CF1D4616B5ED45DD9FBF4683ED95BFBB678AEB1546DCEEF3734578E4F5FF397834EACBEFAA56DAAE7BC78BDDC72434353796AEB769F493FF3DF8DD35BDED5EEFD9AAA7551C4CA4FDD1CA7914D3FE3F0AE7EAEAE0ABAF17D2734B57C215A5CA737FDDC43E334CA71ADDE288665D7CF4D7F9EFC76DBF78F55B9A5EAEC58E19BBEF7EFA2509DFE3C93E277A15FD3AFC93DD7DEC891234FAC5D99DB5BC5DCDAA26EED4ADDF87CBBB30120FDC3ED3C76ECD81EBF666E77AEA9BBD75E7B3D3162C488D74BB03509B6F8137FACE5A06C4D0B0B8A0B807E57BF8B7C523EB99A936AD9C46E9CE6AEA6C5046F9CE62EDB6666F9A3E976971D5A2A6F1113C2137F7CD1ABB26B03CE6CD9A1A1A93C234E01593FA3656B71AF19478953713AE8F2C97D3BE4896B52D4AD2DE6E66D9FDECA277B7ADFD6F8B3399B3694CA7F88EBD7D6AEC8CDDE3F56B7C67573A7CF7B7376BFA9BC77BADDF2B4FDA7BE543D2056E5C6F56AD3D78FCA4E979C6E17AB76D3CF2BA58FDD91BF2E4C9D7ACECB5B4FA3FCDBB1B32E7865C79FABB1B9725067A76D7EE9F5711DDDCAD238956DDB6B4AD5E6EC734A95EB6BAF39DA7AEAE86BA3A896DD2F558E8CCF4DFFBD2DAE05AC5FD3AFC93DD7CEA851A3B6A9ABAB7B3E2FAE5E70C1057D52A38BCFA959A5FB7C7C0F9956C19D74D2498BCE38E38CA43F9C7CF2C98BD2406992606B126CF127FE1415D67230B6368505C50540BFABDF453E299FEC8629B3E66E547BBABBB609EA5265E7EC1A81A5F20DD9CA9D5275FBC65265DBD6C9E239F5A5CA95311917FF4E68AAEC34A154F970C3CC966DC4BD661C254EC5E9A0CB273B2BC6AE4E51B7B3D7FFA28BD7F7483ED9D3FBB628764671B6ABCF6B6CAA8C4D9F9F122B63E37AB471EAE58367B66C16AFCB56ECB69E6A390A51F54DD5131A9A2B93D3ED4E8D025567EFD7D054F96EED698FD3DB1FCF4E315BAAFC3D4EA5BCBABF8FDA15C46D9F31FDD2AD3A166EE3E7AD2D06EBD7F46B72CF3557575777555E589D366D5A9FD6E8E2F36A8ABA57C9B40AECEAABAF1E17AB739F7EFAE97E29E8C6E7EEBDF7DE4F8D1E3DFA5D126C4D822DFEC49F41E05ABCC7DA1616141700FDAE7E17F9A47C52DC8B37712F4E3571BAF679DC9A167557A7983B74F2C9245947BFA6E9D706AF3DF6D863FBDA532DDF7FFFFD7D5AA38BCFAB3DF5727C1F7F95829A3163C683E79D775ED29FCE3CF3CCBBD340996547A4D911893FF16710D8CF8505C50540BFABDF453E299F14F79AB817A79A385DFBFC6D758BBA6B52CC954FEAD734FDDA80575757775E5E4C9D356B56BFD4E8E2736B56E99EE7AF52404F3FFDF466E3C68D4B1E7EF8E17E2DE8A69FFF9FD1A3472FA9BDC8BA1D91664724FEC49F41603F15160C0601FDAE7E17F9E480CB2707DB785ADC6BC651E2549C0E8A7CB2BB45DDB529E6CA27F56B9ABC73C01A3D7AF426757575CFE5C5D4BE5E9D5BBB4AB7A6A0FB5C7C2F7F9D82F9D39FFE74D49429539222D87FFFFD17A681F2E981F07B4BBF67356DC3ED8824D8E24F33C0EB7E4CF6C160AB270B0B0683C0509F7CD3EF0E62F2C9C1954F3EF4D043EFBCEFBEFB6EB9E1861B9E3BF2C8238F1F3E7CF8FAA25CDC1B4789534D9C16681CBFAAA26E4F1473E593FA354DDE3920E33F7D7EF7BC90DAD0D0D0AF35BAF8FC9AA2EEEEFE8205D3DCDCFCF773CF3DB71005DD534E39E5A634487E3840FE23E641BDD2FF907644126CF1A70D91826EB762B20F06593D5D583018040613FD2EF2C941964FA6C3E8F5EEB8E38EE9CB972F7F3E1F57A7DBFDFBECB3CF7E70BFFDF6FBB44817F7C651E25413A7051AC77755D45D7758CF1573E593FA354DDE39E0E23F7DBC39DFEE57BFFA55BFD6E8E2F36BBE73B3BF60C11C75D4518F5E7FFDF58528E8CE9B37EFE6912347CE1E60FF1157FA1FD28E48822DFEB42156D0EDEE80B0B70657BD51583018040603FD2EF2C941964FDE73CF3DDB2E59B2A4CB6B272D5CB8F05FD3A64D3B77C488111B8978716F1C254E35715A90717C6745DDDB87F56C31573EA95FD3E49D032AFE478D1A55C99FBFEEBAEBFAB546179F9F7F97F85EFE82053379F2E4650B162C284441F7F6DB6F8F532E5F3B40FF2376FA1FD28E48822DFEB4215AD05D5992DE9B83AADE2A2C180C0203997E17F9E420CA2753AFB9EBAEBBFEFCFCF3CFAF728CFD422A7DCDD2C6C6C67D45BDB8378E12A79A382DC838BEB3A26E4F1773E593FA354DDE3960E23FFDF7BEFCF1FEAED5C5E7D77CC7FBFC050B66DCB8712F3CFEF8E38528E83EF6D8634BD320797080FF476CF71FD28E48822DFEB4215ED0ED98A47467309514A0190C0283857E17F9E4206A575E7965F2D4534F2D5BDDB1F6134F3CF1AF534E39E5FA112346BC53DC8B7BE32871AA89D35E18C7AFAE38CD72C795B9B7B73EDE1FF930FA354DDED99FF1FF4C7EBFBF6B75F1F9352B749FF6172C98BDF7DE3BF9F7BFFF5D88826EFA3D9EEE46800FA8D6DF3BA2679E7926EB7CE3DFFEF8FCA79F7E3A3AFEC2EC88065B7CF566FCC5DFEDFEFBEFCF6EDF7BEFBD2BFD3BC6913B0F3CF0C02ADF73D1A245C96DB7DDD6ADCF8FF77BF8E1877B2D16962C5992FDDFE8EAF9471E7924993F7F7E767BE1C285C9934F3E992C5BB62CF9C73FFE912C5DBA54FCAD414B13B964C30D378C41DAC455EC9A8A5C5818D6FAFD6330F84A59045070AF6CEDAF067CBF3BD4F7A143753C1379D7E2C58BFB24F7ECCF1CB1BB2D7E9E9FFCE427C9A38F3EBADA63ED784DBC564C1723EE9F7DF6D9151EBBFBEEBB93871E7AA84FC75C0321EE8DA356DE86529CAE6A7EEB89279E58E1B3632E23E6A5CC37F5C9387E75AC6C85EEA9C37A7685AE7CD2FE7785D6B1FFB9E69A6B92E5CB97AFB0DD3DF7DCD3ABDF43DEA975D6FABB56179F5FF37DFE635AA5600E38E0807F1765856EDA49DD350856E816E65411D1C97FE52B5FC912A29D76DA29BBDF31B17DCF7BDEB3CA9617F5E2FCE95B6EB965A7EDC4134FECF43B6CBBEDB6C997BEF4A5E49FFFFCA723260758FCFDE637BF495EF39AD764B737D86083E4DC73CFED74BB18CCBDF9CD6F4E3EFAD18F26BFFEF5AFDBB5D881C736311177D9659725BBEDB65BF2C10F7E30BB1DEDFBDFFF7EF2BEF7BDAFAD9D75D6596D83C04D36D924F9AFFFFAAFEC3DB6D9669B76DB456B6E6ECEB6FDF18F7FBCC273B52D4F7022013AE18413DADACE3BEF9CACBBEEBAC9B1C71EDBEEF13BEFBC33DB3EBEFFEB5FFFFAECF6461B6D949C7DF6D9C9830F3E98FD7F8AFF0B8E2C5FB3981C66A518405FD3EF52D8F14C4C9ED5E66DEF7FFFFBB349AAFCF9FFFEEFFF4E66CC98D1ABB9671172C4D569E79D775EB2FFFEFB5F5CA9541E79E185179EEFC630FB3FE9EFE3B7DFFEF6B7FF9EFE5D2FB442B7FFE33E62EEAD6F7D6B72FEF9E7B77BFCBDEF7D6FF2C31FFEB04FC65C032DEEADD01D9A71DAB158BBE38E3B663117FFC63C66C7CF9F3C7972B2CE3AEB24A79D765AF6995124D9628B2D92CF7FFEF36DDFE3861B6E10A7BD378E5F9B62EEEDBD5CD4954FEAD7DADA05175C90BCEC652F6B2BA4461F147177D14517B5DBEEEF7FFF7BD6A7C4F3D1AF44DF56DBA64D9BD6969B8D1F3FBEAD1D70C0019DCE4FC60131F24EF1DF55FCC74A582B74E996C30E3BECE9A25C43F7D65B6FBD6E005F43B75017738F24F9B39FFD6CF28E77BC239933674EF2F6B7BF3DBB1F47FEE4DBDC75D75DD90EE088238E4866CE9CB9423BFCF0C3B3E763BBFCA8A05FFDEA57C9E9A79FDEAEBDE52D6F498E3BEEB84EBFC75FFFFAD7E495AF7C653269D22405DD01127FF951B8DD29E8C6D1AF51B48F3879E73BDF99B588B9B8BFFEFAEB67C94A6C77E69967763A79BBCF3EFB64711945D9B83F7BF6EC6C122FDEF3939FFC64F2C52F7E31D975D75DB3D79F7AEAA9592C8D1D3B36BB9D272E13274ECC0ABF31E0AB6DDFFDEE77B3F7CC8FC68DEF1FDFE9CB5FFE72972DB6BFF0C20BB3EF1D83C18D37DE382997CB0ABA3D18937D3098722D4700FD2E03643C73C9259724AF7AD5AB92E9D3A76793F91147318E89D510D1B6DA6AAB64EAD4A96D676DE98DDCB30839E29AE493A3468DDA23FD9DA5C3BB250F7735BE7EFEF9E76F9C366DDAB9E9DFF581D85ED41723EE63BCF5ED6F7F3B8BBB18D7444C45DB6CB3CDB2F8CEEFC7CA1871AFA03B94E334FF2EF7DD775FF2894F7C225B4C103F731469E37EED6ADC58B010F3059B6FBE79561C897FE3A0A078AF982F887F63C142A95412A7FD3B8EEFAC981BD7CC5DB793C77BAAA82B9FD4AFB53BF0248AB3EF7EF7BBB3A26CDCDE7AEBAD93B7BDED6DD9EDDA33101C7AE8A1C9C73FFEF1ECF6D5575F9D1D64182DCE761A31FAF39FFF3C7BEE97BFFC65F2A94F7D2AEBEBF6D8638F6C6153CC67467137F69DF17C6C1FAB82E59DE2BFABF8770D5DBAED88238EB8FFFAEBAF2F4441B7A5A5A53C72E4C8D903EC3FE2CA929D7E29E8C60E288EDE89A4353F3544FC478C9DD51BDFF8C6B6231DF3826E9C02218A671D5B9E48E705DDFC68CCCE92EFAE0ABAD17EFAD39F661335DD39ED8E8160FFC6DF8D37DE98C54E14413B2BE8C6113AF1FC2DB7DC92155E6340F4A637BD2979C52B5E916CB7DD7659C2317CF8F064D34D375DE1C8B648428E3EFAE8EC1426B16D0C0A6380B8D75E7B253FFAD18FB2F78D53271D7FFCF1D9E7C6F67FF8C31FB2F78ACF89E42A622DB68BDBF9CF1605DD612B59F1931774E3FBC4AA8F7C82308EC41BD67A045EFED8873FFCE1E48A2BAEC82615E3678E23F122E623693AE38C33B26DE23531B118AB866FBEF9661311AB19937D30A8EAADC282412030D0E97729DC78260ABA3149B5E79E7BC6D1FF6D93FA1DF3B9830F3EB8D772CF22E4886B9A4F8E183162A3F47777729AB73FF99FFFFCE7D99AA1F5D3D75D77DDE9E9730FA47FDB93623B115F9CB88F03A5A358F5FBDFFF3E99376F5E7656AD68AF7EF5ABB3B8CAEFC744AEB81FF205DD211DA751548EF88B988BD5BCF9D9E3A2C0FB810F7C203BAB57535353F6F9279D7452566C8E79A71D76D8215B2117FFC6FBC79C40ED5C9838EDB7717C57C5DC7556F2FCDA1675E593FAB5762D8AA0115B7160481C3898B798331F5653248DB35C461FF3BBDFFD2E3B80E4B7BFFD6DF6F8B5D75E9BF56B71C048ED299AE360957C0E75DF7DF7CD0E6889D7BDFCE52F4FBEF6B5AFB51574E59DE2BFABF81F356A5425DF2EE2B03FC5E7D7ACD0ADF80B164CFA9FFF8228D414C1B1C71E7B5E1A283F1C20FF11BB95ECF47541F7C0030FCC3AF548B2DFF08637B4DB3945721D3B9778BEB1B1B1ADA01BA74FE86C856EECB486B51674E368C7889358911B4716D5B638A54E4CC2C4F3713EFF8EDF294EA513EFD3D0D0A0A05BF0F88B5363478CFCE94F7FEAB4A0FBC73FFE311B08E5A7C28B23C462703761C28476936EDFFBDEF7B25393E4C9CD1D77DC910DA822A189F7896D4E39E5946CC016ED431FFA5016BBF9299423AEA64C99920DDAE2678855B971C45C0CFCE200814888E2142979413756895F7AE9A5C955575DD5AEC50AF1389AEEFFFEEFFFDA4E55326C25C5DF78EFFC77D1F1B426F1FCE73EF7B9ECDF384061DCB871D9CF652262F562B20F0657BD5158300804060BFD2E851ACF7456D08D2242ACD2CDCF1614078EC6A9367B2BF72C428EB8B6F9E4C891233F555F5F7F6BEAA1C71F7FFCB2F4F71313427F8BC7457AF1E23E0A4FB18230C63CDD3995ADB81F92055D719A6E3B66CC98ECF9287EC41C40EC2FF216D774CD0B30071D7450DB2AE158CCF03FFFF33FD9F651CC8D9F21560EC7FC96F9A67E1DC7AFAA98BBB2EDD6B4A82B9FD4AF7559D08D79EE8E97251C5653D0FDCE77BE93DDFFC8473E92EDF7E23221B1AF8BF9D1E807D75B6FBD6CDE320E3E89BE27F2D6384B40A552C90E4E8C8552A3468DCAE655A3F03AACB5A02BEF14FF2BD9A6392FA2C61952FB537C7E4D11BAD95FB060D2CE67C7C99327BF50807AEEBF478F1E7D731A249F1E4CBFDFBE2EE846121D45D738C2274E25D3B1C5E3B182370A5D7941F7A69B6ECAFE83C64E2A6F23468CC81E1FD65AD0FDCB5FFE929D3227AEA112FF46012D9E8B9592713F7668F16F5E64ABBDC87C24D0F94EAF76B5AF826E31E36F975D76C906449D157463601583A3782C8E847DDDEB5E97C5416C174785C5EA8938A5485C1B221E8FA3D96205783CD659921247CC468213071CC4A02E3F0A2E068F91C0449214D7CA8D09BEF85E710AA6386237066F79AC453CC7D16A5D254291F044BCE789501C49176725882386E3F9F8B9E27E1C9DD731697AED6B5F9B1DF010EF11D7B3B8FCF2CBB3D7C49172E2AFB093F63D5D58300804F4BBFADD21ADAF0BBAB1222B5653C541A3717DB3FC1ABABD957B162147EC897C72F8F0E1EBA73FDBE4745CF748FC1BF7456F71C7F17149A258DDB8DF7EFB65A7668C1613B37196ADFC7EC4A0B8378E1ACA711A0769476CC6E945E3A0F38E2D56ECC62AE298BB8A224A7CD728B2C425C7E260F458C91B67FDFA7FFFEFFF659F110596983313A77D9EAF75B798BBB2ED57B7A82B9FD4AFADB4A01BF39BD1C7E52DE6AD87D51474E37BE407A8C4B572E394CA71204ABE6024E64CA3801BFBCA934F3EB95D7F1607A7C42ADBB83E6E9CB5E090430E59A1A02BEFA4A3F477B97B5E448D4571FDA9BEBEFE859A82EEEEFE3A053375EAD475D3C1F373715DA2FEF4C0030F5C9106C8E2F83E76446BD7E2C2E9F9D18D9DB5FCC2EAB505DD28E28E1E3D3A3B75431C49142B236B0BBAB17D5C943D4E2911473C46812C9E8BA390E2A88D986C89A26FC7EF123BC4D8E9C5ED8F7DEC63D9648D826EB1E32F56674771BE634137928818A4FDF9CF7FCE1E9B3F7F7E56F88D98895335C7B525E2344B71F46DB4385D48C44C9C9E398EC69D356B5656A8CD5B1464F3D32AC5B528E208DA187045CB0F2C8855E551AC8DB889826E0CC06210981774E328B4486062B0164955DE2226E3144C91E8445CE631DCDDA3E0E29A14917CC5633128740DDD01555CE8C9C2824120A0DFD5EF9A58EB8382EEEEBBEFDE36911605DDB804473C16638FBCA0DB5BB9671172C49ECC2707DB787A308FE36312374E3B1B13C6F9E96AE376DE5A5A5AC4BD71D4908ED3D81F44D1388ABD2B6B7110508CFB77DA69A764D75D77ED349EBFFAD5AF263BEEB863DB7C8638EDB37C72758BB92B7B5D778BBAF249FD5A972DE607637E316F7156BFE83BF2FBB5AB5D639E3C169AC4429238702572D5FAFAFAB616B96A7EF681DA532E478137FAB3CF7CE633D9FC653E1F1FFB4D79275D49E36D93BABABAE7F2426A1CB4D41FE2736B8AB9CFC5F7F2D729A04993265D14477AF4A7638E39E6376990CCB2235AFB16097074EC71947BEC6CF21609723C1ECF7756D08D899328EC47A2DD5941374E7D16D740896DE3A8C9782EB68B626EEDD143B5897FECB8A2D816F723C18ED5BA7194A5826E71E32F0AFEF1B7FDC10F7ED0AEA01B1D794CB8C56999F36DF3235DBB6A471C7144DBB671A4ECE69B6F9E2543F13E918CE483B6783E4EA31447BDC5ED5B6FBD358BC558911BDBC4D16C9160C5D1C0175F7C715B41B7B36BAC75D6E288E23C698A23832306E348DE782E0AD771BFF628B8F3CF3F3FD97EFBEDB302767E5A938E4953EDEF41FC15AAB8D0538505834040BFABDF6558DF147463E23F0E2A1CD6BA42214E2D17078ED616747B33F7ECEF1C513E39F4C6F1F901D2718ADA38CD78C4685C7A262E611463ECDA31B3B817F743354EE3524F871D7658D6E2D24FF119713BE6B7629570DC8E4B30C5294FF3B37DEDBDF7DED92AB7D8774401378ABD71EDCB28D4E4DB89D33ECB27D7B498BBB2D7AFAAA82B9FD4AFADB4C5A5DC629F17FD4DB55ACD56BFFEFCE73FCF9E8B53287FEB5BDFCA6EFFE217BF688BBB583012796A1C1812B9692C3C89DBDFF8C637DA5D433756ECC6D903E27ADD71204C5C82302E8918B7A3DD7EFBEDF6BFAC545D5DDD797931350E7EEA0FF1B93505DDF3FC550A6AF4E8D1EF1A3366CCBF22D1E90F4F3CF1C43569803C1CDFC38EA8E70ABA8F3FFE78BBC7E3FEB09514746B93A4CE0ABA0F3DF4505B012D12EE61ADE7EDDF6CB3CDB29D51EDC5E0E300812802C6D194B5DF217644714467BCB7826E71E32F8E5A8D84A6B6A01BAB5EF3D8C95B1C311B2D56CD464213AFCB1F8B6BDEC660AF76D03667CE9CEC761468F3415B5CCF2612AA88A3484CE2F94F7FFAD3D9445E9C82241295E9D3A7275FFCE217B3EF112B70E328DC485CA2CF7AECB1C7B2442B2602E3F425713F6235E2330E2688FBB1DDDA5EA7A263D2B4C71E7B747A2083F8EBF7C9FC9E282C180402FA5DFD2E7D309E89DC2A563C449E181359C71C734C7600DFA9A79E9A3DDFB1A0DB5BB9677FE788F2C9A1378E8F49B298208EDB471E796416538F3EFA68763FC6D85FFFFAD7C5BDB817A7ADDB4781245E93FFBCB12A381616445C76FCCEF159B14238B65D7FFDF5B3B981B8966E9CFAD47C539FE793FB0E5BF3626EAEB3A2EE3EF249FDDA9AB4587D1BFD532C14897FE394ECD10745DF13972F8CDBD16FDC73CF3DD94293782CE64163FF16672288F788B9D128D2D6BE6F1C8C985FD736FAAF38D824E6BFA3FF8C330EC4ED68711D5EFB5F5626FD7B6E9F17536385785FAFD28DCF1B356A54DBE996E3FBF8AB14586363E339717A94FE907EF6D9699034D911F56C41F79BDFFC66ED1115D9A920867551D08D9D415C003E6F7124661C5D14CFC72996E37A24B103D972CB2DB3CE3C767EC35A4FB91CA7998895B7FFBFBD7B01B2ABAE0F072E8F2AA01544B04E112B288DC58A967690581DA3680B858A74389C3D09221A0151C8EE461E02A504860E0F11D8DD84470B96E2C08838541019FC6FF65E12B1415E02F29077082621101E2148122A9CFFF91E73334BD8BC36DCDD7BEE7E3E33DFD9DD7BEF3E38F9F2FB7E7FF77BCFB97139DC287031708BE63A5E01D918A435225ED519979C885717350A99816EEBE45FBC3AADF1CAB1680AA2F188CFA3D189F7B369DC178F8B8D59BC5A2C365FD1F0C4136F313C7DF4D147CBF7A58957B935DE5BA2B1698B8D545C3E3986AF8D4D5BE4E5673FFBD9F255B6F1FDF1D878C56FBCE236DEAB397E5EBCF7F32EBBEC5236409167F1FD8D4B8545C4ABDCE27D72E2318B162D2ABF3FF2332EED34F8BF2F7E4EB1DE94AF606B9C897CDB6DB7955FC799E9B1316CBC78E1D4534F2D733EEE8FBF3D5EF4D0B87C53BC322F7E573C0129FF5A6EB8B0B183059B40C0BA6BDD6584F6337169CE9D77DE39DF7DF7DDCB27D3E22D5AA2BF8A5E2C2ED319BD60A3DF6A66EF39DA3DA27E726CE57D3C511CFBE5C89338F331F65CF1E285344DCB4B2BC68B58637F7DCF3DF7C87B793FE6F3349EBF8AF7548FDF1DC3E218F8C615B8DEF39EF794EF4DD9384B78C18205E573585FF9CA57CA2B7DC5202686BBF1364CF17C46FCCCB83F9EAC96A723D64F0E1EC60E6798BB213F473F695D5B679C78E289E5D501E284A45887E28CDCF87D71C598B81265D4C4380969DAB469E55501A3378D752EAE1A106B4FD4C6786E34D6C3F83C22DE06EEA28B2E2AD798B85265AC4571824C449CEDDB380338A25157D55FD6A6A3A3E396C62C27AE563192E2F70D9A25DDE25FA3C52549B27DB1D0BC1CC3BB9174FBEDB7C7A5969F8EDFAF10BDB903DDC30F3FBC7C1F93461C76D8616B1CE8AEFE33A2B98EFBE2520F51E8EEBEFBEEF2558E71099B934E3AA9BC2F9E60699C951B85250A4A5C96394ECD8FC63C9AFAA1FEBEE79F7FBE1CCC35F3BD4B14A2E1E55F6CBCC68F1FBFCE88C7C5ABC2A29988C17D343F8D57CA466EC4C6EF9FFFF99FCB01FEE04D5B5C92249A9C688656BFACD2EA1103DBB80453BCA74EE461FC9EB82D9AA368B462B0BCFAFB60C4654D8E38E288557F436C20D7F4DFDA18FAC61389ABDFD7B8B44ABCE2389AB8F7BDEF7DE5DF1D9BD13DF6D86355FE375EA127FF5A6AB8B03183059B40C0BA6BDD6504F733F1FE8B7BEEB967D9B3C50B45A3CF8C3322E26A3F9153F12458E3C9FA66F79EA3D923EA27C756DE47EE449E44BEC6BE2AAE8E153975ECB1C7967BE9C8A75D77DDB53C2352DECBFBB19EA771E65B9C58102FEC8EEF993C7972F93BBFFFFDEF976FCB14CF7B350624F1A2F075450CA7E5E988F693317C3DE42DC31FE6AECFCFD14F5AD7D62BE28CD6783FDCF83C5E9C122FF668EC6362681A2733C573E431588DB35EE3B9F4461F9A2449F97EBBAB479C1C37F877FCF6B7BF2D9FC31C2AE28428F59775C9B26C7C4747C7AB8DC16AFCDB8F84F83D8386B9AFC6DFE15FA3028AE6E94B471C71C4B218B88D84A79F7E7A5691204F14F14585E8CD8B785F90386371F02590079FC9B874E9D2558F8B274C1A5F0F8E38CB3186FB430D65A3118F57CC479E8CD67BE12A44AD917F7166F75003FBA1722306AE8D5C8B5799C560365E00101FD7F4F31B6778473EAE9E9F6BFB9BE23D73D6F69846FEC759E243E57F346FF1B7C5E743FD7FB464C992216F977F2D315C18EE60C12610B0EE5A7719E17E327AAAA1DEFB2BFAACB86FF5BD48B37BCFD1EA11F593636F1F15EF0DBAB6FB07E7A9BC97F7F274CD35C4F34D6DD34F56E5F7D146CFA3C71AD7B834FC68AD1BEA2F4349D374C6E04B2FC7C0BF99E2E70FBED472FC7EFF0A153279F2E4538F3FFEF897E37FDA662A169CFB8B84BCAD4896131422A1C1967FF28F376973369CC1824D20807517FDA47E12792FEFE5A990A7A3D34FB6F2EFC1BA665D63441D7AE8A15B747474DCD518B0C65B0D346BA81B3FB7F87DAF0E3A3BF7AEF8FDFE152AE690430EB9FC98638E79A15967EA3EFDF4D337C530B748904B1422A110C93FF9C79BB849DBD0C1824D20807517FDA47E12792FEFE5A990A7A3D74FB6DACFC7BA26AC6BA3AAA3A363C7229E1C7CA6EE75D75DF7A6CEE8E2E70D3E3377E5EFDBD1D1AFA84993269D3479F2E417DFECF7D45DF99EB9F3DAFDCC5C854821927F4223342A9BB50D192CD804025877D14FEA2791F7F25E9E0A793ABAFD642BFC5CAC6BC2BAD652B22CFBF0E0A16EC459679D953FF9E4931B359F8BEF8F9F33F8E7C6EF89DFE7A8575CBCB7EDC1071FFCFC85175EB820AEE5BE315E78E1855F7577775F55FCCCA7DBF93D7315228548FE09F937AA9BC1F51D2CD804025877D14FEA2791F7F25E9E0A793AFAFDE468FD3CAC6BC2BAD6D2569EA97BD7E0E16B9CAD7BF1C517E7BFFBDDEF36683E178F8FEF5BEDACDC7CE5CF77666EBB28FE81B72BFE417BBEFCE52F2FB9ECB2CB1E7DE69967FE6F03F2E4FFE6CF9FFFCB534F3DF5CA9583DC9EF8790A915088E49FFCA3499BB7F5192CD804025877D14FEA2791F7F25E9E0A79DA1AFDE448FE1CAC6BC2BA5629F19EB6699ACEE8E8E8587D109B777575E5575C71457EC71D77E48F3EFA68FEECB3CF9643B9F8185FC7ED717F6767E71BBE377E5EFC5CEF99DBA6264E9CB873F18F7C7196654F1F76D8614F5C74D145BF9E3D7BF63D0F3EF8E0BCC58B17BF54E4C9D2A79F7EFAB1FBEEBBEFF6E27FF6FED34F3FFD9AE27BEE29BEE7A9F8BEF87E85482844F24FFE31CA9B389B4000EB2EFA49FD24F25EDECB53214FF59358D78475AD32B22C1BDFD1D171CB1083D9E1C42DF1F31CD5B16193830E3AE8EF8B7FF033D234BDAEF8C7BF75D0B5BCE3E3AD717BDC1F8F8BC72B440A804224FF8446A8053683368100D65DF493FA49E4BDBC97A7429EEA27B1AE09EB5A256559F6858E8E8E6B8A58B18143DC78FC35F1FD8E2228440A91FC13F2AF953783368100D65DF493FA49E4BDBC97A7429EEA27B1AE09EB5AE51D7AE8A1DB7474741C98A6696FF171A088C78B7879E5F0F6E5955F0FACBCFFC078BCA3060A914224FF84FC6BF5CDA04D20807517FDA47E12792FEFE5A990A7FA49AC6BC2BA06A0102944F24FC8BF16DC0CDA04025877D14FEA2791F7F25E9E0A79AA9FC4BA26AC6B000A914224FF84FC6BC1CDA04D20807517FDA47E12792FEFE5A990A7FA49AC6BC2BA06A0102944F24FC8BF16DC0CDA04025877D14FEA2791F7F25E9E0A79AA9FC4BA26AC6B000A914224FF84FC6BC1CDE031368100D65DF493FA49E4BDBC97A7AD112FBDF4527EEFBDF7961F37E67679AA9FC4BA26AC6B000A914224FF84FC6B93CD604747476E13083032C68D1BD7B9C5165B5877F593423F29EF85BC97A76B8C18CE167F72F971636E97A7EDBB8F7F8B612EEAAF750D40211206BAFEDDE5DFD8B272A00BC0C8ACB9F52449ACBBFA49A19F94F742DECB53035D36C6560E01EAAF750D40211206BA42FE8DADE182E30C3032EBED84587357C60447443F29F493F25EC87B796AA00BA8BFEA2F8042241422F927FF589F0183E30C3032EB6D7DD040B7EE88E827857E52DE0B792F4F0D7401F557FD055088844224FFE41FEB3360709C019ABFD60E3E3BD759BAFA49A19F94F742DECB53035D40FD557F011422A110C93FF9C77A0F191C6780E6AFB5F52106BACED2D54F0AFDA4BC17F25E9E1AE802EAAFFA0BA010098548FEC93FD63964709C019ABBCE0E7576AEB374F593423F29EF85BC97A706BA80FAABFE0228444221927FF28FF51A3438CE00CD5D67EB6B19E83A4B573F29F493F25EC87B796AA00BA8BFEA2F8042241422F927FF58EBA0C1710668DE1ABBB6B3739DA5AB9F14FA49792FE4BD3C35D005D45FF5174021120A91FC937FAC73D8E03803346F8DADAFC740D759BAFA49A19F94F742DECB53035D40FD557F011422A110C93FF9C71A870D8E33807517FDA47E12792FEFE5A981AE3C05EB9AB0AE0128440A91FC13F2CF600100EBAE7E52E827E5BD90F7F2D440579E82FAABFE0254DAC0C0C06BCB962D53045A208A7F870545215A2EFF84FC335800C0BA8B7E523F89BC97F7F2D440579E82754D58D7004AB367CF5EB068D12285A005E289279EF86151886E957F42FE192C0060DD453FA99F44DECB7B793A32F1D24B2F95C3D9F8B831B7CB53B0AE09EB1A40D3D46AB5FD6FBAE9A6250B172E5C5CA557182D5FBEBC9D5E51B470EEDCB9571645685E11FBCA3F21FF0C1600B0EE32B6FAC9050B16E827B18F92F7F254C853B0AEE93BAD6B006B168B5FBCA2A5881571EDF9568FFFFCCFFFCC274D9AB4EAEBCB2FBF3C8F27EAAAF0B7AF2156AC3CFEFBCABFFE5CC83F830500ACBB8CA57E72CE9C39F939E79C935F73CD35FA49ECA3E4BD3C15F214AC6BFA4EEB1A40F52549F28E8E8E8EF9699AFE7ED09374754FD4015561BD02B0EE42439EE7EF58B264C9B2C58B17E793274FFEB923020080BE1380CAEBE8E838379E942BE20F871E7AE816C5C7092BBF8E98E008011558C70C1600ACBB507AE491477E96AF54ABD59EC9B2EC20470500007D27009595A6E9EE31C86D0C708BAF2735CECE5D197547096875060B00D65D088F3FFEF8675E7DF5D5C6F36AF96BAFBDF6EAC9279FBC284992AD1D1D0000F49D0054CEB469D336EDE8E8B875D0F036CFB2ECCEC15F3B4B17A802830500EB2EE479BED9A2458B9ECE5713B74D9A34E942470800007D2700959365D9D1430C6F870A67E9022DCD6001C0BA0B0F3DF4D079F91A5C79E5952FA469BAA7A3040080BE1380CA489264878E8E8E25EB39D075962ED0D20C1600ACBB8C6D0B172EFCC0F2E5CB5F5DD3136B7FF8C31F5E9E3265CAFD13264CD8DCD1020040DF094025A469FAE30D18E63A4B176869060B00D65DC6B679F3E6DD9BAFC3FDF7DFFF549665C7395A0000E83B016879699AEEB781C35C67E9022DCD6001C0BACBD89524C96677DE79E78A753DB1F6DC73CFFDA2C8DD67E2F18E1A0000FA4E005A5A514C0E2BE2BFD234BDB1F87867114F3A4B17A8F8BA66B00060DD650C3BF9E493FF7DC58A15FFB796E7D55EECEEEEAE39530200007D27009515EFA77BF0C1078F4BD3F463071D74D0E78B8F933C510754680DB35E01587719C3E23DCAAEBAEAAAF96B7A56EDF6DB6FBFACC8DBBBBD97190000FA4E002A2949922D8B22F3F2EAB77BA20EA80AEB15807517BEFAD5AF7E72EEDCB9AFACFEA4DAABAFBEFAEB499326FD2E4DD33D1D250000F49D00545292243B7574743CBEFAED9EA803AAC27A0560DD8570D659675DFD5A61D0F36A7F88DB8A9CBDC0D1010040DF0940651545E69345CC19E2764FD4015559C7AC5700D65D8817AB6EDDDFDFBFB4F1ACDAC2850B7F58E4EBEFE276470700007D27009595A6E9BF14C5E69AD56FF7441D5015D62B00EB2E347476761EF2FCF3CFBFB278F1E2FC6B5FFBDA6FB22C3BC851010040DF0940A51585E69B435D0AC21375405558AF00ACBB30D845175D74C739E79C9317B97A83A3010080BE1380CA2B8ACD69699AFEDB10B77BA20EA8CA3A66BD02B0EEC22A4992EC14791A1F1D0D0000F49D00545E5170FEA388C387B8DD13754055D631EB15807517E4290000FA4E00DA539AA6D71545E78B0A11A07106C0BA8B3C0500007D2700AD57706E9D3871E21E0A11A07106C0BA8B3C0500007D2700AD5770E62549F27E8508D0385365799EBFF5B1C71EFBD19C39735E191818C8FBFBFBC5084771DC5F9B3D7BF6825AADB6BF8CB4EE823C050040DF09006F5EC1599124C95B152240E34C953DF6D86357CF9E3D3B5FB46851BE6CD9B27CC58A156284238E7B1CFF9B6EBA69497F7FFFBEB2D2BA0BF21400007D27006CA42449B62D0ACE730A11A071A6EAE2CCDC18261AAC8E7E2C5CB870717F7FFFADB2D2BA0BF21400007D27006CA42CCB3E52149CFB152240E34CD5C565969D99DB3A67EAF6F7F72F9795D65D90A70000E83B0160E38BCD5E5996D5142240E34CD5C57BB81AA6B64EC4BF87ACB4EE823C050040DF09001B294DD34945C1B942210234CE54DDFA0E745F7A6161FED86DFF95DF37F3B432E2F3B8CD10D64017EB2EF2140000F49D00B49C2CCBBE5DC4F7142240E34CD5ADCF4077E9F3F3F37B7F7E727EF7CF8E7D5DC46D719F41AC812ED65DE4290000E83B0168B562F3DD344D8F5588008D3355B73E03DD27EFBBEE0DC3DC46FCEEBE9F1AC41AE862DD459E020080BE1380962B363F28E2CB0A11A071A6EAD667A0FB40FDAC350E74E33E8358035DACBBC8530000D07702D052B22CEB2FE20B0A11A071A6EAD667A07B6FFFB4350E74E33E8358035DACBBC8530000D07702D06AC5E63793264DFAA84204689CA93A035D035DACBB204F0100D07702D08EC5E6992449B65788008D3355B73E03DDFB669EB6C6816EDC67106BA08B7517790A0000FA4E005AC6E1871FFE2745B179A5F874138508D0385375EB33D07DF897D3D738D08DFB0C620D74B1EE224F010040DF0940CB48926487A2D8CC5788008D33ED607D06BACFCEBF27BFF7FF9DF2C6CB2D17B7C57D06B106BA587791A70000A0EF04A0950ACDDF1571874204689C6907EB33D08D78FCF6CBDF30D08DDB0C610D74B1EE224F010040DF09404B49D374BFA2D85CAF10011A67DAC17A0D74972FCF1FFEDF0BDF78B9E5E2B6B8CF20D64017EB2EF2140000F49D00B48C2CCBBE5E149B4B142240E34C3B58D74077E9F3F3F3877ED9B7C6F7D08DFBE23186B106BA587791A70000A0EF04A0550ACDBF665976BA4204689C69076B1CE82E5F9E2F7CB896FFE6C613D738CC6D443C261EEB6C5D035DACBBC8530000D07702D00A85667A9AA647294480C6997630D440775D67E53A5BD74017EB2EF2140000F49D00B4AC344D7F5C149B03152240E34C3B186AA0BB3E67E5AEED6C5D8359035DACBBC8530000D07702309A85E6E62CCB3EA510011A67DAC15003DDE10E731B61306BA08B7517790A0000FA4E0046B3D03C9224C987142240E34C3B58E37BE80A035DACBBC8530000D0770250D142F3529224EF5088008D33EDC040D74017EB2EC8530000F49D00B48D18E4C64057210234CEB40B035D035DACBB204F0100D07702D036E252CB71C9658508D038D32E0C740D74B1EE823C050040DF09403B15994F1771B34204689C691706BA06BA5877419E0200A0EF04A06DA4699A1485E66A8508D038D32E0C740D74B1EE823C050040DF0940DBC8B2ECE8A2D0F4294480C6997661A06BA08B7517E4290000FA4E00DAA9C8FC7B9AA627294480C6997661A06BA08B7517E4290000FA4E00DAA9C85C5AC4648508D038D32E0C740D74B1EE823C050040DF0940DB48D3F46745A1D957210234CEB40B035D035DACBB204F0100D07702D04E45E68E891327FEAD4204689C691706BA06BA5877419E0200A0EF04A09D8ACCFC2449765088008D33EDC240D74017EB2EC8530000F49D00B48569D3A66D5A149957264C98B0B94204689C691706BA06BA5877419E0200A0EF04A02D2449B27D51649E5188008D33EDC440D74017EB2EC8530000F49D00B4852CCB762B8ACC6F142240E34C45FE7DEB454C58D7E30C740D74B1EE823C050040DF09405B48D3F41FB22CEB5788008D3355F9F75D196B1DEC1AE81AE862DD05790A0080BE1380B690A6E9214591B95C210234CE54E5DF77B51872B06BA06BA08B7517E4290000FA4E00DA429665C71571B64204689CA9CABFEF1AE275835D035D035DACBB204F0100D07702D02E05E6DC344DA72A4480C699AAFCFBAE23CAC1AE81AE812ED65D90A70000E83B01689702736511131522A09D1A67219A3DD05DB264C91B6E5BB46851FEC8238F0CF9F8279F7CF2755F3FF1C413F90B2FBC30E463172C58903FF0C0031BF4F7C4EF9E3367CE1AEF7FE69967F2FBEEBBAFFC7CEEDCB9E5EF5EB66C59FEDBDFFE365FBA7469D307BA72B2FD43F5C1136B0000A0EF04A049B22CAB15F139850880AA6C8C46FB92CB3104DD6EBBEDF2EBAEBBAEFC7AC68C19F917BFF8C5BCA7A727DF7DF7DDDFF0F8DFFFFEF7F94E3BED944F9D3AB5FCFAFAEBAF8F9A9A7FE10B5F78DDE3162E5C98FFE217BFC8BFF4A52FE51FFDE847CBCF234E3EF9E47CD75D775D153FF8C10FCAE1EC19679CB12AF6DD77DF7CD34D37CD4F3FFDF4D7DDFEF0C30F973FFB8A2BAEC8B7DF7EFBF2F3ADB7DE3ABFEAAAABF2F9F3E7977FC7EDB7DFEE0C5D604CD40F470100007D2700552D30F72749B2AB4204405536466B1BE43634FB0CDD18CEBEF5AD6FCD67CE9C590E6B8B5F996FBEF9E6E5C72DB6D822FFF33FFFF3558FBDF0C20BCBDB7FFEF39FE78B172FCE77DC71C7FC2B5FF94AFEA77FFAA7E510B8F1B8CB2FBFBC7CDCEA71C82187E49FFAD4A7F2EF7EF7BBE5D73148BEFAEAABCBDFB7F7DE7BAF31E2B137DC7043FEE8A38FE6C71D775CBECD36DBE403030306BAC098AD1F8E020000FA4E00AA5A609E4B92645B850880AA6C8CD636C86D1889F7D0FDFEF7BF9FDF7CF3CDF9565B6D95FFE4273FC93B3B3BF371E3C69567D5362E7F1C97338E01EEBBDFFDEEFCA9A79E2A07B371F66DDC7EC925979467D59E75D659AB7E660C5E4F3BEDB47CF9F2E5F9E73EF7B9FCD24B2FCDBFF6B5AFE5071F7C707EF6D9679767D9C619BF311CFEC8473E923FFEF8E365C4EF7BCBCAA171E3B68F7DEC63F92F7FF9CBFCBCF3CECBDFF6B6B7E59B6CB249FEE10F7FB81CE8FEF77FFF77F998F89E69D3A6E5E3C78FCFEFB9E71E035DA0ADEB87A3000080BE1380CAD9679F7DDE561498E50A110015DA18AD7590DBD0CC816E0C4D4F39E5943262581AC3DABFFCCBBF2C87AD71766E7C1E71FEF9E79767E0167F4EFEAE77BDABBC5CF2DBDFFEF6BCAFAFAFFC39F7DE7B6F7EC001079443DD134F3C317FE8A187F2238E3822FFC0073E509E811BDF77D1451795C3DC88DD76DB2D3FF2C82357FD1D7119E5B70C71466F23BEF7BDEFBDEEB1832FB91CF77FFAD39F2E3FC6DFF48D6F7CA3FCFD06BA401BD70FEB100000FA4E00AA274992F71705669E420440BB69E64037CE9ADD6BAFBD565DD2F8DC73CF2D07B28323CEBABDFBEEBBF32CCBF2F7BCE73DE525988F39E698F27BE352C9F1734E3AE9A4F22CDC6BAEB9A63C9376CA9429430E66E3BD76E3E7FCD55FFD5539F01D3CA4DD76DB6DF33BEEB8A3FC3BE2B131088EAF3FF8C10FBE61A0FBCE77BEB3FC5D31D08DF7DA8DB38BE37BE277BBE432D0EEEC670000D0770250D5E2F289226E5588006837CDBEE4F2C2850BCB61E8C30F3F5C9E35FB962186B0F1B818AEC659BA8DF7D48DF7BF8DF7DE1D3CD06DFCCCB8CCF2C5175F9C5F70C105ABE2A73FFDE9AA4B2EFFEA57BF2ABF77DEBC791B74866EBC5F6E5C7E396EDB679F7DBC872E3056F73ED6210000F49D00544F9AA6FB1705E65A8508807633D203DD2449CAF7B68D38E18413560D7423A64F9FBE6AA01B97688ECB310F35D08DD86CB3CDCAF7DC8DF7BADD669B6DCA016C63A01BF7C7FBE636DE733706BA7129E75B6EB9A51C14C7DF73E59557965F0F3E43F7DA6BAFCD3FFFF9CFE7DB6DB7DDAA4B2EAF3ED07DE9A5970C7481B6663F030080BE13804ACAB2EC88A2C05CAC1001D06E9A3DD08DCB2917BF26BFEBAEBBCA816E9C39FB677FF667656CB5D5566B1CE87EFDEB5FCFF7DF7FFFB50E746FBCF1C6F2F3A38E3A6AD540F7339FF94C7EDC71C795EFD71BC3D88D7D0FDDD507BA071D74D0EB1E6FA00BB41BFB190000F49D0054B5B89C9265D9A90A1100EDA69903DD1884EEB0C30EE519B43BEFBC73F9BEB69D9D9DF9F1C71F5F9E9DFB9DEF7C273FF3CC33CBCB2D0F1EE83EF0C003F9965B6E595E82796D03DDB86DD2A449F9B871E3560D740F3CF0C0FCB39FFD6CFE8D6F7C237FF6D967CBC7CE993327EFEEEE2ECFAE8D33858BFFECFCB6DB6E2BBF3EE38C33F2993367968F7BEAA9A7F2534F3DB51CE8C6FDF13B3EFEF18F9783E5F89EF8FB76D96597557F97812ED0A67B1FEB100000FA4E002A595C2E4CD3F44885088076D3CC816E9CED1AC3D6175E78A1BC84725C1E79DB6DB7CDDFFEF6B7E75B6CB1C5AA98366DDAEB06BA31308D41EACB2FBFBC6AA0BBD75E7BBD61A0BBDF7EFB9583DBB8BCF2EA975C5E53CC9D3BB71CCEFEFAD7BF7EC37D975C724979DF01071C50BE27EFFBDEF7BEF2E70F0C0CE47BECB147795FFC7DF7DD779F812ED0CE7B1FEB100000FA4E00AA274DD3FF290ACC010A1100EDA6D9975C5EB468D17A3F76C99225E559B2AB7F5F9C49FBE28B2FBEEEB18F3CF248BE74E9D25567D62E58B0A07CBFDEF8B8B6DF11EFDD7BEBADB7AEFADEC111BF277E467CBE7CF9F221FFBEA16E37D005DA89FD0C0000FA4E00AA5A5CE66459365E2102A0DD347BA02B0C7481CAED7DAC430000E83B01A86471793C49929D142200DA8D81AE812E80FD0C0000FA4E00DAA1B82C4B92644B8508807663A06BA00B603F030080BE13804A4B9264EBA2B82C518800684706BA06BA00F6330000E83B01A8B42449C615C5E5418508807664A06BA00B603F030080BE1380AA1796095996CD528800684706BA06BA00F6330000E83B01A8B4344D8BDAD2F1438508807664A06BA00B603F030080BE13804ACBB2ACAB88F3152200DA9181AE812E80FD0C0000FA4E00AA5E58CE4CD3F43B0A1100EDC840D74017C07E0600007D2700552F2C971571A84204403B32D035D005B09F010040DF0940A5A5697A6396657B2B4400B423035D035D00FB190000F49D0054BDB0DC3571E2C48F2B4400B423035D035D00FB190000F49D0054BDB03C9524C97B152200DA9181AE812E80FD0C0000FA4E002A2B4992CD8AC2F24A7C548800684706BA06BA00F6330000E83B01A8AC383337CED0558800685706BA06BA00F6330000E83B01A87251F99B780F5D8508807665A06BA00B603F030080BE1380CA4AD3749F226E548800685706BA06BA00F6330000E83B01A8AC344DBF5A1496FF528800685706BA06BA00F6330000E83B01A8AC2CCB4E28E20C8508807665A06BA00B603F030080BE13802A17959E344D3B152200DA9581AE812E80FD0C0000FA4E00AA5C54AE2A22558800685706BA06BA00F6330000E83B01A8AC2CCB6615F1198508807665A06BA00B603F030080BE13802A179507932419A71001D0AE0C740D7401EC670000D0770250E5A2B2244992AD152200DA9581AE812E80FD0C0000FA4E002A2949922D8BA2F2B24204403B33D035D005B09F010040DF0940252549B25351541E5788006867030303AF2D5BB6CC30B505A2F87758D0DFDFBF5C5602A3C97E0600007D2700552A289F2C628E4204403B9B3D7BF682458B1619A8B6403CF1C4133FECEFEFBF555602A3BC0FB29F010040DF094035A469FA2F4551B9462102A09DD56AB5FD6FBAE9A6250B172E5CEC4CDD513B3377E1DCB973AFECEFEF9F57C4BEB212184DF6330000E83B01A88C2CCBBE5914950B142200DA5D0C11E3CCD02256C47BB88A118F152B8FBF612E30EAEC670000D0770250A582725A9AA6FFA61001000063681F643F030080BE1380CA1494FF28E270850800001843FB20FB190000F49D0054439AA6D71545E58B0A1100003056D8CF0000A0EF04A04A05E5D6891327EEA11001000063681F643F030080BE1380CA1494794992BC5F21020000C6D03EC87E0600007D27009529282B922479AB420400008CA17D90FD0C0000FA4E005A5F9224DB1605E53985080000184BEC670000D07702500959967DA42828F72B440000C058623F030080BE1380AA1493BDB22CAB29440000C018DB0BD9CF0000A0EF04A0F5A5693AA928285728440000C058623F030080BE13804AC8B2ECDB457C4F21020000C612FB190000F49D0054A5987C374DD363152200464AF2A31F6DF6ED73EADBADF38179BEC9D1BD37BCB3F1E53767D4DFE1E801F026EE85EC670000D07702508962F28322BEAC10013052BACF1DD8A1ABB77E5D7CDED5533BADABB776EDE0E8EEA9EF5DDED7579FD0DD53FB71E3FB3A7B07EEEC9A3E73FCF117F76F3D6D5A7D734712808DDC0BD9CF0000A0EF04A0F56559D65FC41714220046C2B133EAEFEDECABFD63575F6DD6949EFA5F77F5D606E2EBA9BDB58F35E2C80B7EF1AE786CF198CBBAFAEA5F8ACFA7F6D4FEA9AB77E0A1E2F1D717B1B4B8EFEF1D4D003686FD0C0000FA4E00AA524C7E3369D2A48F2A44008C84CEDEDA2145CCE9EAAD2DEEECAB5FD3DD5B9B39B5B7BE67D779F50F447C7BFAC05FC4E3E2F2CA5DBD03F7744EAFEFD7D9539B513CFEC1F231D3678E8F21B02309C09BB017B29F010040DF0940258AC93349926CAF10013052065F723906BA5DBD0357FFF16CDC227A6BCF94B7F7D53B3B7B6B0FC459B99DBD038715B7BFD8D957FB590C8263A05BC47C4712808DDC0BD9CF0000A0EF04A0B51D7EF8E17F521493578A4F375188001829E5A596FB6A8F96EF97DB5B9B1903DEC67DF13EB9F1B1FBDC1BB72D3E3FAAB8FFECF8BA78EC6DE5C7BEDAACC15F03C070D9CF0000A0EF04A0E52549B243514C867D86934204C086EAEAAB9DDCD55BFFDFB8EC725C56F98F67E8D62E2D3EF644149F3F158F3BBA77E083C5631676F70E9CD9DD57EB2E6EBF3BCEEA2D3ECE5BF971AEA309C0C6B09F010040DF0940150AC9DF1571874204C0481A7CC9E5F2F2C97DF5099DE7D7C6454CE999B54BDC3EA567E0935D3DF56F759E3F73B7A37B6F78E7EA67E41ED5376BA7E2F19F703401B09F010040DF0940DB4AD374BFA2985CAF100130923A7BFADF3FF83D74BB7B07F6983A63D68E8DE83AAFBE4DF78CFA87BAFAEAA7C499BC5D3D03E7C7A598E332CC8D9FD1D5533FA9B86F8AA30980FD0C0000FA4E00DA5696655F2F8AC9250A110023656AEFACBFE9EAADDD15C3DAF8BAABA7765AF1F54F0647676FFD88AEBE817DBA7AEB9362B8BBF2712714F7FDAA71B9E6E2F32BBF357DE6BB1D5100EC670000D07702D0CE85E45FB32C3B5D21020000C6E07EC87E0600007D27002D5F48A6A7697A94420400008CC1FD90FD0C0000FA4E005A5B9AA63F2E8AC9810A11000030D6D8CF0000A0EF04A00A85E4E62CCB3EA51001000063703F643F030080BE1380962F248F2449F221850800001883FB21FB190000F49D00B47C21792949927728440000C018DC0FD9CF0000A0EF04A075C5203706BA0A1100003016D9CF0000A0EF04A0A5C5A596E392CB0A1100003016D9CF0000A0EF04A0D58BC8A78BB879630B91104208218410425435EC0C01001881E7E2F59D000C4F9AA6495148AE76240000000000A0390C740118B62CCB8E2E0A499F23010000000000CD61A00BC0C614917F4FD3F424470200000000009AC34017808D2922971631D991000000000080E630D00560D8D234FD595148F675240000000000A0390C7401D8982272C7C48913FFD691000000000080E630D00560638AC8FC24497670240000000000A0390C7401189669D3A66D5A149157264C98B0B9A3010000000000CD61A00BC0B02449B27D51449E71240000000000A0790C740118962CCB762B8AC86F1C090000000000681E035D0086254DD37FC8B2ACDF91000000000080E631D0056058D2343DA42822973B120000000000D03C06BA000C4B9665C71571B623010000000000CD63A00BC0700BC8B9699A4E75240000000000A0790C7401186E01B9B288898E040000000000348F812E00C3926559AD88CF39120000000000D03C06BA000CB780DC9F24C9AE8E040000000000348F812E00C32D20CF2549B2AD23010000000000CD63A00BC006DB679F7DDE561490E58E0400000000003497812E001B2C4992F71705649E23010000000000CD65A00BC0708AC7278AB8D591000000000080E632D0056083A569BA7F5140AE7524000060F4253FFAD166DF3EA7BEDD3A1F98E79B1CDD7BC33B1B5F7E7346FD1D8E1E0000B43E035D0036589665471405E46247020000465FF7B9033B74F5D6AF8BCFBB7A6AA775F5D6AE1D1CDD3DF5BDCBFBFAEA13BA7B6A3F6E7C5F67EFC09D5DD3678E3FFEE2FEADA74DAB6FEE480200406B32D0056038C5E3942CCB4E7524000060741D3BA3FEDECEBEDA3F76F5D5664DE9A9FF75576F6D20BE9EDA5BFB58238EBCE017EF8AC7168FB9ACABAFFEA5F87C6A4FED9FBA7A071E2A1E7F7D114B8BFBFEDED1040080D664A00BC0708AC785699A1EE9480000C0E8EAECAD1D52C49CAEDEDAE2CEBEFA35DDBDB599537BEB7B769D57FF40C4B7A70FFC453C2E2EAFDCD53B704FE7F4FA7E9D3DB519C5E31F2C1F337DE6F818023B920000D0BA0C7401D860699AFE4F51400E7024000060F40DBEE4720C74BB7A07AEFEE3D9B845F4D69E296FEFAB7776F6D61E88B3723B7B070E2B6E7FB1B3AFF6B31804C740B788F98E240000B426035D0086533CE6645936DE91000080D1575E6AB9AFF668F97EB9BDB59931E06DDC17EF931B1FBBCFBD71DBE2F3A38AFBCF8EAF8BC7DE567EECABCD1AFC350000D07A0C7401184EF1783C49929D1C090000185D5D7DB593BB7AEBFF1B975D8ECB2AFFF10CDDDAA5C5C79E88E2F3A7E27147F70E7CB078CCC2EEDE8133BBFB6ADDC5ED77C759BDC5C7792B3FCE75340100A03519E802309CE2B12C49922D1D090000187D832FB95C5E3EB9AF3EA1F3FCDAB888293DB37689DBA7F40C7CB2ABA7FEADCEF367EE7674EF0DEF5CFD8CDCA3FA66ED543CFE138E260000B41E035D00364892245B17C5638923010000ADA1B3A7FFFD83DF43B7BB77608FA93366EDD888AEF3EADB74CFA87FA8ABAF7E4A9CC9DBD533707E5C8A392EC3DCF8195D3DF5938AFBA6389A0000D07A0C7401D82049928C2B8AC7838E0400008CBEA9BDB3FEA6ABB776570C6BE3EBAE9EDA69C5D73F191C9DBDF523BAFA06F6E9EAAD4F8AE1EECAC79D50DCF7ABC6E59A8BCFAFFCD6F499EF76440100A0F518E802B0A18563429665B31C090000000000683E035D0036489AA645EDE8F8A123010000000000CD67A00BC006C9B2ACAB88F31D090000000000683E035D0036B4709C99A6E9771C090000000000683E035D0036B4705C56C4A18E040000000000349F812E001B244DD31BB32CDBDB91000000000080E633D00560430BC75D13274EFCB823010000000000CD67A00BC086168EA7922479AF23010000000000CD67A00BC07A9B366DDAA6513884104208218410420821841042083172614201C0060D751D050000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C6BAFF0FC6E57D9A0AC9FE2D0000000049454E44AE426082, 1); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('efd6c86d-1c4e-11ec-94ee-5ef70686b817', 1, 'flowSubmit.bpmn', 'efd6c86c-1c4e-11ec-94ee-5ef70686b817', 0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C646566696E6974696F6E7320786D6C6E733D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A7873693D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612D696E7374616E63652220786D6C6E733A7873643D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612220786D6C6E733A666C6F7761626C653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E2220786D6C6E733A62706D6E64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F44492220786D6C6E733A6F6D6764633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A6F6D6764693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A62706D6E323D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A64633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220747970654C616E67756167653D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D61222065787072657373696F6E4C616E67756167653D22687474703A2F2F7777772E77332E6F72672F313939392F585061746822207461726765744E616D6573706163653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E222069643D226469616772616D5F666C6F775375626D697422207873693A736368656D614C6F636174696F6E3D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2042504D4E32302E787364223E0A20203C70726F636573732069643D22666C6F775375626D697422206E616D653D22E68AA5E99480E794B3E8AFB72220697345786563757461626C653D2274727565223E0A202020203C657874656E73696F6E456C656D656E74733E0A2020202020203C666C6F7761626C653A657865637574696F6E4C697374656E6572206576656E743D22656E642220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E557064617465466C6F775374617475734C697374656E6572223E3C2F666C6F7761626C653A657865637574696F6E4C697374656E65723E0A202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C73746172744576656E742069643D224576656E745F31376E32727739223E3C2F73746172744576656E743E0A202020203C757365725461736B2069643D2241637469766974795F30336B6A75727422206E616D653D22E68AA5E99480E58D95E5BD95E585A52220666C6F7761626C653A61737369676E65653D22247B7374617274557365724E616D657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934373637353034313130373936382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A66616C73652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383833353236373622206C6162656C3D22E68F90E4BAA42220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30306C647661672220736F757263655265663D224576656E745F31376E3272773922207461726765745265663D2241637469766974795F30336B6A757274223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3079777866777522206E616D653D22E983A8E997A8E9A286E5AFBCE5AEA1E689B92220666C6F7761626C653A63616E64696461746547726F7570733D22247B64657074506F73744C65616465727D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934373637353034313130373936382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550545F504F53545F4C45414445522671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A7461736B4C697374656E6572206576656E743D226372656174652220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E44657074506F73744C65616465724C697374656E6572223E3C2F666C6F7761626C653A7461736B4C697374656E65723E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383833373230303322206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383833373538363622206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E0A202020202020202020203C666C6F7761626C653A666F726D5661726961626C652069643D2231343430393637353831363733343539373132223E3C2F666C6F7761626C653A666F726D5661726961626C653E0A20202020202020203C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F307839647832742220736F757263655265663D2241637469766974795F30336B6A75727422207461726765745265663D2241637469766974795F30797778667775223E3C2F73657175656E6365466C6F773E0A202020203C6578636C7573697665476174657761792069643D22476174657761795F3137397A676E70223E3C2F6578636C7573697665476174657761793E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3138703368716222206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F3079777866777522207461726765745265663D22476174657761795F3137397A676E70223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C656E644576656E742069643D224576656E745F306E766A786768223E3C2F656E644576656E743E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31716967616B7222206E616D653D22E68AA5E99480E98791E9A29DE5B08FE4BA8E313030302220736F757263655265663D22476174657761795F3137397A676E7022207461726765745265663D224576656E745F306E766A786768223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B746F74616C416D6F756E74203C3D20313030307D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F3071617934387522206E616D653D22E680BBE7BB8FE79086E5AEA1E689B92220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934373637353034313130373936382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383835333637373122206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383835343030383122206C6162656C3D22E68B92E7BB9D2220747970653D22726566757365222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F303538636D736222206E616D653D22E68AA5E99480E98791E9A29DE5A4A7E4BA8E313030302220736F757263655265663D22476174657761795F3137397A676E7022207461726765745265663D2241637469766974795F30716179343875223E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B746F74616C416D6F756E74203E20313030307D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F3079637838666222206E616D653D22E5908CE6848F2220736F757263655265663D2241637469766974795F3071617934387522207461726765745265663D224576656E745F306E766A786768223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D226167726565223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D20276167726565277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F31686D61796B6822206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F3079777866777522207461726765745265663D2241637469766974795F30336B6A757274223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30396237756E7222206E616D653D22E68B92E7BB9D2220736F757263655265663D2241637469766974795F3071617934387522207461726765745265663D2241637469766974795F30336B6A757274223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A637573746F6D436F6E646974696F6E20747970653D226F7065726174696F6E22206F7065726174696F6E547970653D22726566757365223E3C2F666C6F7761626C653A637573746F6D436F6E646974696F6E3E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A2020202020203C636F6E646974696F6E45787072657373696F6E207873693A747970653D2274466F726D616C45787072657373696F6E223E3C215B43444154415B247B6F7065726174696F6E54797065203D3D2027726566757365277D5D5D3E3C2F636F6E646974696F6E45787072657373696F6E3E0A202020203C2F73657175656E6365466C6F773E0A20203C2F70726F636573733E0A20203C62706D6E64693A42504D4E4469616772616D2069643D2242504D4E4469616772616D5F666C6F775375626D6974223E0A202020203C62706D6E64693A42504D4E506C616E652062706D6E456C656D656E743D22666C6F775375626D6974222069643D2242504D4E506C616E655F666C6F775375626D6974223E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F31376E32727739222069643D2242504D4E53686170655F4576656E745F31376E32727739223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223130322E302220793D223239322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30336B6A757274222069643D2242504D4E53686170655F41637469766974795F30336B6A757274223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223139302E302220793D223237302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30797778667775222069643D2242504D4E53686170655F41637469766974795F30797778667775223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223335302E302220793D223237302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D22476174657761795F3137397A676E70222069643D2242504D4E53686170655F476174657761795F3137397A676E70223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2235302E30222077696474683D2235302E302220783D223531352E302220793D223238352E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F306E766A786768222069643D2242504D4E53686170655F4576656E745F306E766A786768223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223933322E302220793D223239322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F30716179343875222069643D2242504D4E53686170655F41637469766974795F30716179343875223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223730302E302220793D223337302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31686D61796B68222069643D2242504D4E456467655F466C6F775F31686D61796B68223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223430302E302220793D223237302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223430302E302220793D223234302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223234302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223237302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223330392E302220793D223232322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30796378386662222069643D2242504D4E456467655F466C6F775F30796378386662223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223830302E302220793D223431302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223935302E302220793D223431302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223935302E302220793D223332382E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D223836342E302220793D223339322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F303538636D7362222069643D2242504D4E456467655F466C6F775F303538636D7362223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223534302E302220793D223333352E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223534302E302220793D223431302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223730302E302220793D223431302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2239302E302220783D223537352E302220793D223338332E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31716967616B72222069643D2242504D4E456467655F466C6F775F31716967616B72223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223536352E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223933322E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2239302E302220783D223730342E302220793D223239322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31387033687162222069643D2242504D4E456467655F466C6F775F31387033687162223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223435302E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223531352E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232332E302220783D223437312E302220793D223239322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30783964783274222069643D2242504D4E456467655F466C6F775F30783964783274223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223239302E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223335302E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30306C64766167222069643D2242504D4E456467655F466C6F775F30306C64766167223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223133382E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223139302E302220793D223331302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30396237756E72222069643D2242504D4E456467655F466C6F775F30396237756E72223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223735302E302220793D223435302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223735302E302220793D223438302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223438302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223234302E302220793D223335302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C62706D6E64693A42504D4E4C6162656C3E0A202020202020202020203C6F6D6764633A426F756E6473206865696768743D2231342E30222077696474683D2232322E302220783D223438342E302220793D223436322E30223E3C2F6F6D6764633A426F756E64733E0A20202020202020203C2F62706D6E64693A42504D4E4C6162656C3E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A202020203C2F62706D6E64693A42504D4E506C616E653E0A20203C2F62706D6E64693A42504D4E4469616772616D3E0A3C2F646566696E6974696F6E733E, 0); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('efe9b42e-1c4e-11ec-94ee-5ef70686b817', 1, 'flowSubmit.flowSubmit.png', 'efd6c86c-1c4e-11ec-94ee-5ef70686b817', 0x89504E470D0A1A0A0000000D49484452000003D2000001EA0806000000E82576370000412B4944415478DAEDDD09981C659D3F702EEF83435D5D5714165DEF733D38D63FB3EB09A8A0CB10270104C2722733130251311A5856371A49A62781E0AA5C123934AE201148BA9B841BC20D41C215424E120921481220A9FFFBAB999EED4C66724E92393E9FE7799FE9AEAA3EA6FAEDAAFAF6FBD65BDB6D070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F432B5575CB1E3A9A3CA6F5DEF8259B6FDA0C2A43757EE9E34AEFC466B0F0000803EA7F19CE23F3414CA57C5ED86A6D2590D85D21FAB4B6353F9ABF9BCE6724D6353E97795C7D5178A77378C9DB2CFB0F327EF3C624479276B120000805EEFB471E577D43797BED2D05C9A3AB8A9FC91149C8B717F48A1F4F14A39F1DC1B776D09D2A50B53983E246E0F692A1DD85028CE4CCBFF29956569DE7ED626000000BD5E7DA174642AB7A630BCB8BEB93CB1B1509A32A450DEBB6174798F28A78E2DBE27968B6EDC2938DF5F3FB6FCB5FAA6D2B8B4FC23F93263A7EC13E1DB9A040000A0CFA8EEDA1D413A05E62B5B5A9F53299416E5D39BCBF529703F1CADD0F585E27FA4E9CFD73797AE89001E413A95B9D6240000007D42DEA5BBB9F4787E3E740AD211AC2BF3E23CE896B07DED6EE9F62969FE4FE37E5AF6CEFC6F73696AF57D000000E8D552101EDE5028DF12DDBBA3FB764B8B74E957E96F5394747B412C37A850DC2B2D33BFB150FCEFC6E652639A7E5FB462A7BFB35BFFCEB236010000E813D618B53BBA6937976BEAC794DE1F6570D3D4F7C5F4C14DC57D1B9ACA27D78F99F2B1B80456FB16E8539AA7EE9996FF9CB509000040AF57DF34F9DDD5E74837168A9F1D326EEAEE95D230BABC4BE3B8F27B53C0FE513E305953714C74F98EEEDE95E74821FB8C346FB0B509000040AF36A430F5930D85D2BD11925B02717E1DE9FFAD2EF585F2F10DCDC50352D81E10A1BA75B9EFA579B757BA85A7DB134E1E3BE52DD628000000000000000000000000000000000000000000000000000000000000000000ACC7B7BFFDED4C51B665F12D0400007A5C90B61650FF0000000419D43F0000004106F50F0000409041FD030000106440FD030000041950FF00000041C65A40FD030000106450FF0000000419D43F0000004106F50F0000409001F50F0000106440FD03000004196B01F50F00004090A19B9B3973E671A3468DCA6A6B6BF7B436000000411AD621CBB2372E5DBA74F9E2C58BB38103075E678D0000008234ACC3638F3D764DD6AA542A2DAAABAB3BCC5A0100000469E8C0934F3EB9FFAA55AB2A393A5BBD7AF5AAE1C3872FACADADDDD9DA0100000469A89272F38E0B172E7C266B27A60D1830E03C6B08000010A4A1CACC993347679D983061C273FDFAF5DBDB5A020000BA53682E47705E4F295B536C09F3E7CFDF63C58A15AB3A0BD2AFBCF2CA8B83070F9E515353B393B50500007497205DB30141BAC69A624B983D7BF683D97ACC983163415D5DDDE9D6160000D09DC274596B345B5B6D6DED8E77DF7DF7CAF505E9679F7DF6C6540F17C5F2D61A0000D05D82748DD668B685E1C387FFD7CA952B5F5E478E7EBEB1B1B1A4451A0000E88E61BAAC359AAD2DCE7DBEFCF2CBE77696A2A74F9F7E61AA87F739471A0000E88E41BA466B34DBC2D1471FBDEFAC59B35E6A1FA257AD5A75CF800103E618B51B0000E8CE61BAAC359A6D61E4C89157AE4EAA07EC8E69A91E9E6BED000000DD3948D7688D665BA8ADADDD79F2E4C9CB2A297AFEFCF997A53A3827A65B3B000040770FD379ABB435C1D6565F5F7FE492254B5E5ABC787176CC31C73C5057577798B5020000F484205D2348B3AD8C1F3FFEAE51A346458F8849D6060000F4015996BDFA89279EB8E2D65B6F7DA9582C6693274FEE912582744F7DEF69BDAF9E366DDABC52A974B0FAD7F33EBF891327E6F52FFEAA7F0000D007A41073653A88CE162E5C982D5FBE3C5BB972A5B2954BACF758FF37DC70C3D2146C0E52FF7A5E99376F9EFA0700007D45B404C641B440BBEDCBFCF9F317A7207387FAA7A87F0000D08D45775A2DD1DDA76530059915EA9FA2FE0100403716E7480A11DDA7C4E7A1FE29EA1F0000F48220F3C273F3B327EEBC207B68CA597989DB314DF81064D43FF50F000004E97665D992B9D983D70DCFEEBBE6B4354A4C8B79028820A3FEA97F000020C85495A71FBA6AAD105329731EBA5A001164D43FF50F00000499EAF2707964A74126E60920828CFAA7FE0100802053551E9C3CA2D32013F304104146FD53FF0000409011640419F54FFD030000362DC8C428C99D05999827800832EA9FFA070000824C5579F4E6B19D06999827800832EA9FFA070000824C55F9EBDCFBB307AFFFD1DADD6AD3B49827800832EA9FFA070000824CBBF2E4F48BD70A32314DF81064D43FF58F8DF67AAB0000A0B70799152BB2476F396FED6EB5695ACC13400419F54FFD6383ED9FCAC2D6BF0000F4C620B36CC9DC6CE6CDCD9D9EA31AF3621921449051FFD43F3638440F15A601007A639059B1229BFF68297BE0DAEF771A622A25968965B50E0A32EA9FFAC77A43F4FE9DDC0700A0270799F5B5026A1D1464D43FF58FCD0AD1EB9B0E00404F0B321BD20AB8AED64181449051FFD43F36382C0BD30000BD21C86C6A88A91481449051FFD43F362A240BD300003D3DC828828CFAA7FEB1D542B4300DC02639EAA8A376F9F6B7BF7D68BF7EFD0AE96F31952753793195ACF56FDC2FB6CE3F3496B7D6E8D4D2A54B77BBEAAAABCE1A3B76EC7D679E79E6E261C3862D3FF1C4135747853AE184135E1E3A74E8F3679C71C6ECB3CE3AEBEAD34E3BEDABE921DB0BD2028420A3FE29DDABFE358E2BBFB7F19C5B5ED74742B430CDB69565DB0F3DEFBABF5BEFF7327D276BAFB862C7EA69830A93DEBCAEEFEA71E74F7F5594CEE6378C2EEFE103808D535757F7A5946D26A6B2B235346F6889E527C6E3AD45DADC7EFBED278C193366EEF1C71F9FA5F09C5D79E595D95D77DD953DFEF8E3D95FFFFAD72CC4DFB81FD363FEE9A79FBE7AE0C0812B53A0BEAE7FFFFEFF28482B828CFAA7FE75AD93C695DF585F28FD795D25968965D3EDC18DCDC5EF4669682ECE6828942E6ABB5F2836F4F2102D4CB3CDB47E4F6FCDC37273A9317DF7FE5855CE6D0BBD4DC5310D4DE563F3DB85625DC3E8A91F6C682A9DD5D854FC667A5CFFFA31C5FFB766489EF6F769B9FBA3B40FEA232E28BF765061DADBD2F33F38A830E5438DE75CBB5B63A1DC5CDF5C9E5829E9B987B47FAFF11AE931E33B0CE585E2FF74BAAD692A9DD359D06F3F6DC488113B74B4ECC64E872D10A0F74941F8B68D0CCF9D95DBE2F9ACD53EECFEFBEF3FF0DC73CF9D77DC71C765BFFFFDEFB3458B16651B23968FC7A540FD526363E315A942BD5590510469F54FFDEB1A279E7BE3AE0DCDA57B1A9BA77EB4A312F362999683E0D2412D07F1E9C0BBB97C485E0AA547D3FD13635E1F08D1C2345BDD69E3CAEF48DFC3FDE27BD738B6F4E1148A2F19D2543AB07E4CE9FD79504E41B7252C5EF1EA74FB99F891ABBE50BCBBB1A97470BA7F794B902E7F3BA69F3AAADC760C15BD4AD2FC071A0AE543A3C463EA9B26BFBB2D10379707A6F9B7A7607E7D0AD057A4F7F078FE98B153F649CBDF11E1FA94E6EBDFD9FEFD36164AFB4760EEE87FC97BB254B62D4DC5A111B82BF707158A7BB55F3EFECFF47C53DA2664D9F6F1C3412AB3D27B98143F046CD274E862471D75D46BFBF5EB372E85DFD5ED037143434376E9A597AEB30131E6C7721D84E9D5F1BCF1FCD6721F92EAC78E93264DBA2A02F445175D942D5BB62CDB1CF1F8789E54915E3CFCF0C30F116414415AFD53FFBA2848174A3745CB521C30AF59F203DD9B629974507E587E205D283D91A6CD8EDBAD654EE5761CACF781102D4CB355A5407B78FA7E4D4DDFBBA5116823489FDA5CFE4094FA42E9B4F8AEB62C57FAF71460FF50795CB428E7F39BCB3F4BDFE541E93B7CDC8811E59D2270A7D0FC8378BE784CFD98296FCF4B73B95F9AF65C7ABE33061526BD260FD84DA59111E0073795BE108136B609E9EFF4B4DC5F53B97148A1BC774B881FB14384DEF6413A9EEBB8F3AF7E7D87A13AB62929E477342F6F816F2A9D935E238BF75F999E9EEFE434EDDA78BDF4D8EF353697EB37653A74A5147677AFABABBBAF3A00F7EFDF3F3BFFFCF3B33973E66C54DE89E5E371F1F87681FADE781D6BBB6F84E85D2EB9E49299279F7C72F6C4134F645D299E2F85F3E503070E3C5390510469F54FFDEB9A201DAD5ED1C2B56699F2F64A90CE0F4A5B5ABF7E930E922FA82E71601FAD537D28440BD36C556B74ED6E0DD2D1821BDDB52BE73FB7FEF075712AD7A530FB8BC6E6E209E9F6BD29B0FE2E4ABAFD54C3D8E2A752401E9077016F2EFD389E2B6F752E94EF88DBF54DE59F44808D501DADD769DE7DE9B99A5279A87E6CF96BE931E7A765FE25BDEE49E9FDFC30A6B584E7299FAFB41CAF11A4E3F48F14E05BB61FE55D4E699EBA67A5A4307F4A9A3FB67A5A2CD3FAE3C1C096105FBA29027DEBC1E5F62D3FE64DF97CEB0F07DF881F16367A3A74A114A03F90CADCEAD03B72E4C8ECE9A79FDEACBC138F8FE76917A69F8ED7B3D67B79882E140A4B7EF0831F644B962CC9B68478DE61C386BD78E491475E2CC82882B4FAA7FE6D7E903E7DE44D6F4A7FE7A583D6AB5A4ABA9D0E6AD708D2CDC57FCBBB7F168AA3AA4B5AE6AE98D7C742B430CD563364DCD4DDE33B19E725E7E1B7658C82BFA4F2A71468E7572F1BE1390FB479902E5E1981B535B4DE19413A0F95634AEFAFB46AA7503D223DDFD995FB515A9EA758172DB8E9710BD2ED99F9362205E934EDD3B18D88D6EEFF0BD2A5A608BFED8374FD98299FA9743D6F0DE21756956865BF6F8D69ED4E1149F79F1E5428BF2B6EE7EFB5507AAA6D5E5369487AAD9F6EEC74B589AED2DA123DB7BA15FAAAABAEEAD2CC13CFD7AE75FA692DD3BD3744EF78C925973C1A213A0EFAB6A478FEA143873E3760C080330419459056FFD4BFCD0BD231B26F3A389E5675005BAECCAB0ED2E960F7B674307A6675C95BB4BA6790AE0EB9710588EF6CB7F95782E8E8798469B698FA4279582AA568158E96E908D28D85E297A3CB750CECD5D854FA651EB69BA6FC6B7E1E70A1F442FCCD7FE46A2E1522D8E6E1364ED7680DD2D1DA9BB73C4749CF9D97BC2B7579743CAE651B503E2A6FA94E613A4EDB8816F108E61176A3A5B912A4E3BCEAFC148FD6D6E4F6E748C7F661705371DFF6FFD7BABA768708D0E9B173DB962F14BF1E3F1C546FA3E2393676BA1A4557887396ABBB731F7DF4D1D93DF7DCB345324F3C6F3C7F75376FE74CF742714EF429A79CB2C55AA23B6A993EF6D8639F4F15EA1B828C2248AB7FEADFE606E9BCE5A9B5CB766941FB201DA3763734976B6294EE7C04EF42A96970D3D4F7A5107D409CC7D9CD43F4AFE2F7DED6BF9B1AA6D7F53CC2345B4C475DBB53F01D97B7528F99F2B1EA65D76C912EDDD7127EF300FC542548E7E70C174A37C488D8F9724DC541AD8395DD5519253B0FED85D2CD11C65B027AB121427DDE82DD543E3985EBEFB40C8256FA7974F5FEBFC0DB2E4837158F88AEE41B1BA4F3F985D2EFDB7E506809ECB7E5EF3D6D732AB73776BADA4457681D58ACAD257A4B85E8EA305DDD321DAFEF53E845D2077C500C2CD6D5E7446FC839D3871F7EF892DADADAB709328A20ADFEA97F9B16A4F303DEE8CA5D55E21CC3E8CA9D2F939F5B59BA31CECB8C03D2A13FBBEE0DF54DE5F3EAC74EF9527EBE653A608F6E9CDD304487EFB486DF6C33C2747588AE9423D7F3BAD025E2D253D541BAB5CBF4E5794B700AB6318858CB72B7BC2E0FCC79F82D5E1001B92A60FF3EBEC71194F3EF782CD3543E36BA3CB7B67A1F1F97B78A7995301DDB8638B738CEA78E20DDD2ADBBF4482C1B97DE6AB944D6A4D75407D4F8512DCED1AEDC6FB94EF5DA038E45F88E1E2D9DFDCFD13A9E5EF7F4351E13EFAF509C1981BF7A5C868D9D0E9BA3F51257AB2AA1F6EAABAFDE2A99275EA7AA557A954B63F5227189AB18557B5B38EFBCF3E6A50AD524C82882B4FAA7FE6D9C61E74FDEB9BA4B77D5417774DF7C30827404EA7440FAC568698A03F61805B7A59B673AC84E7F63B4DE2185D2C7E3B238DD304477168237264C77F4F85F76F278619AAE0DD1CD533F9ABE670F47B06CFD6E5E9CC2ED352DADC8E9FBD85CFE595C96AEF5C7B03DA2AB778CA61DE72C575A8AA38B739C531DDFF7182C2CDD2EAEABC477BDF571D746EB73DEFA9D426D04D2CABCF49E8EAC0EC28DA3A7FC63BCCF28D1ADBAF3FF270FE3B7C7A5B7DA5FD77A4354AE6BBFB9D36153555F273A0604DB9ADA0D40769B4FA317B8FDF6DB4F88D6E8E79F7F7E9B04E978DD238E386269FFFEFDFF5190510469F54FFDEBB3D6156237354C6F4C8816A6017AB1C30E3BEC8BD55DBA377774EE4D19CDBBBA8B77BC1F9F4A0F3766CC98B913274ECCB6A58B2FBEF8F154A1CE1764144146FD53FF84E88D08C5EB0AD39B12A28569805E2A658D8995101BD77BDE16E275AB5AA527FA547AB0E79F7FFE2D279C7042F6CC33CF6CD3209D5EFF95FEFDFB2FEC6D03490832828CFAA76C68FDEBC303E96C4C68DDD030BD39215A9806E86552CED83505D7959510BBB55BA3AB5BA5AB82F4CA785F3E9D1EEA4F7FFAD399C3860DCBBA83638F3D7656AA50FBF6905FB4CAA9D4083282B4FAA76C6EFD5BB060C19EB367CF7EF0EEBBEF5EF9C31FFEF0C73535353BF5D63AD94561757D61BA2B42B4300DD08BF64169FEA19500DBD0D0B04D334FBC7E55983ED427D8433537373F70E59557768B203D7EFCF87B5365FAEF1EF285AD54FE757E710519415AFD533AAB7F69B3B7E3CC993347AF58B16255653B98967BF9F2CB2F9F7BF4D147EFDB1BEB641786D4CEC2F40E5D18A28569805EB20F4AD39B2BCBFDE637BFD9A699275EBFEA3D37FB047BA833CF3C73F15D77DDD52D82F4B469D3EEEFD7AFDF553DEC0BBBCE2FAE202348AB7F4A47F5EFC9279FDC7FE1C2859D9E53336BD6AC97468E1C79656D6DEDCEBDA94E767138ED284C3FD2C5215A9806E805FBA0BABABA5265FEF4E9D3B769E689D7AFBC97785F3EC11EEAF4D34F5FBEB5AF1DDD99471E7924BA76DFD943BFB01D7E710519415AFD53AAEB5FF2A6C71E7BEC9A55AB56AD779BB83A498F59D6D8D8F89DDE5227B74028ED284C77758816A6017AF83E28FD9D5D99BEADB34FBC7ED57B9CED13ECA14E38E184D5CF3EFB6CB708D27FFDEB5F97A5CA34B7877F61D7F8E20A3282B4FAA754CAADB7DE9A2D5DBA74F9C66E1B972C59F2D2F8F1E3EFAAADADDDB3A7D7C92D1446A33B77FB96E8475AA77735611AA067EE83FE56B9BFADB34FBC7E558BF4F33EC11EEA88238EC85E7EF9E56E11A4D3FB787E03BE083DAA6CE920B362C58AEC2F7FF94BB66CD9B2F52E1B5FDA8E968BC7BFF0C20B1D3EE6A9A79E5AE3FE7DF7DDD725EF3BAE1D9E02C5560F32BDAD7E6DEDFA376FDEBCECE1871FDEA06567CC98912D5FBE7C83969D33674E7EE5802DF5B92F5CB8300FB19DCD5FB46851F6D0430FE5B767CD9A953DF7DC73F97BDFD0EFD686AEBB51A346658B172FDEE86D633C261EDBD3EB636D6D6DF6DAD7BE3642EED02EDC8DADAB457A43AE33BD2986F6B56D89A2284A6F2ADB3AFBC4EB57BD9F5724D21EEAF8E38F7FB9BBB448A783D9C77A418BF456ED5A1B81340E18CBE572F6873FFC21FBE8473FBA46F9FCE73FDFB66CFAACF36971501EA161D0A041D10B207FFCD4A953B3E38E3B2EBBFEFAEBD708D16F78C31BB25FFCE217F9FDABAFBE3ADB7EFBEDB3BBEFBE7B8DF710E779BCF7BDEFEDB08C1B37AEC3F7BDFFFEFB675FFEF2973B0DF05AA4BB57FD9B3F7F7E76E38D3766871C72485E87E27694E1C387671FFAD087DACA25975C922F1F977678FDEB5F9FFDF8C73FCEEBDA97BEF4A5B54A2C13CB46F7A65D77DD35FBA77FFAA7BC6EEEB3CF3E6B3C6794E6E6E67CD99FFDEC676BCDAB2E95D01BAFF9939FFCA4AD1C74D041D90E3BEC909D7DF6D96B4C7FF4D147F3E52FBDF4D2EC6D6F7B5B7E7BE79D77CE2EBFFCF26CEEDCB9F97723EA7757D5BF891327C6D509AE2F954A8B56AF5EBD6A03368BAFA4757FD931C71CF340FA5C27F5D016E9F65DBBB774B7EE47B67098D6220DD003F741D1F2AB459A2E75EAA9A73EDF5DCE919E3163C6F41E7C8EF4561FEC295ACBFEF77FFF373F588C8011C1E01DEF78471E0AA2C4F5C1FFE11FFE215F3602F39BDEF4A6B683CBC18307E7E1A5A9A929BFFF5FFFF55FD94E3BED943DF8E083F9F2D75C734D3E347F84930818713B824E3C7FDC8E505DDD9A17A30F5E78E1856B9477BEF39DF9F376F4DE6FB9E5963C689D76DA6982740FA87F175F7C7147AD7DD991471E99FDCBBFFC4B5EFFE2FE55575D95EF1C62F91FFDE84779EBE3EDB7DFBE46788DCBEDC5B28F3CF248DEEA1B3FAA7CEE739FCBBEF0852F64071F7C70FED85FFDEA5779FD881F77E27625CC0E1D3A34AF8711D8ABCBF7BEF7BDFC39E387A5582EAE4410F5F9AB5FFD6AA725969F346952F6F8E38F67A79F7E7AB6CB2EBB64C562718B06E94AFD4B3BCDC3860F1FBE705D838DAD5AB5EA9E186C2C7DAE7362F9DE5227BB308C767689AB8E46EDEEAA302D4403F4D07D9073A4E9723FF8C10F9EEE2EA3764F9932A5D80347EDDE66971F8A501207FF71A01821F91BDFF846F6BEF7BD2F9FF7D39FFE346FD9FBEC673F9BDF3FF7DC73F316B9783FD13D7BF6ECD9D9C9279F9CA5CF3F7FFC49279D94F5EFDF3F0FDCB17C049377BDEB5DF9F4C30F3F3C5F66C08001F9FD08C831BFFABD7CE0031FE830687516A4A3FCFCE73FCF5BBCA35BAF20DDFDEB5F84CDB3CE3A2B3F9DE0DFFEEDDFF2807BCC31C7E4F523EA5BFCE0F2B7BFFD2DFF31263EFBD849DC7BEFBD6B3DCF638F3DD616A4A3C53AEA6E3C77F4A8D86DB7DDB2F7BFFFFDD9BBDFFDEE7C9978CEB85DF93F22486FD77117DE3582F475D75D977DF8C31FCE9E7CF2C9BC44B7EE981FD32BD33EFEF18F6737DF7C73367AF4E8EC35AF794DDEDB22EA7104E98B2EBA285F261E3362C488FCBB74FFFDF77769FD8BD1B8D377EABC0913263CF7CA2BAFBC58B5297C3E85F70BD3BC39E9B33DB7078EDABDA197BFEAEA4B5F550F2CB6BEEB4C0BD100BD334877BA0F326A375D2E1D245EDD5DAE237DF6D9674FEC41D791DEA083C5ADD9B5FBD7BFFE755B908EE01CA1235A03E3FE902143B21D77DC31FBE0073F98972BAEB8227F5C848708D851E27EE5FD46508E10F3AD6F7D2BFBCA57BE92CF8BBF71FFEFFEEEEFDA827474FF8EFA132DD0F1FAD5E5EFFFFEEFF3F01DF3E3BCD3F6EF3DBA09C7F3460BB720DDBDEBDFCC9933F35303F6D8638FFCF38CCF6DFCF8F179888EF2B18F7D2C3BF1C413F3652B41BAFDF9F51D05E968C98EBA12ADD4D1653CDE6FB4427FE6339FC9C375FCD8F2EA57BFBAAD0744D4E9F821274E45B8EDB6DBD628D1CBE1D39FFE74F6DBDFFEB6ADBBF6BA42773C77E53DB5EFDA1DF3E3B488F81B3FF644EF8E58075BA2FEF5EBD76FEFFAFAFA19C982679F7DF6C6F45D8D1DFD7D31BD37D6C92E08A7EB0BD1DB6D81302D4403F4F07D90EB48D3E5D201EC57D201EBEAEE30D658FFFEFDEF4F9569DFDEB47EB756908E16C2AF7FFDEB79587EFBDBDFDE56A22B7665D93BEEB823EFEEFADDEF7E376F298CC7FDCFFFFC4F7EAE6BA9545A2B484717DA081BDFFFFEF7F379F1B8B81FD32B41FACF7FFE73B6E79E7BE6ADD7F137424E2C1BAD88713F5AFAE26F7557F02831605584F70828B14C842B41BAFBD6BF3815A0A3301AE73AD7D5D5E53FCE44D0DED8201D837AC58F3E51AFA23538CE853EF6D863F3DE15D1653C5ABAA37B78A5FE5C70C105F98F3F9D85E308C111A82BE1385AB8A3C74D74E18EF9F12340DCDF6BAFBDD60AD26F7EF39BF37398E339E25CEA9B6EBA297F4CB45A6FE9FA575353B3535A8FA7A7EDDFA2F81BF7FB5035DD9890BAA121BA2BC3B4100DD03BC2F6A195F01A8D38DB527D7DFDEAAA207DA84FA7871A3162C40EE9C075658C98BB2DCD9933E7E65491E6C7FB116436AC9C77DE79794B601C1C46E88856BD68058EF34DFBF5EB979D72CA296DE7484797D6FDF6DB2F0FAF71DE7304D8ED5ABBCE46088EE5DA07E9E872BBF7DE7BE75D6063DE273EF189FC7E048DEAAEDDD1C5FC939FFC64DE9537424C2C1BDDB5E3D7B657BDEA5579D86EFFDEE3F5E3B9E2F63FFFF33FE72DD78274F7AD7FD19DFBFCF3CFCF436FA544B8AD74ED8E9E0FD1721CA70C6C4C908EE5A35E45891F7D2224475D88201DF53846AAAE04E968118E501BE30244AB73A5443DFBC8473E9287DFA86B951F6536B4453ACE87AED4F1030E3860AB9C23BDAEED711FDD156D4858DDD810DD15615A8806E825FAF7EFBF6BCA1A2B2B0136063DDD16E275AB42F4CA785F3E9D1EECB4D34EBB2E5A62B6A5FFFCCFFF9C902AD3F982CC86971811BBB1B171ADAEDD71AE69B408D7D4D4E45DBA2BAD84712E68B45847D7D9E88A1D8F8B73542FBBECB23C8C5407E968BDFEE52F7F999708CADBB59EEF5C99561D2E6244E778AD0843D13219CB4637DD08D1D5AD7E9512AD83118E2210555AB523E047F75C41BAFBD6BFA83BBBEFBE7BDE721CE7E647E8AC04E9981FE7248F1C3972A38274E53259F1435EFC1814CF173F001D78E0817997EA1845BE12A46360B37505E34A39FAE8A3DB82740CA817F52A06418B7913264CC8EF57B748FFF18F7FCCBEF8C52F666F7DEB5B3B1DB5BBAB4697EF6BF5AF0BC3F4A686E8CD09D34234402F93B2C6C44A888D06826D215EB72A484FF4A9F4FC5F68FE71E0C0812F4537E16D61C9922577A48AF44CBC0F4166F3CF918ED6C3CAE05F77DE79E71ACBBFEE75AFCB434574AD8EF9D192172D7F312859254847B88EA0542995D1BEE36FF5F4582E9E73C182056D2127C2D576ADE797BEE52D6FC9C34CBC9FEACBFF4457EEB8F455F5FB8A20132D921D0D4E2548779F207DEDB5D7E6B723EC5682748CBA1DE733C7E71D01746383F4BEFBEE9BF78C886ED8115EE3079F18C13BEA49B43847F7F108B351D76330BCF8212706248B3A1CF7A3FEC5F3C50F3371BF32E0D8E69C23DD3E481F76D8611DFE28A4FE6DB530FD9DCD08D1EB0AD3470AD1007D47DA9F7FB112626390DDADDD2A1DAF575757D7D6AD3BDE8F4FA517686C6CBC2246AADD16D26B5F9E2A539320B37125AE995B39D7B912A4E3DACD719E6904E698FECD6F7E330F049556E90843718E73B41EC6FC18CD78C99225D9B469D3F2FB71F99FB8AC565CFEAA5222B8C4BCB89E74F5F4E86A1BE756470089D78DFF355A10B76BEDDA5D5F5F9FB73447508FEBFA46288A56EAE8B65B093BD597D08AAEE7D12A18ADE18274F70CD2712E7E74BD8E205B09D2871E7A68F6AFFFFAAF7977FD08B2EB0AD20B172E6CBB9456A50B760C44177532CEAF8F4B51459D8C1F84E2C795A83BF15AD105BCF21C11C0DFF39EF7E4CBC4F3C5E3B76B1D91BBFAB5E279A2C746B426C7F5A22B3F2CC5FDE8653165CA94B61F82CE3CF3CCBC1EC7FCF83FA377455C8A2B1E3376ECD8FCB5E25271EADF360BD3D521785342F4C63C8F100DD08BA5CC715B25C8464FBAAD295EAFAA35FA369F462F515B5BFBB6A38E3AEAC5AD7D5DB5E9D3A74797EE67E2F505998D2B1138E3803006499A376F5E1EA4E35CE7384F3A06088BF34963A0AF08099591973FF5A94FE5E79D56C24E848D1801396EC7E0648B172FEEF07AD5313FFEB69F1797D21A3468503E68D419679C912F1781A8D20A1DC124024974FF8EAE2C11C25E7CF1C50EFF9F08F4119E22A40BD2DD33487FED6B5FCB0373FC10D3BE6B77A5AC2B48C7359F635EE5FCF84A89A01CBD28E2DCEBE8761D3FB6C4B4A8D771BA405C76AB7DAB763C570C7016CF173FD04408EFECBD57C2F63DF7DCB3D6BCCA0F45F1A35374218F3103E27F8C1F952A3D35A24EC78F41EADF360FD3476EB7F9D7835ED7F308D100BD5C5D5DDD3E297BACAA04DAD8F76F0DF13A55217A55BC0F9F462F920E880F4907A6CB23D06C0DCF3CF3CCD454919E4AE51B82CCA60D00153F7C2C5DBAB4AD55375AEBE27CD3CA32D14258DDB5BAFAB11174A2752E6E4760896B0077D6F21DE795C6DF75BD9F78FD071E78200FC45BEB725682CCD6AB7F115E2B75205A71A3CEC40F24F1B77D7D897AD051BD5BBE7C79DBB5CA3B3A4DA1D26ADDBE15BBB3F714BD2D6214EE752D1325EA76FCF0D4511D8EEF40FC1F95EF45FBF9F1FDEA68BAFAB74DC2746F7A3D00B6917EFDFA8DABEEE21D3FB46F49F1FCD55DBAE3F57D0ABDD0C08103CF1C366CD88B71D0B725A503D319A9E2DE992AD5F70419459056FFD43FB661B815A201FA90A38E3AEAB529D0DE5B09B63150E9960AD3F1BCE9F55655B546DF1BAFEF53E8A58E3CF2C88B870E1DFADC966A997EE699676E88109D2AD22F0519459051FFD43FB661C815A201FAA09443764FE5E9EA96E91890B72BC5F355B744B7BEDEEED67E2F3760C08033060E1CF87C579F33DD7A4EF4ECDEDE122DC80832EA9F224877FBB02B4403F461298F7CA03A4C570620DBDCD1BCE3F1ED0616CB4374BC9EB5DE777EA9F9C6E1871FBEE4BCF3CE9B17E7166E8EE79E7BEEF6D6D1B99FE9CDE7440B32828CFAA7A87F3D224C0BD100545AA6EFAD0EBDD13A1D83E4C6556836462C1F8F6BD70A9DB53EBF96E83EF84BCD5BE3D254471C71C4D20B2FBCF0F1458B16BDBC11F5E9E5B973E7DE7CE699674E680DD04DF17C828C22C8A87FEA1FDB30FC0AD100B48973965B07206B1F80B3868686ECD24B2FCD07378D2B84C4A0A921FEC6FD981EF3EBEBEBD77A6C3C5F3CAF73A2FBB8FEFDFBFF63AA0CE7A720FCCC7FFCC77F3C357EFCF87BA64D9B76FF238F3C327BF1E2C52FA4FAB4EC99679E79E2A1871E9A9E0E16279F7DF6D913D363EE4F8F59108F8BC7F7C5F526C80832EA9F224877AB302D4403D0A1D64B63DDD64120DE94729B4B5CD1DEF6871D76D87EA962FCA45FBF7E57A54A7247D5B905F1F78E981EF363B9ED36FF9A9F828C22C8A87FEA1F5D11868568003624507F29659A89A9ACDCC8F01CCB4F8CC75B8B20C80832EA9FA2FEF586302D4403B0518E3AEAA85D52303EB45FBF7E85F4B798CA93A9542E65F562EBFD62EBFC4363796B0D04194146FD53D4BFDE12A6856800365B0ACB3555ADCF35D6080832828CFAA7A87FBD354C0BD1007455902E5705E9B23502828C20A3FE29EA5F6F0CD34234005D15A26B3A3827BAC69A0141469051FF14F5AF378569211A80AE0CD2E50E82B4566910640419F54F51FF7A4D981E2A4403D08521BA661D2375D7584320C80832EA9FA2FEF5F8301D07364234005D18A4CBEB08D25AA541901164D43F45FDEB15073CD633005DB54FA9D980EB47D7585320C80832EA9FA2FE09D200B0DD7A5BA3B54A832023C8A87F8AFA27480380FD0C08328A20ED7357FF1CE00080FD0C08328A20A3FEA97F38C001C07E060419459051FFD43F1CE000603F030832828CFAA708D20E7000B09F0104194146FD53D43F073800D8CF00828C20A3FE29EA9F031C00B09F01414611A47DEEEA9F031C00B09F0141461164D43FF50F073800D8CF40AF552C16572F5FBE5C88E806257D0EF3529059A1FE29EA9F031C00B09F816E6CDAB469F3162E5C28487483F2D4534F5D9682CC1DEA9FA2FE39C00100FB19E8C64AA5D2C137DC70C3D2F9F3E72FD632B8CD5A02E7CF9A356B420A31B3533948FD53D43F073800603F03DD5C1C3C474B542A2BE31CC99E562EBEF8E22C36183DF1BDB79695ADEBFF20F56F72A6A87F0E7000C07E06D8F21B8BB20D06E0000700EC67800DDB50D4C4C6A2B5D4582380031C00EC6700D6BDA1285705E9B2350238C001C07E06A0F38D44756BB45669C0010E00F633F633C07A3612E50E82B45669C0010E00F633001D6C203A6A8DD62A0D38C001C07E06A0930D44791D415AAB34E0000700FB1980AA8DC3BA5AA3B54A030E7000B09F0168B771286F4090D62A0D38C001C07E06C00603B0BD0200FB19C00603B0BD0200FB19C00603C0F60A00FB19C00603C0F60A00FB19C00603C0F60A00FB19C00603C0F60A00FB19001B0CC0F60A00EC67001B0CC0F60A00EC67001B0C00DB2B00EC67001B0C00DB2B00EC67001B0C00DB2BFA862CCB5EFDC4134F5C71EBADB7BE542C16B3C993272B5BB9A4F5BE7ADAB469F34AA5D2C16A24F633800D0680ED15DD5C0AD157A610972D5CB8305BBE7C79B672E54A652B9758EFB1FE6FB8E186A529581FA456623F03D86000D85ED18D454B7484388176DB97F9F3E72F4E41FA0EB512FB19C00603C0F68A6E2CBA736B89EE3E2DD32948AF502BB19F016C30006CAFE8C6E21C5D21B6FB94F83CD44AEC67001B0C00DB2B7A41907EE1B9F9D913775E903D34E5ACBCC4ED9826FC0AD2D8CF00361800B65708D2EDCAB22573B307AF1B9EDD77CD696B949816F30460411AFB19C00603C0F60A41BAAA3CFDD0556B85E84A99F3D0D502B0208DFD0C608301607B85205D5D1E2E8FEC3448C73C015890C67E06B0C100B0BD4290AE2A0F4E1ED169908E7902B0208DFD0C608301607B85202D480BD2D8CF00361800B657B069413A46E9EE2C48C73C015890C67E06B0C100B0BD4290AE2A8FDE3CB6D3201DF30460411AFB19C00603A06F6FAFB26CFBA1E75DF777EB5BACF19C5B5E577BC5153B564F1B5498F4E698DED9638E3B7FFAABA27436BF6174798F8D79ABF17AC3CE9FBCB35AB46583F45FE7DE9F3D78FD8FD6EED69DA6C53C015890C67E06B0C100E8D3DBAB93C695DF585F28DD9A87E5E6526343A1F4C7AA726E5BE86D2A8E69682A1F9BDF2E14EB1A464FFD604353E9ACC6A6E237D3E3FAD78F29FEBF3543F2B4BF4FCBDD1FA57D501F7141F9B5830AD3DE969EFFC14185291F6A3CE7DADD1A0BE5E6FAE6F2C44A49CF3DA4FD7B4DEF73707DA1784A87A1BC50FC9F34FFCF1D96A6D2399D05FDF6D3468C18B14347CB6EECF49E1CA4A33C39FDE2B582744C137E0569EC67001B0C803EBDBD3A6D5CF91D0DCDA5FD22EC368E2D7D3885E24B8634950EAC1F537A7F1E9453D06D098B57BC3ADD7EA6A1B9382305D9BB1B9B4A07A7FB97B704E9F2B763FAA9A3CA6FAD3C6FE3B8F27BD3FC071A0AE543A3C463EA9B26BFBB2D10379707A6F9B7A7607E7D0AD057A4F7F078FE98B153F649CBDF11E1FA94E6EBDFD9FEFD36164ADF6F6C2E1EDDD1FF128F6F6C9EFAD12829F40F4DCF3FBE727F50A1B857FBE5E3FF4CCF37A56D42966D1F3F1CA4322BBD8749F143C0264DEF0D417AC58AECD15BCE5BBB5B779A16F30460411AFB19C00603A0CF6EAF52A03D3C85D8A9290C2E8D401B41FAD4E6F207A2D4174AA745D06D59AEF4EF296CFFA1F2B86851CEE737977F9642EBA014AC8F1B31A2BC5304EE149A7F10CF178FA91F33E5ED79692EF74BD39E4BCF77C6A0C2A4D7E401BBA9343202FCE0A6D21722D046F84D7FA7A7E5FE9ACA8D430AE5BD237C37168A5FAE9408EFE97DFE67F5B453C716DFB356A86E2A1D1621BFA3FF396F816F2A9D939E2B8BF75F999EDEDBC969DAB5D1C29C1EFBBDC6E672FDA64CEFE9417AD992B9D9CC9B9B3B3D473AE6C53242B0208DFD0C608301D067B7576B74ED6E0DD2D1821BDDB52BE73FB7B6F05E9CCA7529ECFEA2B1B97842BA7D6F0AACBF8B926E3FD530B6F8A9149007E45DC09B4B3F8EE7CA5B9D0BE53BE2767D53F9271160235447EB759A775F7AAEA6541EAA1F5BFE5A7ACCF969997F49AF7B527A3F3F8C698D85299FCF0377A5A4909D967FA27A5A3CA661747997539AA7EE5929D1FD3B2D3BB67A5A2CD3FAE3C1C0D6E7BA29027DBE12A275395AC5D3EBB5FE70F08DF86161A3A7F7E420BD624536FFD152F6C0B5DFEF3444574A2C13CB6A9D16A4B19F016C3000FAE4F66AC8B8A9BBA750392FCE4BCEC36F737146BAFF9754FE9402EDFCEA65233CE7813B0FD2C52B23B0B686D63B2348E7A1724CE9FD9556ED14AA47A4E73BBB723F4ACBF314EBA205373D6E41BA3DF3F49137BD2982749AF6E9146EAF8AD6EE08D26BBCCFC2D44FA6E51F4BF36F896EDCD5F35A83F88555255AD9EF5B635AA17450BBFFE5E94185F2BBE276FE5E0BA5A7DAE6359586A4C0FED38D9DDE5383F4FA5AA1B54E0BD2D8CF00361800B65795005A280F4BA514ADC2D1321D41BAA50B75F1FE183CACB1A9F4CB3CC4364DF9D7FC3CE042E985F89BC2F3A8144E0BE971FB47892EE09520DDD24A5C3A272FE9B9F39277A52E8F8EC7B584D8F251794B750AD3718E75B48847308FB09BCA451D05E9FC5CEA1458E39CEE08FDEBFABFD6D5B53B44804EAF33F7FF9EBBF8F5F8E1A02A6497E33936767A4F0DD21BD20ABDAED669815890C67E06B0C100E853DBAB8EBA76A7E03B2E6FA51E33E563D5CBAED9225DBAAF25FCE601F8A94A90CECF192E946E8811B1F3E59A8A835A072BBBAB324A761EDA0BA59B238CB704F4624384FABC05BBA97C720AD7DF89C0FC7FC1B8FCED08AB95CB6FB504FED2F7373548E7F30BA5DFB7FDA0D034F9DDE9F56ECBDF7B73F180CAED8D9DDE5383F4A686E84A11880569EC67001B0C803EB5BD8A4B4F5507E9149E3F938FC8DD5C9A13C13606116B59EE96D7E581390FBFC50B22205705ECDF47908EA01CE722E7CB34958F8D16E4D656EFE3E3F25631AF12A6E31CE538B738CEA78E20DDD2ADBBF4482C1B97DE8A01CDF2E76B79BD99D5A362E7C1BCA5BBF665C79D7FF5EBD7FA9F9A4B27A5A07D6667FF73B48EA7C79FBEC663E2FDC5EBA4C01FA3866FEAF49E18A415411AFB19C00603C0F66A434374F3D48FA610FD7004CBD6707B710AB7D7B4B42297778A51ADE3DAD2F9BCD1E53DA2AB773E9A7673796084D5D6C7FC29CEA91E76FEE49DF381BF0AA5E2BA4A74056F7DDCB5D1FA9CB77EA7501B81B4322FBDA7232308B74EFFD5D09F5DF7860E0371BBD1B25BC3F8ED71E9ADF6D7B5DE10D152DE15D305694590DEC2DBAEB8DC5DEB6088382E066C3000DB2BAA65D9F65682202D48F75EADA796FC795DA5F28355BA3DB8B1B9F8DD28AD83225ED476BF506CF0EDB69F016C3000DB2B10A405E95EEFC4736FDCB5A1B9744FF48EE9A8C4BC5826968DC108A3874C0C86D8D05C3E242F85D2A3E9FE89ED47E5B79FB19F016C3000DB2B10A405E9DE1BA4E39AEE31227F8CFEBF46C9AF5F7F532C930F10985FBBBDF4449A363B6EB7963995DB3128A16FB8FD0C608301D85E81202D48F789207DDAB8F23BE21AF46B96296FAF04E958B661F4D40FA6FBBFC9073BAC2A3148624F1AF0CF7E06B0C100B0BD42905604E9CD0ED2A78FBCE94D71C9BD8642F9AA96926EC71500AA837473F1DFEA0BC5BBE37AF4D525062A8C79BEDDF633800D06607B0582B420DD6782F4A0C2A437A7003DAD323DAE1B5F99571DA4E39AED31A27F75C947EA17A4ED67001B0CC0F60A046941BAEF05E9D282FFEBB25D5AD03E48C7A8DD0DCDE59A18A53B1FC1BB506A1ADC34F57D29441F50DF5C3EDCB7DB7E06B0C1006CAF409016A4FB4C908EDB7957EEAA1297BF8BAEDCF932638B9F4ACBDD38A850DC2B5AA5E3DAF2F54DE5F3EAC74EF9524353714C9A775FFD98299FF10DB79F016C3000DB2B10A405E95E6DD8F99377AEEED25D1197B34AE5C108D211A81B0BE52F36164AFB8F1851DE294DBFB6BE50BA350278FC1DD2543A7048A1F4F186B153F6F10DB79F016C3000DB2B10A40569B09F016C30006CAF10A415411AFB19C00603C0F60A415AD902417AC488113BA8B5D8CF00361880ED95ED155BA65E9553A911A47B47905EB060C19EB367CF7EF0EEBBEF5EF9C31FFEF0C73535353BA9E5D8CF00361880ED157471BD6A2DEB0CD48274F70ED25996ED3873E6CCD12B56AC5895B54ACBBD7CF9E597CF3DFAE8A3F755D3B19F016C3000DB2BE8FA20BDCE402D4877DF20FDE4934FEEBF70E1C267B24ECC9A35EBA59123475E595B5BBBB31A8FFD0C608301D85E41D707E90E03B520DDFD8274F2A6C71E7BEC9A55AB5665EBB33A498F59D6D8D8F81DB51EFB19C00603B0BD822D13A4D708D48274F72AB7DE7A6BB674E9D2E5D9465AB264C94BE3C78FBFABB6B6764FB51FFB19C00603107814650B96AD15A41F7EF8E135EEDF71C71DD98A152BD65AEEC9279FDCA2EF63E1C2857958ED6CFEA2458BB2871E7A28BF3D6BD6ACECB9E79ECB962F5F9EFDE52F7FC9962D5BB645DFDBBC79F3B251A346658B172FDED81C9D3F261EAB4E2B9D157B5B409006804DFF8166AB77EDBEFAEAABB357BDEA556D01F6C61B6F8C7D7476DD75D7ADB1DC030F3C906DBFFDF6F9FC0B2EB820FBD4A73EB54619397264BEDCC48913B3C18307B795E38F3F3EFBD0873EB45679FCF1C7F350FC939FFCA4AD1C74D041D90E3BEC909D7DF6D96B4C7FF4D147F3E7BEF4D24BB3B7BDED6DF9ED9D77DE39BBFCF2CBB3B973E7E6EF77FAF4E95B7C5DC5FF76ECB1C75E5F2A9516AD5EBD7AD50664E857E6CF9F7FD931C71CF340FA5C2769910640900680AE0BD2DB64B0B1050B16E4A1F87DEF7B5F1E86E3F6673EF399ECDDEF7E777E3BE657961D346850F6E94F7F3ABF7DFBEDB76763C68CC9CB11471C9107D95FFCE217F9BC5FFFFAD7D9DE7BEF9DEDB4D34ED961871D967DF9CB5FCEBEF0852FE4A17A975D76C9E7C7F2D10A7EE59557E6CB7DF5AB5FEDB4C4B293264DCA83F7E9A79F9E3F47B158DC2641BA32D8585D5DDD61C3870F5FB8AEC1C656AD5A754F0C36963ED739B1BC5A0F80200D005D13A4B7E9E5AF227C4608DD6BAFBDB20F7EF0836D25827575388D2ED4BBEEBA6BF6BBDFFD2EFBEC673F9B5D76D965F9F43BEFBC33DB6DB7DDB24F7EF2936B7405BFF8E28BB337BDE94DF9EDEF7CE73BD91E7BEC913FEED5AF7E75F6F5AF7FBD2D4847ABF7873FFCE1BCCB78946815DFAEB535BC32EDE31FFF7876F3CD3767A3478FCE5EF39AD7E4ADE21FF8C007F2207DD14517E5CBC463468C1891EDB3CF3ED9FDF7DFBF5546ED8ED1B8070C1870DE8409139E7BE595575EACCAD0CFA7F576619A37277DB6E71AB51B00411A00BA663FB8CE00BDB583F4534F3DB5C6F4B85F1DA4BFFBDDEFE6F73FF1894FE40136CEA13EE18413F2601BA176C71D77CC860D1B96FDED6F7FCBE6CC99937DFFFBDFCF5EFFFAD767A552293BF2C823B3CF7DEE73595D5D5D1EAE23F0568274A5BB76DCEFACFCFCE73F6F7B5FEDBB76C7FCCF7FFEF3F9DF37BCE10DF97B9A3973E656BB8E74E8D7AFDFDEF5F5F5339205CF3EFBEC8D43860C29A5CFF6BE98AEA603204803C056B6B582F489279E989D76DA696D25026975908EF79102623E2DCE858EAEDBD1CAFCDBDFFE369F3F61C2843C3847E83DEFBCF3D608C2871F7E78DEAA1CE73FBFEE75AFCB4E39E594B58274B46ADF75D75D7917EE98175DBEE37EB494B70FD26F7EF39BF373952348C7B9D437DD7453FE9868B5DE9AD791AE565353B3535D5DDDE9E9F86651FC8DFB6A2F00823400F4C220FDD8638F65DFF8C637DA4A9C037DE08107B6DDAF6EDDEDDFBF7FDEFA1CE74E373535E561BBBEBEBEAD1C7AE8A16DDDBBABBB7647B08E30BDDF7EFB65AF7DED6BF3DB51E2DCE68D69918EF3A12390C7B4030E38609B9E23DD99112346ECA0D602204803402F0ED23178D755575D9507DB72B99CB7F656060D8BAEDA471D75547EFB97BFFC655BB0FDC8473E928D1D3B36FBDAD7BE969F1B1DE72CC7ED6F7DEB5B6B9C231D2DD47FFAD39FB24B2EB9243BEBACB3B2430E39247BE31BDF98DF8EF2C8238FB405E938FFFAB6DB6ECBDF4BBC46B470C7FDEA16E93FFEF18FD917BFF8C5ECAD6F7D6BA7A376BFF0C20BDB34480380200D00BD3848476B7384E0EBAFBF3EFFFB873FFC21EF76BDFFFEFB67175E78617E3B46D48EC1BC66CC98914F8BD1BA23D856AEE5FC9BDFFC260FC7D5CF1BDDB22BE72DBFE52D6FC94E3DF5D43C0047008FC1C6E2769438CF7A73CF916E1FA46394F0EAE505690004690010A4BBACC48060BBEFBE7BDE1DBB325858BCDE0D37DC908FDCDDD8D898BDE31DEFC807078B6B4D47C08E6B3CC728DBD1921DD7778E01C4221C57AEF71CE7298F1F3F3EEFF61DE73BCF9B372F6FE18E12ADDB9516EF2853A64CC9DF478CD41DAF15ADC971BDE808C5311A78DC8FE7AC2C1797E23AF3CC33F3201DF3E33DC7E067071F7C70FE9868258FD1C6A3DBB9200D80200D0082F41619682CCE778EDBFDFAF5CB5BA5B76B6D058EB01A236EDF7BEFBD79A08D56DE934E3A29EF6E1DCBD7D6D6E6E753B72F7139AAEAD7F8CB5FFE9277CFEEA8C479D5EDDFD3AC59B3F2D7BFE79E7BD69A57E95EFECD6F7E330FF6EF7AD7BBF2C01ED7948E4B6BC5BC77BEF39D6DADE582340082340008D25BB42C5FBE3C7BF1C517F3B2B55EB37D89CB674597EF65CB96AD352F02FDFCF9F3F3DBD5D7ACAE94A54B9776385D900640900600415AD94645900640900600415A11A40110A40140905604690004690010A415411A0041DA5A0000415A900600411A000469411A0004690010A415411A00411A00046945900640900600415A11A40110A40140905604690004696B01000469411A0004690010A405690010A40140905604690004690010A415411A00411A00046945900640900600415A11A40110A4AD050010A405690010A401409016A40140900600415A11A40110A40140905604690004690010A415411A00411A0004694590064090B61600409016A40140900600415A900600411A000469459006409006806EAE582CAE5EBE7CB910DB0D4AFA1CE6A520BD42AD04409006806E6CDAB469F3162E5C28C87683F2D4534F5D9682F41D6A25008234007463A552E9E01B6EB861E9FCF9F317F7E496E979F3E6F5E496E8F9B366CD9A9042F4EC540E522B0110A401A09B8BF0162DA1A9AC8C73747B5AB9F5D65BB351A3466513274ECC7AE2FB6F5DEF7708D10008D200C0169765D91B972E5DBA7CF1E2C5D9C08103AFB3460040900600D6E1B1C71EBB266B552A9516D5D5D51D66AD0080200D0074E0C9279FDC7FD5AA55951C9DAD5EBD7AD5F0E1C317D6D6D6EE6CED0080200D005449B979C7850B173E93B513D3060C18709E3504008234005065E6CC99A3B34E4C9830E1B97EFDFAED6D2D0180200D0024F3E7CFDF63C58A15AB3A0BD2AFBCF2CA8B83070F9E515353B393B50500823400F479B367CF7E305B8F1933662CA8ABAB3BDDDA0200411A00FAB4DADADA1DEFBEFBEE95EB0BD2CF3EFBEC8DE95860512C6FAD0180200D007DDAF0E1C3FF6BE5CA952FAF23473FDFD8D858D2220D0082340090C4B9CF975F7EF9DCCE52F4F4E9D32F4CC701F739471A00046900A0D5D1471FBDEFAC59B35E6A1FA257AD5A75CF800103E618B51B000469E8F36AAFB862C7534795DFBADE05B36CFB4185496FAEDC3D695CF98DD61EF44E23478EBC7275523D60774C4BC700E75A3B002048439FD7784EF11F1A0AE5ABE2764353E9AC8642E98FD5A5B1A9FCD57C5E73B9A6B1A9F4BBCAE3EA0BC5BB1BC64ED967D8F993771E31A2AC9B27F422B5B5B53B4F9E3C79592545CF9F3FFFB2B4FF9F13D3AD1D0010A4A14F3B6D5CF91DF5CDA5AF343497A60E6E2A7F2405E762DC1F52287DBC524E3CF7C65D5B8274E9C214A60F89DB439A4A0736148A33D3F27F4A65599AB79FB509BD4B7D7DFD914B962C7969F1E2C5D931C71CF3405D5DDD61D60A0008D2E040B9503A32955B53185E5CDF5C9ED858284D195228EFDD30BABC479453C716DF13CB4537EE149CEFAF1F5BFE5A7D53695C5AFE917C99B153F689F06D4D42EF347EFCF8BB468D1A95A57DFF246B03000469A05575D7EE08D229305FD9D2FA9C4AA1B4289FDE5CAE4F81FBE16885AE2F14FF234D7FBEBEB9744D04F008D2A9CCB526A1F7A9ADADDD33F6FBF1D7DA0000411A689577E96E2E3D9E9F0F9D827404EBCABC380FBA256C5FBB5BBA7D4A9AFFD3B89F96BD33FFDB5C9A5A7D1FB0DF0700EC50A1574B41787843A17C4B74EF8EEEDB2D2DD2A55FA5BF4D51D2ED05B1DCA04271AFB4CCFCC642F1BF1B9B4B8D69FA7DD18A9DFECE6EFD3BCBDA04FB7D00C00E15FA843546ED8E6EDACDE59AFA31A5F74719DC34F57D317D705371DF86A6F2C9F563A67C2C2E81D5BE05FA94E6A97BA6E53F676D82FD3E0060870ABD5E7DD3E477579F23DD58287E76C8B8A9BB574AC3E8F22E8DE3CAEF4D01FB47F9C0644DC531D1E53BBA7B579E2385EC33D2BCC1D626D8EF030076A8D0AB0D294CFD6443A1746F84E496409C5F47FA7FAB4B7DA17C7C4373F18014B60744A86E5DEE7B69DEED956EE1E9F68493C74E798B350AF6FB00801D2A00D8EF030076A80080FD3E00D8A10200F6FB0060870A00D8EF03801D2A0060BF0F0076A80080FD3E0060870A00F6FB00801D2A0060BF0F005B7587AA288AA2284ADF298E7E0000000000000000000000000000000000000000000000000000000000000000000080DCFF0797CC739D73D6B32D0000000049454E44AE426082, 1); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('fa9b683d-1c51-11ec-94ee-5ef70686b817', 1, 'flowTranslate.bpmn', 'fa9b683c-1c51-11ec-94ee-5ef70686b817', 0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C646566696E6974696F6E7320786D6C6E733D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A7873693D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612D696E7374616E63652220786D6C6E733A7873643D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D612220786D6C6E733A666C6F7761626C653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E2220786D6C6E733A62706D6E64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F44492220786D6C6E733A6F6D6764633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A6F6D6764693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220786D6C6E733A62706D6E323D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2220786D6C6E733A64633D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44432220786D6C6E733A64693D22687474703A2F2F7777772E6F6D672E6F72672F737065632F44442F32303130303532342F44492220747970654C616E67756167653D22687474703A2F2F7777772E77332E6F72672F323030312F584D4C536368656D61222065787072657373696F6E4C616E67756167653D22687474703A2F2F7777772E77332E6F72672F313939392F585061746822207461726765744E616D6573706163653D22687474703A2F2F666C6F7761626C652E6F72672F62706D6E222069643D226469616772616D5F666C6F775472616E736C61746522207873693A736368656D614C6F636174696F6E3D22687474703A2F2F7777772E6F6D672E6F72672F737065632F42504D4E2F32303130303532342F4D4F44454C2042504D4E32302E787364223E0A20203C70726F636573732069643D22666C6F775472616E736C61746522206E616D653D22E8BDACE58A9EE6B581E7A88B2220697345786563757461626C653D2274727565223E0A202020203C657874656E73696F6E456C656D656E74733E0A2020202020203C666C6F7761626C653A657865637574696F6E4C697374656E6572206576656E743D22656E642220636C6173733D22636F6D2E666C6F772E64656D6F2E636F6D6D6F6E2E666C6F772E6C697374656E65722E557064617465466C6F775374617475734C697374656E6572223E3C2F666C6F7761626C653A657865637574696F6E4C697374656E65723E0A202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C73746172744576656E742069643D224576656E745F316F756B386B6A223E3C2F73746172744576656E743E0A202020203C757365725461736B2069643D2241637469766974795F303870396B6E6722206E616D653D22E5BD95E585A52220666C6F7761626C653A61737369676E65653D22247B7374617274557365724E616D657D2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934353431313335343236373634382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A66616C73652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383938333631303822206C6162656C3D22E68F90E4BAA42220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F30386C67766F302220736F757263655265663D224576656E745F316F756B386B6A22207461726765745265663D2241637469766974795F303870396B6E67223E3C2F73657175656E6365466C6F773E0A202020203C757365725461736B2069643D2241637469766974795F31326F6C72303122206E616D653D22E8BDACE58A9E2220666C6F7761626C653A63616E64696461746555736572733D22247B7374617274557365724E616D657D2C61646D696E2220666C6F7761626C653A666F726D4B65793D227B2671756F743B666F726D49642671756F743B3A2671756F743B313434303934353431313335343236373634382671756F743B2C2671756F743B726561644F6E6C792671756F743B3A747275652C2671756F743B67726F7570547970652671756F743B3A2671756F743B444550542671756F743B7D223E0A2020202020203C657874656E73696F6E456C656D656E74733E0A20202020202020203C666C6F7761626C653A6F7065726174696F6E4C6973743E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383938343835353422206C6162656C3D22E5908CE6848F2220747970653D226167726565222073686F774F726465723D2230223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A202020202020202020203C666C6F7761626C653A666F726D4F7065726174696F6E2069643D223136333233383938353339353922206C6162656C3D22E8BDACE58A9E2220747970653D227472616E73666572222073686F774F726465723D2231223E3C2F666C6F7761626C653A666F726D4F7065726174696F6E3E0A20202020202020203C2F666C6F7761626C653A6F7065726174696F6E4C6973743E0A20202020202020203C666C6F7761626C653A7661726961626C654C6973743E3C2F666C6F7761626C653A7661726961626C654C6973743E0A2020202020203C2F657874656E73696F6E456C656D656E74733E0A202020203C2F757365725461736B3E0A202020203C73657175656E6365466C6F772069643D22466C6F775F306E343566356A2220736F757263655265663D2241637469766974795F303870396B6E6722207461726765745265663D2241637469766974795F31326F6C723031223E3C2F73657175656E6365466C6F773E0A202020203C656E644576656E742069643D224576656E745F306C7A786E7738223E3C2F656E644576656E743E0A202020203C73657175656E6365466C6F772069643D22466C6F775F317338693965722220736F757263655265663D2241637469766974795F31326F6C72303122207461726765745265663D224576656E745F306C7A786E7738223E3C2F73657175656E6365466C6F773E0A20203C2F70726F636573733E0A20203C62706D6E64693A42504D4E4469616772616D2069643D2242504D4E4469616772616D5F666C6F775472616E736C617465223E0A202020203C62706D6E64693A42504D4E506C616E652062706D6E456C656D656E743D22666C6F775472616E736C617465222069643D2242504D4E506C616E655F666C6F775472616E736C617465223E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F316F756B386B6A222069643D2242504D4E53686170655F4576656E745F316F756B386B6A223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223133322E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F303870396B6E67222069643D2242504D4E53686170655F41637469766974795F303870396B6E67223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223232302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D2241637469766974795F31326F6C723031222069643D2242504D4E53686170655F41637469766974795F31326F6C723031223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2238302E30222077696474683D223130302E302220783D223338302E302220793D223239302E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E53686170652062706D6E456C656D656E743D224576656E745F306C7A786E7738222069643D2242504D4E53686170655F4576656E745F306C7A786E7738223E0A20202020202020203C6F6D6764633A426F756E6473206865696768743D2233362E30222077696474683D2233362E302220783D223534322E302220793D223331322E30223E3C2F6F6D6764633A426F756E64733E0A2020202020203C2F62706D6E64693A42504D4E53686170653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F30386C67766F30222069643D2242504D4E456467655F466C6F775F30386C67766F30223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223136382E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223232302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F306E343566356A222069643D2242504D4E456467655F466C6F775F306E343566356A223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223332302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223338302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A2020202020203C62706D6E64693A42504D4E456467652062706D6E456C656D656E743D22466C6F775F31733869396572222069643D2242504D4E456467655F466C6F775F31733869396572223E0A20202020202020203C6F6D6764693A776179706F696E7420783D223438302E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A20202020202020203C6F6D6764693A776179706F696E7420783D223534322E302220793D223333302E30223E3C2F6F6D6764693A776179706F696E743E0A2020202020203C2F62706D6E64693A42504D4E456467653E0A202020203C2F62706D6E64693A42504D4E506C616E653E0A20203C2F62706D6E64693A42504D4E4469616772616D3E0A3C2F646566696E6974696F6E733E, 0); +INSERT INTO `ACT_GE_BYTEARRAY` VALUES ('faa3f3be-1c51-11ec-94ee-5ef70686b817', 1, 'flowTranslate.flowTranslate.png', 'fa9b683c-1c51-11ec-94ee-5ef70686b817', 0x89504E470D0A1A0A0000000D494844520000024C0000017C08060000003DF6E4F3000012C84944415478DAEDDD796C55E5BA07E0A3C6391ABC0E51E3108FC744FF306AD43847FFF0E8F51AD118A002054B0A020E512243EE85EB05D43844A3880A18F530087A1D1A531447385CA2321A064183CA3C540A5806A52047D65DEF4A4B36A528A5B4DD6D9F277953BB67775FF6EF5BDF5AEBDB7FF90B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040BD254972C4D2A54BDF9E3E7DFA6F93274F4E3EFBEC33D5C895BEEFBBA64D9BB676CA9429B7EB3FFDA0FF00F2501A56EFA41F96C9BA75EB92CACACA64C78E1DAA912BDEF778FFA74E9DBA390DB05BF59FD27F007926B6ECE3C35270347D9595956D48036B96FE53FA0F20CFC46E105BF6F9B3A59F06D676FDA7F41F409E8963188445FE54FC3DF49FD27F00CD34B07ED954962C9DFD8F64D1E743B38AFF8ECB848CC0D27FFA0F4060A5B5B5624DB2F093FF4EE67FD86F8F8ACBE23A4123B0F49FFE0368F581B56A51E95E61555DAB174D1434024BFFE93F0081F5DD3F9FDA6760C575824660E93FFD07D0EA036BE16783F71958719DA01158FA4FFF01082C8125B0F49FFE033060FAE30FD1382B695F8115D7091A81A5FFF41F40AB0FAC1FBE7C719F8115D7091A81A5FFF41F40AB0FAC8D6B16240B3FFD9FBD7787A497C575824660E93FFD07D0EA032B6AD99CB17B05565C26640496FED37F00022B6AFBF6E487AF46ECBD3B24BD2CAE1334024BFFE93F80561D58B192F2F75F0EDFE73124719DD5960596FED37F00AD33B0D22DF7B21FA624DF7CFC5FFB0CABEA8ADBC46D6DED0B2CFDA7FF005A4D60FDD956BDAD7D81A5FFF41F40AB1F30EDCF56FD1F6DED0B1E81A5FFF41F408B0FAC030DABEA123C024BFFE93F80161F584A60E93FFDC7BE151515B5B9EBAEBBDA151414BC90FE9C9CD6B2B4B6A59554FD8CDF27575DDF2E6EEF5D23EF6CDEBCF9DF4A4B4B87BEF8E28BF3870C19B261C0800195BD7BF7DE158DDCAB57AF9D7DFBF6DD3270E0C09543870E9DD8AF5FBF7F4FEF72880193A01058FA4F1930FD998E1D3BFE3DCD9292B476540D8EF6B7E2F625717FEF224D6EE6CC99BD9E7FFEF9353D7BF64CD24152F2CE3BEF245F7FFD75B264C99264E3C68D49889FF17B5C1ED7F7EFDF7F577171F18E74E0F449A74E9DFE6AC0A40496FED37FD43250BA2A1DF0CCA8E320695F35231ECFBB4AA35BB060C17FBCFCF2CB6BEFB9E79EE4BDF7DE4BD6AF5F9FD445DC3EEE970E9C7EEBD3A7CFDB69239F24B094C0D27FFA8FA2A2A2A30A0A0A5E4A0739BB6A0E7C1E7AE8A164FCF8F17FB8611ED7C7ED6A1934ED8AC78DC7F72ED3E0D2BE3C6CD2A449A531501A33664CB275EBD6A43EE2FEF13869036F2B2C2CBC43602981A5FFF45FEB950E6ACE4C37A0E7E70E743A75EA948C1A352A59BD7A759DF2256E1FF78BFBD71838CD8BE7F16ED39083A536E3C68DFBFEBEFBEE4B962E5D9A1C4CF178E920ACB2B8B87888C052024BFFE9BF56B90BEEFCB4D6E40E6E9E7AEAA964D5AA55F5CA97B87F3C4E8D41D3AA783EEF3A0D32587AE185172A060D1A94545454240D211E77C08001DBBA76ED3A56602981A5FFF45FAB9B595A933BAB545A5A7A5033261EAFC66CD32A334D1CF4DD70E3C68DFB21064BF18FBB21C5E3F7EDDB7753E7CE9D070A2C25B0F49FFE6BF9E298A2DCDD70DDBA754BE6CE9DDB2019138F1B8F9FBB7BCE314D1C3471CCD2FDF7DFDF60334BB5CD3475EFDE7D4BDAC86D05961258FA4FFFB56C550778EF9E596AA8C152EEA02977A6299E5FD2536F6963DD1A07781FEC6396F6E798A6C2C2C28AF6EDDB9F2CB094C0D27FFAAF65AA5A3AE0F7EAC1CBC489131B2563E2797266997EB7E400F5164B07C4596C4D61C488116BD3461E26B094C0D27FFAAF65CA5D67290ECC6E4C350E049F21F13960B12865CC2E6DD9B2A549064CF1BC5DBA74D9DC1217B71458024BFFA9D63E60EAD0A1C38DB9BBE2EA7B36DC819C3D97BB6B2E5E8FE4E780C40ADE25252549531A3B76EC92B49147092C25B0F49FFE6B71B34B25D58395582FA929C4F3E6CC3295487EEA6CCB962D27F6EAD52B292F2F6FD20153FAFCFF4AB700D60D1E3CF85081A50496FED37F2D43FAB97E42EE77C335F6EC52EE2C53EE77CFC5EB3202A04E3EF8E08321F1DD70F9A07BF7EECBD346BEBA996C31FD33AD1B0496C0D27FAAB50E98F6A70FD3EBDBE57EDD4953AAF1352AED8C00A893E1C3877F135F949B0F468E1C19CBD83FD94C3E28AAFFD1FDE10786C01258FA4FB5E001D39FF6617AF9F0EADBBDF1C61B4D9A31F1FC39AF79B81100753264C8900DF12586F960DAB4690B0A0A0A4A9BD907C51F7E60082C81A5FF542B1830EDB30F3B76EC38A5FAFA3973E63469C6C4F357BF96785D4600D449FFFEFD2B1B7BEDA57D59BC7871EC929BDD4C3F286AFDC01058024BFFA9563460DAAB0FD39F2BAB2F6FEAAC89E7CF798D2B8D00A8935EBD7AEDFAF9E79FF362C0B471E3C6AD6913AF69E61F147B7C60082C81A5FF542B1C30E5F6E1AFD5BF3775D6C4F3E7CC306D3102A04EBA74E992ECDCB9332F064CE9EBD8B21FFF009B55B5D4C08AB5B3366FDEDCEC5E774BEBAFE6DE7F9B366D4A56AF5EBDC7655BB76E4D7EFCF1C7A4B2B2B2D6FB6CDBB62D59B46851F2CB2FBFE8BF66564D9D35F1FC39AFE75F4600D449CF9E3D77E6CB0CD3FAF5EB7F6C01334CCD6E9748ECD7FFDBDFFE566BBDF4D24BB5DEE7FAEBAF4F6EBAE9A666175A76C9E5574D98302169D3A64DB27DFBF6DD977DFCF1C7C921871C92CD06D4769F182CA5FF6BD94F334CF9DF87319363868916E1E1871FDE922FC7307DFBEDB7739AF1314CCDF6A0DB74A09A9D3D327AF4E83DEAF4D34F4F1E7FFCF15AEFF3D5575F25C71C734CD2AF5F3F81A5FF0EA8EEBDF7DEE4C4134F4C8E38E288E4DC73CF8DD5FE93F3CE3B2F39E59453B201535C16356EDCB8ECF6F139F5CD37DF24A5A5A5D980E9C30F3FCC7E8F8A3576F45F7EF6A163986831060D1AB42A5FCE92FBFCF3CF2737C3B3E45AC469DDE79F7F7E1642356B5F03A6A8679F7D3639F6D863F7DAA522B0F4DFFEFE2D8E3FFEF8E4CE3BEF4C9E7EFAE964D2A449C96BAFBD965C74D145C975D75D97FD7754BA2195DDFEEAABAFAEB547A362F15DFD979F7DE82C395A8CC183074FCC9775981E7BECB19266B40E538B583870C58A1549FCFD6346E9F5D75FDFA34E3BEDB4A473E7CED9F5CB972FDFEBBE77DC71471656B1189C0193FEAB6BC52C65CC24B56DDB3669D7AE5DF2D1471F25175C704172F4D14727279C7042F6DF51BD7BF7CE6E3F7FFEFC64E5CA95596F46DFC56C4159595936B8BAFBEEBB9365CB96E9BF3CEC43EB30D1620C1830E0E6FEFDFBEFCA8763BE3B75EAB4A0B9ACF4BDBFF27DC0142175CE39E724679C7146F63376C345189D75D659D9EF471E7964F673E2C4897BDCEFBBEFBE4B0E3DF4D06CCB3E6E1307E91A30E9BFBAD4D0A143B3DDBA31BB19FDD6A3478F24FD2CCAFA2FBE5D7EE4C89159458FC6ED2FBFFCF2ACDF1E79E491E4E4934FDEFD38D5334F1182FA2F2F075579B3D2F7830F3EB8CB4ADFD46786E9D0EEDDBBEF68EAEF925BBD7AF597690397F92EB9C6AF279E7822B9E4924BB22DF6D8EA8FF089DD6CB13576F8E187EF0EACDC8AE0BAF2CA2BB3FFBEF4D24BB399280326FD57979A316346045872E1851766C72E3DF7DC73C933CF3C931C76D861B1BB6477C5CC52D5DF2DDB6D77DB6DB765B34AD58F73F1C5176783A9E8D57C9F65F25D72BE4B8E66AE5FBF7E9F94949434E980E9D1471F9D9036F12881D5F815BB356EB8E1862C786217480453845804501CA754F3F6115A471D7554F2FEFBEFEF9EA58AD9A608400326FD57D75DC2B13B2E66990A0B0B93F1E3C72703070ECCEA965B6EC97A70E1C285D9CCD365975D969DA010B34B4F3EF9E4EEC788D9D161C38665B3A3F97E12426B1C3055CD3295540F56468D1AD5241913CF9B33602A91FC1CE816C05F8B8B8B7F8BB5759A424545C5ACB481CBE37508ACC6AF9F7EFA29E9DAB56B36508A908A9FB1051F67304580E59EF21D03EBD805174B0AE43EC68D37DE989C7AEAA9C9BC79F30496FEDBAFEAD6ADDBEE83B6A3D7E2F738E3EDDA6BAF4D468C18910D8CE260F0EAB597620634FD9CDA631770ACD914335271E6DC5B6FBD954C9F3E5DFFE5A10E1D3ADC583D58493FE71B7D96299EAF63C78EBB77C7C5EB91FC1CB03E7DFABC3D66CC98261930A5CFFDBF69130F13588D5F53A64CC98229D65C8AD7FAE9A79FEEDE2517BB4B62E6E88A2BAEC8D6BC79F3CD37B32DFE38483706D7359726B8E69A6B92934E3A2999356B96C0D27F7F5A0B162C4866CE9C991DB01DB34C71D9F7DF7F9FDC7CF3CD590F1E77DC71BBCF908BFE4A432EBBFC95575E497EFDF5D76CE62966A2E2C0F1DA4E4AD07F7937CB34A37AC012C7A835A678BE9CD9A519129F7A69DFBEFDC9454545DB1A7B9D8C3973E6C4AEB8F2787E81D5F815C7873CF0C003D98ACB113E1148B16BA37A5669F6ECD9C9EDB7DF9EEDB68B29ED385629B6F66B7BAC8A8A8A6CA629D6C71158FA6F7F2BCE82AB1E3055D7BBEFBE9B9C7DF6D9D95A4DF1FB175F7C919D39F7EAABAF66BFC72AF371365D0C969AD35A60AD79C0D4B163C7ABD2CFFADFAB072E7122496388E7C9192CFD1EAF43E2536F85858577F4ECD9B33282AF31949797FF5FDAC02BD26A2BB0F26301CBD825127F7FDFE5A5FF1A7397706D6B79C5203EB717376EDCB857BF6ED8B041FF35230505052FE5EE9A9B3B776E83664C3C7EEEAEB8787E49CF41535C5C3C64C08001DBE21F7743DABE7DFBB7E93F98D96933FFA7C052024BFFE9BF96AFA8A8E8A874E032AF7A0013C7AD35D4A0291E377DBEDF736697E6C5F34B790EAAAE5DBB8EEDDBB7EFA6869A692A2F2F9F1A83A5B4815F15584A60E93FFDD77AA49FFB67A6B52A77A6290EDA3F98E2F1726796AA9EEF4CE94E83E8DCB9F3C0E2E2E283FE3D7355C72CAD6CE9334B024B60E93F65C054BBF4F3FFFCDC4153F581E0F53D7B2EEE5FE300EF6CB014CFE75DA7A1B704DA161616568C1831626D9CBE5B1F9B366D9A5975365C794B3E664960092CFDA7F4DF7ECF34CDCB1DDCC46C539C5C12C7B4D571E1E3EC7E35669592AAC737B344A36D099C14A7FC77E9D265F3E8D1A397AC5FBF7E675DBEEE64CD9A355F0E19326442D54069583C9EC052024BFFE93FE298A2AA03C16B0E74B2AF518975E0E2CBE1972C59921DF41FE267FC1E97C7F535BEEEA4BA76C5E33A668926118B4AC64ADCE980A7BC478F1E2B468E1C3977DAB4690B162F5EBC72C3860DBFA47DBCB5BCBC7CE9A2458BE6A41F0A9FC517E9567D37DC4F71BF96B828A5C01258FA4FE9BF83B2617E55EE3A4DF5AC19960E205F1CD2A143876BD2867C221DC197A6CD392B675F74FC9C1597C7F571BBB87D6B7EB30496C0D27FCA8069BF074E7FAFFA1A951D751C24C5ED4BE2FEDE4510584A60E93FFDD72A141515B5490740EDD28DEF17D29F93D35A96D6B6AAC1D1B6AADF27575DDF2E6EEF5D0381A50496FED37F00024B092CFDA7FF000C980485C0D27FCA80094060092CFDA7F41F80C01258FA4FE93F008125B0F49FD27F00024B193029FD0720B094C0D27FFA0F40602981A5FFF41F80C052024BFFE93F00032625B0F49FFE034060092CFDA7F41F80C01258FA4FE93F008125B0F49FD27F00024B60E93FA5FF0004961258FA4FFF01082C25B0F49FFE036839264F9EBCABB2B25258E441A57F87B569606DD77F4AFF01E49969D3A6AD5DB76E9DC0C8835AB162C55B6960CDD27F4AFF01E4992953A6DC3E75EAD4CD6565651B6CE937D9967DD9F2E5CB27A461B532AD5BF59FD27F0079283E2463CB32AD1D710C836AF4DA51F5FEDFAAFFF483FE030000000000000000000000000000000000000000EAE5FF017CAAB3DCB95DE9AB0000000049454E44AE426082, 1); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_GE_PROPERTY +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_GE_PROPERTY`; +CREATE TABLE `ACT_GE_PROPERTY` ( + `NAME_` varchar(64) COLLATE utf8_bin NOT NULL, + `VALUE_` varchar(300) COLLATE utf8_bin DEFAULT NULL, + `REV_` int(11) DEFAULT NULL, + PRIMARY KEY (`NAME_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_GE_PROPERTY +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_GE_PROPERTY` VALUES ('batch.schema.version', '6.6.0.0', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('cfg.execution-related-entities-count', 'true', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('cfg.task-related-entities-count', 'true', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('common.schema.version', '6.6.0.0', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('entitylink.schema.version', '6.6.0.0', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('eventsubscription.schema.version', '6.6.0.0', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('identitylink.schema.version', '6.6.0.0', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('job.schema.version', '6.6.0.0', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('next.dbid', '1', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('schema.history', 'create(6.6.0.0)', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('schema.version', '6.6.0.0', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('task.schema.version', '6.6.0.0', 1); +INSERT INTO `ACT_GE_PROPERTY` VALUES ('variable.schema.version', '6.6.0.0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_HI_ACTINST +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_ACTINST`; +CREATE TABLE `ACT_HI_ACTINST` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT '1', + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `ACT_ID_` varchar(255) COLLATE utf8_bin NOT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CALL_PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ACT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ACT_TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `ASSIGNEE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `START_TIME_` datetime(3) NOT NULL, + `END_TIME_` datetime(3) DEFAULT NULL, + `TRANSACTION_ORDER_` int(11) DEFAULT NULL, + `DURATION_` bigint(20) DEFAULT NULL, + `DELETE_REASON_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_HI_ACT_INST_START` (`START_TIME_`), + KEY `ACT_IDX_HI_ACT_INST_END` (`END_TIME_`), + KEY `ACT_IDX_HI_ACT_INST_PROCINST` (`PROC_INST_ID_`,`ACT_ID_`), + KEY `ACT_IDX_HI_ACT_INST_EXEC` (`EXECUTION_ID_`,`ACT_ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_HI_ACTINST +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_HI_ACTINST` VALUES ('150b9686-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', 'Flow_0so810a', NULL, NULL, '同意', 'sequenceFlow', NULL, '2021-09-24 09:31:03.827', '2021-09-24 09:31:03.827', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('150b9687-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', 'Event_04byxr7', NULL, NULL, NULL, 'endEvent', NULL, '2021-09-24 09:31:03.827', '2021-09-24 09:31:03.829', 2, 2, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('17547fdf-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Event_1psmisd', NULL, NULL, NULL, 'startEvent', NULL, '2021-09-24 09:38:17.157', '2021-09-24 09:38:17.157', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('17547fe0-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_00cexea', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:38:17.157', '2021-09-24 09:38:17.157', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('17547fe1-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_0nyla1r', '1754a6f2-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '合同录入', 'userTask', 'userD', '2021-09-24 09:38:17.157', '2021-09-24 09:38:17.178', 3, 21, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('1757db47-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_04kcajc', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:38:17.179', '2021-09-24 09:38:17.179', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('1757db48-1cd8-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1ucrh52', '1757db49-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '业务部领导审批', 'userTask', 'leaderTJ', '2021-09-24 09:38:17.179', '2021-09-24 09:38:34.591', 2, 17412, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('1b41a38a-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Event_1psmisd', NULL, NULL, NULL, 'startEvent', NULL, '2021-09-24 09:45:33.241', '2021-09-24 09:45:33.241', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('1b41a38b-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_00cexea', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:45:33.241', '2021-09-24 09:45:33.241', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('1b41a38c-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_0nyla1r', '1b41a38d-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '合同录入', 'userTask', 'userD', '2021-09-24 09:45:33.241', '2021-09-24 09:45:33.259', 3, 18, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('1b4488c2-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_04kcajc', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:45:33.260', '2021-09-24 09:45:33.260', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('1b4488c3-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_1ucrh52', '1b4488c4-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '业务部领导审批', 'userTask', 'leaderTJ', '2021-09-24 09:45:33.260', '2021-09-24 09:45:53.142', 2, 19882, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('21b8de9e-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_026fvnq', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:38:34.592', '2021-09-24 09:38:34.592', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('21b905af-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Gateway_09cdxtf', NULL, NULL, NULL, 'parallelGateway', NULL, '2021-09-24 09:38:34.593', '2021-09-24 09:38:34.593', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('21b92cc1-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_0zz0u9g', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:38:34.594', '2021-09-24 09:38:34.594', 3, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('21b92cc2-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '21b92cc0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_1yxqbe0', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:38:34.594', '2021-09-24 09:38:34.594', 4, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('21b953d3-1cd8-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_138m4nn', '21b953d4-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '工程部审批', 'userTask', 'admin', '2021-09-24 09:38:34.595', '2021-09-24 09:38:58.969', 5, 24374, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('21b97ae7-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '21b92cc0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_0tm3mph', '21b97ae8-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '造价部审批', 'userTask', 'admin', '2021-09-24 09:38:34.596', '2021-09-24 09:38:51.865', 6, 17269, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('22f48359-1d0e-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', 'Event_17n2rw9', NULL, NULL, NULL, 'startEvent', NULL, '2021-09-24 16:05:09.484', '2021-09-24 16:05:09.489', 1, 5, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('22f5e2ea-1d0e-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', 'Flow_00ldvag', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 16:05:09.493', '2021-09-24 16:05:09.493', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('22f5e2eb-1d0e-11ec-8336-3ae4f1d3c3af', 2, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', 'Activity_03kjurt', '22f9b37c-1d0e-11ec-8336-3ae4f1d3c3af', NULL, '报销单录入', 'userTask', 'userD', '2021-09-24 16:05:09.493', '2021-09-24 16:05:09.579', 3, 86, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('23030251-1d0e-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', 'Flow_0x9dx2t', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 16:05:09.579', '2021-09-24 16:05:09.579', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('23032962-1d0e-11ec-8336-3ae4f1d3c3af', 3, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', 'Activity_0ywxfwu', '23032963-1d0e-11ec-8336-3ae4f1d3c3af', NULL, '部门领导审批', 'userTask', 'leaderTJ', '2021-09-24 16:05:09.580', '2021-09-24 16:50:20.667', 2, 2711087, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('271e4969-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_026fvnq', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:45:53.142', '2021-09-24 09:45:53.142', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('271e707a-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Gateway_09cdxtf', NULL, NULL, NULL, 'parallelGateway', NULL, '2021-09-24 09:45:53.143', '2021-09-24 09:45:53.143', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('271e978c-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_0zz0u9g', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:45:53.144', '2021-09-24 09:45:53.144', 3, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('271e978d-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '271e978b-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_1yxqbe0', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:45:53.144', '2021-09-24 09:45:53.144', 4, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('271e978e-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_138m4nn', '271e978f-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '工程部审批', 'userTask', 'admin', '2021-09-24 09:45:53.144', '2021-09-24 09:46:12.596', 5, 19452, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('271ebea2-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '271e978b-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_0tm3mph', '271ebea3-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '造价部审批', 'userTask', 'admin', '2021-09-24 09:45:53.145', '2021-09-24 09:46:06.323', 6, 13178, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('2c04853b-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '21b92cc0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_1uvj3ds', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:38:51.865', '2021-09-24 09:38:51.865', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('2c04ac4c-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '21b92cc0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Gateway_0oy6ofl', NULL, NULL, NULL, 'parallelGateway', NULL, '2021-09-24 09:38:51.866', '2021-09-24 09:38:51.866', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('2ef98c46-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '271e978b-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_1uvj3ds', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:46:06.323', '2021-09-24 09:46:06.323', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('2ef9b357-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '271e978b-1cd9-11ec-acd8-3ae4f1d3c3af', 'Gateway_0oy6ofl', NULL, NULL, NULL, 'parallelGateway', NULL, '2021-09-24 09:46:06.324', '2021-09-24 09:46:06.324', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('3040a850-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_124e8z3', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:38:58.970', '2021-09-24 09:38:58.970', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('3040a851-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Gateway_0oy6ofl', NULL, NULL, NULL, 'parallelGateway', NULL, '2021-09-24 09:38:58.970', '2021-09-24 09:38:58.971', 2, 1, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('3040cf62-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_1kyhnlz', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:38:58.971', '2021-09-24 09:38:58.971', 3, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('3040cf63-1cd8-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1yuuyie', '3040cf64-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '财务部审批', 'userTask', 'leaderTJ', '2021-09-24 09:38:58.971', '2021-09-24 09:39:52.105', 4, 53134, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('32b6e26a-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_124e8z3', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:46:12.597', '2021-09-24 09:46:12.597', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('32b6e26b-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Gateway_0oy6ofl', NULL, NULL, NULL, 'parallelGateway', NULL, '2021-09-24 09:46:12.597', '2021-09-24 09:46:12.598', 2, 1, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('32b7097c-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_1kyhnlz', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:46:12.598', '2021-09-24 09:46:12.598', 3, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('32b7097d-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_1yuuyie', '32b7097e-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '财务部审批', 'userTask', 'leaderTJ2', '2021-09-24 09:46:12.598', '2021-09-24 09:47:39.942', 4, 87344, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('420171fe-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Event_17n2rw9', NULL, NULL, NULL, 'startEvent', NULL, '2021-09-24 09:32:19.258', '2021-09-24 09:32:19.258', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('420171ff-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Flow_00ldvag', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:32:19.258', '2021-09-24 09:32:19.258', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('42017200-1cd7-11ec-acd8-3ae4f1d3c3af', 2, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_03kjurt', '42019911-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, '报销单录入', 'userTask', 'userD', '2021-09-24 09:32:19.258', '2021-09-24 09:32:19.282', 3, 24, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('42051b86-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Flow_0x9dx2t', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:32:19.282', '2021-09-24 09:32:19.282', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('42051b87-1cd7-11ec-acd8-3ae4f1d3c3af', 3, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_0ywxfwu', '42054298-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, '部门领导审批', 'userTask', 'leaderTJ', '2021-09-24 09:32:19.282', '2021-09-24 09:32:30.145', 2, 10863, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('487eab7e-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Flow_18p3hqb', NULL, NULL, '同意', 'sequenceFlow', NULL, '2021-09-24 09:32:30.145', '2021-09-24 09:32:30.145', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('487ed28f-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Gateway_179zgnp', NULL, NULL, NULL, 'exclusiveGateway', NULL, '2021-09-24 09:32:30.146', '2021-09-24 09:32:30.147', 2, 1, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('487ef9a0-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Flow_058cmsb', NULL, NULL, '报销金额大于1000', 'sequenceFlow', NULL, '2021-09-24 09:32:30.147', '2021-09-24 09:32:30.147', 3, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('487ef9a1-1cd7-11ec-acd8-3ae4f1d3c3af', 3, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_0qay48u', '487ef9a2-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, '总经理审批', 'userTask', 'leader', '2021-09-24 09:32:30.147', '2021-09-24 09:33:02.293', 4, 32146, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('4fec6a4a-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_0di6qa6', NULL, NULL, '同意', 'sequenceFlow', NULL, '2021-09-24 09:39:52.105', '2021-09-24 09:39:52.105', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('4fec915b-1cd8-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1eewt01', '4fec915c-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '法务部审批', 'userTask', 'leaderLaw', '2021-09-24 09:39:52.106', '2021-09-24 09:40:52.217', 2, 60111, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('5ba837d8-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Flow_0ycx8fb', NULL, NULL, '同意', 'sequenceFlow', NULL, '2021-09-24 09:33:02.294', '2021-09-24 09:33:02.294', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('5ba837d9-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', 'Event_0nvjxgh', NULL, NULL, NULL, 'endEvent', NULL, '2021-09-24 09:33:02.294', '2021-09-24 09:33:02.295', 2, 1, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('66c6d394-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_0di6qa6', NULL, NULL, '同意', 'sequenceFlow', NULL, '2021-09-24 09:47:39.943', '2021-09-24 09:47:39.943', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('66c6d395-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_1eewt01', '66c6d396-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '法务部审批', 'userTask', 'leaderLaw', '2021-09-24 09:47:39.943', '2021-09-24 09:48:03.392', 2, 23449, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('7138d683-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Event_17n2rw9', NULL, NULL, NULL, 'startEvent', NULL, '2021-09-24 17:54:43.245', '2021-09-24 17:54:43.246', 1, 1, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('7138fd94-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Flow_00ldvag', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 17:54:43.246', '2021-09-24 17:54:43.246', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('7138fd95-1d1d-11ec-8336-3ae4f1d3c3af', 2, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Activity_03kjurt', '7138fd96-1d1d-11ec-8336-3ae4f1d3c3af', NULL, '报销单录入', 'userTask', 'userD', '2021-09-24 17:54:43.246', '2021-09-24 17:54:43.277', 3, 31, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('713ddf9b-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Flow_0x9dx2t', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 17:54:43.278', '2021-09-24 17:54:43.278', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('713ddf9c-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Activity_0ywxfwu', '713e06ad-1d1d-11ec-8336-3ae4f1d3c3af', NULL, '部门领导审批', 'userTask', NULL, '2021-09-24 17:54:43.278', NULL, 2, NULL, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('719d8e5f-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', '719d8e5e-1cd7-11ec-acd8-3ae4f1d3c3af', 'Event_1psmisd', NULL, NULL, NULL, 'startEvent', NULL, '2021-09-24 09:33:39.134', '2021-09-24 09:33:39.134', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('719d8e60-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', '719d8e5e-1cd7-11ec-acd8-3ae4f1d3c3af', 'Flow_00cexea', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:33:39.134', '2021-09-24 09:33:39.134', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('719d8e61-1cd7-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', '719d8e5e-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_0nyla1r', '719d8e62-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, '合同录入', 'userTask', NULL, '2021-09-24 09:33:39.134', '2021-09-24 09:34:08.588', 3, 29454, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('72f394e9-1d14-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', 'Flow_18p3hqb', NULL, NULL, '同意', 'sequenceFlow', NULL, '2021-09-24 16:50:20.676', '2021-09-24 16:50:20.676', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('72f3bbfa-1d14-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', 'Gateway_179zgnp', NULL, NULL, NULL, 'exclusiveGateway', NULL, '2021-09-24 16:50:20.677', '2021-09-24 16:50:20.678', 2, 1, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('72f3e30b-1d14-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', 'Flow_1qigakr', NULL, NULL, '报销金额小于1000', 'sequenceFlow', NULL, '2021-09-24 16:50:20.678', '2021-09-24 16:50:20.678', 3, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('72f3e30c-1d14-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', 'Event_0nvjxgh', NULL, NULL, NULL, 'endEvent', NULL, '2021-09-24 16:50:20.678', '2021-09-24 16:50:20.679', 4, 1, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('73c0c759-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', 'Flow_0zmsn3x', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:40:52.217', '2021-09-24 09:40:52.217', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('73c163a5-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c1157e-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '73c163a6-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '法务部会签', 'userTask', 'userB', '2021-09-24 09:40:52.221', '2021-09-24 09:41:55.361', 2, 63140, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('73c18aba-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c13c8f-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '73c18abb-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '法务部会签', 'userTask', 'userC', '2021-09-24 09:40:52.222', '2021-09-24 09:42:14.512', 3, 82290, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('73c18abf-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c13c90-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '73c18ac0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '法务部会签', 'userTask', 'leaderLaw', '2021-09-24 09:40:52.222', '2021-09-24 09:41:36.323', 4, 44101, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('74c10343-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_0zmsn3x', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:48:03.393', '2021-09-24 09:48:03.393', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('74c12a5d-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10348-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '74c12a5e-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '法务部会签', 'userTask', 'leaderLaw', '2021-09-24 09:48:03.394', '2021-09-24 09:48:12.066', 2, 8672, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('74c12a61-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10349-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '74c15172-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '法务部会签', 'userTask', 'userC', '2021-09-24 09:48:03.394', '2021-09-24 09:49:14.528', 3, 71134, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('7a4309f6-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '7a4294c2-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '7a4309f7-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '法务部会签', 'userTask', 'admin', '2021-09-24 09:41:03.137', '2021-09-24 09:43:49.221', 1, 166084, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('832c0853-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', '719d8e5e-1cd7-11ec-acd8-3ae4f1d3c3af', '817c52e168a14ade88f104c0d6c43755', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:34:08.589', '2021-09-24 09:34:08.589', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('832c0854-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', '719d8e5e-1cd7-11ec-acd8-3ae4f1d3c3af', 'Event_12ajo3d', NULL, NULL, NULL, 'endEvent', NULL, '2021-09-24 09:34:08.589', '2021-09-24 09:34:08.590', 2, 1, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('8b4134b9-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '8b410da5-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '8b4134ba-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '法务部会签', 'userTask', 'userB', '2021-09-24 09:48:41.143', '2021-09-24 09:48:54.255', 1, 13112, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('9f2844af-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '9f2844ae-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_0jyv1zb', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:49:14.534', '2021-09-24 09:49:14.534', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('9f2844b0-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '9f2844ae-1cd9-11ec-acd8-3ae4f1d3c3af', 'Gateway_1m5fruz', NULL, NULL, NULL, 'exclusiveGateway', NULL, '2021-09-24 09:49:14.534', '2021-09-24 09:49:14.535', 2, 1, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('9f286bc1-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '9f2844ae-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_1f8yxov', NULL, NULL, '同意人数大于40%', 'sequenceFlow', NULL, '2021-09-24 09:49:14.535', '2021-09-24 09:49:14.535', 3, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('9f286bc2-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '9f2844ae-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_1h3pnxy', '9f286bc3-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '总经理审批', 'userTask', 'leader', '2021-09-24 09:49:14.535', '2021-09-24 09:49:45.793', 4, 31258, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('b1ca2a78-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '9f2844ae-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_1a3qclm', NULL, NULL, '同意', 'sequenceFlow', NULL, '2021-09-24 09:49:45.794', '2021-09-24 09:49:45.794', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('b1ca2a79-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '9f2844ae-1cd9-11ec-acd8-3ae4f1d3c3af', 'Event_12ajo3d', NULL, NULL, NULL, 'endEvent', NULL, '2021-09-24 09:49:45.794', '2021-09-24 09:49:45.794', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('c8b7005f-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005e-1cd9-11ec-acd8-3ae4f1d3c3af', 'Event_1ouk8kj', NULL, NULL, NULL, 'startEvent', NULL, '2021-09-24 09:50:24.256', '2021-09-24 09:50:24.256', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('c8b70060-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005e-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_08lgvo0', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:50:24.256', '2021-09-24 09:50:24.256', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('c8b70061-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005e-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_08p9kng', 'c8b70062-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '录入', 'userTask', 'admin', '2021-09-24 09:50:24.256', '2021-09-24 09:50:24.273', 3, 17, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('c8b99877-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005e-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_0n45f5j', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:50:24.273', '2021-09-24 09:50:24.273', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('c8b9bf88-1cd9-11ec-acd8-3ae4f1d3c3af', 4, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005e-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_12olr01', 'c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '转办', 'userTask', 'leaderHR', '2021-09-24 09:50:24.274', '2021-09-24 09:51:06.959', 2, 42685, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('dd42d1d2-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', 'dd42d1d1-1cd8-11ec-acd8-3ae4f1d3c3af', '04daf3f805bc4e2898c586df4fdb97a9', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:43:49.230', '2021-09-24 09:43:49.230', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('dd42d1d3-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', 'dd42d1d1-1cd8-11ec-acd8-3ae4f1d3c3af', 'Event_12ajo3d', NULL, NULL, NULL, 'endEvent', NULL, '2021-09-24 09:43:49.230', '2021-09-24 09:43:49.230', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('e22af662-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005e-1cd9-11ec-acd8-3ae4f1d3c3af', 'Flow_1s8i9er', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:51:06.959', '2021-09-24 09:51:06.959', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('e22b1d73-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005e-1cd9-11ec-acd8-3ae4f1d3c3af', 'Event_0lzxnw8', NULL, NULL, NULL, 'endEvent', NULL, '2021-09-24 09:51:06.960', '2021-09-24 09:51:06.960', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('e7ad5c3f-1cd6-11ec-acd8-3ae4f1d3c3af', 1, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', 'Event_1c9ukkq', NULL, NULL, NULL, 'startEvent', NULL, '2021-09-24 09:29:47.712', '2021-09-24 09:29:47.717', 1, 5, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('e7ae6db0-1cd6-11ec-acd8-3ae4f1d3c3af', 1, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', 'Flow_05fy9wh', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:29:47.719', '2021-09-24 09:29:47.719', 2, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('e7ae94c1-1cd6-11ec-acd8-3ae4f1d3c3af', 2, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', 'Activity_0sc2yuf', 'e7b1c912-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, '请假录入', 'userTask', 'userD', '2021-09-24 09:29:47.720', '2021-09-24 09:29:47.780', 3, 60, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('e7b7e397-1cd6-11ec-acd8-3ae4f1d3c3af', 1, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', 'Flow_0pme0vr', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 09:29:47.781', '2021-09-24 09:29:47.781', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('e7b80aa8-1cd6-11ec-acd8-3ae4f1d3c3af', 3, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', 'Activity_1jw5u20', 'e7b80aa9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, '部门领导审批', 'userTask', 'leaderTJ', '2021-09-24 09:29:47.782', '2021-09-24 09:30:12.027', 2, 24245, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('f62d0f9f-1cd6-11ec-acd8-3ae4f1d3c3af', 1, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', 'Flow_1hbob37', NULL, NULL, '同意', 'sequenceFlow', NULL, '2021-09-24 09:30:12.037', '2021-09-24 09:30:12.037', 1, 0, NULL, ''); +INSERT INTO `ACT_HI_ACTINST` VALUES ('f62d36b0-1cd6-11ec-acd8-3ae4f1d3c3af', 3, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', 'Activity_0olxatv', 'f62d36b1-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'HR审批', 'userTask', 'userA', '2021-09-24 09:30:12.038', '2021-09-24 09:31:03.826', 2, 51788, NULL, ''); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_HI_ATTACHMENT +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_ATTACHMENT`; +CREATE TABLE `ACT_HI_ATTACHMENT` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `URL_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `CONTENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TIME_` datetime(3) DEFAULT NULL, + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_HI_COMMENT +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_COMMENT`; +CREATE TABLE `ACT_HI_COMMENT` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TIME_` datetime(3) NOT NULL, + `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ACTION_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `MESSAGE_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `FULL_MSG_` longblob, + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_HI_COMMENT +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_HI_COMMENT` VALUES ('15061845-1cd7-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:31:03.791', NULL, 'f62d36b1-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'userA_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('21b3123d-1cd8-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:38:34.554', NULL, '1757db49-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderTJ_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('27198e78-1cd9-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:45:53.111', NULL, '1b4488c4-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderTJ_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('303a3fae-1cd8-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:38:58.928', 'userD', '21b953d4-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'admin_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('32b29ca9-1cd9-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:46:12.569', NULL, '271e978f-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'admin_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('48797b5c-1cd7-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:32:30.111', NULL, '42054298-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderTJ_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('4fe76138-1cd8-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:39:52.072', 'userD', '3040cf64-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderTJ_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('5ba3a3f6-1cd7-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:33:02.264', 'userD', '487ef9a2-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leader_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('66c218a3-1cd9-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:47:39.912', NULL, '32b7097e-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderTJ2_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('72ea6d27-1d14-11ec-8336-3ae4f1d3c3af', 'event', '2021-09-24 16:50:20.616', NULL, '23032963-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderTJ_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('73bb4910-1cd8-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:40:52.181', NULL, '4fec915c-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderLaw_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('74bc484a-1cd9-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:48:03.362', NULL, '66c6d396-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderLaw_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('b1c60bc7-1cd9-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:49:45.767', NULL, '9f286bc3-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leader_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('d2ab382d-1cd9-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:50:40.956', 'userD', 'c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'admin_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('d2afa500-1cd9-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:50:40.985', 'userD', 'c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderHR_|_assignee', NULL); +INSERT INTO `ACT_HI_COMMENT` VALUES ('f6245d0d-1cd6-11ec-acd8-3ae4f1d3c3af', 'event', '2021-09-24 09:30:11.980', 'userD', 'e7b80aa9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'AddUserLink', 'leaderTJ_|_assignee', NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_HI_DETAIL +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_DETAIL`; +CREATE TABLE `ACT_HI_DETAIL` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ACT_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin NOT NULL, + `VAR_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REV_` int(11) DEFAULT NULL, + `TIME_` datetime(3) NOT NULL, + `BYTEARRAY_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `DOUBLE_` double DEFAULT NULL, + `LONG_` bigint(20) DEFAULT NULL, + `TEXT_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `TEXT2_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_HI_DETAIL_PROC_INST` (`PROC_INST_ID_`), + KEY `ACT_IDX_HI_DETAIL_ACT_INST` (`ACT_INST_ID_`), + KEY `ACT_IDX_HI_DETAIL_TIME` (`TIME_`), + KEY `ACT_IDX_HI_DETAIL_NAME` (`NAME_`), + KEY `ACT_IDX_HI_DETAIL_TASK_ID` (`TASK_ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_HI_ENTITYLINK +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_ENTITYLINK`; +CREATE TABLE `ACT_HI_ENTITYLINK` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `LINK_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` datetime(3) DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PARENT_ELEMENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REF_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REF_SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REF_SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ROOT_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ROOT_SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HIERARCHY_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_HI_ENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`,`LINK_TYPE_`), + KEY `ACT_IDX_HI_ENT_LNK_ROOT_SCOPE` (`ROOT_SCOPE_ID_`,`ROOT_SCOPE_TYPE_`,`LINK_TYPE_`), + KEY `ACT_IDX_HI_ENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`,`LINK_TYPE_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_HI_IDENTITYLINK +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_IDENTITYLINK`; +CREATE TABLE `ACT_HI_IDENTITYLINK` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `GROUP_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` datetime(3) DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_HI_IDENT_LNK_USER` (`USER_ID_`), + KEY `ACT_IDX_HI_IDENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_HI_IDENT_LNK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_HI_IDENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_HI_IDENT_LNK_TASK` (`TASK_ID_`), + KEY `ACT_IDX_HI_IDENT_LNK_PROCINST` (`PROC_INST_ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_HI_IDENTITYLINK +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('1505f133-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'userA', 'f62d36b1-1cd6-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:31:03.789', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('15061844-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userA', NULL, '2021-09-24 09:31:03.791', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('17547fda-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'starter', 'userD', NULL, '2021-09-24 09:38:17.157', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('1754a6f3-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'userD', '1754a6f2-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:38:17.158', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('1754a6f4-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:38:17.158', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('17576616-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:38:17.176', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('1758025a-1cd8-11ec-acd8-3ae4f1d3c3af', '1440964519391137792', 'candidate', NULL, '1757db49-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:38:17.180', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('1b41a385-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'starter', 'userD', NULL, '2021-09-24 09:45:33.241', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('1b41a38e-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'userD', '1b41a38d-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:45:33.241', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('1b41a38f-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:45:33.241', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('1b441391-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:45:33.258', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('1b4488c5-1cd9-11ec-acd8-3ae4f1d3c3af', '1440964519391137792', 'candidate', NULL, '1b4488c4-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:45:33.260', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('21b2eb2b-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderTJ', '1757db49-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:38:34.553', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('21b3123c-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leaderTJ', NULL, '2021-09-24 09:38:34.554', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('21b953d5-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'candidate', 'admin', '21b953d4-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:38:34.595', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('21b953d6-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'admin', NULL, '2021-09-24 09:38:34.596', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('21b97ae9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'admin', '21b97ae8-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:38:34.596', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('22f3c004-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'starter', 'userD', NULL, '2021-09-24 16:05:09.480', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('22fa76cd-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'assignee', 'userD', '22f9b37c-1d0e-11ec-8336-3ae4f1d3c3af', '2021-09-24 16:05:09.523', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('22fa9dde-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 16:05:09.524', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('23023f00-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 16:05:09.574', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('23035074-1d0e-11ec-8336-3ae4f1d3c3af', '1440964519391137792', 'candidate', NULL, '23032963-1d0e-11ec-8336-3ae4f1d3c3af', '2021-09-24 16:05:09.581', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('27196766-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderTJ', '1b4488c4-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:45:53.110', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('27198e77-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leaderTJ', NULL, '2021-09-24 09:45:53.111', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('271e9790-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'candidate', 'admin', '271e978f-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:45:53.144', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('271ebea1-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'admin', NULL, '2021-09-24 09:45:53.145', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('271ebea4-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'admin', '271ebea3-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:45:53.145', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('2c04371a-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:38:51.863', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('2ef91715-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:46:06.320', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('303a189d-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'admin', '21b953d4-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:38:58.927', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('30400c0f-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:38:58.966', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('3040cf65-1cd8-11ec-acd8-3ae4f1d3c3af', '1440964519395332096', 'candidate', NULL, '3040cf64-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:38:58.971', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('3040cf66-1cd8-11ec-acd8-3ae4f1d3c3af', '1440964519391137792', 'candidate', NULL, '3040cf64-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:38:58.971', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('32b27598-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'admin', '271e978f-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:46:12.568', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('32b7308f-1cd9-11ec-acd8-3ae4f1d3c3af', '1440964519395332096', 'candidate', NULL, '32b7097e-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:46:12.599', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('32b73090-1cd9-11ec-acd8-3ae4f1d3c3af', '1440964519391137792', 'candidate', NULL, '32b7097e-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:46:12.599', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('420171f9-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'starter', 'userD', NULL, '2021-09-24 09:32:19.258', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('42019912-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'userD', '42019911-1cd7-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:32:19.259', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('42019913-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:32:19.259', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('4204cd65-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:32:19.280', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('42054299-1cd7-11ec-acd8-3ae4f1d3c3af', '1440964519391137792', 'candidate', NULL, '42054298-1cd7-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:32:19.283', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('48792d3a-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderTJ', '42054298-1cd7-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:32:30.109', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('48797b5b-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leaderTJ', NULL, '2021-09-24 09:32:30.111', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('487f20b3-1cd7-11ec-acd8-3ae4f1d3c3af', '1440911410581213416', 'candidate', NULL, '487ef9a2-1cd7-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:32:30.148', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('4fe73a27-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderTJ', '3040cf64-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:39:52.071', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('4febf519-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:39:52.102', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('4fec915d-1cd8-11ec-acd8-3ae4f1d3c3af', '1440964387979399168', 'candidate', NULL, '4fec915c-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:39:52.106', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('5ba37ce4-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leader', '487ef9a2-1cd7-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:33:02.263', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('5ba3a3f5-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leader', NULL, '2021-09-24 09:33:02.264', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('5ba7c2a7-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:33:02.291', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('66c1f191-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderTJ2', '32b7097e-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:47:39.911', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('66c218a2-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leaderTJ2', NULL, '2021-09-24 09:47:39.912', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('66c6d397-1cd9-11ec-acd8-3ae4f1d3c3af', '1440964387979399168', 'candidate', NULL, '66c6d396-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:47:39.943', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('7138d67e-1d1d-11ec-8336-3ae4f1d3c3af', NULL, 'starter', 'userD', NULL, '2021-09-24 17:54:43.245', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('7138fd97-1d1d-11ec-8336-3ae4f1d3c3af', NULL, 'assignee', 'userD', '7138fd96-1d1d-11ec-8336-3ae4f1d3c3af', '2021-09-24 17:54:43.246', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('7138fd98-1d1d-11ec-8336-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 17:54:43.246', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('713d6a6a-1d1d-11ec-8336-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 17:54:43.275', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('713e06ae-1d1d-11ec-8336-3ae4f1d3c3af', '1440964519391137792', 'candidate', NULL, '713e06ad-1d1d-11ec-8336-3ae4f1d3c3af', '2021-09-24 17:54:43.279', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('719d8e5b-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'starter', 'userD', NULL, '2021-09-24 09:33:39.134', '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('72ea4615-1d14-11ec-8336-3ae4f1d3c3af', NULL, 'assignee', 'leaderTJ', '23032963-1d0e-11ec-8336-3ae4f1d3c3af', '2021-09-24 16:50:20.614', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('72ea6d26-1d14-11ec-8336-3ae4f1d3c3af', NULL, 'participant', 'leaderTJ', NULL, '2021-09-24 16:50:20.616', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('73bafaee-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderLaw', '4fec915c-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:40:52.179', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('73bb21ff-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leaderLaw', NULL, '2021-09-24 09:40:52.180', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('73c163a7-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'userB', '73c163a6-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:40:52.221', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('73c18ab8-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userB', NULL, '2021-09-24 09:40:52.222', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('73c18abc-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'userC', '73c18abb-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:40:52.222', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('73c18abd-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userC', NULL, '2021-09-24 09:40:52.222', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('73c18ac1-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderLaw', '73c18ac0-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:40:52.222', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('74bc2138-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderLaw', '66c6d396-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:48:03.361', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('74bc4849-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leaderLaw', NULL, '2021-09-24 09:48:03.362', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('74c12a5f-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderLaw', '74c12a5e-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:48:03.394', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('74c15173-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'userC', '74c15172-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:48:03.395', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('74c15174-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userC', NULL, '2021-09-24 09:48:03.395', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('7a4309f8-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'admin', '7a4309f7-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:41:03.137', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('8b4134bb-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'userB', '8b4134ba-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:48:41.143', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('8b415bcc-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userB', NULL, '2021-09-24 09:48:41.144', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('9f26e51d-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:49:14.525', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('9f2892d4-1cd9-11ec-acd8-3ae4f1d3c3af', '1440911410581213416', 'candidate', NULL, '9f286bc3-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:49:14.536', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('a4cd8ab9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:42:14.509', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('b1c5bda5-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leader', '9f286bc3-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:49:45.765', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('b1c60bc6-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leader', NULL, '2021-09-24 09:49:45.767', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('c8b7005b-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'starter', 'admin', NULL, '2021-09-24 09:50:24.256', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('c8b72773-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'admin', 'c8b70062-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:50:24.257', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('c8b72774-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'admin', NULL, '2021-09-24 09:50:24.257', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('c8b94a56-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'admin', NULL, '2021-09-24 09:50:24.271', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('c8b9bf8a-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'candidate', 'admin', 'c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:50:24.274', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('c8b9bf8b-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'candidate', 'admin', 'c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:50:24.274', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('d2ab111c-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'admin', 'c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:50:40.955', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('d2af56de-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderHR', 'c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:50:40.983', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('d2afa4ff-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leaderHR', NULL, '2021-09-24 09:50:40.985', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('e22a8131-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:51:06.956', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('e7ac98ea-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'starter', 'userD', NULL, '2021-09-24 09:29:47.708', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('e7b26553-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'userD', 'e7b1c912-1cd6-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:29:47.745', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('e7b26554-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:29:47.745', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('e7b72046-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:29:47.776', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('e7b80aaa-1cd6-11ec-acd8-3ae4f1d3c3af', '1440964519391137792', 'candidate', NULL, 'e7b80aa9-1cd6-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:29:47.782', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('f62435fb-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'leaderTJ', 'e7b80aa9-1cd6-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:30:11.979', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('f6245d0c-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'leaderTJ', NULL, '2021-09-24 09:30:11.980', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('f62aecbe-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'participant', 'userD', NULL, '2021-09-24 09:30:12.023', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_IDENTITYLINK` VALUES ('f62d36b2-1cd6-11ec-acd8-3ae4f1d3c3af', '1440964221855600640', 'candidate', NULL, 'f62d36b1-1cd6-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:30:12.038', NULL, NULL, NULL, NULL, NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_HI_PROCINST +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_PROCINST`; +CREATE TABLE `ACT_HI_PROCINST` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT '1', + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `BUSINESS_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `START_TIME_` datetime(3) NOT NULL, + `END_TIME_` datetime(3) DEFAULT NULL, + `DURATION_` bigint(20) DEFAULT NULL, + `START_USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `START_ACT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `END_ACT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUPER_PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `DELETE_REASON_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CALLBACK_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CALLBACK_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REFERENCE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REFERENCE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + UNIQUE KEY `PROC_INST_ID_` (`PROC_INST_ID_`), + KEY `ACT_IDX_HI_PRO_INST_END` (`END_TIME_`), + KEY `ACT_IDX_HI_PRO_I_BUSKEY` (`BUSINESS_KEY_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_HI_PROCINST +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_HI_PROCINST` VALUES ('17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', 2, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '1441215377508929536', 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:38:17.157', '2021-09-24 09:43:49.235', 332078, 'userD', 'Event_1psmisd', 'Event_12ajo3d', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_PROCINST` VALUES ('1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', 2, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1441217206602960896', 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '2021-09-24 09:45:33.241', '2021-09-24 09:49:45.799', 252558, 'userD', 'Event_1psmisd', 'Event_12ajo3d', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_PROCINST` VALUES ('22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', 2, '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '1441312736167333888', 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '2021-09-24 16:05:09.478', '2021-09-24 16:50:20.693', 2711215, 'userD', 'Event_17n2rw9', 'Event_0nvjxgh', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_PROCINST` VALUES ('420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', 2, '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '1441213876367527936', 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '2021-09-24 09:32:19.258', '2021-09-24 09:33:02.300', 43042, 'userD', 'Event_17n2rw9', 'Event_0nvjxgh', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_PROCINST` VALUES ('7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', 1, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '1441340309442138112', 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '2021-09-24 17:54:43.245', NULL, NULL, 'userD', 'Event_17n2rw9', NULL, NULL, NULL, '', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_PROCINST` VALUES ('719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', 2, '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', '2021-09-24 09:33:39.134', '2021-09-24 09:34:08.597', 29463, 'userD', 'Event_1psmisd', 'Event_12ajo3d', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_PROCINST` VALUES ('c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', '1441218427220922368', 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', '2021-09-24 09:50:24.256', '2021-09-24 09:51:06.964', 42708, 'admin', 'Event_1ouk8kj', 'Event_0lzxnw8', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_HI_PROCINST` VALUES ('e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 2, 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', '1441213240326492160', 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', '2021-09-24 09:29:47.706', '2021-09-24 09:31:03.843', 76137, 'userD', 'Event_1c9ukkq', 'Event_04byxr7', NULL, NULL, '', NULL, NULL, NULL, NULL, NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_HI_TASKINST +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_TASKINST`; +CREATE TABLE `ACT_HI_TASKINST` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT '1', + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TASK_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TASK_DEF_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PROPAGATED_STAGE_INST_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PARENT_TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ASSIGNEE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `START_TIME_` datetime(3) NOT NULL, + `CLAIM_TIME_` datetime(3) DEFAULT NULL, + `END_TIME_` datetime(3) DEFAULT NULL, + `DURATION_` bigint(20) DEFAULT NULL, + `DELETE_REASON_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `PRIORITY_` int(11) DEFAULT NULL, + `DUE_DATE_` datetime(3) DEFAULT NULL, + `FORM_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + `LAST_UPDATED_TIME_` datetime(3) DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_HI_TASK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_HI_TASK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_HI_TASK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_HI_TASK_INST_PROCINST` (`PROC_INST_ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_HI_TASKINST +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_HI_TASKINST` VALUES ('1754a6f2-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_0nyla1r', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '合同录入', NULL, NULL, NULL, 'userD', '2021-09-24 09:38:17.157', NULL, '2021-09-24 09:38:17.177', 20, NULL, 50, NULL, '{\"formId\":\"1440954920348946432\",\"readOnly\":false,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:38:17.177'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('1757db49-1cd8-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_1ucrh52', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '业务部领导审批', NULL, NULL, NULL, 'leaderTJ', '2021-09-24 09:38:17.179', '2021-09-24 09:38:34.551', '2021-09-24 09:38:34.590', 17411, NULL, 50, NULL, '{\"formId\":\"1440954920348946432\",\"readOnly\":true,\"groupType\":\"DEPT_POST_LEADER\"}', NULL, '', '2021-09-24 09:38:34.590'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('1b41a38d-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_0nyla1r', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '合同录入', NULL, NULL, NULL, 'userD', '2021-09-24 09:45:33.241', NULL, '2021-09-24 09:45:33.258', 17, NULL, 50, NULL, '{\"formId\":\"1440954920348946432\",\"readOnly\":false,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:45:33.258'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('1b4488c4-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_1ucrh52', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '业务部领导审批', NULL, NULL, NULL, 'leaderTJ', '2021-09-24 09:45:33.260', '2021-09-24 09:45:53.107', '2021-09-24 09:45:53.140', 19880, NULL, 50, NULL, '{\"formId\":\"1440954920348946432\",\"readOnly\":true,\"groupType\":\"DEPT_POST_LEADER\"}', NULL, '', '2021-09-24 09:45:53.140'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('21b953d4-1cd8-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_138m4nn', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '工程部审批', NULL, NULL, NULL, 'admin', '2021-09-24 09:38:34.595', '2021-09-24 09:38:58.922', '2021-09-24 09:38:58.967', 24372, NULL, 50, NULL, '{\"formId\":\"1440955194991972352\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:38:58.967'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('21b97ae8-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_0tm3mph', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '21b92cc0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '造价部审批', NULL, NULL, NULL, 'admin', '2021-09-24 09:38:34.596', NULL, '2021-09-24 09:38:51.863', 17267, NULL, 50, NULL, '{\"formId\":\"1440955194991972352\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:38:51.863'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('22f9b37c-1d0e-11ec-8336-3ae4f1d3c3af', 2, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_03kjurt', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '报销单录入', NULL, NULL, NULL, 'userD', '2021-09-24 16:05:09.494', NULL, '2021-09-24 16:05:09.575', 81, NULL, 50, NULL, '{\"formId\":\"1440947675041107968\",\"readOnly\":false,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 16:05:09.575'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('23032963-1d0e-11ec-8336-3ae4f1d3c3af', 3, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_0ywxfwu', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f45c48-1d0e-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '部门领导审批', NULL, NULL, NULL, 'leaderTJ', '2021-09-24 16:05:09.580', '2021-09-24 16:50:20.612', '2021-09-24 16:50:20.665', 2711085, NULL, 50, NULL, '{\"formId\":\"1440947675041107968\",\"readOnly\":true,\"groupType\":\"DEPT_POST_LEADER\"}', NULL, '', '2021-09-24 16:50:20.665'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('271e978f-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_138m4nn', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '工程部审批', NULL, NULL, NULL, 'admin', '2021-09-24 09:45:53.144', '2021-09-24 09:46:12.565', '2021-09-24 09:46:12.595', 19451, NULL, 50, NULL, '{\"formId\":\"1440955194991972352\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:46:12.595'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('271ebea3-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_0tm3mph', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '271e978b-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '造价部审批', NULL, NULL, NULL, 'admin', '2021-09-24 09:45:53.145', NULL, '2021-09-24 09:46:06.321', 13176, NULL, 50, NULL, '{\"formId\":\"1440955194991972352\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:46:06.321'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('3040cf64-1cd8-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_1yuuyie', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '财务部审批', NULL, NULL, NULL, 'leaderTJ', '2021-09-24 09:38:58.971', '2021-09-24 09:39:52.069', '2021-09-24 09:39:52.103', 53132, NULL, 50, NULL, '{\"formId\":\"1440955127790833664\",\"readOnly\":true,\"groupType\":\"POST\"}', NULL, '', '2021-09-24 09:39:52.103'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('32b7097e-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_1yuuyie', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '财务部审批', NULL, NULL, NULL, 'leaderTJ2', '2021-09-24 09:46:12.598', '2021-09-24 09:47:39.909', '2021-09-24 09:47:39.940', 87342, NULL, 50, NULL, '{\"formId\":\"1440955127790833664\",\"readOnly\":true,\"groupType\":\"POST\"}', NULL, '', '2021-09-24 09:47:39.940'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('42019911-1cd7-11ec-acd8-3ae4f1d3c3af', 2, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_03kjurt', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '报销单录入', NULL, NULL, NULL, 'userD', '2021-09-24 09:32:19.258', NULL, '2021-09-24 09:32:19.280', 22, NULL, 50, NULL, '{\"formId\":\"1440947675041107968\",\"readOnly\":false,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:32:19.280'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('42054298-1cd7-11ec-acd8-3ae4f1d3c3af', 3, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_0ywxfwu', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '部门领导审批', NULL, NULL, NULL, 'leaderTJ', '2021-09-24 09:32:19.283', '2021-09-24 09:32:30.107', '2021-09-24 09:32:30.143', 10860, NULL, 50, NULL, '{\"formId\":\"1440947675041107968\",\"readOnly\":true,\"groupType\":\"DEPT_POST_LEADER\"}', NULL, '', '2021-09-24 09:32:30.143'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('487ef9a2-1cd7-11ec-acd8-3ae4f1d3c3af', 3, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_0qay48u', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171fd-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '总经理审批', NULL, NULL, NULL, 'leader', '2021-09-24 09:32:30.147', '2021-09-24 09:33:02.260', '2021-09-24 09:33:02.292', 32145, NULL, 50, NULL, '{\"formId\":\"1440947675041107968\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:33:02.292'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('4fec915c-1cd8-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_1eewt01', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fde-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '法务部审批', NULL, NULL, NULL, 'leaderLaw', '2021-09-24 09:39:52.106', '2021-09-24 09:40:52.177', '2021-09-24 09:40:52.215', 60109, NULL, 50, NULL, '{\"formId\":\"1440955001093492736\",\"readOnly\":true,\"groupType\":\"POST\"}', NULL, '', '2021-09-24 09:40:52.215'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('66c6d396-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_1eewt01', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a389-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '法务部审批', NULL, NULL, NULL, 'leaderLaw', '2021-09-24 09:47:39.943', '2021-09-24 09:48:03.359', '2021-09-24 09:48:03.390', 23447, NULL, 50, NULL, '{\"formId\":\"1440955001093492736\",\"readOnly\":true,\"groupType\":\"POST\"}', NULL, '', '2021-09-24 09:48:03.390'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('7138fd96-1d1d-11ec-8336-3ae4f1d3c3af', 2, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_03kjurt', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '报销单录入', NULL, NULL, NULL, 'userD', '2021-09-24 17:54:43.246', NULL, '2021-09-24 17:54:43.276', 30, NULL, 50, NULL, '{\"formId\":\"1440947675041107968\",\"readOnly\":false,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 17:54:43.276'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('713e06ad-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_0ywxfwu', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '部门领导审批', NULL, NULL, NULL, NULL, '2021-09-24 17:54:43.278', NULL, NULL, NULL, NULL, 50, NULL, '{\"formId\":\"1440947675041107968\",\"readOnly\":true,\"groupType\":\"DEPT_POST_LEADER\"}', NULL, '', '2021-09-24 17:54:43.279'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('719d8e62-1cd7-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_0nyla1r', '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', '719d8e5e-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '合同录入', NULL, NULL, NULL, NULL, '2021-09-24 09:33:39.134', NULL, '2021-09-24 09:34:08.586', 29452, NULL, 50, NULL, '{\"formId\":\"1440954920348946432\",\"readOnly\":false,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:34:08.586'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('73c163a6-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_098ncvw', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c1157e-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '法务部会签', NULL, NULL, NULL, 'userB', '2021-09-24 09:40:52.221', NULL, '2021-09-24 09:41:55.359', 63138, NULL, 50, NULL, '{\"formId\":\"1440955001093492736\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:41:55.359'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('73c18abb-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_098ncvw', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c13c8f-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '法务部会签', NULL, NULL, NULL, 'userC', '2021-09-24 09:40:52.222', NULL, '2021-09-24 09:42:14.510', 82288, NULL, 50, NULL, '{\"formId\":\"1440955001093492736\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:42:14.510'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('73c18ac0-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_098ncvw', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c13c90-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '法务部会签', NULL, NULL, NULL, 'leaderLaw', '2021-09-24 09:40:52.222', NULL, '2021-09-24 09:41:36.318', 44096, NULL, 50, NULL, '{\"formId\":\"1440955001093492736\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:41:36.318'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('74c12a5e-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_098ncvw', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10348-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '法务部会签', NULL, NULL, NULL, 'leaderLaw', '2021-09-24 09:48:03.394', NULL, '2021-09-24 09:48:12.063', 8669, NULL, 50, NULL, '{\"formId\":\"1440955001093492736\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:48:12.063'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('74c15172-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_098ncvw', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10349-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '法务部会签', NULL, NULL, NULL, 'userC', '2021-09-24 09:48:03.395', NULL, '2021-09-24 09:49:14.526', 71131, NULL, 50, NULL, '{\"formId\":\"1440955001093492736\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:49:14.526'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('7a4309f7-1cd8-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_098ncvw', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '7a4294c2-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '法务部会签', NULL, NULL, NULL, 'admin', '2021-09-24 09:41:03.137', NULL, '2021-09-24 09:43:49.214', 166077, NULL, 50, NULL, '{\"formId\":\"1440955001093492736\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:43:49.214'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('8b4134ba-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_098ncvw', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '8b410da5-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '法务部会签', NULL, NULL, NULL, 'userB', '2021-09-24 09:48:41.143', NULL, '2021-09-24 09:48:54.253', 13110, NULL, 50, NULL, '{\"formId\":\"1440955001093492736\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:48:54.253'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('9f286bc3-1cd9-11ec-acd8-3ae4f1d3c3af', 3, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'Activity_1h3pnxy', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '9f2844ae-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '总经理审批', NULL, NULL, NULL, 'leader', '2021-09-24 09:49:14.535', '2021-09-24 09:49:45.763', '2021-09-24 09:49:45.792', 31257, NULL, 50, NULL, '{\"formId\":\"1440954920348946432\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:49:45.792'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('c8b70062-1cd9-11ec-acd8-3ae4f1d3c3af', 2, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_08p9kng', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005e-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '录入', NULL, NULL, NULL, 'admin', '2021-09-24 09:50:24.256', NULL, '2021-09-24 09:50:24.272', 16, NULL, 50, NULL, '{\"formId\":\"1440945411354267648\",\"readOnly\":false,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:50:24.272'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', 4, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', NULL, 'Activity_12olr01', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005e-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '转办', NULL, NULL, NULL, 'leaderHR', '2021-09-24 09:50:24.274', '2021-09-24 09:50:40.953', '2021-09-24 09:51:06.958', 42684, NULL, 50, NULL, '{\"formId\":\"1440945411354267648\",\"readOnly\":true,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:51:06.958'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('e7b1c912-1cd6-11ec-acd8-3ae4f1d3c3af', 2, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', NULL, 'Activity_0sc2yuf', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '请假录入', NULL, NULL, NULL, 'userD', '2021-09-24 09:29:47.720', NULL, '2021-09-24 09:29:47.777', 57, NULL, 50, NULL, '{\"formId\":\"1440945411354267648\",\"readOnly\":false,\"groupType\":\"DEPT\"}', NULL, '', '2021-09-24 09:29:47.777'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('e7b80aa9-1cd6-11ec-acd8-3ae4f1d3c3af', 3, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', NULL, 'Activity_1jw5u20', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, '部门领导审批', NULL, NULL, NULL, 'leaderTJ', '2021-09-24 09:29:47.782', '2021-09-24 09:30:11.977', '2021-09-24 09:30:12.026', 24244, NULL, 50, NULL, '{\"formId\":\"1440945411354267648\",\"readOnly\":true,\"groupType\":\"DEPT_POST_LEADER\"}', NULL, '', '2021-09-24 09:30:12.026'); +INSERT INTO `ACT_HI_TASKINST` VALUES ('f62d36b1-1cd6-11ec-acd8-3ae4f1d3c3af', 3, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', NULL, 'Activity_0olxatv', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ad5c3e-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, 'HR审批', NULL, NULL, NULL, 'userA', '2021-09-24 09:30:12.038', '2021-09-24 09:31:03.787', '2021-09-24 09:31:03.825', 51787, NULL, 50, NULL, '{\"formId\":\"1440945411354267648\",\"readOnly\":true,\"groupType\":\"POST\"}', NULL, '', '2021-09-24 09:31:03.825'); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_HI_TSK_LOG +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_TSK_LOG`; +CREATE TABLE `ACT_HI_TSK_LOG` ( + `ID_` bigint(20) NOT NULL AUTO_INCREMENT, + `TYPE_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `TIME_STAMP_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `DATA_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_HI_VARINST +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_HI_VARINST`; +CREATE TABLE `ACT_HI_VARINST` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT '1', + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin NOT NULL, + `VAR_TYPE_` varchar(100) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `BYTEARRAY_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `DOUBLE_` double DEFAULT NULL, + `LONG_` bigint(20) DEFAULT NULL, + `TEXT_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `TEXT2_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` datetime(3) DEFAULT NULL, + `LAST_UPDATED_TIME_` datetime(3) DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_HI_PROCVAR_NAME_TYPE` (`NAME_`,`VAR_TYPE_`), + KEY `ACT_IDX_HI_VAR_SCOPE_ID_TYPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_HI_VAR_SUB_ID_TYPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_HI_PROCVAR_PROC_INST` (`PROC_INST_ID_`), + KEY `ACT_IDX_HI_PROCVAR_TASK_ID` (`TASK_ID_`), + KEY `ACT_IDX_HI_PROCVAR_EXE` (`EXECUTION_ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_HI_VARINST +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_HI_VARINST` VALUES ('17547fdb-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'startUserName', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:38:17.157', '2021-09-24 09:38:17.157'); +INSERT INTO `ACT_HI_VARINST` VALUES ('17547fdc-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'deptPostLeader', 'long', NULL, NULL, NULL, NULL, NULL, 1440964519391137792, '1440964519391137792', NULL, '2021-09-24 09:38:17.157', '2021-09-24 09:38:17.157'); +INSERT INTO `ACT_HI_VARINST` VALUES ('17547fdd-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'initiator', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:38:17.157', '2021-09-24 09:38:17.157'); +INSERT INTO `ACT_HI_VARINST` VALUES ('17576615-1cd8-11ec-acd8-3ae4f1d3c3af', 8, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'operationType', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'multi_agree', NULL, '2021-09-24 09:38:17.176', '2021-09-24 09:42:14.508'); +INSERT INTO `ACT_HI_VARINST` VALUES ('1b41a386-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'startUserName', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:45:33.241', '2021-09-24 09:45:33.241'); +INSERT INTO `ACT_HI_VARINST` VALUES ('1b41a387-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'deptPostLeader', 'long', NULL, NULL, NULL, NULL, NULL, 1440964519391137792, '1440964519391137792', NULL, '2021-09-24 09:45:33.241', '2021-09-24 09:45:33.241'); +INSERT INTO `ACT_HI_VARINST` VALUES ('1b41a388-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'initiator', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:45:33.241', '2021-09-24 09:45:33.241'); +INSERT INTO `ACT_HI_VARINST` VALUES ('1b441390-1cd9-11ec-acd8-3ae4f1d3c3af', 9, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'operationType', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'agree', NULL, '2021-09-24 09:45:33.257', '2021-09-24 09:49:45.791'); +INSERT INTO `ACT_HI_VARINST` VALUES ('22f40e25-1d0e-11ec-8336-3ae4f1d3c3af', 0, '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'startUserName', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 16:05:09.482', '2021-09-24 16:05:09.482'); +INSERT INTO `ACT_HI_VARINST` VALUES ('22f45c46-1d0e-11ec-8336-3ae4f1d3c3af', 0, '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'deptPostLeader', 'long', NULL, NULL, NULL, NULL, NULL, 1440964519391137792, '1440964519391137792', NULL, '2021-09-24 16:05:09.483', '2021-09-24 16:05:09.483'); +INSERT INTO `ACT_HI_VARINST` VALUES ('22f45c47-1d0e-11ec-8336-3ae4f1d3c3af', 0, '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'initiator', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 16:05:09.483', '2021-09-24 16:05:09.483'); +INSERT INTO `ACT_HI_VARINST` VALUES ('230217ef-1d0e-11ec-8336-3ae4f1d3c3af', 1, '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'operationType', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'agree', NULL, '2021-09-24 16:05:09.574', '2021-09-24 16:50:20.663'); +INSERT INTO `ACT_HI_VARINST` VALUES ('420171fa-1cd7-11ec-acd8-3ae4f1d3c3af', 0, '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'startUserName', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:32:19.258', '2021-09-24 09:32:19.258'); +INSERT INTO `ACT_HI_VARINST` VALUES ('420171fb-1cd7-11ec-acd8-3ae4f1d3c3af', 0, '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'deptPostLeader', 'long', NULL, NULL, NULL, NULL, NULL, 1440964519391137792, '1440964519391137792', NULL, '2021-09-24 09:32:19.258', '2021-09-24 09:32:19.258'); +INSERT INTO `ACT_HI_VARINST` VALUES ('420171fc-1cd7-11ec-acd8-3ae4f1d3c3af', 0, '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'initiator', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:32:19.258', '2021-09-24 09:32:19.258'); +INSERT INTO `ACT_HI_VARINST` VALUES ('4204cd64-1cd7-11ec-acd8-3ae4f1d3c3af', 2, '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'operationType', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'agree', NULL, '2021-09-24 09:32:19.280', '2021-09-24 09:33:02.290'); +INSERT INTO `ACT_HI_VARINST` VALUES ('487e364d-1cd7-11ec-acd8-3ae4f1d3c3af', 0, '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'totalAmount', 'integer', NULL, NULL, NULL, NULL, NULL, 1200, '1200', NULL, '2021-09-24 09:32:30.142', '2021-09-24 09:32:30.142'); +INSERT INTO `ACT_HI_VARINST` VALUES ('7138d67f-1d1d-11ec-8336-3ae4f1d3c3af', 0, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, 'startUserName', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 17:54:43.245', '2021-09-24 17:54:43.245'); +INSERT INTO `ACT_HI_VARINST` VALUES ('7138d680-1d1d-11ec-8336-3ae4f1d3c3af', 0, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, 'deptPostLeader', 'long', NULL, NULL, NULL, NULL, NULL, 1440964519391137792, '1440964519391137792', NULL, '2021-09-24 17:54:43.245', '2021-09-24 17:54:43.245'); +INSERT INTO `ACT_HI_VARINST` VALUES ('7138d681-1d1d-11ec-8336-3ae4f1d3c3af', 0, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, 'initiator', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 17:54:43.245', '2021-09-24 17:54:43.245'); +INSERT INTO `ACT_HI_VARINST` VALUES ('713d6a69-1d1d-11ec-8336-3ae4f1d3c3af', 0, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, 'operationType', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'agree', NULL, '2021-09-24 17:54:43.275', '2021-09-24 17:54:43.275'); +INSERT INTO `ACT_HI_VARINST` VALUES ('719d8e5c-1cd7-11ec-acd8-3ae4f1d3c3af', 0, '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'startUserName', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:33:39.134', '2021-09-24 09:33:39.134'); +INSERT INTO `ACT_HI_VARINST` VALUES ('719d8e5d-1cd7-11ec-acd8-3ae4f1d3c3af', 0, '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', NULL, 'initiator', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:33:39.134', '2021-09-24 09:33:39.134'); +INSERT INTO `ACT_HI_VARINST` VALUES ('72f19918-1d14-11ec-8336-3ae4f1d3c3af', 0, '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', NULL, 'totalAmount', 'integer', NULL, NULL, NULL, NULL, NULL, 800, '800', NULL, '2021-09-24 16:50:20.663', '2021-09-24 16:50:20.663'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73bfb5e1-1cd8-11ec-acd8-3ae4f1d3c3af', 3, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'multiRefuseCount', 'integer', NULL, NULL, NULL, NULL, NULL, 1, '1', NULL, '2021-09-24 09:40:52.210', '2021-09-24 09:42:14.508'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c02b13-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assigneeList', 'serializable', NULL, NULL, NULL, '73c05224-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, '2021-09-24 09:40:52.213', '2021-09-24 09:40:52.213'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c05225-1cd8-11ec-acd8-3ae4f1d3c3af', 3, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'multiAbstainCount', 'integer', NULL, NULL, NULL, NULL, NULL, 0, '0', NULL, '2021-09-24 09:40:52.214', '2021-09-24 09:42:14.508'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c05226-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'multiSignStartTask', 'string', NULL, NULL, NULL, NULL, NULL, NULL, '4fec915c-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '2021-09-24 09:40:52.214', '2021-09-24 09:40:52.214'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c05227-1cd8-11ec-acd8-3ae4f1d3c3af', 3, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'multiAgreeCount', 'integer', NULL, NULL, NULL, NULL, NULL, 2, '2', NULL, '2021-09-24 09:40:52.214', '2021-09-24 09:42:14.508'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c05228-1cd8-11ec-acd8-3ae4f1d3c3af', 3, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'multiNumOfInstances', 'integer', NULL, NULL, NULL, NULL, NULL, 4, '4', NULL, '2021-09-24 09:40:52.214', '2021-09-24 09:42:14.509'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c1157b-1cd8-11ec-acd8-3ae4f1d3c3af', 1, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c0ee6a-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'nrOfInstances', 'integer', NULL, NULL, NULL, NULL, NULL, 4, '4', NULL, '2021-09-24 09:40:52.219', '2021-09-24 09:41:03.135'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c1157c-1cd8-11ec-acd8-3ae4f1d3c3af', 4, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c0ee6a-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'nrOfCompletedInstances', 'integer', NULL, NULL, NULL, NULL, NULL, 4, '4', NULL, '2021-09-24 09:40:52.219', '2021-09-24 09:43:49.220'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c1157d-1cd8-11ec-acd8-3ae4f1d3c3af', 4, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c0ee6a-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'nrOfActiveInstances', 'integer', NULL, NULL, NULL, NULL, NULL, -1, '-1', NULL, '2021-09-24 09:40:52.219', '2021-09-24 09:43:49.220'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c13c91-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c1157e-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userB', NULL, '2021-09-24 09:40:52.220', '2021-09-24 09:40:52.220'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c13c92-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c13c8f-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userC', NULL, '2021-09-24 09:40:52.221', '2021-09-24 09:40:52.221'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c163a3-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c13c90-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'leaderLaw', NULL, '2021-09-24 09:40:52.221', '2021-09-24 09:40:52.221'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c163a4-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c1157e-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'loopCounter', 'integer', NULL, NULL, NULL, NULL, NULL, 0, '0', NULL, '2021-09-24 09:40:52.221', '2021-09-24 09:40:52.221'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c18ab9-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c13c8f-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'loopCounter', 'integer', NULL, NULL, NULL, NULL, NULL, 1, '1', NULL, '2021-09-24 09:40:52.222', '2021-09-24 09:40:52.222'); +INSERT INTO `ACT_HI_VARINST` VALUES ('73c18abe-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c13c90-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'loopCounter', 'integer', NULL, NULL, NULL, NULL, NULL, 2, '2', NULL, '2021-09-24 09:40:52.222', '2021-09-24 09:40:52.222'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c066fb-1cd9-11ec-acd8-3ae4f1d3c3af', 3, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'multiRefuseCount', 'integer', NULL, NULL, NULL, NULL, NULL, 0, '0', NULL, '2021-09-24 09:48:03.389', '2021-09-24 09:49:14.524'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c066fd-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assigneeList', 'serializable', NULL, NULL, NULL, '74c066fe-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, NULL, NULL, NULL, '2021-09-24 09:48:03.389', '2021-09-24 09:48:03.389'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c066ff-1cd9-11ec-acd8-3ae4f1d3c3af', 3, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'multiAbstainCount', 'integer', NULL, NULL, NULL, NULL, NULL, 0, '0', NULL, '2021-09-24 09:48:03.389', '2021-09-24 09:49:14.524'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c08e10-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'multiSignStartTask', 'string', NULL, NULL, NULL, NULL, NULL, NULL, '66c6d396-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '2021-09-24 09:48:03.390', '2021-09-24 09:48:03.390'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c08e11-1cd9-11ec-acd8-3ae4f1d3c3af', 3, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'multiAgreeCount', 'integer', NULL, NULL, NULL, NULL, NULL, 3, '3', NULL, '2021-09-24 09:48:03.390', '2021-09-24 09:49:14.524'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c08e12-1cd9-11ec-acd8-3ae4f1d3c3af', 3, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'multiNumOfInstances', 'integer', NULL, NULL, NULL, NULL, NULL, 3, '3', NULL, '2021-09-24 09:48:03.390', '2021-09-24 09:49:14.525'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c10345-1cd9-11ec-acd8-3ae4f1d3c3af', 1, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10344-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'nrOfInstances', 'integer', NULL, NULL, NULL, NULL, NULL, 3, '3', NULL, '2021-09-24 09:48:03.393', '2021-09-24 09:48:41.142'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c10346-1cd9-11ec-acd8-3ae4f1d3c3af', 3, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10344-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'nrOfCompletedInstances', 'integer', NULL, NULL, NULL, NULL, NULL, 3, '3', NULL, '2021-09-24 09:48:03.393', '2021-09-24 09:49:14.527'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c10347-1cd9-11ec-acd8-3ae4f1d3c3af', 3, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10344-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'nrOfActiveInstances', 'integer', NULL, NULL, NULL, NULL, NULL, -1, '-1', NULL, '2021-09-24 09:48:03.393', '2021-09-24 09:49:14.527'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c1034a-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10348-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'leaderLaw', NULL, '2021-09-24 09:48:03.393', '2021-09-24 09:48:03.393'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c12a5b-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10349-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userC', NULL, '2021-09-24 09:48:03.394', '2021-09-24 09:48:03.394'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c12a5c-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10348-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'loopCounter', 'integer', NULL, NULL, NULL, NULL, NULL, 0, '0', NULL, '2021-09-24 09:48:03.394', '2021-09-24 09:48:03.394'); +INSERT INTO `ACT_HI_VARINST` VALUES ('74c12a60-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c10349-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'loopCounter', 'integer', NULL, NULL, NULL, NULL, NULL, 1, '1', NULL, '2021-09-24 09:48:03.394', '2021-09-24 09:48:03.394'); +INSERT INTO `ACT_HI_VARINST` VALUES ('7a4309f3-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '7a4294c2-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'multiSignStartTask', 'string', NULL, NULL, NULL, NULL, NULL, NULL, '4fec915c-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, '2021-09-24 09:41:03.137', '2021-09-24 09:41:03.137'); +INSERT INTO `ACT_HI_VARINST` VALUES ('7a4309f4-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '7a4294c2-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'admin', NULL, '2021-09-24 09:41:03.137', '2021-09-24 09:41:03.137'); +INSERT INTO `ACT_HI_VARINST` VALUES ('7a4309f5-1cd8-11ec-acd8-3ae4f1d3c3af', 0, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '7a4294c2-1cd8-11ec-acd8-3ae4f1d3c3af', NULL, 'loopCounter', 'integer', NULL, NULL, NULL, NULL, NULL, 3, '3', NULL, '2021-09-24 09:41:03.137', '2021-09-24 09:41:03.137'); +INSERT INTO `ACT_HI_VARINST` VALUES ('8b4134b6-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '8b410da5-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'multiSignStartTask', 'string', NULL, NULL, NULL, NULL, NULL, NULL, '66c6d396-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, '2021-09-24 09:48:41.143', '2021-09-24 09:48:41.143'); +INSERT INTO `ACT_HI_VARINST` VALUES ('8b4134b7-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '8b410da5-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'assignee', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userB', NULL, '2021-09-24 09:48:41.143', '2021-09-24 09:48:41.143'); +INSERT INTO `ACT_HI_VARINST` VALUES ('8b4134b8-1cd9-11ec-acd8-3ae4f1d3c3af', 0, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '8b410da5-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'loopCounter', 'integer', NULL, NULL, NULL, NULL, NULL, 2, '2', NULL, '2021-09-24 09:48:41.143', '2021-09-24 09:48:41.143'); +INSERT INTO `ACT_HI_VARINST` VALUES ('c8b7005c-1cd9-11ec-acd8-3ae4f1d3c3af', 0, 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'startUserName', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'admin', NULL, '2021-09-24 09:50:24.256', '2021-09-24 09:50:24.256'); +INSERT INTO `ACT_HI_VARINST` VALUES ('c8b7005d-1cd9-11ec-acd8-3ae4f1d3c3af', 0, 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'initiator', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'admin', NULL, '2021-09-24 09:50:24.256', '2021-09-24 09:50:24.256'); +INSERT INTO `ACT_HI_VARINST` VALUES ('c8b94a55-1cd9-11ec-acd8-3ae4f1d3c3af', 1, 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', NULL, 'operationType', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'agree', NULL, '2021-09-24 09:50:24.271', '2021-09-24 09:51:06.956'); +INSERT INTO `ACT_HI_VARINST` VALUES ('e7ace70b-1cd6-11ec-acd8-3ae4f1d3c3af', 0, 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'startUserName', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:29:47.711', '2021-09-24 09:29:47.711'); +INSERT INTO `ACT_HI_VARINST` VALUES ('e7ad352c-1cd6-11ec-acd8-3ae4f1d3c3af', 0, 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'deptPostLeader', 'long', NULL, NULL, NULL, NULL, NULL, 1440964519391137792, '1440964519391137792', NULL, '2021-09-24 09:29:47.711', '2021-09-24 09:29:47.711'); +INSERT INTO `ACT_HI_VARINST` VALUES ('e7ad352d-1cd6-11ec-acd8-3ae4f1d3c3af', 0, 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'initiator', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL, '2021-09-24 09:29:47.711', '2021-09-24 09:29:47.711'); +INSERT INTO `ACT_HI_VARINST` VALUES ('e7b72045-1cd6-11ec-acd8-3ae4f1d3c3af', 2, 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', NULL, 'operationType', 'string', NULL, NULL, NULL, NULL, NULL, NULL, 'agree', NULL, '2021-09-24 09:29:47.776', '2021-09-24 09:31:03.823'); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_ID_BYTEARRAY +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_ID_BYTEARRAY`; +CREATE TABLE `ACT_ID_BYTEARRAY` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `BYTES_` longblob, + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_ID_GROUP +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_ID_GROUP`; +CREATE TABLE `ACT_ID_GROUP` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_ID_INFO +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_ID_INFO`; +CREATE TABLE `ACT_ID_INFO` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `USER_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `VALUE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PASSWORD_` longblob, + `PARENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_ID_MEMBERSHIP +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_ID_MEMBERSHIP`; +CREATE TABLE `ACT_ID_MEMBERSHIP` ( + `USER_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `GROUP_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + PRIMARY KEY (`USER_ID_`,`GROUP_ID_`), + KEY `ACT_FK_MEMB_GROUP` (`GROUP_ID_`), + CONSTRAINT `ACT_FK_MEMB_GROUP` FOREIGN KEY (`GROUP_ID_`) REFERENCES `ACT_ID_GROUP` (`ID_`), + CONSTRAINT `ACT_FK_MEMB_USER` FOREIGN KEY (`USER_ID_`) REFERENCES `ACT_ID_USER` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_ID_PRIV +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_ID_PRIV`; +CREATE TABLE `ACT_ID_PRIV` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `NAME_` varchar(255) COLLATE utf8_bin NOT NULL, + PRIMARY KEY (`ID_`), + UNIQUE KEY `ACT_UNIQ_PRIV_NAME` (`NAME_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_ID_PRIV_MAPPING +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_ID_PRIV_MAPPING`; +CREATE TABLE `ACT_ID_PRIV_MAPPING` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `PRIV_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `GROUP_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_FK_PRIV_MAPPING` (`PRIV_ID_`), + KEY `ACT_IDX_PRIV_USER` (`USER_ID_`), + KEY `ACT_IDX_PRIV_GROUP` (`GROUP_ID_`), + CONSTRAINT `ACT_FK_PRIV_MAPPING` FOREIGN KEY (`PRIV_ID_`) REFERENCES `ACT_ID_PRIV` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_ID_PROPERTY +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_ID_PROPERTY`; +CREATE TABLE `ACT_ID_PROPERTY` ( + `NAME_` varchar(64) COLLATE utf8_bin NOT NULL, + `VALUE_` varchar(300) COLLATE utf8_bin DEFAULT NULL, + `REV_` int(11) DEFAULT NULL, + PRIMARY KEY (`NAME_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_ID_PROPERTY +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_ID_PROPERTY` VALUES ('schema.version', '6.6.0.0', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_ID_TOKEN +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_ID_TOKEN`; +CREATE TABLE `ACT_ID_TOKEN` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `TOKEN_VALUE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TOKEN_DATE_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), + `IP_ADDRESS_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `USER_AGENT_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TOKEN_DATA_` varchar(2000) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_ID_USER +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_ID_USER`; +CREATE TABLE `ACT_ID_USER` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `FIRST_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `LAST_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `DISPLAY_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `EMAIL_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PWD_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PICTURE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_PROCDEF_INFO +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_PROCDEF_INFO`; +CREATE TABLE `ACT_PROCDEF_INFO` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `INFO_JSON_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + UNIQUE KEY `ACT_UNIQ_INFO_PROCDEF` (`PROC_DEF_ID_`), + KEY `ACT_IDX_INFO_PROCDEF` (`PROC_DEF_ID_`), + KEY `ACT_FK_INFO_JSON_BA` (`INFO_JSON_ID_`), + CONSTRAINT `ACT_FK_INFO_JSON_BA` FOREIGN KEY (`INFO_JSON_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_INFO_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `ACT_RE_PROCDEF` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RE_DEPLOYMENT +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RE_DEPLOYMENT`; +CREATE TABLE `ACT_RE_DEPLOYMENT` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + `DEPLOY_TIME_` timestamp(3) NULL DEFAULT NULL, + `DERIVED_FROM_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `DERIVED_FROM_ROOT_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PARENT_DEPLOYMENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ENGINE_VERSION_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_RE_DEPLOYMENT +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_RE_DEPLOYMENT` VALUES ('1a075ec8-1c4e-11ec-94ee-5ef70686b817', '请假申请', 'HR', 'flowLeave', '', '2021-09-23 17:10:31.135', NULL, NULL, '1a075ec8-1c4e-11ec-94ee-5ef70686b817', NULL); +INSERT INTO `ACT_RE_DEPLOYMENT` VALUES ('1ba32d20-1c51-11ec-94ee-5ef70686b817', '合同审批', 'XM', 'flowContract', '', '2021-09-23 17:32:02.325', NULL, NULL, '1ba32d20-1c51-11ec-94ee-5ef70686b817', NULL); +INSERT INTO `ACT_RE_DEPLOYMENT` VALUES ('1d1dbf34-1c51-11ec-94ee-5ef70686b817', '报销申请', 'CW', 'flowSubmit', '', '2021-09-23 17:32:04.806', NULL, NULL, '1d1dbf34-1c51-11ec-94ee-5ef70686b817', NULL); +INSERT INTO `ACT_RE_DEPLOYMENT` VALUES ('9d23d445-1cd7-11ec-acd8-3ae4f1d3c3af', '合同审批', 'XM', 'flowContract', '', '2021-09-24 09:34:52.156', NULL, NULL, '9d23d445-1cd7-11ec-acd8-3ae4f1d3c3af', NULL); +INSERT INTO `ACT_RE_DEPLOYMENT` VALUES ('b97761b8-1c51-11ec-94ee-5ef70686b817', '多实例加签', 'HR', 'flowConSign', '', '2021-09-23 17:36:27.118', NULL, NULL, 'b97761b8-1c51-11ec-94ee-5ef70686b817', NULL); +INSERT INTO `ACT_RE_DEPLOYMENT` VALUES ('d273a35d-1cd8-11ec-acd8-3ae4f1d3c3af', '合同审批', 'XM', 'flowContract', '', '2021-09-24 09:43:31.095', NULL, NULL, 'd273a35d-1cd8-11ec-acd8-3ae4f1d3c3af', NULL); +INSERT INTO `ACT_RE_DEPLOYMENT` VALUES ('efd6c86c-1c4e-11ec-94ee-5ef70686b817', '报销申请', 'CW', 'flowSubmit', '', '2021-09-23 17:16:29.849', NULL, NULL, 'efd6c86c-1c4e-11ec-94ee-5ef70686b817', NULL); +INSERT INTO `ACT_RE_DEPLOYMENT` VALUES ('fa9b683c-1c51-11ec-94ee-5ef70686b817', '转办流程', 'HR', 'flowTranslate', '', '2021-09-23 17:38:16.406', NULL, NULL, 'fa9b683c-1c51-11ec-94ee-5ef70686b817', NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_RE_MODEL +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RE_MODEL`; +CREATE TABLE `ACT_RE_MODEL` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `LAST_UPDATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `VERSION_` int(11) DEFAULT NULL, + `META_INFO_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EDITOR_SOURCE_VALUE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EDITOR_SOURCE_EXTRA_VALUE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `ACT_FK_MODEL_SOURCE` (`EDITOR_SOURCE_VALUE_ID_`), + KEY `ACT_FK_MODEL_SOURCE_EXTRA` (`EDITOR_SOURCE_EXTRA_VALUE_ID_`), + KEY `ACT_FK_MODEL_DEPLOYMENT` (`DEPLOYMENT_ID_`), + CONSTRAINT `ACT_FK_MODEL_DEPLOYMENT` FOREIGN KEY (`DEPLOYMENT_ID_`) REFERENCES `ACT_RE_DEPLOYMENT` (`ID_`), + CONSTRAINT `ACT_FK_MODEL_SOURCE` FOREIGN KEY (`EDITOR_SOURCE_VALUE_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_MODEL_SOURCE_EXTRA` FOREIGN KEY (`EDITOR_SOURCE_EXTRA_VALUE_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RE_PROCDEF +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RE_PROCDEF`; +CREATE TABLE `ACT_RE_PROCDEF` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `KEY_` varchar(255) COLLATE utf8_bin NOT NULL, + `VERSION_` int(11) NOT NULL, + `DEPLOYMENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `RESOURCE_NAME_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `DGRM_RESOURCE_NAME_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `HAS_START_FORM_KEY_` tinyint(4) DEFAULT NULL, + `HAS_GRAPHICAL_NOTATION_` tinyint(4) DEFAULT NULL, + `SUSPENSION_STATE_` int(11) DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + `ENGINE_VERSION_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `DERIVED_FROM_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `DERIVED_FROM_ROOT_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `DERIVED_VERSION_` int(11) NOT NULL DEFAULT '0', + PRIMARY KEY (`ID_`), + UNIQUE KEY `ACT_UNIQ_PROCDEF` (`KEY_`,`VERSION_`,`DERIVED_VERSION_`,`TENANT_ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_RE_PROCDEF +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_RE_PROCDEF` VALUES ('flowConSign:1:b981c1fb-1c51-11ec-94ee-5ef70686b817', 1, 'http://flowable.org/bpmn', '多实例加签', 'flowConSign', 1, 'b97761b8-1c51-11ec-94ee-5ef70686b817', 'flowConSign.bpmn', 'flowConSign.flowConSign.png', NULL, 0, 1, 1, '', NULL, NULL, NULL, 0); +INSERT INTO `ACT_RE_PROCDEF` VALUES ('flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', 1, 'http://flowable.org/bpmn', '合同审批', 'flowContract', 1, '1ba32d20-1c51-11ec-94ee-5ef70686b817', 'flowContract.bpmn', 'flowContract.flowContract.png', NULL, 0, 1, 1, '', NULL, NULL, NULL, 0); +INSERT INTO `ACT_RE_PROCDEF` VALUES ('flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', 1, 'http://flowable.org/bpmn', '合同审批', 'flowContract', 2, '9d23d445-1cd7-11ec-acd8-3ae4f1d3c3af', 'flowContract.bpmn', 'flowContract.flowContract.png', NULL, 0, 1, 1, '', NULL, NULL, NULL, 0); +INSERT INTO `ACT_RE_PROCDEF` VALUES ('flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 1, 'http://flowable.org/bpmn', '合同审批', 'flowContract', 3, 'd273a35d-1cd8-11ec-acd8-3ae4f1d3c3af', 'flowContract.bpmn', 'flowContract.flowContract.png', NULL, 0, 1, 1, '', NULL, NULL, NULL, 0); +INSERT INTO `ACT_RE_PROCDEF` VALUES ('flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 1, 'http://flowable.org/bpmn', '请假申请', 'flowLeave', 1, '1a075ec8-1c4e-11ec-94ee-5ef70686b817', 'flowLeave.bpmn', 'flowLeave.flowLeave.png', NULL, 0, 1, 1, '', NULL, NULL, NULL, 0); +INSERT INTO `ACT_RE_PROCDEF` VALUES ('flowSubmit:1:efe9db3f-1c4e-11ec-94ee-5ef70686b817', 1, 'http://flowable.org/bpmn', '报销申请', 'flowSubmit', 1, 'efd6c86c-1c4e-11ec-94ee-5ef70686b817', 'flowSubmit.bpmn', 'flowSubmit.flowSubmit.png', NULL, 0, 1, 1, '', NULL, NULL, NULL, 0); +INSERT INTO `ACT_RE_PROCDEF` VALUES ('flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', 1, 'http://flowable.org/bpmn', '报销申请', 'flowSubmit', 2, '1d1dbf34-1c51-11ec-94ee-5ef70686b817', 'flowSubmit.bpmn', 'flowSubmit.flowSubmit.png', NULL, 0, 1, 1, '', NULL, NULL, NULL, 0); +INSERT INTO `ACT_RE_PROCDEF` VALUES ('flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 1, 'http://flowable.org/bpmn', '转办流程', 'flowTranslate', 1, 'fa9b683c-1c51-11ec-94ee-5ef70686b817', 'flowTranslate.bpmn', 'flowTranslate.flowTranslate.png', NULL, 0, 1, 1, '', NULL, NULL, NULL, 0); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_RU_ACTINST +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_ACTINST`; +CREATE TABLE `ACT_RU_ACTINST` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT '1', + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `ACT_ID_` varchar(255) COLLATE utf8_bin NOT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CALL_PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ACT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ACT_TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `ASSIGNEE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `START_TIME_` datetime(3) NOT NULL, + `END_TIME_` datetime(3) DEFAULT NULL, + `DURATION_` bigint(20) DEFAULT NULL, + `TRANSACTION_ORDER_` int(11) DEFAULT NULL, + `DELETE_REASON_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_RU_ACTI_START` (`START_TIME_`), + KEY `ACT_IDX_RU_ACTI_END` (`END_TIME_`), + KEY `ACT_IDX_RU_ACTI_PROC` (`PROC_INST_ID_`), + KEY `ACT_IDX_RU_ACTI_PROC_ACT` (`PROC_INST_ID_`,`ACT_ID_`), + KEY `ACT_IDX_RU_ACTI_EXEC` (`EXECUTION_ID_`), + KEY `ACT_IDX_RU_ACTI_EXEC_ACT` (`EXECUTION_ID_`,`ACT_ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_RU_ACTINST +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_RU_ACTINST` VALUES ('7138d683-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Event_17n2rw9', NULL, NULL, NULL, 'startEvent', NULL, '2021-09-24 17:54:43.245', '2021-09-24 17:54:43.246', 1, 1, NULL, ''); +INSERT INTO `ACT_RU_ACTINST` VALUES ('7138fd94-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Flow_00ldvag', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 17:54:43.246', '2021-09-24 17:54:43.246', 0, 2, NULL, ''); +INSERT INTO `ACT_RU_ACTINST` VALUES ('7138fd95-1d1d-11ec-8336-3ae4f1d3c3af', 2, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Activity_03kjurt', '7138fd96-1d1d-11ec-8336-3ae4f1d3c3af', NULL, '报销单录入', 'userTask', 'userD', '2021-09-24 17:54:43.246', '2021-09-24 17:54:43.277', 31, 3, NULL, ''); +INSERT INTO `ACT_RU_ACTINST` VALUES ('713ddf9b-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Flow_0x9dx2t', NULL, NULL, NULL, 'sequenceFlow', NULL, '2021-09-24 17:54:43.278', '2021-09-24 17:54:43.278', 0, 1, NULL, ''); +INSERT INTO `ACT_RU_ACTINST` VALUES ('713ddf9c-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 'Activity_0ywxfwu', '713e06ad-1d1d-11ec-8336-3ae4f1d3c3af', NULL, '部门领导审批', 'userTask', NULL, '2021-09-24 17:54:43.278', NULL, NULL, 2, NULL, ''); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_RU_DEADLETTER_JOB +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_DEADLETTER_JOB`; +CREATE TABLE `ACT_RU_DEADLETTER_JOB` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `EXCLUSIVE_` tinyint(1) DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CORRELATION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_DEADLETTER_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`), + KEY `ACT_IDX_DEADLETTER_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`), + KEY `ACT_IDX_DEADLETTER_JOB_CORRELATION_ID` (`CORRELATION_ID_`), + KEY `ACT_IDX_DJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_DJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_DJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`), + KEY `ACT_FK_DEADLETTER_JOB_EXECUTION` (`EXECUTION_ID_`), + KEY `ACT_FK_DEADLETTER_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`), + KEY `ACT_FK_DEADLETTER_JOB_PROC_DEF` (`PROC_DEF_ID_`), + CONSTRAINT `ACT_FK_DEADLETTER_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_DEADLETTER_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_DEADLETTER_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_DEADLETTER_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_DEADLETTER_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `ACT_RE_PROCDEF` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RU_ENTITYLINK +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_ENTITYLINK`; +CREATE TABLE `ACT_RU_ENTITYLINK` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `CREATE_TIME_` datetime(3) DEFAULT NULL, + `LINK_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PARENT_ELEMENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REF_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REF_SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REF_SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ROOT_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ROOT_SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HIERARCHY_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_ENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`,`LINK_TYPE_`), + KEY `ACT_IDX_ENT_LNK_ROOT_SCOPE` (`ROOT_SCOPE_ID_`,`ROOT_SCOPE_TYPE_`,`LINK_TYPE_`), + KEY `ACT_IDX_ENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`,`LINK_TYPE_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RU_EVENT_SUBSCR +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_EVENT_SUBSCR`; +CREATE TABLE `ACT_RU_EVENT_SUBSCR` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `EVENT_TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `EVENT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ACTIVITY_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CONFIGURATION_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CREATED_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_EVENT_SUBSCR_CONFIG_` (`CONFIGURATION_`), + KEY `ACT_FK_EVENT_EXEC` (`EXECUTION_ID_`), + CONSTRAINT `ACT_FK_EVENT_EXEC` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RU_EXECUTION +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_EXECUTION`; +CREATE TABLE `ACT_RU_EXECUTION` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `BUSINESS_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PARENT_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SUPER_EXEC_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ROOT_PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ACT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `IS_ACTIVE_` tinyint(4) DEFAULT NULL, + `IS_CONCURRENT_` tinyint(4) DEFAULT NULL, + `IS_SCOPE_` tinyint(4) DEFAULT NULL, + `IS_EVENT_SCOPE_` tinyint(4) DEFAULT NULL, + `IS_MI_ROOT_` tinyint(4) DEFAULT NULL, + `SUSPENSION_STATE_` int(11) DEFAULT NULL, + `CACHED_ENT_STATE_` int(11) DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `START_ACT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `START_TIME_` datetime(3) DEFAULT NULL, + `START_USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `LOCK_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `IS_COUNT_ENABLED_` tinyint(4) DEFAULT NULL, + `EVT_SUBSCR_COUNT_` int(11) DEFAULT NULL, + `TASK_COUNT_` int(11) DEFAULT NULL, + `JOB_COUNT_` int(11) DEFAULT NULL, + `TIMER_JOB_COUNT_` int(11) DEFAULT NULL, + `SUSP_JOB_COUNT_` int(11) DEFAULT NULL, + `DEADLETTER_JOB_COUNT_` int(11) DEFAULT NULL, + `EXTERNAL_WORKER_JOB_COUNT_` int(11) DEFAULT NULL, + `VAR_COUNT_` int(11) DEFAULT NULL, + `ID_LINK_COUNT_` int(11) DEFAULT NULL, + `CALLBACK_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CALLBACK_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REFERENCE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `REFERENCE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PROPAGATED_STAGE_INST_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_EXEC_BUSKEY` (`BUSINESS_KEY_`), + KEY `ACT_IDC_EXEC_ROOT` (`ROOT_PROC_INST_ID_`), + KEY `ACT_FK_EXE_PROCINST` (`PROC_INST_ID_`), + KEY `ACT_FK_EXE_PARENT` (`PARENT_ID_`), + KEY `ACT_FK_EXE_SUPER` (`SUPER_EXEC_`), + KEY `ACT_FK_EXE_PROCDEF` (`PROC_DEF_ID_`), + CONSTRAINT `ACT_FK_EXE_PARENT` FOREIGN KEY (`PARENT_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`) ON DELETE CASCADE, + CONSTRAINT `ACT_FK_EXE_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `ACT_RE_PROCDEF` (`ID_`), + CONSTRAINT `ACT_FK_EXE_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`) ON DELETE CASCADE ON UPDATE CASCADE, + CONSTRAINT `ACT_FK_EXE_SUPER` FOREIGN KEY (`SUPER_EXEC_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_RU_EXECUTION +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_RU_EXECUTION` VALUES ('7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', 1, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '1441340309442138112', NULL, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, 1, 0, 1, 0, 0, 1, NULL, '', NULL, 'Event_17n2rw9', '2021-09-24 17:54:43.245', 'userD', NULL, NULL, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_RU_EXECUTION` VALUES ('7138d682-1d1d-11ec-8336-3ae4f1d3c3af', 2, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', 'Activity_0ywxfwu', 1, 0, 0, 0, 0, 1, NULL, '', NULL, NULL, '2021-09-24 17:54:43.245', NULL, NULL, NULL, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_RU_EXTERNAL_JOB +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_EXTERNAL_JOB`; +CREATE TABLE `ACT_RU_EXTERNAL_JOB` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `EXCLUSIVE_` tinyint(1) DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CORRELATION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `RETRIES_` int(11) DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_EXTERNAL_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`), + KEY `ACT_IDX_EXTERNAL_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`), + KEY `ACT_IDX_EXTERNAL_JOB_CORRELATION_ID` (`CORRELATION_ID_`), + KEY `ACT_IDX_EJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_EJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_EJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`), + CONSTRAINT `ACT_FK_EXTERNAL_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_EXTERNAL_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RU_HISTORY_JOB +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_HISTORY_JOB`; +CREATE TABLE `ACT_RU_HISTORY_JOB` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `RETRIES_` int(11) DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ADV_HANDLER_CFG_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RU_IDENTITYLINK +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_IDENTITYLINK`; +CREATE TABLE `ACT_RU_IDENTITYLINK` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `GROUP_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_IDENT_LNK_USER` (`USER_ID_`), + KEY `ACT_IDX_IDENT_LNK_GROUP` (`GROUP_ID_`), + KEY `ACT_IDX_IDENT_LNK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_IDENT_LNK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_IDENT_LNK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_ATHRZ_PROCEDEF` (`PROC_DEF_ID_`), + KEY `ACT_FK_TSKASS_TASK` (`TASK_ID_`), + KEY `ACT_FK_IDL_PROCINST` (`PROC_INST_ID_`), + CONSTRAINT `ACT_FK_ATHRZ_PROCEDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `ACT_RE_PROCDEF` (`ID_`), + CONSTRAINT `ACT_FK_IDL_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_TSKASS_TASK` FOREIGN KEY (`TASK_ID_`) REFERENCES `ACT_RU_TASK` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_RU_IDENTITYLINK +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_RU_IDENTITYLINK` VALUES ('7138d67e-1d1d-11ec-8336-3ae4f1d3c3af', 1, NULL, 'starter', 'userD', NULL, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_RU_IDENTITYLINK` VALUES ('7138fd98-1d1d-11ec-8336-3ae4f1d3c3af', 1, NULL, 'participant', 'userD', NULL, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_RU_IDENTITYLINK` VALUES ('713d6a6a-1d1d-11ec-8336-3ae4f1d3c3af', 1, NULL, 'participant', 'userD', NULL, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL); +INSERT INTO `ACT_RU_IDENTITYLINK` VALUES ('713e06ae-1d1d-11ec-8336-3ae4f1d3c3af', 1, '1440964519391137792', 'candidate', NULL, '713e06ad-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_RU_JOB +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_JOB`; +CREATE TABLE `ACT_RU_JOB` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `EXCLUSIVE_` tinyint(1) DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CORRELATION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `RETRIES_` int(11) DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`), + KEY `ACT_IDX_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`), + KEY `ACT_IDX_JOB_CORRELATION_ID` (`CORRELATION_ID_`), + KEY `ACT_IDX_JOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_JOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_JOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`), + KEY `ACT_FK_JOB_EXECUTION` (`EXECUTION_ID_`), + KEY `ACT_FK_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`), + KEY `ACT_FK_JOB_PROC_DEF` (`PROC_DEF_ID_`), + CONSTRAINT `ACT_FK_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `ACT_RE_PROCDEF` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RU_SUSPENDED_JOB +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_SUSPENDED_JOB`; +CREATE TABLE `ACT_RU_SUSPENDED_JOB` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `EXCLUSIVE_` tinyint(1) DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CORRELATION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `RETRIES_` int(11) DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_SUSPENDED_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`), + KEY `ACT_IDX_SUSPENDED_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`), + KEY `ACT_IDX_SUSPENDED_JOB_CORRELATION_ID` (`CORRELATION_ID_`), + KEY `ACT_IDX_SJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_SJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_SJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`), + KEY `ACT_FK_SUSPENDED_JOB_EXECUTION` (`EXECUTION_ID_`), + KEY `ACT_FK_SUSPENDED_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`), + KEY `ACT_FK_SUSPENDED_JOB_PROC_DEF` (`PROC_DEF_ID_`), + CONSTRAINT `ACT_FK_SUSPENDED_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_SUSPENDED_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_SUSPENDED_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_SUSPENDED_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_SUSPENDED_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `ACT_RE_PROCDEF` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RU_TASK +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_TASK`; +CREATE TABLE `ACT_RU_TASK` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TASK_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PROPAGATED_STAGE_INST_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `PARENT_TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `TASK_DEF_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ASSIGNEE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `DELEGATION_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PRIORITY_` int(11) DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `DUE_DATE_` datetime(3) DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUSPENSION_STATE_` int(11) DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + `FORM_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CLAIM_TIME_` datetime(3) DEFAULT NULL, + `IS_COUNT_ENABLED_` tinyint(4) DEFAULT NULL, + `VAR_COUNT_` int(11) DEFAULT NULL, + `ID_LINK_COUNT_` int(11) DEFAULT NULL, + `SUB_TASK_COUNT_` int(11) DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_TASK_CREATE` (`CREATE_TIME_`), + KEY `ACT_IDX_TASK_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_TASK_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_TASK_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`), + KEY `ACT_FK_TASK_EXE` (`EXECUTION_ID_`), + KEY `ACT_FK_TASK_PROCINST` (`PROC_INST_ID_`), + KEY `ACT_FK_TASK_PROCDEF` (`PROC_DEF_ID_`), + CONSTRAINT `ACT_FK_TASK_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_TASK_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `ACT_RE_PROCDEF` (`ID_`), + CONSTRAINT `ACT_FK_TASK_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_RU_TASK +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_RU_TASK` VALUES ('713e06ad-1d1d-11ec-8336-3ae4f1d3c3af', 1, '7138d682-1d1d-11ec-8336-3ae4f1d3c3af', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', NULL, NULL, NULL, NULL, NULL, NULL, '部门领导审批', NULL, NULL, 'Activity_0ywxfwu', NULL, NULL, NULL, 50, '2021-09-24 17:54:43.278', NULL, NULL, 1, '', '{\"formId\":\"1440947675041107968\",\"readOnly\":true,\"groupType\":\"DEPT_POST_LEADER\"}', NULL, 1, 0, 1, 0); +COMMIT; + +-- ---------------------------- +-- Table structure for ACT_RU_TIMER_JOB +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_TIMER_JOB`; +CREATE TABLE `ACT_RU_TIMER_JOB` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `LOCK_EXP_TIME_` timestamp(3) NULL DEFAULT NULL, + `LOCK_OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `EXCLUSIVE_` tinyint(1) DEFAULT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROCESS_INSTANCE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `ELEMENT_NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_DEFINITION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CORRELATION_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `RETRIES_` int(11) DEFAULT NULL, + `EXCEPTION_STACK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `EXCEPTION_MSG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `DUEDATE_` timestamp(3) NULL DEFAULT NULL, + `REPEAT_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `HANDLER_CFG_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `CUSTOM_VALUES_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` timestamp(3) NULL DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_TIMER_JOB_EXCEPTION_STACK_ID` (`EXCEPTION_STACK_ID_`), + KEY `ACT_IDX_TIMER_JOB_CUSTOM_VALUES_ID` (`CUSTOM_VALUES_ID_`), + KEY `ACT_IDX_TIMER_JOB_CORRELATION_ID` (`CORRELATION_ID_`), + KEY `ACT_IDX_TJOB_SCOPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_TJOB_SUB_SCOPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_TJOB_SCOPE_DEF` (`SCOPE_DEFINITION_ID_`,`SCOPE_TYPE_`), + KEY `ACT_FK_TIMER_JOB_EXECUTION` (`EXECUTION_ID_`), + KEY `ACT_FK_TIMER_JOB_PROCESS_INSTANCE` (`PROCESS_INSTANCE_ID_`), + KEY `ACT_FK_TIMER_JOB_PROC_DEF` (`PROC_DEF_ID_`), + CONSTRAINT `ACT_FK_TIMER_JOB_CUSTOM_VALUES` FOREIGN KEY (`CUSTOM_VALUES_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_TIMER_JOB_EXCEPTION` FOREIGN KEY (`EXCEPTION_STACK_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_TIMER_JOB_EXECUTION` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_TIMER_JOB_PROCESS_INSTANCE` FOREIGN KEY (`PROCESS_INSTANCE_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_TIMER_JOB_PROC_DEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `ACT_RE_PROCDEF` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for ACT_RU_VARIABLE +-- ---------------------------- +DROP TABLE IF EXISTS `ACT_RU_VARIABLE`; +CREATE TABLE `ACT_RU_VARIABLE` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `TYPE_` varchar(255) COLLATE utf8_bin NOT NULL, + `NAME_` varchar(255) COLLATE utf8_bin NOT NULL, + `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `BYTEARRAY_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `DOUBLE_` double DEFAULT NULL, + `LONG_` bigint(20) DEFAULT NULL, + `TEXT_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + `TEXT2_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + KEY `ACT_IDX_RU_VAR_SCOPE_ID_TYPE` (`SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_IDX_RU_VAR_SUB_ID_TYPE` (`SUB_SCOPE_ID_`,`SCOPE_TYPE_`), + KEY `ACT_FK_VAR_BYTEARRAY` (`BYTEARRAY_ID_`), + KEY `ACT_IDX_VARIABLE_TASK_ID` (`TASK_ID_`), + KEY `ACT_FK_VAR_EXE` (`EXECUTION_ID_`), + KEY `ACT_FK_VAR_PROCINST` (`PROC_INST_ID_`), + CONSTRAINT `ACT_FK_VAR_BYTEARRAY` FOREIGN KEY (`BYTEARRAY_ID_`) REFERENCES `ACT_GE_BYTEARRAY` (`ID_`), + CONSTRAINT `ACT_FK_VAR_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`), + CONSTRAINT `ACT_FK_VAR_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `ACT_RU_EXECUTION` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of ACT_RU_VARIABLE +-- ---------------------------- +BEGIN; +INSERT INTO `ACT_RU_VARIABLE` VALUES ('7138d67f-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'string', 'startUserName', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL); +INSERT INTO `ACT_RU_VARIABLE` VALUES ('7138d680-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'long', 'deptPostLeader', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, NULL, 1440964519391137792, '1440964519391137792', NULL); +INSERT INTO `ACT_RU_VARIABLE` VALUES ('7138d681-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'string', 'initiator', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'userD', NULL); +INSERT INTO `ACT_RU_VARIABLE` VALUES ('713d6a69-1d1d-11ec-8336-3ae4f1d3c3af', 1, 'string', 'operationType', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'agree', NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for FLW_CHANNEL_DEFINITION +-- ---------------------------- +DROP TABLE IF EXISTS `FLW_CHANNEL_DEFINITION`; +CREATE TABLE `FLW_CHANNEL_DEFINITION` ( + `ID_` varchar(255) COLLATE utf8mb4_bin NOT NULL, + `NAME_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `VERSION_` int(11) DEFAULT NULL, + `KEY_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `CREATE_TIME_` datetime(3) DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `RESOURCE_NAME_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `DESCRIPTION_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + UNIQUE KEY `ACT_IDX_CHANNEL_DEF_UNIQ` (`KEY_`,`VERSION_`,`TENANT_ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Table structure for FLW_EVENT_DEFINITION +-- ---------------------------- +DROP TABLE IF EXISTS `FLW_EVENT_DEFINITION`; +CREATE TABLE `FLW_EVENT_DEFINITION` ( + `ID_` varchar(255) COLLATE utf8mb4_bin NOT NULL, + `NAME_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `VERSION_` int(11) DEFAULT NULL, + `KEY_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `RESOURCE_NAME_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `DESCRIPTION_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + PRIMARY KEY (`ID_`), + UNIQUE KEY `ACT_IDX_EVENT_DEF_UNIQ` (`KEY_`,`VERSION_`,`TENANT_ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Table structure for FLW_EVENT_DEPLOYMENT +-- ---------------------------- +DROP TABLE IF EXISTS `FLW_EVENT_DEPLOYMENT`; +CREATE TABLE `FLW_EVENT_DEPLOYMENT` ( + `ID_` varchar(255) COLLATE utf8mb4_bin NOT NULL, + `NAME_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `CATEGORY_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `DEPLOY_TIME_` datetime(3) DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `PARENT_DEPLOYMENT_ID_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Table structure for FLW_EVENT_RESOURCE +-- ---------------------------- +DROP TABLE IF EXISTS `FLW_EVENT_RESOURCE`; +CREATE TABLE `FLW_EVENT_RESOURCE` ( + `ID_` varchar(255) COLLATE utf8mb4_bin NOT NULL, + `NAME_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `DEPLOYMENT_ID_` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `RESOURCE_BYTES_` longblob, + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Table structure for FLW_EV_DATABASECHANGELOG +-- ---------------------------- +DROP TABLE IF EXISTS `FLW_EV_DATABASECHANGELOG`; +CREATE TABLE `FLW_EV_DATABASECHANGELOG` ( + `ID` varchar(255) COLLATE utf8mb4_bin NOT NULL, + `AUTHOR` varchar(255) COLLATE utf8mb4_bin NOT NULL, + `FILENAME` varchar(255) COLLATE utf8mb4_bin NOT NULL, + `DATEEXECUTED` datetime NOT NULL, + `ORDEREXECUTED` int(11) NOT NULL, + `EXECTYPE` varchar(10) COLLATE utf8mb4_bin NOT NULL, + `MD5SUM` varchar(35) COLLATE utf8mb4_bin DEFAULT NULL, + `DESCRIPTION` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `COMMENTS` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `TAG` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `LIQUIBASE` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL, + `CONTEXTS` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `LABELS` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + `DEPLOYMENT_ID` varchar(10) COLLATE utf8mb4_bin DEFAULT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of FLW_EV_DATABASECHANGELOG +-- ---------------------------- +BEGIN; +INSERT INTO `FLW_EV_DATABASECHANGELOG` VALUES ('1', 'flowable', 'org/flowable/eventregistry/db/liquibase/flowable-eventregistry-db-changelog.xml', '2021-08-22 15:01:56', 1, 'EXECUTED', '8:1b0c48c9cf7945be799d868a2626d687', 'createTable tableName=FLW_EVENT_DEPLOYMENT; createTable tableName=FLW_EVENT_RESOURCE; createTable tableName=FLW_EVENT_DEFINITION; createIndex indexName=ACT_IDX_EVENT_DEF_UNIQ, tableName=FLW_EVENT_DEFINITION; createTable tableName=FLW_CHANNEL_DEFIN...', '', NULL, '3.8.9', NULL, NULL, '9615716437'); +COMMIT; + +-- ---------------------------- +-- Table structure for FLW_EV_DATABASECHANGELOGLOCK +-- ---------------------------- +DROP TABLE IF EXISTS `FLW_EV_DATABASECHANGELOGLOCK`; +CREATE TABLE `FLW_EV_DATABASECHANGELOGLOCK` ( + `ID` int(11) NOT NULL, + `LOCKED` bit(1) NOT NULL, + `LOCKGRANTED` datetime DEFAULT NULL, + `LOCKEDBY` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL, + PRIMARY KEY (`ID`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of FLW_EV_DATABASECHANGELOGLOCK +-- ---------------------------- +BEGIN; +INSERT INTO `FLW_EV_DATABASECHANGELOGLOCK` VALUES (1, b'0', NULL, NULL); +COMMIT; + +-- ---------------------------- +-- Table structure for FLW_RU_BATCH +-- ---------------------------- +DROP TABLE IF EXISTS `FLW_RU_BATCH`; +CREATE TABLE `FLW_RU_BATCH` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `TYPE_` varchar(64) COLLATE utf8_bin NOT NULL, + `SEARCH_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SEARCH_KEY2_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` datetime(3) NOT NULL, + `COMPLETE_TIME_` datetime(3) DEFAULT NULL, + `STATUS_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `BATCH_DOC_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for FLW_RU_BATCH_PART +-- ---------------------------- +DROP TABLE IF EXISTS `FLW_RU_BATCH_PART`; +CREATE TABLE `FLW_RU_BATCH_PART` ( + `ID_` varchar(64) COLLATE utf8_bin NOT NULL, + `REV_` int(11) DEFAULT NULL, + `BATCH_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TYPE_` varchar(64) COLLATE utf8_bin NOT NULL, + `SCOPE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SUB_SCOPE_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SCOPE_TYPE_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `SEARCH_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `SEARCH_KEY2_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `CREATE_TIME_` datetime(3) NOT NULL, + `COMPLETE_TIME_` datetime(3) DEFAULT NULL, + `STATUS_` varchar(255) COLLATE utf8_bin DEFAULT NULL, + `RESULT_DOC_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, + `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', + PRIMARY KEY (`ID_`), + KEY `FLW_IDX_BATCH_PART` (`BATCH_ID_`), + CONSTRAINT `FLW_FK_BATCH_PART_PARENT` FOREIGN KEY (`BATCH_ID_`) REFERENCES `FLW_RU_BATCH` (`ID_`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Table structure for zz_area_code +-- ---------------------------- +DROP TABLE IF EXISTS `zz_area_code`; +CREATE TABLE `zz_area_code` ( + `area_id` bigint(20) unsigned NOT NULL COMMENT '行政区划主键Id', + `area_name` varchar(128) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '行政区划名称', + `area_level` int(11) NOT NULL COMMENT '行政区划级别 (1: 省级别 2: 市级别 3: 区级别)', + `parent_id` bigint(20) DEFAULT NULL COMMENT '父级行政区划Id', + PRIMARY KEY (`area_id`) USING BTREE, + KEY `idx_level` (`area_level`) USING BTREE, + KEY `idx_area_name` (`area_name`) USING BTREE, + KEY `idx_parent_id` (`parent_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='行政区划表'; + +-- ---------------------------- +-- Records of zz_area_code +-- ---------------------------- +BEGIN; +INSERT INTO `zz_area_code` VALUES (110000000000, '北京市', 1, NULL); +INSERT INTO `zz_area_code` VALUES (110100000000, '市辖区', 2, 110000000000); +INSERT INTO `zz_area_code` VALUES (110101000000, '东城区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110102000000, '西城区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110105000000, '朝阳区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110106000000, '丰台区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110107000000, '石景山区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110108000000, '海淀区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110109000000, '门头沟区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110111000000, '房山区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110112000000, '通州区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110113000000, '顺义区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110114000000, '昌平区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110115000000, '大兴区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110116000000, '怀柔区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110117000000, '平谷区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110118000000, '密云区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (110119000000, '延庆区', 3, 110100000000); +INSERT INTO `zz_area_code` VALUES (120000000000, '天津市', 1, NULL); +INSERT INTO `zz_area_code` VALUES (120100000000, '市辖区', 2, 120000000000); +INSERT INTO `zz_area_code` VALUES (120101000000, '和平区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120102000000, '河东区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120103000000, '河西区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120104000000, '南开区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120105000000, '河北区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120106000000, '红桥区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120110000000, '东丽区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120111000000, '西青区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120112000000, '津南区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120113000000, '北辰区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120114000000, '武清区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120115000000, '宝坻区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120116000000, '滨海新区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120117000000, '宁河区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120118000000, '静海区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (120119000000, '蓟州区', 3, 120100000000); +INSERT INTO `zz_area_code` VALUES (130000000000, '河北省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (130100000000, '石家庄市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130101000000, '市辖区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130102000000, '长安区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130104000000, '桥西区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130105000000, '新华区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130107000000, '井陉矿区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130108000000, '裕华区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130109000000, '藁城区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130110000000, '鹿泉区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130111000000, '栾城区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130121000000, '井陉县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130123000000, '正定县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130125000000, '行唐县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130126000000, '灵寿县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130127000000, '高邑县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130128000000, '深泽县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130129000000, '赞皇县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130130000000, '无极县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130131000000, '平山县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130132000000, '元氏县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130133000000, '赵县', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130171000000, '石家庄高新技术产业开发区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130172000000, '石家庄循环化工园区', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130181000000, '辛集市', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130183000000, '晋州市', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130184000000, '新乐市', 3, 130100000000); +INSERT INTO `zz_area_code` VALUES (130200000000, '唐山市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130201000000, '市辖区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130202000000, '路南区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130203000000, '路北区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130204000000, '古冶区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130205000000, '开平区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130207000000, '丰南区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130208000000, '丰润区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130209000000, '曹妃甸区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130224000000, '滦南县', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130225000000, '乐亭县', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130227000000, '迁西县', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130229000000, '玉田县', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130271000000, '唐山市芦台经济技术开发区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130272000000, '唐山市汉沽管理区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130273000000, '唐山高新技术产业开发区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130274000000, '河北唐山海港经济开发区', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130281000000, '遵化市', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130283000000, '迁安市', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130284000000, '滦州市', 3, 130200000000); +INSERT INTO `zz_area_code` VALUES (130300000000, '秦皇岛市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130301000000, '市辖区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130302000000, '海港区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130303000000, '山海关区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130304000000, '北戴河区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130306000000, '抚宁区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130321000000, '青龙满族自治县', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130322000000, '昌黎县', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130324000000, '卢龙县', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130371000000, '秦皇岛市经济技术开发区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130372000000, '北戴河新区', 3, 130300000000); +INSERT INTO `zz_area_code` VALUES (130400000000, '邯郸市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130401000000, '市辖区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130402000000, '邯山区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130403000000, '丛台区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130404000000, '复兴区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130406000000, '峰峰矿区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130407000000, '肥乡区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130408000000, '永年区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130423000000, '临漳县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130424000000, '成安县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130425000000, '大名县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130426000000, '涉县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130427000000, '磁县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130430000000, '邱县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130431000000, '鸡泽县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130432000000, '广平县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130433000000, '馆陶县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130434000000, '魏县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130435000000, '曲周县', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130471000000, '邯郸经济技术开发区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130473000000, '邯郸冀南新区', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130481000000, '武安市', 3, 130400000000); +INSERT INTO `zz_area_code` VALUES (130500000000, '邢台市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130501000000, '市辖区', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130502000000, '桥东区', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130503000000, '桥西区', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130521000000, '邢台县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130522000000, '临城县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130523000000, '内丘县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130524000000, '柏乡县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130525000000, '隆尧县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130526000000, '任县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130527000000, '南和县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130528000000, '宁晋县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130529000000, '巨鹿县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130530000000, '新河县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130531000000, '广宗县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130532000000, '平乡县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130533000000, '威县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130534000000, '清河县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130535000000, '临西县', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130571000000, '河北邢台经济开发区', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130581000000, '南宫市', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130582000000, '沙河市', 3, 130500000000); +INSERT INTO `zz_area_code` VALUES (130600000000, '保定市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130601000000, '市辖区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130602000000, '竞秀区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130606000000, '莲池区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130607000000, '满城区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130608000000, '清苑区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130609000000, '徐水区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130623000000, '涞水县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130624000000, '阜平县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130626000000, '定兴县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130627000000, '唐县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130628000000, '高阳县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130629000000, '容城县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130630000000, '涞源县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130631000000, '望都县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130632000000, '安新县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130633000000, '易县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130634000000, '曲阳县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130635000000, '蠡县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130636000000, '顺平县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130637000000, '博野县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130638000000, '雄县', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130671000000, '保定高新技术产业开发区', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130672000000, '保定白沟新城', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130681000000, '涿州市', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130682000000, '定州市', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130683000000, '安国市', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130684000000, '高碑店市', 3, 130600000000); +INSERT INTO `zz_area_code` VALUES (130700000000, '张家口市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130701000000, '市辖区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130702000000, '桥东区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130703000000, '桥西区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130705000000, '宣化区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130706000000, '下花园区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130708000000, '万全区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130709000000, '崇礼区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130722000000, '张北县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130723000000, '康保县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130724000000, '沽源县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130725000000, '尚义县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130726000000, '蔚县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130727000000, '阳原县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130728000000, '怀安县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130730000000, '怀来县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130731000000, '涿鹿县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130732000000, '赤城县', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130771000000, '张家口市高新技术产业开发区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130772000000, '张家口市察北管理区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130773000000, '张家口市塞北管理区', 3, 130700000000); +INSERT INTO `zz_area_code` VALUES (130800000000, '承德市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130801000000, '市辖区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130802000000, '双桥区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130803000000, '双滦区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130804000000, '鹰手营子矿区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130821000000, '承德县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130822000000, '兴隆县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130824000000, '滦平县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130825000000, '隆化县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130826000000, '丰宁满族自治县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130827000000, '宽城满族自治县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130828000000, '围场满族蒙古族自治县', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130871000000, '承德高新技术产业开发区', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130881000000, '平泉市', 3, 130800000000); +INSERT INTO `zz_area_code` VALUES (130900000000, '沧州市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (130901000000, '市辖区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130902000000, '新华区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130903000000, '运河区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130921000000, '沧县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130922000000, '青县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130923000000, '东光县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130924000000, '海兴县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130925000000, '盐山县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130926000000, '肃宁县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130927000000, '南皮县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130928000000, '吴桥县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130929000000, '献县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130930000000, '孟村回族自治县', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130971000000, '河北沧州经济开发区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130972000000, '沧州高新技术产业开发区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130973000000, '沧州渤海新区', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130981000000, '泊头市', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130982000000, '任丘市', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130983000000, '黄骅市', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (130984000000, '河间市', 3, 130900000000); +INSERT INTO `zz_area_code` VALUES (131000000000, '廊坊市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (131001000000, '市辖区', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131002000000, '安次区', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131003000000, '广阳区', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131022000000, '固安县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131023000000, '永清县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131024000000, '香河县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131025000000, '大城县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131026000000, '文安县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131028000000, '大厂回族自治县', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131071000000, '廊坊经济技术开发区', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131081000000, '霸州市', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131082000000, '三河市', 3, 131000000000); +INSERT INTO `zz_area_code` VALUES (131100000000, '衡水市', 2, 130000000000); +INSERT INTO `zz_area_code` VALUES (131101000000, '市辖区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131102000000, '桃城区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131103000000, '冀州区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131121000000, '枣强县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131122000000, '武邑县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131123000000, '武强县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131124000000, '饶阳县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131125000000, '安平县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131126000000, '故城县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131127000000, '景县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131128000000, '阜城县', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131171000000, '河北衡水高新技术产业开发区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131172000000, '衡水滨湖新区', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (131182000000, '深州市', 3, 131100000000); +INSERT INTO `zz_area_code` VALUES (140000000000, '山西省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (140100000000, '太原市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140101000000, '市辖区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140105000000, '小店区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140106000000, '迎泽区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140107000000, '杏花岭区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140108000000, '尖草坪区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140109000000, '万柏林区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140110000000, '晋源区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140121000000, '清徐县', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140122000000, '阳曲县', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140123000000, '娄烦县', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140171000000, '山西转型综合改革示范区', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140181000000, '古交市', 3, 140100000000); +INSERT INTO `zz_area_code` VALUES (140200000000, '大同市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140201000000, '市辖区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140212000000, '新荣区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140213000000, '平城区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140214000000, '云冈区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140215000000, '云州区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140221000000, '阳高县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140222000000, '天镇县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140223000000, '广灵县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140224000000, '灵丘县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140225000000, '浑源县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140226000000, '左云县', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140271000000, '山西大同经济开发区', 3, 140200000000); +INSERT INTO `zz_area_code` VALUES (140300000000, '阳泉市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140301000000, '市辖区', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140302000000, '城区', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140303000000, '矿区', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140311000000, '郊区', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140321000000, '平定县', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140322000000, '盂县', 3, 140300000000); +INSERT INTO `zz_area_code` VALUES (140400000000, '长治市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140401000000, '市辖区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140403000000, '潞州区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140404000000, '上党区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140405000000, '屯留区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140406000000, '潞城区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140423000000, '襄垣县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140425000000, '平顺县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140426000000, '黎城县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140427000000, '壶关县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140428000000, '长子县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140429000000, '武乡县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140430000000, '沁县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140431000000, '沁源县', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140471000000, '山西长治高新技术产业园区', 3, 140400000000); +INSERT INTO `zz_area_code` VALUES (140500000000, '晋城市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140501000000, '市辖区', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140502000000, '城区', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140521000000, '沁水县', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140522000000, '阳城县', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140524000000, '陵川县', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140525000000, '泽州县', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140581000000, '高平市', 3, 140500000000); +INSERT INTO `zz_area_code` VALUES (140600000000, '朔州市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140601000000, '市辖区', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140602000000, '朔城区', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140603000000, '平鲁区', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140621000000, '山阴县', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140622000000, '应县', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140623000000, '右玉县', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140671000000, '山西朔州经济开发区', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140681000000, '怀仁市', 3, 140600000000); +INSERT INTO `zz_area_code` VALUES (140700000000, '晋中市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140701000000, '市辖区', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140702000000, '榆次区', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140721000000, '榆社县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140722000000, '左权县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140723000000, '和顺县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140724000000, '昔阳县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140725000000, '寿阳县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140726000000, '太谷县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140727000000, '祁县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140728000000, '平遥县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140729000000, '灵石县', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140781000000, '介休市', 3, 140700000000); +INSERT INTO `zz_area_code` VALUES (140800000000, '运城市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140801000000, '市辖区', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140802000000, '盐湖区', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140821000000, '临猗县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140822000000, '万荣县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140823000000, '闻喜县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140824000000, '稷山县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140825000000, '新绛县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140826000000, '绛县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140827000000, '垣曲县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140828000000, '夏县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140829000000, '平陆县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140830000000, '芮城县', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140881000000, '永济市', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140882000000, '河津市', 3, 140800000000); +INSERT INTO `zz_area_code` VALUES (140900000000, '忻州市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (140901000000, '市辖区', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140902000000, '忻府区', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140921000000, '定襄县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140922000000, '五台县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140923000000, '代县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140924000000, '繁峙县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140925000000, '宁武县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140926000000, '静乐县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140927000000, '神池县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140928000000, '五寨县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140929000000, '岢岚县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140930000000, '河曲县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140931000000, '保德县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140932000000, '偏关县', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140971000000, '五台山风景名胜区', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (140981000000, '原平市', 3, 140900000000); +INSERT INTO `zz_area_code` VALUES (141000000000, '临汾市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (141001000000, '市辖区', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141002000000, '尧都区', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141021000000, '曲沃县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141022000000, '翼城县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141023000000, '襄汾县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141024000000, '洪洞县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141025000000, '古县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141026000000, '安泽县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141027000000, '浮山县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141028000000, '吉县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141029000000, '乡宁县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141030000000, '大宁县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141031000000, '隰县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141032000000, '永和县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141033000000, '蒲县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141034000000, '汾西县', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141081000000, '侯马市', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141082000000, '霍州市', 3, 141000000000); +INSERT INTO `zz_area_code` VALUES (141100000000, '吕梁市', 2, 140000000000); +INSERT INTO `zz_area_code` VALUES (141101000000, '市辖区', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141102000000, '离石区', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141121000000, '文水县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141122000000, '交城县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141123000000, '兴县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141124000000, '临县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141125000000, '柳林县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141126000000, '石楼县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141127000000, '岚县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141128000000, '方山县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141129000000, '中阳县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141130000000, '交口县', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141181000000, '孝义市', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (141182000000, '汾阳市', 3, 141100000000); +INSERT INTO `zz_area_code` VALUES (150000000000, '内蒙古自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (150100000000, '呼和浩特市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150101000000, '市辖区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150102000000, '新城区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150103000000, '回民区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150104000000, '玉泉区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150105000000, '赛罕区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150121000000, '土默特左旗', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150122000000, '托克托县', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150123000000, '和林格尔县', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150124000000, '清水河县', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150125000000, '武川县', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150171000000, '呼和浩特金海工业园区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150172000000, '呼和浩特经济技术开发区', 3, 150100000000); +INSERT INTO `zz_area_code` VALUES (150200000000, '包头市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150201000000, '市辖区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150202000000, '东河区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150203000000, '昆都仑区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150204000000, '青山区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150205000000, '石拐区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150206000000, '白云鄂博矿区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150207000000, '九原区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150221000000, '土默特右旗', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150222000000, '固阳县', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150223000000, '达尔罕茂明安联合旗', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150271000000, '包头稀土高新技术产业开发区', 3, 150200000000); +INSERT INTO `zz_area_code` VALUES (150300000000, '乌海市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150301000000, '市辖区', 3, 150300000000); +INSERT INTO `zz_area_code` VALUES (150302000000, '海勃湾区', 3, 150300000000); +INSERT INTO `zz_area_code` VALUES (150303000000, '海南区', 3, 150300000000); +INSERT INTO `zz_area_code` VALUES (150304000000, '乌达区', 3, 150300000000); +INSERT INTO `zz_area_code` VALUES (150400000000, '赤峰市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150401000000, '市辖区', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150402000000, '红山区', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150403000000, '元宝山区', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150404000000, '松山区', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150421000000, '阿鲁科尔沁旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150422000000, '巴林左旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150423000000, '巴林右旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150424000000, '林西县', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150425000000, '克什克腾旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150426000000, '翁牛特旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150428000000, '喀喇沁旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150429000000, '宁城县', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150430000000, '敖汉旗', 3, 150400000000); +INSERT INTO `zz_area_code` VALUES (150500000000, '通辽市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150501000000, '市辖区', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150502000000, '科尔沁区', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150521000000, '科尔沁左翼中旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150522000000, '科尔沁左翼后旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150523000000, '开鲁县', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150524000000, '库伦旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150525000000, '奈曼旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150526000000, '扎鲁特旗', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150571000000, '通辽经济技术开发区', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150581000000, '霍林郭勒市', 3, 150500000000); +INSERT INTO `zz_area_code` VALUES (150600000000, '鄂尔多斯市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150601000000, '市辖区', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150602000000, '东胜区', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150603000000, '康巴什区', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150621000000, '达拉特旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150622000000, '准格尔旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150623000000, '鄂托克前旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150624000000, '鄂托克旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150625000000, '杭锦旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150626000000, '乌审旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150627000000, '伊金霍洛旗', 3, 150600000000); +INSERT INTO `zz_area_code` VALUES (150700000000, '呼伦贝尔市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150701000000, '市辖区', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150702000000, '海拉尔区', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150703000000, '扎赉诺尔区', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150721000000, '阿荣旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150722000000, '莫力达瓦达斡尔族自治旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150723000000, '鄂伦春自治旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150724000000, '鄂温克族自治旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150725000000, '陈巴尔虎旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150726000000, '新巴尔虎左旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150727000000, '新巴尔虎右旗', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150781000000, '满洲里市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150782000000, '牙克石市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150783000000, '扎兰屯市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150784000000, '额尔古纳市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150785000000, '根河市', 3, 150700000000); +INSERT INTO `zz_area_code` VALUES (150800000000, '巴彦淖尔市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150801000000, '市辖区', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150802000000, '临河区', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150821000000, '五原县', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150822000000, '磴口县', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150823000000, '乌拉特前旗', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150824000000, '乌拉特中旗', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150825000000, '乌拉特后旗', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150826000000, '杭锦后旗', 3, 150800000000); +INSERT INTO `zz_area_code` VALUES (150900000000, '乌兰察布市', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (150901000000, '市辖区', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150902000000, '集宁区', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150921000000, '卓资县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150922000000, '化德县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150923000000, '商都县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150924000000, '兴和县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150925000000, '凉城县', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150926000000, '察哈尔右翼前旗', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150927000000, '察哈尔右翼中旗', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150928000000, '察哈尔右翼后旗', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150929000000, '四子王旗', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (150981000000, '丰镇市', 3, 150900000000); +INSERT INTO `zz_area_code` VALUES (152200000000, '兴安盟', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (152201000000, '乌兰浩特市', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152202000000, '阿尔山市', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152221000000, '科尔沁右翼前旗', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152222000000, '科尔沁右翼中旗', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152223000000, '扎赉特旗', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152224000000, '突泉县', 3, 152200000000); +INSERT INTO `zz_area_code` VALUES (152500000000, '锡林郭勒盟', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (152501000000, '二连浩特市', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152502000000, '锡林浩特市', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152522000000, '阿巴嘎旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152523000000, '苏尼特左旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152524000000, '苏尼特右旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152525000000, '东乌珠穆沁旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152526000000, '西乌珠穆沁旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152527000000, '太仆寺旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152528000000, '镶黄旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152529000000, '正镶白旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152530000000, '正蓝旗', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152531000000, '多伦县', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152571000000, '乌拉盖管委会', 3, 152500000000); +INSERT INTO `zz_area_code` VALUES (152900000000, '阿拉善盟', 2, 150000000000); +INSERT INTO `zz_area_code` VALUES (152921000000, '阿拉善左旗', 3, 152900000000); +INSERT INTO `zz_area_code` VALUES (152922000000, '阿拉善右旗', 3, 152900000000); +INSERT INTO `zz_area_code` VALUES (152923000000, '额济纳旗', 3, 152900000000); +INSERT INTO `zz_area_code` VALUES (152971000000, '内蒙古阿拉善经济开发区', 3, 152900000000); +INSERT INTO `zz_area_code` VALUES (210000000000, '辽宁省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (210100000000, '沈阳市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210101000000, '市辖区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210102000000, '和平区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210103000000, '沈河区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210104000000, '大东区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210105000000, '皇姑区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210106000000, '铁西区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210111000000, '苏家屯区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210112000000, '浑南区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210113000000, '沈北新区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210114000000, '于洪区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210115000000, '辽中区', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210123000000, '康平县', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210124000000, '法库县', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210181000000, '新民市', 3, 210100000000); +INSERT INTO `zz_area_code` VALUES (210200000000, '大连市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210201000000, '市辖区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210202000000, '中山区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210203000000, '西岗区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210204000000, '沙河口区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210211000000, '甘井子区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210212000000, '旅顺口区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210213000000, '金州区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210214000000, '普兰店区', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210224000000, '长海县', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210281000000, '瓦房店市', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210283000000, '庄河市', 3, 210200000000); +INSERT INTO `zz_area_code` VALUES (210300000000, '鞍山市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210301000000, '市辖区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210302000000, '铁东区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210303000000, '铁西区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210304000000, '立山区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210311000000, '千山区', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210321000000, '台安县', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210323000000, '岫岩满族自治县', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210381000000, '海城市', 3, 210300000000); +INSERT INTO `zz_area_code` VALUES (210400000000, '抚顺市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210401000000, '市辖区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210402000000, '新抚区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210403000000, '东洲区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210404000000, '望花区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210411000000, '顺城区', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210421000000, '抚顺县', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210422000000, '新宾满族自治县', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210423000000, '清原满族自治县', 3, 210400000000); +INSERT INTO `zz_area_code` VALUES (210500000000, '本溪市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210501000000, '市辖区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210502000000, '平山区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210503000000, '溪湖区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210504000000, '明山区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210505000000, '南芬区', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210521000000, '本溪满族自治县', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210522000000, '桓仁满族自治县', 3, 210500000000); +INSERT INTO `zz_area_code` VALUES (210600000000, '丹东市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210601000000, '市辖区', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210602000000, '元宝区', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210603000000, '振兴区', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210604000000, '振安区', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210624000000, '宽甸满族自治县', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210681000000, '东港市', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210682000000, '凤城市', 3, 210600000000); +INSERT INTO `zz_area_code` VALUES (210700000000, '锦州市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210701000000, '市辖区', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210702000000, '古塔区', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210703000000, '凌河区', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210711000000, '太和区', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210726000000, '黑山县', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210727000000, '义县', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210781000000, '凌海市', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210782000000, '北镇市', 3, 210700000000); +INSERT INTO `zz_area_code` VALUES (210800000000, '营口市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210801000000, '市辖区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210802000000, '站前区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210803000000, '西市区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210804000000, '鲅鱼圈区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210811000000, '老边区', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210881000000, '盖州市', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210882000000, '大石桥市', 3, 210800000000); +INSERT INTO `zz_area_code` VALUES (210900000000, '阜新市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (210901000000, '市辖区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210902000000, '海州区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210903000000, '新邱区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210904000000, '太平区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210905000000, '清河门区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210911000000, '细河区', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210921000000, '阜新蒙古族自治县', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (210922000000, '彰武县', 3, 210900000000); +INSERT INTO `zz_area_code` VALUES (211000000000, '辽阳市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211001000000, '市辖区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211002000000, '白塔区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211003000000, '文圣区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211004000000, '宏伟区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211005000000, '弓长岭区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211011000000, '太子河区', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211021000000, '辽阳县', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211081000000, '灯塔市', 3, 211000000000); +INSERT INTO `zz_area_code` VALUES (211100000000, '盘锦市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211101000000, '市辖区', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211102000000, '双台子区', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211103000000, '兴隆台区', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211104000000, '大洼区', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211122000000, '盘山县', 3, 211100000000); +INSERT INTO `zz_area_code` VALUES (211200000000, '铁岭市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211201000000, '市辖区', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211202000000, '银州区', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211204000000, '清河区', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211221000000, '铁岭县', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211223000000, '西丰县', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211224000000, '昌图县', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211281000000, '调兵山市', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211282000000, '开原市', 3, 211200000000); +INSERT INTO `zz_area_code` VALUES (211300000000, '朝阳市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211301000000, '市辖区', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211302000000, '双塔区', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211303000000, '龙城区', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211321000000, '朝阳县', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211322000000, '建平县', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211324000000, '喀喇沁左翼蒙古族自治县', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211381000000, '北票市', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211382000000, '凌源市', 3, 211300000000); +INSERT INTO `zz_area_code` VALUES (211400000000, '葫芦岛市', 2, 210000000000); +INSERT INTO `zz_area_code` VALUES (211401000000, '市辖区', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211402000000, '连山区', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211403000000, '龙港区', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211404000000, '南票区', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211421000000, '绥中县', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211422000000, '建昌县', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (211481000000, '兴城市', 3, 211400000000); +INSERT INTO `zz_area_code` VALUES (220000000000, '吉林省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (220100000000, '长春市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220101000000, '市辖区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220102000000, '南关区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220103000000, '宽城区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220104000000, '朝阳区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220105000000, '二道区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220106000000, '绿园区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220112000000, '双阳区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220113000000, '九台区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220122000000, '农安县', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220171000000, '长春经济技术开发区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220172000000, '长春净月高新技术产业开发区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220173000000, '长春高新技术产业开发区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220174000000, '长春汽车经济技术开发区', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220182000000, '榆树市', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220183000000, '德惠市', 3, 220100000000); +INSERT INTO `zz_area_code` VALUES (220200000000, '吉林市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220201000000, '市辖区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220202000000, '昌邑区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220203000000, '龙潭区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220204000000, '船营区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220211000000, '丰满区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220221000000, '永吉县', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220271000000, '吉林经济开发区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220272000000, '吉林高新技术产业开发区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220273000000, '吉林中国新加坡食品区', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220281000000, '蛟河市', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220282000000, '桦甸市', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220283000000, '舒兰市', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220284000000, '磐石市', 3, 220200000000); +INSERT INTO `zz_area_code` VALUES (220300000000, '四平市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220301000000, '市辖区', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220302000000, '铁西区', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220303000000, '铁东区', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220322000000, '梨树县', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220323000000, '伊通满族自治县', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220381000000, '公主岭市', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220382000000, '双辽市', 3, 220300000000); +INSERT INTO `zz_area_code` VALUES (220400000000, '辽源市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220401000000, '市辖区', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220402000000, '龙山区', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220403000000, '西安区', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220421000000, '东丰县', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220422000000, '东辽县', 3, 220400000000); +INSERT INTO `zz_area_code` VALUES (220500000000, '通化市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220501000000, '市辖区', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220502000000, '东昌区', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220503000000, '二道江区', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220521000000, '通化县', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220523000000, '辉南县', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220524000000, '柳河县', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220581000000, '梅河口市', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220582000000, '集安市', 3, 220500000000); +INSERT INTO `zz_area_code` VALUES (220600000000, '白山市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220601000000, '市辖区', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220602000000, '浑江区', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220605000000, '江源区', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220621000000, '抚松县', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220622000000, '靖宇县', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220623000000, '长白朝鲜族自治县', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220681000000, '临江市', 3, 220600000000); +INSERT INTO `zz_area_code` VALUES (220700000000, '松原市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220701000000, '市辖区', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220702000000, '宁江区', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220721000000, '前郭尔罗斯蒙古族自治县', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220722000000, '长岭县', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220723000000, '乾安县', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220771000000, '吉林松原经济开发区', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220781000000, '扶余市', 3, 220700000000); +INSERT INTO `zz_area_code` VALUES (220800000000, '白城市', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (220801000000, '市辖区', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220802000000, '洮北区', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220821000000, '镇赉县', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220822000000, '通榆县', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220871000000, '吉林白城经济开发区', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220881000000, '洮南市', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (220882000000, '大安市', 3, 220800000000); +INSERT INTO `zz_area_code` VALUES (222400000000, '延边朝鲜族自治州', 2, 220000000000); +INSERT INTO `zz_area_code` VALUES (222401000000, '延吉市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222402000000, '图们市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222403000000, '敦化市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222404000000, '珲春市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222405000000, '龙井市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222406000000, '和龙市', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222424000000, '汪清县', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (222426000000, '安图县', 3, 222400000000); +INSERT INTO `zz_area_code` VALUES (230000000000, '黑龙江省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (230100000000, '哈尔滨市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230101000000, '市辖区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230102000000, '道里区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230103000000, '南岗区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230104000000, '道外区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230108000000, '平房区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230109000000, '松北区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230110000000, '香坊区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230111000000, '呼兰区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230112000000, '阿城区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230113000000, '双城区', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230123000000, '依兰县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230124000000, '方正县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230125000000, '宾县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230126000000, '巴彦县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230127000000, '木兰县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230128000000, '通河县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230129000000, '延寿县', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230183000000, '尚志市', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230184000000, '五常市', 3, 230100000000); +INSERT INTO `zz_area_code` VALUES (230200000000, '齐齐哈尔市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230201000000, '市辖区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230202000000, '龙沙区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230203000000, '建华区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230204000000, '铁锋区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230205000000, '昂昂溪区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230206000000, '富拉尔基区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230207000000, '碾子山区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230208000000, '梅里斯达斡尔族区', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230221000000, '龙江县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230223000000, '依安县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230224000000, '泰来县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230225000000, '甘南县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230227000000, '富裕县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230229000000, '克山县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230230000000, '克东县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230231000000, '拜泉县', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230281000000, '讷河市', 3, 230200000000); +INSERT INTO `zz_area_code` VALUES (230300000000, '鸡西市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230301000000, '市辖区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230302000000, '鸡冠区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230303000000, '恒山区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230304000000, '滴道区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230305000000, '梨树区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230306000000, '城子河区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230307000000, '麻山区', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230321000000, '鸡东县', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230381000000, '虎林市', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230382000000, '密山市', 3, 230300000000); +INSERT INTO `zz_area_code` VALUES (230400000000, '鹤岗市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230401000000, '市辖区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230402000000, '向阳区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230403000000, '工农区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230404000000, '南山区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230405000000, '兴安区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230406000000, '东山区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230407000000, '兴山区', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230421000000, '萝北县', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230422000000, '绥滨县', 3, 230400000000); +INSERT INTO `zz_area_code` VALUES (230500000000, '双鸭山市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230501000000, '市辖区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230502000000, '尖山区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230503000000, '岭东区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230505000000, '四方台区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230506000000, '宝山区', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230521000000, '集贤县', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230522000000, '友谊县', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230523000000, '宝清县', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230524000000, '饶河县', 3, 230500000000); +INSERT INTO `zz_area_code` VALUES (230600000000, '大庆市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230601000000, '市辖区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230602000000, '萨尔图区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230603000000, '龙凤区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230604000000, '让胡路区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230605000000, '红岗区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230606000000, '大同区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230621000000, '肇州县', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230622000000, '肇源县', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230623000000, '林甸县', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230624000000, '杜尔伯特蒙古族自治县', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230671000000, '大庆高新技术产业开发区', 3, 230600000000); +INSERT INTO `zz_area_code` VALUES (230700000000, '伊春市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230701000000, '市辖区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230702000000, '伊春区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230703000000, '南岔区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230704000000, '友好区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230705000000, '西林区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230706000000, '翠峦区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230707000000, '新青区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230708000000, '美溪区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230709000000, '金山屯区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230710000000, '五营区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230711000000, '乌马河区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230712000000, '汤旺河区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230713000000, '带岭区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230714000000, '乌伊岭区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230715000000, '红星区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230716000000, '上甘岭区', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230722000000, '嘉荫县', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230781000000, '铁力市', 3, 230700000000); +INSERT INTO `zz_area_code` VALUES (230800000000, '佳木斯市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230801000000, '市辖区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230803000000, '向阳区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230804000000, '前进区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230805000000, '东风区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230811000000, '郊区', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230822000000, '桦南县', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230826000000, '桦川县', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230828000000, '汤原县', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230881000000, '同江市', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230882000000, '富锦市', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230883000000, '抚远市', 3, 230800000000); +INSERT INTO `zz_area_code` VALUES (230900000000, '七台河市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (230901000000, '市辖区', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (230902000000, '新兴区', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (230903000000, '桃山区', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (230904000000, '茄子河区', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (230921000000, '勃利县', 3, 230900000000); +INSERT INTO `zz_area_code` VALUES (231000000000, '牡丹江市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (231001000000, '市辖区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231002000000, '东安区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231003000000, '阳明区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231004000000, '爱民区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231005000000, '西安区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231025000000, '林口县', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231071000000, '牡丹江经济技术开发区', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231081000000, '绥芬河市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231083000000, '海林市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231084000000, '宁安市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231085000000, '穆棱市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231086000000, '东宁市', 3, 231000000000); +INSERT INTO `zz_area_code` VALUES (231100000000, '黑河市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (231101000000, '市辖区', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231102000000, '爱辉区', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231121000000, '嫩江县', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231123000000, '逊克县', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231124000000, '孙吴县', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231181000000, '北安市', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231182000000, '五大连池市', 3, 231100000000); +INSERT INTO `zz_area_code` VALUES (231200000000, '绥化市', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (231201000000, '市辖区', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231202000000, '北林区', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231221000000, '望奎县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231222000000, '兰西县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231223000000, '青冈县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231224000000, '庆安县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231225000000, '明水县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231226000000, '绥棱县', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231281000000, '安达市', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231282000000, '肇东市', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (231283000000, '海伦市', 3, 231200000000); +INSERT INTO `zz_area_code` VALUES (232700000000, '大兴安岭地区', 2, 230000000000); +INSERT INTO `zz_area_code` VALUES (232701000000, '漠河市', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232721000000, '呼玛县', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232722000000, '塔河县', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232761000000, '加格达奇区', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232762000000, '松岭区', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232763000000, '新林区', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (232764000000, '呼中区', 3, 232700000000); +INSERT INTO `zz_area_code` VALUES (310000000000, '上海市', 1, NULL); +INSERT INTO `zz_area_code` VALUES (310100000000, '市辖区', 2, 310000000000); +INSERT INTO `zz_area_code` VALUES (310101000000, '黄浦区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310104000000, '徐汇区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310105000000, '长宁区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310106000000, '静安区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310107000000, '普陀区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310109000000, '虹口区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310110000000, '杨浦区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310112000000, '闵行区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310113000000, '宝山区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310114000000, '嘉定区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310115000000, '浦东新区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310116000000, '金山区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310117000000, '松江区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310118000000, '青浦区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310120000000, '奉贤区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (310151000000, '崇明区', 3, 310100000000); +INSERT INTO `zz_area_code` VALUES (320000000000, '江苏省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (320100000000, '南京市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320101000000, '市辖区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320102000000, '玄武区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320104000000, '秦淮区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320105000000, '建邺区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320106000000, '鼓楼区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320111000000, '浦口区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320113000000, '栖霞区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320114000000, '雨花台区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320115000000, '江宁区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320116000000, '六合区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320117000000, '溧水区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320118000000, '高淳区', 3, 320100000000); +INSERT INTO `zz_area_code` VALUES (320200000000, '无锡市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320201000000, '市辖区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320205000000, '锡山区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320206000000, '惠山区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320211000000, '滨湖区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320213000000, '梁溪区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320214000000, '新吴区', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320281000000, '江阴市', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320282000000, '宜兴市', 3, 320200000000); +INSERT INTO `zz_area_code` VALUES (320300000000, '徐州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320301000000, '市辖区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320302000000, '鼓楼区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320303000000, '云龙区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320305000000, '贾汪区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320311000000, '泉山区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320312000000, '铜山区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320321000000, '丰县', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320322000000, '沛县', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320324000000, '睢宁县', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320371000000, '徐州经济技术开发区', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320381000000, '新沂市', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320382000000, '邳州市', 3, 320300000000); +INSERT INTO `zz_area_code` VALUES (320400000000, '常州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320401000000, '市辖区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320402000000, '天宁区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320404000000, '钟楼区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320411000000, '新北区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320412000000, '武进区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320413000000, '金坛区', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320481000000, '溧阳市', 3, 320400000000); +INSERT INTO `zz_area_code` VALUES (320500000000, '苏州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320501000000, '市辖区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320505000000, '虎丘区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320506000000, '吴中区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320507000000, '相城区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320508000000, '姑苏区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320509000000, '吴江区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320571000000, '苏州工业园区', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320581000000, '常熟市', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320582000000, '张家港市', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320583000000, '昆山市', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320585000000, '太仓市', 3, 320500000000); +INSERT INTO `zz_area_code` VALUES (320600000000, '南通市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320601000000, '市辖区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320602000000, '崇川区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320611000000, '港闸区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320612000000, '通州区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320623000000, '如东县', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320671000000, '南通经济技术开发区', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320681000000, '启东市', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320682000000, '如皋市', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320684000000, '海门市', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320685000000, '海安市', 3, 320600000000); +INSERT INTO `zz_area_code` VALUES (320700000000, '连云港市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320701000000, '市辖区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320703000000, '连云区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320706000000, '海州区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320707000000, '赣榆区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320722000000, '东海县', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320723000000, '灌云县', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320724000000, '灌南县', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320771000000, '连云港经济技术开发区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320772000000, '连云港高新技术产业开发区', 3, 320700000000); +INSERT INTO `zz_area_code` VALUES (320800000000, '淮安市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320801000000, '市辖区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320803000000, '淮安区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320804000000, '淮阴区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320812000000, '清江浦区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320813000000, '洪泽区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320826000000, '涟水县', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320830000000, '盱眙县', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320831000000, '金湖县', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320871000000, '淮安经济技术开发区', 3, 320800000000); +INSERT INTO `zz_area_code` VALUES (320900000000, '盐城市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (320901000000, '市辖区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320902000000, '亭湖区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320903000000, '盐都区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320904000000, '大丰区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320921000000, '响水县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320922000000, '滨海县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320923000000, '阜宁县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320924000000, '射阳县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320925000000, '建湖县', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320971000000, '盐城经济技术开发区', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (320981000000, '东台市', 3, 320900000000); +INSERT INTO `zz_area_code` VALUES (321000000000, '扬州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (321001000000, '市辖区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321002000000, '广陵区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321003000000, '邗江区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321012000000, '江都区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321023000000, '宝应县', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321071000000, '扬州经济技术开发区', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321081000000, '仪征市', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321084000000, '高邮市', 3, 321000000000); +INSERT INTO `zz_area_code` VALUES (321100000000, '镇江市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (321101000000, '市辖区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321102000000, '京口区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321111000000, '润州区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321112000000, '丹徒区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321171000000, '镇江新区', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321181000000, '丹阳市', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321182000000, '扬中市', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321183000000, '句容市', 3, 321100000000); +INSERT INTO `zz_area_code` VALUES (321200000000, '泰州市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (321201000000, '市辖区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321202000000, '海陵区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321203000000, '高港区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321204000000, '姜堰区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321271000000, '泰州医药高新技术产业开发区', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321281000000, '兴化市', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321282000000, '靖江市', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321283000000, '泰兴市', 3, 321200000000); +INSERT INTO `zz_area_code` VALUES (321300000000, '宿迁市', 2, 320000000000); +INSERT INTO `zz_area_code` VALUES (321301000000, '市辖区', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321302000000, '宿城区', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321311000000, '宿豫区', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321322000000, '沭阳县', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321323000000, '泗阳县', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321324000000, '泗洪县', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (321371000000, '宿迁经济技术开发区', 3, 321300000000); +INSERT INTO `zz_area_code` VALUES (330000000000, '浙江省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (330100000000, '杭州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330101000000, '市辖区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330102000000, '上城区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330103000000, '下城区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330104000000, '江干区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330105000000, '拱墅区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330106000000, '西湖区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330108000000, '滨江区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330109000000, '萧山区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330110000000, '余杭区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330111000000, '富阳区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330112000000, '临安区', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330122000000, '桐庐县', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330127000000, '淳安县', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330182000000, '建德市', 3, 330100000000); +INSERT INTO `zz_area_code` VALUES (330200000000, '宁波市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330201000000, '市辖区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330203000000, '海曙区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330205000000, '江北区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330206000000, '北仑区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330211000000, '镇海区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330212000000, '鄞州区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330213000000, '奉化区', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330225000000, '象山县', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330226000000, '宁海县', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330281000000, '余姚市', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330282000000, '慈溪市', 3, 330200000000); +INSERT INTO `zz_area_code` VALUES (330300000000, '温州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330301000000, '市辖区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330302000000, '鹿城区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330303000000, '龙湾区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330304000000, '瓯海区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330305000000, '洞头区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330324000000, '永嘉县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330326000000, '平阳县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330327000000, '苍南县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330328000000, '文成县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330329000000, '泰顺县', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330371000000, '温州经济技术开发区', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330381000000, '瑞安市', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330382000000, '乐清市', 3, 330300000000); +INSERT INTO `zz_area_code` VALUES (330400000000, '嘉兴市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330401000000, '市辖区', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330402000000, '南湖区', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330411000000, '秀洲区', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330421000000, '嘉善县', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330424000000, '海盐县', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330481000000, '海宁市', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330482000000, '平湖市', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330483000000, '桐乡市', 3, 330400000000); +INSERT INTO `zz_area_code` VALUES (330500000000, '湖州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330501000000, '市辖区', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330502000000, '吴兴区', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330503000000, '南浔区', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330521000000, '德清县', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330522000000, '长兴县', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330523000000, '安吉县', 3, 330500000000); +INSERT INTO `zz_area_code` VALUES (330600000000, '绍兴市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330601000000, '市辖区', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330602000000, '越城区', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330603000000, '柯桥区', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330604000000, '上虞区', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330624000000, '新昌县', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330681000000, '诸暨市', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330683000000, '嵊州市', 3, 330600000000); +INSERT INTO `zz_area_code` VALUES (330700000000, '金华市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330701000000, '市辖区', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330702000000, '婺城区', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330703000000, '金东区', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330723000000, '武义县', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330726000000, '浦江县', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330727000000, '磐安县', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330781000000, '兰溪市', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330782000000, '义乌市', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330783000000, '东阳市', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330784000000, '永康市', 3, 330700000000); +INSERT INTO `zz_area_code` VALUES (330800000000, '衢州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330801000000, '市辖区', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330802000000, '柯城区', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330803000000, '衢江区', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330822000000, '常山县', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330824000000, '开化县', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330825000000, '龙游县', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330881000000, '江山市', 3, 330800000000); +INSERT INTO `zz_area_code` VALUES (330900000000, '舟山市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (330901000000, '市辖区', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (330902000000, '定海区', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (330903000000, '普陀区', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (330921000000, '岱山县', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (330922000000, '嵊泗县', 3, 330900000000); +INSERT INTO `zz_area_code` VALUES (331000000000, '台州市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (331001000000, '市辖区', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331002000000, '椒江区', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331003000000, '黄岩区', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331004000000, '路桥区', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331022000000, '三门县', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331023000000, '天台县', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331024000000, '仙居县', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331081000000, '温岭市', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331082000000, '临海市', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331083000000, '玉环市', 3, 331000000000); +INSERT INTO `zz_area_code` VALUES (331100000000, '丽水市', 2, 330000000000); +INSERT INTO `zz_area_code` VALUES (331101000000, '市辖区', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331102000000, '莲都区', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331121000000, '青田县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331122000000, '缙云县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331123000000, '遂昌县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331124000000, '松阳县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331125000000, '云和县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331126000000, '庆元县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331127000000, '景宁畲族自治县', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (331181000000, '龙泉市', 3, 331100000000); +INSERT INTO `zz_area_code` VALUES (340000000000, '安徽省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (340100000000, '合肥市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340101000000, '市辖区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340102000000, '瑶海区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340103000000, '庐阳区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340104000000, '蜀山区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340111000000, '包河区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340121000000, '长丰县', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340122000000, '肥东县', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340123000000, '肥西县', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340124000000, '庐江县', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340171000000, '合肥高新技术产业开发区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340172000000, '合肥经济技术开发区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340173000000, '合肥新站高新技术产业开发区', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340181000000, '巢湖市', 3, 340100000000); +INSERT INTO `zz_area_code` VALUES (340200000000, '芜湖市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340201000000, '市辖区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340202000000, '镜湖区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340203000000, '弋江区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340207000000, '鸠江区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340208000000, '三山区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340221000000, '芜湖县', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340222000000, '繁昌县', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340223000000, '南陵县', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340225000000, '无为县', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340271000000, '芜湖经济技术开发区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340272000000, '安徽芜湖长江大桥经济开发区', 3, 340200000000); +INSERT INTO `zz_area_code` VALUES (340300000000, '蚌埠市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340301000000, '市辖区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340302000000, '龙子湖区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340303000000, '蚌山区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340304000000, '禹会区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340311000000, '淮上区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340321000000, '怀远县', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340322000000, '五河县', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340323000000, '固镇县', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340371000000, '蚌埠市高新技术开发区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340372000000, '蚌埠市经济开发区', 3, 340300000000); +INSERT INTO `zz_area_code` VALUES (340400000000, '淮南市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340401000000, '市辖区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340402000000, '大通区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340403000000, '田家庵区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340404000000, '谢家集区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340405000000, '八公山区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340406000000, '潘集区', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340421000000, '凤台县', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340422000000, '寿县', 3, 340400000000); +INSERT INTO `zz_area_code` VALUES (340500000000, '马鞍山市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340501000000, '市辖区', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340503000000, '花山区', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340504000000, '雨山区', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340506000000, '博望区', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340521000000, '当涂县', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340522000000, '含山县', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340523000000, '和县', 3, 340500000000); +INSERT INTO `zz_area_code` VALUES (340600000000, '淮北市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340601000000, '市辖区', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340602000000, '杜集区', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340603000000, '相山区', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340604000000, '烈山区', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340621000000, '濉溪县', 3, 340600000000); +INSERT INTO `zz_area_code` VALUES (340700000000, '铜陵市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340701000000, '市辖区', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340705000000, '铜官区', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340706000000, '义安区', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340711000000, '郊区', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340722000000, '枞阳县', 3, 340700000000); +INSERT INTO `zz_area_code` VALUES (340800000000, '安庆市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (340801000000, '市辖区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340802000000, '迎江区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340803000000, '大观区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340811000000, '宜秀区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340822000000, '怀宁县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340825000000, '太湖县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340826000000, '宿松县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340827000000, '望江县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340828000000, '岳西县', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340871000000, '安徽安庆经济开发区', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340881000000, '桐城市', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (340882000000, '潜山市', 3, 340800000000); +INSERT INTO `zz_area_code` VALUES (341000000000, '黄山市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341001000000, '市辖区', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341002000000, '屯溪区', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341003000000, '黄山区', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341004000000, '徽州区', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341021000000, '歙县', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341022000000, '休宁县', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341023000000, '黟县', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341024000000, '祁门县', 3, 341000000000); +INSERT INTO `zz_area_code` VALUES (341100000000, '滁州市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341101000000, '市辖区', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341102000000, '琅琊区', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341103000000, '南谯区', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341122000000, '来安县', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341124000000, '全椒县', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341125000000, '定远县', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341126000000, '凤阳县', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341171000000, '苏滁现代产业园', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341172000000, '滁州经济技术开发区', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341181000000, '天长市', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341182000000, '明光市', 3, 341100000000); +INSERT INTO `zz_area_code` VALUES (341200000000, '阜阳市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341201000000, '市辖区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341202000000, '颍州区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341203000000, '颍东区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341204000000, '颍泉区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341221000000, '临泉县', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341222000000, '太和县', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341225000000, '阜南县', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341226000000, '颍上县', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341271000000, '阜阳合肥现代产业园区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341272000000, '阜阳经济技术开发区', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341282000000, '界首市', 3, 341200000000); +INSERT INTO `zz_area_code` VALUES (341300000000, '宿州市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341301000000, '市辖区', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341302000000, '埇桥区', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341321000000, '砀山县', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341322000000, '萧县', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341323000000, '灵璧县', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341324000000, '泗县', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341371000000, '宿州马鞍山现代产业园区', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341372000000, '宿州经济技术开发区', 3, 341300000000); +INSERT INTO `zz_area_code` VALUES (341500000000, '六安市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341501000000, '市辖区', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341502000000, '金安区', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341503000000, '裕安区', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341504000000, '叶集区', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341522000000, '霍邱县', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341523000000, '舒城县', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341524000000, '金寨县', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341525000000, '霍山县', 3, 341500000000); +INSERT INTO `zz_area_code` VALUES (341600000000, '亳州市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341601000000, '市辖区', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341602000000, '谯城区', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341621000000, '涡阳县', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341622000000, '蒙城县', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341623000000, '利辛县', 3, 341600000000); +INSERT INTO `zz_area_code` VALUES (341700000000, '池州市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341701000000, '市辖区', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341702000000, '贵池区', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341721000000, '东至县', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341722000000, '石台县', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341723000000, '青阳县', 3, 341700000000); +INSERT INTO `zz_area_code` VALUES (341800000000, '宣城市', 2, 340000000000); +INSERT INTO `zz_area_code` VALUES (341801000000, '市辖区', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341802000000, '宣州区', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341821000000, '郎溪县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341822000000, '广德县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341823000000, '泾县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341824000000, '绩溪县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341825000000, '旌德县', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341871000000, '宣城市经济开发区', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (341881000000, '宁国市', 3, 341800000000); +INSERT INTO `zz_area_code` VALUES (350000000000, '福建省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (350100000000, '福州市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350101000000, '市辖区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350102000000, '鼓楼区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350103000000, '台江区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350104000000, '仓山区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350105000000, '马尾区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350111000000, '晋安区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350112000000, '长乐区', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350121000000, '闽侯县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350122000000, '连江县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350123000000, '罗源县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350124000000, '闽清县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350125000000, '永泰县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350128000000, '平潭县', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350181000000, '福清市', 3, 350100000000); +INSERT INTO `zz_area_code` VALUES (350200000000, '厦门市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350201000000, '市辖区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350203000000, '思明区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350205000000, '海沧区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350206000000, '湖里区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350211000000, '集美区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350212000000, '同安区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350213000000, '翔安区', 3, 350200000000); +INSERT INTO `zz_area_code` VALUES (350300000000, '莆田市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350301000000, '市辖区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350302000000, '城厢区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350303000000, '涵江区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350304000000, '荔城区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350305000000, '秀屿区', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350322000000, '仙游县', 3, 350300000000); +INSERT INTO `zz_area_code` VALUES (350400000000, '三明市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350401000000, '市辖区', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350402000000, '梅列区', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350403000000, '三元区', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350421000000, '明溪县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350423000000, '清流县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350424000000, '宁化县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350425000000, '大田县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350426000000, '尤溪县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350427000000, '沙县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350428000000, '将乐县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350429000000, '泰宁县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350430000000, '建宁县', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350481000000, '永安市', 3, 350400000000); +INSERT INTO `zz_area_code` VALUES (350500000000, '泉州市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350501000000, '市辖区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350502000000, '鲤城区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350503000000, '丰泽区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350504000000, '洛江区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350505000000, '泉港区', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350521000000, '惠安县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350524000000, '安溪县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350525000000, '永春县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350526000000, '德化县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350527000000, '金门县', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350581000000, '石狮市', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350582000000, '晋江市', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350583000000, '南安市', 3, 350500000000); +INSERT INTO `zz_area_code` VALUES (350600000000, '漳州市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350601000000, '市辖区', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350602000000, '芗城区', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350603000000, '龙文区', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350622000000, '云霄县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350623000000, '漳浦县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350624000000, '诏安县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350625000000, '长泰县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350626000000, '东山县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350627000000, '南靖县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350628000000, '平和县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350629000000, '华安县', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350681000000, '龙海市', 3, 350600000000); +INSERT INTO `zz_area_code` VALUES (350700000000, '南平市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350701000000, '市辖区', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350702000000, '延平区', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350703000000, '建阳区', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350721000000, '顺昌县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350722000000, '浦城县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350723000000, '光泽县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350724000000, '松溪县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350725000000, '政和县', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350781000000, '邵武市', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350782000000, '武夷山市', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350783000000, '建瓯市', 3, 350700000000); +INSERT INTO `zz_area_code` VALUES (350800000000, '龙岩市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350801000000, '市辖区', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350802000000, '新罗区', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350803000000, '永定区', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350821000000, '长汀县', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350823000000, '上杭县', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350824000000, '武平县', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350825000000, '连城县', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350881000000, '漳平市', 3, 350800000000); +INSERT INTO `zz_area_code` VALUES (350900000000, '宁德市', 2, 350000000000); +INSERT INTO `zz_area_code` VALUES (350901000000, '市辖区', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350902000000, '蕉城区', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350921000000, '霞浦县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350922000000, '古田县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350923000000, '屏南县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350924000000, '寿宁县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350925000000, '周宁县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350926000000, '柘荣县', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350981000000, '福安市', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (350982000000, '福鼎市', 3, 350900000000); +INSERT INTO `zz_area_code` VALUES (360000000000, '江西省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (360100000000, '南昌市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360101000000, '市辖区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360102000000, '东湖区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360103000000, '西湖区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360104000000, '青云谱区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360105000000, '湾里区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360111000000, '青山湖区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360112000000, '新建区', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360121000000, '南昌县', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360123000000, '安义县', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360124000000, '进贤县', 3, 360100000000); +INSERT INTO `zz_area_code` VALUES (360200000000, '景德镇市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360201000000, '市辖区', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360202000000, '昌江区', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360203000000, '珠山区', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360222000000, '浮梁县', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360281000000, '乐平市', 3, 360200000000); +INSERT INTO `zz_area_code` VALUES (360300000000, '萍乡市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360301000000, '市辖区', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360302000000, '安源区', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360313000000, '湘东区', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360321000000, '莲花县', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360322000000, '上栗县', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360323000000, '芦溪县', 3, 360300000000); +INSERT INTO `zz_area_code` VALUES (360400000000, '九江市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360401000000, '市辖区', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360402000000, '濂溪区', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360403000000, '浔阳区', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360404000000, '柴桑区', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360423000000, '武宁县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360424000000, '修水县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360425000000, '永修县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360426000000, '德安县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360428000000, '都昌县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360429000000, '湖口县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360430000000, '彭泽县', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360481000000, '瑞昌市', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360482000000, '共青城市', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360483000000, '庐山市', 3, 360400000000); +INSERT INTO `zz_area_code` VALUES (360500000000, '新余市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360501000000, '市辖区', 3, 360500000000); +INSERT INTO `zz_area_code` VALUES (360502000000, '渝水区', 3, 360500000000); +INSERT INTO `zz_area_code` VALUES (360521000000, '分宜县', 3, 360500000000); +INSERT INTO `zz_area_code` VALUES (360600000000, '鹰潭市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360601000000, '市辖区', 3, 360600000000); +INSERT INTO `zz_area_code` VALUES (360602000000, '月湖区', 3, 360600000000); +INSERT INTO `zz_area_code` VALUES (360603000000, '余江区', 3, 360600000000); +INSERT INTO `zz_area_code` VALUES (360681000000, '贵溪市', 3, 360600000000); +INSERT INTO `zz_area_code` VALUES (360700000000, '赣州市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360701000000, '市辖区', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360702000000, '章贡区', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360703000000, '南康区', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360704000000, '赣县区', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360722000000, '信丰县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360723000000, '大余县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360724000000, '上犹县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360725000000, '崇义县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360726000000, '安远县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360727000000, '龙南县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360728000000, '定南县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360729000000, '全南县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360730000000, '宁都县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360731000000, '于都县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360732000000, '兴国县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360733000000, '会昌县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360734000000, '寻乌县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360735000000, '石城县', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360781000000, '瑞金市', 3, 360700000000); +INSERT INTO `zz_area_code` VALUES (360800000000, '吉安市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360801000000, '市辖区', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360802000000, '吉州区', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360803000000, '青原区', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360821000000, '吉安县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360822000000, '吉水县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360823000000, '峡江县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360824000000, '新干县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360825000000, '永丰县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360826000000, '泰和县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360827000000, '遂川县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360828000000, '万安县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360829000000, '安福县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360830000000, '永新县', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360881000000, '井冈山市', 3, 360800000000); +INSERT INTO `zz_area_code` VALUES (360900000000, '宜春市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (360901000000, '市辖区', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360902000000, '袁州区', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360921000000, '奉新县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360922000000, '万载县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360923000000, '上高县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360924000000, '宜丰县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360925000000, '靖安县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360926000000, '铜鼓县', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360981000000, '丰城市', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360982000000, '樟树市', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (360983000000, '高安市', 3, 360900000000); +INSERT INTO `zz_area_code` VALUES (361000000000, '抚州市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (361001000000, '市辖区', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361002000000, '临川区', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361003000000, '东乡区', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361021000000, '南城县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361022000000, '黎川县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361023000000, '南丰县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361024000000, '崇仁县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361025000000, '乐安县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361026000000, '宜黄县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361027000000, '金溪县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361028000000, '资溪县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361030000000, '广昌县', 3, 361000000000); +INSERT INTO `zz_area_code` VALUES (361100000000, '上饶市', 2, 360000000000); +INSERT INTO `zz_area_code` VALUES (361101000000, '市辖区', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361102000000, '信州区', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361103000000, '广丰区', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361121000000, '上饶县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361123000000, '玉山县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361124000000, '铅山县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361125000000, '横峰县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361126000000, '弋阳县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361127000000, '余干县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361128000000, '鄱阳县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361129000000, '万年县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361130000000, '婺源县', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (361181000000, '德兴市', 3, 361100000000); +INSERT INTO `zz_area_code` VALUES (370000000000, '山东省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (370100000000, '济南市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370101000000, '市辖区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370102000000, '历下区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370103000000, '市中区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370104000000, '槐荫区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370105000000, '天桥区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370112000000, '历城区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370113000000, '长清区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370114000000, '章丘区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370115000000, '济阳区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370124000000, '平阴县', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370126000000, '商河县', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370171000000, '济南高新技术产业开发区', 3, 370100000000); +INSERT INTO `zz_area_code` VALUES (370200000000, '青岛市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370201000000, '市辖区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370202000000, '市南区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370203000000, '市北区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370211000000, '黄岛区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370212000000, '崂山区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370213000000, '李沧区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370214000000, '城阳区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370215000000, '即墨区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370271000000, '青岛高新技术产业开发区', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370281000000, '胶州市', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370283000000, '平度市', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370285000000, '莱西市', 3, 370200000000); +INSERT INTO `zz_area_code` VALUES (370300000000, '淄博市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370301000000, '市辖区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370302000000, '淄川区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370303000000, '张店区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370304000000, '博山区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370305000000, '临淄区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370306000000, '周村区', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370321000000, '桓台县', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370322000000, '高青县', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370323000000, '沂源县', 3, 370300000000); +INSERT INTO `zz_area_code` VALUES (370400000000, '枣庄市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370401000000, '市辖区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370402000000, '市中区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370403000000, '薛城区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370404000000, '峄城区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370405000000, '台儿庄区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370406000000, '山亭区', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370481000000, '滕州市', 3, 370400000000); +INSERT INTO `zz_area_code` VALUES (370500000000, '东营市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370501000000, '市辖区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370502000000, '东营区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370503000000, '河口区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370505000000, '垦利区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370522000000, '利津县', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370523000000, '广饶县', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370571000000, '东营经济技术开发区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370572000000, '东营港经济开发区', 3, 370500000000); +INSERT INTO `zz_area_code` VALUES (370600000000, '烟台市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370601000000, '市辖区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370602000000, '芝罘区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370611000000, '福山区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370612000000, '牟平区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370613000000, '莱山区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370634000000, '长岛县', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370671000000, '烟台高新技术产业开发区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370672000000, '烟台经济技术开发区', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370681000000, '龙口市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370682000000, '莱阳市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370683000000, '莱州市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370684000000, '蓬莱市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370685000000, '招远市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370686000000, '栖霞市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370687000000, '海阳市', 3, 370600000000); +INSERT INTO `zz_area_code` VALUES (370700000000, '潍坊市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370701000000, '市辖区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370702000000, '潍城区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370703000000, '寒亭区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370704000000, '坊子区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370705000000, '奎文区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370724000000, '临朐县', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370725000000, '昌乐县', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370772000000, '潍坊滨海经济技术开发区', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370781000000, '青州市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370782000000, '诸城市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370783000000, '寿光市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370784000000, '安丘市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370785000000, '高密市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370786000000, '昌邑市', 3, 370700000000); +INSERT INTO `zz_area_code` VALUES (370800000000, '济宁市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370801000000, '市辖区', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370811000000, '任城区', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370812000000, '兖州区', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370826000000, '微山县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370827000000, '鱼台县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370828000000, '金乡县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370829000000, '嘉祥县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370830000000, '汶上县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370831000000, '泗水县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370832000000, '梁山县', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370871000000, '济宁高新技术产业开发区', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370881000000, '曲阜市', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370883000000, '邹城市', 3, 370800000000); +INSERT INTO `zz_area_code` VALUES (370900000000, '泰安市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (370901000000, '市辖区', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370902000000, '泰山区', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370911000000, '岱岳区', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370921000000, '宁阳县', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370923000000, '东平县', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370982000000, '新泰市', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (370983000000, '肥城市', 3, 370900000000); +INSERT INTO `zz_area_code` VALUES (371000000000, '威海市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371001000000, '市辖区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371002000000, '环翠区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371003000000, '文登区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371071000000, '威海火炬高技术产业开发区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371072000000, '威海经济技术开发区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371073000000, '威海临港经济技术开发区', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371082000000, '荣成市', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371083000000, '乳山市', 3, 371000000000); +INSERT INTO `zz_area_code` VALUES (371100000000, '日照市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371101000000, '市辖区', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371102000000, '东港区', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371103000000, '岚山区', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371121000000, '五莲县', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371122000000, '莒县', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371171000000, '日照经济技术开发区', 3, 371100000000); +INSERT INTO `zz_area_code` VALUES (371200000000, '莱芜市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371201000000, '市辖区', 3, 371200000000); +INSERT INTO `zz_area_code` VALUES (371202000000, '莱城区', 3, 371200000000); +INSERT INTO `zz_area_code` VALUES (371203000000, '钢城区', 3, 371200000000); +INSERT INTO `zz_area_code` VALUES (371300000000, '临沂市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371301000000, '市辖区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371302000000, '兰山区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371311000000, '罗庄区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371312000000, '河东区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371321000000, '沂南县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371322000000, '郯城县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371323000000, '沂水县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371324000000, '兰陵县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371325000000, '费县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371326000000, '平邑县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371327000000, '莒南县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371328000000, '蒙阴县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371329000000, '临沭县', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371371000000, '临沂高新技术产业开发区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371372000000, '临沂经济技术开发区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371373000000, '临沂临港经济开发区', 3, 371300000000); +INSERT INTO `zz_area_code` VALUES (371400000000, '德州市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371401000000, '市辖区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371402000000, '德城区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371403000000, '陵城区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371422000000, '宁津县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371423000000, '庆云县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371424000000, '临邑县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371425000000, '齐河县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371426000000, '平原县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371427000000, '夏津县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371428000000, '武城县', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371471000000, '德州经济技术开发区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371472000000, '德州运河经济开发区', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371481000000, '乐陵市', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371482000000, '禹城市', 3, 371400000000); +INSERT INTO `zz_area_code` VALUES (371500000000, '聊城市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371501000000, '市辖区', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371502000000, '东昌府区', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371521000000, '阳谷县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371522000000, '莘县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371523000000, '茌平县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371524000000, '东阿县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371525000000, '冠县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371526000000, '高唐县', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371581000000, '临清市', 3, 371500000000); +INSERT INTO `zz_area_code` VALUES (371600000000, '滨州市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371601000000, '市辖区', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371602000000, '滨城区', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371603000000, '沾化区', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371621000000, '惠民县', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371622000000, '阳信县', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371623000000, '无棣县', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371625000000, '博兴县', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371681000000, '邹平市', 3, 371600000000); +INSERT INTO `zz_area_code` VALUES (371700000000, '菏泽市', 2, 370000000000); +INSERT INTO `zz_area_code` VALUES (371701000000, '市辖区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371702000000, '牡丹区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371703000000, '定陶区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371721000000, '曹县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371722000000, '单县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371723000000, '成武县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371724000000, '巨野县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371725000000, '郓城县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371726000000, '鄄城县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371728000000, '东明县', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371771000000, '菏泽经济技术开发区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (371772000000, '菏泽高新技术开发区', 3, 371700000000); +INSERT INTO `zz_area_code` VALUES (410000000000, '河南省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (410100000000, '郑州市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410101000000, '市辖区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410102000000, '中原区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410103000000, '二七区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410104000000, '管城回族区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410105000000, '金水区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410106000000, '上街区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410108000000, '惠济区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410122000000, '中牟县', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410171000000, '郑州经济技术开发区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410172000000, '郑州高新技术产业开发区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410173000000, '郑州航空港经济综合实验区', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410181000000, '巩义市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410182000000, '荥阳市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410183000000, '新密市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410184000000, '新郑市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410185000000, '登封市', 3, 410100000000); +INSERT INTO `zz_area_code` VALUES (410200000000, '开封市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410201000000, '市辖区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410202000000, '龙亭区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410203000000, '顺河回族区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410204000000, '鼓楼区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410205000000, '禹王台区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410212000000, '祥符区', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410221000000, '杞县', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410222000000, '通许县', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410223000000, '尉氏县', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410225000000, '兰考县', 3, 410200000000); +INSERT INTO `zz_area_code` VALUES (410300000000, '洛阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410301000000, '市辖区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410302000000, '老城区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410303000000, '西工区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410304000000, '瀍河回族区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410305000000, '涧西区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410306000000, '吉利区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410311000000, '洛龙区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410322000000, '孟津县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410323000000, '新安县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410324000000, '栾川县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410325000000, '嵩县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410326000000, '汝阳县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410327000000, '宜阳县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410328000000, '洛宁县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410329000000, '伊川县', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410371000000, '洛阳高新技术产业开发区', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410381000000, '偃师市', 3, 410300000000); +INSERT INTO `zz_area_code` VALUES (410400000000, '平顶山市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410401000000, '市辖区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410402000000, '新华区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410403000000, '卫东区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410404000000, '石龙区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410411000000, '湛河区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410421000000, '宝丰县', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410422000000, '叶县', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410423000000, '鲁山县', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410425000000, '郏县', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410471000000, '平顶山高新技术产业开发区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410472000000, '平顶山市新城区', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410481000000, '舞钢市', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410482000000, '汝州市', 3, 410400000000); +INSERT INTO `zz_area_code` VALUES (410500000000, '安阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410501000000, '市辖区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410502000000, '文峰区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410503000000, '北关区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410505000000, '殷都区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410506000000, '龙安区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410522000000, '安阳县', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410523000000, '汤阴县', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410526000000, '滑县', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410527000000, '内黄县', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410571000000, '安阳高新技术产业开发区', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410581000000, '林州市', 3, 410500000000); +INSERT INTO `zz_area_code` VALUES (410600000000, '鹤壁市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410601000000, '市辖区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410602000000, '鹤山区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410603000000, '山城区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410611000000, '淇滨区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410621000000, '浚县', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410622000000, '淇县', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410671000000, '鹤壁经济技术开发区', 3, 410600000000); +INSERT INTO `zz_area_code` VALUES (410700000000, '新乡市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410701000000, '市辖区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410702000000, '红旗区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410703000000, '卫滨区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410704000000, '凤泉区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410711000000, '牧野区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410721000000, '新乡县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410724000000, '获嘉县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410725000000, '原阳县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410726000000, '延津县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410727000000, '封丘县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410728000000, '长垣县', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410771000000, '新乡高新技术产业开发区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410772000000, '新乡经济技术开发区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410773000000, '新乡市平原城乡一体化示范区', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410781000000, '卫辉市', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410782000000, '辉县市', 3, 410700000000); +INSERT INTO `zz_area_code` VALUES (410800000000, '焦作市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410801000000, '市辖区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410802000000, '解放区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410803000000, '中站区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410804000000, '马村区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410811000000, '山阳区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410821000000, '修武县', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410822000000, '博爱县', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410823000000, '武陟县', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410825000000, '温县', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410871000000, '焦作城乡一体化示范区', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410882000000, '沁阳市', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410883000000, '孟州市', 3, 410800000000); +INSERT INTO `zz_area_code` VALUES (410900000000, '濮阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (410901000000, '市辖区', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410902000000, '华龙区', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410922000000, '清丰县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410923000000, '南乐县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410926000000, '范县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410927000000, '台前县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410928000000, '濮阳县', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410971000000, '河南濮阳工业园区', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (410972000000, '濮阳经济技术开发区', 3, 410900000000); +INSERT INTO `zz_area_code` VALUES (411000000000, '许昌市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411001000000, '市辖区', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411002000000, '魏都区', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411003000000, '建安区', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411024000000, '鄢陵县', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411025000000, '襄城县', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411071000000, '许昌经济技术开发区', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411081000000, '禹州市', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411082000000, '长葛市', 3, 411000000000); +INSERT INTO `zz_area_code` VALUES (411100000000, '漯河市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411101000000, '市辖区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411102000000, '源汇区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411103000000, '郾城区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411104000000, '召陵区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411121000000, '舞阳县', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411122000000, '临颍县', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411171000000, '漯河经济技术开发区', 3, 411100000000); +INSERT INTO `zz_area_code` VALUES (411200000000, '三门峡市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411201000000, '市辖区', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411202000000, '湖滨区', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411203000000, '陕州区', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411221000000, '渑池县', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411224000000, '卢氏县', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411271000000, '河南三门峡经济开发区', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411281000000, '义马市', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411282000000, '灵宝市', 3, 411200000000); +INSERT INTO `zz_area_code` VALUES (411300000000, '南阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411301000000, '市辖区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411302000000, '宛城区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411303000000, '卧龙区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411321000000, '南召县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411322000000, '方城县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411323000000, '西峡县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411324000000, '镇平县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411325000000, '内乡县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411326000000, '淅川县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411327000000, '社旗县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411328000000, '唐河县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411329000000, '新野县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411330000000, '桐柏县', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411371000000, '南阳高新技术产业开发区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411372000000, '南阳市城乡一体化示范区', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411381000000, '邓州市', 3, 411300000000); +INSERT INTO `zz_area_code` VALUES (411400000000, '商丘市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411401000000, '市辖区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411402000000, '梁园区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411403000000, '睢阳区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411421000000, '民权县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411422000000, '睢县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411423000000, '宁陵县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411424000000, '柘城县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411425000000, '虞城县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411426000000, '夏邑县', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411471000000, '豫东综合物流产业聚集区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411472000000, '河南商丘经济开发区', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411481000000, '永城市', 3, 411400000000); +INSERT INTO `zz_area_code` VALUES (411500000000, '信阳市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411501000000, '市辖区', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411502000000, '浉河区', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411503000000, '平桥区', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411521000000, '罗山县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411522000000, '光山县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411523000000, '新县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411524000000, '商城县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411525000000, '固始县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411526000000, '潢川县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411527000000, '淮滨县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411528000000, '息县', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411571000000, '信阳高新技术产业开发区', 3, 411500000000); +INSERT INTO `zz_area_code` VALUES (411600000000, '周口市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411601000000, '市辖区', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411602000000, '川汇区', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411621000000, '扶沟县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411622000000, '西华县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411623000000, '商水县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411624000000, '沈丘县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411625000000, '郸城县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411626000000, '淮阳县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411627000000, '太康县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411628000000, '鹿邑县', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411671000000, '河南周口经济开发区', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411681000000, '项城市', 3, 411600000000); +INSERT INTO `zz_area_code` VALUES (411700000000, '驻马店市', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (411701000000, '市辖区', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411702000000, '驿城区', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411721000000, '西平县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411722000000, '上蔡县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411723000000, '平舆县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411724000000, '正阳县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411725000000, '确山县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411726000000, '泌阳县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411727000000, '汝南县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411728000000, '遂平县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411729000000, '新蔡县', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (411771000000, '河南驻马店经济开发区', 3, 411700000000); +INSERT INTO `zz_area_code` VALUES (419000000000, '省直辖县级行政区划', 2, 410000000000); +INSERT INTO `zz_area_code` VALUES (419001000000, '济源市', 3, 419000000000); +INSERT INTO `zz_area_code` VALUES (420000000000, '湖北省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (420100000000, '武汉市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420101000000, '市辖区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420102000000, '江岸区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420103000000, '江汉区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420104000000, '硚口区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420105000000, '汉阳区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420106000000, '武昌区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420107000000, '青山区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420111000000, '洪山区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420112000000, '东西湖区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420113000000, '汉南区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420114000000, '蔡甸区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420115000000, '江夏区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420116000000, '黄陂区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420117000000, '新洲区', 3, 420100000000); +INSERT INTO `zz_area_code` VALUES (420200000000, '黄石市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420201000000, '市辖区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420202000000, '黄石港区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420203000000, '西塞山区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420204000000, '下陆区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420205000000, '铁山区', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420222000000, '阳新县', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420281000000, '大冶市', 3, 420200000000); +INSERT INTO `zz_area_code` VALUES (420300000000, '十堰市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420301000000, '市辖区', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420302000000, '茅箭区', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420303000000, '张湾区', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420304000000, '郧阳区', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420322000000, '郧西县', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420323000000, '竹山县', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420324000000, '竹溪县', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420325000000, '房县', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420381000000, '丹江口市', 3, 420300000000); +INSERT INTO `zz_area_code` VALUES (420500000000, '宜昌市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420501000000, '市辖区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420502000000, '西陵区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420503000000, '伍家岗区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420504000000, '点军区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420505000000, '猇亭区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420506000000, '夷陵区', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420525000000, '远安县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420526000000, '兴山县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420527000000, '秭归县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420528000000, '长阳土家族自治县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420529000000, '五峰土家族自治县', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420581000000, '宜都市', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420582000000, '当阳市', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420583000000, '枝江市', 3, 420500000000); +INSERT INTO `zz_area_code` VALUES (420600000000, '襄阳市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420601000000, '市辖区', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420602000000, '襄城区', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420606000000, '樊城区', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420607000000, '襄州区', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420624000000, '南漳县', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420625000000, '谷城县', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420626000000, '保康县', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420682000000, '老河口市', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420683000000, '枣阳市', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420684000000, '宜城市', 3, 420600000000); +INSERT INTO `zz_area_code` VALUES (420700000000, '鄂州市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420701000000, '市辖区', 3, 420700000000); +INSERT INTO `zz_area_code` VALUES (420702000000, '梁子湖区', 3, 420700000000); +INSERT INTO `zz_area_code` VALUES (420703000000, '华容区', 3, 420700000000); +INSERT INTO `zz_area_code` VALUES (420704000000, '鄂城区', 3, 420700000000); +INSERT INTO `zz_area_code` VALUES (420800000000, '荆门市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420801000000, '市辖区', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420802000000, '东宝区', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420804000000, '掇刀区', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420822000000, '沙洋县', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420881000000, '钟祥市', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420882000000, '京山市', 3, 420800000000); +INSERT INTO `zz_area_code` VALUES (420900000000, '孝感市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (420901000000, '市辖区', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420902000000, '孝南区', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420921000000, '孝昌县', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420922000000, '大悟县', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420923000000, '云梦县', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420981000000, '应城市', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420982000000, '安陆市', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (420984000000, '汉川市', 3, 420900000000); +INSERT INTO `zz_area_code` VALUES (421000000000, '荆州市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (421001000000, '市辖区', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421002000000, '沙市区', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421003000000, '荆州区', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421022000000, '公安县', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421023000000, '监利县', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421024000000, '江陵县', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421071000000, '荆州经济技术开发区', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421081000000, '石首市', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421083000000, '洪湖市', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421087000000, '松滋市', 3, 421000000000); +INSERT INTO `zz_area_code` VALUES (421100000000, '黄冈市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (421101000000, '市辖区', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421102000000, '黄州区', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421121000000, '团风县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421122000000, '红安县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421123000000, '罗田县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421124000000, '英山县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421125000000, '浠水县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421126000000, '蕲春县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421127000000, '黄梅县', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421171000000, '龙感湖管理区', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421181000000, '麻城市', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421182000000, '武穴市', 3, 421100000000); +INSERT INTO `zz_area_code` VALUES (421200000000, '咸宁市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (421201000000, '市辖区', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421202000000, '咸安区', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421221000000, '嘉鱼县', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421222000000, '通城县', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421223000000, '崇阳县', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421224000000, '通山县', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421281000000, '赤壁市', 3, 421200000000); +INSERT INTO `zz_area_code` VALUES (421300000000, '随州市', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (421301000000, '市辖区', 3, 421300000000); +INSERT INTO `zz_area_code` VALUES (421303000000, '曾都区', 3, 421300000000); +INSERT INTO `zz_area_code` VALUES (421321000000, '随县', 3, 421300000000); +INSERT INTO `zz_area_code` VALUES (421381000000, '广水市', 3, 421300000000); +INSERT INTO `zz_area_code` VALUES (422800000000, '恩施土家族苗族自治州', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (422801000000, '恩施市', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422802000000, '利川市', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422822000000, '建始县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422823000000, '巴东县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422825000000, '宣恩县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422826000000, '咸丰县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422827000000, '来凤县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (422828000000, '鹤峰县', 3, 422800000000); +INSERT INTO `zz_area_code` VALUES (429000000000, '省直辖县级行政区划', 2, 420000000000); +INSERT INTO `zz_area_code` VALUES (429004000000, '仙桃市', 3, 429000000000); +INSERT INTO `zz_area_code` VALUES (429005000000, '潜江市', 3, 429000000000); +INSERT INTO `zz_area_code` VALUES (429006000000, '天门市', 3, 429000000000); +INSERT INTO `zz_area_code` VALUES (429021000000, '神农架林区', 3, 429000000000); +INSERT INTO `zz_area_code` VALUES (430000000000, '湖南省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (430100000000, '长沙市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430101000000, '市辖区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430102000000, '芙蓉区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430103000000, '天心区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430104000000, '岳麓区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430105000000, '开福区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430111000000, '雨花区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430112000000, '望城区', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430121000000, '长沙县', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430181000000, '浏阳市', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430182000000, '宁乡市', 3, 430100000000); +INSERT INTO `zz_area_code` VALUES (430200000000, '株洲市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430201000000, '市辖区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430202000000, '荷塘区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430203000000, '芦淞区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430204000000, '石峰区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430211000000, '天元区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430212000000, '渌口区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430223000000, '攸县', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430224000000, '茶陵县', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430225000000, '炎陵县', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430271000000, '云龙示范区', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430281000000, '醴陵市', 3, 430200000000); +INSERT INTO `zz_area_code` VALUES (430300000000, '湘潭市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430301000000, '市辖区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430302000000, '雨湖区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430304000000, '岳塘区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430321000000, '湘潭县', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430371000000, '湖南湘潭高新技术产业园区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430372000000, '湘潭昭山示范区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430373000000, '湘潭九华示范区', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430381000000, '湘乡市', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430382000000, '韶山市', 3, 430300000000); +INSERT INTO `zz_area_code` VALUES (430400000000, '衡阳市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430401000000, '市辖区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430405000000, '珠晖区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430406000000, '雁峰区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430407000000, '石鼓区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430408000000, '蒸湘区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430412000000, '南岳区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430421000000, '衡阳县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430422000000, '衡南县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430423000000, '衡山县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430424000000, '衡东县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430426000000, '祁东县', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430471000000, '衡阳综合保税区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430472000000, '湖南衡阳高新技术产业园区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430473000000, '湖南衡阳松木经济开发区', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430481000000, '耒阳市', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430482000000, '常宁市', 3, 430400000000); +INSERT INTO `zz_area_code` VALUES (430500000000, '邵阳市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430501000000, '市辖区', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430502000000, '双清区', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430503000000, '大祥区', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430511000000, '北塔区', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430521000000, '邵东县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430522000000, '新邵县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430523000000, '邵阳县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430524000000, '隆回县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430525000000, '洞口县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430527000000, '绥宁县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430528000000, '新宁县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430529000000, '城步苗族自治县', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430581000000, '武冈市', 3, 430500000000); +INSERT INTO `zz_area_code` VALUES (430600000000, '岳阳市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430601000000, '市辖区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430602000000, '岳阳楼区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430603000000, '云溪区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430611000000, '君山区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430621000000, '岳阳县', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430623000000, '华容县', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430624000000, '湘阴县', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430626000000, '平江县', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430671000000, '岳阳市屈原管理区', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430681000000, '汨罗市', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430682000000, '临湘市', 3, 430600000000); +INSERT INTO `zz_area_code` VALUES (430700000000, '常德市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430701000000, '市辖区', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430702000000, '武陵区', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430703000000, '鼎城区', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430721000000, '安乡县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430722000000, '汉寿县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430723000000, '澧县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430724000000, '临澧县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430725000000, '桃源县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430726000000, '石门县', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430771000000, '常德市西洞庭管理区', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430781000000, '津市市', 3, 430700000000); +INSERT INTO `zz_area_code` VALUES (430800000000, '张家界市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430801000000, '市辖区', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430802000000, '永定区', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430811000000, '武陵源区', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430821000000, '慈利县', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430822000000, '桑植县', 3, 430800000000); +INSERT INTO `zz_area_code` VALUES (430900000000, '益阳市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (430901000000, '市辖区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430902000000, '资阳区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430903000000, '赫山区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430921000000, '南县', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430922000000, '桃江县', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430923000000, '安化县', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430971000000, '益阳市大通湖管理区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430972000000, '湖南益阳高新技术产业园区', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (430981000000, '沅江市', 3, 430900000000); +INSERT INTO `zz_area_code` VALUES (431000000000, '郴州市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (431001000000, '市辖区', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431002000000, '北湖区', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431003000000, '苏仙区', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431021000000, '桂阳县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431022000000, '宜章县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431023000000, '永兴县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431024000000, '嘉禾县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431025000000, '临武县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431026000000, '汝城县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431027000000, '桂东县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431028000000, '安仁县', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431081000000, '资兴市', 3, 431000000000); +INSERT INTO `zz_area_code` VALUES (431100000000, '永州市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (431101000000, '市辖区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431102000000, '零陵区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431103000000, '冷水滩区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431121000000, '祁阳县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431122000000, '东安县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431123000000, '双牌县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431124000000, '道县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431125000000, '江永县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431126000000, '宁远县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431127000000, '蓝山县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431128000000, '新田县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431129000000, '江华瑶族自治县', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431171000000, '永州经济技术开发区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431172000000, '永州市金洞管理区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431173000000, '永州市回龙圩管理区', 3, 431100000000); +INSERT INTO `zz_area_code` VALUES (431200000000, '怀化市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (431201000000, '市辖区', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431202000000, '鹤城区', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431221000000, '中方县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431222000000, '沅陵县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431223000000, '辰溪县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431224000000, '溆浦县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431225000000, '会同县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431226000000, '麻阳苗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431227000000, '新晃侗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431228000000, '芷江侗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431229000000, '靖州苗族侗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431230000000, '通道侗族自治县', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431271000000, '怀化市洪江管理区', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431281000000, '洪江市', 3, 431200000000); +INSERT INTO `zz_area_code` VALUES (431300000000, '娄底市', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (431301000000, '市辖区', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431302000000, '娄星区', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431321000000, '双峰县', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431322000000, '新化县', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431381000000, '冷水江市', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (431382000000, '涟源市', 3, 431300000000); +INSERT INTO `zz_area_code` VALUES (433100000000, '湘西土家族苗族自治州', 2, 430000000000); +INSERT INTO `zz_area_code` VALUES (433101000000, '吉首市', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433122000000, '泸溪县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433123000000, '凤凰县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433124000000, '花垣县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433125000000, '保靖县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433126000000, '古丈县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433127000000, '永顺县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433130000000, '龙山县', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433172000000, '湖南吉首经济开发区', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (433173000000, '湖南永顺经济开发区', 3, 433100000000); +INSERT INTO `zz_area_code` VALUES (440000000000, '广东省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (440100000000, '广州市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440101000000, '市辖区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440103000000, '荔湾区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440104000000, '越秀区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440105000000, '海珠区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440106000000, '天河区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440111000000, '白云区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440112000000, '黄埔区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440113000000, '番禺区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440114000000, '花都区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440115000000, '南沙区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440117000000, '从化区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440118000000, '增城区', 3, 440100000000); +INSERT INTO `zz_area_code` VALUES (440200000000, '韶关市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440201000000, '市辖区', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440203000000, '武江区', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440204000000, '浈江区', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440205000000, '曲江区', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440222000000, '始兴县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440224000000, '仁化县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440229000000, '翁源县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440232000000, '乳源瑶族自治县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440233000000, '新丰县', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440281000000, '乐昌市', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440282000000, '南雄市', 3, 440200000000); +INSERT INTO `zz_area_code` VALUES (440300000000, '深圳市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440301000000, '市辖区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440303000000, '罗湖区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440304000000, '福田区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440305000000, '南山区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440306000000, '宝安区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440307000000, '龙岗区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440308000000, '盐田区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440309000000, '龙华区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440310000000, '坪山区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440311000000, '光明区', 3, 440300000000); +INSERT INTO `zz_area_code` VALUES (440400000000, '珠海市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440401000000, '市辖区', 3, 440400000000); +INSERT INTO `zz_area_code` VALUES (440402000000, '香洲区', 3, 440400000000); +INSERT INTO `zz_area_code` VALUES (440403000000, '斗门区', 3, 440400000000); +INSERT INTO `zz_area_code` VALUES (440404000000, '金湾区', 3, 440400000000); +INSERT INTO `zz_area_code` VALUES (440500000000, '汕头市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440501000000, '市辖区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440507000000, '龙湖区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440511000000, '金平区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440512000000, '濠江区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440513000000, '潮阳区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440514000000, '潮南区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440515000000, '澄海区', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440523000000, '南澳县', 3, 440500000000); +INSERT INTO `zz_area_code` VALUES (440600000000, '佛山市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440601000000, '市辖区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440604000000, '禅城区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440605000000, '南海区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440606000000, '顺德区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440607000000, '三水区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440608000000, '高明区', 3, 440600000000); +INSERT INTO `zz_area_code` VALUES (440700000000, '江门市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440701000000, '市辖区', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440703000000, '蓬江区', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440704000000, '江海区', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440705000000, '新会区', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440781000000, '台山市', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440783000000, '开平市', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440784000000, '鹤山市', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440785000000, '恩平市', 3, 440700000000); +INSERT INTO `zz_area_code` VALUES (440800000000, '湛江市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440801000000, '市辖区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440802000000, '赤坎区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440803000000, '霞山区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440804000000, '坡头区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440811000000, '麻章区', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440823000000, '遂溪县', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440825000000, '徐闻县', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440881000000, '廉江市', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440882000000, '雷州市', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440883000000, '吴川市', 3, 440800000000); +INSERT INTO `zz_area_code` VALUES (440900000000, '茂名市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (440901000000, '市辖区', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440902000000, '茂南区', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440904000000, '电白区', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440981000000, '高州市', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440982000000, '化州市', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (440983000000, '信宜市', 3, 440900000000); +INSERT INTO `zz_area_code` VALUES (441200000000, '肇庆市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441201000000, '市辖区', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441202000000, '端州区', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441203000000, '鼎湖区', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441204000000, '高要区', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441223000000, '广宁县', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441224000000, '怀集县', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441225000000, '封开县', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441226000000, '德庆县', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441284000000, '四会市', 3, 441200000000); +INSERT INTO `zz_area_code` VALUES (441300000000, '惠州市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441301000000, '市辖区', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441302000000, '惠城区', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441303000000, '惠阳区', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441322000000, '博罗县', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441323000000, '惠东县', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441324000000, '龙门县', 3, 441300000000); +INSERT INTO `zz_area_code` VALUES (441400000000, '梅州市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441401000000, '市辖区', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441402000000, '梅江区', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441403000000, '梅县区', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441422000000, '大埔县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441423000000, '丰顺县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441424000000, '五华县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441426000000, '平远县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441427000000, '蕉岭县', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441481000000, '兴宁市', 3, 441400000000); +INSERT INTO `zz_area_code` VALUES (441500000000, '汕尾市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441501000000, '市辖区', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441502000000, '城区', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441521000000, '海丰县', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441523000000, '陆河县', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441581000000, '陆丰市', 3, 441500000000); +INSERT INTO `zz_area_code` VALUES (441600000000, '河源市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441601000000, '市辖区', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441602000000, '源城区', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441621000000, '紫金县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441622000000, '龙川县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441623000000, '连平县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441624000000, '和平县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441625000000, '东源县', 3, 441600000000); +INSERT INTO `zz_area_code` VALUES (441700000000, '阳江市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441701000000, '市辖区', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441702000000, '江城区', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441704000000, '阳东区', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441721000000, '阳西县', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441781000000, '阳春市', 3, 441700000000); +INSERT INTO `zz_area_code` VALUES (441800000000, '清远市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (441801000000, '市辖区', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441802000000, '清城区', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441803000000, '清新区', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441821000000, '佛冈县', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441823000000, '阳山县', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441825000000, '连山壮族瑶族自治县', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441826000000, '连南瑶族自治县', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441881000000, '英德市', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441882000000, '连州市', 3, 441800000000); +INSERT INTO `zz_area_code` VALUES (441900000000, '东莞市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (442000000000, '中山市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (445100000000, '潮州市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (445101000000, '市辖区', 3, 445100000000); +INSERT INTO `zz_area_code` VALUES (445102000000, '湘桥区', 3, 445100000000); +INSERT INTO `zz_area_code` VALUES (445103000000, '潮安区', 3, 445100000000); +INSERT INTO `zz_area_code` VALUES (445122000000, '饶平县', 3, 445100000000); +INSERT INTO `zz_area_code` VALUES (445200000000, '揭阳市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (445201000000, '市辖区', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445202000000, '榕城区', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445203000000, '揭东区', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445222000000, '揭西县', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445224000000, '惠来县', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445281000000, '普宁市', 3, 445200000000); +INSERT INTO `zz_area_code` VALUES (445300000000, '云浮市', 2, 440000000000); +INSERT INTO `zz_area_code` VALUES (445301000000, '市辖区', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445302000000, '云城区', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445303000000, '云安区', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445321000000, '新兴县', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445322000000, '郁南县', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (445381000000, '罗定市', 3, 445300000000); +INSERT INTO `zz_area_code` VALUES (450000000000, '广西壮族自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (450100000000, '南宁市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450101000000, '市辖区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450102000000, '兴宁区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450103000000, '青秀区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450105000000, '江南区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450107000000, '西乡塘区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450108000000, '良庆区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450109000000, '邕宁区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450110000000, '武鸣区', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450123000000, '隆安县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450124000000, '马山县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450125000000, '上林县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450126000000, '宾阳县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450127000000, '横县', 3, 450100000000); +INSERT INTO `zz_area_code` VALUES (450200000000, '柳州市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450201000000, '市辖区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450202000000, '城中区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450203000000, '鱼峰区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450204000000, '柳南区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450205000000, '柳北区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450206000000, '柳江区', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450222000000, '柳城县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450223000000, '鹿寨县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450224000000, '融安县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450225000000, '融水苗族自治县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450226000000, '三江侗族自治县', 3, 450200000000); +INSERT INTO `zz_area_code` VALUES (450300000000, '桂林市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450301000000, '市辖区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450302000000, '秀峰区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450303000000, '叠彩区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450304000000, '象山区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450305000000, '七星区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450311000000, '雁山区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450312000000, '临桂区', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450321000000, '阳朔县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450323000000, '灵川县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450324000000, '全州县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450325000000, '兴安县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450326000000, '永福县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450327000000, '灌阳县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450328000000, '龙胜各族自治县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450329000000, '资源县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450330000000, '平乐县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450332000000, '恭城瑶族自治县', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450381000000, '荔浦市', 3, 450300000000); +INSERT INTO `zz_area_code` VALUES (450400000000, '梧州市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450401000000, '市辖区', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450403000000, '万秀区', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450405000000, '长洲区', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450406000000, '龙圩区', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450421000000, '苍梧县', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450422000000, '藤县', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450423000000, '蒙山县', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450481000000, '岑溪市', 3, 450400000000); +INSERT INTO `zz_area_code` VALUES (450500000000, '北海市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450501000000, '市辖区', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450502000000, '海城区', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450503000000, '银海区', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450512000000, '铁山港区', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450521000000, '合浦县', 3, 450500000000); +INSERT INTO `zz_area_code` VALUES (450600000000, '防城港市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450601000000, '市辖区', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450602000000, '港口区', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450603000000, '防城区', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450621000000, '上思县', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450681000000, '东兴市', 3, 450600000000); +INSERT INTO `zz_area_code` VALUES (450700000000, '钦州市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450701000000, '市辖区', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450702000000, '钦南区', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450703000000, '钦北区', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450721000000, '灵山县', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450722000000, '浦北县', 3, 450700000000); +INSERT INTO `zz_area_code` VALUES (450800000000, '贵港市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450801000000, '市辖区', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450802000000, '港北区', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450803000000, '港南区', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450804000000, '覃塘区', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450821000000, '平南县', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450881000000, '桂平市', 3, 450800000000); +INSERT INTO `zz_area_code` VALUES (450900000000, '玉林市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (450901000000, '市辖区', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450902000000, '玉州区', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450903000000, '福绵区', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450921000000, '容县', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450922000000, '陆川县', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450923000000, '博白县', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450924000000, '兴业县', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (450981000000, '北流市', 3, 450900000000); +INSERT INTO `zz_area_code` VALUES (451000000000, '百色市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451001000000, '市辖区', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451002000000, '右江区', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451021000000, '田阳县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451022000000, '田东县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451023000000, '平果县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451024000000, '德保县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451026000000, '那坡县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451027000000, '凌云县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451028000000, '乐业县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451029000000, '田林县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451030000000, '西林县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451031000000, '隆林各族自治县', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451081000000, '靖西市', 3, 451000000000); +INSERT INTO `zz_area_code` VALUES (451100000000, '贺州市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451101000000, '市辖区', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451102000000, '八步区', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451103000000, '平桂区', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451121000000, '昭平县', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451122000000, '钟山县', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451123000000, '富川瑶族自治县', 3, 451100000000); +INSERT INTO `zz_area_code` VALUES (451200000000, '河池市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451201000000, '市辖区', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451202000000, '金城江区', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451203000000, '宜州区', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451221000000, '南丹县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451222000000, '天峨县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451223000000, '凤山县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451224000000, '东兰县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451225000000, '罗城仫佬族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451226000000, '环江毛南族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451227000000, '巴马瑶族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451228000000, '都安瑶族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451229000000, '大化瑶族自治县', 3, 451200000000); +INSERT INTO `zz_area_code` VALUES (451300000000, '来宾市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451301000000, '市辖区', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451302000000, '兴宾区', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451321000000, '忻城县', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451322000000, '象州县', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451323000000, '武宣县', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451324000000, '金秀瑶族自治县', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451381000000, '合山市', 3, 451300000000); +INSERT INTO `zz_area_code` VALUES (451400000000, '崇左市', 2, 450000000000); +INSERT INTO `zz_area_code` VALUES (451401000000, '市辖区', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451402000000, '江州区', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451421000000, '扶绥县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451422000000, '宁明县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451423000000, '龙州县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451424000000, '大新县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451425000000, '天等县', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (451481000000, '凭祥市', 3, 451400000000); +INSERT INTO `zz_area_code` VALUES (460000000000, '海南省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (460100000000, '海口市', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (460101000000, '市辖区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460105000000, '秀英区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460106000000, '龙华区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460107000000, '琼山区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460108000000, '美兰区', 3, 460100000000); +INSERT INTO `zz_area_code` VALUES (460200000000, '三亚市', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (460201000000, '市辖区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460202000000, '海棠区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460203000000, '吉阳区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460204000000, '天涯区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460205000000, '崖州区', 3, 460200000000); +INSERT INTO `zz_area_code` VALUES (460300000000, '三沙市', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (460321000000, '西沙群岛', 3, 460300000000); +INSERT INTO `zz_area_code` VALUES (460322000000, '南沙群岛', 3, 460300000000); +INSERT INTO `zz_area_code` VALUES (460323000000, '中沙群岛的岛礁及其海域', 3, 460300000000); +INSERT INTO `zz_area_code` VALUES (460400000000, '儋州市', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (469000000000, '省直辖县级行政区划', 2, 460000000000); +INSERT INTO `zz_area_code` VALUES (469001000000, '五指山市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469002000000, '琼海市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469005000000, '文昌市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469006000000, '万宁市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469007000000, '东方市', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469021000000, '定安县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469022000000, '屯昌县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469023000000, '澄迈县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469024000000, '临高县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469025000000, '白沙黎族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469026000000, '昌江黎族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469027000000, '乐东黎族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469028000000, '陵水黎族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469029000000, '保亭黎族苗族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (469030000000, '琼中黎族苗族自治县', 3, 469000000000); +INSERT INTO `zz_area_code` VALUES (500000000000, '重庆市', 1, NULL); +INSERT INTO `zz_area_code` VALUES (500100000000, '市辖区', 2, 500000000000); +INSERT INTO `zz_area_code` VALUES (500101000000, '万州区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500102000000, '涪陵区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500103000000, '渝中区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500104000000, '大渡口区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500105000000, '江北区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500106000000, '沙坪坝区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500107000000, '九龙坡区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500108000000, '南岸区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500109000000, '北碚区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500110000000, '綦江区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500111000000, '大足区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500112000000, '渝北区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500113000000, '巴南区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500114000000, '黔江区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500115000000, '长寿区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500116000000, '江津区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500117000000, '合川区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500118000000, '永川区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500119000000, '南川区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500120000000, '璧山区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500151000000, '铜梁区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500152000000, '潼南区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500153000000, '荣昌区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500154000000, '开州区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500155000000, '梁平区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500156000000, '武隆区', 3, 500100000000); +INSERT INTO `zz_area_code` VALUES (500200000000, '县', 2, 500000000000); +INSERT INTO `zz_area_code` VALUES (500229000000, '城口县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500230000000, '丰都县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500231000000, '垫江县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500233000000, '忠县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500235000000, '云阳县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500236000000, '奉节县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500237000000, '巫山县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500238000000, '巫溪县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500240000000, '石柱土家族自治县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500241000000, '秀山土家族苗族自治县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500242000000, '酉阳土家族苗族自治县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (500243000000, '彭水苗族土家族自治县', 3, 500200000000); +INSERT INTO `zz_area_code` VALUES (510000000000, '四川省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (510100000000, '成都市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510101000000, '市辖区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510104000000, '锦江区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510105000000, '青羊区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510106000000, '金牛区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510107000000, '武侯区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510108000000, '成华区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510112000000, '龙泉驿区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510113000000, '青白江区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510114000000, '新都区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510115000000, '温江区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510116000000, '双流区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510117000000, '郫都区', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510121000000, '金堂县', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510129000000, '大邑县', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510131000000, '蒲江县', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510132000000, '新津县', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510181000000, '都江堰市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510182000000, '彭州市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510183000000, '邛崃市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510184000000, '崇州市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510185000000, '简阳市', 3, 510100000000); +INSERT INTO `zz_area_code` VALUES (510300000000, '自贡市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510301000000, '市辖区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510302000000, '自流井区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510303000000, '贡井区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510304000000, '大安区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510311000000, '沿滩区', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510321000000, '荣县', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510322000000, '富顺县', 3, 510300000000); +INSERT INTO `zz_area_code` VALUES (510400000000, '攀枝花市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510401000000, '市辖区', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510402000000, '东区', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510403000000, '西区', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510411000000, '仁和区', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510421000000, '米易县', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510422000000, '盐边县', 3, 510400000000); +INSERT INTO `zz_area_code` VALUES (510500000000, '泸州市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510501000000, '市辖区', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510502000000, '江阳区', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510503000000, '纳溪区', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510504000000, '龙马潭区', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510521000000, '泸县', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510522000000, '合江县', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510524000000, '叙永县', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510525000000, '古蔺县', 3, 510500000000); +INSERT INTO `zz_area_code` VALUES (510600000000, '德阳市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510601000000, '市辖区', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510603000000, '旌阳区', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510604000000, '罗江区', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510623000000, '中江县', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510681000000, '广汉市', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510682000000, '什邡市', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510683000000, '绵竹市', 3, 510600000000); +INSERT INTO `zz_area_code` VALUES (510700000000, '绵阳市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510701000000, '市辖区', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510703000000, '涪城区', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510704000000, '游仙区', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510705000000, '安州区', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510722000000, '三台县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510723000000, '盐亭县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510725000000, '梓潼县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510726000000, '北川羌族自治县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510727000000, '平武县', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510781000000, '江油市', 3, 510700000000); +INSERT INTO `zz_area_code` VALUES (510800000000, '广元市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510801000000, '市辖区', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510802000000, '利州区', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510811000000, '昭化区', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510812000000, '朝天区', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510821000000, '旺苍县', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510822000000, '青川县', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510823000000, '剑阁县', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510824000000, '苍溪县', 3, 510800000000); +INSERT INTO `zz_area_code` VALUES (510900000000, '遂宁市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (510901000000, '市辖区', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510903000000, '船山区', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510904000000, '安居区', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510921000000, '蓬溪县', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510922000000, '射洪县', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (510923000000, '大英县', 3, 510900000000); +INSERT INTO `zz_area_code` VALUES (511000000000, '内江市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511001000000, '市辖区', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511002000000, '市中区', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511011000000, '东兴区', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511024000000, '威远县', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511025000000, '资中县', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511071000000, '内江经济开发区', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511083000000, '隆昌市', 3, 511000000000); +INSERT INTO `zz_area_code` VALUES (511100000000, '乐山市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511101000000, '市辖区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511102000000, '市中区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511111000000, '沙湾区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511112000000, '五通桥区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511113000000, '金口河区', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511123000000, '犍为县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511124000000, '井研县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511126000000, '夹江县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511129000000, '沐川县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511132000000, '峨边彝族自治县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511133000000, '马边彝族自治县', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511181000000, '峨眉山市', 3, 511100000000); +INSERT INTO `zz_area_code` VALUES (511300000000, '南充市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511301000000, '市辖区', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511302000000, '顺庆区', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511303000000, '高坪区', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511304000000, '嘉陵区', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511321000000, '南部县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511322000000, '营山县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511323000000, '蓬安县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511324000000, '仪陇县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511325000000, '西充县', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511381000000, '阆中市', 3, 511300000000); +INSERT INTO `zz_area_code` VALUES (511400000000, '眉山市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511401000000, '市辖区', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511402000000, '东坡区', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511403000000, '彭山区', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511421000000, '仁寿县', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511423000000, '洪雅县', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511424000000, '丹棱县', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511425000000, '青神县', 3, 511400000000); +INSERT INTO `zz_area_code` VALUES (511500000000, '宜宾市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511501000000, '市辖区', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511502000000, '翠屏区', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511503000000, '南溪区', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511504000000, '叙州区', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511523000000, '江安县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511524000000, '长宁县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511525000000, '高县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511526000000, '珙县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511527000000, '筠连县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511528000000, '兴文县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511529000000, '屏山县', 3, 511500000000); +INSERT INTO `zz_area_code` VALUES (511600000000, '广安市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511601000000, '市辖区', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511602000000, '广安区', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511603000000, '前锋区', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511621000000, '岳池县', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511622000000, '武胜县', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511623000000, '邻水县', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511681000000, '华蓥市', 3, 511600000000); +INSERT INTO `zz_area_code` VALUES (511700000000, '达州市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511701000000, '市辖区', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511702000000, '通川区', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511703000000, '达川区', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511722000000, '宣汉县', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511723000000, '开江县', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511724000000, '大竹县', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511725000000, '渠县', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511771000000, '达州经济开发区', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511781000000, '万源市', 3, 511700000000); +INSERT INTO `zz_area_code` VALUES (511800000000, '雅安市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511801000000, '市辖区', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511802000000, '雨城区', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511803000000, '名山区', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511822000000, '荥经县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511823000000, '汉源县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511824000000, '石棉县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511825000000, '天全县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511826000000, '芦山县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511827000000, '宝兴县', 3, 511800000000); +INSERT INTO `zz_area_code` VALUES (511900000000, '巴中市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (511901000000, '市辖区', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511902000000, '巴州区', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511903000000, '恩阳区', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511921000000, '通江县', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511922000000, '南江县', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511923000000, '平昌县', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (511971000000, '巴中经济开发区', 3, 511900000000); +INSERT INTO `zz_area_code` VALUES (512000000000, '资阳市', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (512001000000, '市辖区', 3, 512000000000); +INSERT INTO `zz_area_code` VALUES (512002000000, '雁江区', 3, 512000000000); +INSERT INTO `zz_area_code` VALUES (512021000000, '安岳县', 3, 512000000000); +INSERT INTO `zz_area_code` VALUES (512022000000, '乐至县', 3, 512000000000); +INSERT INTO `zz_area_code` VALUES (513200000000, '阿坝藏族羌族自治州', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (513201000000, '马尔康市', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513221000000, '汶川县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513222000000, '理县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513223000000, '茂县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513224000000, '松潘县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513225000000, '九寨沟县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513226000000, '金川县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513227000000, '小金县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513228000000, '黑水县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513230000000, '壤塘县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513231000000, '阿坝县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513232000000, '若尔盖县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513233000000, '红原县', 3, 513200000000); +INSERT INTO `zz_area_code` VALUES (513300000000, '甘孜藏族自治州', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (513301000000, '康定市', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513322000000, '泸定县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513323000000, '丹巴县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513324000000, '九龙县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513325000000, '雅江县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513326000000, '道孚县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513327000000, '炉霍县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513328000000, '甘孜县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513329000000, '新龙县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513330000000, '德格县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513331000000, '白玉县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513332000000, '石渠县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513333000000, '色达县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513334000000, '理塘县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513335000000, '巴塘县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513336000000, '乡城县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513337000000, '稻城县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513338000000, '得荣县', 3, 513300000000); +INSERT INTO `zz_area_code` VALUES (513400000000, '凉山彝族自治州', 2, 510000000000); +INSERT INTO `zz_area_code` VALUES (513401000000, '西昌市', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513422000000, '木里藏族自治县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513423000000, '盐源县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513424000000, '德昌县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513425000000, '会理县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513426000000, '会东县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513427000000, '宁南县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513428000000, '普格县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513429000000, '布拖县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513430000000, '金阳县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513431000000, '昭觉县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513432000000, '喜德县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513433000000, '冕宁县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513434000000, '越西县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513435000000, '甘洛县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513436000000, '美姑县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (513437000000, '雷波县', 3, 513400000000); +INSERT INTO `zz_area_code` VALUES (520000000000, '贵州省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (520100000000, '贵阳市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520101000000, '市辖区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520102000000, '南明区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520103000000, '云岩区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520111000000, '花溪区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520112000000, '乌当区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520113000000, '白云区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520115000000, '观山湖区', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520121000000, '开阳县', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520122000000, '息烽县', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520123000000, '修文县', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520181000000, '清镇市', 3, 520100000000); +INSERT INTO `zz_area_code` VALUES (520200000000, '六盘水市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520201000000, '钟山区', 3, 520200000000); +INSERT INTO `zz_area_code` VALUES (520203000000, '六枝特区', 3, 520200000000); +INSERT INTO `zz_area_code` VALUES (520221000000, '水城县', 3, 520200000000); +INSERT INTO `zz_area_code` VALUES (520281000000, '盘州市', 3, 520200000000); +INSERT INTO `zz_area_code` VALUES (520300000000, '遵义市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520301000000, '市辖区', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520302000000, '红花岗区', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520303000000, '汇川区', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520304000000, '播州区', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520322000000, '桐梓县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520323000000, '绥阳县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520324000000, '正安县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520325000000, '道真仡佬族苗族自治县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520326000000, '务川仡佬族苗族自治县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520327000000, '凤冈县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520328000000, '湄潭县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520329000000, '余庆县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520330000000, '习水县', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520381000000, '赤水市', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520382000000, '仁怀市', 3, 520300000000); +INSERT INTO `zz_area_code` VALUES (520400000000, '安顺市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520401000000, '市辖区', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520402000000, '西秀区', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520403000000, '平坝区', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520422000000, '普定县', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520423000000, '镇宁布依族苗族自治县', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520424000000, '关岭布依族苗族自治县', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520425000000, '紫云苗族布依族自治县', 3, 520400000000); +INSERT INTO `zz_area_code` VALUES (520500000000, '毕节市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520501000000, '市辖区', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520502000000, '七星关区', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520521000000, '大方县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520522000000, '黔西县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520523000000, '金沙县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520524000000, '织金县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520525000000, '纳雍县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520526000000, '威宁彝族回族苗族自治县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520527000000, '赫章县', 3, 520500000000); +INSERT INTO `zz_area_code` VALUES (520600000000, '铜仁市', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (520601000000, '市辖区', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520602000000, '碧江区', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520603000000, '万山区', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520621000000, '江口县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520622000000, '玉屏侗族自治县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520623000000, '石阡县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520624000000, '思南县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520625000000, '印江土家族苗族自治县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520626000000, '德江县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520627000000, '沿河土家族自治县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (520628000000, '松桃苗族自治县', 3, 520600000000); +INSERT INTO `zz_area_code` VALUES (522300000000, '黔西南布依族苗族自治州', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (522301000000, '兴义市', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522302000000, '兴仁市', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522323000000, '普安县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522324000000, '晴隆县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522325000000, '贞丰县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522326000000, '望谟县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522327000000, '册亨县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522328000000, '安龙县', 3, 522300000000); +INSERT INTO `zz_area_code` VALUES (522600000000, '黔东南苗族侗族自治州', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (522601000000, '凯里市', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522622000000, '黄平县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522623000000, '施秉县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522624000000, '三穗县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522625000000, '镇远县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522626000000, '岑巩县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522627000000, '天柱县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522628000000, '锦屏县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522629000000, '剑河县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522630000000, '台江县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522631000000, '黎平县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522632000000, '榕江县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522633000000, '从江县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522634000000, '雷山县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522635000000, '麻江县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522636000000, '丹寨县', 3, 522600000000); +INSERT INTO `zz_area_code` VALUES (522700000000, '黔南布依族苗族自治州', 2, 520000000000); +INSERT INTO `zz_area_code` VALUES (522701000000, '都匀市', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522702000000, '福泉市', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522722000000, '荔波县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522723000000, '贵定县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522725000000, '瓮安县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522726000000, '独山县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522727000000, '平塘县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522728000000, '罗甸县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522729000000, '长顺县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522730000000, '龙里县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522731000000, '惠水县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (522732000000, '三都水族自治县', 3, 522700000000); +INSERT INTO `zz_area_code` VALUES (530000000000, '云南省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (530100000000, '昆明市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530101000000, '市辖区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530102000000, '五华区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530103000000, '盘龙区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530111000000, '官渡区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530112000000, '西山区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530113000000, '东川区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530114000000, '呈贡区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530115000000, '晋宁区', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530124000000, '富民县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530125000000, '宜良县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530126000000, '石林彝族自治县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530127000000, '嵩明县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530128000000, '禄劝彝族苗族自治县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530129000000, '寻甸回族彝族自治县', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530181000000, '安宁市', 3, 530100000000); +INSERT INTO `zz_area_code` VALUES (530300000000, '曲靖市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530301000000, '市辖区', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530302000000, '麒麟区', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530303000000, '沾益区', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530304000000, '马龙区', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530322000000, '陆良县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530323000000, '师宗县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530324000000, '罗平县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530325000000, '富源县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530326000000, '会泽县', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530381000000, '宣威市', 3, 530300000000); +INSERT INTO `zz_area_code` VALUES (530400000000, '玉溪市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530401000000, '市辖区', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530402000000, '红塔区', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530403000000, '江川区', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530422000000, '澄江县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530423000000, '通海县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530424000000, '华宁县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530425000000, '易门县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530426000000, '峨山彝族自治县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530427000000, '新平彝族傣族自治县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530428000000, '元江哈尼族彝族傣族自治县', 3, 530400000000); +INSERT INTO `zz_area_code` VALUES (530500000000, '保山市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530501000000, '市辖区', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530502000000, '隆阳区', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530521000000, '施甸县', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530523000000, '龙陵县', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530524000000, '昌宁县', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530581000000, '腾冲市', 3, 530500000000); +INSERT INTO `zz_area_code` VALUES (530600000000, '昭通市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530601000000, '市辖区', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530602000000, '昭阳区', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530621000000, '鲁甸县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530622000000, '巧家县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530623000000, '盐津县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530624000000, '大关县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530625000000, '永善县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530626000000, '绥江县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530627000000, '镇雄县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530628000000, '彝良县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530629000000, '威信县', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530681000000, '水富市', 3, 530600000000); +INSERT INTO `zz_area_code` VALUES (530700000000, '丽江市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530701000000, '市辖区', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530702000000, '古城区', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530721000000, '玉龙纳西族自治县', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530722000000, '永胜县', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530723000000, '华坪县', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530724000000, '宁蒗彝族自治县', 3, 530700000000); +INSERT INTO `zz_area_code` VALUES (530800000000, '普洱市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530801000000, '市辖区', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530802000000, '思茅区', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530821000000, '宁洱哈尼族彝族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530822000000, '墨江哈尼族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530823000000, '景东彝族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530824000000, '景谷傣族彝族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530825000000, '镇沅彝族哈尼族拉祜族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530826000000, '江城哈尼族彝族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530827000000, '孟连傣族拉祜族佤族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530828000000, '澜沧拉祜族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530829000000, '西盟佤族自治县', 3, 530800000000); +INSERT INTO `zz_area_code` VALUES (530900000000, '临沧市', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (530901000000, '市辖区', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530902000000, '临翔区', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530921000000, '凤庆县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530922000000, '云县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530923000000, '永德县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530924000000, '镇康县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530925000000, '双江拉祜族佤族布朗族傣族自治县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530926000000, '耿马傣族佤族自治县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (530927000000, '沧源佤族自治县', 3, 530900000000); +INSERT INTO `zz_area_code` VALUES (532300000000, '楚雄彝族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532301000000, '楚雄市', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532322000000, '双柏县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532323000000, '牟定县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532324000000, '南华县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532325000000, '姚安县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532326000000, '大姚县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532327000000, '永仁县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532328000000, '元谋县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532329000000, '武定县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532331000000, '禄丰县', 3, 532300000000); +INSERT INTO `zz_area_code` VALUES (532500000000, '红河哈尼族彝族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532501000000, '个旧市', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532502000000, '开远市', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532503000000, '蒙自市', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532504000000, '弥勒市', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532523000000, '屏边苗族自治县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532524000000, '建水县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532525000000, '石屏县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532527000000, '泸西县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532528000000, '元阳县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532529000000, '红河县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532530000000, '金平苗族瑶族傣族自治县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532531000000, '绿春县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532532000000, '河口瑶族自治县', 3, 532500000000); +INSERT INTO `zz_area_code` VALUES (532600000000, '文山壮族苗族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532601000000, '文山市', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532622000000, '砚山县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532623000000, '西畴县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532624000000, '麻栗坡县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532625000000, '马关县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532626000000, '丘北县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532627000000, '广南县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532628000000, '富宁县', 3, 532600000000); +INSERT INTO `zz_area_code` VALUES (532800000000, '西双版纳傣族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532801000000, '景洪市', 3, 532800000000); +INSERT INTO `zz_area_code` VALUES (532822000000, '勐海县', 3, 532800000000); +INSERT INTO `zz_area_code` VALUES (532823000000, '勐腊县', 3, 532800000000); +INSERT INTO `zz_area_code` VALUES (532900000000, '大理白族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (532901000000, '大理市', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532922000000, '漾濞彝族自治县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532923000000, '祥云县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532924000000, '宾川县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532925000000, '弥渡县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532926000000, '南涧彝族自治县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532927000000, '巍山彝族回族自治县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532928000000, '永平县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532929000000, '云龙县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532930000000, '洱源县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532931000000, '剑川县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (532932000000, '鹤庆县', 3, 532900000000); +INSERT INTO `zz_area_code` VALUES (533100000000, '德宏傣族景颇族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (533102000000, '瑞丽市', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533103000000, '芒市', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533122000000, '梁河县', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533123000000, '盈江县', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533124000000, '陇川县', 3, 533100000000); +INSERT INTO `zz_area_code` VALUES (533300000000, '怒江傈僳族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (533301000000, '泸水市', 3, 533300000000); +INSERT INTO `zz_area_code` VALUES (533323000000, '福贡县', 3, 533300000000); +INSERT INTO `zz_area_code` VALUES (533324000000, '贡山独龙族怒族自治县', 3, 533300000000); +INSERT INTO `zz_area_code` VALUES (533325000000, '兰坪白族普米族自治县', 3, 533300000000); +INSERT INTO `zz_area_code` VALUES (533400000000, '迪庆藏族自治州', 2, 530000000000); +INSERT INTO `zz_area_code` VALUES (533401000000, '香格里拉市', 3, 533400000000); +INSERT INTO `zz_area_code` VALUES (533422000000, '德钦县', 3, 533400000000); +INSERT INTO `zz_area_code` VALUES (533423000000, '维西傈僳族自治县', 3, 533400000000); +INSERT INTO `zz_area_code` VALUES (540000000000, '西藏自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (540100000000, '拉萨市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540101000000, '市辖区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540102000000, '城关区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540103000000, '堆龙德庆区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540104000000, '达孜区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540121000000, '林周县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540122000000, '当雄县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540123000000, '尼木县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540124000000, '曲水县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540127000000, '墨竹工卡县', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540171000000, '格尔木藏青工业园区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540172000000, '拉萨经济技术开发区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540173000000, '西藏文化旅游创意园区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540174000000, '达孜工业园区', 3, 540100000000); +INSERT INTO `zz_area_code` VALUES (540200000000, '日喀则市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540202000000, '桑珠孜区', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540221000000, '南木林县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540222000000, '江孜县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540223000000, '定日县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540224000000, '萨迦县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540225000000, '拉孜县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540226000000, '昂仁县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540227000000, '谢通门县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540228000000, '白朗县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540229000000, '仁布县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540230000000, '康马县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540231000000, '定结县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540232000000, '仲巴县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540233000000, '亚东县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540234000000, '吉隆县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540235000000, '聂拉木县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540236000000, '萨嘎县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540237000000, '岗巴县', 3, 540200000000); +INSERT INTO `zz_area_code` VALUES (540300000000, '昌都市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540302000000, '卡若区', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540321000000, '江达县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540322000000, '贡觉县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540323000000, '类乌齐县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540324000000, '丁青县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540325000000, '察雅县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540326000000, '八宿县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540327000000, '左贡县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540328000000, '芒康县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540329000000, '洛隆县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540330000000, '边坝县', 3, 540300000000); +INSERT INTO `zz_area_code` VALUES (540400000000, '林芝市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540402000000, '巴宜区', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540421000000, '工布江达县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540422000000, '米林县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540423000000, '墨脱县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540424000000, '波密县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540425000000, '察隅县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540426000000, '朗县', 3, 540400000000); +INSERT INTO `zz_area_code` VALUES (540500000000, '山南市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540501000000, '市辖区', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540502000000, '乃东区', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540521000000, '扎囊县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540522000000, '贡嘎县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540523000000, '桑日县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540524000000, '琼结县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540525000000, '曲松县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540526000000, '措美县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540527000000, '洛扎县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540528000000, '加查县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540529000000, '隆子县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540530000000, '错那县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540531000000, '浪卡子县', 3, 540500000000); +INSERT INTO `zz_area_code` VALUES (540600000000, '那曲市', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (540602000000, '色尼区', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540621000000, '嘉黎县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540622000000, '比如县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540623000000, '聂荣县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540624000000, '安多县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540625000000, '申扎县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540626000000, '索县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540627000000, '班戈县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540628000000, '巴青县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540629000000, '尼玛县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (540630000000, '双湖县', 3, 540600000000); +INSERT INTO `zz_area_code` VALUES (542500000000, '阿里地区', 2, 540000000000); +INSERT INTO `zz_area_code` VALUES (542521000000, '普兰县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542522000000, '札达县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542523000000, '噶尔县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542524000000, '日土县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542525000000, '革吉县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542526000000, '改则县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (542527000000, '措勤县', 3, 542500000000); +INSERT INTO `zz_area_code` VALUES (610000000000, '陕西省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (610100000000, '西安市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610101000000, '市辖区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610102000000, '新城区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610103000000, '碑林区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610104000000, '莲湖区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610111000000, '灞桥区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610112000000, '未央区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610113000000, '雁塔区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610114000000, '阎良区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610115000000, '临潼区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610116000000, '长安区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610117000000, '高陵区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610118000000, '鄠邑区', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610122000000, '蓝田县', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610124000000, '周至县', 3, 610100000000); +INSERT INTO `zz_area_code` VALUES (610200000000, '铜川市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610201000000, '市辖区', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610202000000, '王益区', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610203000000, '印台区', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610204000000, '耀州区', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610222000000, '宜君县', 3, 610200000000); +INSERT INTO `zz_area_code` VALUES (610300000000, '宝鸡市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610301000000, '市辖区', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610302000000, '渭滨区', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610303000000, '金台区', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610304000000, '陈仓区', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610322000000, '凤翔县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610323000000, '岐山县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610324000000, '扶风县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610326000000, '眉县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610327000000, '陇县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610328000000, '千阳县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610329000000, '麟游县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610330000000, '凤县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610331000000, '太白县', 3, 610300000000); +INSERT INTO `zz_area_code` VALUES (610400000000, '咸阳市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610401000000, '市辖区', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610402000000, '秦都区', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610403000000, '杨陵区', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610404000000, '渭城区', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610422000000, '三原县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610423000000, '泾阳县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610424000000, '乾县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610425000000, '礼泉县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610426000000, '永寿县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610428000000, '长武县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610429000000, '旬邑县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610430000000, '淳化县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610431000000, '武功县', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610481000000, '兴平市', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610482000000, '彬州市', 3, 610400000000); +INSERT INTO `zz_area_code` VALUES (610500000000, '渭南市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610501000000, '市辖区', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610502000000, '临渭区', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610503000000, '华州区', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610522000000, '潼关县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610523000000, '大荔县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610524000000, '合阳县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610525000000, '澄城县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610526000000, '蒲城县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610527000000, '白水县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610528000000, '富平县', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610581000000, '韩城市', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610582000000, '华阴市', 3, 610500000000); +INSERT INTO `zz_area_code` VALUES (610600000000, '延安市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610601000000, '市辖区', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610602000000, '宝塔区', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610603000000, '安塞区', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610621000000, '延长县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610622000000, '延川县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610623000000, '子长县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610625000000, '志丹县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610626000000, '吴起县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610627000000, '甘泉县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610628000000, '富县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610629000000, '洛川县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610630000000, '宜川县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610631000000, '黄龙县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610632000000, '黄陵县', 3, 610600000000); +INSERT INTO `zz_area_code` VALUES (610700000000, '汉中市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610701000000, '市辖区', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610702000000, '汉台区', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610703000000, '南郑区', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610722000000, '城固县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610723000000, '洋县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610724000000, '西乡县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610725000000, '勉县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610726000000, '宁强县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610727000000, '略阳县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610728000000, '镇巴县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610729000000, '留坝县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610730000000, '佛坪县', 3, 610700000000); +INSERT INTO `zz_area_code` VALUES (610800000000, '榆林市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610801000000, '市辖区', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610802000000, '榆阳区', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610803000000, '横山区', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610822000000, '府谷县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610824000000, '靖边县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610825000000, '定边县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610826000000, '绥德县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610827000000, '米脂县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610828000000, '佳县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610829000000, '吴堡县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610830000000, '清涧县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610831000000, '子洲县', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610881000000, '神木市', 3, 610800000000); +INSERT INTO `zz_area_code` VALUES (610900000000, '安康市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (610901000000, '市辖区', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610902000000, '汉滨区', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610921000000, '汉阴县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610922000000, '石泉县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610923000000, '宁陕县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610924000000, '紫阳县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610925000000, '岚皋县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610926000000, '平利县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610927000000, '镇坪县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610928000000, '旬阳县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (610929000000, '白河县', 3, 610900000000); +INSERT INTO `zz_area_code` VALUES (611000000000, '商洛市', 2, 610000000000); +INSERT INTO `zz_area_code` VALUES (611001000000, '市辖区', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611002000000, '商州区', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611021000000, '洛南县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611022000000, '丹凤县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611023000000, '商南县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611024000000, '山阳县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611025000000, '镇安县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (611026000000, '柞水县', 3, 611000000000); +INSERT INTO `zz_area_code` VALUES (620000000000, '甘肃省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (620100000000, '兰州市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620101000000, '市辖区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620102000000, '城关区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620103000000, '七里河区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620104000000, '西固区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620105000000, '安宁区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620111000000, '红古区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620121000000, '永登县', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620122000000, '皋兰县', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620123000000, '榆中县', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620171000000, '兰州新区', 3, 620100000000); +INSERT INTO `zz_area_code` VALUES (620200000000, '嘉峪关市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620201000000, '市辖区', 3, 620200000000); +INSERT INTO `zz_area_code` VALUES (620300000000, '金昌市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620301000000, '市辖区', 3, 620300000000); +INSERT INTO `zz_area_code` VALUES (620302000000, '金川区', 3, 620300000000); +INSERT INTO `zz_area_code` VALUES (620321000000, '永昌县', 3, 620300000000); +INSERT INTO `zz_area_code` VALUES (620400000000, '白银市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620401000000, '市辖区', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620402000000, '白银区', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620403000000, '平川区', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620421000000, '靖远县', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620422000000, '会宁县', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620423000000, '景泰县', 3, 620400000000); +INSERT INTO `zz_area_code` VALUES (620500000000, '天水市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620501000000, '市辖区', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620502000000, '秦州区', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620503000000, '麦积区', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620521000000, '清水县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620522000000, '秦安县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620523000000, '甘谷县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620524000000, '武山县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620525000000, '张家川回族自治县', 3, 620500000000); +INSERT INTO `zz_area_code` VALUES (620600000000, '武威市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620601000000, '市辖区', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620602000000, '凉州区', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620621000000, '民勤县', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620622000000, '古浪县', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620623000000, '天祝藏族自治县', 3, 620600000000); +INSERT INTO `zz_area_code` VALUES (620700000000, '张掖市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620701000000, '市辖区', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620702000000, '甘州区', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620721000000, '肃南裕固族自治县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620722000000, '民乐县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620723000000, '临泽县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620724000000, '高台县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620725000000, '山丹县', 3, 620700000000); +INSERT INTO `zz_area_code` VALUES (620800000000, '平凉市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620801000000, '市辖区', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620802000000, '崆峒区', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620821000000, '泾川县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620822000000, '灵台县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620823000000, '崇信县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620825000000, '庄浪县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620826000000, '静宁县', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620881000000, '华亭市', 3, 620800000000); +INSERT INTO `zz_area_code` VALUES (620900000000, '酒泉市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (620901000000, '市辖区', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620902000000, '肃州区', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620921000000, '金塔县', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620922000000, '瓜州县', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620923000000, '肃北蒙古族自治县', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620924000000, '阿克塞哈萨克族自治县', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620981000000, '玉门市', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (620982000000, '敦煌市', 3, 620900000000); +INSERT INTO `zz_area_code` VALUES (621000000000, '庆阳市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (621001000000, '市辖区', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621002000000, '西峰区', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621021000000, '庆城县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621022000000, '环县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621023000000, '华池县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621024000000, '合水县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621025000000, '正宁县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621026000000, '宁县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621027000000, '镇原县', 3, 621000000000); +INSERT INTO `zz_area_code` VALUES (621100000000, '定西市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (621101000000, '市辖区', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621102000000, '安定区', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621121000000, '通渭县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621122000000, '陇西县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621123000000, '渭源县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621124000000, '临洮县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621125000000, '漳县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621126000000, '岷县', 3, 621100000000); +INSERT INTO `zz_area_code` VALUES (621200000000, '陇南市', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (621201000000, '市辖区', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621202000000, '武都区', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621221000000, '成县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621222000000, '文县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621223000000, '宕昌县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621224000000, '康县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621225000000, '西和县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621226000000, '礼县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621227000000, '徽县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (621228000000, '两当县', 3, 621200000000); +INSERT INTO `zz_area_code` VALUES (622900000000, '临夏回族自治州', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (622901000000, '临夏市', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622921000000, '临夏县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622922000000, '康乐县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622923000000, '永靖县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622924000000, '广河县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622925000000, '和政县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622926000000, '东乡族自治县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (622927000000, '积石山保安族东乡族撒拉族自治县', 3, 622900000000); +INSERT INTO `zz_area_code` VALUES (623000000000, '甘南藏族自治州', 2, 620000000000); +INSERT INTO `zz_area_code` VALUES (623001000000, '合作市', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623021000000, '临潭县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623022000000, '卓尼县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623023000000, '舟曲县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623024000000, '迭部县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623025000000, '玛曲县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623026000000, '碌曲县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (623027000000, '夏河县', 3, 623000000000); +INSERT INTO `zz_area_code` VALUES (630000000000, '青海省', 1, NULL); +INSERT INTO `zz_area_code` VALUES (630100000000, '西宁市', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (630101000000, '市辖区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630102000000, '城东区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630103000000, '城中区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630104000000, '城西区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630105000000, '城北区', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630121000000, '大通回族土族自治县', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630122000000, '湟中县', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630123000000, '湟源县', 3, 630100000000); +INSERT INTO `zz_area_code` VALUES (630200000000, '海东市', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (630202000000, '乐都区', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630203000000, '平安区', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630222000000, '民和回族土族自治县', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630223000000, '互助土族自治县', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630224000000, '化隆回族自治县', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (630225000000, '循化撒拉族自治县', 3, 630200000000); +INSERT INTO `zz_area_code` VALUES (632200000000, '海北藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632221000000, '门源回族自治县', 3, 632200000000); +INSERT INTO `zz_area_code` VALUES (632222000000, '祁连县', 3, 632200000000); +INSERT INTO `zz_area_code` VALUES (632223000000, '海晏县', 3, 632200000000); +INSERT INTO `zz_area_code` VALUES (632224000000, '刚察县', 3, 632200000000); +INSERT INTO `zz_area_code` VALUES (632300000000, '黄南藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632321000000, '同仁县', 3, 632300000000); +INSERT INTO `zz_area_code` VALUES (632322000000, '尖扎县', 3, 632300000000); +INSERT INTO `zz_area_code` VALUES (632323000000, '泽库县', 3, 632300000000); +INSERT INTO `zz_area_code` VALUES (632324000000, '河南蒙古族自治县', 3, 632300000000); +INSERT INTO `zz_area_code` VALUES (632500000000, '海南藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632521000000, '共和县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632522000000, '同德县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632523000000, '贵德县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632524000000, '兴海县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632525000000, '贵南县', 3, 632500000000); +INSERT INTO `zz_area_code` VALUES (632600000000, '果洛藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632621000000, '玛沁县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632622000000, '班玛县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632623000000, '甘德县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632624000000, '达日县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632625000000, '久治县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632626000000, '玛多县', 3, 632600000000); +INSERT INTO `zz_area_code` VALUES (632700000000, '玉树藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632701000000, '玉树市', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632722000000, '杂多县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632723000000, '称多县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632724000000, '治多县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632725000000, '囊谦县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632726000000, '曲麻莱县', 3, 632700000000); +INSERT INTO `zz_area_code` VALUES (632800000000, '海西蒙古族藏族自治州', 2, 630000000000); +INSERT INTO `zz_area_code` VALUES (632801000000, '格尔木市', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632802000000, '德令哈市', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632803000000, '茫崖市', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632821000000, '乌兰县', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632822000000, '都兰县', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632823000000, '天峻县', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (632857000000, '大柴旦行政委员会', 3, 632800000000); +INSERT INTO `zz_area_code` VALUES (640000000000, '宁夏回族自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (640100000000, '银川市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640101000000, '市辖区', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640104000000, '兴庆区', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640105000000, '西夏区', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640106000000, '金凤区', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640121000000, '永宁县', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640122000000, '贺兰县', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640181000000, '灵武市', 3, 640100000000); +INSERT INTO `zz_area_code` VALUES (640200000000, '石嘴山市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640201000000, '市辖区', 3, 640200000000); +INSERT INTO `zz_area_code` VALUES (640202000000, '大武口区', 3, 640200000000); +INSERT INTO `zz_area_code` VALUES (640205000000, '惠农区', 3, 640200000000); +INSERT INTO `zz_area_code` VALUES (640221000000, '平罗县', 3, 640200000000); +INSERT INTO `zz_area_code` VALUES (640300000000, '吴忠市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640301000000, '市辖区', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640302000000, '利通区', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640303000000, '红寺堡区', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640323000000, '盐池县', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640324000000, '同心县', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640381000000, '青铜峡市', 3, 640300000000); +INSERT INTO `zz_area_code` VALUES (640400000000, '固原市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640401000000, '市辖区', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640402000000, '原州区', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640422000000, '西吉县', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640423000000, '隆德县', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640424000000, '泾源县', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640425000000, '彭阳县', 3, 640400000000); +INSERT INTO `zz_area_code` VALUES (640500000000, '中卫市', 2, 640000000000); +INSERT INTO `zz_area_code` VALUES (640501000000, '市辖区', 3, 640500000000); +INSERT INTO `zz_area_code` VALUES (640502000000, '沙坡头区', 3, 640500000000); +INSERT INTO `zz_area_code` VALUES (640521000000, '中宁县', 3, 640500000000); +INSERT INTO `zz_area_code` VALUES (640522000000, '海原县', 3, 640500000000); +INSERT INTO `zz_area_code` VALUES (650000000000, '新疆维吾尔自治区', 1, NULL); +INSERT INTO `zz_area_code` VALUES (650100000000, '乌鲁木齐市', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (650101000000, '市辖区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650102000000, '天山区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650103000000, '沙依巴克区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650104000000, '新市区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650105000000, '水磨沟区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650106000000, '头屯河区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650107000000, '达坂城区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650109000000, '米东区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650121000000, '乌鲁木齐县', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650171000000, '乌鲁木齐经济技术开发区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650172000000, '乌鲁木齐高新技术产业开发区', 3, 650100000000); +INSERT INTO `zz_area_code` VALUES (650200000000, '克拉玛依市', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (650201000000, '市辖区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650202000000, '独山子区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650203000000, '克拉玛依区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650204000000, '白碱滩区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650205000000, '乌尔禾区', 3, 650200000000); +INSERT INTO `zz_area_code` VALUES (650400000000, '吐鲁番市', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (650402000000, '高昌区', 3, 650400000000); +INSERT INTO `zz_area_code` VALUES (650421000000, '鄯善县', 3, 650400000000); +INSERT INTO `zz_area_code` VALUES (650422000000, '托克逊县', 3, 650400000000); +INSERT INTO `zz_area_code` VALUES (650500000000, '哈密市', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (650502000000, '伊州区', 3, 650500000000); +INSERT INTO `zz_area_code` VALUES (650521000000, '巴里坤哈萨克自治县', 3, 650500000000); +INSERT INTO `zz_area_code` VALUES (650522000000, '伊吾县', 3, 650500000000); +INSERT INTO `zz_area_code` VALUES (652300000000, '昌吉回族自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (652301000000, '昌吉市', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652302000000, '阜康市', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652323000000, '呼图壁县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652324000000, '玛纳斯县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652325000000, '奇台县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652327000000, '吉木萨尔县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652328000000, '木垒哈萨克自治县', 3, 652300000000); +INSERT INTO `zz_area_code` VALUES (652700000000, '博尔塔拉蒙古自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (652701000000, '博乐市', 3, 652700000000); +INSERT INTO `zz_area_code` VALUES (652702000000, '阿拉山口市', 3, 652700000000); +INSERT INTO `zz_area_code` VALUES (652722000000, '精河县', 3, 652700000000); +INSERT INTO `zz_area_code` VALUES (652723000000, '温泉县', 3, 652700000000); +INSERT INTO `zz_area_code` VALUES (652800000000, '巴音郭楞蒙古自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (652801000000, '库尔勒市', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652822000000, '轮台县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652823000000, '尉犁县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652824000000, '若羌县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652825000000, '且末县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652826000000, '焉耆回族自治县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652827000000, '和静县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652828000000, '和硕县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652829000000, '博湖县', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652871000000, '库尔勒经济技术开发区', 3, 652800000000); +INSERT INTO `zz_area_code` VALUES (652900000000, '阿克苏地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (652901000000, '阿克苏市', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652922000000, '温宿县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652923000000, '库车县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652924000000, '沙雅县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652925000000, '新和县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652926000000, '拜城县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652927000000, '乌什县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652928000000, '阿瓦提县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (652929000000, '柯坪县', 3, 652900000000); +INSERT INTO `zz_area_code` VALUES (653000000000, '克孜勒苏柯尔克孜自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (653001000000, '阿图什市', 3, 653000000000); +INSERT INTO `zz_area_code` VALUES (653022000000, '阿克陶县', 3, 653000000000); +INSERT INTO `zz_area_code` VALUES (653023000000, '阿合奇县', 3, 653000000000); +INSERT INTO `zz_area_code` VALUES (653024000000, '乌恰县', 3, 653000000000); +INSERT INTO `zz_area_code` VALUES (653100000000, '喀什地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (653101000000, '喀什市', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653121000000, '疏附县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653122000000, '疏勒县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653123000000, '英吉沙县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653124000000, '泽普县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653125000000, '莎车县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653126000000, '叶城县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653127000000, '麦盖提县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653128000000, '岳普湖县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653129000000, '伽师县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653130000000, '巴楚县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653131000000, '塔什库尔干塔吉克自治县', 3, 653100000000); +INSERT INTO `zz_area_code` VALUES (653200000000, '和田地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (653201000000, '和田市', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653221000000, '和田县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653222000000, '墨玉县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653223000000, '皮山县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653224000000, '洛浦县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653225000000, '策勒县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653226000000, '于田县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (653227000000, '民丰县', 3, 653200000000); +INSERT INTO `zz_area_code` VALUES (654000000000, '伊犁哈萨克自治州', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (654002000000, '伊宁市', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654003000000, '奎屯市', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654004000000, '霍尔果斯市', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654021000000, '伊宁县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654022000000, '察布查尔锡伯自治县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654023000000, '霍城县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654024000000, '巩留县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654025000000, '新源县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654026000000, '昭苏县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654027000000, '特克斯县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654028000000, '尼勒克县', 3, 654000000000); +INSERT INTO `zz_area_code` VALUES (654200000000, '塔城地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (654201000000, '塔城市', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654202000000, '乌苏市', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654221000000, '额敏县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654223000000, '沙湾县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654224000000, '托里县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654225000000, '裕民县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654226000000, '和布克赛尔蒙古自治县', 3, 654200000000); +INSERT INTO `zz_area_code` VALUES (654300000000, '阿勒泰地区', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (654301000000, '阿勒泰市', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654321000000, '布尔津县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654322000000, '富蕴县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654323000000, '福海县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654324000000, '哈巴河县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654325000000, '青河县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (654326000000, '吉木乃县', 3, 654300000000); +INSERT INTO `zz_area_code` VALUES (659000000000, '自治区直辖县级行政区划', 2, 650000000000); +INSERT INTO `zz_area_code` VALUES (659001000000, '石河子市', 3, 659000000000); +INSERT INTO `zz_area_code` VALUES (659002000000, '阿拉尔市', 3, 659000000000); +INSERT INTO `zz_area_code` VALUES (659003000000, '图木舒克市', 3, 659000000000); +INSERT INTO `zz_area_code` VALUES (659004000000, '五家渠市', 3, 659000000000); +INSERT INTO `zz_area_code` VALUES (659006000000, '铁门关市', 3, 659000000000); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_flow_category +-- ---------------------------- +DROP TABLE IF EXISTS `zz_flow_category`; +CREATE TABLE `zz_flow_category` ( + `category_id` bigint(20) NOT NULL COMMENT '主键Id', + `name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '显示名称', + `code` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '分类编码', + `show_order` int(11) NOT NULL COMMENT '实现顺序', + `update_time` datetime NOT NULL COMMENT '更新时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + PRIMARY KEY (`category_id`) USING BTREE, + UNIQUE KEY `idx_code` (`code`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_flow_category +-- ---------------------------- +BEGIN; +INSERT INTO `zz_flow_category` VALUES (1440940473421139968, '人事管理', 'HR', 1, '2021-09-23 15:25:55', 1440911410581213417, '2021-09-23 15:25:55', 1440911410581213417); +INSERT INTO `zz_flow_category` VALUES (1440940520124715008, '财务管理', 'CW', 2, '2021-09-23 15:26:06', 1440911410581213417, '2021-09-23 15:26:06', 1440911410581213417); +INSERT INTO `zz_flow_category` VALUES (1440940563934220288, '项目管理', 'XM', 3, '2021-09-23 15:26:16', 1440911410581213417, '2021-09-23 15:26:16', 1440911410581213417); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_flow_entry +-- ---------------------------- +DROP TABLE IF EXISTS `zz_flow_entry`; +CREATE TABLE `zz_flow_entry` ( + `entry_id` bigint(20) NOT NULL COMMENT '主键', + `process_definition_name` varchar(200) NOT NULL COMMENT '流程名称', + `process_definition_key` varchar(150) NOT NULL COMMENT '流程标识Key', + `category_id` bigint(20) NOT NULL COMMENT '流程分类', + `main_entry_publish_id` bigint(20) DEFAULT NULL COMMENT '工作流部署的发布主版本Id', + `lastest_publish_time` datetime DEFAULT NULL COMMENT '最新发布时间', + `status` int(11) NOT NULL COMMENT '流程状态', + `bpmn_xml` longtext COMMENT '流程定义的xml', + `bind_form_type` int(11) NOT NULL COMMENT '绑定表单类型', + `page_id` bigint(20) DEFAULT NULL COMMENT '在线表单的页面Id', + `default_form_id` bigint(20) DEFAULT NULL COMMENT '在线表单Id', + `default_router_name` varchar(255) DEFAULT NULL COMMENT '静态表单的缺省路由名称', + `update_time` datetime NOT NULL COMMENT '更新时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + PRIMARY KEY (`entry_id`) USING BTREE, + UNIQUE KEY `idx_process_definition_key` (`process_definition_key`) USING BTREE, + KEY `idx_category_id` (`category_id`) USING BTREE, + KEY `idx_status` (`status`) USING BTREE, + KEY `idx_process_definition_name` (`process_definition_name`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- ---------------------------- +-- Records of zz_flow_entry +-- ---------------------------- +BEGIN; +INSERT INTO `zz_flow_entry` VALUES (1440962968085860352, '请假申请', 'flowLeave', 1440940473421139968, 1440966810131238912, '2021-09-23 17:10:34', 1, '\n\n \n \n Flow_05fy9wh\n \n \n \n \n \n \n \n \n Flow_05fy9wh\n Flow_012hd4v\n Flow_1dpnyz6\n Flow_0pme0vr\n \n \n \n \n \n \n \n \n \n \n Flow_0pme0vr\n Flow_1hbob37\n Flow_012hd4v\n \n \n \n \n \n \n \n \n \n \n Flow_1hbob37\n Flow_0so810a\n Flow_1dpnyz6\n \n \n \n \n \n ${operationType == \'agree\'}\n \n \n Flow_0so810a\n \n \n \n \n \n ${operationType == \'agree\'}\n \n \n \n \n \n ${operationType == \'refuse\'}\n \n \n \n \n \n ${operationType == \'refuse\'}\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n', 0, 1440945149889744896, 1440945411354267648, NULL, '2021-09-24 09:30:26', 1440911410581213417, '2021-09-23 16:55:18', 1440911410581213417); +INSERT INTO `zz_flow_entry` VALUES (1440966906914803712, '报销申请', 'flowSubmit', 1440940520124715008, 1440972224344363008, '2021-09-23 17:32:05', 1, '\n\n \n \n Flow_00ldvag\n \n \n \n \n \n \n \n \n Flow_00ldvag\n Flow_1hmaykh\n Flow_09b7unr\n Flow_0x9dx2t\n \n \n \n \n \n \n \n \n \n \n \n \n Flow_0x9dx2t\n Flow_18p3hqb\n Flow_1hmaykh\n \n \n \n Flow_18p3hqb\n Flow_1qigakr\n Flow_058cmsb\n \n \n \n \n \n ${operationType == \'agree\'}\n \n \n Flow_1qigakr\n Flow_0ycx8fb\n \n \n ${totalAmount <= 1000}\n \n \n \n \n \n \n \n \n \n Flow_058cmsb\n Flow_0ycx8fb\n Flow_09b7unr\n \n \n ${totalAmount > 1000}\n \n \n \n \n \n ${operationType == \'agree\'}\n \n \n \n \n \n ${operationType == \'refuse\'}\n \n \n \n \n \n ${operationType == \'refuse\'}\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n', 0, 1440946020174270464, 1440947675041107968, NULL, '2021-09-24 13:23:15', 1440911410581213417, '2021-09-23 17:10:57', 1440911410581213417); +INSERT INTO `zz_flow_entry` VALUES (1440968423508021248, '合同审批', 'flowContract', 1440940563934220288, 1441216695006924800, '2021-09-24 09:43:31', 1, '\n\n \n \n Flow_00cexea\n \n \n \n \n \n \n \n \n Flow_00cexea\n Flow_0lloy56\n Flow_1vsrivb\n Flow_1m2406f\n Flow_04kcajc\n \n \n \n \n \n \n \n \n \n Flow_04kcajc\n Flow_026fvnq\n \n \n \n \n Flow_026fvnq\n Flow_0zz0u9g\n Flow_1yxqbe0\n \n \n \n \n \n \n \n \n Flow_0zz0u9g\n Flow_124e8z3\n \n \n \n \n \n \n \n \n \n Flow_1yxqbe0\n Flow_1uvj3ds\n \n \n \n \n Flow_124e8z3\n Flow_1uvj3ds\n Flow_1kyhnlz\n \n \n \n \n \n \n \n \n \n \n Flow_1kyhnlz\n Flow_0di6qa6\n Flow_0lloy56\n \n \n \n \n \n \n \n \n \n \n Flow_0zmsn3x\n Flow_0jyv1zb\n \n ${nrOfInstances == nrOfCompletedInstances}\n \n \n \n \n \n \n ${operationType == \'agree\'}\n \n \n Flow_0jyv1zb\n Flow_1f8yxov\n Flow_1vsrivb\n \n \n \n \n \n \n \n \n \n \n Flow_1f8yxov\n Flow_1a3qclm\n Flow_1m2406f\n \n \n ${multiAgreeCount / multiNumOfInstances > 0.4}\n \n \n Flow_1a3qclm\n \n \n \n \n \n ${operationType == \'agree\'}\n \n \n \n \n \n ${operationType == \'refuse\'}\n \n \n \n \n \n \n \n \n \n Flow_0di6qa6\n Flow_0zmsn3x\n \n \n \n ${multiAgreeCount / multiNumOfInstances <= 0.4}\n \n \n \n \n \n ${operationType == \'refuse\'}\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n', 0, 1440952710487609344, 1440954920348946432, NULL, '2021-09-24 10:17:32', 1440966324770574336, '2021-09-23 17:16:59', 1440911410581213417); +INSERT INTO `zz_flow_entry` VALUES (1440972435892473856, '多实例加签', 'flowConSign', 1440940473421139968, 1440973324426416128, '2021-09-23 17:36:27', 1, '\n\n \n \n Flow_111kyps\n \n \n \n \n \n \n \n \n \n Flow_111kyps\n Flow_009p7hy\n Flow_0ct2yid\n \n \n \n \n \n \n \n \n \n Flow_0ct2yid\n Flow_052kvzh\n \n ${nrOfInstances == nrOfCompletedInstances}\n \n \n \n \n \n \n \n \n \n \n \n Flow_052kvzh\n Flow_1ng5qp7\n Flow_009p7hy\n \n \n \n Flow_1ng5qp7\n \n \n \n \n \n ${operationType == \'agree\'}\n \n \n \n \n \n ${operationType == \'refuse\'}\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n', 0, 1440945149889744896, 1440945411354267648, NULL, '2021-09-23 17:36:21', 1440911410581213417, '2021-09-23 17:32:55', 1440911410581213417); +INSERT INTO `zz_flow_entry` VALUES (1440973419167354880, '转办流程', 'flowTranslate', 1440940473421139968, 1440973782771568640, '2021-09-23 17:38:16', 1, '\n\n \n \n Flow_08lgvo0\n \n \n \n \n \n \n \n \n Flow_08lgvo0\n Flow_0n45f5j\n \n \n \n \n \n \n \n \n \n \n Flow_0n45f5j\n Flow_1s8i9er\n \n \n \n Flow_1s8i9er\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n', 0, 1440945149889744896, 1440945411354267648, NULL, '2021-09-23 17:38:00', 1440911410581213417, '2021-09-23 17:36:50', 1440911410581213417); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_flow_entry_publish +-- ---------------------------- +DROP TABLE IF EXISTS `zz_flow_entry_publish`; +CREATE TABLE `zz_flow_entry_publish` ( + `entry_publish_id` bigint(20) NOT NULL COMMENT '主键Id', + `entry_id` bigint(20) NOT NULL COMMENT '流程Id', + `process_definition_id` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '流程引擎的定义Id', + `deploy_id` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '流程引擎的部署Id', + `publish_version` int(11) NOT NULL COMMENT '发布版本', + `active_status` bit(1) NOT NULL COMMENT '激活状态', + `main_version` bit(1) NOT NULL COMMENT '是否为主版本', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `publish_time` datetime NOT NULL COMMENT '发布时间', + `init_task_info` text CHARACTER SET utf8mb4 COMMENT '第一个非开始节点任务的附加信息', + PRIMARY KEY (`entry_publish_id`) USING BTREE, + UNIQUE KEY `idx_process_definition_id` (`process_definition_id`) USING BTREE, + KEY `idx_entry_id` (`entry_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_flow_entry_publish +-- ---------------------------- +BEGIN; +INSERT INTO `zz_flow_entry_publish` VALUES (1440966810131238912, 1440962968085860352, 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', '1a075ec8-1c4e-11ec-94ee-5ef70686b817', 1, b'1', b'1', 1440911410581213417, '2021-09-23 17:10:34', '{\"assignee\":\"${startUserName}\",\"formId\":1440945411354267648,\"groupType\":\"DEPT\",\"operationList\":[{\"showOrder\":\"0\",\"id\":\"1632387369558\",\"label\":\"提交\",\"type\":\"agree\"}],\"readOnly\":false,\"taskKey\":\"Activity_0sc2yuf\",\"taskType\":1}'); +INSERT INTO `zz_flow_entry_publish` VALUES (1440968302972112896, 1440966906914803712, 'flowSubmit:1:efe9db3f-1c4e-11ec-94ee-5ef70686b817', 'efd6c86c-1c4e-11ec-94ee-5ef70686b817', 1, b'1', b'0', 1440911410581213417, '2021-09-23 17:16:30', '{\"assignee\":\"${startUserName}\",\"formId\":1440947675041107968,\"groupType\":\"DEPT\",\"operationList\":[{\"showOrder\":\"0\",\"id\":\"1632388352676\",\"label\":\"提交\",\"type\":\"agree\"}],\"readOnly\":false,\"taskKey\":\"Activity_03kjurt\",\"taskType\":1}'); +INSERT INTO `zz_flow_entry_publish` VALUES (1440972214223507456, 1440968423508021248, 'flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', '1ba32d20-1c51-11ec-94ee-5ef70686b817', 1, b'1', b'0', 1440911410581213417, '2021-09-23 17:32:02', '{\"formId\":1440954920348946432,\"groupType\":\"DEPT\",\"operationList\":[{\"showOrder\":\"0\",\"id\":\"1632388965712\",\"label\":\"提交\",\"type\":\"agree\"}],\"readOnly\":false,\"taskKey\":\"Activity_0nyla1r\",\"taskType\":1}'); +INSERT INTO `zz_flow_entry_publish` VALUES (1440972224344363008, 1440966906914803712, 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '1d1dbf34-1c51-11ec-94ee-5ef70686b817', 2, b'1', b'1', 1440911410581213417, '2021-09-23 17:32:05', '{\"assignee\":\"${startUserName}\",\"formId\":1440947675041107968,\"groupType\":\"DEPT\",\"operationList\":[{\"showOrder\":\"0\",\"id\":\"1632388352676\",\"label\":\"提交\",\"type\":\"agree\"}],\"readOnly\":false,\"taskKey\":\"Activity_03kjurt\",\"taskType\":1}'); +INSERT INTO `zz_flow_entry_publish` VALUES (1440973324426416128, 1440972435892473856, 'flowConSign:1:b981c1fb-1c51-11ec-94ee-5ef70686b817', 'b97761b8-1c51-11ec-94ee-5ef70686b817', 1, b'1', b'1', 1440911410581213417, '2021-09-23 17:36:27', '{\"assignee\":\"${startUserName}\",\"formId\":1440945411354267648,\"groupType\":\"DEPT\",\"operationList\":[{\"showOrder\":\"0\",\"id\":\"1632389626319\",\"label\":\"提交\",\"type\":\"multi_sign\"},{\"showOrder\":\"1\",\"id\":\"1632389633373\",\"label\":\"加签\",\"type\":\"multi_consign\"}],\"readOnly\":false,\"taskKey\":\"Activity_1xk7j4n\",\"taskType\":1}'); +INSERT INTO `zz_flow_entry_publish` VALUES (1440973782771568640, 1440973419167354880, 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'fa9b683c-1c51-11ec-94ee-5ef70686b817', 1, b'1', b'1', 1440911410581213417, '2021-09-23 17:38:16', '{\"assignee\":\"${startUserName}\",\"formId\":1440945411354267648,\"groupType\":\"DEPT\",\"operationList\":[{\"showOrder\":\"0\",\"id\":\"1632389836108\",\"label\":\"提交\",\"type\":\"agree\"}],\"readOnly\":false,\"taskKey\":\"Activity_08p9kng\",\"taskType\":1}'); +INSERT INTO `zz_flow_entry_publish` VALUES (1441214529919782912, 1440968423508021248, 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '9d23d445-1cd7-11ec-acd8-3ae4f1d3c3af', 2, b'1', b'0', 1440911410581213417, '2021-09-24 09:34:55', '{\"assignee\":\"${startUserName}\",\"formId\":1440954920348946432,\"groupType\":\"DEPT\",\"operationList\":[{\"showOrder\":\"0\",\"id\":\"1632388965712\",\"label\":\"提交\",\"type\":\"agree\"}],\"readOnly\":false,\"taskKey\":\"Activity_0nyla1r\",\"taskType\":1}'); +INSERT INTO `zz_flow_entry_publish` VALUES (1441216695006924800, 1440968423508021248, 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 'd273a35d-1cd8-11ec-acd8-3ae4f1d3c3af', 3, b'1', b'1', 1440911410581213417, '2021-09-24 09:43:31', '{\"assignee\":\"${startUserName}\",\"formId\":1440954920348946432,\"groupType\":\"DEPT\",\"operationList\":[{\"showOrder\":\"0\",\"id\":\"1632388965712\",\"label\":\"提交\",\"type\":\"agree\"}],\"readOnly\":false,\"taskKey\":\"Activity_0nyla1r\",\"taskType\":1}'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_flow_entry_publish_variable +-- ---------------------------- +DROP TABLE IF EXISTS `zz_flow_entry_publish_variable`; +CREATE TABLE `zz_flow_entry_publish_variable` ( + `variable_id` bigint(20) NOT NULL COMMENT '主键Id', + `entry_publish_id` bigint(20) NOT NULL COMMENT '流程Id', + `variable_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '变量名', + `show_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '显示名', + `variable_type` int(11) NOT NULL COMMENT '变量类型', + `bind_datasource_id` bigint(20) DEFAULT NULL COMMENT '绑定数据源Id', + `bind_relation_id` bigint(20) DEFAULT NULL COMMENT '绑定数据源关联Id', + `bind_column_id` bigint(20) DEFAULT NULL COMMENT '绑定字段Id', + `builtin` bit(1) NOT NULL COMMENT '是否内置', + PRIMARY KEY (`variable_id`) USING BTREE, + KEY `idx_entry_publish_id` (`entry_publish_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_flow_entry_publish_variable +-- ---------------------------- +BEGIN; +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440966810181570560, 1440966810131238912, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440966810181570561, 1440966810131238912, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440968302993084416, 1440968302972112896, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440968302993084417, 1440968302972112896, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440968302993084418, 1440968302972112896, 'totalAmount', '报销金额', 1, 1440946127531675648, NULL, 1440946127493926912, b'0'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440972214244478976, 1440972214223507456, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440972214244478977, 1440972214223507456, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440972224365334528, 1440972224344363008, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440972224365334529, 1440972224344363008, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440972224365334530, 1440972224344363008, 'totalAmount', '报销金额', 1, 1440946127531675648, NULL, 1440946127493926912, b'0'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440973324443193344, 1440973324426416128, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440973324443193345, 1440973324426416128, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440973782788345856, 1440973782771568640, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1440973782788345857, 1440973782771568640, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1441214529953337344, 1441214529919782912, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1441214529953337345, 1441214529919782912, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1441216695027896320, 1441216695006924800, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1'); +INSERT INTO `zz_flow_entry_publish_variable` VALUES (1441216695027896321, 1441216695006924800, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_flow_entry_variable +-- ---------------------------- +DROP TABLE IF EXISTS `zz_flow_entry_variable`; +CREATE TABLE `zz_flow_entry_variable` ( + `variable_id` bigint(20) NOT NULL COMMENT '主键Id', + `entry_id` bigint(20) NOT NULL COMMENT '流程Id', + `variable_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '变量名', + `show_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '显示名', + `variable_type` int(11) NOT NULL COMMENT '变量类型', + `bind_datasource_id` bigint(20) DEFAULT NULL COMMENT '绑定数据源Id', + `bind_relation_id` bigint(20) DEFAULT NULL COMMENT '绑定数据源关联Id', + `bind_column_id` bigint(20) DEFAULT NULL COMMENT '绑定字段Id', + `builtin` bit(1) NOT NULL COMMENT '是否内置', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`variable_id`) USING BTREE, + UNIQUE KEY `uk_entry_id_variable_name` (`entry_id`,`variable_name`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_flow_entry_variable +-- ---------------------------- +BEGIN; +INSERT INTO `zz_flow_entry_variable` VALUES (1440962968090054657, 1440962968085860352, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1', '2021-09-23 16:55:18'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440962968094248961, 1440962968085860352, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1', '2021-09-23 16:55:18'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440966906918998017, 1440966906914803712, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1', '2021-09-23 17:10:57'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440966906927386625, 1440966906914803712, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1', '2021-09-23 17:10:57'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440967581673459712, 1440966906914803712, 'totalAmount', '报销金额', 1, 1440946127531675648, NULL, 1440946127493926912, b'0', '2021-09-23 17:13:38'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440968423512215553, 1440968423508021248, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1', '2021-09-23 17:16:59'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440968423516409857, 1440968423508021248, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1', '2021-09-23 17:16:59'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440972435900862465, 1440972435892473856, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1', '2021-09-23 17:32:55'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440972435905056768, 1440972435892473856, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1', '2021-09-23 17:32:55'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440973419171549185, 1440973419167354880, 'operationType', '审批类型', 1, NULL, NULL, NULL, b'1', '2021-09-23 17:36:50'); +INSERT INTO `zz_flow_entry_variable` VALUES (1440973419175743489, 1440973419167354880, 'startUserName', '流程启动用户', 0, NULL, NULL, NULL, b'1', '2021-09-23 17:36:50'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_flow_task_comment +-- ---------------------------- +DROP TABLE IF EXISTS `zz_flow_task_comment`; +CREATE TABLE `zz_flow_task_comment` ( + `id` bigint(20) NOT NULL COMMENT '主键Id', + `process_instance_id` varchar(64) COLLATE utf8_bin NOT NULL COMMENT '流程实例Id', + `task_id` varchar(64) COLLATE utf8_bin NOT NULL COMMENT '任务Id', + `task_key` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '任务标识', + `task_name` varchar(512) COLLATE utf8_bin DEFAULT NULL COMMENT '任务名称', + `approval_type` varchar(32) COLLATE utf8_bin NOT NULL COMMENT '审批类型', + `comment` varchar(1024) COLLATE utf8_bin DEFAULT NULL COMMENT '批注内容', + `delegate_assignee` varchar(512) COLLATE utf8_bin DEFAULT NULL COMMENT '委托指定人,比如加签、转办等', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_username` varchar(255) COLLATE utf8_bin NOT NULL COMMENT '创建者用户名', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_process_instance_id` (`process_instance_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; + +-- ---------------------------- +-- Records of zz_flow_task_comment +-- ---------------------------- +BEGIN; +INSERT INTO `zz_flow_task_comment` VALUES (1441213241249239040, 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7b1c912-1cd6-11ec-acd8-3ae4f1d3c3af', 'Activity_0sc2yuf', '请假录入', 'agree', NULL, NULL, 1440966324770574336, '员工D', '2021-09-24 09:29:48'); +INSERT INTO `zz_flow_task_comment` VALUES (1441213342894002176, 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'e7b80aa9-1cd6-11ec-acd8-3ae4f1d3c3af', 'Activity_1jw5u20', '部门领导审批', 'agree', '同意', NULL, 1440966073686953984, '天津总监', '2021-09-24 09:30:12'); +INSERT INTO `zz_flow_task_comment` VALUES (1441213560184115200, 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 'f62d36b1-1cd6-11ec-acd8-3ae4f1d3c3af', 'Activity_0olxatv', 'HR审批', 'agree', '同意', NULL, 1440965465605148672, '员工A', '2021-09-24 09:31:04'); +INSERT INTO `zz_flow_task_comment` VALUES (1441213876594020352, '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '42019911-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_03kjurt', '报销单录入', 'agree', NULL, NULL, 1440966324770574336, '员工D', '2021-09-24 09:32:19'); +INSERT INTO `zz_flow_task_comment` VALUES (1441213922165133312, '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '42054298-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_0ywxfwu', '部门领导审批', 'agree', '同意', NULL, 1440966073686953984, '天津总监', '2021-09-24 09:32:30'); +INSERT INTO `zz_flow_task_comment` VALUES (1441214057024589824, '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', '487ef9a2-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_0qay48u', '总经理审批', 'agree', '好的', NULL, 1440969706411397120, '总部领导', '2021-09-24 09:33:02'); +INSERT INTO `zz_flow_task_comment` VALUES (1441214335085973504, '719d8e5a-1cd7-11ec-acd8-3ae4f1d3c3af', '719d8e62-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_0nyla1r', '合同录入', 'stop', '配置错误', NULL, 1440966324770574336, '员工D', '2021-09-24 09:34:09'); +INSERT INTO `zz_flow_task_comment` VALUES (1441215377718644736, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '1754a6f2-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_0nyla1r', '合同录入', 'agree', NULL, NULL, 1440966324770574336, '员工D', '2021-09-24 09:38:17'); +INSERT INTO `zz_flow_task_comment` VALUES (1441215450896666624, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '1757db49-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1ucrh52', '业务部领导审批', 'agree', '同意', NULL, 1440966073686953984, '天津总监', '2021-09-24 09:38:35'); +INSERT INTO `zz_flow_task_comment` VALUES (1441215523189690368, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '21b97ae8-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_0tm3mph', '造价部审批', 'agree', '同意', NULL, 1440911410581213417, '管理员', '2021-09-24 09:38:52'); +INSERT INTO `zz_flow_task_comment` VALUES (1441215553006997504, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '21b953d4-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_138m4nn', '工程部审批', 'agree', '同意', NULL, 1440911410581213417, '管理员', '2021-09-24 09:38:59'); +INSERT INTO `zz_flow_task_comment` VALUES (1441215775858757632, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '3040cf64-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1yuuyie', '财务部审批', 'agree', '没问题', NULL, 1440966073686953984, '天津总监', '2021-09-24 09:39:52'); +INSERT INTO `zz_flow_task_comment` VALUES (1441216028087422976, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '4fec915c-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1eewt01', '法务部审批', 'multi_sign', '用户 [leaderLaw] 会签 [[\"userB\",\"userC\",\"leaderLaw\"]]。', NULL, 1440965808049098752, '法务经理', '2021-09-24 09:40:52'); +INSERT INTO `zz_flow_task_comment` VALUES (1441216073780170752, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '4fec915c-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1eewt01', '法务部审批', 'multi_consign', '用户 [leaderLaw] 加签 [[\"admin\"]]。', NULL, 1440965808049098752, '法务经理', '2021-09-24 09:41:03'); +INSERT INTO `zz_flow_task_comment` VALUES (1441216212972343296, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c18ac0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '法务部会签', 'multi_agree', '同意', NULL, 1440965808049098752, '法务经理', '2021-09-24 09:41:36'); +INSERT INTO `zz_flow_task_comment` VALUES (1441216292819308544, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c163a6-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '法务部会签', 'multi_refuse', '不同意', NULL, 1440965586715676672, '员工B', '2021-09-24 09:41:55'); +INSERT INTO `zz_flow_task_comment` VALUES (1441216373144424448, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '73c18abb-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '法务部会签', 'multi_agree', '同意', NULL, 1440965697961201664, '员工C', '2021-09-24 09:42:15'); +INSERT INTO `zz_flow_task_comment` VALUES (1441216770470842368, '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', '7a4309f7-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '法务部会签', 'stop', '多实例条件配置错误', NULL, 1440911410581213417, '管理员', '2021-09-24 09:43:49'); +INSERT INTO `zz_flow_task_comment` VALUES (1441217206766538752, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b41a38d-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_0nyla1r', '合同录入', 'agree', NULL, NULL, 1440966324770574336, '员工D', '2021-09-24 09:45:33'); +INSERT INTO `zz_flow_task_comment` VALUES (1441217290182856704, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '1b4488c4-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_1ucrh52', '业务部领导审批', 'agree', '同意', NULL, 1440966073686953984, '天津总监', '2021-09-24 09:45:53'); +INSERT INTO `zz_flow_task_comment` VALUES (1441217345438617600, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '271ebea3-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_0tm3mph', '造价部审批', 'agree', '同意', NULL, 1440911410581213417, '管理员', '2021-09-24 09:46:06'); +INSERT INTO `zz_flow_task_comment` VALUES (1441217371766263808, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '271e978f-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_138m4nn', '工程部审批', 'agree', '同意', NULL, 1440911410581213417, '管理员', '2021-09-24 09:46:13'); +INSERT INTO `zz_flow_task_comment` VALUES (1441217738105163776, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '32b7097e-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_1yuuyie', '财务部审批', 'agree', '同意', NULL, 1440966186522120192, '天津经理', '2021-09-24 09:47:40'); +INSERT INTO `zz_flow_task_comment` VALUES (1441217836524507136, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '66c6d396-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_1eewt01', '法务部审批', 'multi_sign', '用户 [leaderLaw] 会签 [[\"leaderLaw\",\"userC\"]]。', NULL, 1440965808049098752, '法务经理', '2021-09-24 09:48:03'); +INSERT INTO `zz_flow_task_comment` VALUES (1441217872834596864, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c12a5e-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '法务部会签', 'multi_agree', '同意', NULL, 1440965808049098752, '法务经理', '2021-09-24 09:48:12'); +INSERT INTO `zz_flow_task_comment` VALUES (1441217994800762880, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '66c6d396-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_1eewt01', '法务部审批', 'multi_consign', '用户 [leaderLaw] 加签 [[\"userB\"]]。', NULL, 1440965808049098752, '法务经理', '2021-09-24 09:48:41'); +INSERT INTO `zz_flow_task_comment` VALUES (1441218049788088320, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '8b4134ba-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '法务部会签', 'multi_agree', '拒绝', NULL, 1440965586715676672, '员工B', '2021-09-24 09:48:54'); +INSERT INTO `zz_flow_task_comment` VALUES (1441218134890516480, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '74c15172-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '法务部会签', 'multi_agree', 't同意', NULL, 1440965697961201664, '员工C', '2021-09-24 09:49:15'); +INSERT INTO `zz_flow_task_comment` VALUES (1441218265987682304, '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', '9f286bc3-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_1h3pnxy', '总经理审批', 'agree', '同意', NULL, 1440969706411397120, '总部领导', '2021-09-24 09:49:46'); +INSERT INTO `zz_flow_task_comment` VALUES (1441218427363528704, 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b70062-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_08p9kng', '录入', 'agree', NULL, NULL, 1440911410581213417, '管理员', '2021-09-24 09:50:24'); +INSERT INTO `zz_flow_task_comment` VALUES (1441218497429377024, 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_12olr01', '转办', 'transfer', '交给你了', 'leaderHR', 1440911410581213417, '管理员', '2021-09-24 09:50:41'); +INSERT INTO `zz_flow_task_comment` VALUES (1441218606418366464, 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 'c8b9bf89-1cd9-11ec-acd8-3ae4f1d3c3af', 'Activity_12olr01', '转办', 'agree', '同意', NULL, 1440965344985354240, '人事经理', '2021-09-24 09:51:07'); +INSERT INTO `zz_flow_task_comment` VALUES (1441312737664700416, '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '22f9b37c-1d0e-11ec-8336-3ae4f1d3c3af', 'Activity_03kjurt', '报销单录入', 'agree', NULL, NULL, 1440966324770574336, '员工D', '2021-09-24 16:05:10'); +INSERT INTO `zz_flow_task_comment` VALUES (1441324108838080512, '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', '23032963-1d0e-11ec-8336-3ae4f1d3c3af', 'Activity_0ywxfwu', '部门领导审批', 'agree', '同意', NULL, 1440966073686953984, '天津总监', '2021-09-24 16:50:21'); +INSERT INTO `zz_flow_task_comment` VALUES (1441340309681213440, '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', '7138fd96-1d1d-11ec-8336-3ae4f1d3c3af', 'Activity_03kjurt', '报销单录入', 'agree', NULL, NULL, 1440966324770574336, '员工D', '2021-09-24 17:54:43'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_flow_task_ext +-- ---------------------------- +DROP TABLE IF EXISTS `zz_flow_task_ext`; +CREATE TABLE `zz_flow_task_ext` ( + `process_definition_id` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '流程引擎的定义Id', + `task_id` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '流程引擎任务Id', + `operation_list_json` longtext COLLATE utf8mb4_bin COMMENT '操作列表JSON', + `variable_list_json` longtext COLLATE utf8mb4_bin COMMENT '变量列表JSON', + `assignee_list_json` text COLLATE utf8mb4_bin COMMENT '存储多实例的assigneeList的JSON', + `group_type` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '分组类型', + PRIMARY KEY (`process_definition_id`,`task_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_flow_task_ext +-- ---------------------------- +BEGIN; +INSERT INTO `zz_flow_task_ext` VALUES ('flowConSign:1:b981c1fb-1c51-11ec-94ee-5ef70686b817', 'Activity_006g6qo', '[{\"showOrder\":\"0\",\"id\":\"1632389733600\",\"label\":\"同意\",\"type\":\"multi_agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowConSign:1:b981c1fb-1c51-11ec-94ee-5ef70686b817', 'Activity_0p7omdm', '[{\"showOrder\":\"0\",\"id\":\"1632389682895\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632389686939\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowConSign:1:b981c1fb-1c51-11ec-94ee-5ef70686b817', 'Activity_1xk7j4n', '[{\"showOrder\":\"0\",\"id\":\"1632389626319\",\"label\":\"提交\",\"type\":\"multi_sign\"},{\"showOrder\":\"1\",\"id\":\"1632389633373\",\"label\":\"加签\",\"type\":\"multi_consign\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', 'Activity_098ncvw', '[{\"showOrder\":\"0\",\"id\":\"1632389190662\",\"label\":\"同意\",\"type\":\"multi_agree\"},{\"showOrder\":\"1\",\"id\":\"1632389197406\",\"label\":\"拒绝\",\"type\":\"multi_refuse\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', 'Activity_0nyla1r', '[{\"showOrder\":\"0\",\"id\":\"1632388965712\",\"label\":\"提交\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', 'Activity_0tm3mph', '[{\"showOrder\":\"0\",\"id\":\"1632388982377\",\"label\":\"同意\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', 'Activity_138m4nn', '[{\"showOrder\":\"0\",\"id\":\"1632388978101\",\"label\":\"同意\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', 'Activity_1eewt01', '[{\"showOrder\":\"0\",\"id\":\"1632389337024\",\"label\":\"会签\",\"type\":\"multi_sign\"},{\"showOrder\":\"1\",\"id\":\"1632389341901\",\"label\":\"加签\",\"type\":\"multi_consign\"}]', NULL, NULL, 'POST'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', 'Activity_1h3pnxy', '[{\"showOrder\":\"0\",\"id\":\"1632389449508\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632389452850\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', 'Activity_1ucrh52', '[{\"showOrder\":\"0\",\"id\":\"1632388972455\",\"label\":\"同意\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT_POST_LEADER'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:1:1bbc0c53-1c51-11ec-94ee-5ef70686b817', 'Activity_1yuuyie', '[{\"showOrder\":\"0\",\"id\":\"1632389037814\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632389042489\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'POST'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '[{\"showOrder\":\"0\",\"id\":\"1632389190662\",\"label\":\"同意\",\"type\":\"multi_agree\"},{\"showOrder\":\"1\",\"id\":\"1632389197406\",\"label\":\"拒绝\",\"type\":\"multi_refuse\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_0nyla1r', '[{\"showOrder\":\"0\",\"id\":\"1632388965712\",\"label\":\"提交\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_0tm3mph', '[{\"showOrder\":\"0\",\"id\":\"1632388982377\",\"label\":\"同意\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_138m4nn', '[{\"showOrder\":\"0\",\"id\":\"1632388978101\",\"label\":\"同意\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_1eewt01', '[{\"showOrder\":\"0\",\"id\":\"1632389337024\",\"label\":\"会签\",\"type\":\"multi_sign\"},{\"showOrder\":\"1\",\"id\":\"1632389341901\",\"label\":\"加签\",\"type\":\"multi_consign\"}]', NULL, NULL, 'POST'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_1h3pnxy', '[{\"showOrder\":\"0\",\"id\":\"1632389449508\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632389452850\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_1ucrh52', '[{\"showOrder\":\"0\",\"id\":\"1632388972455\",\"label\":\"同意\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT_POST_LEADER'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', 'Activity_1yuuyie', '[{\"showOrder\":\"0\",\"id\":\"1632389037814\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632389042489\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'POST'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_098ncvw', '[{\"showOrder\":\"0\",\"id\":\"1632389190662\",\"label\":\"同意\",\"type\":\"multi_agree\"},{\"showOrder\":\"1\",\"id\":\"1632389197406\",\"label\":\"拒绝\",\"type\":\"multi_refuse\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_0nyla1r', '[{\"showOrder\":\"0\",\"id\":\"1632388965712\",\"label\":\"提交\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_0tm3mph', '[{\"showOrder\":\"0\",\"id\":\"1632388982377\",\"label\":\"同意\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_138m4nn', '[{\"showOrder\":\"0\",\"id\":\"1632388978101\",\"label\":\"同意\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1eewt01', '[{\"showOrder\":\"0\",\"id\":\"1632389337024\",\"label\":\"会签\",\"type\":\"multi_sign\"},{\"showOrder\":\"1\",\"id\":\"1632389341901\",\"label\":\"加签\",\"type\":\"multi_consign\"}]', NULL, NULL, 'POST'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1h3pnxy', '[{\"showOrder\":\"0\",\"id\":\"1632389449508\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632389452850\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1ucrh52', '[{\"showOrder\":\"0\",\"id\":\"1632388972455\",\"label\":\"同意\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT_POST_LEADER'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', 'Activity_1yuuyie', '[{\"showOrder\":\"0\",\"id\":\"1632389037814\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632389042489\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'POST'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'Activity_0olxatv', '[{\"showOrder\":\"0\",\"id\":\"1632388147727\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632388151069\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'POST'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'Activity_0sc2yuf', '[{\"showOrder\":\"0\",\"id\":\"1632387369558\",\"label\":\"提交\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'Activity_1jw5u20', '[{\"showOrder\":\"0\",\"id\":\"1632387389734\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632387393116\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'DEPT_POST_LEADER'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowSubmit:1:efe9db3f-1c4e-11ec-94ee-5ef70686b817', 'Activity_03kjurt', '[{\"showOrder\":\"0\",\"id\":\"1632388352676\",\"label\":\"提交\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowSubmit:1:efe9db3f-1c4e-11ec-94ee-5ef70686b817', 'Activity_0qay48u', '[{\"showOrder\":\"0\",\"id\":\"1632388536771\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632388540081\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowSubmit:1:efe9db3f-1c4e-11ec-94ee-5ef70686b817', 'Activity_0ywxfwu', '[{\"showOrder\":\"0\",\"id\":\"1632388372003\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632388375866\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', '[{\"variableType\":1,\"showName\":\"报销金额\",\"variableName\":\"totalAmount\",\"bindColumnId\":1440946127493926912,\"createTime\":1632388418000,\"builtin\":false,\"bindDatasourceId\":1440946127531675648,\"variableId\":1440967581673459712,\"entryId\":1440966906914803712}]', NULL, 'DEPT_POST_LEADER'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', 'Activity_03kjurt', '[{\"showOrder\":\"0\",\"id\":\"1632388352676\",\"label\":\"提交\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', 'Activity_0qay48u', '[{\"showOrder\":\"0\",\"id\":\"1632388536771\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632388540081\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', 'Activity_0ywxfwu', '[{\"showOrder\":\"0\",\"id\":\"1632388372003\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632388375866\",\"label\":\"拒绝\",\"type\":\"refuse\"}]', '[{\"variableType\":1,\"showName\":\"报销金额\",\"variableName\":\"totalAmount\",\"bindColumnId\":1440946127493926912,\"createTime\":1632388418000,\"builtin\":false,\"bindDatasourceId\":1440946127531675648,\"variableId\":1440967581673459712,\"entryId\":1440966906914803712}]', NULL, 'DEPT_POST_LEADER'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'Activity_08p9kng', '[{\"showOrder\":\"0\",\"id\":\"1632389836108\",\"label\":\"提交\",\"type\":\"agree\"}]', NULL, NULL, 'DEPT'); +INSERT INTO `zz_flow_task_ext` VALUES ('flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'Activity_12olr01', '[{\"showOrder\":\"0\",\"id\":\"1632389848554\",\"label\":\"同意\",\"type\":\"agree\"},{\"showOrder\":\"1\",\"id\":\"1632389853959\",\"label\":\"转办\",\"type\":\"transfer\"}]', NULL, NULL, 'DEPT'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_flow_work_order +-- ---------------------------- +DROP TABLE IF EXISTS `zz_flow_work_order`; +CREATE TABLE `zz_flow_work_order` ( + `work_order_id` bigint(20) NOT NULL COMMENT '主键Id', + `process_definition_key` varchar(128) COLLATE utf8mb4_bin NOT NULL COMMENT '流程定义标识', + `process_definition_name` varchar(200) CHARACTER SET utf8mb4 NOT NULL COMMENT '流程名称', + `process_definition_id` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '流程引擎的定义Id', + `process_instance_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '流程实例Id', + `online_table_id` bigint(20) DEFAULT NULL COMMENT '在线表单的主表Id', + `business_key` varchar(128) COLLATE utf8mb4_bin NOT NULL COMMENT '业务主键值', + `task_id` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '未完成的任务Id', + `task_name` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '未完成的任务名称', + `task_definition_key` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '未完成的任务标识', + `flow_status` int(11) NOT NULL DEFAULT '0' COMMENT '流程状态', + `submit_username` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '提交用户登录名称', + `dept_id` bigint(20) NOT NULL COMMENT '提交用户所在部门Id', + `update_time` datetime NOT NULL COMMENT '更新时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`work_order_id`) USING BTREE, + UNIQUE KEY `uk_process_instance_id` (`process_instance_id`) USING BTREE, + KEY `idx_process_definition_key` (`process_definition_key`) USING BTREE, + KEY `idx_create_user_id` (`create_user_id`) USING BTREE, + KEY `idx_create_time` (`create_time`) USING BTREE, + KEY `idx_dept_id` (`dept_id`) USING BTREE, + KEY `idx_business_key` (`business_key`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_flow_work_order +-- ---------------------------- +BEGIN; +INSERT INTO `zz_flow_work_order` VALUES (1441213241270210560, 'flowLeave', '请假申请', 'flowLeave:1:1bc2a35b-1c4e-11ec-94ee-5ef70686b817', 'e7ac71d9-1cd6-11ec-acd8-3ae4f1d3c3af', 1440945228079960064, '1441213240326492160', NULL, NULL, NULL, 3, 'userD', 1440963698460987392, '2021-09-24 09:31:04', 1440965465605148672, '2021-09-24 09:29:48', 1440966324770574336, 1); +INSERT INTO `zz_flow_work_order` VALUES (1441213876598214656, 'flowSubmit', '报销申请', 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '420171f8-1cd7-11ec-acd8-3ae4f1d3c3af', 1440946127460372480, '1441213876367527936', NULL, NULL, NULL, 3, 'userD', 1440963698460987392, '2021-09-24 09:33:02', 1440969706411397120, '2021-09-24 09:32:19', 1440966324770574336, 1); +INSERT INTO `zz_flow_work_order` VALUES (1441215377722839040, 'flowContract', '合同审批', 'flowContract:2:9edd1d08-1cd7-11ec-acd8-3ae4f1d3c3af', '17547fd9-1cd8-11ec-acd8-3ae4f1d3c3af', 1440952815294877696, '1441215377508929536', NULL, NULL, NULL, 4, 'userD', 1440963698460987392, '2021-09-24 09:43:49', 1440911410581213417, '2021-09-24 09:38:17', 1440966324770574336, 1); +INSERT INTO `zz_flow_work_order` VALUES (1441217206770733056, 'flowContract', '合同审批', 'flowContract:3:d28aadd0-1cd8-11ec-acd8-3ae4f1d3c3af', '1b41a384-1cd9-11ec-acd8-3ae4f1d3c3af', 1440952815294877696, '1441217206602960896', NULL, NULL, NULL, 3, 'userD', 1440963698460987392, '2021-09-24 09:49:46', 1440969706411397120, '2021-09-24 09:45:33', 1440966324770574336, 1); +INSERT INTO `zz_flow_work_order` VALUES (1441218427367723008, 'flowTranslate', '转办流程', 'flowTranslate:1:faa41acf-1c51-11ec-94ee-5ef70686b817', 'c8b7005a-1cd9-11ec-acd8-3ae4f1d3c3af', 1440945228079960064, '1441218427220922368', NULL, NULL, NULL, 3, 'admin', 1440911410581213416, '2021-09-24 09:51:07', 1440965344985354240, '2021-09-24 09:50:24', 1440911410581213417, 1); +INSERT INTO `zz_flow_work_order` VALUES (1441312737689866240, 'flowSubmit', '报销申请', 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '22f398f3-1d0e-11ec-8336-3ae4f1d3c3af', 1440946127460372480, '1441312736167333888', NULL, NULL, NULL, 3, 'userD', 1440963698460987392, '2021-09-24 16:50:21', 1440966073686953984, '2021-09-24 16:05:10', 1440966324770574336, 1); +INSERT INTO `zz_flow_work_order` VALUES (1441340309685407744, 'flowSubmit', '报销申请', 'flowSubmit:2:1d2bc8f7-1c51-11ec-94ee-5ef70686b817', '7138d67d-1d1d-11ec-8336-3ae4f1d3c3af', 1440946127460372480, '1441340309442138112', NULL, NULL, NULL, 0, 'userD', 1440963698460987392, '2021-09-24 17:54:43', 1440966324770574336, '2021-09-24 17:54:43', 1440966324770574336, 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_column +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_column`; +CREATE TABLE `zz_online_column` ( + `column_id` bigint(20) NOT NULL COMMENT '主键Id', + `column_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '字段名', + `table_id` bigint(20) NOT NULL COMMENT '数据表Id', + `column_type` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '数据表中的字段类型', + `full_column_type` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '数据表中的完整字段类型(包括了精度和刻度)', + `primary_key` bit(1) NOT NULL COMMENT '是否为主键', + `auto_increment` bit(1) NOT NULL COMMENT '是否是自增主键(0: 不是 1: 是)', + `nullable` bit(1) NOT NULL COMMENT '是否可以为空 (0: 不可以为空 1: 可以为空)', + `column_default` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '缺省值', + `column_show_order` int(11) NOT NULL COMMENT '字段在数据表中的显示位置', + `column_comment` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '数据表中的字段注释', + `object_field_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '对象映射字段名称', + `object_field_type` varchar(32) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '对象映射字段类型', + `filter_type` int(11) NOT NULL DEFAULT '1' COMMENT '字段过滤类型', + `parent_key` bit(1) NOT NULL COMMENT '是否是主键的父Id', + `dept_filter` bit(1) NOT NULL COMMENT '是否部门过滤字段', + `user_filter` bit(1) NOT NULL COMMENT '是否用户过滤字段', + `field_kind` int(11) DEFAULT NULL COMMENT '字段类别', + `max_file_count` int(11) DEFAULT NULL COMMENT '包含的文件文件数量,0表示无限制', + `dict_id` bigint(20) DEFAULT NULL COMMENT '字典Id', + `update_time` datetime NOT NULL COMMENT '更新时间', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`column_id`), + KEY `idx_table_id` (`table_id`) USING BTREE, + KEY `idx_dict_id` (`dict_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_column +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_column` VALUES (1440945228088348672, 'id', 1440945228079960064, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'id', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:44:49', '2021-09-23 15:44:49'); +INSERT INTO `zz_online_column` VALUES (1440945228092542976, 'user_id', 1440945228079960064, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 2, '请假用户', 'userId', 'Long', 0, b'0', b'0', b'0', 21, NULL, 1440944417170001920, '2021-09-24 09:29:41', '2021-09-23 15:44:49'); +INSERT INTO `zz_online_column` VALUES (1440945228100931584, 'leave_reason', 1440945228079960064, 'varchar', 'varchar(512)', b'0', b'0', b'0', NULL, 3, '请假原因', 'leaveReason', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:44:49', '2021-09-23 15:44:49'); +INSERT INTO `zz_online_column` VALUES (1440945228105125888, 'leave_type', 1440945228079960064, 'int', 'int(11)', b'0', b'0', b'0', NULL, 4, '请假类型', 'leaveType', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, 1440943031288074240, '2021-09-23 15:45:01', '2021-09-23 15:44:49'); +INSERT INTO `zz_online_column` VALUES (1440945228113514496, 'leave_begin_time', 1440945228079960064, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 5, '请假开始时间', 'leaveBeginTime', 'Date', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:44:49', '2021-09-23 15:44:49'); +INSERT INTO `zz_online_column` VALUES (1440945228117708800, 'leave_end_time', 1440945228079960064, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 6, '请假结束时间', 'leaveEndTime', 'Date', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:44:49', '2021-09-23 15:44:49'); +INSERT INTO `zz_online_column` VALUES (1440945228126097408, 'apply_time', 1440945228079960064, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 7, '申请时间', 'applyTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 15:45:06', '2021-09-23 15:44:49'); +INSERT INTO `zz_online_column` VALUES (1440946127468761088, 'id', 1440946127460372480, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'id', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:48:23', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440946127481344000, 'submit_name', 1440946127460372480, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 2, '报销名称', 'submitName', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:48:23', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440946127489732608, 'submit_kind', 1440946127460372480, 'int', 'int(11)', b'0', b'0', b'0', NULL, 3, '报销类别', 'submitKind', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, 1440943168626364416, '2021-09-23 15:49:11', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440946127493926912, 'total_amount', 1440946127460372480, 'int', 'int(11)', b'0', b'0', b'0', NULL, 4, '报销金额', 'totalAmount', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:49:52', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440946127498121216, 'description', 1440946127460372480, 'varchar', 'varchar(512)', b'0', b'0', b'0', NULL, 5, '报销描述', 'description', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:48:23', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440946127506509824, 'memo', 1440946127460372480, 'varchar', 'varchar(512)', b'0', b'0', b'1', NULL, 6, '备注', 'memo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:48:23', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440946127510704128, 'update_user_id', 1440946127460372480, 'bigint', 'bigint(20)', b'0', b'0', b'1', NULL, 7, '修改人', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 15:50:04', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440946127514898432, 'update_time', 1440946127460372480, 'datetime', 'datetime', b'0', b'0', b'1', NULL, 8, '修改时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 15:50:08', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440946127523287040, 'create_user_id', 1440946127460372480, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 9, '创建人', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 15:50:12', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440946127527481344, 'create_time', 1440946127460372480, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 10, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 15:50:16', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_column` VALUES (1440947089222668288, 'id', 1440947089218473984, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'id', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:52:12', '2021-09-23 15:52:12'); +INSERT INTO `zz_online_column` VALUES (1440947089231056896, 'submit_id', 1440947089218473984, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 2, '报销单据Id', 'submitId', 'Long', 1, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:57:41', '2021-09-23 15:52:12'); +INSERT INTO `zz_online_column` VALUES (1440947089235251200, 'expense_type', 1440947089218473984, 'int', 'int(11)', b'0', b'0', b'0', NULL, 3, '费用类型', 'expenseType', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, 1440943309924077568, '2021-09-23 15:53:15', '2021-09-23 15:52:12'); +INSERT INTO `zz_online_column` VALUES (1440947089243639808, 'expense_time', 1440947089218473984, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 4, '发生日期', 'expenseTime', 'Date', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:52:12', '2021-09-23 15:52:12'); +INSERT INTO `zz_online_column` VALUES (1440947089252028416, 'amount', 1440947089218473984, 'int', 'int(11)', b'0', b'0', b'0', NULL, 5, '金额', 'amount', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:52:12', '2021-09-23 15:52:12'); +INSERT INTO `zz_online_column` VALUES (1440947089260417024, 'image_url', 1440947089218473984, 'varchar', 'varchar(512)', b'0', b'0', b'1', NULL, 6, '报销凭证', 'imageUrl', 'String', 0, b'0', b'0', b'0', 2, 1, NULL, '2021-09-23 15:53:53', '2021-09-23 15:52:12'); +INSERT INTO `zz_online_column` VALUES (1440947089264611328, 'description', 1440947089218473984, 'varchar', 'varchar(255)', b'0', b'0', b'1', NULL, 7, '费用描述', 'description', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 15:52:12', '2021-09-23 15:52:12'); +INSERT INTO `zz_online_column` VALUES (1440952815303266304, 'contract_id', 1440952815294877696, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'contractId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:14:57', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815307460608, 'first_party_id', 1440952815294877696, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 2, '甲方企业', 'firstPartyId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, 1440943452526219264, '2021-09-23 16:16:50', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815311654912, 'second_party_id', 1440952815294877696, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 3, '乙方企业', 'secondPartyId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, 1440943955939168256, '2021-09-23 16:16:59', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815315849216, 'contract_type', 1440952815294877696, 'int', 'int(11)', b'0', b'0', b'0', NULL, 4, '合同类型', 'contractType', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, 1440944300799037440, '2021-09-23 16:17:03', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815320043520, 'due_date', 1440952815294877696, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 5, '到期日期', 'dueDate', 'Date', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:14:57', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815324237824, 'sales_id', 1440952815294877696, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 6, '业务员', 'salesId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, 1440944417170001920, '2021-09-23 16:17:10', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815332626432, 'commission_rate', 1440952815294877696, 'int', 'int(11)', b'0', b'0', b'0', NULL, 7, '提成比例(%)', 'commissionRate', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:17:38', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815336820736, 'attachment', 1440952815294877696, 'varchar', 'varchar(512)', b'0', b'0', b'1', NULL, 8, '合同附件', 'attachment', 'String', 0, b'0', b'0', b'0', 1, 1, NULL, '2021-09-23 16:17:46', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815341015040, 'security_attachment', 1440952815294877696, 'varchar', 'varchar(512)', b'0', b'0', b'1', NULL, 9, '保密协议', 'securityAttachment', 'String', 0, b'0', b'0', b'0', 1, 1, NULL, '2021-09-23 16:17:53', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815345209344, 'intellectual_property_attachment', 1440952815294877696, 'varchar', 'varchar(512)', b'0', b'0', b'1', NULL, 10, '知识产权协议', 'intellectualPropertyAttachment', 'String', 0, b'0', b'0', b'0', 1, 1, NULL, '2021-09-23 16:18:00', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815349403648, 'other_attachment', 1440952815294877696, 'varchar', 'varchar(512)', b'0', b'0', b'1', NULL, 11, '其他附件', 'otherAttachment', 'String', 0, b'0', b'0', b'0', 1, 1, NULL, '2021-09-23 16:18:05', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815353597952, 'create_user_id', 1440952815294877696, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 12, '创建者', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 16:18:09', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815357792256, 'create_time', 1440952815294877696, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 13, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 16:18:15', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815361986560, 'update_user_id', 1440952815294877696, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 14, '更新者', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 16:18:19', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815366180864, 'update_time', 1440952815294877696, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 15, '最后更新时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 16:18:24', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952815370375168, 'deleted_flag', 1440952815294877696, 'int', 'int(11)', b'0', b'0', b'0', '0', 16, '删除标记(1: 正常 -1: 已删除)', 'deletedFlag', 'Integer', 0, b'0', b'0', b'0', 31, NULL, NULL, '2021-09-23 16:18:28', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_column` VALUES (1440952921037475840, 'first_party_id', 1440952921024892928, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'firstPartyId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:23', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921041670144, 'company_name', 1440952921024892928, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 2, '公司名称', 'companyName', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:23', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921050058752, 'legal_person', 1440952921024892928, 'varchar', 'varchar(64)', b'0', b'0', b'0', NULL, 3, '公司法人', 'legalPerson', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:18:38', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921054253056, 'legal_person_id', 1440952921024892928, 'char', 'char(18)', b'0', b'0', b'0', NULL, 4, '法人身份证号', 'legalPersonId', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:23', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921058447360, 'registry_address', 1440952921024892928, 'varchar', 'varchar(512)', b'0', b'0', b'0', NULL, 5, '注册地址', 'registryAddress', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:23', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921066835968, 'contact_info', 1440952921024892928, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 6, '联系方式', 'contactInfo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:23', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921079418880, 'business_scope', 1440952921024892928, 'varchar', 'varchar(4000)', b'0', b'0', b'0', NULL, 7, '经营范围', 'businessScope', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:23', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921087807488, 'memo', 1440952921024892928, 'varchar', 'varchar(1024)', b'0', b'0', b'1', NULL, 8, '备注', 'memo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:23', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921092001792, 'create_user_id', 1440952921024892928, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 9, '创建者', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 16:18:48', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921100390400, 'create_time', 1440952921024892928, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 10, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 16:18:51', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921104584704, 'update_user_id', 1440952921024892928, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 11, '更新者', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 16:18:54', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921108779008, 'update_time', 1440952921024892928, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 12, '最后更新时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 16:19:00', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952921112973312, 'deleted_flag', 1440952921024892928, 'int', 'int(11)', b'0', b'0', b'0', '0', 13, '删除标记(1: 正常 -1: 已删除)', 'deletedFlag', 'Integer', 0, b'0', b'0', b'0', 31, NULL, NULL, '2021-09-23 16:19:04', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_column` VALUES (1440952988393803776, 'second_party_id', 1440952988389609472, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'secondPartyId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:39', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988406386688, 'company_name', 1440952988389609472, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 2, '公司名称', 'companyName', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:39', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988456718336, 'legal_person', 1440952988389609472, 'varchar', 'varchar(64)', b'0', b'0', b'0', NULL, 3, '公司法人', 'legalPerson', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:19:12', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988469301248, 'legal_person_id', 1440952988389609472, 'char', 'char(18)', b'0', b'0', b'0', NULL, 4, '法人身份证号', 'legalPersonId', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:39', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988473495552, 'registry_address', 1440952988389609472, 'varchar', 'varchar(512)', b'0', b'0', b'0', NULL, 5, '注册地址', 'registryAddress', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:39', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988486078464, 'contact_info', 1440952988389609472, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 6, '联系方式', 'contactInfo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:39', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988494467072, 'business_scope', 1440952988389609472, 'varchar', 'varchar(4000)', b'0', b'0', b'0', NULL, 7, '经营范围', 'businessScope', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:39', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988498661376, 'memo', 1440952988389609472, 'varchar', 'varchar(1024)', b'0', b'0', b'1', NULL, 8, '备注', 'memo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:15:39', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988502855680, 'create_user_id', 1440952988389609472, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 9, '创建者', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 16:19:17', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988507049984, 'create_time', 1440952988389609472, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 10, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 16:19:21', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988515438592, 'update_user_id', 1440952988389609472, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 11, '更新者', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 16:19:24', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988519632896, 'update_time', 1440952988389609472, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 12, '最后更新时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 16:19:28', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440952988528021504, 'deleted_flag', 1440952988389609472, 'int', 'int(11)', b'0', b'0', b'0', '0', 13, '删除标记(1: 正常 -1: 已删除)', 'deletedFlag', 'Integer', 0, b'0', b'0', b'0', 31, NULL, NULL, '2021-09-23 16:19:33', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_column` VALUES (1440953088910299136, 'contract_detail_id', 1440953088901910528, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'contractDetailId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:16:03', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088918687744, 'contract_id', 1440953088901910528, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 2, '合同Id', 'contractId', 'Long', 1, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:42:59', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088922882048, 'product_id', 1440953088901910528, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 3, '合同产品', 'productId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, 1440944049128214528, '2021-09-23 16:20:03', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088927076352, 'total_count', 1440953088901910528, 'int', 'int(11)', b'0', b'0', b'0', NULL, 4, '产品数量', 'totalCount', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:20:10', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088935464960, 'total_amount', 1440953088901910528, 'int', 'int(11)', b'0', b'0', b'0', NULL, 5, '产品总价', 'totalAmount', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:20:56', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088939659264, 'meno', 1440953088901910528, 'varchar', 'varchar(1024)', b'0', b'0', b'1', NULL, 6, '备注', 'meno', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:16:03', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088948047872, 'create_user_id', 1440953088901910528, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 7, '创建者', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 16:21:00', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088952242176, 'create_time', 1440953088901910528, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 8, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 16:21:04', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088960630784, 'update_user_id', 1440953088901910528, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 9, '更新者', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 16:21:07', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088964825088, 'update_time', 1440953088901910528, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 10, '最后更新时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 16:21:12', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953088973213696, 'deleted_flag', 1440953088901910528, 'int', 'int(11)', b'0', b'0', b'0', '0', 11, '删除标记(1: 正常 -1: 已删除)', 'deletedFlag', 'Integer', 0, b'0', b'0', b'0', 31, NULL, NULL, '2021-09-23 16:21:15', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_column` VALUES (1440953170518872064, 'pay_detail_id', 1440953170514677760, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'payDetailId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:16:22', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170531454976, 'contract_id', 1440953170514677760, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 2, '合同Id', 'contractId', 'Long', 1, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:43:04', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170535649280, 'pay_date', 1440953170514677760, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 3, '付款日期', 'payDate', 'Date', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:16:22', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170539843584, 'pay_type', 1440953170514677760, 'int', 'int(11)', b'0', b'0', b'0', NULL, 4, '付款类型', 'payType', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, 1440944184381935616, '2021-09-23 16:21:27', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170548232192, 'percentage', 1440953170514677760, 'int', 'int(11)', b'0', b'0', b'0', NULL, 5, '百分比', 'percentage', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:16:22', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170552426496, 'memo', 1440953170514677760, 'varchar', 'varchar(1024)', b'0', b'0', b'1', NULL, 6, '备注', 'memo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:16:22', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170560815104, 'create_user_id', 1440953170514677760, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 7, '创建者', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 16:21:43', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170569203712, 'create_time', 1440953170514677760, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 8, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 16:21:46', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170573398016, 'update_user_id', 1440953170514677760, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 9, '更新者', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 16:21:49', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170581786624, 'update_time', 1440953170514677760, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 10, '最后更新时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 16:21:52', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953170585980928, 'deleted_flag', 1440953170514677760, 'int', 'int(11)', b'0', b'0', b'0', '0', 11, '删除标记(1: 正常 -1: 已删除)', 'deletedFlag', 'Integer', 0, b'0', b'0', b'0', 31, NULL, NULL, '2021-09-23 16:21:55', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_column` VALUES (1440953245668216832, 'delivery_id', 1440953245664022528, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'deliveryId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:16:40', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245676605440, 'contract_id', 1440953245664022528, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 2, '合同Id', 'contractId', 'Long', 1, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:43:09', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245684994048, 'delivery_date', 1440953245664022528, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 3, '交付日期', 'deliveryDate', 'Date', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:16:40', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245697576960, 'product_id', 1440953245664022528, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 4, '交付产品', 'productId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, 1440944049128214528, '2021-09-23 16:22:18', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245705965568, 'total_count', 1440953245664022528, 'int', 'int(11)', b'0', b'0', b'0', NULL, 5, '交付数量', 'totalCount', 'Integer', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:22:21', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245718548480, 'memo', 1440953245664022528, 'varchar', 'varchar(1024)', b'0', b'0', b'1', NULL, 6, '备注', 'memo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:16:40', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245722742784, 'create_user_id', 1440953245664022528, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 7, '创建者', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 16:22:45', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245726937088, 'create_time', 1440953245664022528, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 8, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 16:22:48', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245731131392, 'update_user_id', 1440953245664022528, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 9, '更新者', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 16:22:52', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245735325696, 'update_time', 1440953245664022528, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 10, '最后更新时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 16:22:56', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440953245743714304, 'deleted_flag', 1440953245664022528, 'int', 'int(11)', b'0', b'0', b'0', '0', 11, '删除标记(1: 正常 -1: 已删除)', 'deletedFlag', 'Integer', 0, b'0', b'0', b'0', 31, NULL, NULL, '2021-09-23 16:22:59', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_column` VALUES (1440958971132252160, 'first_party_id', 1440958971128057856, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'firstPartyId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:39:25', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971140640768, 'company_name', 1440958971128057856, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 2, '公司名称', 'companyName', 'String', 3, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:41:25', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971144835072, 'legal_person', 1440958971128057856, 'varchar', 'varchar(64)', b'0', b'0', b'0', NULL, 3, '公司法人', 'legalPerson', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:39:32', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971149029376, 'legal_person_id', 1440958971128057856, 'char', 'char(18)', b'0', b'0', b'0', NULL, 4, '法人身份证号', 'legalPersonId', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:39:25', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971153223680, 'registry_address', 1440958971128057856, 'varchar', 'varchar(512)', b'0', b'0', b'0', NULL, 5, '注册地址', 'registryAddress', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:39:25', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971157417984, 'contact_info', 1440958971128057856, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 6, '联系方式', 'contactInfo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:39:25', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971161612288, 'business_scope', 1440958971128057856, 'varchar', 'varchar(4000)', b'0', b'0', b'0', NULL, 7, '经营范围', 'businessScope', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:39:25', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971165806592, 'memo', 1440958971128057856, 'varchar', 'varchar(1024)', b'0', b'0', b'1', NULL, 8, '备注', 'memo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:39:25', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971170000896, 'create_user_id', 1440958971128057856, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 9, '创建者', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 16:39:40', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971174195200, 'create_time', 1440958971128057856, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 10, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 16:39:43', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971178389504, 'update_user_id', 1440958971128057856, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 11, '更新者', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 16:39:46', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971182583808, 'update_time', 1440958971128057856, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 12, '最后更新时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 16:39:53', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440958971186778112, 'deleted_flag', 1440958971128057856, 'int', 'int(11)', b'0', b'0', b'0', '0', 13, '删除标记(1: 正常 -1: 已删除)', 'deletedFlag', 'Integer', 0, b'0', b'0', b'0', 31, NULL, NULL, '2021-09-23 16:39:58', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_column` VALUES (1440961208285925376, 'second_party_id', 1440961208273342464, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'secondPartyId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:48:18', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208294313984, 'company_name', 1440961208273342464, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 2, '公司名称', 'companyName', 'String', 3, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:48:23', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208298508288, 'legal_person', 1440961208273342464, 'varchar', 'varchar(64)', b'0', b'0', b'0', NULL, 3, '公司法人', 'legalPerson', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:48:28', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208302702592, 'legal_person_id', 1440961208273342464, 'char', 'char(18)', b'0', b'0', b'0', NULL, 4, '法人身份证号', 'legalPersonId', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:48:18', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208306896896, 'registry_address', 1440961208273342464, 'varchar', 'varchar(512)', b'0', b'0', b'0', NULL, 5, '注册地址', 'registryAddress', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:48:18', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208315285504, 'contact_info', 1440961208273342464, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 6, '联系方式', 'contactInfo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:48:18', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208319479808, 'business_scope', 1440961208273342464, 'varchar', 'varchar(4000)', b'0', b'0', b'0', NULL, 7, '经营范围', 'businessScope', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:48:18', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208323674112, 'memo', 1440961208273342464, 'varchar', 'varchar(1024)', b'0', b'0', b'1', NULL, 8, '备注', 'memo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:48:18', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208327868416, 'create_user_id', 1440961208273342464, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 9, '创建者', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 16:48:36', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208332062720, 'create_time', 1440961208273342464, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 10, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 16:48:40', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208336257024, 'update_user_id', 1440961208273342464, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 11, '更新者', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 16:48:44', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208340451328, 'update_time', 1440961208273342464, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 12, '最后更新时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 16:48:49', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440961208344645632, 'deleted_flag', 1440961208273342464, 'int', 'int(11)', b'0', b'0', b'0', '0', 13, '删除标记(1: 正常 -1: 已删除)', 'deletedFlag', 'Integer', 0, b'0', b'0', b'0', 31, NULL, NULL, '2021-09-23 16:48:55', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_column` VALUES (1440962162720772096, 'product_id', 1440962162712383488, 'bigint', 'bigint(20)', b'1', b'0', b'0', NULL, 1, '主键Id', 'productId', 'Long', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:52:06', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162729160704, 'product_name', 1440962162712383488, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 2, '产品名称', 'productName', 'String', 3, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:52:10', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162733355008, 'product_spec', 1440962162712383488, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 3, '规格', 'productSpec', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:52:06', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162737549312, 'type', 1440962162712383488, 'varchar', 'varchar(255)', b'0', b'0', b'0', NULL, 4, '型号', 'type', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:52:06', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162741743616, 'cost_price', 1440962162712383488, 'int', 'int(11)', b'0', b'0', b'0', NULL, 5, '产品价格', 'costPrice', 'Integer', 2, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:53:05', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162745937920, 'memo', 1440962162712383488, 'varchar', 'varchar(1024)', b'0', b'0', b'1', NULL, 6, '备注', 'memo', 'String', 0, b'0', b'0', b'0', NULL, NULL, NULL, '2021-09-23 16:52:06', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162750132224, 'create_user_id', 1440962162712383488, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 7, '创建者', 'createUserId', 'Long', 0, b'0', b'0', b'0', 21, NULL, NULL, '2021-09-23 16:52:20', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162754326528, 'create_time', 1440962162712383488, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 8, '创建时间', 'createTime', 'Date', 0, b'0', b'0', b'0', 20, NULL, NULL, '2021-09-23 16:52:23', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162762715136, 'update_user_id', 1440962162712383488, 'bigint', 'bigint(20)', b'0', b'0', b'0', NULL, 9, '更新者', 'updateUserId', 'Long', 0, b'0', b'0', b'0', 23, NULL, NULL, '2021-09-23 16:52:27', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162766909440, 'update_time', 1440962162712383488, 'datetime', 'datetime', b'0', b'0', b'0', NULL, 10, '最后更新时间', 'updateTime', 'Date', 0, b'0', b'0', b'0', 22, NULL, NULL, '2021-09-23 16:52:31', '2021-09-23 16:52:06'); +INSERT INTO `zz_online_column` VALUES (1440962162771103744, 'deleted_flag', 1440962162712383488, 'int', 'int(11)', b'0', b'0', b'0', '0', 11, '删除标记(1: 正常 -1: 已删除)', 'deletedFlag', 'Integer', 0, b'0', b'0', b'0', 31, NULL, NULL, '2021-09-23 16:52:34', '2021-09-23 16:52:06'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_column_rule +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_column_rule`; +CREATE TABLE `zz_online_column_rule` ( + `column_id` bigint(20) NOT NULL COMMENT '字段Id', + `rule_id` bigint(20) NOT NULL COMMENT '规则Id', + `prop_data_json` text COLLATE utf8mb4_bin COMMENT '规则属性数据', + PRIMARY KEY (`column_id`,`rule_id`) USING BTREE, + KEY `idx_rule_id` (`rule_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_column_rule +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_column_rule` VALUES (1440946127493926912, 2, '{\"message\":\"报销金额必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440946127493926912, 4, '{\"message\":\"报销金额必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440946261518716928, 2, '{\"message\":\"报销金额必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440946261518716928, 4, '{\"message\":\"报销金额必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440947089252028416, 2, '{\"message\":\"报销金额必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440947089252028416, 4, '{\"message\":\"报销金额必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440949025019793408, 2, '{\"message\":\"提成比例必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440949025019793408, 4, '{\"message\":\"提成比例必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440949181786099712, 6, '{\"message\":\"请输入正确的手机号码\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440949481989214208, 1, '{\"message\":\"产品数量必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440949481989214208, 4, '{\"message\":\"产品数量必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440949481993408512, 2, '{\"message\":\"产品总价必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440949481993408512, 4, '{\"message\":\"产品总价必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440949804128538624, 2, '{\"message\":\"交付商品数量必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440949804128538624, 4, '{\"message\":\"交付商品数量必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440952815332626432, 2, '{\"message\":\"提成比例必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440952815332626432, 4, '{\"message\":\"提成比例必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440953088927076352, 2, '{\"message\":\"产品数量必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440953088927076352, 4, '{\"message\":\"产品数量必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440953088935464960, 2, '{\"message\":\"产品总价必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440953088935464960, 4, '{\"message\":\"产品总价必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440953245705965568, 2, '{\"message\":\"交付数量必须大于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440953245705965568, 4, '{\"message\":\"交付数量必须大于0\",\"min\":0}'); +INSERT INTO `zz_online_column_rule` VALUES (1440962162741743616, 2, '{\"message\":\"产品价格不能小于0\"}'); +INSERT INTO `zz_online_column_rule` VALUES (1440962162741743616, 4, '{\"message\":\"产品价格不能小于0\",\"min\":0}'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_datasource +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_datasource`; +CREATE TABLE `zz_online_datasource` ( + `datasource_id` bigint(20) NOT NULL COMMENT '主键Id', + `datasource_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '数据源名称', + `variable_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '数据源变量名', + `dblink_id` bigint(20) NOT NULL COMMENT '数据库链接Id', + `master_table_id` bigint(20) NOT NULL COMMENT '主表Id', + `update_time` datetime NOT NULL COMMENT '更新时间', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`datasource_id`), + UNIQUE KEY `idx_variable_name` (`variable_name`) USING BTREE, + KEY `idx_master_table_id` (`master_table_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_datasource +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_datasource` VALUES (1440945228130291712, '请假申请', 'dsFlowLeave', 1, 1440945228079960064, '2021-09-23 15:44:49', '2021-09-23 15:44:49'); +INSERT INTO `zz_online_datasource` VALUES (1440946127531675648, '报销申请', 'dsFlowSubmit', 1, 1440946127460372480, '2021-09-23 15:48:23', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_datasource` VALUES (1440952815374569472, '合同审批', 'dsFlowContract', 1, 1440952815294877696, '2021-09-23 16:14:57', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_datasource` VALUES (1440958971190972416, '甲方管理', 'dsFirstParty', 1, 1440958971128057856, '2021-09-23 16:39:25', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_datasource` VALUES (1440961208344645633, '乙方管理', 'dsSecondParty', 1, 1440961208273342464, '2021-09-23 16:48:18', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_datasource` VALUES (1440962162771103745, '产品管理', 'dsProduct', 1, 1440962162712383488, '2021-09-23 16:52:06', '2021-09-23 16:52:06'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_datasource_relation +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_datasource_relation`; +CREATE TABLE `zz_online_datasource_relation` ( + `relation_id` bigint(20) NOT NULL COMMENT '主键Id', + `relation_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '关联名称', + `variable_name` varchar(128) COLLATE utf8mb4_bin NOT NULL COMMENT '变量名', + `datasource_id` bigint(20) NOT NULL COMMENT '主数据源Id', + `relation_type` int(11) NOT NULL COMMENT '关联类型', + `master_column_id` bigint(20) NOT NULL COMMENT '主表关联字段Id', + `slave_table_id` bigint(20) NOT NULL COMMENT '从表Id', + `slave_column_id` bigint(20) NOT NULL COMMENT '从表关联字段Id', + `cascade_delete` bit(1) NOT NULL COMMENT '删除主表的时候是否级联删除一对一和一对多的从表数据,多对多只是删除关联,不受到这个标记的影响。', + `left_join` bit(1) NOT NULL COMMENT '是否左连接', + `update_time` datetime NOT NULL COMMENT '更新时间', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`relation_id`) USING BTREE, + KEY `idx_datasource_id` (`datasource_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_datasource_relation +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_datasource_relation` VALUES (1440947089268805632, '报销详情', 'id_zz_test_flow_submit_detail_submit_idRelation', 1440946127531675648, 1, 1440946127468761088, 1440947089218473984, 1440947089231056896, b'1', b'1', '2021-09-23 15:52:12', '2021-09-23 15:52:12'); +INSERT INTO `zz_online_datasource_relation` VALUES (1440952921117167616, '甲方企业', 'first_party_id_zz_test_flow_first_party_first_party_idRelation', 1440952815374569472, 0, 1440952815307460608, 1440952921024892928, 1440952921037475840, b'0', b'1', '2021-09-23 16:15:23', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_datasource_relation` VALUES (1440952988536410112, '乙方企业', 'second_party_id_zz_test_flow_second_party_second_party_idRelation', 1440952815374569472, 0, 1440952815311654912, 1440952988389609472, 1440952988393803776, b'0', b'1', '2021-09-23 16:15:39', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_datasource_relation` VALUES (1440953088977408000, '合同详情', 'contract_id_zz_test_flow_contract_detail_contract_idRelation', 1440952815374569472, 1, 1440952815303266304, 1440953088901910528, 1440953088918687744, b'1', b'1', '2021-09-23 16:16:03', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_datasource_relation` VALUES (1440953170590175232, '付款详情', 'contract_id_zz_test_flow_pay_detail_contract_idRelation', 1440952815374569472, 1, 1440952815303266304, 1440953170514677760, 1440953170531454976, b'1', b'1', '2021-09-23 16:16:22', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_datasource_relation` VALUES (1440953245747908608, '交付详情', 'contract_id_zz_test_flow_delivery_detail_contract_idRelation', 1440952815374569472, 1, 1440952815303266304, 1440953245664022528, 1440953245676605440, b'1', b'1', '2021-09-23 16:16:40', '2021-09-23 16:16:40'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_datasource_table +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_datasource_table`; +CREATE TABLE `zz_online_datasource_table` ( + `id` bigint(20) NOT NULL COMMENT '主键Id', + `datasource_id` bigint(20) NOT NULL COMMENT '数据源Id', + `relation_id` bigint(20) DEFAULT NULL COMMENT '数据源关联Id', + `table_id` bigint(20) NOT NULL COMMENT '数据表Id', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_relation_id` (`relation_id`) USING BTREE, + KEY `idx_datasource_id` (`datasource_id`) USING BTREE, + KEY `idx_table_id` (`table_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_datasource_table +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_datasource_table` VALUES (1440945228134486016, 1440945228130291712, NULL, 1440945228079960064); +INSERT INTO `zz_online_datasource_table` VALUES (1440946127535869952, 1440946127531675648, NULL, 1440946127460372480); +INSERT INTO `zz_online_datasource_table` VALUES (1440947089272999936, 1440946127531675648, 1440947089268805632, 1440947089218473984); +INSERT INTO `zz_online_datasource_table` VALUES (1440952815378763776, 1440952815374569472, NULL, 1440952815294877696); +INSERT INTO `zz_online_datasource_table` VALUES (1440952921121361920, 1440952815374569472, 1440952921117167616, 1440952921024892928); +INSERT INTO `zz_online_datasource_table` VALUES (1440952988540604416, 1440952815374569472, 1440952988536410112, 1440952988389609472); +INSERT INTO `zz_online_datasource_table` VALUES (1440953088981602304, 1440952815374569472, 1440953088977408000, 1440953088901910528); +INSERT INTO `zz_online_datasource_table` VALUES (1440953170594369536, 1440952815374569472, 1440953170590175232, 1440953170514677760); +INSERT INTO `zz_online_datasource_table` VALUES (1440953245752102912, 1440952815374569472, 1440953245747908608, 1440953245664022528); +INSERT INTO `zz_online_datasource_table` VALUES (1440958971195166720, 1440958971190972416, NULL, 1440958971128057856); +INSERT INTO `zz_online_datasource_table` VALUES (1440961208348839936, 1440961208344645633, NULL, 1440961208273342464); +INSERT INTO `zz_online_datasource_table` VALUES (1440962162775298048, 1440962162771103745, NULL, 1440962162712383488); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_dblink +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_dblink`; +CREATE TABLE `zz_online_dblink` ( + `dblink_id` bigint(20) NOT NULL COMMENT '主键Id', + `dblink_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '链接中文名称', + `variable_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '链接英文名称', + `dblink_desc` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '链接描述', + `dblink_config_constant` int(255) NOT NULL COMMENT '数据源配置常量', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`dblink_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_dblink +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_dblink` VALUES (1, 'first', 'first', '第一个链接', 0, '2021-09-23 00:00:00'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_dict +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_dict`; +CREATE TABLE `zz_online_dict` ( + `dict_id` bigint(20) NOT NULL COMMENT '主键Id', + `dict_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '字典名称', + `dict_type` int(11) NOT NULL COMMENT '字典类型', + `dblink_id` bigint(20) DEFAULT NULL COMMENT '数据库链接Id', + `table_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '字典表名称', + `key_column_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '字典表键字段名称', + `parent_key_column_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '字典表父键字段名称', + `value_column_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '字典值字段名称', + `deleted_column_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '逻辑删除字段', + `user_filter_column_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户过滤滤字段名称', + `dept_filter_column_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'dept_filter_column_name', + `tenant_filter_column_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '租户过滤字段名称', + `tree_flag` bit(1) NOT NULL COMMENT '是否树形标记', + `dict_list_url` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '获取字典列表数据的url', + `dict_ids_url` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '根据主键id批量获取字典数据的url', + `dict_data_json` text COLLATE utf8mb4_bin COMMENT '字典的JSON数据', + `update_time` datetime NOT NULL COMMENT '更新时间', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`dict_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_dict +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_dict` VALUES (1440943031288074240, '请假类型', 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, b'0', NULL, NULL, '{\"dictData\":[{\"type\":\"Integer\",\"id\":1,\"name\":\"年假\"},{\"type\":\"Integer\",\"id\":2,\"name\":\"事假\"},{\"type\":\"Integer\",\"id\":3,\"name\":\"婚假\"}],\"paramList\":[]}', '2021-09-23 15:36:05', '2021-09-23 15:36:05'); +INSERT INTO `zz_online_dict` VALUES (1440943168626364416, '报销类别', 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, b'0', NULL, NULL, '{\"dictData\":[{\"type\":\"Integer\",\"id\":1,\"name\":\"差旅报销\"},{\"type\":\"Integer\",\"id\":2,\"name\":\"日常报销\"}],\"paramList\":[]}', '2021-09-23 15:36:37', '2021-09-23 15:36:37'); +INSERT INTO `zz_online_dict` VALUES (1440943309924077568, '费用类别', 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, b'0', NULL, NULL, '{\"dictData\":[{\"type\":\"Integer\",\"id\":1,\"name\":\"食宿费用\"},{\"type\":\"Integer\",\"id\":2,\"name\":\"交通费用\"}],\"paramList\":[]}', '2021-09-23 15:37:11', '2021-09-23 15:37:11'); +INSERT INTO `zz_online_dict` VALUES (1440943452526219264, '甲方企业', 1, 1, 'zz_test_flow_first_party', 'first_party_id', NULL, 'company_name', 'deleted_flag', NULL, NULL, NULL, b'0', NULL, NULL, '{\"paramList\":[]}', '2021-09-23 15:37:45', '2021-09-23 15:37:45'); +INSERT INTO `zz_online_dict` VALUES (1440943955939168256, '乙方企业', 1, 1, 'zz_test_flow_second_party', 'second_party_id', NULL, 'company_name', 'deleted_flag', NULL, NULL, NULL, b'0', NULL, NULL, '{\"paramList\":[]}', '2021-09-23 15:39:45', '2021-09-23 15:39:45'); +INSERT INTO `zz_online_dict` VALUES (1440944049128214528, '商品字典', 1, 1, 'zz_test_flow_product', 'product_id', NULL, 'product_name', 'deleted_flag', NULL, NULL, NULL, b'0', NULL, NULL, '{\"paramList\":[]}', '2021-09-23 15:40:07', '2021-09-23 15:40:07'); +INSERT INTO `zz_online_dict` VALUES (1440944184381935616, '付款类型', 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, b'0', NULL, NULL, '{\"dictData\":[{\"type\":\"Integer\",\"id\":1,\"name\":\"预付款\"},{\"type\":\"Integer\",\"id\":2,\"name\":\"分期款\"},{\"type\":\"Integer\",\"id\":3,\"name\":\"项目尾款\"}],\"paramList\":[]}', '2021-09-23 15:40:40', '2021-09-23 15:40:40'); +INSERT INTO `zz_online_dict` VALUES (1440944300799037440, '合同类型', 15, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, b'0', NULL, NULL, '{\"dictData\":[{\"type\":\"Integer\",\"id\":1,\"name\":\"生产合同\"},{\"type\":\"Integer\",\"id\":2,\"name\":\"代工合同\"}],\"paramList\":[]}', '2021-09-23 15:41:07', '2021-09-23 15:41:07'); +INSERT INTO `zz_online_dict` VALUES (1440944417170001920, '用户字典', 1, 1, 'zz_sys_user', 'user_id', NULL, 'show_name', 'deleted_flag', NULL, NULL, NULL, b'0', NULL, NULL, '{\"paramList\":[]}', '2021-09-23 15:41:35', '2021-09-23 15:41:35'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_form +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_form`; +CREATE TABLE `zz_online_form` ( + `form_id` bigint(20) NOT NULL COMMENT '主键Id', + `page_id` bigint(20) NOT NULL COMMENT '页面id', + `form_code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '表单编码', + `form_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '表单名称', + `form_kind` int(11) NOT NULL COMMENT '表单类别', + `form_type` int(11) NOT NULL COMMENT '表单类型', + `master_table_id` bigint(20) NOT NULL COMMENT '表单主表id', + `widget_json` mediumtext COLLATE utf8mb4_bin COMMENT '表单组件JSON', + `params_json` text COLLATE utf8mb4_bin COMMENT '表单参数JSON', + `update_time` datetime NOT NULL COMMENT '更新时间', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`form_id`) USING BTREE, + UNIQUE KEY `uk_page_id_form_code` (`page_id`,`form_code`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_form +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_form` VALUES (1440945411354267648, 1440945149889744896, 'formFlowLeave', '请假申请', 5, 10, 1440945228079960064, '{\"formConfig\":{\"formKind\":5,\"formType\":10,\"gutter\":20,\"labelWidth\":120,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":10,\"span\":24,\"placeholder\":\"\",\"id\":1632383156919,\"datasourceId\":\"1440945228130291712\",\"tableId\":\"1440945228079960064\",\"columnId\":\"1440945228105125888\",\"columnName\":\"leave_type\",\"showName\":\"请假类型\",\"variableName\":\"leaveType\",\"dictParamList\":[],\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":20,\"span\":24,\"placeholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"valueFormat\":\"yyyy-MM-dd\",\"readOnly\":false,\"disabled\":false,\"id\":1632383163405,\"datasourceId\":\"1440945228130291712\",\"tableId\":\"1440945228079960064\",\"columnId\":\"1440945228113514496\",\"columnName\":\"leave_begin_time\",\"showName\":\"开始时间\",\"variableName\":\"leaveBeginTime\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":20,\"span\":24,\"placeholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"valueFormat\":\"yyyy-MM-dd\",\"readOnly\":false,\"disabled\":false,\"id\":1632383171595,\"datasourceId\":\"1440945228130291712\",\"tableId\":\"1440945228079960064\",\"columnId\":\"1440945228117708800\",\"columnName\":\"leave_end_time\",\"showName\":\"结束时间\",\"variableName\":\"leaveEndTime\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632383177429,\"datasourceId\":\"1440945228130291712\",\"tableId\":\"1440945228079960064\",\"columnId\":\"1440945228100931584\",\"columnName\":\"leave_reason\",\"showName\":\"请假原因\",\"variableName\":\"leaveReason\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440945228088348672\",\"columnName\":\"id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 15:44:49\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"id\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440945228079960064\",\"updateTime\":\"2021-09-23 15:44:49\",\"userFilter\":false}]', '2021-09-23 15:46:50', '2021-09-23 15:45:32'); +INSERT INTO `zz_online_form` VALUES (1440945468593934336, 1440945149889744896, 'formOrderLeave', '请假工单', 5, 11, 1440945228079960064, '{\"formConfig\":{\"formKind\":5,\"formType\":11,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}],\"tableWidget\":{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440945228092542976\",\"tableId\":\"1440945228079960064\",\"showName\":\"请假用户\",\"showOrder\":1,\"sortable\":false},{\"columnId\":\"1440945228105125888\",\"tableId\":\"1440945228079960064\",\"showName\":\"请假类型\",\"showOrder\":2,\"sortable\":false},{\"columnId\":\"1440945228113514496\",\"tableId\":\"1440945228079960064\",\"showName\":\"开始时间\",\"showOrder\":3,\"sortable\":false},{\"columnId\":\"1440945228117708800\",\"tableId\":\"1440945228079960064\",\"showName\":\"结束时间\",\"showOrder\":4,\"sortable\":false}],\"operationList\":[],\"queryParamList\":[],\"tableId\":\"1440945228079960064\",\"variableName\":\"formOrderLeave\",\"showName\":\"请假工单\",\"hasError\":false,\"datasourceId\":\"1440945228130291712\"}},\"widgetList\":[]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440945228088348672\",\"columnName\":\"id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 15:44:49\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"id\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440945228079960064\",\"updateTime\":\"2021-09-23 15:44:49\",\"userFilter\":false}]', '2021-09-23 17:56:51', '2021-09-23 15:45:46'); +INSERT INTO `zz_online_form` VALUES (1440947675041107968, 1440946020174270464, 'formFlowSubmit', '报销申请', 5, 10, 1440946127460372480, '{\"formConfig\":{\"formKind\":5,\"formType\":10,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632383719604,\"datasourceId\":\"1440946127531675648\",\"tableId\":\"1440946127460372480\",\"columnId\":\"1440946127481344000\",\"columnName\":\"submit_name\",\"showName\":\"报销名称\",\"variableName\":\"submitName\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632383720428,\"datasourceId\":\"1440946127531675648\",\"tableId\":\"1440946127460372480\",\"columnId\":\"1440946127489732608\",\"columnName\":\"submit_kind\",\"showName\":\"报销类别\",\"variableName\":\"submitKind\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":3,\"span\":12,\"defaultValue\":0,\"min\":0,\"step\":1,\"precision\":2,\"controlVisible\":1,\"controlPosition\":0,\"readOnly\":false,\"disabled\":false,\"id\":1632383724574,\"datasourceId\":\"1440946127531675648\",\"tableId\":\"1440946127460372480\",\"columnId\":\"1440946127493926912\",\"columnName\":\"total_amount\",\"showName\":\"报销金额\",\"variableName\":\"totalAmount\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632383744379,\"datasourceId\":\"1440946127531675648\",\"tableId\":\"1440946127460372480\",\"columnId\":\"1440946127498121216\",\"columnName\":\"description\",\"showName\":\"报销描述\",\"variableName\":\"description\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632383752809,\"datasourceId\":\"1440946127531675648\",\"tableId\":\"1440946127460372480\",\"columnId\":\"1440946127506509824\",\"columnName\":\"memo\",\"showName\":\"备注\",\"variableName\":\"memo\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440947089235251200\",\"tableId\":\"1440947089218473984\",\"showName\":\"费用类型\",\"showOrder\":1,\"sortable\":false,\"relationId\":\"1440947089268805632\",\"dataFieldName\":null},{\"columnId\":\"1440947089252028416\",\"tableId\":\"1440947089218473984\",\"showName\":\"金额\",\"showOrder\":2,\"sortable\":false,\"relationId\":\"1440947089268805632\",\"dataFieldName\":null},{\"columnId\":\"1440947089260417024\",\"tableId\":\"1440947089218473984\",\"showName\":\"报销凭证\",\"showOrder\":3,\"sortable\":false,\"relationId\":\"1440947089268805632\",\"dataFieldName\":null},{\"columnId\":\"1440947089264611328\",\"tableId\":\"1440947089218473984\",\"showName\":\"费用描述\",\"showOrder\":4,\"sortable\":false,\"relationId\":\"1440947089268805632\",\"dataFieldName\":null}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":true,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false,\"formId\":\"1440947791881834496\"},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\",\"formId\":\"1440947791881834496\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[{\"tableId\":\"1440947089218473984\",\"columnId\":\"1440947089231056896\",\"paramValueType\":0,\"paramValue\":\"id\"}],\"id\":1632383762135,\"relationId\":\"1440947089268805632\",\"tableId\":\"1440947089218473984\",\"columnName\":\"id_zz_test_flow_submit_detail_submit_idRelation\",\"showName\":\"报销详情\",\"variableName\":\"id_zz_test_flow_submit_detail_submit_idRelation\",\"dictParamList\":null,\"hasError\":false}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440946127468761088\",\"columnName\":\"id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 15:48:23\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"id\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440946127460372480\",\"updateTime\":\"2021-09-23 15:48:23\",\"userFilter\":false}]', '2021-09-23 15:58:07', '2021-09-23 15:54:32'); +INSERT INTO `zz_online_form` VALUES (1440947791881834496, 1440946020174270464, 'formEditFlowSubmitDetail', '编辑报销详情', 1, 5, 1440947089218473984, '{\"formConfig\":{\"formKind\":1,\"formType\":5,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":10,\"span\":24,\"placeholder\":\"\",\"id\":1632383900080,\"datasourceId\":\"1440946127531675648\",\"relationId\":\"1440947089268805632\",\"tableId\":\"1440947089218473984\",\"columnId\":\"1440947089235251200\",\"columnName\":\"expense_type\",\"showName\":\"费用类型\",\"variableName\":\"expenseType\",\"dictParamList\":[],\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":20,\"span\":24,\"placeholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"valueFormat\":\"yyyy-MM-dd\",\"readOnly\":false,\"disabled\":false,\"id\":1632383900902,\"datasourceId\":\"1440946127531675648\",\"relationId\":\"1440947089268805632\",\"tableId\":\"1440947089218473984\",\"columnId\":\"1440947089243639808\",\"columnName\":\"expense_time\",\"showName\":\"发生日期\",\"variableName\":\"expenseTime\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":3,\"span\":24,\"defaultValue\":0,\"min\":0,\"step\":1,\"precision\":2,\"controlVisible\":1,\"controlPosition\":0,\"readOnly\":false,\"disabled\":false,\"id\":1632383906027,\"datasourceId\":\"1440946127531675648\",\"relationId\":\"1440947089268805632\",\"tableId\":\"1440947089218473984\",\"columnId\":\"1440947089252028416\",\"columnName\":\"amount\",\"showName\":\"金额\",\"variableName\":\"amount\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":4,\"readOnly\":false,\"disabled\":false,\"id\":1632383907850,\"datasourceId\":\"1440946127531675648\",\"relationId\":\"1440947089268805632\",\"tableId\":\"1440947089218473984\",\"columnId\":\"1440947089264611328\",\"columnName\":\"description\",\"showName\":\"费用描述\",\"variableName\":\"description\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":31,\"span\":24,\"isImage\":true,\"fileFieldName\":\"uploadFile\",\"actionUrl\":\"/admin/flow/flowOnlineOperation/upload\",\"downloadUrl\":\"/admin/flow/flowOnlineOperation/download\",\"id\":1632383908452,\"datasourceId\":\"1440946127531675648\",\"relationId\":\"1440947089268805632\",\"tableId\":\"1440947089218473984\",\"columnId\":\"1440947089260417024\",\"columnName\":\"image_url\",\"showName\":\"报销凭证\",\"variableName\":\"imageUrl\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440947089222668288\",\"columnName\":\"id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 15:52:12\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"id\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440947089218473984\",\"updateTime\":\"2021-09-23 15:52:12\",\"userFilter\":false}]', '2021-09-23 15:59:08', '2021-09-23 15:55:00'); +INSERT INTO `zz_online_form` VALUES (1440954920348946432, 1440952710487609344, 'formFlowContract', '合同审批', 5, 10, 1440952815294877696, '{\"formConfig\":{\"formKind\":5,\"formType\":10,\"gutter\":20,\"labelWidth\":120,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"contract_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632385543720,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815307460608\",\"columnName\":\"first_party_id\",\"showName\":\"甲方企业\",\"variableName\":\"firstPartyId\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632385544316,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815311654912\",\"columnName\":\"second_party_id\",\"showName\":\"乙方企业\",\"variableName\":\"secondPartyId\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632385545012,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815315849216\",\"columnName\":\"contract_type\",\"showName\":\"合同类型\",\"variableName\":\"contractType\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632385545729,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815324237824\",\"columnName\":\"sales_id\",\"showName\":\"业务员\",\"variableName\":\"salesId\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":20,\"span\":12,\"placeholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"valueFormat\":\"yyyy-MM-dd\",\"readOnly\":false,\"disabled\":false,\"id\":1632385550074,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815320043520\",\"columnName\":\"due_date\",\"showName\":\"到期日期\",\"variableName\":\"dueDate\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":3,\"span\":12,\"defaultValue\":0,\"min\":0,\"step\":1,\"precision\":2,\"controlVisible\":1,\"controlPosition\":0,\"readOnly\":false,\"disabled\":false,\"id\":1632385552142,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815332626432\",\"columnName\":\"commission_rate\",\"showName\":\"提成比例\",\"variableName\":\"commissionRate\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":31,\"span\":12,\"isImage\":false,\"fileFieldName\":\"uploadFile\",\"actionUrl\":\"/admin/flow/flowOnlineOperation/upload\",\"downloadUrl\":\"/admin/flow/flowOnlineOperation/download\",\"id\":1632385586521,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815336820736\",\"columnName\":\"attachment\",\"showName\":\"合同附件\",\"variableName\":\"attachment\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":31,\"span\":12,\"isImage\":false,\"fileFieldName\":\"uploadFile\",\"actionUrl\":\"/admin/flow/flowOnlineOperation/upload\",\"downloadUrl\":\"/admin/flow/flowOnlineOperation/download\",\"id\":1632385587136,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815341015040\",\"columnName\":\"security_attachment\",\"showName\":\"保密协议\",\"variableName\":\"securityAttachment\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":31,\"span\":12,\"isImage\":false,\"fileFieldName\":\"uploadFile\",\"actionUrl\":\"/admin/flow/flowOnlineOperation/upload\",\"downloadUrl\":\"/admin/flow/flowOnlineOperation/download\",\"id\":1632385587746,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815345209344\",\"columnName\":\"intellectual_property_attachment\",\"showName\":\"知识产权协议\",\"variableName\":\"intellectualPropertyAttachment\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":31,\"span\":12,\"isImage\":false,\"fileFieldName\":\"uploadFile\",\"actionUrl\":\"/admin/flow/flowOnlineOperation/upload\",\"downloadUrl\":\"/admin/flow/flowOnlineOperation/download\",\"id\":1632385589128,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815349403648\",\"columnName\":\"other_attachment\",\"showName\":\"其他附件\",\"variableName\":\"otherAttachment\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":1,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440953088922882048\",\"tableId\":\"1440953088901910528\",\"showName\":\"合同产品\",\"showOrder\":1,\"sortable\":false,\"relationId\":\"1440953088977408000\",\"dataFieldName\":null},{\"columnId\":\"1440953088927076352\",\"tableId\":\"1440953088901910528\",\"showName\":\"产品数量\",\"showOrder\":2,\"sortable\":false,\"relationId\":\"1440953088977408000\",\"dataFieldName\":null},{\"columnId\":\"1440953088935464960\",\"tableId\":\"1440953088901910528\",\"showName\":\"产品总价\",\"showOrder\":3,\"sortable\":false,\"relationId\":\"1440953088977408000\",\"dataFieldName\":null},{\"columnId\":\"1440953088939659264\",\"tableId\":\"1440953088901910528\",\"showName\":\"备注\",\"showOrder\":4,\"sortable\":false,\"relationId\":\"1440953088977408000\",\"dataFieldName\":null}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":true,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false,\"formId\":\"1440955295755931648\"},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\",\"formId\":\"1440955295755931648\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[{\"tableId\":\"1440953088901910528\",\"columnId\":\"1440953088918687744\",\"paramValueType\":1,\"paramValue\":\"1440952815303266304\"}],\"id\":1632385613866,\"relationId\":\"1440953088977408000\",\"tableId\":\"1440953088901910528\",\"columnName\":\"contract_id_zz_test_flow_contract_detail_contract_idRelation\",\"showName\":\"合同详情\",\"variableName\":\"contract_id_zz_test_flow_contract_detail_contract_idRelation\",\"dictParamList\":null,\"hasError\":false},{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":1,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440953245684994048\",\"tableId\":\"1440953245664022528\",\"showName\":\"交付日期\",\"showOrder\":1,\"sortable\":false,\"relationId\":\"1440953245747908608\",\"dataFieldName\":null},{\"columnId\":\"1440953245697576960\",\"tableId\":\"1440953245664022528\",\"showName\":\"交付产品\",\"showOrder\":2,\"sortable\":false,\"relationId\":\"1440953245747908608\",\"dataFieldName\":null},{\"columnId\":\"1440953245705965568\",\"tableId\":\"1440953245664022528\",\"showName\":\"交付数量\",\"showOrder\":3,\"sortable\":false,\"relationId\":\"1440953245747908608\",\"dataFieldName\":null},{\"columnId\":\"1440953245718548480\",\"tableId\":\"1440953245664022528\",\"showName\":\"备注\",\"showOrder\":4,\"sortable\":false,\"relationId\":\"1440953245747908608\",\"dataFieldName\":null}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":true,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false,\"formId\":\"1440955424638504960\"},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\",\"formId\":\"1440955424638504960\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[{\"tableId\":\"1440953245664022528\",\"columnId\":\"1440953245676605440\",\"paramValueType\":1,\"paramValue\":\"1440952815303266304\"}],\"id\":1632385617093,\"relationId\":\"1440953245747908608\",\"tableId\":\"1440953245664022528\",\"columnName\":\"contract_id_zz_test_flow_delivery_detail_contract_idRelation\",\"showName\":\"交付详情\",\"variableName\":\"contract_id_zz_test_flow_delivery_detail_contract_idRelation\",\"dictParamList\":null,\"hasError\":false},{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440953170535649280\",\"tableId\":\"1440953170514677760\",\"showName\":\"付款日期\",\"showOrder\":1,\"sortable\":false,\"relationId\":\"1440953170590175232\",\"dataFieldName\":null},{\"columnId\":\"1440953170539843584\",\"tableId\":\"1440953170514677760\",\"showName\":\"付款类型\",\"showOrder\":2,\"sortable\":false,\"relationId\":\"1440953170590175232\",\"dataFieldName\":null},{\"columnId\":\"1440953170548232192\",\"tableId\":\"1440953170514677760\",\"showName\":\"付款比例(%)\",\"showOrder\":3,\"sortable\":false,\"relationId\":\"1440953170590175232\",\"dataFieldName\":null},{\"columnId\":\"1440953170552426496\",\"tableId\":\"1440953170514677760\",\"showName\":\"备注\",\"showOrder\":4,\"sortable\":false,\"relationId\":\"1440953170590175232\",\"dataFieldName\":null}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":true,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false,\"formId\":\"1440955361006718976\"},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\",\"formId\":\"1440955361006718976\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[{\"tableId\":\"1440953170514677760\",\"columnId\":\"1440953170531454976\",\"paramValueType\":1,\"paramValue\":\"1440952815303266304\"}],\"id\":1632385617965,\"relationId\":\"1440953170590175232\",\"tableId\":\"1440953170514677760\",\"columnName\":\"contract_id_zz_test_flow_pay_detail_contract_idRelation\",\"showName\":\"付款详情\",\"variableName\":\"contract_id_zz_test_flow_pay_detail_contract_idRelation\",\"dictParamList\":null,\"hasError\":false}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440952815303266304\",\"columnName\":\"contract_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:14:57\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"contractId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440952815294877696\",\"updateTime\":\"2021-09-23 16:14:57\",\"userFilter\":false}]', '2021-09-24 09:36:35', '2021-09-23 16:23:19'); +INSERT INTO `zz_online_form` VALUES (1440955001093492736, 1440952710487609344, 'formFlowContractLaw', '法务信息', 5, 10, 1440952815294877696, '{\"formConfig\":{\"formKind\":5,\"formType\":10,\"gutter\":20,\"labelWidth\":120,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"contract_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":2,\"widgetType\":40,\"span\":24,\"position\":\"center\",\"id\":1632385804854,\"columnName\":\"divider\",\"showName\":\"甲方信息\",\"variableName\":\"divider\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632385840611,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440952921117167616\",\"tableId\":\"1440952921024892928\",\"columnId\":\"1440952921041670144\",\"columnName\":\"company_name\",\"showName\":\"公司名称\",\"variableName\":\"companyName\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632385850871,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440952921117167616\",\"tableId\":\"1440952921024892928\",\"columnId\":\"1440952921066835968\",\"columnName\":\"contact_info\",\"showName\":\"联系方式\",\"variableName\":\"contactInfo\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632385854474,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440952921117167616\",\"tableId\":\"1440952921024892928\",\"columnId\":\"1440952921058447360\",\"columnName\":\"registry_address\",\"showName\":\"注册地址\",\"variableName\":\"registryAddress\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632385855796,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440952921117167616\",\"tableId\":\"1440952921024892928\",\"columnId\":\"1440952921079418880\",\"columnName\":\"business_scope\",\"showName\":\"经营范围\",\"variableName\":\"businessScope\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":2,\"widgetType\":40,\"span\":24,\"position\":\"center\",\"id\":1632385870258,\"columnName\":\"divider\",\"showName\":\"乙方信息\",\"variableName\":\"divider1\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632385881057,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440952988536410112\",\"tableId\":\"1440952988389609472\",\"columnId\":\"1440952988406386688\",\"columnName\":\"company_name\",\"showName\":\"公司名称\",\"variableName\":\"companyName1\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632385882845,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440952988536410112\",\"tableId\":\"1440952988389609472\",\"columnId\":\"1440952988486078464\",\"columnName\":\"contact_info\",\"showName\":\"联系方式\",\"variableName\":\"contactInfo1\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632385886068,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440952988536410112\",\"tableId\":\"1440952988389609472\",\"columnId\":\"1440952988473495552\",\"columnName\":\"registry_address\",\"showName\":\"注册地址\",\"variableName\":\"registryAddress1\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632385886979,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440952988536410112\",\"tableId\":\"1440952988389609472\",\"columnId\":\"1440952988494467072\",\"columnName\":\"business_scope\",\"showName\":\"经营范围\",\"variableName\":\"businessScope1\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":2,\"widgetType\":40,\"span\":24,\"position\":\"center\",\"id\":1632385900924,\"columnName\":\"divider\",\"showName\":\"合同信息\",\"variableName\":\"divider2\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632385921859,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815315849216\",\"columnName\":\"contract_type\",\"showName\":\"合同类型\",\"variableName\":\"contractType\",\"readOnly\":true,\"dictParamList\":[],\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":20,\"span\":12,\"placeholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"valueFormat\":\"yyyy-MM-dd\",\"readOnly\":true,\"disabled\":false,\"id\":1632385943091,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815320043520\",\"columnName\":\"due_date\",\"showName\":\"到期日期\",\"variableName\":\"dueDate\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":31,\"span\":12,\"isImage\":false,\"fileFieldName\":\"uploadFile\",\"actionUrl\":\"/admin/flow/flowOnlineOperation/upload\",\"downloadUrl\":\"/admin/flow/flowOnlineOperation/download\",\"id\":1632385951296,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815336820736\",\"columnName\":\"attachment\",\"showName\":\"合同附件\",\"variableName\":\"attachment\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":31,\"span\":12,\"isImage\":false,\"fileFieldName\":\"uploadFile\",\"actionUrl\":\"/admin/flow/flowOnlineOperation/upload\",\"downloadUrl\":\"/admin/flow/flowOnlineOperation/download\",\"id\":1632385954049,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815341015040\",\"columnName\":\"security_attachment\",\"showName\":\"保密协议\",\"variableName\":\"securityAttachment\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":31,\"span\":12,\"isImage\":false,\"fileFieldName\":\"uploadFile\",\"actionUrl\":\"/admin/flow/flowOnlineOperation/upload\",\"downloadUrl\":\"/admin/flow/flowOnlineOperation/download\",\"id\":1632385954722,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815345209344\",\"columnName\":\"intellectual_property_attachment\",\"showName\":\"知识产权协议\",\"variableName\":\"intellectualPropertyAttachment\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":31,\"span\":12,\"isImage\":false,\"fileFieldName\":\"uploadFile\",\"actionUrl\":\"/admin/flow/flowOnlineOperation/upload\",\"downloadUrl\":\"/admin/flow/flowOnlineOperation/download\",\"id\":1632385955926,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815349403648\",\"columnName\":\"other_attachment\",\"showName\":\"其他附件\",\"variableName\":\"otherAttachment\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440952815303266304\",\"columnName\":\"contract_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:14:57\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"contractId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440952815294877696\",\"updateTime\":\"2021-09-23 16:14:57\",\"userFilter\":false}]', '2021-09-23 16:32:45', '2021-09-23 16:23:39'); +INSERT INTO `zz_online_form` VALUES (1440955127790833664, 1440952710487609344, 'formFlowContractPay', '付款详情', 5, 10, 1440952815294877696, '{\"formConfig\":{\"formKind\":5,\"formType\":10,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"contract_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632385985050,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815307460608\",\"columnName\":\"first_party_id\",\"showName\":\"甲方企业\",\"variableName\":\"firstPartyId\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632385985722,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815311654912\",\"columnName\":\"second_party_id\",\"showName\":\"乙方企业\",\"variableName\":\"secondPartyId\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632385986562,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815315849216\",\"columnName\":\"contract_type\",\"showName\":\"合同类型\",\"variableName\":\"contractType\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632385987354,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815324237824\",\"columnName\":\"sales_id\",\"showName\":\"业务员\",\"variableName\":\"salesId\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":20,\"span\":12,\"placeholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"valueFormat\":\"yyyy-MM-dd\",\"readOnly\":false,\"disabled\":false,\"id\":1632385998420,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815320043520\",\"columnName\":\"due_date\",\"showName\":\"到期日期\",\"variableName\":\"dueDate\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440953170535649280\",\"tableId\":\"1440953170514677760\",\"showName\":\"付款日期\",\"showOrder\":1,\"sortable\":false,\"relationId\":\"1440953170590175232\",\"dataFieldName\":null},{\"columnId\":\"1440953170539843584\",\"tableId\":\"1440953170514677760\",\"showName\":\"付款类型\",\"showOrder\":2,\"sortable\":false,\"relationId\":\"1440953170590175232\",\"dataFieldName\":null},{\"columnId\":\"1440953170548232192\",\"tableId\":\"1440953170514677760\",\"showName\":\"付款比例(%)\",\"showOrder\":3,\"sortable\":false,\"relationId\":\"1440953170590175232\",\"dataFieldName\":null},{\"columnId\":\"1440953170552426496\",\"tableId\":\"1440953170514677760\",\"showName\":\"备注\",\"showOrder\":4,\"sortable\":false,\"relationId\":\"1440953170590175232\",\"dataFieldName\":null}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":false,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":false,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":false,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[{\"tableId\":\"1440953170514677760\",\"columnId\":\"1440953170531454976\",\"paramValueType\":1,\"paramValue\":\"1440952815303266304\"}],\"id\":1632386005350,\"relationId\":\"1440953170590175232\",\"tableId\":\"1440953170514677760\",\"columnName\":\"contract_id_zz_test_flow_pay_detail_contract_idRelation\",\"showName\":\"付款详情\",\"variableName\":\"contract_id_zz_test_flow_pay_detail_contract_idRelation\",\"dictParamList\":null,\"hasError\":false}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440952815303266304\",\"columnName\":\"contract_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:14:57\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"contractId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440952815294877696\",\"updateTime\":\"2021-09-23 16:14:57\",\"userFilter\":false}]', '2021-09-23 16:45:43', '2021-09-23 16:24:09'); +INSERT INTO `zz_online_form` VALUES (1440955194991972352, 1440952710487609344, 'formFlowContractDetail', '合同详情', 5, 10, 1440952815294877696, '{\"formConfig\":{\"formKind\":5,\"formType\":10,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"contract_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632386076617,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815307460608\",\"columnName\":\"first_party_id\",\"showName\":\"甲方企业\",\"variableName\":\"firstPartyId\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632386077249,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815311654912\",\"columnName\":\"second_party_id\",\"showName\":\"乙方企业\",\"variableName\":\"secondPartyId\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632386077906,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815315849216\",\"columnName\":\"contract_type\",\"showName\":\"合同类型\",\"variableName\":\"contractType\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":12,\"placeholder\":\"\",\"id\":1632386078973,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815324237824\",\"columnName\":\"sales_id\",\"showName\":\"业务员\",\"variableName\":\"salesId\",\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":20,\"span\":12,\"placeholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"valueFormat\":\"yyyy-MM-dd\",\"readOnly\":false,\"disabled\":false,\"id\":1632386079478,\"datasourceId\":\"1440952815374569472\",\"tableId\":\"1440952815294877696\",\"columnId\":\"1440952815320043520\",\"columnName\":\"due_date\",\"showName\":\"到期日期\",\"variableName\":\"dueDate\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440953088922882048\",\"tableId\":\"1440953088901910528\",\"showName\":\"合同产品\",\"showOrder\":1,\"sortable\":false,\"relationId\":\"1440953088977408000\",\"dataFieldName\":null},{\"columnId\":\"1440953088927076352\",\"tableId\":\"1440953088901910528\",\"showName\":\"产品数量\",\"showOrder\":2,\"sortable\":false,\"relationId\":\"1440953088977408000\",\"dataFieldName\":null},{\"columnId\":\"1440953088935464960\",\"tableId\":\"1440953088901910528\",\"showName\":\"产品总价\",\"showOrder\":3,\"sortable\":false,\"relationId\":\"1440953088977408000\",\"dataFieldName\":null},{\"columnId\":\"1440953088939659264\",\"tableId\":\"1440953088901910528\",\"showName\":\"备注\",\"showOrder\":4,\"sortable\":false,\"relationId\":\"1440953088977408000\",\"dataFieldName\":null}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":false,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":false,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":false,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[{\"tableId\":\"1440953088901910528\",\"columnId\":\"1440953088918687744\",\"paramValueType\":1,\"paramValue\":\"1440952815303266304\"}],\"id\":1632386082967,\"relationId\":\"1440953088977408000\",\"tableId\":\"1440953088901910528\",\"columnName\":\"contract_id_zz_test_flow_contract_detail_contract_idRelation\",\"showName\":\"合同详情\",\"variableName\":\"contract_id_zz_test_flow_contract_detail_contract_idRelation\",\"dictParamList\":null,\"hasError\":false},{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440953245684994048\",\"tableId\":\"1440953245664022528\",\"showName\":\"交付日期\",\"showOrder\":1,\"sortable\":false,\"relationId\":\"1440953245747908608\",\"dataFieldName\":null},{\"columnId\":\"1440953245697576960\",\"tableId\":\"1440953245664022528\",\"showName\":\"交付产品\",\"showOrder\":2,\"sortable\":false,\"relationId\":\"1440953245747908608\",\"dataFieldName\":null},{\"columnId\":\"1440953245705965568\",\"tableId\":\"1440953245664022528\",\"showName\":\"交付数量\",\"showOrder\":3,\"sortable\":false,\"relationId\":\"1440953245747908608\",\"dataFieldName\":null},{\"columnId\":\"1440953245718548480\",\"tableId\":\"1440953245664022528\",\"showName\":\"备注\",\"showOrder\":4,\"sortable\":false,\"relationId\":\"1440953245747908608\",\"dataFieldName\":null}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":false,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":false,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":false,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[{\"tableId\":\"1440953245664022528\",\"columnId\":\"1440953245676605440\",\"paramValueType\":1,\"paramValue\":\"1440952815303266304\"}],\"id\":1632386085719,\"relationId\":\"1440953245747908608\",\"tableId\":\"1440953245664022528\",\"columnName\":\"contract_id_zz_test_flow_delivery_detail_contract_idRelation\",\"showName\":\"交付详情\",\"variableName\":\"contract_id_zz_test_flow_delivery_detail_contract_idRelation\",\"dictParamList\":null,\"hasError\":false}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440952815303266304\",\"columnName\":\"contract_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:14:57\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"contractId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440952815294877696\",\"updateTime\":\"2021-09-23 16:14:57\",\"userFilter\":false}]', '2021-09-23 16:46:06', '2021-09-23 16:24:25'); +INSERT INTO `zz_online_form` VALUES (1440955295755931648, 1440952710487609344, 'formEditProduct', '编辑商品信息', 1, 5, 1440953088901910528, '{\"formConfig\":{\"formKind\":1,\"formType\":5,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"contract_detail_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":10,\"span\":24,\"placeholder\":\"\",\"id\":1632386167477,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953088977408000\",\"tableId\":\"1440953088901910528\",\"columnId\":\"1440953088922882048\",\"columnName\":\"product_id\",\"showName\":\"合同产品\",\"variableName\":\"productId\",\"dictParamList\":[],\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":3,\"span\":24,\"defaultValue\":0,\"min\":0,\"step\":1,\"precision\":0,\"controlVisible\":1,\"controlPosition\":0,\"readOnly\":false,\"disabled\":false,\"id\":1632386168097,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953088977408000\",\"tableId\":\"1440953088901910528\",\"columnId\":\"1440953088927076352\",\"columnName\":\"total_count\",\"showName\":\"产品数量\",\"variableName\":\"totalCount\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":3,\"span\":24,\"defaultValue\":0,\"min\":0,\"step\":1,\"precision\":2,\"controlVisible\":1,\"controlPosition\":0,\"readOnly\":false,\"disabled\":false,\"id\":1632386168937,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953088977408000\",\"tableId\":\"1440953088901910528\",\"columnId\":\"1440953088935464960\",\"columnName\":\"total_amount\",\"showName\":\"产品总价\",\"variableName\":\"totalAmount\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":4,\"readOnly\":false,\"disabled\":false,\"id\":1632386170038,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953088977408000\",\"tableId\":\"1440953088901910528\",\"columnId\":\"1440953088939659264\",\"columnName\":\"meno\",\"showName\":\"备注\",\"variableName\":\"meno\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440953088910299136\",\"columnName\":\"contract_detail_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:16:03\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"contractDetailId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440953088901910528\",\"updateTime\":\"2021-09-23 16:16:03\",\"userFilter\":false}]', '2021-09-23 16:40:38', '2021-09-23 16:24:49'); +INSERT INTO `zz_online_form` VALUES (1440955361006718976, 1440952710487609344, 'formEditPay', '编辑付款信息', 1, 5, 1440953170514677760, '{\"formConfig\":{\"formKind\":1,\"formType\":5,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"pay_detail_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":10,\"span\":24,\"placeholder\":\"\",\"id\":1632386206508,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953170590175232\",\"tableId\":\"1440953170514677760\",\"columnId\":\"1440953170539843584\",\"columnName\":\"pay_type\",\"showName\":\"付款类型\",\"variableName\":\"payType\",\"dictParamList\":[],\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":20,\"span\":24,\"placeholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"valueFormat\":\"yyyy-MM-dd\",\"readOnly\":false,\"disabled\":false,\"id\":1632386207312,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953170590175232\",\"tableId\":\"1440953170514677760\",\"columnId\":\"1440953170535649280\",\"columnName\":\"pay_date\",\"showName\":\"付款日期\",\"variableName\":\"payDate\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":3,\"span\":24,\"defaultValue\":0,\"min\":0,\"max\":100,\"step\":1,\"precision\":2,\"controlVisible\":1,\"controlPosition\":0,\"readOnly\":false,\"disabled\":false,\"id\":1632386208455,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953170590175232\",\"tableId\":\"1440953170514677760\",\"columnId\":\"1440953170548232192\",\"columnName\":\"percentage\",\"showName\":\"百分比\",\"variableName\":\"percentage\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386209209,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953170590175232\",\"tableId\":\"1440953170514677760\",\"columnId\":\"1440953170552426496\",\"columnName\":\"memo\",\"showName\":\"备注\",\"variableName\":\"memo\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440953170518872064\",\"columnName\":\"pay_detail_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:16:22\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"payDetailId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440953170514677760\",\"updateTime\":\"2021-09-23 16:16:22\",\"userFilter\":false}]', '2021-09-23 16:40:43', '2021-09-23 16:25:04'); +INSERT INTO `zz_online_form` VALUES (1440955424638504960, 1440952710487609344, 'formEditDelivery', '编辑交付信息', 1, 5, 1440953245664022528, '{\"formConfig\":{\"formKind\":1,\"formType\":5,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"delivery_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":20,\"span\":24,\"placeholder\":\"\",\"type\":\"date\",\"format\":\"yyyy-MM-dd\",\"valueFormat\":\"yyyy-MM-dd\",\"readOnly\":false,\"disabled\":false,\"id\":1632386237515,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953245747908608\",\"tableId\":\"1440953245664022528\",\"columnId\":\"1440953245684994048\",\"columnName\":\"delivery_date\",\"showName\":\"交付日期\",\"variableName\":\"deliveryDate\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":10,\"span\":24,\"placeholder\":\"\",\"id\":1632386238087,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953245747908608\",\"tableId\":\"1440953245664022528\",\"columnId\":\"1440953245697576960\",\"columnName\":\"product_id\",\"showName\":\"交付产品\",\"variableName\":\"productId\",\"dictParamList\":[],\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":3,\"span\":24,\"defaultValue\":0,\"min\":0,\"step\":1,\"precision\":0,\"controlVisible\":1,\"controlPosition\":0,\"readOnly\":false,\"disabled\":false,\"id\":1632386238799,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953245747908608\",\"tableId\":\"1440953245664022528\",\"columnId\":\"1440953245705965568\",\"columnName\":\"total_count\",\"showName\":\"交付数量\",\"variableName\":\"totalCount\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":4,\"readOnly\":false,\"disabled\":false,\"id\":1632386239345,\"datasourceId\":\"1440952815374569472\",\"relationId\":\"1440953245747908608\",\"tableId\":\"1440953245664022528\",\"columnId\":\"1440953245718548480\",\"columnName\":\"memo\",\"showName\":\"备注\",\"variableName\":\"memo\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440953245668216832\",\"columnName\":\"delivery_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:16:40\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"deliveryId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440953245664022528\",\"updateTime\":\"2021-09-23 16:16:40\",\"userFilter\":false}]', '2021-09-23 16:40:49', '2021-09-23 16:25:20'); +INSERT INTO `zz_online_form` VALUES (1440955483438452736, 1440952710487609344, 'formOrderContract', '合同工单', 5, 11, 1440952815294877696, '{\"formConfig\":{\"formKind\":5,\"formType\":11,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"contract_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}],\"tableWidget\":{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440952815307460608\",\"tableId\":\"1440952815294877696\",\"showName\":\"甲方企业\",\"showOrder\":1,\"sortable\":false},{\"columnId\":\"1440952815311654912\",\"tableId\":\"1440952815294877696\",\"showName\":\"乙方企业\",\"showOrder\":2,\"sortable\":false},{\"columnId\":\"1440952815315849216\",\"tableId\":\"1440952815294877696\",\"showName\":\"合同类型\",\"showOrder\":3,\"sortable\":false},{\"columnId\":\"1440952815320043520\",\"tableId\":\"1440952815294877696\",\"showName\":\"到期日期\",\"showOrder\":4,\"sortable\":false},{\"columnId\":\"1440952815324237824\",\"tableId\":\"1440952815294877696\",\"showName\":\"业务员\",\"showOrder\":5,\"sortable\":false}],\"operationList\":[],\"queryParamList\":[],\"tableId\":\"1440952815294877696\",\"variableName\":\"formOrderContract\",\"showName\":\"合同工单\",\"hasError\":false,\"datasourceId\":\"1440952815374569472\"}},\"widgetList\":[]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440952815303266304\",\"columnName\":\"contract_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:14:57\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"contractId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440952815294877696\",\"updateTime\":\"2021-09-23 16:14:57\",\"userFilter\":false}]', '2021-09-23 16:38:33', '2021-09-23 16:25:34'); +INSERT INTO `zz_online_form` VALUES (1440959226632474624, 1440958861153406976, 'formFirstParty', '甲方企业管理', 5, 1, 1440958971128057856, '{\"formConfig\":{\"formKind\":5,\"formType\":1,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[],\"tableWidget\":{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440958971140640768\",\"tableId\":\"1440958971128057856\",\"showName\":\"公司名称\",\"showOrder\":1,\"sortable\":false},{\"columnId\":\"1440958971144835072\",\"tableId\":\"1440958971128057856\",\"showName\":\"公司法人\",\"showOrder\":2,\"sortable\":false},{\"columnId\":\"1440958971157417984\",\"tableId\":\"1440958971128057856\",\"showName\":\"联系方式\",\"showOrder\":3,\"sortable\":false},{\"columnId\":\"1440958971153223680\",\"tableId\":\"1440958971128057856\",\"showName\":\"注册地址\",\"showOrder\":4,\"sortable\":false}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":true,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false,\"formId\":\"1440959420396736512\"},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\",\"formId\":\"1440959420396736512\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[],\"tableId\":\"1440958971128057856\",\"variableName\":\"formFirstParty\",\"showName\":\"甲方企业管理\",\"datasourceId\":\"1440958971190972416\",\"hasError\":false}},\"widgetList\":[{\"widgetKind\":0,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386494962,\"datasourceId\":\"1440958971190972416\",\"tableId\":\"1440958971128057856\",\"columnId\":\"1440958971140640768\",\"columnName\":\"company_name\",\"showName\":\"公司名称\",\"variableName\":\"companyName\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]}]}', '[{\"autoIncrement\":false,\"columnComment\":\"公司名称\",\"columnId\":\"1440958971140640768\",\"columnName\":\"company_name\",\"columnShowOrder\":2,\"columnType\":\"varchar\",\"createTime\":\"2021-09-23 16:39:25\",\"deptFilter\":false,\"filterType\":3,\"fullColumnType\":\"varchar(255)\",\"nullable\":false,\"objectFieldName\":\"companyName\",\"objectFieldType\":\"String\",\"parentKey\":false,\"primaryKey\":false,\"tableId\":\"1440958971128057856\",\"updateTime\":\"2021-09-23 16:41:25\",\"userFilter\":false}]', '2021-09-23 16:42:32', '2021-09-23 16:40:26'); +INSERT INTO `zz_online_form` VALUES (1440959420396736512, 1440958861153406976, 'formViewFirstParty', '编辑甲方企业', 1, 5, 1440958971128057856, '{\"formConfig\":{\"formKind\":1,\"formType\":5,\"gutter\":20,\"labelWidth\":120,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"first_party_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386807099,\"datasourceId\":\"1440958971190972416\",\"tableId\":\"1440958971128057856\",\"columnId\":\"1440958971140640768\",\"columnName\":\"company_name\",\"showName\":\"公司名称\",\"variableName\":\"companyName\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386808030,\"datasourceId\":\"1440958971190972416\",\"tableId\":\"1440958971128057856\",\"columnId\":\"1440958971144835072\",\"columnName\":\"legal_person\",\"showName\":\"公司法人\",\"variableName\":\"legalPerson\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386809518,\"datasourceId\":\"1440958971190972416\",\"tableId\":\"1440958971128057856\",\"columnId\":\"1440958971149029376\",\"columnName\":\"legal_person_id\",\"showName\":\"法人身份证号\",\"variableName\":\"legalPersonId\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386811364,\"datasourceId\":\"1440958971190972416\",\"tableId\":\"1440958971128057856\",\"columnId\":\"1440958971157417984\",\"columnName\":\"contact_info\",\"showName\":\"联系方式\",\"variableName\":\"contactInfo\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386814864,\"datasourceId\":\"1440958971190972416\",\"tableId\":\"1440958971128057856\",\"columnId\":\"1440958971153223680\",\"columnName\":\"registry_address\",\"showName\":\"注册地址\",\"variableName\":\"registryAddress\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386817801,\"datasourceId\":\"1440958971190972416\",\"tableId\":\"1440958971128057856\",\"columnId\":\"1440958971161612288\",\"columnName\":\"business_scope\",\"showName\":\"经营范围\",\"variableName\":\"businessScope\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386819192,\"datasourceId\":\"1440958971190972416\",\"tableId\":\"1440958971128057856\",\"columnId\":\"1440958971165806592\",\"columnName\":\"memo\",\"showName\":\"备注\",\"variableName\":\"memo\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440958971132252160\",\"columnName\":\"first_party_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:39:25\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"firstPartyId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440958971128057856\",\"updateTime\":\"2021-09-23 16:39:25\",\"userFilter\":false}]', '2021-09-23 16:47:25', '2021-09-23 16:41:12'); +INSERT INTO `zz_online_form` VALUES (1440961456601305088, 1440961119001776128, 'formSecondParty', '乙方管理', 5, 1, 1440961208273342464, '{\"formConfig\":{\"formKind\":5,\"formType\":1,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[],\"tableWidget\":{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440961208294313984\",\"tableId\":\"1440961208273342464\",\"showName\":\"公司名称\",\"showOrder\":1,\"sortable\":false,\"dataFieldName\":\"company_name\"},{\"columnId\":\"1440961208298508288\",\"tableId\":\"1440961208273342464\",\"showName\":\"公司法人\",\"showOrder\":2,\"sortable\":false,\"dataFieldName\":\"legal_person\"},{\"columnId\":\"1440961208315285504\",\"tableId\":\"1440961208273342464\",\"showName\":\"联系方式\",\"showOrder\":3,\"sortable\":false,\"dataFieldName\":\"contact_info\"},{\"columnId\":\"1440961208306896896\",\"tableId\":\"1440961208273342464\",\"showName\":\"注册地址\",\"showOrder\":4,\"sortable\":false,\"dataFieldName\":\"registry_address\"}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":true,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false,\"formId\":\"1440961779596267520\"},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\",\"formId\":\"1440961779596267520\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[],\"tableId\":\"1440961208273342464\",\"variableName\":\"formSecondParty\",\"showName\":\"乙方管理\",\"datasourceId\":\"1440961208344645633\",\"hasError\":false}},\"widgetList\":[{\"widgetKind\":0,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632386975051,\"datasourceId\":\"1440961208344645633\",\"tableId\":\"1440961208273342464\",\"columnId\":\"1440961208294313984\",\"columnName\":\"company_name\",\"showName\":\"公司名称\",\"variableName\":\"companyName\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[],\"hasError\":false}]}', '[{\"autoIncrement\":false,\"columnComment\":\"公司名称\",\"columnId\":\"1440961208294313984\",\"columnName\":\"company_name\",\"columnShowOrder\":2,\"columnType\":\"varchar\",\"createTime\":\"2021-09-23 16:48:18\",\"deptFilter\":false,\"filterType\":3,\"fullColumnType\":\"varchar(255)\",\"nullable\":false,\"objectFieldName\":\"companyName\",\"objectFieldType\":\"String\",\"parentKey\":false,\"primaryKey\":false,\"tableId\":\"1440961208273342464\",\"updateTime\":\"2021-09-23 16:48:23\",\"userFilter\":false}]', '2021-09-23 16:50:51', '2021-09-23 16:49:18'); +INSERT INTO `zz_online_form` VALUES (1440961779596267520, 1440961119001776128, 'formViewSecondParty', '编辑乙方信息', 1, 5, 1440961208273342464, '{\"formConfig\":{\"formKind\":1,\"formType\":5,\"gutter\":20,\"labelWidth\":120,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[{\"columnName\":\"second_party_id\",\"primaryKey\":true,\"slaveClumn\":false,\"builtin\":true}]},\"widgetList\":[{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632387055657,\"datasourceId\":\"1440961208344645633\",\"tableId\":\"1440961208273342464\",\"columnId\":\"1440961208294313984\",\"columnName\":\"company_name\",\"showName\":\"公司名称\",\"variableName\":\"companyName\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632387056269,\"datasourceId\":\"1440961208344645633\",\"tableId\":\"1440961208273342464\",\"columnId\":\"1440961208298508288\",\"columnName\":\"legal_person\",\"showName\":\"公司法人\",\"variableName\":\"legalPerson\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632387056789,\"datasourceId\":\"1440961208344645633\",\"tableId\":\"1440961208273342464\",\"columnId\":\"1440961208302702592\",\"columnName\":\"legal_person_id\",\"showName\":\"法人身份证号\",\"variableName\":\"legalPersonId\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632387059360,\"datasourceId\":\"1440961208344645633\",\"tableId\":\"1440961208273342464\",\"columnId\":\"1440961208315285504\",\"columnName\":\"contact_info\",\"showName\":\"联系方式\",\"variableName\":\"contactInfo\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632387060899,\"datasourceId\":\"1440961208344645633\",\"tableId\":\"1440961208273342464\",\"columnId\":\"1440961208306896896\",\"columnName\":\"registry_address\",\"showName\":\"注册地址\",\"variableName\":\"registryAddress\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":4,\"readOnly\":false,\"disabled\":false,\"id\":1632387061874,\"datasourceId\":\"1440961208344645633\",\"tableId\":\"1440961208273342464\",\"columnId\":\"1440961208319479808\",\"columnName\":\"business_scope\",\"showName\":\"经营范围\",\"variableName\":\"businessScope\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":1,\"widgetType\":1,\"span\":24,\"type\":\"textarea\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":4,\"readOnly\":false,\"disabled\":false,\"id\":1632387062646,\"datasourceId\":\"1440961208344645633\",\"tableId\":\"1440961208273342464\",\"columnId\":\"1440961208323674112\",\"columnName\":\"memo\",\"showName\":\"备注\",\"variableName\":\"memo\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]}]}', '[{\"autoIncrement\":false,\"columnComment\":\"主键Id\",\"columnId\":\"1440961208285925376\",\"columnName\":\"second_party_id\",\"columnShowOrder\":1,\"columnType\":\"bigint\",\"createTime\":\"2021-09-23 16:48:18\",\"deptFilter\":false,\"filterType\":0,\"fullColumnType\":\"bigint(20)\",\"nullable\":false,\"objectFieldName\":\"secondPartyId\",\"objectFieldType\":\"Long\",\"parentKey\":false,\"primaryKey\":true,\"tableId\":\"1440961208273342464\",\"updateTime\":\"2021-09-23 16:48:18\",\"userFilter\":false}]', '2021-09-23 16:51:20', '2021-09-23 16:50:35'); +INSERT INTO `zz_online_form` VALUES (1440962496864194560, 1440962061336055808, 'formProduct', '产品管理', 5, 1, 1440962162712383488, '{\"formConfig\":{\"formKind\":5,\"formType\":1,\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"paramList\":[],\"tableWidget\":{\"widgetKind\":2,\"widgetType\":100,\"span\":24,\"supportBottom\":0,\"tableInfo\":{\"paged\":true,\"optionColumnWidth\":150},\"titleColor\":\"#409EFF\",\"tableColumnList\":[{\"columnId\":\"1440962162729160704\",\"tableId\":\"1440962162712383488\",\"showName\":\"产品名称\",\"showOrder\":1,\"sortable\":false},{\"columnId\":\"1440962162733355008\",\"tableId\":\"1440962162712383488\",\"showName\":\"规格\",\"showOrder\":2,\"sortable\":false},{\"columnId\":\"1440962162741743616\",\"tableId\":\"1440962162712383488\",\"showName\":\"产品价格\",\"showOrder\":3,\"sortable\":false},{\"columnId\":\"1440962162745937920\",\"tableId\":\"1440962162712383488\",\"showName\":\"备注\",\"showOrder\":4,\"sortable\":false}],\"operationList\":[{\"id\":1,\"type\":0,\"name\":\"新建\",\"enabled\":true,\"builtin\":true,\"rowOperation\":false,\"btnType\":\"primary\",\"plain\":false,\"formId\":\"1440962547132928000\"},{\"id\":2,\"type\":1,\"name\":\"编辑\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn success\",\"formId\":\"1440962547132928000\"},{\"id\":3,\"type\":2,\"name\":\"删除\",\"enabled\":true,\"builtin\":true,\"rowOperation\":true,\"btnClass\":\"table-btn delete\"}],\"queryParamList\":[],\"tableId\":\"1440962162712383488\",\"variableName\":\"formProduct\",\"showName\":\"产品管理\",\"datasourceId\":\"1440962162771103745\",\"hasError\":false}},\"widgetList\":[{\"widgetKind\":0,\"widgetType\":1,\"span\":12,\"type\":\"text\",\"placeholder\":\"\",\"defaultValue\":\"\",\"minRows\":2,\"maxRows\":2,\"readOnly\":false,\"disabled\":false,\"id\":1632387220352,\"datasourceId\":\"1440962162771103745\",\"tableId\":\"1440962162712383488\",\"columnId\":\"1440962162729160704\",\"columnName\":\"product_name\",\"showName\":\"产品名称\",\"variableName\":\"productName\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]},{\"widgetKind\":0,\"widgetType\":4,\"readOnly\":false,\"disabled\":false,\"id\":1632387221253,\"datasourceId\":\"1440962162771103745\",\"tableId\":\"1440962162712383488\",\"columnId\":\"1440962162741743616\",\"columnName\":\"cost_price\",\"showName\":\"产品价格\",\"variableName\":\"costPrice\",\"dictParamList\":null,\"queryParamList\":[],\"tableColumnList\":[]}]}', '[{\"autoIncrement\":false,\"columnComment\":\"产品名称\",\"columnId\":\"1440962162729160704\",\"columnName\":\"product_name\",\"columnShowOrder\":2,\"columnType\":\"varchar\",\"createTime\":\"2021-09-23 16:52:06\",\"deptFilter\":false,\"filterType\":3,\"fullColumnType\":\"varchar(255)\",\"nullable\":false,\"objectFieldName\":\"productName\",\"objectFieldType\":\"String\",\"parentKey\":false,\"primaryKey\":false,\"tableId\":\"1440962162712383488\",\"updateTime\":\"2021-09-23 16:52:10\",\"userFilter\":false},{\"autoIncrement\":false,\"columnComment\":\"产品价格\",\"columnId\":\"1440962162741743616\",\"columnName\":\"cost_price\",\"columnShowOrder\":5,\"columnType\":\"int\",\"createTime\":\"2021-09-23 16:52:06\",\"deptFilter\":false,\"filterType\":2,\"fullColumnType\":\"int(11)\",\"nullable\":false,\"objectFieldName\":\"costPrice\",\"objectFieldType\":\"Integer\",\"parentKey\":false,\"primaryKey\":false,\"tableId\":\"1440962162712383488\",\"updateTime\":\"2021-09-23 16:53:05\",\"userFilter\":false}]', '2021-09-23 16:54:15', '2021-09-23 16:53:26'); +INSERT INTO `zz_online_form` VALUES (1440962547132928000, 1440962061336055808, 'formEditProduct', '编辑产品', 1, 5, 1440962162712383488, '{\"formConfig\":{\"gutter\":20,\"labelWidth\":100,\"labelPosition\":\"right\",\"width\":800,\"widgetList\":[],\"paramList\":[]},\"widgetList\":[]}', '[]', '2021-09-23 16:53:38', '2021-09-23 16:53:38'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_form_datasource +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_form_datasource`; +CREATE TABLE `zz_online_form_datasource` ( + `id` bigint(20) NOT NULL COMMENT '主键Id', + `form_id` bigint(20) NOT NULL COMMENT '表单Id', + `datasource_id` bigint(20) NOT NULL COMMENT '数据源Id', + PRIMARY KEY (`id`), + KEY `idx_form_id` (`form_id`) USING BTREE, + KEY `idx_datasource_id` (`datasource_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_form_datasource +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_form_datasource` VALUES (1440945738333818880, 1440945411354267648, 1440945228130291712); +INSERT INTO `zz_online_form_datasource` VALUES (1440948576577392640, 1440947675041107968, 1440946127531675648); +INSERT INTO `zz_online_form_datasource` VALUES (1440948832954224640, 1440947791881834496, 1440946127531675648); +INSERT INTO `zz_online_form_datasource` VALUES (1440957294211764224, 1440955001093492736, 1440952815374569472); +INSERT INTO `zz_online_form_datasource` VALUES (1440958752122474496, 1440955483438452736, 1440952815374569472); +INSERT INTO `zz_online_form_datasource` VALUES (1440959275592585216, 1440955295755931648, 1440952815374569472); +INSERT INTO `zz_online_form_datasource` VALUES (1440959299529478144, 1440955361006718976, 1440952815374569472); +INSERT INTO `zz_online_form_datasource` VALUES (1440959323269238784, 1440955424638504960, 1440952815374569472); +INSERT INTO `zz_online_form_datasource` VALUES (1440959757073518592, 1440959226632474624, 1440958971190972416); +INSERT INTO `zz_online_form_datasource` VALUES (1440960555518005248, 1440955127790833664, 1440952815374569472); +INSERT INTO `zz_online_form_datasource` VALUES (1440960654734266368, 1440955194991972352, 1440952815374569472); +INSERT INTO `zz_online_form_datasource` VALUES (1440960985459331072, 1440959420396736512, 1440958971190972416); +INSERT INTO `zz_online_form_datasource` VALUES (1440961848324132864, 1440961456601305088, 1440961208344645633); +INSERT INTO `zz_online_form_datasource` VALUES (1440961970739089408, 1440961779596267520, 1440961208344645633); +INSERT INTO `zz_online_form_datasource` VALUES (1440962547137122304, 1440962547132928000, 1440962162771103745); +INSERT INTO `zz_online_form_datasource` VALUES (1440962702619971584, 1440962496864194560, 1440962162771103745); +INSERT INTO `zz_online_form_datasource` VALUES (1440978457667309568, 1440945468593934336, 1440945228130291712); +INSERT INTO `zz_online_form_datasource` VALUES (1441214948859449344, 1440954920348946432, 1440952815374569472); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_page +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_page`; +CREATE TABLE `zz_online_page` ( + `page_id` bigint(20) NOT NULL COMMENT '主键Id', + `page_code` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '页面编码', + `page_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '页面名称', + `page_type` int(11) NOT NULL COMMENT '页面类型', + `status` int(11) NOT NULL COMMENT '页面编辑状态', + `published` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否发布', + `update_time` datetime NOT NULL COMMENT '更新时间', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`page_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_page +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_page` VALUES (1440945149889744896, 'pageFlowLeave', '请假申请', 10, 2, b'1', '2021-09-23 15:45:08', '2021-09-23 15:44:30'); +INSERT INTO `zz_online_page` VALUES (1440946020174270464, 'pageSubmit', '报销申请', 10, 2, b'1', '2021-09-23 15:57:43', '2021-09-23 15:47:57'); +INSERT INTO `zz_online_page` VALUES (1440952710487609344, 'pageFlowContract', '合同审批', 10, 2, b'1', '2021-09-23 16:23:02', '2021-09-23 16:14:32'); +INSERT INTO `zz_online_page` VALUES (1440958861153406976, 'formFirstParty', '甲方企业', 1, 2, b'1', '2021-09-23 16:40:03', '2021-09-23 16:38:59'); +INSERT INTO `zz_online_page` VALUES (1440961119001776128, 'pageSecondParty', '乙方企业管理', 1, 2, b'1', '2021-09-23 16:48:58', '2021-09-23 16:47:57'); +INSERT INTO `zz_online_page` VALUES (1440962061336055808, 'pageProduct', '产品管理', 1, 2, b'1', '2021-09-23 16:53:12', '2021-09-23 16:51:42'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_page_datasource +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_page_datasource`; +CREATE TABLE `zz_online_page_datasource` ( + `id` bigint(20) NOT NULL COMMENT '主键Id', + `page_id` bigint(20) NOT NULL COMMENT '页面主键Id', + `datasource_id` bigint(20) NOT NULL COMMENT '数据源主键Id', + PRIMARY KEY (`id`), + KEY `idx_page_id` (`page_id`) USING BTREE, + KEY `idx_datasource_id` (`datasource_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_page_datasource +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_page_datasource` VALUES (1440945228138680320, 1440945149889744896, 1440945228130291712); +INSERT INTO `zz_online_page_datasource` VALUES (1440946127540064256, 1440946020174270464, 1440946127531675648); +INSERT INTO `zz_online_page_datasource` VALUES (1440952815382958080, 1440952710487609344, 1440952815374569472); +INSERT INTO `zz_online_page_datasource` VALUES (1440958971195166721, 1440958861153406976, 1440958971190972416); +INSERT INTO `zz_online_page_datasource` VALUES (1440961208353034240, 1440961119001776128, 1440961208344645633); +INSERT INTO `zz_online_page_datasource` VALUES (1440962162779492352, 1440962061336055808, 1440962162771103745); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_rule +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_rule`; +CREATE TABLE `zz_online_rule` ( + `rule_id` bigint(20) NOT NULL COMMENT '主键Id', + `rule_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '规则名称', + `rule_type` int(11) NOT NULL COMMENT '规则类型', + `builtin` bit(1) NOT NULL COMMENT '内置规则标记', + `pattern` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '自定义规则的正则表达式', + `update_time` datetime NOT NULL COMMENT '更新时间', + `create_time` datetime NOT NULL COMMENT '创建时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记', + PRIMARY KEY (`rule_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_rule +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_rule` VALUES (1, '只允许整数', 1, b'1', NULL, '2021-09-23 00:00:00', '2021-09-23 00:00:00', 1); +INSERT INTO `zz_online_rule` VALUES (2, '只允许数字', 2, b'1', NULL, '2021-09-23 00:00:00', '2021-09-23 00:00:00', 1); +INSERT INTO `zz_online_rule` VALUES (3, '只允许英文字符', 3, b'1', NULL, '2021-09-23 00:00:00', '2021-09-23 00:00:00', 1); +INSERT INTO `zz_online_rule` VALUES (4, '范围验证', 4, b'1', NULL, '2021-09-23 00:00:00', '2021-09-23 00:00:00', 1); +INSERT INTO `zz_online_rule` VALUES (5, '邮箱格式验证', 5, b'1', NULL, '2021-09-23 00:00:00', '2021-09-23 00:00:00', 1); +INSERT INTO `zz_online_rule` VALUES (6, '手机格式验证', 6, b'1', NULL, '2021-09-23 00:00:00', '2021-09-23 00:00:00', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_table +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_table`; +CREATE TABLE `zz_online_table` ( + `table_id` bigint(20) NOT NULL COMMENT '主键Id', + `table_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '表名称', + `model_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '实体名称', + `dblink_id` bigint(20) NOT NULL COMMENT '数据库链接Id', + `update_time` datetime NOT NULL COMMENT '更新时间', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`table_id`), + KEY `idx_dblink_id` (`dblink_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_table +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_table` VALUES (1440945228079960064, 'zz_test_flow_leave', 'ZzTestFlowLeave', 1, '2021-09-23 15:44:48', '2021-09-23 15:44:48'); +INSERT INTO `zz_online_table` VALUES (1440946127460372480, 'zz_test_flow_submit', 'ZzTestFlowSubmit', 1, '2021-09-23 15:48:23', '2021-09-23 15:48:23'); +INSERT INTO `zz_online_table` VALUES (1440947089218473984, 'zz_test_flow_submit_detail', 'ZzTestFlowSubmitDetail', 1, '2021-09-23 15:52:12', '2021-09-23 15:52:12'); +INSERT INTO `zz_online_table` VALUES (1440952815294877696, 'zz_test_flow_contract', 'ZzTestFlowContract', 1, '2021-09-23 16:14:57', '2021-09-23 16:14:57'); +INSERT INTO `zz_online_table` VALUES (1440952921024892928, 'zz_test_flow_first_party', 'ZzTestFlowFirstParty', 1, '2021-09-23 16:15:23', '2021-09-23 16:15:23'); +INSERT INTO `zz_online_table` VALUES (1440952988389609472, 'zz_test_flow_second_party', 'ZzTestFlowSecondParty', 1, '2021-09-23 16:15:39', '2021-09-23 16:15:39'); +INSERT INTO `zz_online_table` VALUES (1440953088901910528, 'zz_test_flow_contract_detail', 'ZzTestFlowContractDetail', 1, '2021-09-23 16:16:03', '2021-09-23 16:16:03'); +INSERT INTO `zz_online_table` VALUES (1440953170514677760, 'zz_test_flow_pay_detail', 'ZzTestFlowPayDetail', 1, '2021-09-23 16:16:22', '2021-09-23 16:16:22'); +INSERT INTO `zz_online_table` VALUES (1440953245664022528, 'zz_test_flow_delivery_detail', 'ZzTestFlowDeliveryDetail', 1, '2021-09-23 16:16:40', '2021-09-23 16:16:40'); +INSERT INTO `zz_online_table` VALUES (1440958971128057856, 'zz_test_flow_first_party', 'ZzTestFlowFirstParty', 1, '2021-09-23 16:39:25', '2021-09-23 16:39:25'); +INSERT INTO `zz_online_table` VALUES (1440961208273342464, 'zz_test_flow_second_party', 'ZzTestFlowSecondParty', 1, '2021-09-23 16:48:18', '2021-09-23 16:48:18'); +INSERT INTO `zz_online_table` VALUES (1440962162712383488, 'zz_test_flow_product', 'ZzTestFlowProduct', 1, '2021-09-23 16:52:06', '2021-09-23 16:52:06'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_online_virtual_column +-- ---------------------------- +DROP TABLE IF EXISTS `zz_online_virtual_column`; +CREATE TABLE `zz_online_virtual_column` ( + `virtual_column_id` bigint(20) NOT NULL COMMENT '主键Id', + `table_id` bigint(20) NOT NULL COMMENT '所在表Id', + `object_field_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '字段名称', + `object_field_type` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '属性类型', + `column_prompt` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '字段提示名', + `virtual_type` int(11) NOT NULL COMMENT '虚拟字段类型(0: 聚合)', + `datasource_id` bigint(20) NOT NULL COMMENT '关联数据源Id', + `relation_id` bigint(20) DEFAULT NULL COMMENT '关联Id', + `aggregation_table_id` bigint(20) DEFAULT NULL COMMENT '聚合字段所在关联表Id', + `aggregation_column_id` bigint(20) DEFAULT NULL COMMENT '关联表聚合字段Id', + `aggregation_type` int(11) DEFAULT NULL COMMENT '聚合类型(0: sum 1: count 2: avg 3: min 4: max)', + `where_clause_json` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '存储过滤条件的json', + PRIMARY KEY (`virtual_column_id`) USING BTREE, + KEY `idx_database_id` (`datasource_id`) USING BTREE, + KEY `idx_relation_id` (`relation_id`) USING BTREE, + KEY `idx_table_id` (`table_id`) USING BTREE, + KEY `idx_aggregation_column_id` (`aggregation_column_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_online_virtual_column +-- ---------------------------- +BEGIN; +INSERT INTO `zz_online_virtual_column` VALUES (1440947297541165056, 1440946127460372480, 'totalAmount', 'Long', '报销总金额', 0, 1440946127531675648, 1440947089268805632, 1440947089218473984, 1440947089252028416, 0, '[]'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_data_perm +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_data_perm`; +CREATE TABLE `zz_sys_data_perm` ( + `data_perm_id` bigint(20) NOT NULL COMMENT '主键', + `data_perm_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '显示名称', + `rule_type` tinyint(2) NOT NULL COMMENT '数据权限规则类型(0: 全部可见 1: 只看自己 2: 只看本部门 3: 本部门及子部门 4: 多部门及子部门 5: 自定义部门列表)。', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`data_perm_id`) USING BTREE, + KEY `idx_create_time` (`create_time`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据权限表'; + +-- ---------------------------- +-- Records of zz_sys_data_perm +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_data_perm` VALUES (1440965237959299072, '查看全部', 0, 1440911410581213417, '2021-09-23 17:04:19', 1440911410581213417, '2021-09-23 17:04:19', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_data_perm_dept +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_data_perm_dept`; +CREATE TABLE `zz_sys_data_perm_dept` ( + `data_perm_id` bigint(20) NOT NULL COMMENT '数据权限Id', + `dept_id` bigint(20) NOT NULL COMMENT '部门Id', + PRIMARY KEY (`data_perm_id`,`dept_id`), + KEY `idx_dept_id` (`dept_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据权限和部门关联表'; + +-- ---------------------------- +-- Table structure for zz_sys_data_perm_user +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_data_perm_user`; +CREATE TABLE `zz_sys_data_perm_user` ( + `data_perm_id` bigint(20) NOT NULL COMMENT '数据权限Id', + `user_id` bigint(20) NOT NULL COMMENT '用户Id', + PRIMARY KEY (`data_perm_id`,`user_id`), + KEY `idx_user_id` (`user_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='数据权限和用户关联表'; + +-- ---------------------------- +-- Records of zz_sys_data_perm_user +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_data_perm_user` VALUES (1440965237959299072, 1440965344985354240); +INSERT INTO `zz_sys_data_perm_user` VALUES (1440965237959299072, 1440965465605148672); +INSERT INTO `zz_sys_data_perm_user` VALUES (1440965237959299072, 1440965586715676672); +INSERT INTO `zz_sys_data_perm_user` VALUES (1440965237959299072, 1440965697961201664); +INSERT INTO `zz_sys_data_perm_user` VALUES (1440965237959299072, 1440965808049098752); +INSERT INTO `zz_sys_data_perm_user` VALUES (1440965237959299072, 1440966073686953984); +INSERT INTO `zz_sys_data_perm_user` VALUES (1440965237959299072, 1440966186522120192); +INSERT INTO `zz_sys_data_perm_user` VALUES (1440965237959299072, 1440966324770574336); +INSERT INTO `zz_sys_data_perm_user` VALUES (1440965237959299072, 1440969706411397120); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_dept +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_dept`; +CREATE TABLE `zz_sys_dept` ( + `dept_id` bigint(20) NOT NULL COMMENT '部门Id', + `parent_id` bigint(20) DEFAULT NULL COMMENT '父部门Id', + `dept_name` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '部门名称', + `show_order` int(11) NOT NULL COMMENT '兄弟部分之间的显示顺序,数字越小越靠前', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`dept_id`) USING BTREE, + KEY `idx_parent_id` (`parent_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='部门管理表'; + +-- ---------------------------- +-- Records of zz_sys_dept +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_dept` VALUES (1440911410581213416, NULL, '公司总部', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_dept` VALUES (1440963592970047488, 1440911410581213416, '人事部', 1, 1440911410581213417, '2021-09-23 16:57:47', 1440911410581213417, '2021-09-23 16:57:47', 1); +INSERT INTO `zz_sys_dept` VALUES (1440963642542526464, 1440911410581213416, '法务部', 2, 1440911410581213417, '2021-09-23 16:57:59', 1440911410581213417, '2021-09-23 16:57:59', 1); +INSERT INTO `zz_sys_dept` VALUES (1440963698460987392, NULL, '天津分公司', 2, 1440911410581213417, '2021-09-23 16:58:12', 1440911410581213417, '2021-09-23 16:58:12', 1); +INSERT INTO `zz_sys_dept` VALUES (1440963733084966912, NULL, '北京分公司', 2, 1440911410581213417, '2021-09-23 16:58:20', 1440911410581213417, '2021-09-23 16:58:20', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_dept_post +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_dept_post`; +CREATE TABLE `zz_sys_dept_post` ( + `dept_post_id` bigint(20) NOT NULL COMMENT '主键Id', + `dept_id` bigint(20) NOT NULL COMMENT '部门Id', + `post_id` bigint(20) NOT NULL COMMENT '岗位Id', + `post_show_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '部门岗位显示名称', + PRIMARY KEY (`dept_post_id`) USING BTREE, + KEY `idx_post_id` (`post_id`) USING BTREE, + KEY `idx_dept_id` (`dept_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_sys_dept_post +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_dept_post` VALUES (1440964221780103168, 1440963592970047488, 1440964097913917440, '人事部经理'); +INSERT INTO `zz_sys_dept_post` VALUES (1440964221855600640, 1440963592970047488, 1440964157770829824, '人事专员'); +INSERT INTO `zz_sys_dept_post` VALUES (1440964387979399168, 1440963642542526464, 1440964097913917440, '法务部经理'); +INSERT INTO `zz_sys_dept_post` VALUES (1440964387983593472, 1440963642542526464, 1440964157770829824, '法务专员'); +INSERT INTO `zz_sys_dept_post` VALUES (1440964519391137792, 1440963698460987392, 1440963890539139072, '天津大区总监'); +INSERT INTO `zz_sys_dept_post` VALUES (1440964519395332096, 1440963698460987392, 1440964040611336192, '天津地区经理'); +INSERT INTO `zz_sys_dept_post` VALUES (1440964519399526400, 1440963698460987392, 1440964157770829824, '员工'); +INSERT INTO `zz_sys_dept_post` VALUES (1440964725134331904, 1440963733084966912, 1440963890539139072, '北京大区总监'); +INSERT INTO `zz_sys_dept_post` VALUES (1440964725138526208, 1440963733084966912, 1440964040611336192, '北京地区经理'); +INSERT INTO `zz_sys_dept_post` VALUES (1440964725142720512, 1440963733084966912, 1440964157770829824, '员工'); +INSERT INTO `zz_sys_dept_post` VALUES (1440969551792574464, 1440911410581213416, 1440963890539139072, '总裁'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_dept_relation +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_dept_relation`; +CREATE TABLE `zz_sys_dept_relation` ( + `parent_dept_id` bigint(20) NOT NULL COMMENT '父部门Id', + `dept_id` bigint(20) NOT NULL COMMENT '部门Id', + PRIMARY KEY (`parent_dept_id`,`dept_id`), + KEY `idx_dept_id` (`dept_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='部门关联关系表'; + +-- ---------------------------- +-- Records of zz_sys_dept_relation +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_dept_relation` VALUES (1440911410581213416, 1440911410581213416); +INSERT INTO `zz_sys_dept_relation` VALUES (1440911410581213416, 1440963592970047488); +INSERT INTO `zz_sys_dept_relation` VALUES (1440963592970047488, 1440963592970047488); +INSERT INTO `zz_sys_dept_relation` VALUES (1440911410581213416, 1440963642542526464); +INSERT INTO `zz_sys_dept_relation` VALUES (1440963642542526464, 1440963642542526464); +INSERT INTO `zz_sys_dept_relation` VALUES (1440963698460987392, 1440963698460987392); +INSERT INTO `zz_sys_dept_relation` VALUES (1440963733084966912, 1440963733084966912); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_menu +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_menu`; +CREATE TABLE `zz_sys_menu` ( + `menu_id` bigint(20) NOT NULL COMMENT '主键Id', + `parent_id` bigint(20) DEFAULT NULL COMMENT '父菜单Id,目录菜单的父菜单为null', + `menu_name` varchar(50) COLLATE utf8mb4_bin NOT NULL COMMENT '菜单显示名称', + `menu_type` int(11) NOT NULL COMMENT '(0: 目录 1: 菜单 2: 按钮 3: UI片段)', + `form_router_name` varchar(64) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '前端表单路由名称,仅用于menu_type为1的菜单类型', + `online_form_id` bigint(20) DEFAULT NULL COMMENT '在线表单主键Id', + `online_menu_perm_type` int(11) DEFAULT NULL COMMENT '在线表单菜单的权限控制类型', + `online_flow_entry_id` bigint(20) DEFAULT NULL COMMENT '仅用于在线表单的流程Id', + `show_order` int(11) NOT NULL COMMENT '菜单显示顺序 (值越小,排序越靠前)', + `icon` varchar(50) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '菜单图标', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`menu_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE, + KEY `idx_parent_id` (`parent_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='菜单和操作权限管理表'; + +-- ---------------------------- +-- Records of zz_sys_menu +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_menu` VALUES (1392786476428693504, NULL, '在线表单', 0, NULL, NULL, NULL, NULL, 2, 'el-icon-c-scale-to-original', 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 17:42:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1392786549942259712, 1392786476428693504, '字典管理', 1, 'formOnlineDict', NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1392786950682841088, 1392786476428693504, '表单管理', 1, 'formOnlinePage', NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532054578925568, NULL, '系统管理', 0, NULL, NULL, NULL, NULL, 1, 'el-icon-setting', 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 17:41:39', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532055971434496, 1401532054578925568, '用户管理', 1, 'formSysUser', NULL, NULL, NULL, 100, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532055971434497, 1401532054578925568, '部门管理', 1, 'formSysDept', NULL, NULL, NULL, 105, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532055971434498, 1401532054578925568, '角色管理', 1, 'formSysRole', NULL, NULL, NULL, 110, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532055971434499, 1401532054578925568, '数据权限管理', 1, 'formSysDataPerm', NULL, NULL, NULL, 115, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532055971434500, 1401532054578925568, '菜单管理', 1, 'formSysMenu', NULL, NULL, NULL, 120, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532055971434501, 1401532054578925568, '权限字管理', 1, 'formSysPermCode', NULL, NULL, NULL, 125, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532055971434502, 1401532054578925568, '权限管理', 1, 'formSysPerm', NULL, NULL, NULL, 130, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532055971434503, 1401532054578925568, '字典管理', 1, 'formSysDict', NULL, NULL, NULL, 135, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1401532055971434504, 1401532054578925568, '在线用户', 1, 'formSysLoginUser', NULL, NULL, NULL, 145, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418057714138877952, NULL, '流程管理', 0, NULL, NULL, NULL, NULL, 3, 'el-icon-s-operation', 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 17:42:12', 1); +INSERT INTO `zz_sys_menu` VALUES (1418057835631087616, 1418057714138877952, '流程分类', 1, 'formFlowCategory', NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418058049951633408, 1418057835631087616, '新建', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418058115667988480, 1418057835631087616, '编辑', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418058170542067712, 1418057835631087616, '删除', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418058289182150656, 1418057714138877952, '流程设计', 1, 'formFlowEntry', NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418058515099947008, 1418058289182150656, '启动', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418058602723151872, 1418058289182150656, '编辑', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418058744037642240, 1418057714138877952, '流程实例', 1, 'formAllInstance', NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418058844164067328, 1418058744037642240, '终止', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418058907674218496, 1418058744037642240, '删除', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418059005175009280, NULL, '任务管理', 0, NULL, NULL, NULL, NULL, 4, 'el-icon-tickets', 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 17:42:32', 1); +INSERT INTO `zz_sys_menu` VALUES (1418059167532322816, 1418059005175009280, '待办任务', 1, 'formMyTask', NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1418059283920064512, 1418059005175009280, '历史任务', 1, 'formMyHistoryTask', NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1423161217970606080, 1418059005175009280, '已办任务', 1, 'formMyApprovedTask', NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1433040549035642880, 1401532054578925568, '岗位管理', 1, 'formSysPost', NULL, NULL, NULL, 106, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213280, 1401532055971434496, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213281, 1401532055971434496, '新增', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213282, 1401532055971434496, '编辑', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213283, 1401532055971434496, '删除', 3, NULL, NULL, NULL, NULL, 4, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213284, 1401532055971434496, '重置密码', 3, NULL, NULL, NULL, NULL, 5, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213285, 1401532055971434496, '权限详情', 3, NULL, NULL, NULL, NULL, 6, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213294, 1401532055971434497, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213295, 1401532055971434497, '新增', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213296, 1401532055971434497, '编辑', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213297, 1401532055971434497, '删除', 3, NULL, NULL, NULL, NULL, 4, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213298, 1401532055971434497, '设置岗位', 3, NULL, NULL, NULL, NULL, 5, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213299, 1401532055971434497, '查看岗位', 3, NULL, NULL, NULL, NULL, 6, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213308, 1401532055971434498, '角色管理', 2, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213309, 1401532055971434498, '用户授权', 2, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213310, 1440911410581213308, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213311, 1440911410581213308, '新增', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213312, 1440911410581213308, '编辑', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213313, 1440911410581213308, '删除', 3, NULL, NULL, NULL, NULL, 4, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213314, 1440911410581213308, '权限详情', 3, NULL, NULL, NULL, NULL, 5, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213315, 1440911410581213309, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213316, 1440911410581213309, '授权用户', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213317, 1440911410581213309, '移除用户', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213328, 1401532055971434499, '数据权限管理', 2, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213329, 1401532055971434499, '用户授权', 2, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213330, 1440911410581213328, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213331, 1440911410581213328, '新增', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213332, 1440911410581213328, '编辑', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213333, 1440911410581213328, '删除', 3, NULL, NULL, NULL, NULL, 4, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213334, 1440911410581213329, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213335, 1440911410581213329, '授权用户', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213336, 1440911410581213329, '移除用户', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213346, 1401532055971434500, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213347, 1401532055971434500, '新增', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213348, 1401532055971434500, '编辑', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213349, 1401532055971434500, '删除', 3, NULL, NULL, NULL, NULL, 4, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213350, 1401532055971434500, '权限详情', 3, NULL, NULL, NULL, NULL, 5, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213358, 1401532055971434501, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213359, 1401532055971434501, '新增', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213360, 1401532055971434501, '编辑', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213361, 1401532055971434501, '删除', 3, NULL, NULL, NULL, NULL, 4, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213362, 1401532055971434501, '权限详情', 3, NULL, NULL, NULL, NULL, 5, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213370, 1401532055971434502, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213371, 1401532055971434502, '新增模块', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213372, 1401532055971434502, '编辑模块', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213373, 1401532055971434502, '删除模块', 3, NULL, NULL, NULL, NULL, 4, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213374, 1401532055971434502, '新增权限', 3, NULL, NULL, NULL, NULL, 5, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213375, 1401532055971434502, '编辑权限', 3, NULL, NULL, NULL, NULL, 6, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213376, 1401532055971434502, '删除权限', 3, NULL, NULL, NULL, NULL, 7, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213377, 1401532055971434502, '权限详情', 3, NULL, NULL, NULL, NULL, 8, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213388, 1401532055971434503, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213389, 1401532055971434503, '新增', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213390, 1401532055971434503, '编辑', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213391, 1401532055971434503, '删除', 3, NULL, NULL, NULL, NULL, 4, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213392, 1401532055971434503, '同步缓存', 3, NULL, NULL, NULL, NULL, 5, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213400, 1401532055971434504, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213401, 1401532055971434504, '强制下线', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213406, 1433040549035642880, '岗位管理', 2, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213407, 1440911410581213406, '显示', 3, NULL, NULL, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213408, 1440911410581213406, '新增', 3, NULL, NULL, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213409, 1440911410581213406, '编辑', 3, NULL, NULL, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440911410581213410, 1440911410581213406, '删除', 3, NULL, NULL, NULL, NULL, 4, NULL, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440973980537196544, NULL, '业务管理', 0, NULL, NULL, NULL, NULL, 5, 'el-icon-goods', 1440911410581213417, '2021-09-23 17:39:04', 1440911410581213417, '2021-09-23 17:42:45', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974056105971712, 1440973980537196544, '甲方管理', 1, NULL, 1440959226632474624, NULL, NULL, 1, NULL, 1440911410581213417, '2021-09-23 17:39:22', 1440911410581213417, '2021-09-23 17:39:22', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974056110166016, 1440974056105971712, '查看', 3, NULL, 1440959226632474624, 0, NULL, 0, NULL, 1440911410581213417, '2021-09-23 17:39:22', 1440911410581213417, '2021-09-23 17:39:22', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974056114360320, 1440974056105971712, '编辑', 3, NULL, 1440959226632474624, 1, NULL, 1, NULL, 1440911410581213417, '2021-09-23 17:39:22', 1440911410581213417, '2021-09-23 17:39:22', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974134195523584, 1440973980537196544, '乙方管理', 1, NULL, 1440961456601305088, NULL, NULL, 2, NULL, 1440911410581213417, '2021-09-23 17:39:40', 1440911410581213417, '2021-09-23 17:39:40', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974134199717888, 1440974134195523584, '查看', 3, NULL, 1440961456601305088, 0, NULL, 0, NULL, 1440911410581213417, '2021-09-23 17:39:40', 1440911410581213417, '2021-09-23 17:39:40', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974134203912192, 1440974134195523584, '编辑', 3, NULL, 1440961456601305088, 1, NULL, 1, NULL, 1440911410581213417, '2021-09-23 17:39:40', 1440911410581213417, '2021-09-23 17:39:40', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974233613111296, 1440973980537196544, '产品管理', 1, NULL, 1440962496864194560, NULL, NULL, 3, NULL, 1440911410581213417, '2021-09-23 17:40:04', 1440911410581213417, '2021-09-23 17:40:04', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974233617305600, 1440974233613111296, '查看', 3, NULL, 1440962496864194560, 0, NULL, 0, NULL, 1440911410581213417, '2021-09-23 17:40:04', 1440911410581213417, '2021-09-23 17:40:04', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974233621499904, 1440974233613111296, '编辑', 3, NULL, 1440962496864194560, 1, NULL, 1, NULL, 1440911410581213417, '2021-09-23 17:40:04', 1440911410581213417, '2021-09-23 17:40:04', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974310754750464, NULL, '工单管理', 0, NULL, NULL, NULL, NULL, 6, 'el-icon-menu', 1440911410581213417, '2021-09-23 17:40:22', 1440911410581213417, '2021-09-23 17:43:00', 1); +INSERT INTO `zz_sys_menu` VALUES (1440974580402360320, 1440974310754750464, '请假申请', 1, NULL, 1440945468593934336, NULL, 1440962968085860352, 1, NULL, 1440911410581213417, '2021-09-23 17:41:27', 1440911410581213417, '2021-09-23 17:54:31', 1); +INSERT INTO `zz_sys_menu` VALUES (1440978065088843776, 1440974310754750464, '合同工单管理', 1, NULL, 1440955483438452736, NULL, 1440968423508021248, 2, NULL, 1440911410581213417, '2021-09-23 17:55:17', 1440911410581213417, '2021-09-23 17:55:17', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_menu_perm_code +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_menu_perm_code`; +CREATE TABLE `zz_sys_menu_perm_code` ( + `menu_id` bigint(20) NOT NULL COMMENT '关联菜单Id', + `perm_code_id` bigint(20) NOT NULL COMMENT '关联权限字Id', + PRIMARY KEY (`menu_id`,`perm_code_id`) USING BTREE, + KEY `idx_perm_code_id` (`perm_code_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='菜单和权限关系表'; + +-- ---------------------------- +-- Records of zz_sys_menu_perm_code +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_menu_perm_code` VALUES (1392786549942259712, 1400638885750378496); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1392786950682841088, 1400639252747784192); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418057835631087616, 1418046848794365952); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418058049951633408, 1418046986677915648); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418058115667988480, 1418047095188754432); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418058170542067712, 1418047182946177024); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418058289182150656, 1418048205177753600); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418058602723151872, 1418048335343783936); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418058744037642240, 1418049164754817024); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418058844164067328, 1418049287106859008); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418058907674218496, 1418049398776008704); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418059167532322816, 1418050322282057728); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418058515099947008, 1418050797706416128); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1418059283920064512, 1418057346877231104); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1423161217970606080, 1423636498195943424); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1423161217970606080, 1423637544578322432); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213280, 1440911410581213287); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213281, 1440911410581213288); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213282, 1440911410581213289); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213283, 1440911410581213290); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213284, 1440911410581213291); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213285, 1440911410581213292); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213294, 1440911410581213301); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213295, 1440911410581213302); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213296, 1440911410581213303); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213297, 1440911410581213304); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213298, 1440911410581213305); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213299, 1440911410581213306); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213310, 1440911410581213319); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213315, 1440911410581213320); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213311, 1440911410581213321); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213312, 1440911410581213322); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213313, 1440911410581213323); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213314, 1440911410581213324); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213316, 1440911410581213325); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213317, 1440911410581213326); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213330, 1440911410581213338); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213334, 1440911410581213339); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213331, 1440911410581213340); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213332, 1440911410581213341); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213333, 1440911410581213342); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213335, 1440911410581213343); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213336, 1440911410581213344); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213346, 1440911410581213352); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213347, 1440911410581213353); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213348, 1440911410581213354); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213349, 1440911410581213355); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213350, 1440911410581213356); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213358, 1440911410581213364); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213359, 1440911410581213365); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213360, 1440911410581213366); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213361, 1440911410581213367); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213362, 1440911410581213368); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213370, 1440911410581213379); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213371, 1440911410581213380); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213372, 1440911410581213381); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213373, 1440911410581213382); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213374, 1440911410581213383); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213375, 1440911410581213384); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213376, 1440911410581213385); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213377, 1440911410581213386); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1401532055971434503, 1440911410581213394); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213388, 1440911410581213394); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1401532055971434503, 1440911410581213395); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213389, 1440911410581213395); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1401532055971434503, 1440911410581213396); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213390, 1440911410581213396); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1401532055971434503, 1440911410581213397); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213391, 1440911410581213397); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1401532055971434503, 1440911410581213398); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213392, 1440911410581213398); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213400, 1440911410581213403); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213401, 1440911410581213404); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213407, 1440911410581213412); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213408, 1440911410581213413); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213409, 1440911410581213414); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440911410581213410, 1440911410581213415); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440974580402360320, 1440976898661289984); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440978065088843776, 1440976998183735296); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440974580402360320, 1440977405874278400); +INSERT INTO `zz_sys_menu_perm_code` VALUES (1440978065088843776, 1440977767599443968); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm`; +CREATE TABLE `zz_sys_perm` ( + `perm_id` bigint(20) NOT NULL COMMENT '权限id', + `module_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '权限所在的权限模块id', + `perm_name` varchar(64) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '权限名称', + `url` varchar(128) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '关联的url', + `show_order` int(11) NOT NULL DEFAULT '0' COMMENT '权限在当前模块下的顺序,由小到大', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`perm_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE, + KEY `idx_module_id` (`module_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统权限表'; + +-- ---------------------------- +-- Records of zz_sys_perm +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm` VALUES (1400626748101496832, 1400625224646397952, '显示列表', '/admin/online/onlineDblink/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400626963806162944, 1400625224646397952, '数据表列表', '/admin/online/onlineDblink/listDblinkTables', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400627109692444672, 1400625224646397952, '数据表字段列表', '/admin/online/onlineDblink/listDblinkTableColumns', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400632108514283520, 1400625585851469824, '显示列表', '/admin/online/onlineDict/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400632216169484288, 1400625585851469824, '详情', '/admin/online/onlineDict/view', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400632326538399744, 1400625585851469824, '新增', '/admin/online/onlineDict/add', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400632438635368448, 1400625585851469824, '编辑', '/admin/online/onlineDict/update', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400632511620452352, 1400625585851469824, '删除', '/admin/online/onlineDict/delete', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400632924021198848, 1400625800033603584, '显示列表', '/admin/online/onlineTable/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400632978937221120, 1400625800033603584, '详情', '/admin/online/onlineTable/view', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633026181861376, 1400625800033603584, '新增', '/admin/online/onlineTable/add', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633077717274624, 1400625800033603584, '编辑', '/admin/online/onlineTable/update', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633129688895488, 1400625800033603584, '删除', '/admin/online/onlineTable/delete', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633375525441536, 1400625906245963776, '显示列表', '/admin/online/onlineColumn/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633437093629952, 1400625906245963776, '详情', '/admin/online/onlineColumn/view', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633529678696448, 1400625906245963776, '新增', '/admin/online/onlineColumn/add', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633568027217920, 1400625906245963776, '编辑', '/admin/online/onlineColumn/update', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633612201627648, 1400625906245963776, '删除', '/admin/online/onlineColumn/delete', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633713376628736, 1400625906245963776, '刷新字段', '/admin/online/onlineColumn/refresh', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633798403559424, 1400625906245963776, '字段验证规则列表', '/admin/online/onlineColumn/listOnlineColumnRule', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400633922085195776, 1400625906245963776, '未使用字段验证规则列表', '/admin/online/onlineColumn/listNotInOnlineColumnRule', 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400634012745076736, 1400625906245963776, '添加字段验证规则', '/admin/online/onlineColumn/addOnlineColumnRule', 9, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400634100498305024, 1400625906245963776, '删除字段验证规则', '/admin/online/onlineColumn/deleteOnlineColumnRule', 10, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400634280308117504, 1400625906245963776, '编辑字段验证规则', '/admin/online/onlineColumn/updateOnlineColumnRule', 11, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400634354593435648, 1400625906245963776, '字段验证规则详情', '/admin/online/onlineColumn/viewOnlineColumnRule', 12, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400634559896227840, 1400626018774945792, '显示列表', '/admin/online/onlineRule/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400634613151305728, 1400626018774945792, '详情', '/admin/online/onlineRule/view', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400634651944423424, 1400626018774945792, '新增', '/admin/online/onlineRule/add', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400634693472227328, 1400626018774945792, '编辑', '/admin/online/onlineRule/update', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400634735549485056, 1400626018774945792, '删除', '/admin/online/onlineRule/delete', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635131969933312, 1400625338886656000, '显示列表', '/admin/online/onlinePage/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635267726970880, 1400625338886656000, '页面以及表单列表', '/admin/online/onlinePage/listAllPageAndForm', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635341274091520, 1400625338886656000, '详情', '/admin/online/onlinePage/view', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635378506928128, 1400625338886656000, '新增', '/admin/online/onlinePage/add', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635426808532992, 1400625338886656000, '编辑', '/admin/online/onlinePage/update', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635527698321408, 1400625338886656000, '更新启用状态', '/admin/online/onlinePage/updatePublished', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635581532213248, 1400625338886656000, '删除', '/admin/online/onlinePage/delete', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635661106548736, 1400625338886656000, '页面数据源列表', '/admin/online/onlinePage/listOnlinePageDatasource', 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635757332271104, 1400625338886656000, '未使用页面数据源列表', '/admin/online/onlinePage/listNotInOnlinePageDatasource', 9, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635827347787776, 1400625338886656000, '添加页面数据源', '/admin/online/onlinePage/addOnlinePageDatasource', 10, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635896461529088, 1400625338886656000, '删除页面数据源', '/admin/online/onlinePage/deleteOnlinePageDatasource', 11, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400635963469729792, 1400625338886656000, '编辑页面数据源', '/admin/online/onlinePage/updateOnlinePageDatasource', 12, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636031752998912, 1400625338886656000, '页面数据源详情', '/admin/online/onlinePage/viewOnlinePageDatasource', 13, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636182936686592, 1400626192725315584, '显示列表', '/admin/online/onlineDatasource/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636217728438272, 1400626192725315584, '详情', '/admin/online/onlineDatasource/view', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636258107002880, 1400626192725315584, '新增', '/admin/online/onlineDatasource/add', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636301480300544, 1400626192725315584, '编辑', '/admin/online/onlineDatasource/update', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636338838966272, 1400626192725315584, '删除', '/admin/online/onlineDatasource/delete', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636501900922880, 1400626237478539264, '显示列表', '/admin/online/onlineDatasourceRelation/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636535371468800, 1400626237478539264, '详情', '/admin/online/onlineDatasourceRelation/view', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636571165659136, 1400626237478539264, '新增', '/admin/online/onlineDatasourceRelation/add', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636610403373056, 1400626237478539264, '编辑', '/admin/online/onlineDatasourceRelation/update', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400636656679129088, 1400626237478539264, '删除', '/admin/online/onlineDatasourceRelation/delete', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400637740705386496, 1400626463740268544, '显示列表', '/admin/online/onlineForm/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400637775962705920, 1400626463740268544, '详情', '/admin/online/onlineForm/view', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400637822737584128, 1400626463740268544, '新增', '/admin/online/onlineForm/add', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400637858414333952, 1400626463740268544, '编辑', '/admin/online/onlineForm/update', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400637895328403456, 1400626463740268544, '删除', '/admin/online/onlineForm/delete', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1400637970863624192, 1400626463740268544, '渲染信息', '/admin/online/onlineForm/render', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1413405061278601216, 1413404952566435840, '显示列表', '/admin/online/onlineVirtualColumn/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1413405166471745536, 1413404952566435840, '详情', '/admin/online/onlineVirtualColumn/view', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1413405224021790720, 1413404952566435840, '新增', '/admin/online/onlineVirtualColumn/add', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1413405313788284928, 1413404952566435840, '编辑', '/admin/online/onlineVirtualColumn/update', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1413405352866615296, 1413404952566435840, '删除', '/admin/online/onlineVirtualColumn/delete', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418030338508066816, 1418029566533832704, '显示列表', '/admin/flow/flowCategory/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418030386436378624, 1418029566533832704, '新增', '/admin/flow/flowCategory/add', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418030437971791872, 1418029566533832704, '编辑', '/admin/flow/flowCategory/update', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418030477918343168, 1418029566533832704, '删除', '/admin/flow/flowCategory/delete', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418030533757112320, 1418029566533832704, '详情', '/admin/flow/flowCategory/view', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031006660694016, 1418029615040958464, '显示列表', '/admin/flow/flowEntry/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031078391681024, 1418029615040958464, '新增', '/admin/flow/flowEntry/add', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031120481521664, 1418029615040958464, '编辑', '/admin/flow/flowEntry/update', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031174604820480, 1418029615040958464, '删除', '/admin/flow/flowEntry/delete', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031219706171392, 1418029615040958464, '详情', '/admin/flow/flowEntry/view', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031304779239424, 1418029615040958464, '发布', '/admin/flow/flowEntry/publish', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031515207471104, 1418029615040958464, '流程版本列表', '/admin/flow/flowEntry/listFlowEntryPublish', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031648351457280, 1418029615040958464, '设置主版本', '/admin/flow/flowEntry/updateMainVersion', 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031712788549632, 1418029615040958464, '挂起', '/admin/flow/flowEntry/suspendFlowEntryPublish', 9, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418031801271586816, 1418029615040958464, '激活', '/admin/flow/flowEntry/activateFlowEntryPublish', 10, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418032222232907776, 1418031999276290048, '显示列表', '/admin/flow/flowEntryVariable/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418032258429751296, 1418031999276290048, '新增', '/admin/flow/flowEntryVariable/add', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418032300414734336, 1418031999276290048, '编辑', '/admin/flow/flowEntryVariable/update', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418032344064856064, 1418031999276290048, '删除', '/admin/flow/flowEntryVariable/delete', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418032382409183232, 1418031999276290048, '详情', '/admin/flow/flowEntryVariable/view', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418033804987076608, 1418030256765276160, '流程实例列表', '/admin/flow/flowOperation/listAllHistoricProcessInstance', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418033889183535104, 1418030256765276160, '我的历史流程', '/admin/flow/flowOperation/listHistoricProcessInstance', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418034243434450944, 1418030256765276160, '历史流程数据', '/admin/flow/flowOnlineOperation/viewHistoricProcessInstance', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418035997727264768, 1418030256765276160, '历史流程信息', '/admin/flow/flowOperation/viewInitialHistoricTaskInfo', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418040510253109248, 1418030256765276160, '终止流程', '/admin/flow/flowOperation/stopProcessInstance', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418040574245605376, 1418030256765276160, '删除流程', '/admin/flow/flowOperation/deleteProcessInstance', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418051334564745216, 1418051228918616064, '仅启动流程', '/admin/flow/flowOperation/startOnly', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418051485324808192, 1418051228918616064, '获取启动信息', '/admin/flow/flowOperation/viewInitialTaskInfo', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418051693639110656, 1418051634793025536, '流程审批', '/admin/flow/flowOperation/viewRuntimeTaskInfo', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418054128097038336, 1418051634793025536, '在办流程数据', '/admin/flow/flowOnlineOperation/viewUserTask', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418054519798894592, 1418054414190514176, '获取流程图', '/admin/flow/flowOperation/viewProcessBpmn', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418054618176294912, 1418054414190514176, '审批历史记录列表', '/admin/flow/flowOperation/listFlowTaskComment', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418054792965525504, 1418054414190514176, '流程审批状态', '/admin/flow/flowOperation/viewHighlightFlowData', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418055060981551104, 1418051634793025536, '提交审批数据', '/admin/flow/flowOnlineOperation/submitUserTask', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418056212146032640, 1418051634793025536, '待办任务列表', '/admin/flow/flowOperation/listRuntimeTask', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418056212146032641, 1418051634793025536, '待办任务数量', '/admin/flow/flowOperation/countRuntimeTask', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418079603167072256, 1418054414190514176, '文件上传', '/admin/flow/flowOnlineOperation/upload', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1418079670594703360, 1418054414190514176, '文件下载', '/admin/flow/flowOnlineOperation/download', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1423635764486344704, 1423635643371622400, '已办任务列表', '/admin/flow/flowOperation/listHistoricTask', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1423635851312631808, 1423635643371622400, '已办任务信息', '/admin/flow/flowOperation/viewHistoricTaskInfo', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1423636091033882624, 1423635643371622400, '加签', '/admin/flow/flowOperation/submitConsign', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1423984506028691456, 1418030256765276160, '撤销工单', '/admin/flow/flowOperation/cancelWorkOrder', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213185, 1440911410581213184, '新增', '/admin/upms/sysDept/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213186, 1440911410581213184, '编辑', '/admin/upms/sysDept/update', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213187, 1440911410581213184, '删除', '/admin/upms/sysDept/delete', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213188, 1440911410581213184, '显示列表', '/admin/upms/sysDept/list', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213189, 1440911410581213184, '导出', '/admin/upms/sysDept/export', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213190, 1440911410581213184, '详情', '/admin/upms/sysDept/view', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213191, 1440911410581213184, '打印', '/admin/upms/sysDept/print', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213192, 1440911410581213184, '新增部门岗位', '/admin/upms/sysDept/addSysDeptPost', 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213193, 1440911410581213184, '编辑部门岗位', '/admin/upms/sysDept/updateSysDeptPost', 9, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213194, 1440911410581213184, '移除部门岗位', '/admin/upms/sysDept/deleteSysDeptPost', 10, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213195, 1440911410581213184, '列表显示部门岗位', '/admin/upms/sysDept/listSysDeptPost', 11, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213196, 1440911410581213184, '列表显示未关联部门岗位', '/admin/upms/sysDept/listNotInSysDeptPost', 12, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213197, 1440911410581213184, '详情显示部门岗位', '/admin/upms/sysDept/viewSysDeptPost', 13, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213199, 1440911410581213198, '新增', '/admin/upms/sysUser/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213200, 1440911410581213198, '编辑', '/admin/upms/sysUser/update', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213201, 1440911410581213198, '删除', '/admin/upms/sysUser/delete', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213202, 1440911410581213198, '显示列表', '/admin/upms/sysUser/list', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213203, 1440911410581213198, '导出', '/admin/upms/sysUser/export', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213204, 1440911410581213198, '详情', '/admin/upms/sysUser/view', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213205, 1440911410581213198, '打印', '/admin/upms/sysUser/print', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213206, 1440911410581213198, '重置密码', '/admin/upms/sysUser/resetPassword', 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213207, 1440911410581213198, '用户权限资源分配详情', '/admin/upms/sysUser/listSysPermWithDetail', 9, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213208, 1440911410581213198, '用户权限字分配详情', '/admin/upms/sysUser/listSysPermCodeWithDetail', 10, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213209, 1440911410581213198, '用户菜单分配详情', '/admin/upms/sysUser/listSysMenuWithDetail', 11, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213211, 1440911410581213210, '新增', '/admin/upms/sysRole/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213212, 1440911410581213210, '编辑', '/admin/upms/sysRole/update', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213213, 1440911410581213210, '删除', '/admin/upms/sysRole/delete', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213214, 1440911410581213210, '显示列表', '/admin/upms/sysRole/list', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213215, 1440911410581213210, '详情', '/admin/upms/sysRole/view', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213216, 1440911410581213210, '授权用户', '/admin/upms/sysRole/addUserRole', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213217, 1440911410581213210, '移除用户', '/admin/upms/sysRole/deleteUserRole', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213218, 1440911410581213210, '角色用户列表', '/admin/upms/sysRole/listUserRole', 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213219, 1440911410581213210, '角色未添加用户列表', '/admin/upms/sysRole/listNotInUserRole', 9, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213220, 1440911410581213210, '角色权限资源分配详情', '/admin/upms/sysRole/listSysPermWithDetail', 10, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213221, 1440911410581213210, '角色权限字分配详情', '/admin/upms/sysRole/listSysPermCodeWithDetail', 11, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213223, 1440911410581213222, '新增', '/admin/upms/sysDataPerm/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213224, 1440911410581213222, '编辑', '/admin/upms/sysDataPerm/update', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213225, 1440911410581213222, '删除', '/admin/upms/sysDataPerm/delete', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213226, 1440911410581213222, '显示列表', '/admin/upms/sysDataPerm/list', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213227, 1440911410581213222, '详情', '/admin/upms/sysDataPerm/view', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213228, 1440911410581213222, '授权用户', '/admin/upms/sysDataPerm/addDataPermUser', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213229, 1440911410581213222, '移除用户', '/admin/upms/sysDataPerm/deleteDataPermUser', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213230, 1440911410581213222, '数据权限用户列表', '/admin/upms/sysDataPerm/listDataPermUser', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213231, 1440911410581213222, '数据权限未添加用户列表', '/admin/upms/sysDataPerm/listNotInDataPermUser', 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213233, 1440911410581213232, '新增', '/admin/upms/sysPost/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213234, 1440911410581213232, '编辑', '/admin/upms/sysPost/update', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213235, 1440911410581213232, '删除', '/admin/upms/sysPost/delete', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213236, 1440911410581213232, '显示列表', '/admin/upms/sysPost/list', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213237, 1440911410581213232, '详情', '/admin/upms/sysPost/view', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213239, 1440911410581213238, '新增', '/admin/upms/sysMenu/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213240, 1440911410581213238, '删除', '/admin/upms/sysMenu/delete', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213241, 1440911410581213238, '编辑', '/admin/upms/sysMenu/update', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213242, 1440911410581213238, '显示列表', '/admin/upms/sysMenu/list', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213243, 1440911410581213238, '详情', '/admin/upms/sysMenu/view', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213244, 1440911410581213238, '菜单权限资源分配详情', '/admin/upms/sysMenu/listSysPermWithDetail', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213245, 1440911410581213238, '菜单用户分配详情', '/admin/upms/sysMenu/listSysUserWithDetail', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213247, 1440911410581213246, '新增', '/admin/upms/sysPermCode/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213248, 1440911410581213246, '编辑', '/admin/upms/sysPermCode/update', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213249, 1440911410581213246, '删除', '/admin/upms/sysPermCode/delete', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213250, 1440911410581213246, '显示列表', '/admin/upms/sysPermCode/list', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213251, 1440911410581213246, '详情', '/admin/upms/sysPermCode/view', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213252, 1440911410581213246, '权限字用户分配详情', '/admin/upms/sysPermCode/listSysUserWithDetail', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213253, 1440911410581213246, '权限字角色分配详情', '/admin/upms/sysPermCode/listSysRoleWithDetail', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213255, 1440911410581213254, '新增', '/admin/upms/sysPermModule/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213256, 1440911410581213254, '编辑', '/admin/upms/sysPermModule/update', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213257, 1440911410581213254, '删除', '/admin/upms/sysPermModule/delete', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213258, 1440911410581213254, '显示列表', '/admin/upms/sysPermModule/list', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213259, 1440911410581213254, '显示全部', '/admin/upms/sysPermModule/listAll', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213261, 1440911410581213260, '新增', '/admin/upms/sysPerm/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213262, 1440911410581213260, '编辑', '/admin/upms/sysPerm/update', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213263, 1440911410581213260, '删除', '/admin/upms/sysPerm/delete', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213264, 1440911410581213260, '显示列表', '/admin/upms/sysPerm/list', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213265, 1440911410581213260, '详情', '/admin/upms/sysPerm/view', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213266, 1440911410581213260, '权限资源用户分配详情', '/admin/upms/sysPerm/listSysUserWithDetail', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213267, 1440911410581213260, '权限资源角色分配详情', '/admin/upms/sysPerm/listSysRoleWithDetail', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213268, 1440911410581213260, '权限资源菜单分配详情', '/admin/upms/sysPerm/listSysMenuWithDetail', 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213271, 1440911410581213270, '新增', '/admin/app/areaCode/add', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213272, 1440911410581213270, '编辑', '/admin/app/areaCode/update', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213273, 1440911410581213270, '删除', '/admin/app/areaCode/delete', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213274, 1440911410581213270, '同步缓存', '/admin/app/areaCode/reloadCachedData', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213276, 1440911410581213275, '显示列表', '/admin/upms/loginUser/list', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440911410581213277, 1440911410581213275, '删除', '/admin/upms/loginUser/delete', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440975727276068864, 1440975375537541120, '启动并提交数据', '/admin/flow/flowOnlineOperation/startAndTakeUserTask/flowLeave', 1, 1440911410581213417, '2021-09-23 17:46:00', 1440911410581213417, '2021-09-23 17:46:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440975781374201856, 1440975375537541120, '工单列表', '/admin/flow/flowOnlineOperation/listWorkOrder/flowLeave', 2, 1440911410581213417, '2021-09-23 17:46:13', 1440911410581213417, '2021-09-23 17:46:13', 1); +INSERT INTO `zz_sys_perm` VALUES (1440975850529886208, 1440975429199466496, '启动并提交数据', '/admin/flow/flowOnlineOperation/startAndTakeUserTask/flowSubmit', 1, 1440911410581213417, '2021-09-23 17:46:29', 1440911410581213417, '2021-09-23 17:46:29', 1); +INSERT INTO `zz_sys_perm` VALUES (1440975895627042816, 1440975429199466496, '工单列表', '/admin/flow/flowOnlineOperation/listWorkOrder/flowSubmit', 2, 1440911410581213417, '2021-09-23 17:46:40', 1440911410581213417, '2021-09-23 17:46:40', 1); +INSERT INTO `zz_sys_perm` VALUES (1440975979374710784, 1440975469133434880, '启动并提交数据', '/admin/flow/flowOnlineOperation/startAndTakeUserTask/flowContract', 1, 1440911410581213417, '2021-09-23 17:47:00', 1440911410581213417, '2021-09-23 17:47:00', 1); +INSERT INTO `zz_sys_perm` VALUES (1440976024471867392, 1440975469133434880, '工单列表', '/admin/flow/flowOnlineOperation/listWorkOrder/flowContract', 2, 1440911410581213417, '2021-09-23 17:47:11', 1440911410581213417, '2021-09-23 17:47:11', 1); +INSERT INTO `zz_sys_perm` VALUES (1440976144311521280, 1440975527128076288, '启动并提交数据', '/admin/flow/flowOnlineOperation/startAndTakeUserTask/flowConSign', 1, 1440911410581213417, '2021-09-23 17:47:40', 1440911410581213417, '2021-09-23 17:47:40', 1); +INSERT INTO `zz_sys_perm` VALUES (1440976188553039872, 1440975527128076288, '工单列表', '/admin/flow/flowOnlineOperation/listWorkOrder/flowConSign', 2, 1440911410581213417, '2021-09-23 17:47:50', 1440911410581213417, '2021-09-23 17:47:50', 1); +INSERT INTO `zz_sys_perm` VALUES (1440976259415805952, 1440975571776442368, '启动并提交数据', '/admin/flow/flowOnlineOperation/startAndTakeUserTask/flowTranslate', 1, 1440911410581213417, '2021-09-23 17:48:07', 1440911410581213417, '2021-09-23 17:48:07', 1); +INSERT INTO `zz_sys_perm` VALUES (1440976310951219200, 1440975571776442368, '工单列表', '/admin/flow/flowOnlineOperation/listWorkOrder/flowTranslate', 2, 1440911410581213417, '2021-09-23 17:48:19', 1440911410581213417, '2021-09-23 17:48:19', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm_code +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm_code`; +CREATE TABLE `zz_sys_perm_code` ( + `perm_code_id` bigint(20) NOT NULL COMMENT '主键Id', + `parent_id` bigint(20) DEFAULT NULL COMMENT '上级权限字Id', + `perm_code` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '权限字标识(一般为有含义的英文字符串)', + `perm_code_type` int(11) NOT NULL COMMENT '类型(0: 表单 1: UI片段 2: 操作)', + `show_name` varchar(128) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '显示名称', + `show_order` int(11) NOT NULL COMMENT '显示顺序(数值越小,越靠前)', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`perm_code_id`), + UNIQUE KEY `idx_perm_code` (`perm_code`) USING BTREE, + KEY `idx_parent_id` (`parent_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统权限资源表'; + +-- ---------------------------- +-- Records of zz_sys_perm_code +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_code` VALUES (1400638673195634688, NULL, 'formOnlineDict', 0, '在线表单字典管理', 12000, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1400638885750378496, 1400638673195634688, 'formOnlineDict:fragmentOnlineDict', 1, '在线表单字典管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1400639030462255104, NULL, 'formOnlinePage', 0, '在线表单表单管理', 12100, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1400639252747784192, 1400639030462255104, 'formOnlinePage:fragmentOnlinePage', 1, '在线表单表单管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418046729906819072, NULL, 'formFlowCategory', 0, '流程分类', 13000, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418046848794365952, 1418046729906819072, 'formFlowCategory:formFlowCategory', 1, '流程分类', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418046986677915648, 1418046848794365952, 'formFlowCategory:formFlowCategory:add', 2, '新增', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418047095188754432, 1418046848794365952, 'formFlowCategory:formFlowCategory:update', 2, '编辑', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418047182946177024, 1418046848794365952, 'formFlowCategory:formFlowCategory:delete', 2, '删除', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418048134759583744, NULL, 'formFlowEntry', 0, '流程设计', 13100, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418048205177753600, 1418048134759583744, 'formFlowEntry:formFlowEntry', 1, '流程设计', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418048335343783936, 1418048205177753600, 'formFlowEntry:formFlowEntry:update', 2, '编辑', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418048872671875072, NULL, 'formAllInstance', 0, '流程实例', 13200, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418049164754817024, 1418048872671875072, 'formAllInstance:formAllInstance', 1, '流程实例', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418049287106859008, 1418049164754817024, 'formAllInstance:formAllInstance:stop', 2, '终止', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418049398776008704, 1418049164754817024, 'formAllInstance:formAllInstance:delete', 2, '删除', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418050031436435456, NULL, 'formMyTask', 0, '我的待办', 13300, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418050322282057728, 1418050031436435456, 'formMyTask:formMyTask', 1, '我的待办', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418050797706416128, 1418048205177753600, 'formFlowEntry:formFlowEntry:start', 2, '启动', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-24 09:28:39', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418057020824621056, NULL, 'formMyHistoryTask', 0, '历史流程', 13400, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1418057346877231104, 1418057020824621056, 'formMyHistoryTask:formMyHistoryTask', 1, '历史流程', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1423636498195943424, NULL, 'formMyApprovedTask', 0, '已办任务', 13500, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1423637544578322432, 1423636498195943424, 'formMyApprovedTask:formMyApprovedTask', 1, '已办任务', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213286, NULL, 'formSysUser', 0, '用户管理', 10000, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213287, 1440911410581213286, 'formSysUser:fragmentSysUser', 1, '用户管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213288, 1440911410581213287, 'formSysUser:fragmentSysUser:add', 2, '新增', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213289, 1440911410581213287, 'formSysUser:fragmentSysUser:update', 2, '编辑', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213290, 1440911410581213287, 'formSysUser:fragmentSysUser:delete', 2, '删除', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213291, 1440911410581213287, 'formSysUser:fragmentSysUser:resetPassword', 2, '重置密码', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213292, 1440911410581213287, 'formSysUser:fragmentSysUser:listSysUserPermDetail', 2, '权限详情', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213300, NULL, 'formSysDept', 0, '部门管理', 10100, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213301, 1440911410581213300, 'formSysDept:fragmentSysDept', 1, '部门管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213302, 1440911410581213301, 'formSysDept:fragmentSysDept:add', 2, '新增', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213303, 1440911410581213301, 'formSysDept:fragmentSysDept:update', 2, '编辑', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213304, 1440911410581213301, 'formSysDept:fragmentSysDept:delete', 2, '删除', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213305, 1440911410581213301, 'formSysDept:fragmentSysDept:editPost', 2, '设置岗位', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213306, 1440911410581213301, 'formSysDept:fragmentSysDept:viewPost', 2, '查看岗位', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213318, NULL, 'formSysRole', 0, '角色管理', 10200, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213319, 1440911410581213318, 'formSysRole:fragmentSysRole', 1, '角色管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213320, 1440911410581213318, 'formSysRole:fragmentSysRoleUser', 1, '用户授权', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213321, 1440911410581213319, 'formSysRole:fragmentSysRole:add', 2, '新增', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213322, 1440911410581213319, 'formSysRole:fragmentSysRole:update', 2, '编辑', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213323, 1440911410581213319, 'formSysRole:fragmentSysRole:delete', 2, '删除', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213324, 1440911410581213319, 'formSysRole:fragmentSysRole:listSysRolePermDetail', 2, '权限详情', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213325, 1440911410581213320, 'formSysRole:fragmentSysRoleUser:addUserRole', 2, '授权用户', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213326, 1440911410581213320, 'formSysRole:fragmentSysRoleUser:deleteUserRole', 2, '移除用户', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213337, NULL, 'formSysDataPerm', 0, '数据权限管理', 10400, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213338, 1440911410581213337, 'formSysDataPerm:fragmentSysDataPerm', 1, '数据权限管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213339, 1440911410581213337, 'formSysDataPerm:fragmentSysDataPermUser', 1, '用户授权', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213340, 1440911410581213338, 'formSysDataPerm:fragmentSysDataPerm:add', 2, '新增', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213341, 1440911410581213338, 'formSysDataPerm:fragmentSysDataPerm:update', 2, '编辑', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213342, 1440911410581213338, 'formSysDataPerm:fragmentSysDataPerm:delete', 2, '删除', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213343, 1440911410581213339, 'formSysDataPerm:fragmentSysDataPermUser:addDataPermUser', 2, '授权用户', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213344, 1440911410581213339, 'formSysDataPerm:fragmentSysDataPermUser:deleteDataPermUser', 2, '移除用户', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213351, NULL, 'formSysMenu', 0, '菜单管理', 10600, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213352, 1440911410581213351, 'formSysMenu:fragmentSysMenu', 1, '菜单管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213353, 1440911410581213352, 'formSysMenu:fragmentSysMenu:add', 2, '新增', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213354, 1440911410581213352, 'formSysMenu:fragmentSysMenu:update', 2, '编辑', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213355, 1440911410581213352, 'formSysMenu:fragmentSysMenu:delete', 2, '删除', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213356, 1440911410581213352, 'formSysMenu:fragmentSysMenu:listSysMenuPermDetail', 2, '权限详情', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213363, NULL, 'formSysPermCode', 0, '权限字管理', 10700, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213364, 1440911410581213363, 'formSysPermCode:fragmentSysPermCode', 1, '权限字管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213365, 1440911410581213364, 'formSysPermCode:fragmentSysPermCode:add', 2, '新增', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213366, 1440911410581213364, 'formSysPermCode:fragmentSysPermCode:update', 2, '编辑', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213367, 1440911410581213364, 'formSysPermCode:fragmentSysPermCode:delete', 2, '删除', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213368, 1440911410581213364, 'formSysPermCode:fragmentSysPermCode:listSysPermCodePermDetail', 2, '权限详情', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213378, NULL, 'formSysPerm', 0, '权限管理', 10800, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213379, 1440911410581213378, 'formSysPerm:fragmentSysPerm', 1, '权限管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213380, 1440911410581213379, 'formSysPerm:fragmentSysPerm:addPermModule', 2, '新增模块', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213381, 1440911410581213379, 'formSysPerm:fragmentSysPerm:updatePermModule', 2, '编辑模块', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213382, 1440911410581213379, 'formSysPerm:fragmentSysPerm:deletePermModule', 2, '删除模块', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213383, 1440911410581213379, 'formSysPerm:fragmentSysPerm:addPerm', 2, '新增权限', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213384, 1440911410581213379, 'formSysPerm:fragmentSysPerm:updatePerm', 2, '编辑权限', 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213385, 1440911410581213379, 'formSysPerm:fragmentSysPerm:deletePerm', 2, '删除权限', 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213386, 1440911410581213379, 'formSysPerm:fragmentSysPerm:listSysPermPermDetail', 2, '权限详情', 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213393, NULL, 'formSysDict', 0, '字典管理', 10900, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213394, 1440911410581213393, 'formSysDict:fragmentSysDict', 1, '字典管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213395, 1440911410581213394, 'formSysDict:fragmentSysDict:add', 2, '新增', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213396, 1440911410581213394, 'formSysDict:fragmentSysDict:update', 2, '编辑', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213397, 1440911410581213394, 'formSysDict:fragmentSysDict:delete', 2, '删除', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213398, 1440911410581213394, 'formSysDict:fragmentSysDict:reloadCache', 2, '同步缓存', 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213402, NULL, 'formSysLoginUser', 0, '在线用户', 11200, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213403, 1440911410581213402, 'formSysLoginUser:fragmentLoginUser', 1, '在线用户', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213404, 1440911410581213403, 'formSysLoginUser:fragmentLoginUser:delete', 2, '强制下线', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213411, NULL, 'formSysPost', 0, '岗位管理', 10150, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213412, 1440911410581213411, 'formSysPost:fragmentSysPost', 1, '岗位管理', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213413, 1440911410581213412, 'formSysPost:fragmentSysPost:add', 2, '新增', 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213414, 1440911410581213412, 'formSysPost:fragmentSysPost:update', 2, '编辑', 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440911410581213415, 1440911410581213412, 'formSysPost:fragmentSysPost:delete', 2, '删除', 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440976898661289984, NULL, 'formFlowLeave', 0, '请假申请', 14000, 1440911410581213417, '2021-09-23 17:50:39', 1440911410581213417, '2021-09-23 17:50:39', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440976998183735296, NULL, 'formContractOrder', 0, '合同工单', 14100, 1440911410581213417, '2021-09-23 17:51:03', 1440911410581213417, '2021-09-23 17:51:03', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440977405874278400, 1440976898661289984, 'formFlowLeave:formFlowLeave', 1, '请假申请', 1, 1440911410581213417, '2021-09-23 17:52:40', 1440911410581213417, '2021-09-23 17:52:40', 1); +INSERT INTO `zz_sys_perm_code` VALUES (1440977767599443968, 1440976998183735296, 'formContractOrder:formContractOrder', 1, '合同工单', 1, 1440911410581213417, '2021-09-23 17:54:07', 1440911410581213417, '2021-09-23 17:54:07', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm_code_perm +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm_code_perm`; +CREATE TABLE `zz_sys_perm_code_perm` ( + `perm_code_id` bigint(20) NOT NULL COMMENT '权限字Id', + `perm_id` bigint(20) NOT NULL COMMENT '权限id', + PRIMARY KEY (`perm_code_id`,`perm_id`), + KEY `idx_perm_id` (`perm_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统权限字和权限资源关联表'; + +-- ---------------------------- +-- Records of zz_sys_perm_code_perm +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400638885750378496, 1400626748101496832); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400626748101496832); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400638885750378496, 1400626963806162944); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400626963806162944); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400638885750378496, 1400627109692444672); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400627109692444672); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400638885750378496, 1400632108514283520); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400632108514283520); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400638885750378496, 1400632216169484288); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400632216169484288); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400638885750378496, 1400632326538399744); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400638885750378496, 1400632438635368448); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400638885750378496, 1400632511620452352); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400632924021198848); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400632978937221120); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633026181861376); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633077717274624); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633129688895488); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633375525441536); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1400633375525441536); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633437093629952); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633529678696448); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633568027217920); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633612201627648); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633713376628736); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633798403559424); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400633922085195776); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400634012745076736); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400634100498305024); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400634280308117504); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400634354593435648); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400634559896227840); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400634613151305728); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400634651944423424); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400634693472227328); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400634735549485056); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635131969933312); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1400635131969933312); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635267726970880); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635341274091520); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635378506928128); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635426808532992); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635527698321408); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635581532213248); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635661106548736); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1400635661106548736); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635757332271104); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635827347787776); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635896461529088); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400635963469729792); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636031752998912); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636182936686592); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636217728438272); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636258107002880); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636301480300544); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636338838966272); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636501900922880); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1400636501900922880); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636535371468800); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636571165659136); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636610403373056); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400636656679129088); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400637740705386496); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1400637740705386496); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400637775962705920); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1423637544578322432, 1400637775962705920); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1400637775962705920); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1400637775962705920); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400637822737584128); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400637858414333952); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400637895328403456); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1400637970863624192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1400637970863624192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1400637970863624192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418057346877231104, 1400637970863624192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1423637544578322432, 1400637970863624192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1400637970863624192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1400637970863624192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1413405061278601216); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1413405061278601216); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1413405166471745536); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1413405224021790720); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1413405313788284928); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1400639252747784192, 1413405352866615296); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418026612762349572); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418026612762349580); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418046848794365952, 1418030338508066816); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418046986677915648, 1418030386436378624); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418047095188754432, 1418030437971791872); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418047182946177024, 1418030477918343168); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418047095188754432, 1418030533757112320); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048205177753600, 1418031006660694016); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418031078391681024); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418031120481521664); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418031174604820480); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418031219706171392); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418031304779239424); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418031515207471104); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418031648351457280); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418031712788549632); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418031801271586816); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418032222232907776); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418032258429751296); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418032300414734336); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418032344064856064); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418032382409183232); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418049164754817024, 1418033804987076608); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418057346877231104, 1418033889183535104); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418049164754817024, 1418034243434450944); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418057346877231104, 1418034243434450944); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1423637544578322432, 1418034243434450944); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418034243434450944); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418034243434450944); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418049164754817024, 1418035997727264768); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418057346877231104, 1418035997727264768); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418035997727264768); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418035997727264768); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418049287106859008, 1418040510253109248); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418049398776008704, 1418040574245605376); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1418051334564745216); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418051334564745216); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418051334564745216); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1418051485324808192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418051485324808192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418051485324808192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418051693639110656); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418051693639110656); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418051693639110656); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418054128097038336); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418054128097038336); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418054128097038336); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1418054519798894592); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418049164754817024, 1418054519798894592); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418054519798894592); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1418054519798894592); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418057346877231104, 1418054519798894592); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1423637544578322432, 1418054519798894592); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418054519798894592); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418054519798894592); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418054618176294912); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418057346877231104, 1418054618176294912); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1423637544578322432, 1418054618176294912); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418054618176294912); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418054618176294912); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418049164754817024, 1418054792965525504); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418054792965525504); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418057346877231104, 1418054792965525504); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1423637544578322432, 1418054792965525504); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418054792965525504); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418054792965525504); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418055060981551104); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418055060981551104); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418055060981551104); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418056212146032640); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418079603167072256); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1418079603167072256); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418079603167072256); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418079603167072256); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050322282057728, 1418079670594703360); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1418079670594703360); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418057346877231104, 1418079670594703360); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1418079670594703360); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1418079670594703360); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1423637544578322432, 1423635764486344704); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1423637544578322432, 1423635851312631808); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1423637544578322432, 1423636091033882624); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1423636091033882624); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1423636091033882624); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1423984506028691456); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1423984506028691456); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213302, 1440911410581213185); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213303, 1440911410581213186); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213304, 1440911410581213187); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213288, 1440911410581213188); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213289, 1440911410581213188); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213301, 1440911410581213188); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213301, 1440911410581213189); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213303, 1440911410581213190); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213303, 1440911410581213191); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213305, 1440911410581213192); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213305, 1440911410581213193); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213305, 1440911410581213194); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213305, 1440911410581213195); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213306, 1440911410581213195); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213305, 1440911410581213196); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213305, 1440911410581213197); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213306, 1440911410581213197); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213288, 1440911410581213199); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213289, 1440911410581213200); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213290, 1440911410581213201); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418048335343783936, 1440911410581213202); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213287, 1440911410581213202); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213287, 1440911410581213203); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213289, 1440911410581213204); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213289, 1440911410581213205); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213291, 1440911410581213206); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213292, 1440911410581213207); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213292, 1440911410581213208); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213292, 1440911410581213209); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213321, 1440911410581213211); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213322, 1440911410581213212); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213323, 1440911410581213213); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213288, 1440911410581213214); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213289, 1440911410581213214); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213319, 1440911410581213214); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213322, 1440911410581213215); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213325, 1440911410581213216); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213326, 1440911410581213217); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213320, 1440911410581213218); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213325, 1440911410581213219); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213324, 1440911410581213220); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213324, 1440911410581213221); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213340, 1440911410581213223); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213341, 1440911410581213224); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213342, 1440911410581213225); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213288, 1440911410581213226); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213289, 1440911410581213226); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213338, 1440911410581213226); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213341, 1440911410581213227); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213343, 1440911410581213228); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213344, 1440911410581213229); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213339, 1440911410581213230); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213343, 1440911410581213231); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213413, 1440911410581213233); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213414, 1440911410581213234); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213415, 1440911410581213235); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213412, 1440911410581213236); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213414, 1440911410581213237); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213353, 1440911410581213239); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213355, 1440911410581213240); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213354, 1440911410581213241); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213321, 1440911410581213242); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213322, 1440911410581213242); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213352, 1440911410581213242); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213354, 1440911410581213243); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213356, 1440911410581213244); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213356, 1440911410581213245); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213365, 1440911410581213247); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213366, 1440911410581213248); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213367, 1440911410581213249); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213353, 1440911410581213250); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213354, 1440911410581213250); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213364, 1440911410581213250); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213366, 1440911410581213251); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213368, 1440911410581213252); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213368, 1440911410581213253); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213380, 1440911410581213255); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213381, 1440911410581213256); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213382, 1440911410581213257); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213379, 1440911410581213258); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213365, 1440911410581213259); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213366, 1440911410581213259); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213379, 1440911410581213259); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213383, 1440911410581213261); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213384, 1440911410581213262); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213385, 1440911410581213263); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213379, 1440911410581213264); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213384, 1440911410581213265); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213386, 1440911410581213266); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213386, 1440911410581213267); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213386, 1440911410581213268); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213394, 1440911410581213271); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213394, 1440911410581213272); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213394, 1440911410581213273); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213394, 1440911410581213274); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213403, 1440911410581213276); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440911410581213404, 1440911410581213277); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1440975727276068864); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1440975727276068864); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977405874278400, 1440975781374201856); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1440975850529886208); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1440975979374710784); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1440975979374710784); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1440977767599443968, 1440976024471867392); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1440976144311521280); +INSERT INTO `zz_sys_perm_code_perm` VALUES (1418050797706416128, 1440976259415805952); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm_module +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm_module`; +CREATE TABLE `zz_sys_perm_module` ( + `module_id` bigint(20) NOT NULL COMMENT '权限模块id', + `parent_id` bigint(20) DEFAULT '0' COMMENT '上级权限模块id', + `module_name` varchar(64) COLLATE utf8mb4_bin NOT NULL DEFAULT '' COMMENT '权限模块名称', + `module_type` int(11) NOT NULL COMMENT '模块类型(0: 普通模块 1: Controller模块)', + `show_order` int(11) NOT NULL DEFAULT '0' COMMENT '权限模块在当前层级下的顺序,由小到大', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`module_id`) USING BTREE, + KEY `idx_show_order` (`show_order`) USING BTREE, + KEY `idx_parent_id` (`parent_id`) USING BTREE, + KEY `idx_module_type` (`module_type`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统权限模块表'; + +-- ---------------------------- +-- Records of zz_sys_perm_module +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_module` VALUES (1400625106979393536, NULL, '在线表单', 0, 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1400625224646397952, 1400625106979393536, '数据库连接', 1, 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1400625338886656000, 1400625106979393536, '页面管理', 1, 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1400625585851469824, 1400625106979393536, '在线表单字典管理', 1, 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1400625800033603584, 1400625106979393536, '数据表管理', 1, 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1400625906245963776, 1400625106979393536, '数据表字段', 1, 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1400626018774945792, 1400625106979393536, '字段验证规则', 1, 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1400626192725315584, 1400625106979393536, '数据源管理', 1, 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1400626237478539264, 1400625106979393536, '数据源关联', 1, 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1400626463740268544, 1400625106979393536, '表单管理', 1, 9, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1401532052901203970, NULL, '用户权限', 0, 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1401532056508305408, NULL, '系统配置', 0, 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1401532056508305409, NULL, '缺省分组', 0, 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1413404952566435840, 1400625106979393536, '虚拟字段管理', 1, 10, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1418028920103505920, NULL, '流程管理', 0, 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1418029566533832704, 1418028920103505920, '流程分类', 1, 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1418029615040958464, 1418028920103505920, '流程设计', 1, 2, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1418030256765276160, 1418028920103505920, '流程操作', 1, 4, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1418031999276290048, 1418028920103505920, '流程变量', 1, 3, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1418038955105849344, NULL, '工单列表', 0, 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1418051228918616064, 1418028920103505920, '启动流程', 1, 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1418051634793025536, 1418028920103505920, '审批流程', 1, 6, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1418054414190514176, 1418028920103505920, '流程审批数据', 1, 7, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1423635643371622400, 1418028920103505920, '已办任务', 1, 8, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213184, 1401532052901203970, '部门管理', 1, 0, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213198, 1401532052901203970, '用户管理', 1, 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213210, 1401532052901203970, '角色管理', 1, 10, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213222, 1401532052901203970, '数据权限管理', 1, 15, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213232, 1401532052901203970, '岗位管理', 1, 20, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213238, 1401532052901203970, '菜单管理', 1, 25, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213246, 1401532052901203970, '权限字管理', 1, 30, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213254, 1401532052901203970, '权限模块管理', 1, 35, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213260, 1401532052901203970, '权限资源管理', 1, 40, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213269, 1401532056508305408, '字典管理', 0, 0, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213270, 1440911410581213269, '行政区划', 1, 1, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440911410581213275, 1401532056508305408, '在线用户', 1, 5, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440975375537541120, 1418038955105849344, '请假申请', 1, 1, 1440911410581213417, '2021-09-23 17:44:36', 1440911410581213417, '2021-09-23 17:44:36', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440975429199466496, 1418038955105849344, '报销申请', 1, 2, 1440911410581213417, '2021-09-23 17:44:49', 1440911410581213417, '2021-09-23 17:44:49', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440975469133434880, 1418038955105849344, '合同审批', 1, 3, 1440911410581213417, '2021-09-23 17:44:59', 1440911410581213417, '2021-09-23 17:44:59', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440975527128076288, 1418038955105849344, '多实例加签', 1, 4, 1440911410581213417, '2021-09-23 17:45:12', 1440911410581213417, '2021-09-23 17:45:12', 1); +INSERT INTO `zz_sys_perm_module` VALUES (1440975571776442368, 1418038955105849344, '转办流程', 1, 5, 1440911410581213417, '2021-09-23 17:45:23', 1440911410581213417, '2021-09-23 17:45:32', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_perm_whitelist +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_perm_whitelist`; +CREATE TABLE `zz_sys_perm_whitelist` ( + `perm_url` varchar(512) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL COMMENT '权限资源的url', + `module_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '权限资源所属模块名字(通常是Controller的名字)', + `perm_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL COMMENT '权限的名称', + PRIMARY KEY (`perm_url`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='权限资源白名单表(认证用户均可访问的url资源)'; + +-- ---------------------------- +-- Records of zz_sys_perm_whitelist +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/app/areaCode/listAll', '行政区划', '字典全部列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/app/areaCode/listDict', '行政区划', '行政区划列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/app/areaCode/listDictByIds', '行政区划', '行政区划批量Id列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/app/areaCode/listDictByParentId', '行政区划', '行政区划过滤列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/flow/flowCategory/listDict', '流程管理', '流程分类字典'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/flow/flowEntry/listDict', '流程管理', '流程字典'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/flow/flowEntry/viewDict', '流程管理', '流程部分数据查看'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/flow/flowOnlineOperation/listFlowEntryForm', '流程管理', '流程列表包含在线表单列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/flow/flowOperation/countRuntimeTask', '流程管理', '待办任务列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/online/onlineOperation/listDict', '在线表单', '在线表单字典'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/upms/login/doLogout', '登录模块', '退出登陆'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/upms/login/getLoginInfo', '登录模块', '获取登录信息'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/upms/sysDept/listDict', '部门管理', '部门字典字典列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/upms/sysDept/listDictByIds', '部门管理', '部门字典字典批量Id列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/upms/sysDept/listDictByParentId', '部门管理', '部门字典下一级字典列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/upms/sysDept/listSysDeptPostWithRelation', '系统管理', '部门岗位关联列表'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/upms/sysPost/listDict', '系统管理', '岗位字典接口'); +INSERT INTO `zz_sys_perm_whitelist` VALUES ('/admin/upms/sysPost/listDictByIds', '系统管理', '岗位字典接口'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_post +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_post`; +CREATE TABLE `zz_sys_post` ( + `post_id` bigint(20) NOT NULL COMMENT '岗位Id', + `post_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '岗位名称', + `level` int(11) NOT NULL COMMENT '岗位层级,数值越小级别越高', + `leader_post` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否领导岗位', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`post_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_sys_post +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_post` VALUES (1440963890539139072, '总经理', 1, b'1', 1440911410581213417, '2021-09-23 16:58:58', 1440911410581213417, '2021-09-23 16:59:27', 1); +INSERT INTO `zz_sys_post` VALUES (1440964040611336192, '副经理', 2, b'1', 1440911410581213417, '2021-09-23 16:59:34', 1440911410581213417, '2021-09-23 16:59:34', 1); +INSERT INTO `zz_sys_post` VALUES (1440964097913917440, '组长', 10, b'1', 1440911410581213417, '2021-09-23 16:59:47', 1440911410581213417, '2021-09-23 16:59:47', 1); +INSERT INTO `zz_sys_post` VALUES (1440964131539652608, '副组长', 11, b'1', 1440911410581213417, '2021-09-23 16:59:55', 1440911410581213417, '2021-09-23 16:59:55', 1); +INSERT INTO `zz_sys_post` VALUES (1440964157770829824, '组员', 20, b'0', 1440911410581213417, '2021-09-23 17:00:02', 1440911410581213417, '2021-09-23 17:00:02', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_role +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_role`; +CREATE TABLE `zz_sys_role` ( + `role_id` bigint(20) NOT NULL COMMENT '主键Id', + `role_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '角色名称', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '逻辑删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`role_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统角色表'; + +-- ---------------------------- +-- Records of zz_sys_role +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_role` VALUES (1440965195903012864, '查看全部', 1440911410581213417, '2021-09-23 17:04:09', 1440911410581213417, '2021-09-24 09:25:49', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_role_menu +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_role_menu`; +CREATE TABLE `zz_sys_role_menu` ( + `role_id` bigint(20) NOT NULL COMMENT '角色Id', + `menu_id` bigint(20) NOT NULL COMMENT '菜单Id', + PRIMARY KEY (`role_id`,`menu_id`) USING BTREE, + KEY `idx_menu_id` (`menu_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='角色与菜单对应关系表'; + +-- ---------------------------- +-- Records of zz_sys_role_menu +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1392786476428693504); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1392786549942259712); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1392786950682841088); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532054578925568); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532055971434496); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532055971434497); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532055971434498); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532055971434499); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532055971434500); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532055971434501); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532055971434502); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532055971434503); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1401532055971434504); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418057714138877952); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418057835631087616); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418058049951633408); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418058115667988480); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418058170542067712); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418058289182150656); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418058515099947008); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418058602723151872); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418058744037642240); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418058844164067328); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418058907674218496); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418059005175009280); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418059167532322816); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1418059283920064512); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1423161217970606080); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1433040549035642880); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213280); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213281); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213282); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213283); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213284); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213285); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213294); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213295); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213296); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213297); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213298); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213299); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213308); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213309); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213310); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213311); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213312); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213313); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213314); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213315); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213316); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213317); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213328); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213329); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213330); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213331); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213332); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213333); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213334); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213335); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213336); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213346); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213347); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213348); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213349); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213350); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213358); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213359); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213360); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213361); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213362); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213370); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213371); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213372); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213373); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213374); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213375); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213376); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213377); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213388); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213389); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213390); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213391); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213392); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213400); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213401); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213406); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213407); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213408); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213409); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440911410581213410); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440973980537196544); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974056105971712); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974056110166016); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974056114360320); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974134195523584); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974134199717888); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974134203912192); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974233613111296); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974233617305600); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974233621499904); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974310754750464); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440974580402360320); +INSERT INTO `zz_sys_role_menu` VALUES (1440965195903012864, 1440978065088843776); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_user +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_user`; +CREATE TABLE `zz_sys_user` ( + `user_id` bigint(20) NOT NULL COMMENT '主键Id', + `login_name` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '用户登录名称', + `password` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '密码', + `show_name` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '用户显示名称', + `dept_id` bigint(20) NOT NULL COMMENT '用户所在部门Id', + `user_type` int(11) NOT NULL COMMENT '用户类型(0: 管理员 1: 系统管理用户 2: 系统业务用户)', + `head_image_url` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '用户头像的Url', + `user_status` int(11) NOT NULL COMMENT '状态(0: 正常 1: 锁定)', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者Id', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者Id', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`user_id`) USING BTREE, + UNIQUE KEY `uk_login_name` (`login_name`) USING BTREE, + KEY `idx_dept_id` (`dept_id`) USING BTREE, + KEY `idx_status` (`user_status`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='系统用户表'; + +-- ---------------------------- +-- Records of zz_sys_user +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_user` VALUES (1440911410581213417, 'admin', '$2a$10$GT/GXfypSJ.2f7.npoAAHuINPkC/VJttDGYBB3xyQqWt1bi9qEnL6', '管理员', 1440911410581213416, 0, 'CHANGE TO YOUR HEAD IMAGE URL!!!', 0, 1440911410581213417, '2021-09-23 00:00:00', 1440911410581213417, '2021-09-23 00:00:00', 1); +INSERT INTO `zz_sys_user` VALUES (1440965344985354240, 'leaderHR', '$2a$10$tLqussQ4t4n..A274vS9luxZI8zmxdQSkmwXcOU3egPJtyFIVDYj.', '人事经理', 1440963592970047488, 2, NULL, 0, 1440911410581213417, '2021-09-23 17:04:45', 1440911410581213417, '2021-09-23 17:04:45', 1); +INSERT INTO `zz_sys_user` VALUES (1440965465605148672, 'userA', '$2a$10$BGsgE5KA/hKV95.kCZmMleiUssNRpOGE0qMTkCGHsSiugnqSsaSFS', '员工A', 1440963592970047488, 2, NULL, 0, 1440911410581213417, '2021-09-23 17:05:14', 1440911410581213417, '2021-09-23 17:05:14', 1); +INSERT INTO `zz_sys_user` VALUES (1440965586715676672, 'userB', '$2a$10$J0obwzeNt3iWoArSdRCKLeABdcMwe/rJrPIoGNW.LFgCYKhFKC9Lu', '员工B', 1440963642542526464, 2, NULL, 0, 1440911410581213417, '2021-09-23 17:05:42', 1440911410581213417, '2021-09-23 17:05:42', 1); +INSERT INTO `zz_sys_user` VALUES (1440965697961201664, 'userC', '$2a$10$KukIvoMoncnpSafKnueXnOLEhI5V7cW0GBsGt9EkTGq482vsRgQwm', '员工C', 1440963642542526464, 2, NULL, 0, 1440911410581213417, '2021-09-23 17:06:09', 1440911410581213417, '2021-09-23 17:06:09', 1); +INSERT INTO `zz_sys_user` VALUES (1440965808049098752, 'leaderLaw', '$2a$10$8o2qUYKOpizH42gIs4hDU.TjrzzWu/tOJeQebvXISkAI3wscFbAl2', '法务经理', 1440963642542526464, 2, NULL, 0, 1440911410581213417, '2021-09-23 17:06:35', 1440911410581213417, '2021-09-23 17:06:35', 1); +INSERT INTO `zz_sys_user` VALUES (1440966073686953984, 'leaderTJ', '$2a$10$NLZDkFP/nLkGzo/blYJ7w.HmmZF8v12ByockmYXPZZ7cr/TqILB/u', '天津总监', 1440963698460987392, 2, NULL, 0, 1440911410581213417, '2021-09-23 17:07:39', 1440911410581213417, '2021-09-23 17:07:39', 1); +INSERT INTO `zz_sys_user` VALUES (1440966186522120192, 'leaderTJ2', '$2a$10$F7vVIJeC7OdHTNV050aqieJwJcBdjrUOCGjAE4wq0mESLb1Pn6yoe', '天津经理', 1440963698460987392, 2, NULL, 0, 1440911410581213417, '2021-09-23 17:08:05', 1440911410581213417, '2021-09-23 17:08:05', 1); +INSERT INTO `zz_sys_user` VALUES (1440966324770574336, 'userD', '$2a$10$7G2Lcw1GducD2FtCxQask.7lVRPRvKZk7YVZOsT319uXVtK2LQPji', '员工D', 1440963698460987392, 2, NULL, 0, 1440911410581213417, '2021-09-23 17:08:38', 1440911410581213417, '2021-09-23 17:08:38', 1); +INSERT INTO `zz_sys_user` VALUES (1440969706411397120, 'leader', '$2a$10$LgJRx/7YT.F6oUs4PPVpxuSYQBOdcXqx6dvdkaJmA7ObWdpJzhOQu', '总部领导', 1440911410581213416, 2, NULL, 0, 1440911410581213417, '2021-09-23 17:22:05', 1440911410581213417, '2021-09-23 17:22:05', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_user_post +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_user_post`; +CREATE TABLE `zz_sys_user_post` ( + `user_id` bigint(20) NOT NULL COMMENT '用户Id', + `dept_post_id` bigint(20) NOT NULL COMMENT '部门岗位Id', + `post_id` bigint(20) NOT NULL COMMENT '岗位Id', + PRIMARY KEY (`user_id`,`dept_post_id`) USING BTREE, + KEY `idx_post_id` (`post_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_sys_user_post +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_user_post` VALUES (1440966073686953984, 1440964519391137792, 1440963890539139072); +INSERT INTO `zz_sys_user_post` VALUES (1440969706411397120, 1440969551792574464, 1440963890539139072); +INSERT INTO `zz_sys_user_post` VALUES (1440966186522120192, 1440964519395332096, 1440964040611336192); +INSERT INTO `zz_sys_user_post` VALUES (1440965344985354240, 1440964221780103168, 1440964097913917440); +INSERT INTO `zz_sys_user_post` VALUES (1440965808049098752, 1440964387979399168, 1440964097913917440); +INSERT INTO `zz_sys_user_post` VALUES (1440965465605148672, 1440964221855600640, 1440964157770829824); +INSERT INTO `zz_sys_user_post` VALUES (1440965586715676672, 1440964387983593472, 1440964157770829824); +INSERT INTO `zz_sys_user_post` VALUES (1440965697961201664, 1440964387983593472, 1440964157770829824); +INSERT INTO `zz_sys_user_post` VALUES (1440966324770574336, 1440964519399526400, 1440964157770829824); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_sys_user_role +-- ---------------------------- +DROP TABLE IF EXISTS `zz_sys_user_role`; +CREATE TABLE `zz_sys_user_role` ( + `user_id` bigint(20) NOT NULL COMMENT '用户Id', + `role_id` bigint(20) NOT NULL COMMENT '角色Id', + PRIMARY KEY (`user_id`,`role_id`) USING BTREE, + KEY `idx_role_id` (`role_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin ROW_FORMAT=COMPACT COMMENT='用户与角色对应关系表'; + +-- ---------------------------- +-- Records of zz_sys_user_role +-- ---------------------------- +BEGIN; +INSERT INTO `zz_sys_user_role` VALUES (1440965344985354240, 1440965195903012864); +INSERT INTO `zz_sys_user_role` VALUES (1440965465605148672, 1440965195903012864); +INSERT INTO `zz_sys_user_role` VALUES (1440965586715676672, 1440965195903012864); +INSERT INTO `zz_sys_user_role` VALUES (1440965697961201664, 1440965195903012864); +INSERT INTO `zz_sys_user_role` VALUES (1440965808049098752, 1440965195903012864); +INSERT INTO `zz_sys_user_role` VALUES (1440966073686953984, 1440965195903012864); +INSERT INTO `zz_sys_user_role` VALUES (1440966186522120192, 1440965195903012864); +INSERT INTO `zz_sys_user_role` VALUES (1440966324770574336, 1440965195903012864); +INSERT INTO `zz_sys_user_role` VALUES (1440969706411397120, 1440965195903012864); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_contract +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_contract`; +CREATE TABLE `zz_test_flow_contract` ( + `contract_id` bigint(20) NOT NULL COMMENT '主键Id', + `first_party_id` bigint(20) NOT NULL COMMENT '甲方信息Id', + `second_party_id` bigint(20) NOT NULL COMMENT '乙方信息Id', + `contract_type` int(11) NOT NULL COMMENT '合同类型', + `due_date` datetime NOT NULL COMMENT '到期日期', + `sales_id` bigint(20) NOT NULL COMMENT '业务员Id', + `commission_rate` int(11) NOT NULL COMMENT '提成比例', + `attachment` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '合同附件URL', + `security_attachment` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '保密协议附件URL', + `intellectual_property_attachment` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '知识产权协议附件', + `other_attachment` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '其他附件', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL DEFAULT '0' COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`contract_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_contract +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_contract` VALUES (1424647986075406336, 1424645184158699520, 1424645446290116608, 1, '2021-09-18 00:00:00', 1424607792735457280, 5, '[{\"name\":\"logo.png\",\"filename\":\"c29d9f9302c04114b559f130fe606c4f.png\"}]', '[{\"name\":\"新建位图图像.png\",\"filename\":\"d861d009ae2c46ddbb7ccaf2d679a639.png\"}]', '[{\"name\":\"logo.png\",\"filename\":\"46c75b9445f44540922a84f471f61340.png\"}]', '[{\"name\":\"新建位图图像.png\",\"filename\":\"08c56233600d4da9822c07f22bf4fa0e.png\"}]', 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_contract` VALUES (1441215377508929536, 1424645184158699520, 1424645446290116608, 1, '2021-09-30 00:00:00', 1440966324770574336, 5, '[{\"name\":\"新建位图图像.png\",\"filename\":\"d9aa27ea7eec4375b123e11ce92ec9b5.png\"}]', '[{\"name\":\"新建位图图像.png\",\"filename\":\"0c20b1c7256148018451852ddae9f8aa.png\"}]', NULL, NULL, 1440966324770574336, '2021-09-24 09:38:17', 1440966324770574336, '2021-09-24 09:38:17', 1); +INSERT INTO `zz_test_flow_contract` VALUES (1441217206602960896, 1424645184158699520, 1424645446290116608, 1, '2021-10-09 00:00:00', 1440966324770574336, 7, '[{\"name\":\"新建位图图像.png\",\"filename\":\"dcd2db9b75664251a3baf595f6752d90.png\"}]', '[{\"name\":\"新建位图图像.png\",\"filename\":\"e85a5b89d3bd4a3f94d58b0630afc7af.png\"}]', NULL, NULL, 1440966324770574336, '2021-09-24 09:45:33', 1440966324770574336, '2021-09-24 09:45:33', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_contract_detail +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_contract_detail`; +CREATE TABLE `zz_test_flow_contract_detail` ( + `contract_detail_id` bigint(20) NOT NULL COMMENT '主键Id', + `contract_id` bigint(20) NOT NULL COMMENT '合同Id', + `product_id` bigint(20) NOT NULL COMMENT '产品Id', + `total_count` int(11) NOT NULL COMMENT '数量', + `total_amount` int(11) NOT NULL COMMENT '总价', + `meno` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL DEFAULT '0' COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`contract_detail_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_contract_detail +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_contract_detail` VALUES (1424647986087989249, 1424647986075406336, 1424645586203709440, 1, 12001, '加急', 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_contract_detail` VALUES (1424647986092183552, 1424647986075406336, 1424645694550970368, 5, 143680, NULL, 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_contract_detail` VALUES (1441215377550872576, 1441215377508929536, 1424645586203709440, 100, 1230000, '加急', 1440966324770574336, '2021-09-24 09:38:17', 1440966324770574336, '2021-09-24 09:38:17', 1); +INSERT INTO `zz_test_flow_contract_detail` VALUES (1441217206628126720, 1441217206602960896, 1424645586203709440, 50, 234000, '加急', 1440966324770574336, '2021-09-24 09:45:33', 1440966324770574336, '2021-09-24 09:45:33', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_delivery_detail +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_delivery_detail`; +CREATE TABLE `zz_test_flow_delivery_detail` ( + `delivery_id` bigint(20) NOT NULL COMMENT '主键Id', + `contract_id` bigint(20) NOT NULL COMMENT '合同Id', + `delivery_date` datetime NOT NULL COMMENT '交付日期', + `product_id` bigint(20) NOT NULL COMMENT '产品Id', + `total_count` int(11) NOT NULL COMMENT '数量', + `memo` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL DEFAULT '0' COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`delivery_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_delivery_detail +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_delivery_detail` VALUES (1424647986079600640, 1424647986075406336, '2021-08-14 00:00:00', 1424645586203709440, 1, NULL, 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_delivery_detail` VALUES (1424647986083794944, 1424647986075406336, '2021-08-28 00:00:00', 1424645694550970368, 2, NULL, 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_delivery_detail` VALUES (1424647986087989248, 1424647986075406336, '2021-09-11 00:00:00', 1424645694550970368, 3, NULL, 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_delivery_detail` VALUES (1441215377538289664, 1441215377508929536, '2021-09-27 00:00:00', 1424645586203709440, 40, NULL, 1440966324770574336, '2021-09-24 09:38:17', 1440966324770574336, '2021-09-24 09:38:17', 1); +INSERT INTO `zz_test_flow_delivery_detail` VALUES (1441215377546678272, 1441215377508929536, '2021-09-30 00:00:00', 1424645586203709440, 60, '加急', 1440966324770574336, '2021-09-24 09:38:17', 1440966324770574336, '2021-09-24 09:38:17', 1); +INSERT INTO `zz_test_flow_delivery_detail` VALUES (1441217206619738113, 1441217206602960896, '2021-09-27 00:00:00', 1424645586203709440, 20, NULL, 1440966324770574336, '2021-09-24 09:45:33', 1440966324770574336, '2021-09-24 09:45:33', 1); +INSERT INTO `zz_test_flow_delivery_detail` VALUES (1441217206623932416, 1441217206602960896, '2021-09-29 00:00:00', 1424645586203709440, 30, NULL, 1440966324770574336, '2021-09-24 09:45:33', 1440966324770574336, '2021-09-24 09:45:33', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_first_party +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_first_party`; +CREATE TABLE `zz_test_flow_first_party` ( + `first_party_id` bigint(20) NOT NULL COMMENT '主键Id', + `company_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '公司名称', + `legal_person` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '法人', + `legal_person_id` char(18) COLLATE utf8mb4_bin NOT NULL COMMENT '法人身份证号', + `registry_address` varchar(512) COLLATE utf8mb4_bin NOT NULL COMMENT '注册地址', + `contact_info` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '联系方式', + `business_scope` varchar(4000) COLLATE utf8mb4_bin NOT NULL COMMENT '经营范围', + `memo` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL DEFAULT '0' COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`first_party_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_first_party +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_first_party` VALUES (1424645184158699520, '天津哈哈乐商贸公司', '王哈哈', '120104197604150375', '天津市津南区', '022-23451234', '商贸商贸', '天津商贸', 1424545631073996884, '2021-08-08 16:14:15', 1424545631073996884, '2021-08-08 16:14:15', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_leave +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_leave`; +CREATE TABLE `zz_test_flow_leave` ( + `id` bigint(20) NOT NULL COMMENT '主键Id', + `user_id` bigint(20) NOT NULL COMMENT '请假用户Id', + `leave_reason` varchar(512) COLLATE utf8mb4_bin NOT NULL COMMENT '请假原因', + `leave_type` int(11) NOT NULL COMMENT '请假类型', + `leave_begin_time` datetime NOT NULL COMMENT '请假开始时间', + `leave_end_time` datetime NOT NULL COMMENT '请假结束时间', + `apply_time` datetime NOT NULL COMMENT '申请时间', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_user_id` (`user_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_leave +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_leave` VALUES (1424636082313498624, 1424545631073996884, '请假2天', 1, '2021-08-01 00:00:00', '2021-08-02 00:00:00', '2021-08-08 15:38:05'); +INSERT INTO `zz_test_flow_leave` VALUES (1424649303212691456, 1424545631073996884, '请假一天', 1, '2021-08-01 00:00:00', '2021-08-01 00:00:00', '2021-08-08 16:30:37'); +INSERT INTO `zz_test_flow_leave` VALUES (1424652775060410368, 1424545631073996884, '请假2天', 1, '2021-08-01 00:00:00', '2021-08-02 00:00:00', '2021-08-08 16:44:25'); +INSERT INTO `zz_test_flow_leave` VALUES (1424653286929076224, 1424545631073996884, '请假一天', 1, '2021-08-01 00:00:00', '2021-08-01 00:00:00', '2021-08-08 16:46:27'); +INSERT INTO `zz_test_flow_leave` VALUES (1424653896705380352, 1424545631073996884, '请假3天!!!', 2, '2021-08-01 00:00:00', '2021-08-03 00:00:00', '2021-08-08 16:48:52'); +INSERT INTO `zz_test_flow_leave` VALUES (1424654125999591424, 1424545631073996884, '结婚了结婚了', 3, '2021-08-01 00:00:00', '2021-08-07 00:00:00', '2021-08-08 16:49:47'); +INSERT INTO `zz_test_flow_leave` VALUES (1424657782186971136, 1424654900813369344, '请假请假', 1, '2021-08-01 00:00:00', '2021-08-07 00:00:00', '2021-08-08 17:04:19'); +INSERT INTO `zz_test_flow_leave` VALUES (1424658915961868288, 1424545631073996884, '测试', 1, '2021-08-01 00:00:00', '2021-08-07 00:00:00', '2021-08-08 17:08:49'); +INSERT INTO `zz_test_flow_leave` VALUES (1424659588543680512, 1424608402885054464, '测试请假', 1, '2021-08-01 00:00:00', '2021-08-02 00:00:00', '2021-08-08 17:11:29'); +INSERT INTO `zz_test_flow_leave` VALUES (1424659995714129920, 1424608402885054464, '测试了测试了', 1, '2021-08-01 00:00:00', '2021-08-07 00:00:00', '2021-08-08 17:13:07'); +INSERT INTO `zz_test_flow_leave` VALUES (1424660095102357504, 1424608402885054464, '测试了测试了!!!', 1, '2021-08-01 00:00:00', '2021-08-07 00:00:00', '2021-08-08 17:13:30'); +INSERT INTO `zz_test_flow_leave` VALUES (1441213240326492160, 1440966324770574336, '请假一天', 1, '2021-09-17 00:00:00', '2021-09-18 00:00:00', '2021-09-24 09:29:48'); +INSERT INTO `zz_test_flow_leave` VALUES (1441218427220922368, 1440911410581213417, '请假2天', 1, '2021-09-02 00:00:00', '2021-09-04 00:00:00', '2021-09-24 09:50:24'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_pay_detail +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_pay_detail`; +CREATE TABLE `zz_test_flow_pay_detail` ( + `pay_detail_id` bigint(20) NOT NULL COMMENT '主键Id', + `contract_id` bigint(20) NOT NULL COMMENT '合同Id', + `pay_date` datetime NOT NULL COMMENT '付款日期', + `pay_type` int(11) NOT NULL COMMENT '付款类型', + `percentage` int(11) NOT NULL COMMENT '百分比', + `memo` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL DEFAULT '0' COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`pay_detail_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_pay_detail +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_pay_detail` VALUES (1424647986096377856, 1424647986075406336, '2021-08-18 00:00:00', 1, 20, '预付款', 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1424647986100572160, 1424647986075406336, '2021-08-28 00:00:00', 2, 50, '分期款', 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1424647986104766464, 1424647986075406336, '2021-09-04 00:00:00', 2, 29, '分期款', 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1424647986108960768, 1424647986075406336, '2021-09-17 00:00:00', 3, 10, '尾款', 1424545631073996884, '2021-08-08 16:25:23', 1424545631073996884, '2021-08-08 16:25:23', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1441215377521512448, 1441215377508929536, '2021-09-25 00:00:00', 1, 20, NULL, 1440966324770574336, '2021-09-24 09:38:17', 1440966324770574336, '2021-09-24 09:38:17', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1441215377529901056, 1441215377508929536, '2021-09-28 00:00:00', 2, 60, NULL, 1440966324770574336, '2021-09-24 09:38:17', 1440966324770574336, '2021-09-24 09:38:17', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1441215377534095360, 1441215377508929536, '2021-10-05 00:00:00', 3, 20, NULL, 1440966324770574336, '2021-09-24 09:38:17', 1440966324770574336, '2021-09-24 09:38:17', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1441217206607155200, 1441217206602960896, '2021-09-26 00:00:00', 1, 20, NULL, 1440966324770574336, '2021-09-24 09:45:33', 1440966324770574336, '2021-09-24 09:45:33', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1441217206611349504, 1441217206602960896, '2021-10-01 00:00:00', 2, 40, NULL, 1440966324770574336, '2021-09-24 09:45:33', 1440966324770574336, '2021-09-24 09:45:33', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1441217206615543808, 1441217206602960896, '2021-10-07 00:00:00', 2, 30, NULL, 1440966324770574336, '2021-09-24 09:45:33', 1440966324770574336, '2021-09-24 09:45:33', 1); +INSERT INTO `zz_test_flow_pay_detail` VALUES (1441217206619738112, 1441217206602960896, '2021-10-15 00:00:00', 3, 10, NULL, 1440966324770574336, '2021-09-24 09:45:33', 1440966324770574336, '2021-09-24 09:45:33', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_product +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_product`; +CREATE TABLE `zz_test_flow_product` ( + `product_id` bigint(20) NOT NULL COMMENT '主键Id', + `product_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '产品名称', + `product_spec` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '规格', + `type` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '型号', + `cost_price` int(11) NOT NULL COMMENT '成本价', + `memo` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL DEFAULT '0' COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`product_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_product +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_product` VALUES (1424645586203709440, '单动薄板拉伸(冲压)液压机', '630T', '630T', 12001, '机身采用四柱整体框架或组合框架结构,均为全钢板焊接;四角八面直角导轨导向、精度高,刚性好,并采用液压预紧。', 1424545631073996884, '2021-08-08 16:15:51', 1424545631073996884, '2021-08-08 16:15:51', 1); +INSERT INTO `zz_test_flow_product` VALUES (1424645694550970368, '单动薄板拉伸液压机', '315T', 'YLL27', 143680, '机身采用四柱整体框架或组合框架结构,均为全钢板焊接;四角八面直角导轨导向、精度高,刚性好,并采用液压预紧。液压系统采用二通插装集成阀;整个系统工作稳定、可靠、使用寿命长、泄露少、故障点少。', 1424545631073996884, '2021-08-08 16:16:17', 1424545631073996884, '2021-08-08 16:16:17', 1); +INSERT INTO `zz_test_flow_product` VALUES (1424645807918813184, '单柱校正液压机', '210T', 'YLL30', 89000, '计算机优化直立式C型结构设计,刚性好。机器各部件均安装于机身内,外形整齐美观。液压系统采用手动换向阀,调速方便。具有手动和脚踏两种操作方式。机器行程、压力可在规定范围内调节。', 1424545631073996884, '2021-08-08 16:16:44', 1424545631073996884, '2021-08-08 16:16:44', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_second_party +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_second_party`; +CREATE TABLE `zz_test_flow_second_party` ( + `second_party_id` bigint(20) NOT NULL COMMENT '主键Id', + `company_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '公司名称', + `legal_person` varchar(64) COLLATE utf8mb4_bin NOT NULL COMMENT '法人', + `legal_person_id` char(18) COLLATE utf8mb4_bin NOT NULL COMMENT '法人身份证号', + `registry_address` varchar(512) COLLATE utf8mb4_bin NOT NULL COMMENT '注册地址', + `contact_info` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '联系方式', + `business_scope` varchar(4000) COLLATE utf8mb4_bin NOT NULL COMMENT '经营范围', + `memo` varchar(1024) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注', + `create_user_id` bigint(20) NOT NULL COMMENT '创建者', + `create_time` datetime NOT NULL COMMENT '创建时间', + `update_user_id` bigint(20) NOT NULL COMMENT '更新者', + `update_time` datetime NOT NULL COMMENT '最后更新时间', + `deleted_flag` int(11) NOT NULL DEFAULT '0' COMMENT '删除标记(1: 正常 -1: 已删除)', + PRIMARY KEY (`second_party_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_second_party +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_second_party` VALUES (1424645446290116608, '天津乐呵呵公司', '乐呵呵', '120106197003150043', '天津市河东区', '022-12345678', '乐呵呵乐呵呵', '乐呵呵乐呵呵', 1424545631073996884, '2021-08-08 16:15:18', 1424545631073996884, '2021-08-08 16:15:18', 1); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_submit +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_submit`; +CREATE TABLE `zz_test_flow_submit` ( + `id` bigint(20) NOT NULL COMMENT '主键Id', + `submit_name` varchar(255) COLLATE utf8mb4_bin NOT NULL COMMENT '报销名称', + `submit_kind` int(11) NOT NULL COMMENT '报销类别', + `total_amount` int(11) NOT NULL COMMENT '报销金额', + `description` varchar(512) COLLATE utf8mb4_bin NOT NULL COMMENT '报销描述', + `memo` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '备注', + `update_user_id` bigint(20) DEFAULT NULL COMMENT '修改人', + `update_time` datetime DEFAULT NULL COMMENT '修改时间', + `create_user_id` bigint(20) NOT NULL COMMENT '创建人', + `create_time` datetime NOT NULL COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_submit_kind` (`submit_kind`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_submit +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_submit` VALUES (1424636815804993536, '7月份出差报销', 1, 1200, '7月份出差报销', '出差报销', 1424545631073996884, '2021-08-08 15:41:47', 1424545631073996884, '2021-08-08 15:41:00'); +INSERT INTO `zz_test_flow_submit` VALUES (1441213876367527936, '出差报销', 1, 1200, '出差', '出差', 1440966324770574336, '2021-09-24 09:32:19', 1440966324770574336, '2021-09-24 09:32:19'); +INSERT INTO `zz_test_flow_submit` VALUES (1441312736167333888, '出差', 1, 800, '出差', NULL, 1440966324770574336, '2021-09-24 16:05:09', 1440966324770574336, '2021-09-24 16:05:09'); +INSERT INTO `zz_test_flow_submit` VALUES (1441340309442138112, '团建', 2, 500, '团建', NULL, 1440966324770574336, '2021-09-24 17:54:43', 1440966324770574336, '2021-09-24 17:54:43'); +COMMIT; + +-- ---------------------------- +-- Table structure for zz_test_flow_submit_detail +-- ---------------------------- +DROP TABLE IF EXISTS `zz_test_flow_submit_detail`; +CREATE TABLE `zz_test_flow_submit_detail` ( + `id` bigint(20) NOT NULL COMMENT '主键Id', + `submit_id` bigint(20) NOT NULL COMMENT '报销单据Id', + `expense_type` int(11) NOT NULL COMMENT '费用类型', + `expense_time` datetime NOT NULL COMMENT '发生日期', + `amount` int(11) NOT NULL COMMENT '金额', + `image_url` varchar(512) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '上传图片URL', + `description` varchar(255) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '费用描述', + PRIMARY KEY (`id`) USING BTREE, + KEY `idx_submit_id` (`submit_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; + +-- ---------------------------- +-- Records of zz_test_flow_submit_detail +-- ---------------------------- +BEGIN; +INSERT INTO `zz_test_flow_submit_detail` VALUES (1424636815809187840, 1424636815804993536, 1, '2021-07-06 00:00:00', 500, '[{\"name\":\"图片1.png\",\"filename\":\"5981b24ffaf640a590b57c462d9ff889.png\"}]', '住宿一天'); +INSERT INTO `zz_test_flow_submit_detail` VALUES (1424636815813382144, 1424636815804993536, 2, '2021-07-22 00:00:00', 700, '[{\"name\":\"logo.png\",\"filename\":\"4b63d00a0e3b420a9e86e751ba210f6a.png\"}]', '交通费用'); +INSERT INTO `zz_test_flow_submit_detail` VALUES (1441213876384305152, 1441213876367527936, 1, '2021-09-23 00:00:00', 600, '[{\"name\":\"logo.png\",\"filename\":\"38b7e4a097654ff38e176846ba005fcf.png\"}]', NULL); +INSERT INTO `zz_test_flow_submit_detail` VALUES (1441312736230248448, 1441312736167333888, 1, '2021-09-24 00:00:00', 600, '[{\"name\":\"logo.png\",\"filename\":\"1252138daaf744a3b1fdf06a07c5a173.png\"}]', '吃饭'); +INSERT INTO `zz_test_flow_submit_detail` VALUES (1441340309446332416, 1441340309442138112, 1, '2021-09-30 00:00:00', 500, '[{\"name\":\"logo.png\",\"filename\":\"f33b658b052f487c9a34af274f48dcd3.png\"}]', '团建费用'); +COMMIT; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/docker-compose.yml b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/docker-compose.yml new file mode 100644 index 00000000..94903d49 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/docker-compose.yml @@ -0,0 +1,16 @@ +version: '3.2' + +services: + + redis: + container_name: redis + build: + context: services/redis/ + args: + - REDIS_VER=4 + ports: + - "6379:6379" + volumes: + - ./services/redis/redis.conf:/usr/local/etc/redis/redis.conf:rw + - ./data/redis:/data:rw + - ./logs/redis:/var/log/:rw diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/services/redis/Dockerfile b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/services/redis/Dockerfile new file mode 100644 index 00000000..924bd9d6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/services/redis/Dockerfile @@ -0,0 +1,13 @@ +ARG REDIS_VER + +FROM redis:${REDIS_VER} + +COPY redis.conf /usr/local/etc/redis/redis.conf +CMD ["redis-server", "/usr/local/etc/redis/redis.conf"] + +# 设置时区为上海 +ENV TZ=Asia/Shanghai +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +# Ubuntu软件源选择中国的服务器 +RUN sed -i 's/archive.ubuntu.com/mirrors.ustc.edu.cn/g' /etc/apt/sources.list \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/services/redis/redis.conf b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/services/redis/redis.conf new file mode 100644 index 00000000..2eecfa5a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/docker-files/services/redis/redis.conf @@ -0,0 +1,1307 @@ +# Redis configuration file example. +# +# Note that in order to read the configuration file, Redis must be +# started with the file path as first argument: +# +# ./redis-server /path/to/redis.conf + +# Note on units: when memory size is needed, it is possible to specify +# it in the usual form of 1k 5GB 4M and so forth: +# +# 1k => 1000 bytes +# 1kb => 1024 bytes +# 1m => 1000000 bytes +# 1mb => 1024*1024 bytes +# 1g => 1000000000 bytes +# 1gb => 1024*1024*1024 bytes +# +# units are case insensitive so 1GB 1Gb 1gB are all the same. + +################################## INCLUDES ################################### + +# Include one or more other config files here. This is useful if you +# have a standard template that goes to all Redis servers but also need +# to customize a few per-server settings. Include files can include +# other files, so use this wisely. +# +# Notice option "include" won't be rewritten by command "CONFIG REWRITE" +# from admin or Redis Sentinel. Since Redis always uses the last processed +# line as value of a configuration directive, you'd better put includes +# at the beginning of this file to avoid overwriting config change at runtime. +# +# If instead you are interested in using includes to override configuration +# options, it is better to use include as the last line. +# +# include /path/to/local.conf +# include /path/to/other.conf + +################################## MODULES ##################################### + +# Load modules at startup. If the server is not able to load modules +# it will abort. It is possible to use multiple loadmodule directives. +# +# loadmodule /path/to/my_module.so +# loadmodule /path/to/other_module.so + +################################## NETWORK ##################################### + +# By default, if no "bind" configuration directive is specified, Redis listens +# for connections from all the network interfaces available on the server. +# It is possible to listen to just one or multiple selected interfaces using +# the "bind" configuration directive, followed by one or more IP addresses. +# +# Examples: +# +# bind 192.168.1.100 10.0.0.1 +# bind 127.0.0.1 ::1 +# +# ~~~ WARNING ~~~ If the computer running Redis is directly exposed to the +# internet, binding to all the interfaces is dangerous and will expose the +# instance to everybody on the internet. So by default we uncomment the +# following bind directive, that will force Redis to listen only into +# the IPv4 lookback interface address (this means Redis will be able to +# accept connections only from clients running into the same computer it +# is running). +# +# IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES +# JUST COMMENT THE FOLLOWING LINE. +# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bind 0.0.0.0 + +# Protected mode is a layer of security protection, in order to avoid that +# Redis instances left open on the internet are accessed and exploited. +# +# When protected mode is on and if: +# +# 1) The server is not binding explicitly to a set of addresses using the +# "bind" directive. +# 2) No password is configured. +# +# The server only accepts connections from clients connecting from the +# IPv4 and IPv6 loopback addresses 127.0.0.1 and ::1, and from Unix domain +# sockets. +# +# By default protected mode is enabled. You should disable it only if +# you are sure you want clients from other hosts to connect to Redis +# even if no authentication is configured, nor a specific set of interfaces +# are explicitly listed using the "bind" directive. +protected-mode yes + +# Accept connections on the specified port, default is 6379 (IANA #815344). +# If port 0 is specified Redis will not listen on a TCP socket. +port 6379 + +# TCP listen() backlog. +# +# In high requests-per-second environments you need an high backlog in order +# to avoid slow clients connections issues. Note that the Linux kernel +# will silently truncate it to the value of /proc/sys/net/core/somaxconn so +# make sure to raise both the value of somaxconn and tcp_max_syn_backlog +# in order to get the desired effect. +tcp-backlog 511 + +# Unix socket. +# +# Specify the path for the Unix socket that will be used to listen for +# incoming connections. There is no default, so Redis will not listen +# on a unix socket when not specified. +# +# unixsocket /tmp/redis.sock +# unixsocketperm 700 + +# Close the connection after a client is idle for N seconds (0 to disable) +timeout 0 + +# TCP keepalive. +# +# If non-zero, use SO_KEEPALIVE to send TCP ACKs to clients in absence +# of communication. This is useful for two reasons: +# +# 1) Detect dead peers. +# 2) Take the connection alive from the point of view of network +# equipment in the middle. +# +# On Linux, the specified value (in seconds) is the period used to send ACKs. +# Note that to close the connection the double of the time is needed. +# On other kernels the period depends on the kernel configuration. +# +# A reasonable value for this option is 300 seconds, which is the new +# Redis default starting with Redis 3.2.1. +tcp-keepalive 300 + +################################# GENERAL ##################################### + +# By default Redis does not run as a daemon. Use 'yes' if you need it. +# Note that Redis will write a pid file in /var/run/redis.pid when daemonized. +daemonize no + +# If you run Redis from upstart or systemd, Redis can interact with your +# supervision tree. Options: +# supervised no - no supervision interaction +# supervised upstart - signal upstart by putting Redis into SIGSTOP mode +# supervised systemd - signal systemd by writing READY=1 to $NOTIFY_SOCKET +# supervised auto - detect upstart or systemd method based on +# UPSTART_JOB or NOTIFY_SOCKET environment variables +# Note: these supervision methods only signal "process is ready." +# They do not enable continuous liveness pings back to your supervisor. +supervised no + +# If a pid file is specified, Redis writes it where specified at startup +# and removes it at exit. +# +# When the server runs non daemonized, no pid file is created if none is +# specified in the configuration. When the server is daemonized, the pid file +# is used even if not specified, defaulting to "/var/run/redis.pid". +# +# Creating a pid file is best effort: if Redis is not able to create it +# nothing bad happens, the server will start and run normally. +pidfile /var/run/redis_6379.pid + +# Specify the server verbosity level. +# This can be one of: +# debug (a lot of information, useful for development/testing) +# verbose (many rarely useful info, but not a mess like the debug level) +# notice (moderately verbose, what you want in production probably) +# warning (only very important / critical messages are logged) +loglevel notice + +# Specify the log file name. Also the empty string can be used to force +# Redis to log on the standard output. Note that if you use standard +# output for logging but daemonize, logs will be sent to /dev/null +logfile /var/log/redis_6379.log + +# To enable logging to the system logger, just set 'syslog-enabled' to yes, +# and optionally update the other syslog parameters to suit your needs. +# syslog-enabled no + +# Specify the syslog identity. +# syslog-ident redis + +# Specify the syslog facility. Must be USER or between LOCAL0-LOCAL7. +# syslog-facility local0 + +# Set the number of databases. The default database is DB 0, you can select +# a different one on a per-connection basis using SELECT where +# dbid is a number between 0 and 'databases'-1 +databases 16 + +# By default Redis shows an ASCII art logo only when started to log to the +# standard output and if the standard output is a TTY. Basically this means +# that normally a logo is displayed only in interactive sessions. +# +# However it is possible to force the pre-4.0 behavior and always show a +# ASCII art logo in startup logs by setting the following option to yes. +always-show-logo yes + +################################ SNAPSHOTTING ################################ +# +# Save the DB on disk: +# +# save +# +# Will save the DB if both the given number of seconds and the given +# number of write operations against the DB occurred. +# +# In the example below the behaviour will be to save: +# after 900 sec (15 min) if at least 1 key changed +# after 300 sec (5 min) if at least 10 keys changed +# after 60 sec if at least 10000 keys changed +# +# Note: you can disable saving completely by commenting out all "save" lines. +# +# It is also possible to remove all the previously configured save +# points by adding a save directive with a single empty string argument +# like in the following example: +# +# save "" + +save 900 1 +save 300 10 +save 60 10000 + +# By default Redis will stop accepting writes if RDB snapshots are enabled +# (at least one save point) and the latest background save failed. +# This will make the user aware (in a hard way) that data is not persisting +# on disk properly, otherwise chances are that no one will notice and some +# disaster will happen. +# +# If the background saving process will start working again Redis will +# automatically allow writes again. +# +# However if you have setup your proper monitoring of the Redis server +# and persistence, you may want to disable this feature so that Redis will +# continue to work as usual even if there are problems with disk, +# permissions, and so forth. +stop-writes-on-bgsave-error yes + +# Compress string objects using LZF when dump .rdb databases? +# For default that's set to 'yes' as it's almost always a win. +# If you want to save some CPU in the saving child set it to 'no' but +# the dataset will likely be bigger if you have compressible values or keys. +rdbcompression yes + +# Since version 5 of RDB a CRC64 checksum is placed at the end of the file. +# This makes the format more resistant to corruption but there is a performance +# hit to pay (around 10%) when saving and loading RDB files, so you can disable it +# for maximum performances. +# +# RDB files created with checksum disabled have a checksum of zero that will +# tell the loading code to skip the check. +rdbchecksum yes + +# The filename where to dump the DB +dbfilename dump.rdb + +# The working directory. +# +# The DB will be written inside this directory, with the filename specified +# above using the 'dbfilename' configuration directive. +# +# The Append Only File will also be created inside this directory. +# +# Note that you must specify a directory here, not a file name. +dir ./ + +################################# REPLICATION ################################# + +# Master-Slave replication. Use slaveof to make a Redis instance a copy of +# another Redis server. A few things to understand ASAP about Redis replication. +# +# 1) Redis replication is asynchronous, but you can configure a master to +# stop accepting writes if it appears to be not connected with at least +# a given number of slaves. +# 2) Redis slaves are able to perform a partial resynchronization with the +# master if the replication link is lost for a relatively small amount of +# time. You may want to configure the replication backlog size (see the next +# sections of this file) with a sensible value depending on your needs. +# 3) Replication is automatic and does not need user intervention. After a +# network partition slaves automatically try to reconnect to masters +# and resynchronize with them. +# +# slaveof + +# If the master is password protected (using the "requirepass" configuration +# directive below) it is possible to tell the slave to authenticate before +# starting the replication synchronization process, otherwise the master will +# refuse the slave request. +# +# masterauth + +# When a slave loses its connection with the master, or when the replication +# is still in progress, the slave can act in two different ways: +# +# 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will +# still reply to client requests, possibly with out of date data, or the +# data set may just be empty if this is the first synchronization. +# +# 2) if slave-serve-stale-data is set to 'no' the slave will reply with +# an error "SYNC with master in progress" to all the kind of commands +# but to INFO and SLAVEOF. +# +slave-serve-stale-data yes + +# You can configure a slave instance to accept writes or not. Writing against +# a slave instance may be useful to store some ephemeral data (because data +# written on a slave will be easily deleted after resync with the master) but +# may also cause problems if clients are writing to it because of a +# misconfiguration. +# +# Since Redis 2.6 by default slaves are read-only. +# +# Note: read only slaves are not designed to be exposed to untrusted clients +# on the internet. It's just a protection layer against misuse of the instance. +# Still a read only slave exports by default all the administrative commands +# such as CONFIG, DEBUG, and so forth. To a limited extent you can improve +# security of read only slaves using 'rename-command' to shadow all the +# administrative / dangerous commands. +slave-read-only yes + +# Replication SYNC strategy: disk or socket. +# +# ------------------------------------------------------- +# WARNING: DISKLESS REPLICATION IS EXPERIMENTAL CURRENTLY +# ------------------------------------------------------- +# +# New slaves and reconnecting slaves that are not able to continue the replication +# process just receiving differences, need to do what is called a "full +# synchronization". An RDB file is transmitted from the master to the slaves. +# The transmission can happen in two different ways: +# +# 1) Disk-backed: The Redis master creates a new process that writes the RDB +# file on disk. Later the file is transferred by the parent +# process to the slaves incrementally. +# 2) Diskless: The Redis master creates a new process that directly writes the +# RDB file to slave sockets, without touching the disk at all. +# +# With disk-backed replication, while the RDB file is generated, more slaves +# can be queued and served with the RDB file as soon as the current child producing +# the RDB file finishes its work. With diskless replication instead once +# the transfer starts, new slaves arriving will be queued and a new transfer +# will start when the current one terminates. +# +# When diskless replication is used, the master waits a configurable amount of +# time (in seconds) before starting the transfer in the hope that multiple slaves +# will arrive and the transfer can be parallelized. +# +# With slow disks and fast (large bandwidth) networks, diskless replication +# works better. +repl-diskless-sync no + +# When diskless replication is enabled, it is possible to configure the delay +# the server waits in order to spawn the child that transfers the RDB via socket +# to the slaves. +# +# This is important since once the transfer starts, it is not possible to serve +# new slaves arriving, that will be queued for the next RDB transfer, so the server +# waits a delay in order to let more slaves arrive. +# +# The delay is specified in seconds, and by default is 5 seconds. To disable +# it entirely just set it to 0 seconds and the transfer will start ASAP. +repl-diskless-sync-delay 5 + +# Slaves send PINGs to server in a predefined interval. It's possible to change +# this interval with the repl_ping_slave_period option. The default value is 10 +# seconds. +# +# repl-ping-slave-period 10 + +# The following option sets the replication timeout for: +# +# 1) Bulk transfer I/O during SYNC, from the point of view of slave. +# 2) Master timeout from the point of view of slaves (data, pings). +# 3) Slave timeout from the point of view of masters (REPLCONF ACK pings). +# +# It is important to make sure that this value is greater than the value +# specified for repl-ping-slave-period otherwise a timeout will be detected +# every time there is low traffic between the master and the slave. +# +# repl-timeout 60 + +# Disable TCP_NODELAY on the slave socket after SYNC? +# +# If you select "yes" Redis will use a smaller number of TCP packets and +# less bandwidth to send data to slaves. But this can add a delay for +# the data to appear on the slave side, up to 40 milliseconds with +# Linux kernels using a default configuration. +# +# If you select "no" the delay for data to appear on the slave side will +# be reduced but more bandwidth will be used for replication. +# +# By default we optimize for low latency, but in very high traffic conditions +# or when the master and slaves are many hops away, turning this to "yes" may +# be a good idea. +repl-disable-tcp-nodelay no + +# Set the replication backlog size. The backlog is a buffer that accumulates +# slave data when slaves are disconnected for some time, so that when a slave +# wants to reconnect again, often a full resync is not needed, but a partial +# resync is enough, just passing the portion of data the slave missed while +# disconnected. +# +# The bigger the replication backlog, the longer the time the slave can be +# disconnected and later be able to perform a partial resynchronization. +# +# The backlog is only allocated once there is at least a slave connected. +# +# repl-backlog-size 1mb + +# After a master has no longer connected slaves for some time, the backlog +# will be freed. The following option configures the amount of seconds that +# need to elapse, starting from the time the last slave disconnected, for +# the backlog buffer to be freed. +# +# Note that slaves never free the backlog for timeout, since they may be +# promoted to masters later, and should be able to correctly "partially +# resynchronize" with the slaves: hence they should always accumulate backlog. +# +# A value of 0 means to never release the backlog. +# +# repl-backlog-ttl 3600 + +# The slave priority is an integer number published by Redis in the INFO output. +# It is used by Redis Sentinel in order to select a slave to promote into a +# master if the master is no longer working correctly. +# +# A slave with a low priority number is considered better for promotion, so +# for instance if there are three slaves with priority 10, 100, 25 Sentinel will +# pick the one with priority 10, that is the lowest. +# +# However a special priority of 0 marks the slave as not able to perform the +# role of master, so a slave with priority of 0 will never be selected by +# Redis Sentinel for promotion. +# +# By default the priority is 100. +slave-priority 100 + +# It is possible for a master to stop accepting writes if there are less than +# N slaves connected, having a lag less or equal than M seconds. +# +# The N slaves need to be in "online" state. +# +# The lag in seconds, that must be <= the specified value, is calculated from +# the last ping received from the slave, that is usually sent every second. +# +# This option does not GUARANTEE that N replicas will accept the write, but +# will limit the window of exposure for lost writes in case not enough slaves +# are available, to the specified number of seconds. +# +# For example to require at least 3 slaves with a lag <= 10 seconds use: +# +# min-slaves-to-write 3 +# min-slaves-max-lag 10 +# +# Setting one or the other to 0 disables the feature. +# +# By default min-slaves-to-write is set to 0 (feature disabled) and +# min-slaves-max-lag is set to 10. + +# A Redis master is able to list the address and port of the attached +# slaves in different ways. For example the "INFO replication" section +# offers this information, which is used, among other tools, by +# Redis Sentinel in order to discover slave instances. +# Another place where this info is available is in the output of the +# "ROLE" command of a master. +# +# The listed IP and address normally reported by a slave is obtained +# in the following way: +# +# IP: The address is auto detected by checking the peer address +# of the socket used by the slave to connect with the master. +# +# Port: The port is communicated by the slave during the replication +# handshake, and is normally the port that the slave is using to +# list for connections. +# +# However when port forwarding or Network Address Translation (NAT) is +# used, the slave may be actually reachable via different IP and port +# pairs. The following two options can be used by a slave in order to +# report to its master a specific set of IP and port, so that both INFO +# and ROLE will report those values. +# +# There is no need to use both the options if you need to override just +# the port or the IP address. +# +# slave-announce-ip 5.5.5.5 +# slave-announce-port 1234 + +################################## SECURITY ################################### + +# Require clients to issue AUTH before processing any other +# commands. This might be useful in environments in which you do not trust +# others with access to the host running redis-server. +# +# This should stay commented out for backward compatibility and because most +# people do not need auth (e.g. they run their own servers). +# +# Warning: since Redis is pretty fast an outside user can try up to +# 150k passwords per second against a good box. This means that you should +# use a very strong password otherwise it will be very easy to break. +# +# requirepass foobared + +# Command renaming. +# +# It is possible to change the name of dangerous commands in a shared +# environment. For instance the CONFIG command may be renamed into something +# hard to guess so that it will still be available for internal-use tools +# but not available for general clients. +# +# Example: +# +# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52 +# +# It is also possible to completely kill a command by renaming it into +# an empty string: +# +# rename-command CONFIG "" +# +# Please note that changing the name of commands that are logged into the +# AOF file or transmitted to slaves may cause problems. + +################################### CLIENTS #################################### + +# Set the max number of connected clients at the same time. By default +# this limit is set to 10000 clients, however if the Redis server is not +# able to configure the process file limit to allow for the specified limit +# the max number of allowed clients is set to the current file limit +# minus 32 (as Redis reserves a few file descriptors for internal uses). +# +# Once the limit is reached Redis will close all the new connections sending +# an error 'max number of clients reached'. +# +# maxclients 10000 + +############################## MEMORY MANAGEMENT ################################ + +# Set a memory usage limit to the specified amount of bytes. +# When the memory limit is reached Redis will try to remove keys +# according to the eviction policy selected (see maxmemory-policy). +# +# If Redis can't remove keys according to the policy, or if the policy is +# set to 'noeviction', Redis will start to reply with errors to commands +# that would use more memory, like SET, LPUSH, and so on, and will continue +# to reply to read-only commands like GET. +# +# This option is usually useful when using Redis as an LRU or LFU cache, or to +# set a hard memory limit for an instance (using the 'noeviction' policy). +# +# WARNING: If you have slaves attached to an instance with maxmemory on, +# the size of the output buffers needed to feed the slaves are subtracted +# from the used memory count, so that network problems / resyncs will +# not trigger a loop where keys are evicted, and in turn the output +# buffer of slaves is full with DELs of keys evicted triggering the deletion +# of more keys, and so forth until the database is completely emptied. +# +# In short... if you have slaves attached it is suggested that you set a lower +# limit for maxmemory so that there is some free RAM on the system for slave +# output buffers (but this is not needed if the policy is 'noeviction'). +# +# maxmemory + +# MAXMEMORY POLICY: how Redis will select what to remove when maxmemory +# is reached. You can select among five behaviors: +# +# volatile-lru -> Evict using approximated LRU among the keys with an expire set. +# allkeys-lru -> Evict any key using approximated LRU. +# volatile-lfu -> Evict using approximated LFU among the keys with an expire set. +# allkeys-lfu -> Evict any key using approximated LFU. +# volatile-random -> Remove a random key among the ones with an expire set. +# allkeys-random -> Remove a random key, any key. +# volatile-ttl -> Remove the key with the nearest expire time (minor TTL) +# noeviction -> Don't evict anything, just return an error on write operations. +# +# LRU means Least Recently Used +# LFU means Least Frequently Used +# +# Both LRU, LFU and volatile-ttl are implemented using approximated +# randomized algorithms. +# +# Note: with any of the above policies, Redis will return an error on write +# operations, when there are no suitable keys for eviction. +# +# At the date of writing these commands are: set setnx setex append +# incr decr rpush lpush rpushx lpushx linsert lset rpoplpush sadd +# sinter sinterstore sunion sunionstore sdiff sdiffstore zadd zincrby +# zunionstore zinterstore hset hsetnx hmset hincrby incrby decrby +# getset mset msetnx exec sort +# +# The default is: +# +# maxmemory-policy noeviction + +# LRU, LFU and minimal TTL algorithms are not precise algorithms but approximated +# algorithms (in order to save memory), so you can tune it for speed or +# accuracy. For default Redis will check five keys and pick the one that was +# used less recently, you can change the sample size using the following +# configuration directive. +# +# The default of 5 produces good enough results. 10 Approximates very closely +# true LRU but costs more CPU. 3 is faster but not very accurate. +# +# maxmemory-samples 5 + +############################# LAZY FREEING #################################### + +# Redis has two primitives to delete keys. One is called DEL and is a blocking +# deletion of the object. It means that the server stops processing new commands +# in order to reclaim all the memory associated with an object in a synchronous +# way. If the key deleted is associated with a small object, the time needed +# in order to execute the DEL command is very small and comparable to most other +# O(1) or O(log_N) commands in Redis. However if the key is associated with an +# aggregated value containing millions of elements, the server can block for +# a long time (even seconds) in order to complete the operation. +# +# For the above reasons Redis also offers non blocking deletion primitives +# such as UNLINK (non blocking DEL) and the ASYNC option of FLUSHALL and +# FLUSHDB commands, in order to reclaim memory in background. Those commands +# are executed in constant time. Another thread will incrementally free the +# object in the background as fast as possible. +# +# DEL, UNLINK and ASYNC option of FLUSHALL and FLUSHDB are user-controlled. +# It's up to the design of the application to understand when it is a good +# idea to use one or the other. However the Redis server sometimes has to +# delete keys or flush the whole database as a side effect of other operations. +# Specifically Redis deletes objects independently of a user call in the +# following scenarios: +# +# 1) On eviction, because of the maxmemory and maxmemory policy configurations, +# in order to make room for new data, without going over the specified +# memory limit. +# 2) Because of expire: when a key with an associated time to live (see the +# EXPIRE command) must be deleted from memory. +# 3) Because of a side effect of a command that stores data on a key that may +# already exist. For example the RENAME command may delete the old key +# content when it is replaced with another one. Similarly SUNIONSTORE +# or SORT with STORE option may delete existing keys. The SET command +# itself removes any old content of the specified key in order to replace +# it with the specified string. +# 4) During replication, when a slave performs a full resynchronization with +# its master, the content of the whole database is removed in order to +# load the RDB file just transfered. +# +# In all the above cases the default is to delete objects in a blocking way, +# like if DEL was called. However you can configure each case specifically +# in order to instead release memory in a non-blocking way like if UNLINK +# was called, using the following configuration directives: + +lazyfree-lazy-eviction no +lazyfree-lazy-expire no +lazyfree-lazy-server-del no +slave-lazy-flush no + +############################## APPEND ONLY MODE ############################### + +# By default Redis asynchronously dumps the dataset on disk. This mode is +# good enough in many applications, but an issue with the Redis process or +# a power outage may result into a few minutes of writes lost (depending on +# the configured save points). +# +# The Append Only File is an alternative persistence mode that provides +# much better durability. For instance using the default data fsync policy +# (see later in the config file) Redis can lose just one second of writes in a +# dramatic event like a server power outage, or a single write if something +# wrong with the Redis process itself happens, but the operating system is +# still running correctly. +# +# AOF and RDB persistence can be enabled at the same time without problems. +# If the AOF is enabled on startup Redis will load the AOF, that is the file +# with the better durability guarantees. +# +# Please check http://redis.io/topics/persistence for more information. + +appendonly no + +# The name of the append only file (default: "appendonly.aof") + +appendfilename "appendonly.aof" + +# The fsync() call tells the Operating System to actually write data on disk +# instead of waiting for more data in the output buffer. Some OS will really flush +# data on disk, some other OS will just try to do it ASAP. +# +# Redis supports three different modes: +# +# no: don't fsync, just let the OS flush the data when it wants. Faster. +# always: fsync after every write to the append only log. Slow, Safest. +# everysec: fsync only one time every second. Compromise. +# +# The default is "everysec", as that's usually the right compromise between +# speed and data safety. It's up to you to understand if you can relax this to +# "no" that will let the operating system flush the output buffer when +# it wants, for better performances (but if you can live with the idea of +# some data loss consider the default persistence mode that's snapshotting), +# or on the contrary, use "always" that's very slow but a bit safer than +# everysec. +# +# More details please check the following article: +# http://antirez.com/post/redis-persistence-demystified.html +# +# If unsure, use "everysec". + +# appendfsync always +appendfsync everysec +# appendfsync no + +# When the AOF fsync policy is set to always or everysec, and a background +# saving process (a background save or AOF log background rewriting) is +# performing a lot of I/O against the disk, in some Linux configurations +# Redis may block too long on the fsync() call. Note that there is no fix for +# this currently, as even performing fsync in a different thread will block +# our synchronous write(2) call. +# +# In order to mitigate this problem it's possible to use the following option +# that will prevent fsync() from being called in the main process while a +# BGSAVE or BGREWRITEAOF is in progress. +# +# This means that while another child is saving, the durability of Redis is +# the same as "appendfsync none". In practical terms, this means that it is +# possible to lose up to 30 seconds of log in the worst scenario (with the +# default Linux settings). +# +# If you have latency problems turn this to "yes". Otherwise leave it as +# "no" that is the safest pick from the point of view of durability. + +no-appendfsync-on-rewrite no + +# Automatic rewrite of the append only file. +# Redis is able to automatically rewrite the log file implicitly calling +# BGREWRITEAOF when the AOF log size grows by the specified percentage. +# +# This is how it works: Redis remembers the size of the AOF file after the +# latest rewrite (if no rewrite has happened since the restart, the size of +# the AOF at startup is used). +# +# This base size is compared to the current size. If the current size is +# bigger than the specified percentage, the rewrite is triggered. Also +# you need to specify a minimal size for the AOF file to be rewritten, this +# is useful to avoid rewriting the AOF file even if the percentage increase +# is reached but it is still pretty small. +# +# Specify a percentage of zero in order to disable the automatic AOF +# rewrite feature. + +auto-aof-rewrite-percentage 100 +auto-aof-rewrite-min-size 64mb + +# An AOF file may be found to be truncated at the end during the Redis +# startup process, when the AOF data gets loaded back into memory. +# This may happen when the system where Redis is running +# crashes, especially when an ext4 filesystem is mounted without the +# data=ordered option (however this can't happen when Redis itself +# crashes or aborts but the operating system still works correctly). +# +# Redis can either exit with an error when this happens, or load as much +# data as possible (the default now) and start if the AOF file is found +# to be truncated at the end. The following option controls this behavior. +# +# If aof-load-truncated is set to yes, a truncated AOF file is loaded and +# the Redis server starts emitting a log to inform the user of the event. +# Otherwise if the option is set to no, the server aborts with an error +# and refuses to start. When the option is set to no, the user requires +# to fix the AOF file using the "redis-check-aof" utility before to restart +# the server. +# +# Note that if the AOF file will be found to be corrupted in the middle +# the server will still exit with an error. This option only applies when +# Redis will try to read more data from the AOF file but not enough bytes +# will be found. +aof-load-truncated yes + +# When rewriting the AOF file, Redis is able to use an RDB preamble in the +# AOF file for faster rewrites and recoveries. When this option is turned +# on the rewritten AOF file is composed of two different stanzas: +# +# [RDB file][AOF tail] +# +# When loading Redis recognizes that the AOF file starts with the "REDIS" +# string and loads the prefixed RDB file, and continues loading the AOF +# tail. +# +# This is currently turned off by default in order to avoid the surprise +# of a format change, but will at some point be used as the default. +aof-use-rdb-preamble no + +################################ LUA SCRIPTING ############################### + +# Max execution time of a Lua script in milliseconds. +# +# If the maximum execution time is reached Redis will log that a script is +# still in execution after the maximum allowed time and will start to +# reply to queries with an error. +# +# When a long running script exceeds the maximum execution time only the +# SCRIPT KILL and SHUTDOWN NOSAVE commands are available. The first can be +# used to stop a script that did not yet called write commands. The second +# is the only way to shut down the server in the case a write command was +# already issued by the script but the user doesn't want to wait for the natural +# termination of the script. +# +# Set it to 0 or a negative value for unlimited execution without warnings. +lua-time-limit 5000 + +################################ REDIS CLUSTER ############################### +# +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# WARNING EXPERIMENTAL: Redis Cluster is considered to be stable code, however +# in order to mark it as "mature" we need to wait for a non trivial percentage +# of users to deploy it in production. +# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +# +# Normal Redis instances can't be part of a Redis Cluster; only nodes that are +# started as cluster nodes can. In order to start a Redis instance as a +# cluster node enable the cluster support uncommenting the following: +# +# cluster-enabled yes + +# Every cluster node has a cluster configuration file. This file is not +# intended to be edited by hand. It is created and updated by Redis nodes. +# Every Redis Cluster node requires a different cluster configuration file. +# Make sure that instances running in the same system do not have +# overlapping cluster configuration file names. +# +# cluster-config-file nodes-6379.conf + +# Cluster node timeout is the amount of milliseconds a node must be unreachable +# for it to be considered in failure state. +# Most other internal time limits are multiple of the node timeout. +# +# cluster-node-timeout 15000 + +# A slave of a failing master will avoid to start a failover if its data +# looks too old. +# +# There is no simple way for a slave to actually have an exact measure of +# its "data age", so the following two checks are performed: +# +# 1) If there are multiple slaves able to failover, they exchange messages +# in order to try to give an advantage to the slave with the best +# replication offset (more data from the master processed). +# Slaves will try to get their rank by offset, and apply to the start +# of the failover a delay proportional to their rank. +# +# 2) Every single slave computes the time of the last interaction with +# its master. This can be the last ping or command received (if the master +# is still in the "connected" state), or the time that elapsed since the +# disconnection with the master (if the replication link is currently down). +# If the last interaction is too old, the slave will not try to failover +# at all. +# +# The point "2" can be tuned by user. Specifically a slave will not perform +# the failover if, since the last interaction with the master, the time +# elapsed is greater than: +# +# (node-timeout * slave-validity-factor) + repl-ping-slave-period +# +# So for example if node-timeout is 30 seconds, and the slave-validity-factor +# is 10, and assuming a default repl-ping-slave-period of 10 seconds, the +# slave will not try to failover if it was not able to talk with the master +# for longer than 310 seconds. +# +# A large slave-validity-factor may allow slaves with too old data to failover +# a master, while a too small value may prevent the cluster from being able to +# elect a slave at all. +# +# For maximum availability, it is possible to set the slave-validity-factor +# to a value of 0, which means, that slaves will always try to failover the +# master regardless of the last time they interacted with the master. +# (However they'll always try to apply a delay proportional to their +# offset rank). +# +# Zero is the only value able to guarantee that when all the partitions heal +# the cluster will always be able to continue. +# +# cluster-slave-validity-factor 10 + +# Cluster slaves are able to migrate to orphaned masters, that are masters +# that are left without working slaves. This improves the cluster ability +# to resist to failures as otherwise an orphaned master can't be failed over +# in case of failure if it has no working slaves. +# +# Slaves migrate to orphaned masters only if there are still at least a +# given number of other working slaves for their old master. This number +# is the "migration barrier". A migration barrier of 1 means that a slave +# will migrate only if there is at least 1 other working slave for its master +# and so forth. It usually reflects the number of slaves you want for every +# master in your cluster. +# +# Default is 1 (slaves migrate only if their masters remain with at least +# one slave). To disable migration just set it to a very large value. +# A value of 0 can be set but is useful only for debugging and dangerous +# in production. +# +# cluster-migration-barrier 1 + +# By default Redis Cluster nodes stop accepting queries if they detect there +# is at least an hash slot uncovered (no available node is serving it). +# This way if the cluster is partially down (for example a range of hash slots +# are no longer covered) all the cluster becomes, eventually, unavailable. +# It automatically returns available as soon as all the slots are covered again. +# +# However sometimes you want the subset of the cluster which is working, +# to continue to accept queries for the part of the key space that is still +# covered. In order to do so, just set the cluster-require-full-coverage +# option to no. +# +# cluster-require-full-coverage yes + +# In order to setup your cluster make sure to read the documentation +# available at http://redis.io web site. + +########################## CLUSTER DOCKER/NAT support ######################## + +# In certain deployments, Redis Cluster nodes address discovery fails, because +# addresses are NAT-ted or because ports are forwarded (the typical case is +# Docker and other containers). +# +# In order to make Redis Cluster working in such environments, a static +# configuration where each node knows its public address is needed. The +# following two options are used for this scope, and are: +# +# * cluster-announce-ip +# * cluster-announce-port +# * cluster-announce-bus-port +# +# Each instruct the node about its address, client port, and cluster message +# bus port. The information is then published in the header of the bus packets +# so that other nodes will be able to correctly map the address of the node +# publishing the information. +# +# If the above options are not used, the normal Redis Cluster auto-detection +# will be used instead. +# +# Note that when remapped, the bus port may not be at the fixed offset of +# clients port + 10000, so you can specify any port and bus-port depending +# on how they get remapped. If the bus-port is not set, a fixed offset of +# 10000 will be used as usually. +# +# Example: +# +# cluster-announce-ip 10.1.1.5 +# cluster-announce-port 6379 +# cluster-announce-bus-port 6380 + +################################## SLOW LOG ################################### + +# The Redis Slow Log is a system to log queries that exceeded a specified +# execution time. The execution time does not include the I/O operations +# like talking with the client, sending the reply and so forth, +# but just the time needed to actually execute the command (this is the only +# stage of command execution where the thread is blocked and can not serve +# other requests in the meantime). +# +# You can configure the slow log with two parameters: one tells Redis +# what is the execution time, in microseconds, to exceed in order for the +# command to get logged, and the other parameter is the length of the +# slow log. When a new command is logged the oldest one is removed from the +# queue of logged commands. + +# The following time is expressed in microseconds, so 1000000 is equivalent +# to one second. Note that a negative number disables the slow log, while +# a value of zero forces the logging of every command. +slowlog-log-slower-than 10000 + +# There is no limit to this length. Just be aware that it will consume memory. +# You can reclaim memory used by the slow log with SLOWLOG RESET. +slowlog-max-len 128 + +################################ LATENCY MONITOR ############################## + +# The Redis latency monitoring subsystem samples different operations +# at runtime in order to collect data related to possible sources of +# latency of a Redis instance. +# +# Via the LATENCY command this information is available to the user that can +# print graphs and obtain reports. +# +# The system only logs operations that were performed in a time equal or +# greater than the amount of milliseconds specified via the +# latency-monitor-threshold configuration directive. When its value is set +# to zero, the latency monitor is turned off. +# +# By default latency monitoring is disabled since it is mostly not needed +# if you don't have latency issues, and collecting data has a performance +# impact, that while very small, can be measured under big load. Latency +# monitoring can easily be enabled at runtime using the command +# "CONFIG SET latency-monitor-threshold " if needed. +latency-monitor-threshold 0 + +############################# EVENT NOTIFICATION ############################## + +# Redis can notify Pub/Sub clients about events happening in the key space. +# This feature is documented at http://redis.io/topics/notifications +# +# For instance if keyspace events notification is enabled, and a client +# performs a DEL operation on key "foo" stored in the Database 0, two +# messages will be published via Pub/Sub: +# +# PUBLISH __keyspace@0__:foo del +# PUBLISH __keyevent@0__:del foo +# +# It is possible to select the events that Redis will notify among a set +# of classes. Every class is identified by a single character: +# +# K Keyspace events, published with __keyspace@__ prefix. +# E Keyevent events, published with __keyevent@__ prefix. +# g Generic commands (non-type specific) like DEL, EXPIRE, RENAME, ... +# $ String commands +# l List commands +# s Set commands +# h Hash commands +# z Sorted set commands +# x Expired events (events generated every time a key expires) +# e Evicted events (events generated when a key is evicted for maxmemory) +# A Alias for g$lshzxe, so that the "AKE" string means all the events. +# +# The "notify-keyspace-events" takes as argument a string that is composed +# of zero or multiple characters. The empty string means that notifications +# are disabled. +# +# Example: to enable list and generic events, from the point of view of the +# event name, use: +# +# notify-keyspace-events Elg +# +# Example 2: to get the stream of the expired keys subscribing to channel +# name __keyevent@0__:expired use: +# +# notify-keyspace-events Ex +# +# By default all notifications are disabled because most users don't need +# this feature and the feature has some overhead. Note that if you don't +# specify at least one of K or E, no events will be delivered. +notify-keyspace-events "" + +############################### ADVANCED CONFIG ############################### + +# Hashes are encoded using a memory efficient data structure when they have a +# small number of entries, and the biggest entry does not exceed a given +# threshold. These thresholds can be configured using the following directives. +hash-max-ziplist-entries 512 +hash-max-ziplist-value 64 + +# Lists are also encoded in a special way to save a lot of space. +# The number of entries allowed per internal list node can be specified +# as a fixed maximum size or a maximum number of elements. +# For a fixed maximum size, use -5 through -1, meaning: +# -5: max size: 64 Kb <-- not recommended for normal workloads +# -4: max size: 32 Kb <-- not recommended +# -3: max size: 16 Kb <-- probably not recommended +# -2: max size: 8 Kb <-- good +# -1: max size: 4 Kb <-- good +# Positive numbers mean store up to _exactly_ that number of elements +# per list node. +# The highest performing option is usually -2 (8 Kb size) or -1 (4 Kb size), +# but if your use case is unique, adjust the settings as necessary. +list-max-ziplist-size -2 + +# Lists may also be compressed. +# Compress depth is the number of quicklist ziplist nodes from *each* side of +# the list to *exclude* from compression. The head and tail of the list +# are always uncompressed for fast push/pop operations. Settings are: +# 0: disable all list compression +# 1: depth 1 means "don't start compressing until after 1 node into the list, +# going from either the head or tail" +# So: [head]->node->node->...->node->[tail] +# [head], [tail] will always be uncompressed; inner nodes will compress. +# 2: [head]->[next]->node->node->...->node->[prev]->[tail] +# 2 here means: don't compress head or head->next or tail->prev or tail, +# but compress all nodes between them. +# 3: [head]->[next]->[next]->node->node->...->node->[prev]->[prev]->[tail] +# etc. +list-compress-depth 0 + +# Sets have a special encoding in just one case: when a set is composed +# of just strings that happen to be integers in radix 10 in the range +# of 64 bit signed integers. +# The following configuration setting sets the limit in the size of the +# set in order to use this special memory saving encoding. +set-max-intset-entries 512 + +# Similarly to hashes and lists, sorted sets are also specially encoded in +# order to save a lot of space. This encoding is only used when the length and +# elements of a sorted set are below the following limits: +zset-max-ziplist-entries 128 +zset-max-ziplist-value 64 + +# HyperLogLog sparse representation bytes limit. The limit includes the +# 16 bytes header. When an HyperLogLog using the sparse representation crosses +# this limit, it is converted into the dense representation. +# +# A value greater than 16000 is totally useless, since at that point the +# dense representation is more memory efficient. +# +# The suggested value is ~ 3000 in order to have the benefits of +# the space efficient encoding without slowing down too much PFADD, +# which is O(N) with the sparse encoding. The value can be raised to +# ~ 10000 when CPU is not a concern, but space is, and the data set is +# composed of many HyperLogLogs with cardinality in the 0 - 15000 range. +hll-sparse-max-bytes 3000 + +# Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in +# order to help rehashing the main Redis hash table (the one mapping top-level +# keys to values). The hash table implementation Redis uses (see dict.c) +# performs a lazy rehashing: the more operation you run into a hash table +# that is rehashing, the more rehashing "steps" are performed, so if the +# server is idle the rehashing is never complete and some more memory is used +# by the hash table. +# +# The default is to use this millisecond 10 times every second in order to +# actively rehash the main dictionaries, freeing memory when possible. +# +# If unsure: +# use "activerehashing no" if you have hard latency requirements and it is +# not a good thing in your environment that Redis can reply from time to time +# to queries with 2 milliseconds delay. +# +# use "activerehashing yes" if you don't have such hard requirements but +# want to free memory asap when possible. +activerehashing yes + +# The client output buffer limits can be used to force disconnection of clients +# that are not reading data from the server fast enough for some reason (a +# common reason is that a Pub/Sub client can't consume messages as fast as the +# publisher can produce them). +# +# The limit can be set differently for the three different classes of clients: +# +# normal -> normal clients including MONITOR clients +# slave -> slave clients +# pubsub -> clients subscribed to at least one pubsub channel or pattern +# +# The syntax of every client-output-buffer-limit directive is the following: +# +# client-output-buffer-limit +# +# A client is immediately disconnected once the hard limit is reached, or if +# the soft limit is reached and remains reached for the specified number of +# seconds (continuously). +# So for instance if the hard limit is 32 megabytes and the soft limit is +# 16 megabytes / 10 seconds, the client will get disconnected immediately +# if the size of the output buffers reach 32 megabytes, but will also get +# disconnected if the client reaches 16 megabytes and continuously overcomes +# the limit for 10 seconds. +# +# By default normal clients are not limited because they don't receive data +# without asking (in a push way), but just after a request, so only +# asynchronous clients may create a scenario where data is requested faster +# than it can read. +# +# Instead there is a default limit for pubsub and slave clients, since +# subscribers and slaves receive data in a push fashion. +# +# Both the hard or the soft limit can be disabled by setting them to zero. +client-output-buffer-limit normal 0 0 0 +client-output-buffer-limit slave 256mb 64mb 60 +client-output-buffer-limit pubsub 32mb 8mb 60 + +# Client query buffers accumulate new commands. They are limited to a fixed +# amount by default in order to avoid that a protocol desynchronization (for +# instance due to a bug in the client) will lead to unbound memory usage in +# the query buffer. However you can configure it here if you have very special +# needs, such us huge multi/exec requests or alike. +# +# client-query-buffer-limit 1gb + +# In the Redis protocol, bulk requests, that are, elements representing single +# strings, are normally limited ot 512 mb. However you can change this limit +# here. +# +# proto-max-bulk-len 512mb + +# Redis calls an internal function to perform many background tasks, like +# closing connections of clients in timeout, purging expired keys that are +# never requested, and so forth. +# +# Not all tasks are performed with the same frequency, but Redis checks for +# tasks to perform according to the specified "hz" value. +# +# By default "hz" is set to 10. Raising the value will use more CPU when +# Redis is idle, but at the same time will make Redis more responsive when +# there are many keys expiring at the same time, and timeouts may be +# handled with more precision. +# +# The range is between 1 and 500, however a value over 100 is usually not +# a good idea. Most users should use the default of 10 and raise this up to +# 100 only in environments where very low latency is required. +hz 10 + +# When a child rewrites the AOF file, if the following option is enabled +# the file will be fsync-ed every 32 MB of data generated. This is useful +# in order to commit the file to the disk more incrementally and avoid +# big latency spikes. +aof-rewrite-incremental-fsync yes + +# Redis LFU eviction (see maxmemory setting) can be tuned. However it is a good +# idea to start with the default settings and only change them after investigating +# how to improve the performances and how the keys LFU change over time, which +# is possible to inspect via the OBJECT FREQ command. +# +# There are two tunable parameters in the Redis LFU implementation: the +# counter logarithm factor and the counter decay time. It is important to +# understand what the two parameters mean before changing them. +# +# The LFU counter is just 8 bits per key, it's maximum value is 255, so Redis +# uses a probabilistic increment with logarithmic behavior. Given the value +# of the old counter, when a key is accessed, the counter is incremented in +# this way: +# +# 1. A random number R between 0 and 1 is extracted. +# 2. A probability P is calculated as 1/(old_value*lfu_log_factor+1). +# 3. The counter is incremented only if R < P. +# +# The default lfu-log-factor is 10. This is a table of how the frequency +# counter changes with a different number of accesses with different +# logarithmic factors: +# +# +--------+------------+------------+------------+------------+------------+ +# | factor | 100 hits | 1000 hits | 100K hits | 1M hits | 10M hits | +# +--------+------------+------------+------------+------------+------------+ +# | 0 | 104 | 255 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 1 | 18 | 49 | 255 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 10 | 10 | 18 | 142 | 255 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# | 100 | 8 | 11 | 49 | 143 | 255 | +# +--------+------------+------------+------------+------------+------------+ +# +# NOTE: The above table was obtained by running the following commands: +# +# redis-benchmark -n 1000000 incr foo +# redis-cli object freq foo +# +# NOTE 2: The counter initial value is 5 in order to give new objects a chance +# to accumulate hits. +# +# The counter decay time is the time, in minutes, that must elapse in order +# for the key counter to be divided by two (or decremented if it has a value +# less <= 10). +# +# The default value for the lfu-decay-time is 1. A Special value of 0 means to +# decay the counter every time it happens to be scanned. +# +# lfu-log-factor 10 +# lfu-decay-time 1 + +########################### ACTIVE DEFRAGMENTATION ####################### +# +# WARNING THIS FEATURE IS EXPERIMENTAL. However it was stress tested +# even in production and manually tested by multiple engineers for some +# time. +# +# What is active defragmentation? +# ------------------------------- +# +# Active (online) defragmentation allows a Redis server to compact the +# spaces left between small allocations and deallocations of data in memory, +# thus allowing to reclaim back memory. +# +# Fragmentation is a natural process that happens with every allocator (but +# less so with Jemalloc, fortunately) and certain workloads. Normally a server +# restart is needed in order to lower the fragmentation, or at least to flush +# away all the data and create it again. However thanks to this feature +# implemented by Oran Agra for Redis 4.0 this process can happen at runtime +# in an "hot" way, while the server is running. +# +# Basically when the fragmentation is over a certain level (see the +# configuration options below) Redis will start to create new copies of the +# values in contiguous memory regions by exploiting certain specific Jemalloc +# features (in order to understand if an allocation is causing fragmentation +# and to allocate it in a better place), and at the same time, will release the +# old copies of the data. This process, repeated incrementally for all the keys +# will cause the fragmentation to drop back to normal values. +# +# Important things to understand: +# +# 1. This feature is disabled by default, and only works if you compiled Redis +# to use the copy of Jemalloc we ship with the source code of Redis. +# This is the default with Linux builds. +# +# 2. You never need to enable this feature if you don't have fragmentation +# issues. +# +# 3. Once you experience fragmentation, you can enable this feature when +# needed with the command "CONFIG SET activedefrag yes". +# +# The configuration parameters are able to fine tune the behavior of the +# defragmentation process. If you are not sure about what they mean it is +# a good idea to leave the defaults untouched. + +# Enabled active defragmentation +# activedefrag yes + +# Minimum amount of fragmentation waste to start active defrag +# active-defrag-ignore-bytes 100mb + +# Minimum percentage of fragmentation to start active defrag +# active-defrag-threshold-lower 10 + +# Maximum percentage of fragmentation at which we use maximum effort +# active-defrag-threshold-upper 100 + +# Minimal effort for defrag in CPU percentage +# active-defrag-cycle-min 25 + +# Maximal effort for defrag in CPU percentage +# active-defrag-cycle-max 75 + diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/attachment/21344f62d80b417d8e25343ffe976f7f.png b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/attachment/21344f62d80b417d8e25343ffe976f7f.png new file mode 100644 index 0000000000000000000000000000000000000000..6775c929720f0766a1093b22e0e35ff586f5d2cb GIT binary patch literal 27185 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�nSXn)Ro?G4KnjdWo;8?t*JOlscH5#U@( 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 literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/attachment/d9aa27ea7eec4375b123e11ce92ec9b5.png b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/attachment/d9aa27ea7eec4375b123e11ce92ec9b5.png new file mode 100644 index 0000000000000000000000000000000000000000..6775c929720f0766a1093b22e0e35ff586f5d2cb GIT binary patch literal 27185 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�nSXn)Ro?G4KnjdWo;8?t*JOlscH5#U@( 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 literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/attachment/dcd2db9b75664251a3baf595f6752d90.png b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/attachment/dcd2db9b75664251a3baf595f6752d90.png new file mode 100644 index 0000000000000000000000000000000000000000..6775c929720f0766a1093b22e0e35ff586f5d2cb GIT binary patch literal 27185 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�nSXn)Ro?G4KnjdWo;8?t*JOlscH5#U@( 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 literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/security_attachment/0c20b1c7256148018451852ddae9f8aa.png b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/security_attachment/0c20b1c7256148018451852ddae9f8aa.png new file mode 100644 index 0000000000000000000000000000000000000000..6775c929720f0766a1093b22e0e35ff586f5d2cb GIT binary patch literal 27185 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�nSXn)Ro?G4KnjdWo;8?t*JOlscH5#U@( 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 literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/security_attachment/861726471ed54fee96f8c16d3e76550e.png b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/security_attachment/861726471ed54fee96f8c16d3e76550e.png new file mode 100644 index 0000000000000000000000000000000000000000..6775c929720f0766a1093b22e0e35ff586f5d2cb GIT binary patch literal 27185 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�nSXn)Ro?G4KnjdWo;8?t*JOlscH5#U@( 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 literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/security_attachment/e85a5b89d3bd4a3f94d58b0630afc7af.png b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/attachment/ZzTestFlowContract/security_attachment/e85a5b89d3bd4a3f94d58b0630afc7af.png new file mode 100644 index 0000000000000000000000000000000000000000..6775c929720f0766a1093b22e0e35ff586f5d2cb GIT binary patch literal 27185 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�nSXn)Ro?G4KnjdWo;8?t*JOlscH5#U@( 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 literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/image/ZzTestFlowSubmitDetail/image_url/1252138daaf744a3b1fdf06a07c5a173.png b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/image/ZzTestFlowSubmitDetail/image_url/1252138daaf744a3b1fdf06a07c5a173.png new file mode 100644 index 0000000000000000000000000000000000000000..f2df5bb8023bc0ad62ecb69d3958e000d8198ea9 GIT binary patch literal 9808 zcmV-WCa>9vP)Rs>p5P=;1%8$!2n zWRzJZ6;Ncb4H%FlgqRp0$dn0Qk~iG>OjWhl>Obn7JDzigmq*t3?eCsjReSHX*WR_( z+H2S)?(7Y&gX15YgSjSxp!q5@Pd(1U*ALPCdY#$RkF(O7Wa9WLMYBe)UPB5&6x;z3 z(1dz-743ED9X_2_8dz9dCRG7}*v`&sK4|6c*3-N6|D%3ysrxy=nK*|KnE|f>4FJcx zg7k3~5RN;3gl@PoyI1#{I$<|;u4>(oOqSnw7h+)?n3<%V8;xVPQ`Ty98Vy2ppz6CS zO4jd^cDu9>O)_0uV*b`yvIiE-o_(D8f0)CXH4sQ{>T%$y$Km07BVV#dGM_RKcf@V@ zZzlL-T=d6*`{`u)fbPGy&O#k&I1Cqo!1_PKOENw9an9g>Xc_r;>$nSH(!TF5*Wz*= z;+F!K0=c*$dtP0q4(?P!3lKxdNV12QMez&mJbyw6;hbu@0|rtXOv1^~!a!0-a4^mS zISY772;qOU+ufT=!ly0CK4coM0NST$SbKsyjnIM|CYI0cr`gYtW)Ii0Bmy#^@ejCn ziP7$=*o)f}lP?zcuc+AvLEZ%%y%P|)QwV)F@KSgG8St}ZjU5Pg28o9-oX`Q=I$x0U z5iY|0qaYUp-}^!KucyArwRgTH@H%&{0e&6)>{H*@9frFgyac!wcpWhFgX-wi6Iv8^ z`2{z<(uG$8vv;JqisOz))7|kqEZlq+_g6c9g$vKVgN==ZQ^q<}jbQOEtF5UwAv{wf zoD^^HwR$~Ajt1hbBDPR^x+>6id}*MBOgr96l61n&W}?M2MC7mtbr`6W`vft&XOX1u zDJIgV1uI{wYPX!k2u8xGA+$K1ZtJHlCV$~7rwPt})dq)BoXaKH7eTJ^$hV?|TUvCF z2I;eC2MH24)iHCL%{s9kS?RV9Ckc14sOLIzpAh^ZZhoN)&Hc@{;3_}s7A|aeniq-q zNA^{H44gcn4QPO*9@O}s{chtGssq((HxRJ4qIF+Hxe|--5w|ZP=`94$-G)1eA?p}V zstv5;C~(xHTon;Q;;6^FI`RmY@Lcc*0|)jpG{LbLPV1G;54*@8N@A~~fng^vzE7Ia z+BD*~!)$ph`H-geSkZl~;K&X2`*z-0e!u<^?}h7q<4Se#Qjm2Pvg72*R_#SLajYA` zZ&cCuy4!sXdxjv-1p_URpM?d+0`l_W}DRw20tlKkPmI2g{QC zX=b~!V~ug4mglc@eq2l`f-P#rmyu5dbf5FiQ?pLkZJD~+s;$6zJ{D_Fm?DonDz6$&rBF{$T zTc%sPa?Aq(qm{Oq%vMRHsC4H2D=pjmcPA1sWUM$f6kNV3&M&(2E5Pz@Dyg6|rPxOi zJ7+&Q?pYX?k{&iqKdWN**zH+Yxx$QJ6|-w(%v4$$2qEV{x`>3hiLjD52=@h^0G!6& z7Q{U8IpB&-{g_i?s4^h=2z&t%-X^77Y3gs4z(aN-q7v_3wrZa$Tj?VcisO60jfBtc za5q3_sY$mxffw@LI1%o(2Vw95;FnyaJB~UoO1f0g&=U|?-=qkHv}EbBnKvYTdy%Nm z?ClM8a6yD_NaA0+^I~@|7&L1b7C}@{Vf6YI@W{X8{^KZb2l<6@y@@$-M$cRN>cRK= zcgrU=yKS1w-D)gjAmO$h@J}HgQ~E3Q|Cuz4$7^jT!RO%eZV{fhD{U0|mo4>b_d}W;0E)@XU~o? zdrJsA58RP=0x#Q9j`)B#hycnO3)<*KaXHUnddJT82xjGjMPxLg#c|hNWtqUsfCCP{ zH13%YBfVPVt?fgNFRyy*$hg;V2Vp3JjhCTh!>$zEFofqIdRN^hEMr6B3|M(-gUED2es z*}4>X*tXm5YhIF#zej@0{M_N&&Li_00wrUnSOE9!|qUM z!fbmULSVTyg~pPg0#vfdgD^e6Ks&T3YqhFU0+I^ie8kP3F}8R2MaS<0n-yo>5Ir({ z_g}sK%<{;45nGb1Ch5CS@wcm z8yh)L-r-w}(rfLiK*Fv%^bkxGiXPL)7V%`zVDuYTW~cvmr_p+Sh~v~=c|Pz4hZDmq zNn9JJqwu_-GCOwLD|`#F|Fw}g?Knl-Ckaw+cxHtZ1MIhC<} zTSSm}wWj80W~onh*(S6ET>PyPdF0+mQaKkwQM^<7`Rb-!y*m<}vYz59yDS1`fhKUf znib+saASFDntrW8C@U9(1udkEZvy^wBrX8xa}OUpc1e;I1qMmCR;%u$>BE%~dg73M z7xI1Y%X=#oKSLXiqv(Lax^qCp-+;@n6p||f>iU)F@-`9wi*3!ifh%Rw03w^2yQ9X( z-MJNEr2e@TEQDfq;l%rrm3)00=0E~533O?)Ix&TAWmOeC1b9C17^>KgZ*=R8x5W_N zQ{f4{dPdSSq$f}~;=G$0zb&bsHR=sf@dxC2_G3k<|AIr3o_kLK78jR(-g-Hz+h;s3 z1zJD4@|Vqrtgcq05*9x?M_d$0t6oI>{qFwcEeq!SAa?%h>cnF$CjUj%j&C$^i92fG zCWy&~S6V<=Li~dWzp*=+g;19NwAyNXP3rY^{_GHIDK+b(y)A?=!^IKd6)OIF?(0?` zaX;K^wJyZ{K4Sc~xIhP{AGt#PUY%k4tL-mOytRG#5gD)`)nm z#OozqDr>02U zFtf8=!n*|?y-n-cim}N@foCE>DOfM5v=>0?23hfGB2O4o-7VVVf&Zr&kwpB*cM`;2 z`g<+S@rj%;*&(!Y+!QMnaleFfZBN=SQ>;h7;dM+zUt zAw1sPKPdYMW;Caz>W>3?_W&P4o}q&vA6L6H&w4#!v}Ip}^Q{+9J;doA_5S0POaF2V z;Z_SNmIZ1Da7Rm8s~ge0s*(nuNUWUbeC8;wgsj3*T^B*-HKIVcFhm6!;5X5^_+q?D#|*|>#j zE8&dkr_A3YS-EuT9?}|3C=thExH^^zod(4xjffKsmgko!#lVFi90?)$bBC9&)$1zB>G?k#`03@(BcQ2s{8Lku$CRYLhEJl% zyS$WV-ND3yLjiw^VDEv-Op+&+vhD)n{uQy&b{=UN?av>$ds5t7yO*?#QO<35Dbmbt zNV6O-h3o-+I*myHtgG~Isy#l$a(l&nLWuF)_Qd38B*f=vVV{mk%0ylg`aKqBX3!XM z{P*4c$3ZR-5v=4GHGfI^LpcB|*G$m4rB35OrLnkknhNhhc>EnkunK#80`6;s&dQB} zXx!)`1tZ+Ek~!TQvU?`f<2mD^B;Ea1GrI|?qCaOJwL~&gskP-&a&GS}r#)KIJL*VX zgE^1k?-Bb|fw!9|t(6{Ay2SGIG+vfV&3gR_?*5y3Kh{*_&n@~5085umGyj=cbh1B) zaMB+``~$!_dzR8Wf`jN2a!(E!avUIFWU^*;zsX&0^D2#GGZ=)Xos)>jnIoHa2&%W$ z((E`6J_E~tH;0Q=vOUU$+KjbRFp7(Q$c~Q0(j?ObQ;Ta`q3#cMH&)DWb9wiJ;V!Ucbo@T$hICtn1Kn_rf zP>bt)Q8K5vJzyr(XZyI3;Ni_~Ve*u4i&5Zmcc-!m1dN$vmErCqh^>wyGJuHBBuJI= z3!7J@2w04(Ww|cwR6-T$Q~i5nPtpA+0pd<9lXJ=#Ca7ZSu%bZfQY9%N0O|LPQqQw0|OKT2W6KmZrQMvUHVP_;bHd#(a(q%n?hP{M_!Rh*I|o!bWUey;GlfP^_gKojYxCLIM~v-l6T@Pe3}OI;hmUFrnG{ zb{5Uhevh&!P_0Z9We6WkqJ0QB3#d^w)&siWeUKh&+aV!I3bHh((`k+Hp9&_5TS<8| zrTg_Jov$`vC6ENL%+Y3_nfZCNW7GK0Tph`rjOG!<7EHaDK zBI34gy_Gc#Dk6>xssk{g)m^6DnqUXcxv82Ldw4EF*-Y@Ja*%~8Gl4brZg!k{hs%k? z;mD}lB4B2xcY3`;0vpl?`iKaL>X^aqFdnZARjLN=xF{2=3v?!0cv536)va2JX9GV1 z90C4q6Jp!pyusgZKxLUoihR(aS0=DQ0J@nI!v56~!9k$gY@rFHWzGgA;IJd7kFV_C zQ}5_aVB&7g<#~pj83OTqQ$ss=Xfc9A;{$je=l&k zATJs=qh(q70AsbW5s^OvuE4oG;Qu7TGb+MVP`wNlk+UqL*{Wlux_|n)3f{E^nA>Y#z{@}Zbhn;$;J{W(_|z++6dX1Ig&WhjAlKfUayh& zgd(r8HFZwKLT=eh+HvyB8vVt<&<2y4`)^0{1EoXK>yy`N z*hf_S<9SxQ&&KxMoscACS&ExO8JL({W*B6z&GE)Dai>UAP8>Qw5riU<%H^6W{Y)uU z&%sAWc6%w*@7n*CPCaJ%JJuP!q+J}a2Z>oF5Z6kqiu;zC9R`6^uKeaBI+YCqtArT> zL)NjzbRBUXEATJwa&biGwn;J9Ib08Fbe0;E+&(kM(V02sCue?mqu*~>%SE2rZcTl~ zMPG}r>(WEkF~n503OkaX)BQ?wti3=ivf6CX%bFxbL`z2oMN3DF^T*kEysfkzwfJ3K z{^ZPe!-S1V84|?&;YqZRn6aruBVdHJXn;yUsg;B>2OP`SS;q(k5;dD^Pfq=D49Ta( zcvuzAvHeLApBM2}5E@yJR@$bSbZBUAaWvi_ZViFoMfA%K&m8rP4>AHgSMskn32NIi ztHcHIKvD>`9FkH=N+lhZLK1a<Z_ zN<>No=2s5T>m{JzCO5gn>jk;*_!cS%5?;{nh4#&SCf(iC}WE&3-y#+uZ#&|fEHXpEZZsY!)Z*RS4tAW)|wknEk zL0aq8Kvd*sdwKpEcfYT0%L(5Z9F`L7%9Kht2XT^GCE!JbqV%hZJU)LfhW_1>6#M=tirb3Pde{ot-9|@!b+2pPvvW=JLT!zRy;CJE${QvZ<}U+Kf z^m;jE8UIZ-hJx+2RUpr6|J6;e0D0CZLc0l4i|AxAvUn1o<#9aQFqcnKP*8xh|DZBj zc_NSMOip}m$>fwg1U=;)x~!`3}A;o04`Cr|GtUf>Ud8nd%kW4@QS5~$b@9}AEcZ)iha8a6O$_! zO6r&4kTi?cDiEFIOKq9BPJBd+w1XsmrX>EHp#Enn8&4w;iZb0qOIOYi_=INhtdk%7 zuyy;wrnz@RJ!Jy|J(u`3;0_SlariZJX{*R9H`+`jbFwViBn!<9bALWMn#cppug%i_ zhz?1@(((DM+v)yh(9wPqcP9jY z*XrtAv1Vb`2vrfp+$di0qRLUZ>Cx?0{gVI-`bAgCH(hi{wu`>6f*b`ud`J6qd~W!5 zx;kYnSY2Mm%&T~C^ShOWy)1+s1^YYPnco=8q^L72Qtj&Ah_JK`f%UEQ6zH3Xf~cc) zLsK8j`j&4$hB2U zkq}T~QIh95MJy>w!%BM-Fg7^H-4`6ccwm`bE5lr$jpYc=o3|mbQ5cK=OoG2qHIihJ zkVQxq9q4(W``m zIt15ex%hho*PV8aJBl=lga31JY`1quIbN{}OnA5~}7k>Bu`{@r-(MViF$*YxB^ z-K8TU1cx{@Dmm{Lbiv^g*!{q(jSxN1(Dv6Rlcnw^Wk$h!%1V9!+j4@VnOqk_c^o*j zpT2NGL%ddy7g4Tn=UtL2L(PR~OyKfi5g&iDfkTocFSp>^hzyX-&dzVYD&Qs`JAQob zW9H$fbmYM(jyw0q^u6Ld0}L9o)srmfX)@svu)RV zp0UuaPJ>%BsXCw>$)x}FAa>z?-k{R-eKXUGzm^yEg?_(=1P4v=wbLU}g!c)4zj1B2 zI}-HoXAd6ufT%KRoI8q65xaW$ zLJ*^0rXN4vKgh;%qCd-gK1+{mbCHa;*C{=GZbv`n=3C1_!V3_d4ZeUmk_w)rxFl;2 zJG>3pSx0w{;`U-<3FYV_{-GV}tFXE_`P1#r<&_~-mCnrU zG5Y-md0DIYbrir5kvEP#ylMb3BuuoIf2y^#`f*9dk14$7sZ^0SBZ>&*i|IG|E3H)3 zFO;nzTASg=aJh#Fe_NfwR7verfgmK^oJ8#AqTc+g5ap1GT`(pu`sx=V0i|?af87k zcn9!b$BtGj(`mHuhT3ZP&uS<7kUR87mt>6Zb}$VPG9&ADUqxRph|A%Lnr=6vuJLd2 z=QvUmcp*qTh>?VnToMvWa6w$V66IGVD?aZgza{X1^_Jvn5iWAK8+X78ALM6`nkPrz zATG1GT*QV**+6+!VfMOOZTb_r7xZ!?q)PBeuU{u|N3#+ltpSmLZYLb9RKl!%Dx2uN zGIXrU_1YmYV9%#Cl>d<)TKxFz=dG#tl@Ttl%^|;jm7Bi^_%{s!)yP!;1WPuJg%;9R z%0?d-G>QHsSGlW;-x6Z-kFHkQhOFeZq|c!^k;*$s^vbcjc7M=$04oF)eJH6vL7*O8 zubq+k4=;6VJ~4M1Wxrsxv%>7`G^?E+MT{gSNNNwT$lEbJf2S}fQz0C+>!*Km{=)P@ zdp$C9kC0@=an<69r8PenLb**{+bAsEE zQDwjEgx`+)XO%N1wC9CXhg}m~9s%JSyKZ?!F!x_5 zEnMFAiC2MDX}k`qj=B)NQdAR9h!PPkE1S!p?e*>Om@bC*MJpel2%ZTpPEr}@aWPhz zAZo%euvJ9rtL@IKJ=*2!{Jg_>6&7$+knoM*@(3qhv)|3`NoA6{r(Z8Z^5jsI*IKT- zda(_iF1-HwkodpHmGJB3?b#V&Dk6hDLA7=j-*kxE$$=vkLlj3vD&kpnc(>LKTn;<_ zA`!hh&x_YZ_o*F;rUSvZTz-|(e-a7TpA23nMd)ZkD2f{oJY@bc;k5YKaUo?xs7~%T zq~Z7M-(3Gc?W_PO35<)nKN(2fxjXQDg@2+eU+7)mcnyKE2K!B@N@c1gm)}q4iYJA8 z$793uN=^n&{yQv671Lje8T?MY+r83i>7PgRjJ>Q&Z5qI|AdijMV*v!Y+CBWUJ6D5$ z2e{ecwjIC2vVQLj;4T7p$K{7b{E;!*LqTeSfDZcH!#p}dh<0nR_CFnP75$(zBRaWV^2ga^5W2RV)ixx?+5#@oOa%%x40GBG^dZ_1IW zn&eIJ8HdvmP7^1SO%|~6h>S`=tv2@dVJ+=9TfNTr`n9nJyM4ha`&O1|Ae!AWG0}Kt z-pgOm@8>TUmHX^ob1ST^(ahoOAbvL3+Eqa|@L(ByHss_o9=8(N(C^fw_xeNkzbS~zJH_Q8D6eHxw!r?OvY2d*iQV|~l%$m&bC=h+`$KTvb&5ptCOGwk zULW-;$ZOpF0pM=}ZaQUsoH|O}1iaDVfgrDCkfr;BfFHnzBe%g3hnL}Yfr`A;kuUh# zZtw@Oc1D8_Vgm;WrC-7Q-cjm`^kGm%q*J|BA38DLAtEQ|JjB+-~_5?=^g%L>VU|%xNxnyTxY8PJh8I$x#e`C)WoX9pV5wk9~j)}-vzH; z-L(Z=2z=Is&kl@oXNqw5XmYmT_Y&c*h@9o-heVihye>#(V|KcZ_e5lYO5lDUmm4JT qEsJ(D$PKP?WLuQkAQ%14hW`)3lpI^^)lqf;00009vP)Rs>p5P=;1%8$!2n zWRzJZ6;Ncb4H%FlgqRp0$dn0Qk~iG>OjWhl>Obn7JDzigmq*t3?eCsjReSHX*WR_( z+H2S)?(7Y&gX15YgSjSxp!q5@Pd(1U*ALPCdY#$RkF(O7Wa9WLMYBe)UPB5&6x;z3 z(1dz-743ED9X_2_8dz9dCRG7}*v`&sK4|6c*3-N6|D%3ysrxy=nK*|KnE|f>4FJcx zg7k3~5RN;3gl@PoyI1#{I$<|;u4>(oOqSnw7h+)?n3<%V8;xVPQ`Ty98Vy2ppz6CS zO4jd^cDu9>O)_0uV*b`yvIiE-o_(D8f0)CXH4sQ{>T%$y$Km07BVV#dGM_RKcf@V@ zZzlL-T=d6*`{`u)fbPGy&O#k&I1Cqo!1_PKOENw9an9g>Xc_r;>$nSH(!TF5*Wz*= z;+F!K0=c*$dtP0q4(?P!3lKxdNV12QMez&mJbyw6;hbu@0|rtXOv1^~!a!0-a4^mS zISY772;qOU+ufT=!ly0CK4coM0NST$SbKsyjnIM|CYI0cr`gYtW)Ii0Bmy#^@ejCn ziP7$=*o)f}lP?zcuc+AvLEZ%%y%P|)QwV)F@KSgG8St}ZjU5Pg28o9-oX`Q=I$x0U z5iY|0qaYUp-}^!KucyArwRgTH@H%&{0e&6)>{H*@9frFgyac!wcpWhFgX-wi6Iv8^ z`2{z<(uG$8vv;JqisOz))7|kqEZlq+_g6c9g$vKVgN==ZQ^q<}jbQOEtF5UwAv{wf zoD^^HwR$~Ajt1hbBDPR^x+>6id}*MBOgr96l61n&W}?M2MC7mtbr`6W`vft&XOX1u zDJIgV1uI{wYPX!k2u8xGA+$K1ZtJHlCV$~7rwPt})dq)BoXaKH7eTJ^$hV?|TUvCF z2I;eC2MH24)iHCL%{s9kS?RV9Ckc14sOLIzpAh^ZZhoN)&Hc@{;3_}s7A|aeniq-q zNA^{H44gcn4QPO*9@O}s{chtGssq((HxRJ4qIF+Hxe|--5w|ZP=`94$-G)1eA?p}V zstv5;C~(xHTon;Q;;6^FI`RmY@Lcc*0|)jpG{LbLPV1G;54*@8N@A~~fng^vzE7Ia z+BD*~!)$ph`H-geSkZl~;K&X2`*z-0e!u<^?}h7q<4Se#Qjm2Pvg72*R_#SLajYA` zZ&cCuy4!sXdxjv-1p_URpM?d+0`l_W}DRw20tlKkPmI2g{QC zX=b~!V~ug4mglc@eq2l`f-P#rmyu5dbf5FiQ?pLkZJD~+s;$6zJ{D_Fm?DonDz6$&rBF{$T zTc%sPa?Aq(qm{Oq%vMRHsC4H2D=pjmcPA1sWUM$f6kNV3&M&(2E5Pz@Dyg6|rPxOi zJ7+&Q?pYX?k{&iqKdWN**zH+Yxx$QJ6|-w(%v4$$2qEV{x`>3hiLjD52=@h^0G!6& z7Q{U8IpB&-{g_i?s4^h=2z&t%-X^77Y3gs4z(aN-q7v_3wrZa$Tj?VcisO60jfBtc za5q3_sY$mxffw@LI1%o(2Vw95;FnyaJB~UoO1f0g&=U|?-=qkHv}EbBnKvYTdy%Nm z?ClM8a6yD_NaA0+^I~@|7&L1b7C}@{Vf6YI@W{X8{^KZb2l<6@y@@$-M$cRN>cRK= zcgrU=yKS1w-D)gjAmO$h@J}HgQ~E3Q|Cuz4$7^jT!RO%eZV{fhD{U0|mo4>b_d}W;0E)@XU~o? zdrJsA58RP=0x#Q9j`)B#hycnO3)<*KaXHUnddJT82xjGjMPxLg#c|hNWtqUsfCCP{ zH13%YBfVPVt?fgNFRyy*$hg;V2Vp3JjhCTh!>$zEFofqIdRN^hEMr6B3|M(-gUED2es z*}4>X*tXm5YhIF#zej@0{M_N&&Li_00wrUnSOE9!|qUM z!fbmULSVTyg~pPg0#vfdgD^e6Ks&T3YqhFU0+I^ie8kP3F}8R2MaS<0n-yo>5Ir({ z_g}sK%<{;45nGb1Ch5CS@wcm z8yh)L-r-w}(rfLiK*Fv%^bkxGiXPL)7V%`zVDuYTW~cvmr_p+Sh~v~=c|Pz4hZDmq zNn9JJqwu_-GCOwLD|`#F|Fw}g?Knl-Ckaw+cxHtZ1MIhC<} zTSSm}wWj80W~onh*(S6ET>PyPdF0+mQaKkwQM^<7`Rb-!y*m<}vYz59yDS1`fhKUf znib+saASFDntrW8C@U9(1udkEZvy^wBrX8xa}OUpc1e;I1qMmCR;%u$>BE%~dg73M z7xI1Y%X=#oKSLXiqv(Lax^qCp-+;@n6p||f>iU)F@-`9wi*3!ifh%Rw03w^2yQ9X( z-MJNEr2e@TEQDfq;l%rrm3)00=0E~533O?)Ix&TAWmOeC1b9C17^>KgZ*=R8x5W_N zQ{f4{dPdSSq$f}~;=G$0zb&bsHR=sf@dxC2_G3k<|AIr3o_kLK78jR(-g-Hz+h;s3 z1zJD4@|Vqrtgcq05*9x?M_d$0t6oI>{qFwcEeq!SAa?%h>cnF$CjUj%j&C$^i92fG zCWy&~S6V<=Li~dWzp*=+g;19NwAyNXP3rY^{_GHIDK+b(y)A?=!^IKd6)OIF?(0?` zaX;K^wJyZ{K4Sc~xIhP{AGt#PUY%k4tL-mOytRG#5gD)`)nm z#OozqDr>02U zFtf8=!n*|?y-n-cim}N@foCE>DOfM5v=>0?23hfGB2O4o-7VVVf&Zr&kwpB*cM`;2 z`g<+S@rj%;*&(!Y+!QMnaleFfZBN=SQ>;h7;dM+zUt zAw1sPKPdYMW;Caz>W>3?_W&P4o}q&vA6L6H&w4#!v}Ip}^Q{+9J;doA_5S0POaF2V z;Z_SNmIZ1Da7Rm8s~ge0s*(nuNUWUbeC8;wgsj3*T^B*-HKIVcFhm6!;5X5^_+q?D#|*|>#j zE8&dkr_A3YS-EuT9?}|3C=thExH^^zod(4xjffKsmgko!#lVFi90?)$bBC9&)$1zB>G?k#`03@(BcQ2s{8Lku$CRYLhEJl% zyS$WV-ND3yLjiw^VDEv-Op+&+vhD)n{uQy&b{=UN?av>$ds5t7yO*?#QO<35Dbmbt zNV6O-h3o-+I*myHtgG~Isy#l$a(l&nLWuF)_Qd38B*f=vVV{mk%0ylg`aKqBX3!XM z{P*4c$3ZR-5v=4GHGfI^LpcB|*G$m4rB35OrLnkknhNhhc>EnkunK#80`6;s&dQB} zXx!)`1tZ+Ek~!TQvU?`f<2mD^B;Ea1GrI|?qCaOJwL~&gskP-&a&GS}r#)KIJL*VX zgE^1k?-Bb|fw!9|t(6{Ay2SGIG+vfV&3gR_?*5y3Kh{*_&n@~5085umGyj=cbh1B) zaMB+``~$!_dzR8Wf`jN2a!(E!avUIFWU^*;zsX&0^D2#GGZ=)Xos)>jnIoHa2&%W$ z((E`6J_E~tH;0Q=vOUU$+KjbRFp7(Q$c~Q0(j?ObQ;Ta`q3#cMH&)DWb9wiJ;V!Ucbo@T$hICtn1Kn_rf zP>bt)Q8K5vJzyr(XZyI3;Ni_~Ve*u4i&5Zmcc-!m1dN$vmErCqh^>wyGJuHBBuJI= z3!7J@2w04(Ww|cwR6-T$Q~i5nPtpA+0pd<9lXJ=#Ca7ZSu%bZfQY9%N0O|LPQqQw0|OKT2W6KmZrQMvUHVP_;bHd#(a(q%n?hP{M_!Rh*I|o!bWUey;GlfP^_gKojYxCLIM~v-l6T@Pe3}OI;hmUFrnG{ zb{5Uhevh&!P_0Z9We6WkqJ0QB3#d^w)&siWeUKh&+aV!I3bHh((`k+Hp9&_5TS<8| zrTg_Jov$`vC6ENL%+Y3_nfZCNW7GK0Tph`rjOG!<7EHaDK zBI34gy_Gc#Dk6>xssk{g)m^6DnqUXcxv82Ldw4EF*-Y@Ja*%~8Gl4brZg!k{hs%k? z;mD}lB4B2xcY3`;0vpl?`iKaL>X^aqFdnZARjLN=xF{2=3v?!0cv536)va2JX9GV1 z90C4q6Jp!pyusgZKxLUoihR(aS0=DQ0J@nI!v56~!9k$gY@rFHWzGgA;IJd7kFV_C zQ}5_aVB&7g<#~pj83OTqQ$ss=Xfc9A;{$je=l&k zATJs=qh(q70AsbW5s^OvuE4oG;Qu7TGb+MVP`wNlk+UqL*{Wlux_|n)3f{E^nA>Y#z{@}Zbhn;$;J{W(_|z++6dX1Ig&WhjAlKfUayh& zgd(r8HFZwKLT=eh+HvyB8vVt<&<2y4`)^0{1EoXK>yy`N z*hf_S<9SxQ&&KxMoscACS&ExO8JL({W*B6z&GE)Dai>UAP8>Qw5riU<%H^6W{Y)uU z&%sAWc6%w*@7n*CPCaJ%JJuP!q+J}a2Z>oF5Z6kqiu;zC9R`6^uKeaBI+YCqtArT> zL)NjzbRBUXEATJwa&biGwn;J9Ib08Fbe0;E+&(kM(V02sCue?mqu*~>%SE2rZcTl~ zMPG}r>(WEkF~n503OkaX)BQ?wti3=ivf6CX%bFxbL`z2oMN3DF^T*kEysfkzwfJ3K z{^ZPe!-S1V84|?&;YqZRn6aruBVdHJXn;yUsg;B>2OP`SS;q(k5;dD^Pfq=D49Ta( zcvuzAvHeLApBM2}5E@yJR@$bSbZBUAaWvi_ZViFoMfA%K&m8rP4>AHgSMskn32NIi ztHcHIKvD>`9FkH=N+lhZLK1a<Z_ zN<>No=2s5T>m{JzCO5gn>jk;*_!cS%5?;{nh4#&SCf(iC}WE&3-y#+uZ#&|fEHXpEZZsY!)Z*RS4tAW)|wknEk zL0aq8Kvd*sdwKpEcfYT0%L(5Z9F`L7%9Kht2XT^GCE!JbqV%hZJU)LfhW_1>6#M=tirb3Pde{ot-9|@!b+2pPvvW=JLT!zRy;CJE${QvZ<}U+Kf z^m;jE8UIZ-hJx+2RUpr6|J6;e0D0CZLc0l4i|AxAvUn1o<#9aQFqcnKP*8xh|DZBj zc_NSMOip}m$>fwg1U=;)x~!`3}A;o04`Cr|GtUf>Ud8nd%kW4@QS5~$b@9}AEcZ)iha8a6O$_! zO6r&4kTi?cDiEFIOKq9BPJBd+w1XsmrX>EHp#Enn8&4w;iZb0qOIOYi_=INhtdk%7 zuyy;wrnz@RJ!Jy|J(u`3;0_SlariZJX{*R9H`+`jbFwViBn!<9bALWMn#cppug%i_ zhz?1@(((DM+v)yh(9wPqcP9jY z*XrtAv1Vb`2vrfp+$di0qRLUZ>Cx?0{gVI-`bAgCH(hi{wu`>6f*b`ud`J6qd~W!5 zx;kYnSY2Mm%&T~C^ShOWy)1+s1^YYPnco=8q^L72Qtj&Ah_JK`f%UEQ6zH3Xf~cc) zLsK8j`j&4$hB2U zkq}T~QIh95MJy>w!%BM-Fg7^H-4`6ccwm`bE5lr$jpYc=o3|mbQ5cK=OoG2qHIihJ zkVQxq9q4(W``m zIt15ex%hho*PV8aJBl=lga31JY`1quIbN{}OnA5~}7k>Bu`{@r-(MViF$*YxB^ z-K8TU1cx{@Dmm{Lbiv^g*!{q(jSxN1(Dv6Rlcnw^Wk$h!%1V9!+j4@VnOqk_c^o*j zpT2NGL%ddy7g4Tn=UtL2L(PR~OyKfi5g&iDfkTocFSp>^hzyX-&dzVYD&Qs`JAQob zW9H$fbmYM(jyw0q^u6Ld0}L9o)srmfX)@svu)RV zp0UuaPJ>%BsXCw>$)x}FAa>z?-k{R-eKXUGzm^yEg?_(=1P4v=wbLU}g!c)4zj1B2 zI}-HoXAd6ufT%KRoI8q65xaW$ zLJ*^0rXN4vKgh;%qCd-gK1+{mbCHa;*C{=GZbv`n=3C1_!V3_d4ZeUmk_w)rxFl;2 zJG>3pSx0w{;`U-<3FYV_{-GV}tFXE_`P1#r<&_~-mCnrU zG5Y-md0DIYbrir5kvEP#ylMb3BuuoIf2y^#`f*9dk14$7sZ^0SBZ>&*i|IG|E3H)3 zFO;nzTASg=aJh#Fe_NfwR7verfgmK^oJ8#AqTc+g5ap1GT`(pu`sx=V0i|?af87k zcn9!b$BtGj(`mHuhT3ZP&uS<7kUR87mt>6Zb}$VPG9&ADUqxRph|A%Lnr=6vuJLd2 z=QvUmcp*qTh>?VnToMvWa6w$V66IGVD?aZgza{X1^_Jvn5iWAK8+X78ALM6`nkPrz zATG1GT*QV**+6+!VfMOOZTb_r7xZ!?q)PBeuU{u|N3#+ltpSmLZYLb9RKl!%Dx2uN zGIXrU_1YmYV9%#Cl>d<)TKxFz=dG#tl@Ttl%^|;jm7Bi^_%{s!)yP!;1WPuJg%;9R z%0?d-G>QHsSGlW;-x6Z-kFHkQhOFeZq|c!^k;*$s^vbcjc7M=$04oF)eJH6vL7*O8 zubq+k4=;6VJ~4M1Wxrsxv%>7`G^?E+MT{gSNNNwT$lEbJf2S}fQz0C+>!*Km{=)P@ zdp$C9kC0@=an<69r8PenLb**{+bAsEE zQDwjEgx`+)XO%N1wC9CXhg}m~9s%JSyKZ?!F!x_5 zEnMFAiC2MDX}k`qj=B)NQdAR9h!PPkE1S!p?e*>Om@bC*MJpel2%ZTpPEr}@aWPhz zAZo%euvJ9rtL@IKJ=*2!{Jg_>6&7$+knoM*@(3qhv)|3`NoA6{r(Z8Z^5jsI*IKT- zda(_iF1-HwkodpHmGJB3?b#V&Dk6hDLA7=j-*kxE$$=vkLlj3vD&kpnc(>LKTn;<_ zA`!hh&x_YZ_o*F;rUSvZTz-|(e-a7TpA23nMd)ZkD2f{oJY@bc;k5YKaUo?xs7~%T zq~Z7M-(3Gc?W_PO35<)nKN(2fxjXQDg@2+eU+7)mcnyKE2K!B@N@c1gm)}q4iYJA8 z$793uN=^n&{yQv671Lje8T?MY+r83i>7PgRjJ>Q&Z5qI|AdijMV*v!Y+CBWUJ6D5$ z2e{ecwjIC2vVQLj;4T7p$K{7b{E;!*LqTeSfDZcH!#p}dh<0nR_CFnP75$(zBRaWV^2ga^5W2RV)ixx?+5#@oOa%%x40GBG^dZ_1IW zn&eIJ8HdvmP7^1SO%|~6h>S`=tv2@dVJ+=9TfNTr`n9nJyM4ha`&O1|Ae!AWG0}Kt z-pgOm@8>TUmHX^ob1ST^(ahoOAbvL3+Eqa|@L(ByHss_o9=8(N(C^fw_xeNkzbS~zJH_Q8D6eHxw!r?OvY2d*iQV|~l%$m&bC=h+`$KTvb&5ptCOGwk zULW-;$ZOpF0pM=}ZaQUsoH|O}1iaDVfgrDCkfr;BfFHnzBe%g3hnL}Yfr`A;kuUh# zZtw@Oc1D8_Vgm;WrC-7Q-cjm`^kGm%q*J|BA38DLAtEQ|JjB+-~_5?=^g%L>VU|%xNxnyTxY8PJh8I$x#e`C)WoX9pV5wk9~j)}-vzH; z-L(Z=2z=Is&kl@oXNqw5XmYmT_Y&c*h@9o-heVihye>#(V|KcZ_e5lYO5lDUmm4JT qEsJ(D$PKP?WLuQkAQ%14hW`)3lpI^^)lqf;0000Z@;axWpp{WR;~7fh=c$}b?0(x`h^rdZ(jJI=54TpTi#rP;D=0Bf+|8)9JtY4^H3oG^Ae;InJp7H^y zY*iSS9B@MjW{0TZqEn!Ll6-_D&rI5i?PFVG5H6VD3P!dqfS@jcAf4}j$BQ9Ecn=u=%+$?LNu#(eKz6IeO3&4ZVehg#eVlZOE(0Fqe8MQKqq zW$z)Zc;h8z`PT>Rk&&n|$dfioF2QPgyNWdKEA>M`3cOkPv1XZm(Uufo?2HMWVz2nv zXZvffvrt8*%gnaN(*C5sRmse@topZ{pZ>Ujh+Yzc@kbzSz%cYq%OEtLLH>dNLV42W zv5R2JQ$-xW`X|7;=eZtN{$vcd@(3%m|F7cKvCkKLz}*=pSb$5SMkaegRNF_4nod>& z=$7OTu1TW-iTay2HkJC?nilV9tVEfINr1LRa|8PL>ww*ID5=)$z86h|>`s&mS$Iet zSSaWeECfGeyC2N(D^p*{?rzG!>Iq6k|DZT5(|z(r`sX;w=O`h%sFsDnYxkGffCDdj zG(4{!Hxc)9^O`sM>Ji^na_v2(c>x!VDJU-dsD~`eOEY~Q1_Mzqe}-WHZYxQ57o#i6 z^XN1Ib9)2rcPdpo&^Xix!$Wa+4{%t!w7-Tf51*;bykJC)`yBd>G@fPNd{~PB7 z^s8jXUXTkqYESe_^xtQ@4B)fyrOB1(bvIiXe93?OQ3C#8WpaE{xRiJh$h-h1&%Ap8 z>0hD9qP(a7MscG?-TTnk7FAo^>^G-}9iG|w2XNMik0K3jYP5*D4sepeca3jKrj!QU z(8)nCj3%}{4EKN}v`59dO|Apx96os<{Do+?@WIG8s2LB@dX1iGePx2FbU55~h~-z_ zMtyZf4%neZ>jj!nq}}5XvEb|_0{b_}T#3f1T&NoZt=0n1WZQvpMj$PMmUE-AMMq8Ahvl!>twNmo51&6>VT`& z;gCtYEAoFI^rP5Z%>*C3=_J6O**(<;hIUX>lji+|-YKdyQ6 z@Pul@UXU6dr(ZO_?^OXTa*!-)6a6c9ODC!`=5`VIq%tw2fIr&&64$VoTLO-X zUt0yo2cm8qvcYEXrGP|WD|gT*-vawG^QLEI7&_>cJ7RNLA{4oLJ3O@LhA{M;)YJ#- zHmpu~iB&ZmCiLUZU^WnZ3U;7{NYbLDVdc&NCIEM4=FN-yxDGpQ7hSoYe=%w_@{xlIxsi~Mh5vrG2;KcpF3iUw1 zwjVJk=l1o1|n5Kc;xpL}1rX`TesRtQ*IfNYhwh}ouwhecHlVXo-+$?02g7_xd`Z|Um zU;1;r%+4#T*L_kve!v|(9?$^44dou<8my;?>Nv$guKVG&I9KWeYj~Lk35xnB0(Nf9 zU!Pz=7YbGcsRob*7VsHm7UG7>-%TdzP=r4&b3BtgO~=T3#l+@RKSFlbR&FzvUlYCY z6H3RdNXgJA`L4VkT4Lp4T3C*?am#tLh5ck#rLD`1>{#-tBWT&XIjd92T?&nG5KQsG zYsU!UO-D(doelGs)t8R9@F8nKwwi5^g3n`)aOBN_Pu(AvnjdK8g0n|)3VJOKmPKxL zN>=4bDn=Ix=#4!nr773HgSJJPzgiQK6R1nn-MUg-AQeiI`Ya{FpFjXO1+s9N`Hn{XsWn|_5hPxepB!!IDd?T&C)Y6l()U84Gqm12W(DixMk;JfH$mYC(s z&JC@7`Kg}s&ee&x+~OOCd6WXBpze`&A0dm455m!?uTN>Z9Vxc1yr;Z%eu@L zwfBLFpJ+hRJ@O!EK#CYI7UiqPCLOV+w>_*P9^~II$Was^4-uw|a>UiUj~Rvc&{gr} z2sN4HwHg|_k<}RHht^p8f>Pw&7^bidL{(d0r9SYr?M&`xT<{xR5*Y=((~015B2l_1 zodQxE&LE$3bj;uVwm6t!kEgWXBK$#|g4Z%wb=;siW%1Jc+lV7Pd`TB)+ga%7k<0+* zi(hZJghSCZss3%|(f@2_`|U74Y+%(Y%TYFK2&l6vB->Mn#*HE^LjMRm_yvhfuOneP z^xuA*|s9AL#-~O8x!lav?t9f5IT$p?B}^i6FX&nNrOS zBDPPkGs>5lEF>4H%Y(xH;Y@DXLb;Hyo4zJe(f?=QOvOb4S>qjDWHypdqc#GGXNL z2EQIx0$X?(+L_?LRf|>rvz?hk?Sio>i~tm^Bb+*_!z2Hy0O|P2wDam1Qvdni+G+n? z`^&b6uOR-jp?hAf`(EF{yuqy>7)-peA;vGTaJ^v2_B#($%Zl1Pe0vw1g;G2bBkR)Y z=1v%1ji|Wotjsu5L9^I%+ZD3str-+FaZVXs<1NwVz>l*2USgr9*3_E`1U2V={S0LD z7Abv}{8Uqv$0aJcS$v9C-$6tr9)@D)mM6|8GHp>X891tP-6#Db%E0unf0pF>%9Ny% zo6z%l{RwbhCl4WKc&MFTy&dhdd@JJ>G-GX6vTxjdXw^~|+VU{&C4;9;vaGtBU}?k} z=9?mIFrbqfCB>2TQDjlly#+SMtgt%ScC*q>@wna7%U0j{5fXTRs?X;SN&Rv@SLmIz zDC)!WS!C`pAxAUDtSqr_gs~OAG1N5wYRVTP?$j`+%0euPahuJj9)dvji(^8ZvVeAT zMZWd?G`>9r-Gj_Ezb$z;w3p4)-uQB!0~kL)@m)6&55b#)iOteTzMwa#O9V$cA|t%{ zsq~0$Ttr~AvKoJWWm;w}++)o!7#ZKh11ji-hrLIDimsUCXF2tr*>E%)pIp|>ScB*V zO7$g_JAK&$fi&msO3jU=e%Rjn17ZZ?1*27JS5$Pnz`c1q?NGshTbLJPeTL4?q&%|X zlJwl_xnXxAFHxfgD%QIaLc_)ud-b%%p>)dLQl>8}nFiljl5|}Y_y8-rqp%&U+8kzi zvowsL85BA2!H7#oxB*AAVZcs6$bAl5im~BYvinr^LF^(h6<|!cv68Y=Uea`21o@Ld zxKPpQN7FUOT6GdVq8(cob1j&?7#%{w81R$NCI1x_oLiV7kf|!U-{&F4AV72i+PvdY z;9Eqxz%}QdYZE*%!hgJ=@quBUQdo_8^H}84t8Mf2Qpt#L9uF19I>HY<^#D7Lu3>eK zp-l2_A194f-r(47c!_b5g*(FSaxWV68w!L+7_b{raqB+u!;KqTnd%+~uF?s7VDrnL zf1^0U8vRq$wfU)K!Kbc@5Y3t$6{0u1&fS>O{x~yR^}yHAGo`Qnv{uvM%XIbUw>{PqaQRWes?L4Pom2(n1(BmcSY2@?FbgHuwBH6alO*}JJrF%aX0vZuUgbRSa;hDHT4oZohJMu?O(YyL9E z*}qkBlbgxON-QUyH!6d}6>Riqvp{DSh3dBw^6p{X`;3PF0z``LLNv46_W0GJN?90WAN3SP+3xh;mn3!Wg7o$Jv$zX>IQX| z*gFH|XtOa)U2Y++`pbE<7Mg5uUd_-)nhTD8Pn~-VWz|o zgp+MUB{Q^wZq~98y$%by0D>0Q1?OlxNvhHo^;ca># z3T1J>kpbRgcauwIGDsH^=oxg5TNh)06l!yDUJz%8hGU%-g?W zv;kQRl)W=*pIBcA?OS|VyrX15vUV=gar1SrUy&pwILz-w6Ly~PO*av-cW!>HMLUTf zK_+>5GHOCW9mF!od}@og^as-qYPab-=;<%r9v`SS z(I9_NG~e|jLebH){qRjC6-YD=tf?(O77g^$!i<|PFZI2Vd zAarmcuV5;V=L{oeQqn5wGB-6I%P+2aS}x*4;&Ld)H;-qr`i7X3-8F(f0Me+ukusg# zL4Ra!0@PCdwm0#(5^Yq9MCOJqV~xG9kth8XNI)NzHDz^`tDH0F5B*83f5rwQL>mor zRGQMl4|#7YX$tIUE*>_9r%u7ea0_=&&LDfgTxRP^g9M5$s@NrKsMBzT20IiD3tWse zUYH8 zs3*1EU-P3l$D85$tiy*vIi@BQYIwl5vDL=bP$%XeXpd5$zKjG)vC}hheqVBghX?Nr zT$jBU^*Yxez{<4Db2~&?w;uS+Hj{iI2_*UBd(*~MaBhSLTIaIv3*h^NG*6>^Avb)8 zi<`TNZtR3MnhUT+;;){udyXXcS!$0$#vE?C39g5YO|v0`COSBwoC%7))QyKg5;&;S zM^Ht`YHNA|DiP|7wpnAyydeP|F!D3o!(Xt6A(#ApfX04Fza;4hf0Rzx4w zu@hCKeK@i1b`Te4S)7ayQ3X=@=VbM2AJ(L3+{e_`)Br1AXTL5YeS4+$T#JF?0t-So zy?Y8E6hjGGApI!R$;2^*Avi(MOQo}OoV#AXc{AKCz<54n9Fbi30OC?=RC0|cO8{2C z1l#O5H!qvAFU<1*Ip`%di2EyL5!p5y9YwSRI2>3Iu`M@|b*{!np7|F*f0nLnO+c&y z-LOC)FYq*Kos(OA;4X0U6t92XcNv*^o`JDZpg$)^+)*t6iY zpgc)Rv$WRYX$ILH#t4xN;KB)AZ#GzB`xzt$6ok<{ce+4M2X23Hw`EX)17wmlyK|0k zZ^nC&G*@9Bd)_1-IYz2*FrhgB{t*3UrN1(}yK}g&4M~-`Z!+vx$ha_q*r7{8GmlC~ z)-@|mG51)|Db()I-7B5g)KeE2d*r`vcj*HeaYd7S3gkjhvb`qWO!LZ`3Pm+`=Fi=_ z(H}w~6LU%Yqjp_!QOF}uhI0ZN62uEIsDSGSLw%*#{!;&xWAUsbfRvVhMJilV#6K+U zc^X0-LZa#!J!Sv5xFwRS=Tl45A8gwQz-mWH=j^&0dxFu%w|WqXT}tUcxy6FamCtMg z923DH+N%-80+b`<;4oFk?!h0CY;J%MUUQ;Q2gtl4IQ`vB?mDBWjGDY>fJ@f7B{MNP z1NC)qAx>f0*z1aObE*wZ`uq?z>`yH(PRTtjJQ8#11Y{u?ce8!JAS!_wJDAh|rd4*& zdYr-k&WIC4Qh5EsPf+z5c#YE_D&Tl!4o4)OBq(yQX9GLhkU#q9KV&vfRi7sZfgSV> zEEhAG$gBXC%Um&4b4PrBaOccHf(}Gea_fO%9=F*=8v}3|G{>ib-r-F@R#SXW_HF2e zT$jN{YV#2_MD5Pwzdz;t!JXn(+nz(JbdzE9WBa>{z>tnsyJP4moK;CcwIDc%hrwzQ6})qjh^4~iJn|Kms$qbmw`C+l6py~3TT~s@2aaOWr7EykLfs% z70e`HVT}n+7{D+7_&?{;xk2209-YJ#2H+=lnG6nub|Pa^9U2N4KTF;f`~Y)bjlRIY z=pKGPbDe~Wt0555AD22OLl32z)r7%yOsOBn&G{Aw+fW0Uu_1!iCji~&x&@Gp{b*fr zN^g$l(Yy!d%K1RuL{ev2u2*#!${NkTFqIMbraKW0l7|!eF(VW3pFlc-TQ#$d^2suP ztody_AGLs}K5f>va^o4|(VqJ|8czUa#jm`SaPTsq2+j8{(Jt8bFj$Hl@xlbG$N*M) z#F4l;P<0P?Zn?M=*&^w}i1{05Eo33Cq)J)Q{W$<5eqhjjLIyQIsT`!hyCby%uHo)s z#6N5DC+7)ysHukyx14F=``BNXoV_jT48{OYgT2Ylya(e7Dj0*ZsZxJRE(slwHUnUwa8-9xPkJBx0}bwNu&iT@K-BbGbLdCbFhBd9^Wyt zr29>T(Q>gtMa|VCXCE50^8>}&0ZTp(_GgCo>FjAn+!MoX$If>Mfi`@*3oLFpNcU-0 z97%O{iFL9PZ13=I%`RMe#Gl`JuBLwTRcmP7fzF0zXK2**EN8 zO`7nei!#=OAn@C(s)kv!Qnj_$-7ehapN*mpsiXTJOYY2eF`v}R?kI5t2%$gXR2Zp!D9i$vgInbl&Jp)h) zQGvWY4~4TuadgWj%OF5kNpR-o(1oSTaoYWdnp+xg!EeS&A2w?jIhxvsPmvx)8 z1v59*!1s*BGeNZ(`b0r*YEYwsL1MY@WuLNSjC9n|amg{^6lN~A|ENv(w#w9xid;GU z2T85pBZ_NAqhC|@v*Vyx0);Gh!_3S|sJZ38^56}OzZ+Nli^eX2w7OoiQ~%B)yyRMK zjlQyCr9NT!UWI7jz`#ia_TS|M0)8&i$*6lo;!xrN&(tLT{`D|HcfS+R#j2U2I-F%_ zIE$Jsu%5^}%{VwU1*2<47)t9hweHkK2rTM#Cd6{u9|b6!-%0skqI^23OG`#FQe z8~*pN4N4|<=+Z?`uf0W`Ek$6p%5o7nXZJm!VRh{SJuAF3a86uw)G!aku@uByjE?UC z_4#7voo}$fpl;oq+%v62fb{|ei4$#WHChS+?G zFabipsPeRQ;;ct+uF3;Zr~72>kG3VSoG0T>Bh0Et(f7ELC9%$Ad2*!uqS^Ta!u5!P ze%F*MZ3)mt=ll%J`Rj&20$kWB%df)oidEdgvNmebAMD)LM5HyBh5!d%Q-Lz!e`fW7 zs0cNf#YLBD@IJKwcj}a7USW52;CT0K@Ak)M?}jk*n^ZsL`9iL>ZkC^s^Cdvimil>1 zC%lGTYI;vzeFN9x*(Vo;uS|$4>U-bkX~7!Zdl4om?8R}A#bpM{{3dANomJALofx;W zhSo~?;ppZZyJzWh zrT0v7gBxu1KGv(VLkQ(x$_VvyOfUioL&gg%;`BbfTk)LA>OX2^?qA5 z%n^Q)n#pOnxE9wC|E4C$X-7X~M=}5oQZvj6^Q~jpWnwTLYY=LgM}!H7u3u!cK*Hvf zMf3NtW;=Dx`^nS`ue(646^8kbrLYpYH_85{<3JZw0LIvwd?3smFBslb^AQ$d=et3y&ra6*)IvWN=T%#~DYP<(CDv{%C&=gFG2xQL>I)?rrBixF0#ABqx_VvNrpI&PNFT1>*CA1+Ex_p zRSUykrP~Uj$nxh8Z0>TzG0B&;oPf*lEQlI7z~j8)rN>F>F{=+;2Qk|AG)~y)bcw|O zdWj8_XzSN<6Jle`JbgkG+5r5G!n7mYBPn;o^}X=gd$Y6gzu=n7obe<#D=3-@;iCVe zLx3r@`Yic8<-h8(p@au57TbBF!IWOCmsp@|dO}yviIARj7W(1Ig#y;JvNu#3 z<~()In@miyJHIFbnDqcOdVZXGeO*esej2NS0Nbgl3PsylE8zmUt3G27{0UNgScd)g)s1IyST|A@rV7-M66$SL-N>jNEZsY$nA34Z{2N@ zEiXSGeEZb}4!h_~z#EjA`N-+^4WF)C5t94`Q7sF3&I|6S@*E!9E8|?ec>H#C5+EfC zuvw0L>~kD@PzYB@X;tl3<-E^244|@Hy2H6|-9W>2WF7|l!yHGZ@Y>6pErD{ly9&`< z1)X94u_F~l&h>wlmW;W2;8%OYvnloS``B5RiE-}pMJFv0V~UIkNwCS#Ojg^iIOKqI zv%S4!li#7}Bc7g6JZ-@#?{W|%^L@fY!J>JO=T?7AYzl1HR5)FiPe7oH^w+-_bnn0{ ze(~VNp=~|)3x1hEpOGsnfXGtM%Yq!ciP2rh`2(+GgHbI}GqOHu2ay@F=#W600yS&s zuuzXltxB;rhcDsWubJ&DHa;2x>f?%v1t1=W^RSHUhjAGopq@k3>2W3Be_(K4HHp=E z^n_1q|61HdbJwbMi`-&&6m)YasC$Av^k0470$2;wwoes9l8|+t<4Ty7|3h3n`!%Tl zpNw#8-??OT@SDNM8?XZqgqqb9-3#T!&2es-z7fxP18dBJkNnElwJ`*Wo_;aLZ7&jA za_#_5`a(?Ciq}zj#758QiU~90KT;6*%&$sKJpb_YmGSbYRp1Um=^{Ii4b1Bb6xve& zpx)a08W$KyW090T;0zYP{L%JuVXV+Xk`Tp_QSRkIM>u7o4ghV_Z?0ws70iwU8imsa zkjC9!*z@6lI(}<7ru(fnw3%6cksN14Vv-z{Hg2e9^gR18<{MP9>m*O_Gmik2_mPkM zX6_O1`%eTkoGNw>vQ@ML#vh&4dxJUGt^DnqzdVvmvY>AAVt5@8fc?mnv3?g|$5oH1 z_=4Y|5bT^iLZKF(ip*)?TX&qyMY!iTfwvT;2ly?9emA!$5k2J=;)+k>=RPL_rMw!2 z6LyI26P}u(Y5g4X4>-{Gm_gSA8Yf7E`!!cqMTu|$eOWl>FYb*`5N!U>1CQNl;}-0E zzZhb7o4{wzDNl51G9PrBtSrn#hxn`W0U5j~%i`58h>IKlOlWdK)d&YPpgST?5}P9o z;G^U?#3wQ^HD$EqHVJi5H$S#x0ZPuiY$a{ZqpM}kr@Kua{e+KK*H9ghFe__FF#BKU z=%7eiO@6U=_h*#NYy-JJ3LbkfMw0%nYy^K|YlsDe^^dWGwIVmJ116nwM@&t&$zz%} zKH1(Kln!WGOg_d16J*EH;gI$1=&nB65-mUgLhXnwI%y6R; zr2I7Kuo*e8IjP9K`bbmT%lojyGp5Nl2(WKm8&x&q;7L^S;x+)x830meSnl1o+8>8| zR63v15ZoC+%_#!r94XS~Kz!6`5SIp7)qrQf&grH0NA^yY&L)0#V>#>s{(Lsb%|t^3 zh)I2XtWk623td!^V3TMmdMxt@+?0s+n0zTHypJNQ`FyGJ;yS>XdpjZ@;1+T735<9k zN>w8QH*{MR7$~G3Hpt^ou)8B{?*;{$TV zwZToZ6J);l>9be*dzyWDT0r>Ljn6KZde0coUd8;?as9)Y3RIAEKrQw4)}F0#7@@Q5DpZ+1AAlMyTNV^}O?K|vn{2Ks5c2MWzOQzFUSw4xJw9|aA!aUao zpV*A^^B$;O{EoH<1%c~5{si;%-5PzRp~_DXQ0}Ay52kU z5zWFF^DM=q1K|6M^eROkf z`ZAJtujR12itbM8VsOQ;Whv9V97t!AmzYO_6Y^`rWZdkjhFLnUn#7F=ALv%ZHC{|G zafHukf9&q&ItSTvAxRoAchMLjT(|s3;Yfs z&`{_BpUEcg$|Y)qEL-v>o%NjRY{;sU)No6}AbHG&x_$!cro9U4LUT3_mHK)_?0~m( zvcC(?ofwf(z~yu*C+E~V9>qm|t|yJG$$wva0Grd)69avYP;`sS55tBFv{b@Q^2<6GHoAZKuk!?jN7iq`-d5cl$qsZeXNS z?mba8oy+S#u)i;9OHGtQUi&IRbs^{!LEqO;wnQ1p8mh&KAEGPI(;wlww=xc0Y56{8 zk+}lFdeD`{WlTY;rnx8uia?TfpTqjb78iU85Z|DvJwC>66CT#BgFflcl2U4NPw4uL z`D>t{pgi$)(Mm8%(bW=;Of^qrr%(-)^t}a_Ls*w@FPW)#X z)aKK1Yt2z`Emi_hPN!wi<>DCF_O38(>$2;}r*6TwY>skw)jd&;P+6v}jZ*ulr4UfqaJmi{-aB zH5#5|zvl6fg?`*T11_{n{erY1#vu18H6*$GE0H3!6jN+QbfcTcK;!|-d;X47JLd$=!zs(B6IM!@tS(*M-d4ZRh#v|@pHvc1)4mePbo=sLR9da0 z+>TWv?t^yOMkdh{@*mu@%|AZZfZ9xTzm^s9H+g=)I34^*Ud#Wefn?0_`A2cOsQR%* zV#BUuJ|yAo(YI4pVJ#YWiV|%O+Gv1%Ke?LACES!8W=l_##HwH~i!hm9*M?d}*E`b# zz5sU14@+q=^n9bG4MJgdn5z4l50j%|TwTZJJzX0Wz@~&So)iZ!cC2d# zD(5ynyS(j6#4N1%R^gBq)0CQEIF@`AV&I0bdfn;?uz+^?uhI*0?%z77D}N^}jcWyL zk2=Crc2|7Mr>fHmjZI}54MG3W^H4R5%#ro#rB!iS_{FcA@SC?gghYG1hDukJGMy%b z!yY}BI>Y2Uho^d`uUoA^1TVXnvAKVvQ+t{3vi|ruK*G_m+e4Zrszcb4=i2=AZ4xd~ z$a70)jH>0Q+TX94FDn@G>qSXBAeJCHCmYx)8$ zjdF`&H&_$N>dx~YGQJ3RQ-+@!tsq9!I%G`0ofwCk$9743Kj|Pd5vu)qmaAUNqRV!Z z-7@A$Ht6sYC!-EcOo^N;ZNVMsdwYV!1e2P%WrJ?EsNNavgF$!Mr)-xb+T{DsII`-E zTS17%nC?6v%bOhnEI@EPPM7x()}TZhG_zA-e~xY*YAROH+~c-)R{rIVFdeACvP-#_ zZAFJFI`SthCOH;pZ9$8ua-FKag4)nU*SDW88Jcua=5yp-jq)itE(yCe@9k^9mhBvLU- z$8ij}epbH}MW)3D(vWBsa zSH{F(K!fM4&MAZgJzpN@*0NmPeM-Wxe$=+|1HUXEolMa()Y?D%ot=R+rVh z3OMwOX#sbMU1m{Lj3|~8gR+r?=QFW;UShSkc_daclE>LLwfaSxMKye+`5RM9`?~a5 zo>P=EdJRY_0g5M)Zv#2U7Ba+~oFMe`9VR_?!MLb8jvukIQDC=9;n9}+?9B`zxyUG} zr--nz#CEMLQ9JQatTEZ@+YQi8lWjms+Q zaUU(Xi3?nz#WkNFDc57_H2mJkn7T-bF}qjf{-+IznUIJ~i~zwDBo)tJ+3RY%;08QQ!SE z+sFykeMiG#e>SrES!?#g$Ff*NXWUahOJvR=a+faGQgjF)`zyB<+0AsYR?T3?$qf}VfSi=&f!`|c=S zeDGuZ`L@UA47MGQan(uTt|uonLF{kK1e@D=$KY)EbI{e)0AAJ5p9|Gqd^9~9#e7ih z2C6re?Gk*6#g{v=(>L0f^TzADUrsz()WPGOTIVs}Kau3g<2`JVOIueQwVK1zL0@%C zCOqEUT&;a6AGQR#?LCaYYd>3VD~KoAJycHFJMqfe9dl=L_tf+6_MkV(sAt^jmJ9+) zsdNh4(kdOZRqv3Q0{xLus$?%gv=W`tW)|ZQ`C0IVoqzPw^;8r4Eu-{2TYleM8aylB z6m(2Xrs-7Tc?b`Q8FH$rqTV7}Fr`&1k!NDA5(LDNvDI6KJUdn@&WaQG7QLw7Lp`v+U3b9*}nM*8bznae}E>6`X5=duZ%r4WjvHeSq6sXL6552_@2zb zWyu*|Fo^Er_r6Dn9MoPZzkS^lJeL`#Pu5A4` z$Qx9&X{hQI)&j5(`M67SgUq&0FIk}<81|whxZDxQbvJOy70%3CJ*7uaxm(<&Vg#t| zyf;4OYpfl7s^G%H_Y+fqV9?35=p-S#OzPnnv00EdU#2g|m)BGF+Nq>zTC_*55&@pw zKv7^Yd#R(c+L7;&RD!p+LI!aK+^H7Ez{1l#=y-~6%efF*8NmtEU!<@bx5 z8pHc*g{OgR^T%tP__>qqI&yly{^%GDNODrAMzH$G6$Bf*80%~GS=^1R+M}u-o!MNt z+S8z}I8Qj0+MUlaxTockK&kY8>UKsPGoAk%2WS}weV^rvhj8pK7Qt$0%dl(f6#O@5l>3mgD`UFAdD5CkpBS_+!rN-x4ND zNz$a1=psvo4w|=^SUpqr@!M-$(*%9r83>fKq>!|SeLt;%o$|eEd4(jWM(E3s!n9Io z;wEPx3cE3AZ(A1B($3e~&POPfh7=_ZpEz$k;~l|Hma=;91aay#0R>-Y4G&18OHIXV z%~lI+YCP-{x*!E_=SE$cjx;a70FS3#b`-zrZ7D*nh7=~+zkoj8Ep_^bqP3F^$m}K^IUK1rsSsTtd%hGbZ6U*L_kTsXWgqzHR!b?07 z)!ZUca?Q*9>%L?N_L~g8Io01ojVo-n?ZzWAlwXQ}NIqYC=^xmrTi<6^OLX?IiTgBc z@OafeR7%~->7>~vih%@Ik~3^mQM{u zW>q(jeFi*8WrYH2g5hh$dur@KEE_v`-E65d)%hdVd zp+-+VJ5boPL$R5nK;ES2`VBb&c6eY5�nSXn)Ro?G4KnjdWo;8?t*JOlscH5#U@( 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 literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/image/ZzTestFlowSubmitDetail/image_url/f33b658b052f487c9a34af274f48dcd3.png b/orange-demo-flowable/orange-demo-flowable-service/zz-resource/upload-files/online/image/ZzTestFlowSubmitDetail/image_url/f33b658b052f487c9a34af274f48dcd3.png new file mode 100644 index 0000000000000000000000000000000000000000..f2df5bb8023bc0ad62ecb69d3958e000d8198ea9 GIT binary patch literal 9808 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 1% +last 2 versions diff --git a/orange-demo-flowable/orange-demo-flowable-web/.editorconfig b/orange-demo-flowable/orange-demo-flowable-web/.editorconfig new file mode 100644 index 00000000..7053c49a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/.editorconfig @@ -0,0 +1,5 @@ +[*.{js,jsx,ts,tsx,vue}] +indent_style = space +indent_size = 2 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/orange-demo-flowable/orange-demo-flowable-web/.eslintignore b/orange-demo-flowable/orange-demo-flowable-web/.eslintignore new file mode 100644 index 00000000..9c420b5a --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/.eslintignore @@ -0,0 +1 @@ +/src/views/workflow/package/* \ No newline at end of file diff --git a/orange-demo-flowable/orange-demo-flowable-web/.eslintrc.js b/orange-demo-flowable/orange-demo-flowable-web/.eslintrc.js new file mode 100644 index 00000000..81d92950 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/.eslintrc.js @@ -0,0 +1,39 @@ +module.exports = { + root: true, + env: { + node: true + }, + 'extends': [ + 'plugin:vue/essential', + '@vue/standard' + ], + parserOptions: { + parser: 'babel-eslint' + }, + rules: { + 'no-console': 'off', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', + 'semi': ['off', 'always'], + 'prefer-promise-reject-errors': ['error', { 'allowEmptyReject': true }], + 'no-trailing-spaces': ['error', { 'skipBlankLines': true }], + 'prefer-const': ['off'], + 'quote-props': ['off'], + 'object-curly-spacing': ['off'], + 'dot-notation': ['off'], + 'lines-between-class-members': ['off'], + // 'no-undef': ['off', 'always'], + // 'no-unused-vars': ['off', 'always'], + 'no-new-func': ['off', 'always'] + }, + overrides: [ + { + files: [ + '**/__tests__/*.{j,t}s?(x)', + '**/tests/unit/**/*.spec.{j,t}s?(x)' + ], + env: { + jest: true + } + } + ] +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/.gitignore b/orange-demo-flowable/orange-demo-flowable-web/.gitignore new file mode 100644 index 00000000..a0dddc6f --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/.gitignore @@ -0,0 +1,21 @@ +.DS_Store +node_modules +/dist + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/orange-demo-flowable/orange-demo-flowable-web/README.md b/orange-demo-flowable/orange-demo-flowable-web/README.md new file mode 100644 index 00000000..3b5fbf8e --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/README.md @@ -0,0 +1,15 @@ +## 橙单代码生成器 +### 构建命令 +``` bash +# install dependencies +npm install + +# serve with hot reload at localhost:8080 +npm run dev + +# build for production with minification +npm run build + +# run all tests +npm test +``` diff --git a/orange-demo-flowable/orange-demo-flowable-web/babel.config.js b/orange-demo-flowable/orange-demo-flowable-web/babel.config.js new file mode 100644 index 00000000..e9558405 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: [ + '@vue/cli-plugin-babel/preset' + ] +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/jest.config.js b/orange-demo-flowable/orange-demo-flowable-web/jest.config.js new file mode 100644 index 00000000..0f957914 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: '@vue/cli-plugin-unit-jest' +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/package.json b/orange-demo-flowable/orange-demo-flowable-web/package.json new file mode 100644 index 00000000..db304a7c --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/package.json @@ -0,0 +1,71 @@ +{ + "name": "orange-project", + "version": "1.0.0", + "private": true, + "scripts": { + "serve": "vue-cli-service serve", + "dev": "vue-cli-service serve", + "build": "vue-cli-service build", + "test:unit": "vue-cli-service test:unit", + "lint": "vue-cli-service lint" + }, + "dependencies": { + "axios": "^0.18.0", + "echarts": "^4.2.1", + "element-ui": "^2.13.0", + "jquery": "^3.3.1", + "js-cookie": "^2.2.1", + "jsencrypt": "^3.0.0-rc.1", + "json-bigint": "^0.3.0", + "layui-layer": "^1.0.9", + "lodash": "^4.17.5", + "core-js": "^3.6.4", + "register-service-worker": "^1.6.2", + "sortablejs": "^1.7.0", + "v-charts": "^1.19.0", + "vue": "^2.6.11", + "vue-router": "^3.1.5", + "vuex": "^3.1.2", + "wangeditor": "^3.1.1", + "vue-json-viewer": "^2.2.18", + "min-dash": "^3.5.2", + "vuedraggable": "^2.24.3", + "xml-js": "^1.6.11", + "highlight.js": "^10.5.0", + "bpmn-js-token-simulation": "^0.10.0" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "~4.2.0", + "@vue/cli-plugin-eslint": "~4.2.0", + "@vue/cli-plugin-pwa": "~4.2.0", + "@vue/cli-plugin-router": "~4.2.0", + "@vue/cli-plugin-unit-jest": "~4.2.0", + "@vue/cli-plugin-vuex": "~4.2.0", + "@vue/cli-service": "~4.2.0", + "@vue/eslint-config-standard": "^5.1.0", + "@vue/test-utils": "1.0.0-beta.31", + "babel-eslint": "^10.0.3", + "bpmn-js": "^7.4.0", + "bpmn-js-properties-panel": "^0.37.2", + "camunda-bpmn-moddle": "^4.4.1", + "eslint": "^6.7.2", + "eslint-plugin-import": "^2.20.1", + "eslint-plugin-node": "^11.0.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^4.0.0", + "eslint-plugin-vue": "^6.1.2", + "lint-staged": "^9.5.0", + "node-sass": "^4.13.1", + "sass-loader": "^7.3.1", + "vue-template-compiler": "^2.6.11" + }, + "gitHooks": { + "pre-commit": "lint-staged" + }, + "lint-staged": { + "*.{js,jsx,vue}": [ + "vue-cli-service lint", + "git add" + ] + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/public/favicon.ico b/orange-demo-flowable/orange-demo-flowable-web/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/android-chrome-192x192.png b/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..b02aa64d97167ad649e496908b35f14c603d9249 GIT binary patch literal 9416 zcmaiaXIK+m6y}7Elz=p)MnHo|M?q?+0v{qpLa)*lLYEGqqjV4i=}jOYT}nWZqF?|) zgh-1tgLI@XT{CZOOrNn4PA94gdt+0swRr0GxtN=oJ9)6$5}Z8vu~a z0suCTT&%u4c!A=HwuTyT`R`r$p*$UIq4d$xQKwvhFj3OT{OH^VTlieG)RYbVr#JIl z(mDIH=Ppe(jQxytM}R(c{bw&opbQ^vZuTtH3D0=B_H|CF-g$>FWnM_E<8xJ;6x|$I z5G`a2B~ocHl=45jx%nT5vR43_%##6zzVX(HLh_o0w@uPo%~p-v-(oDb3R6|P%IEF4 z#wIQfyvY8F!v*IL!3%yDDE;^Uec_bR`)5#5OYHbjmxA;8`ENvd^-LYxm>)hTiEF%U zkN$D_^9{A1x73rnLs#ZZ%a11T;`K@VTo(k}RlVtj?cvL>fxM;LcX~c<-x(7x`pVDM zc{OYct-^Hikf}3ECxUyMMsv<| zf+5!5j#w_e_d*z9^^%|Ht-CMXFE${zR!096`Z0Aze9fEWr}|K9QwaZ1^~WBd|8Z8V z8EP!@Bwgvs--tSLM##X-93mjI^{%RgAmi(oeI>jCWazZd{W@fJ*K1Z>Fg%) z*4xn<5M$Q*0RH%LVB<3zd)|M*sP=1-R8QTAD2HS!B@!5EiXUxo?{m*wfcM7589&n@ z$ygP6irp0@_%d_lrF~Sy#}X3HN=*yFtFbTpWKUO5E%xS4?!uLWNuuQL+VKot=;~g* zC_QORR7Q9{Rspt6SeF|hW}YUK5?9a+5NUhH%MzF!lkhsn=*IY$ea%5V$N-?{!_n_Y zcP_fN@MLsZ>*#8BT48Q>j2NG8jkFohb{L;B8zf@s19ZOY2KFv*oDRB9n}z*SA$_W% z>se>krL-Xo9-hf%TffAoA;Dl>5D{V*+g&c5Khq1nOB!aGvJ<8f!n#GjJyxb|XMW{g zb(sGj?LU-ZtV&jrf9ytjp$zw2(<6bg^~W#`31{KDDP?(VKKRo!D<91yKbWm1F^X0j`%4J-3w1y22K9zf$MZa-{{e4%mk z;9`r1Y|z~HuUH|VudeyK9Fl4Y4dQ>>!BdB){T7ir5o) zB)NVqRY?{>SNu|l&XB2l*J%8#Jq*UZd5Ve>>52qkZ5k884j(Rp^jfQVt}v%qeN{bo zOmcyni(CZv!`K#r!iCJN3SDd;tdgr}7aUI`XkcA-De;-{2q*jvW`?fp$bGN;_-^PG zW7FD8#iI&rH1`87=d*9lv>7CY(QSDnpD+p|r)>am9WoZ}l2ZM#y7BfWeL^Y1TYl&x zPt~*lQgjr+CheE00LQdH+H~A;x$wa>B&}MK_RDHr^1+^I`&vAE5 zH^fGpr9CaI;*!s^vio#F39|D^sP8-Z+hGrj;IJ9kCAYpPL$xG%!T?R5ROj$t(=;4N0K zlW+S?iwOe8{x0(?oAS%6a-x9!GpUfOt$Ak9B5ogKhWJ;m?u`Hgc&=Q`)V|wVm}2@P zm^$^?$)f+?pTI!-vaoMaFlC}AO&INra{&NM=Wylv%O>(jK&}B#`*sA^R8B&=cb}Ug z_yu5`sWmZ3dV!uQ!{%AB)?9{g?GSXv`F@3z+P zAyJc8@-Rvt53m)rxfiNMr^KT4UT;kC>a(v*cqq-4ln$zsp1Uw{+IWKwL#aQ~%zBIm zBnzcYAFf)TIRW;!3p44?6E$|OHd4N(`bF~{7NFRZ|71A8K){8kNc_>aU4T{ABTcEH&nS(WU0FZ+)RVtJTFZ&>bl2qQ=54MsACbrcmU%yF{&Q&WJ8gqB3F#;0-7IGQj*Rbg z3%dW(UbN15y1Hv~!Fi$>QO5k;m75hNbC@rkVA!m^*72Mrap%SJbspLaslGqfPpkmv zBQjn<%R?YsNod`Fi-e4~aSJd=QCb)2@J%mcyH7OOZA$6BTAcTD<2bZKNu^U)k^uQQ zzQ=wd+534W?nAp4Z{8ghS;{UB@rp z7mg;eH;eH}a+9Av_%n^-LPQ}Ti`qq@y~R7FeXxz}nRiREHL*Xk6>K~%B!;ynzx%X| zNAI5Xm9R8Pb#;%yxlgo)#x|ua7Oh}ez`Hn{0@;tO{cYU^Gjq8}hn(hn7TyvdMZs<#RPf&O(+W^S`hK9Jl{AD)hkda8T{xw_^ zHq5%9SQ%+#c`F@F5{*$0lg;QhewpRZyj`TP%6VE}n&^)A@vMIOtw3rGnk7#Q=7L7` zF8WB)bx{}m4-gq-Wz8=Krn@*Sg`fA*^jRC2o4jf@1Z>RU4UG&`9Cuhy_Esbhp+6-f z9ZdG4wCha=3Zs4{^l7H2ru>H5tOd}8ImjN1UyD&7PPu5-?$#f|lgin)o^3nkb3hs1 zU-&k~Dg z-6!Q|#o7bEd^qMLIL}LW=59gBqu7oGy@%wbYknIG9x)J(DNGAev%(NvwZF;Y+~RuE zK{vUG$x<<9!|_~s+x`WcPU1_l8l38KQo6n%_a>a@hKvw!O}z}8Rp!R;iZ zP{-zJo1B*Ix8}NXZT)H!{~QBOxuFoY2bk%>r&?#sd5sEk%V$0%+lfe(e1?=)aQlE) zxCken!LMG7tiqawER;WQwbuz8{3)hvsK%M78yYaiiG=I|Z=2VC>C)1K(SU%r`kv&M zx4KnNekRuB0(q$AMlZb1LmxzeM~Kgra|C7o%zG4<6Kl8jXk{gfjVdVeIOfsSb<`)>?6622$sYI3>yQ+x*$LUfve5+91)bZ+X-)EI zT5E#a)5e&~KEp*d{*=p4j41v`eb{!R^QUJGCf@i_+yS)zqIa-B!KGpA%b3p>rYp}T zw4V%n&PKedPZn@T*Rg$Nci6yd&y{{`mL_6MacC$MKN+O57Zd zZ*Q5=S}*S&Gb$8$d3GL&(@~S|MA9-ICP=XpjU}hnP#HUsfwB zg8W_IWHhw0dg3?Z`->OloxKC!l6y$`qt$x@R3^?1PBJ^}emdey>fxDRS(M*q$Easu z)Gu*fJ351(q^nr}-Zt6YPlLWKL@NZzAVw_v^k>Eh>p1{u$`$QyJq@i_}w&}zBhZV{y}FA&aLatrk6I<%+?nPzXUOX2HbI~&(=B)^BY`*c(FS=27Vl?!nsQ(G5bat<~6g!u6red z{pp|oPA>dHMT=#-Ejfm^d9ei<`f(ij*mGa2{jq_@!hlElFuNMa_L&2a3n_q zTXxTFzrDBt>>>~(JIRw)cPCwwR#7b5u3db{jeh63<0Scw>`^Yeq8y9`of6WtO7zaN z16`#6f4X3T_dTimZPvo$+?eVKgg$<4Fb;p5#Q&p<=Yb;RR4=2d_=cTj)(=I-XJ30g zF7%yfD(2sa+0{-A9 ztzXDvW1m*Edlqjzm*{GC%s4hb;VPUsv>IwrYHpVRkY5O#AXvc5gxh~){-C71$*?! zFxSW*jT317Nj6gnS@B=)_rYbQ6YcX}mhQGwGLEF8(k;OL;_ zeF$)BJNnBjL~i7zvZbJPFVzGg#&(R_gT}i|HS>z<%b&7@=5i;hae_p! zd}QeibUf`j`3Hw#_-8ehWYP*;QIVh@cT~tpso2fPHCH6@ke0mk2TjUIeVfib`kjhO zk<74+5VJG(FR#ruObKq+Zn?1sR^fy*x_&)CinKB(G5P-Lq^@e;u{{s*Z7JJ*eJv6@ zBld9PPo=8K-D7TKhWCdzz7o>f>OIT1_C5Iac;_3C85|wo(B}jf&AA0tf=->nI}i8Y z4IOqjE8BJMZcO2&DE=}gQIQkV^^su0JsEnCCyH!a3O3X^h$89n>;xCWaZm+bd9;SI zt)G8!^hXV@6kF$92p`9~_Wocxh1YM%=lR4oeG}kLb&Q{7PWDmX-PT+x8_=kh(*+|; z7j#LAn@Op@2r<)jsMu)X2A}Q#G#+o+k93$)EY2mWAZrAAXPTA#?u!)AjuSfjQ?WCu zfBjB~aafM;bxxdk(yG^(S!CrCVKGz*loI1*xnMvTHq+CdM)F%f6_@aBv9(DHmr23o z!Y1)MLej+arq4#m8jdlJ$0=XM*k%FXAG)#|h2DGbfb9+R?UwJgrGd`bN%k#X`ahE zrRToVHBh>r9X;?x9S>AAShc5x7?`VgHUAy}y(xT^OjDpB!70A^QQYtM$)DcrWjO>z zW~Sv*1vC%zJ3hXZ;uH^)dDN4C?{~dyZAii)(_FKlDEi$2C0E6PRxiJp+n545DDu`##O z6T73~IM|VDT{)}nv_3NYS(;Xwsjxrh{s7b1!nc>$!Vp;2mN(vwf?QL7cY^iSR5}SP zFNfmxZt7cM@Pe=M8NmIn(BWW-(rVTvu-N|p^=4n9S%YZgKiZ= zm-vlJWsnODC7(2z{66ESx)ou8trzx!au_g zCJ#MI)(z!Pd6o_0s@o52xro#RLDns}?Ml#RTa--t%2n1xTy?u4jQifuKNc88uryZ& zBirV&|Hx-OMJ)iV41i>By?;N)E-0h2)=$)_dDx+8ZuuHp>mq8E>0=`$kcK4k+J2kG zgjxrDO~uS+i&x;t*HBK!`hJh|IevImord@z_7}aDIAUg~N7a!c^3*o-jbfY>?3U7==iX7Zes1Ox%{>rJxuV8k9V z@0y};oI0ReI2@Y(RV0-!vIVj{)h^p)-xDFr6x zNNCvO*9(4gBegZZ9@%2Hq-f6^NkE&i^_3ieDM}LrN|Tm=5%oLO@orDze1B^dm4=Y1 ziM*eGKya&YvLm3CSM(IA`v&3bHS5bazbL*TY9LYlTe`?3lEoI}z+B$K&5hM%W5KTB z+7;{Ko30#D3UnSOAgLLm>}S|-bu9@-3Yy=3-e10VMz+Fy1IkBZiZFAc6LT6LF%ro4MlRb(@_t#}D$; zeMw_V%bT4KUEH)xmmVUw3?G6^@45YToPd97+@Q<1hO&4XL_gS>2T)rTmZU|Q{m!CI5Tvg(su~c z0I)ofW9&unE1BsNB5saoRAp^j@NdbT2Y`5BC2kdz{%`tHF%}+)jP5@~wH(em!7^sd zPur0Yg+HWO=DoJ7MS?$YOkS11$GRjZQI8TqrvQee+bQ==&(79R?XM+A5-HgEDK%*dZyhZd(Bu zT_#T}HH;XP;_n8Tq~R842HEliQH>XtD-=TZognmcDpX@^v)p;)FhL`fKI(vyet--( z6)a$eXc|n^&)$}C8WE`7(^LFH&TO@%e*guSBY6MAu%`uQ=}o;XE8A~(u7c<(4?}LU zOo)1KupG*Ja9)D~w0epzpiU-vpX@NQ$H3}9y;D*4Ke>tlm@~j)PKYt+Zj=+G`?5D` zmS5wf%PiML)?*qTOuygycgi@thwuP{?7j!y9fp*7{ZG)+$XDR%(UVpVPfQOK@ZS9W7l=~pbcx1R5dw(y&y>mSX+=FyMPibx`RwB&T`6N053 zVOfjs+SVIz$JGiVFJWK@0L+Gg1J#sANm`(2%!}ZcHYC!QDmzE^fRZ(=RP_^Lz3cVm52|oaoet<69Tp=*Y4P)$I z1pDMNyk?J9-(8so$dtEHJZ~enT_W9I~kYCCff4&hL(WyTx$-2U$^&2ub&_rhl>RdfcW%vVw~Cva7>ni;y$lYB z*OW-*O<_I1nWNWc32CZJ5VW!(QJ{#V-d{h1gJN;)jco0Qa@T9|nw{f|deI6?oJP=5 z9pod*!rwfGTlW7tMGS!`aiL74pMG~4t`9nZDiMONvHj-UED+6al8?$C$}3MxaUyJe z09k?24ya2FK7~fCe3lMg@m-PXOjUeB0AhTqu2(=tGo0R2;>`X&9u0Bkx?Ry=bZHo1 z6ok$sA`IIu{(1<&KLVg%fzZl}&qdhOgvq2H1=fV%FezIve#aj90{J zU_S5FGjc^k;%T`5_*X;)n93^xDG3h4P)ks|6zv1zpt$;8qxI%qKep&EuM0jGTgb%@ z(w|8-RyPaUYC%6>A~YV_H3d$zFm^;k8~ga*+0?~jopT?W~MU{S6fO zlDH0%r6N#G#;777*jKtSa3vOIteIe#z_l%kbtyj;v01wJh8IB7rc{43Y3*bqj~V^J zRRJ3SDKnFo)_9oU6(fg~xgvVhdK%m=~RY@3Rlz8lc4;YBAAA{Bg=iA_6UT=e}B+ruA#^L7f{a^>v0A?w@zZ>;sp@`686n0E53@b0Su z3j5Qft7I#Yp@VSs-hoDLRKWZ~m71!)dZ~@3#2|x@{vFHmdq2sX z&%DJPbNs$7KC6;ICFQkT6vivm#HY04NJzJ|J{qeIT8ns2n&&Y5 zz3w-arou<=)duF5|ClpBb4&nlP?0rKX3_t2{Kqsg2E^C2y^yi8k$?UE_<(h-Woja~ zQRi1zcI*8!8qg?gZLt}(-}1N9G3|+2J|witV6g#j5Lf)~k=m6|dR=3(UQ5weO;BZh zWuMi5ox**n@A8L$y!wS#v-wJqpvD4NDhR6;$*8>%u#}T2law`1nviMLqHC4v6IA&f zs*U|HuIH!i?w!j3S{)LC!M&hE%KQku5u|9PsAciABA#ds>c`FpUY)uiW27*EikbbZ z1Z2A7+VPvmQ1IK$R~+e=a~B-W7{dIO3Q$|rSCPl$z`fW;1q%3^TO{wboP`m&yji}r z2ZJ`r0{38rS|h55nC^QViA^(~*mh`6NRHqcaJ|k$G&%@UlH6sY4d(df6YDdd{BOD` zS!^qrqGa8Fq=wkM+2XX{FK*^t3M2D$j+qK04kh~U&Uilr_o@#p(WM?j_m0$EoI&g8T!~qy_8m~pZ$iwnUX}w zD~myTA`!6Qm$@}(a5Y)TEj8DxQC*Z#kE_0SBW{2rl~vMVunw}PY4jIgQXc^i`rxXv zD~}ESU#|z{D=5?K;rCPZc5 zvhQWdz7J#OJnzxx`}}^_^A|jIbq#0EIm0>cbKkG+F3i|admqa|76^j&>FQ`)f*>UL z5(zOgf|qsQ?j7(#?{vZ70t9`GVBNjW0KON#sdLEyg8U^R2pb?X&k}L#Cq1SJgX9dJUMkWE|~fb zEKvHR4p{~Ykpd&+Kl<5=e?sQw_PgHEF-3@0<+weod@cR@wU*c`t_NL8g2S$oNv;o< zt|s}V!8b-WRE>O6EqV-!bzg?sAHZ7~vl?57z3Ss4zfL%k_r!hryvEtiy1H|s+~1#a zb5besUr$z9XdI4cX2wiU6BvX=|NrvmZ8BFCg%7vgWV^UCDq+O~ZxE`zr%P;i|wi2S_WNa(!*%gh-ltu9F>a^9=Q7}dNI$D{wGd2*x0HkT7(c70xx z5;RLLzTBSXl3z|xT4qgK)p|yC{)ovKvCvpMHn)#QvL*sn8KRetT}e0qC;!}Oo|rz+ zQewgs!|^!HIw8%nZIoVYM5jaOAvuDVTp9Ni>d4m(ZGY{a%7HDSNNu-Opp0eyDCntg zI+?F>)HNa$BeYUTboMyMEH`9$IIOeVl1Ya?g@gN&L?c6))eZ-BYce0cbW2SQ`;#ho zarK3w%lNR|Bl0!uq+WGIX0(dCI4by3tvugy(XF=#;wY87o{FoTfw$rayIEtBc9mK~ zyBSF}2%@uJ&i!j&j?uGm4noXdrHM5x66?K9?SXmu{u0lPZsW{RB3bxgjyK&LSiYd{ zGVI@4jPF#({dG)<=!!P7O+X#DF_t#%o;lLd2_L(^U<(z)aXQ#cLJ;X)A`gPzfxCL+ zNc$wkG3|Re?%jR06@oRxuDjYrK8oOzIMUW$8!c2B90{ZGu(!_^@i7f4$W6%z)hkwUk&M_=(GbZXwSK_RszBXEa` z)y_1>g!8)l%Czdk0e7?XhuM$p3R)sQpjZR8F{%sCB5aS2v(5*BEN=PAu_KaUws@x}V{el(3ooOp;IKVS=LDahDTjMx7_x zq7X%MLyDQvESv%nrAG-CSjRfQyC!Gg14(5&b94+cymj@0~B2qAsbiQCT3 zi5tEAZbH)To|gDAZA=6beAa4-9Q8ZP&Vr*M?N{RHz4ft|Yl~aWpZ8`?zM{9+k>J!ln+)j~lf|AbC#kGqk_*eSCtY2tIk1 z@=bxtIs@PSnY5p($o%_gkE@OELAx*3k1bC5a+v5Z?OchKyOa8D`G*ky$8&=B$vWg$ zx85yyH(g8OG=y}0*wtHcq*FJb&v)H) zsPiV6KO6@)!=%$L^~P$8Vz5YHllQU$%Cv}^!A@)v2y02}u9HZvdQz2lP zWXFnJJjgEmOyCo_?0!ql7YatZj81En{M$`r8%~}N<%O6P<-H1e8b(p_rDnDPA9S&> zw?M;|Yz-=#xb|DfeY2kZRSGLHnE3FN=!*MHKkR6<+rIIea0#4W3NcCMU3ZV$uE>aA zRvWasvzsy%BFDAm52;a$3oaGxBiGM5gEy$4_*1af`XEUP~g)j2rmvY6o+IsfT&JeRy z>h@+dQzkItr8_dzZTD6FG{Xur)@yAG`uq`Nvyu4Fd})W>l)y||wK|*)D-t8#?}+Tb zBTgOKMR;3s5~YdH2OSy-qWI3x$CzchZ86#{MxtNJUr?zn#`LUzfYbe3&OaZ2;2FS; zR;&_t>lVZN(hJuhX70cq%`ZkWI{nFPO~?b!N1~sw1Y9;u)Oa&D;gk|+X?Kz(az`3( z^E0O%hroX1e%f0p7s$B%g)Ct3h`v;v;m9e+APr+H_p}qr{t?jWz6$w9WyB9=?4}rA zLuk!}6F;(vYe$S(Ya{XUDH{{vwKY5&X^f7RjqKELeF){qi`4oL5J=!Zm$eJNChKVEOP$g6; z8hOXHY~|xrsCBMw^3^Cj)jy$X{pgD7Hk07F6)}5lL_Ei5?FTx$$KBTJBUFv3L4TFx zRZ%mTqI5zlxa*3_L&fHTLeH_EPJBk(jXXkaQ>D-y6~sqNV*|J&o9SkdGtdmLke3^u zkk@%8oMw0D*J-cIq7u0aM*_z$dN9|SK$3Jd$)(HiS{LE?w>RGGgh;O2n##I#+nTw2 zQ4fkq>1%!~7p70$*s@{6z(%sLUMe+cr2yY`5jkmscV_BDv={tZFk1hFv)#yxcI9f{ z&u5p9zU*@_z?Ryo#fJ+Ye}?bQ#A+dm9g?XTQ80E223zOJt3IHjkE4hdmXEyS4`}7i z-hl(l+;ES+CgDmEIwQM{;A6t~VQ*)1z^oH3_)B7l(1r7Iqb@00(hqy&%|`^5WG*}i zDXY9}=Y4HE%3HYRMT*DQWbWmO&K*jl5u63K4B!7_^a&O)ct&4(k@&iT*3U>Xy|>n@F6#_`kw4aLDSedr_Ndq z_uKbZvipv*>U%TWTaNLI{iHG)QlX31*LGd_Czx`3zbvzP3#1$X$656X+KPD)G`(kV z!rStCQi?0vx#d_*jKXgx0^)&v7M=B>jI0CBk5s%uN)yBG)`bkM`)(!| zVJEEBxcM%gO}#Pw;&dr@#21)Ko_H=_V_ZF-fR3X*RH>%lqf~O#s73)cMJvd_LphAD0ea^QrY-ve-WC;(VY--YzvP z7txR6IKQ~Esc`+$gwoOamS;gK{HfoS6l0@I@ZDWFuSw-1?oD~RqSP}JX(}Ifaric> zR4Z5#A1__54j=0B|Jtw`(!##}X^UA!3Z7XPx`Uj^!d3Zi!n;dC<@gg0K`z6HDyTA~ zad@Niacg#@>Vsohh^Z>2rw-r)P*GelpPr{}sd><=nBaXivAZ1tPlg8``N(huG-1Pvy5qEsVeG1<-EL0VFc8$4|TAQ z-r_!4A!DH+FYvIZ0dfM5TBC15W`EuK^L`%_%=j1;)WIk`K#vyTNC?BZaMEfuZj!tj zO?zq)@lvtrhsT00D1qax?~^avkM3@DuS>OjI0YRAzsloBuUmr7YIQv@uj$#*3GTd1 zxiOVO^*%6gq7@a79QOEwyS+W}K&Oz|&T=fhv@wh>0hYB5Xan2ntvmE%=}T`)%($17 zzrH0JZL@7YCzdgLu5OdU^H>m{AB3r5p=jHPe~&sPEq$B?+YPBMj~G-{rZx5I_^mtdoD`;w%M&1>N zB<-!fa;x!MTc(D|#tra$ls=XW=PnDNFt&<@6?v6E{IuNchyR*M@KDA<4=@xu`75($ zaz%yD$QH4t-z*rI4u9vPH~T!;~lI-V4lycw6U4U5{$@J8w|(}yY}~@99kJOV4h_xfTH?<_F2cYPK|F9%O zc@Dsmlrn%NNjk<#oZoH!n6HUdFSrXo>@zB!HR917^#qqJ@XOcEW5`Y}qzY6SBltpZ zN^7b3QE$BHV0F!l%S!3Qwmw}}^#Fh?xx=O%f__Y4S#5daO*WOg*R_!jgI|rn+NMFj zEA4j46Zw&rc5dr(SKJikM7#^@?@o;B#Ze@x@7{b7eg@(4=iG`*P$lyl*T6oH2(y=Z z*P`F;9P5Ja{J`J#WlpQyKK@tQvQ_#OD;sRt8VXU}b8 zkO7+*6E5^f=}rRt$UQJdQTevawE+^bw3^JnxFw{CI5|hPU0-MaVoxueA%i}`pySOv zkDQ5Kyzj;%bf0gs>rUz{vf+or(_>9YDT9mMR$xg-O+el|$oTJ9PTEGrxgsSl|+Z#@X#P84Wn!Y@d9y>;^JC_IUF3VG} z)DL?ljK481{qWJdlZEjkD?%0<1tt8WOE~-bWzFh!M%r(3>r&(=1b`fgNsD`UGm}jc zK6&}wOx+k7!zO9?w*CG}m!YtYwzuV&s3iSMz1`#9$QA$IZ$=^}#(-Bg7{K$9C#4I^ z+v1ZJ#q2TUts+m%!`Wg&CZ!pAt_@8j;hTere{(5WE)QIz9>%zcqn`ftwiK=l;^w1Y zT`*w6Jz94OVm0Ia{JfYj-9d$}2a8nbV0H?KJKrvcVeV41fW$DcytBWy2O zuiDz%o`P<^WANv1X7H^+wI|!<-7BFjVxPB#iZ3J)lT3grcvy|`F!x5mt()~M-U1Bq zjRr(HGKCM~xnq?7Id#|PAIQYz(SyB5r=Nvky^kv=3Aq>+g^a($bd-SJMJNozc|_$R z^jc9mZbwKmZ;e&rAp#T$D1*UWgfh~4$O+>utipP|^}wznXGqP38%WmOFViRxeADF(GFd?xAR%1hw^ot@Zg`YdPF`EEy(ooEQ zfVzcX3VLsB*#OBRxcEiNGW>x|S?Zk?>YHXJ#-Bm_2qsR~J$lAo<@1caGA)RZc*_O9 zGIDb8kzr7D(EwPgF%#&{45;IUrwum}{BSu!--)xMF%x&IY&V_W+sv!oBrjQtJ_pD0 z3VFNT^zAb`x#DiSLy0)~LmRT(hTeN3b3uEoUKmYk_jgtXT>0en{JZGyilmy|loxVT z{>R_}Hy~b>pm!9fesia)IN+}Beq3rA1!Xrx3cBfl8W1tx$$3{!dC*fyIjXfq78;bk zO_(PGj4y)rXN#QQx4g@MKDZdQn)1tq^P)Q!-^D7YFLfR1mv49hH2Fy$ph<0nWdy>J zIwcgPzx(_N{2Y3A$2Op9?q}Lf{Yy!vzeI(U+AQF9hJyRHP@QB-V-l53 z6WS!Nv+JK1j*exIJS)eK?X@Z+oVx9Ezt;7wiMa4Fe}ZPt38Ss#ZBRzO#y*DeDHkrR zmO0_6L_uBVov$@+NS^IN9RF_>+a7R%>D{`vm#fU@0S*Tb8VsXhAQ0 z(~y|6Kj<2ivbwN&Ydp*|@Y3AdYbVQ%_B$A|Bq<6^+y(TV&JH#CfUddnl@g37>b|?I zATaUtZ-|^C>S;0KTK7r2*1E!$8^={WTCcd3|J7OAN}DH@7gDI&30j6TImN^yualso zgFTfGtvnw&UA7Q(c!l@Qr>DravZR6P1bczz%JbL+Z+{*_gO~bQAsu=0ad53pPi%n# zHELRThJC#}xBcbEinv>e+^TuM7P=zany3@XFo~G#SHYXT0BAMi1ieC*Om0!|n}!YfCo%@(5s{gldGNzIo^9S}eg(+Qy}dR1qzm z2NrM?{eph-AMx5wN~;tQgRa>tQ*;e>=p+F|dABup;=>u^Qc#>ktAKno7>YAXG46)YHEyo`FXB4UfC;Z#-~ELvbB7!ZVM&Vkj_uJT8;Gu!UnbhqW}&L zQ3)NH%N@hb9B;gUz#}9eyChIdrWl=Dk#`%IuKX=2EX%U2D$;J{3P9lI2SdLXJdO5m z-?OL(G=lbtiat@PiH6Ed@X=kkTTQm8=sQdplzM=6kCo@+A5{u}&xH%$_ULky^j`s=*0pw=5ruil~Cwb;UGBgv(l0YGFXljNaT{l+hWg0=LVa0C&H{bpcp)Ih?k@*H0W`08J%! z=~FL|Qfv)eQ=-3eppAa@8QZhiKcy=GTvpcuszU{p#InWfQw4Q)*D@{KHkMfhCh)ZN zcWOED=(on~M?ezp2r-~{5W3i&(i8rcI%olwIomkuaw@wVL82RhWYCHy@+?&8-#D5-bo-$=vj6gmTE{8WjJrj+}pvxyutrU)jl>>3*^4+}CmR#+&^6I$9sLI?h?B+3LYoXc0IPS-7 zRP7Bi)4OC6U-nK*f;neo0*6IK|L5BPcOA9yTnu~5IN5zt)v7DxQbpH*si1D|Zc$x$QOqFMk!D<$fxRq;L z4perN;nv0uzqKm`q$1A`UIb6>ehRhAjS6)S?;VxVo=GH`YsuVbKillBwGIcsYrhlj%hlX~N5|q^&auc|l&yvRfX0)ejjj?Hub(dvK#_lf;Y(en*_IB)Ld& zj6O;%CVr$)Rf0(70Kk?1Q(DAA0*&^&)%3jXlrJndO0r(OX_vl;xkJZ+_2{?ll+l3j zUzv%Y4X`*vVlE{HptxMVR3I0c9d3Bg#HMa|f#bWf^5I<+V-j7~ITol0V**${4Fk<6 zQ?{doBi(ZYQ+QM5?7ozF&Te6 z=TZFUI}ma2vJHy^P1%qkMCb^lSkrIHRWom1==RXUcVb8lGb?{_*Y#%6u6)@_#NRFq zT7?t;`FAqDG?++D##VW9e~j#P|l5Pc`OeD|1s7f?H>ld z>!Y%aG>OIO`qPYD+ceq@|4Zm4a$Wrcq(jy};5?wiJzunbPoX-6tTIE9mc0BAUq~JP z78T(o^2W6~z2`yM7twtM`8#J<_45u!7C_@sM=~I8-iu%4LM-z5KR+L5kAHZSbx5<{ zmXq@8+b_UeEqh~Nqje#$V1b18RrM>9wFkgN%c`Q4X|1LQ!70TA-W|c9(l?lk?ba=K~2bH%l!B=g3sP?WL{^eI~C;5`Y zdgnu*r%_p2||vm2)ByFc*xZyD44krPNXLybJ#@$ND1#d!&+s#DG7i&Bn&{}Q}p42yz9Fm$_GcHe(r%jqYb6s zDJwu-F?lJTg3OrviE-VYr~>MWZ+|h-UUboT3fIIpx=^{=){c|GMu{R8oPm|pTxe<# z+?hAzl5*IfhH~lIO-M3Ss7JzqG|=3$#p+(=5D82 znEM58zNWKBZZ3DfvT|2FCURH5e{`(~ga7&NcwqK$6zr~p-u4DQ6t3;j_8^nRW;U?8 zHaq_mu(JwQ-)EDgmVJz(i#$M0s{pGzgA)&kvB@V-MOpN=bo%9*E-Tsd-Zkdc)FB0i z=F3V?Pa4TYNva>Zb(U1YZc=BMWJgzLg0CJr_gZjaW(h#F9gebhkJFkso|xLg06a<0 z0r?05yc9SiDTPfwR`=PIDPfD+9WQV>^X|OvRARUrbVEymelv2OL%QSR-%XbmRBEn` zFSwv8=8syPVlR&~t!{xraoN6{`Q^xTf+vy-+ypNIjQb1TFthbJGP7sld59InPth9{ zn2{CjZ#5D~nS=@yOsDV#!GD>Tf0Ul>HHsv z&Yp#3nbLL*NH3}>Ew8H)0rTSYl1X&;3(BT6 zJxhEvH{N>Qsq(4tyOp4;f0-kcBs=&uO*iPI_bTG8H1?h$)_iUu=#BLtPTPb9AV?f< zDCyJRxvReK@IU$wDtrYX^5d^Wz7tp1gxojgZfg8#kxAO_@@N1x)ET>u=#^(>%X+t6 zJa^=Hq0TiPGh6LcTIa6QCN(?o*ww0q^@`NT6bC)wZ`Ls+-@RB92T)_qd?6cgU_J~t z{oF2Y_r+wvJ&|El=9r63-_^>}?VyT3BkJ&PAx-FQBeXIND~zs7Z5%X{ zw^Kg(6IsHAOq-?ydR#9{M5X*G)|kx*ksVLup6AErk=|1$uX;50#MJ{FLOC%#%Tgoj z*--k7?#H3O<9sKlEOWTw$3a1t7JO~SB41Y3g3`J>sUtEizn)Mb4T#k9ec0yI zX?oMSO@Zn;%%$pOVEJrbGE$wSCkdfPO#vPH+(MCFdb@m? z3o2LROUl0=dM)jJZ8slyd+17KVqY-}|DG8wN3;Ot<{sCDSvPWcMaKht zM;mqe1JJ$QPC+LuA3y3mg*XgdoAaO411_EE-j8iDaKtHhjoYpB5%vhp&_f?$0K&#= zWjLq{j(v;+dd%m)bC$k4n>ULkUUr$cIDb|Kc5U2uIndFRGge)vYMZ4H4b>W!!s)2C zhgn~c26yizsJ(SmJ3o72K!!CL&3W<5hq;Now=ehEw=q8*QCJbg31G9v!(!fv!GueX z+T0{{kvr}&*K2SbkCJX?X$YtMRU-ES?MskGEjM?C;xpLre|Aa3xp#Y%7TXV5$?<{CR|_PGjpr$k_h?XU$8^#;y8!G&t&* za#CDScPzovb~8@#3MV97B7@#ZJives4t`g0eehw~y{ms8W$ClHn9&u_iUrgb6G6rQ za^%*HvKwPZ7&D+(-Cb}=Dv9D|M2%a(X@Q0^xp1u6#}#Pk`kr+KS?;GWXu%OWw$$Ac zLzpfMx8}XWG^L0{i;AFaI62aI`w;E2=VpeEou5y>4C?OWTI>5)Tzdc6cq*tMlS_8H zM(b_QKkz&O63nAFFzTjFv;I-A`*Cns?K04y0=Wve(+0scsThLl#hZ|mx(2NAaO!WSSm9vAS+ zpAPM!cG^gK0=S>n`>Ep0zXfx9tCqbGlj2o3TahK>*UCRA*EGxkaqgi+U||9|ZD>df z!gmK_?M@4z&r1;@J7(MenRKQ)E}j5S7m1V>RZVZeyeE< zVOv%&ce4Q0k@p4^4tArVMtVhRXP)?O(dFvmjl9~+)2F<-;MWwYf*{! zSF$7*P1#gyTR)F>Y8mZD85&Wg*2R#D7eL&A|F}|5)Aw@)e7C#hZtqrftRA^uG;5?t zavJ|heLWRO2iXJ0`j^8QYJc%*iBZq7U&T0p`%(E32Suz*0`sCbB=uX;u2|ppnYuY* z`aS}cKBjxf{}(5GlYgSzRNf6-78yb5UF!9xKh*-(Tjf!fHtujWxOWnvD%5XH@as1? z=()!l6Ym-)@v}=1UEQPnN=ib<=CA(?4z5gL030;BeRhH!A%n0O@Tw=QKlD@EsN_xk zXPmS!u!^?{{j=8;?AghdPhD`6GR>#F_&kw{Y%f)N5d4XPp`G2CKAB#J)MT3HPWaS& ztBt8M6@M!xqPiY&XzNM-t*KviWP*K;e$4kbVKqPw5Klg%g zYqKXNQyDO2-ZxHty6_oPRYVy&?KQ@=EXFzSIAssn7#wBVLZ?Nyf zJSnO(_$ST0Qu%k|e=yH+59U26DE{>szg|z6Ie%g+it2syjo}voRM6x*hJ&J!YV@76 zhh+<~d<;Fkublpac|`!`?LvhQ5H&9X4cUOpy}o3P#*ra1<+$XRqB1YPxw={{_rrAt zxa0+lhPxJ_aKk=ig%i0-)VA~mFE{#YMu!z3Mi!L0;OB%u`I3;a9)`y@ZhxX!|MOaB+j2f zo9X`}7UvZXfvSf{f>U8O^b}(*tl5pohQe2_a?1x_A#@yoJZn zpHJgX_j?m8huqR}VK~@?jN!!RBt%9$h}@SZC7mcw(=@*BHa-z1&D$R3)G4pL1#7Nc z-#QBv-fRgff;ExE7Z zgL_a1KlPYCTsfB#gaLixqGw%0=eHJ&@|~^op=6471oXBGZfCT6WdvjQi$VepK`YYO z;xop4*le%Dhb5#Oa>(C}>C~EsuP27Q5}CL-V)sw}KAFBYRcN(hvh^I`Rs%LEAfWI5 zNW$R15w_{h^zHS93ofb?gDNc2JdP*t|;2SN=v79L^KntEFTQpCS@eXX$eF-pQCA;MO6ZscQ^!8#{ zv4F88_Ak3x(5##^65sHyXUs02<%~G-b2KR8yUEbCwJbcxhXG(OWjM zs-86_)ni|{Ljo<+rKh%gV;x^fyTNX}q^kE;;|Xg9z_Mg%z>tOhZlx(#?A&>=FyA>v zuOaq0O7>BeXryf32+3lO!J2j*Xi=n4YG}-4xlGHUe*&BQ+Sa8Lpzd03G&F*p*+zCJ zWpPn;f%p7&nC^W-Kw7P+??B>*yq>eGls{*$N(*xLC{rZ*MzmSFXz5^Oz{J$H{;R%gA|l^7K>##= z+k(Ng8_QE^he%Ps<}l@$iXm}CgF`b4JC9?RphLEo*>D7F9$p-u@L+y5-4bPmY`-O0 z%e3EKWlRg-9f|iYeOepAzS2*)^=7?5uw^v5ckl}EiTRdDe53Tg&#nuNyWjCYkNs6j z{BXb8W2AK0tmk=a+4S(QTM$!08W;0c@-CKh9|f`zaY>b`IX7H3*QqFf%I* zzNdxDV*#N^cZp{%hRgYt1E=>L9sItZlAW^ai37K?2HeV62FDf@KeliZm1T!=yP6Hb@9VZa9e&Yr8(e^l8%45DGyRthD0Z= z!K#eC=fZ;+yuHYUOLAFNBnJ4PCLrZx5RP4XS#}E-x}pTX&&K`q;Ig}_WeF(7*jO^8 z9NpQjwgifv+H#pGAVH3z0o{*p-!p^^zHf?2t!Xof=r5i!;{tuIr@^?$zoae|>a3TOdMR8s}z;k;i~lgI{u z*-la3@Vh~uUg$9EyCE5;>3y%4+^b%BwOkwf*Y&#+(EZ;7ycFW@Ie;5Wc8(21j{pp{}G(Af6l-L~Ca3rL^IS+oN8@fxqiIO@gb zE0F70ilcm7iN5!(vGvNIssbfoAxG3w)g5qOw%I2bg@-=}6ThB8a2?JYIi2D2xRJ)n z2Ma7;_*n4jkehs~SQeaL3F>`YcU$h;OKkM+W^a(4CPw8v=pu`r7Zba4@wE!m7iMk9 zGU94Iy^*d+wE3;}{U`L2HiJM^5`;07B;#@=Ib#>g+IUmXuoso*;~-T^_Bf-k^*|;u zUmA-MDRN6wNF0&vVQo`FJxxSR4m(i2yPCS7$>D<<`KJ+G#d`#VaY6&<5d4jKAd>jm!&HBX#Gb$N%MzeMf&TR;T9b@+ z;o-%^oF5uf>B62}4^3^{(}JRdXlpVszRTur*J+hZwx4qg3RCaM%o$8njkHD?@}L;_ zMEN6#z7|PZp2jxuQ~5g@Yq~49z#t^p!q&Croddj=0-F-tH6SzBk7Z&E z$%Ej+e~AYV9s4XQXn3{YR}bJ4ff09~`>)B$W%`My#R8PJp- zQBU*OIFIo6lQE?pUafB3xn?TY)LwkE z2cdYsdjfCYuCcw3zh0I1>podE)Rh{QjRTQkl+jyxySP0#g)_toD~V)v&BZbB?k#iB zbKWsk{3s?4fmFpg)+u)(yZ*Erwd{j>S3aGWQJpIgs~W{LQ8xv|AbDw;X+DMh&oo~N zTPvfLtD|x-Y&hVfvC)|JMI!#dg`DR z%vr7l12{|ncFS*u6GFhT=4?AhK7NFO`PE?t&@(NR6Gs7(KAy{$0xTnm0$bki_C?>E z+~O!Pim4(86qFxa$ro&KN1t73Yiyl9YD6W6OSL_WyaZ|%b#m18BY;5a!I!#_{r4kc zu4KwRqm|E63A)Zr&hwrE3>Ky!u$5D*TE@mqjWpx3>C3-1uuB~BTDtB#V7s~vfHpoG zrU3Wq{13n&rs?XZ=~ZzfW>)Tn2aen)n9{Ux4V+avAd(^Ci0iWy7aSYq_?3WeN^$9k zjrwK@?Ar%=ICt$nB6V<~lsL^zmq&A)H-z5r)vO0ufIUg{9Djp4F=F#*^WrN()o&ov zpJP?tW_P!9^g}kKgF4P=C$#WZ1})16uIT!Ixk2MS*?JPl*6Iv_-7;J#=O-*^Lz$J8 zm$&xhynLFRH+~%>7DWZOb4ySeih8Bb7=8*$NPi&|f=~2zS?G zQmIlP7mE@AX6GH~wI`sVm09GJq;F4BJad87x#MkV7t{7)`Zc}AeU-GwZ*YH}v8zm9 z+)`0~MV-g&sOqOu5zA8;-62Td<|GS;Ci1ljep=#$`SAHXpItHyRhUeXSQHwkUqj(B z63$O7JKiLYtSo_NSO%n#jP!OUjofPE=}%wy7)&h9B+kqktEDf}U$^L1+Pb@Phxw~P z;xS}TrRpbI*Fvw2?u@Hk~A^61m9m>_6wN_5V0S~4oJSCGLy&`Wz7CHwz^^fwb z44*i>!i?9zl_&8s^d)fLtzP+`!`fEWD60^zYP8o}tIoDUv`#hmV$V2T_v44de;c{6 z@FU`jqR$|RB$uGjWeMR9&xlx~|F>C*4&4$DU2pKRbLzjyhi;2@o5a&7Hw^KiS6k%>DX+7-RcSqn3WgUHR@}9ghu^lkCDNTUN`0TN)GBDb zsPtd&+Q0Vuq}}o&Mu80h@>Cij4!B$a>%}r4IjMU0u0N5&ee+FBE{-n723^x<-!}pjLvtJTc z*=_40Aj2W)$P-e+$DaI1=C%0G^SeZ=bM(zoO&kuXr(<5@r4>XKj?-K`Fe#PCAGo=6 z13iy1-E2%E92|mjl;lLv14>(?`T%jerFA5ay$5Q-z@~!J|spGD^+!kJqWdiCb73ak8|@rSvt0~mfA zh(qik0;y0(g^b{19(3t8RwwPuE$x`F*`RWQhJYH1m9 zppo5$k+rG!4#eLtoNqNR6k}Q)jaz{U_90(MUUX$U_^UroNOikSJoU%{K~R)nn{>Fu z{|E}qlq%VJ58eE8;QjNr|4<`#;5>*i02LZUQ(JD~y1oIzt0+&)7lUqfZz%(m*chs2 z1Y)8MesT(skGw`^A{z*!=ugpUR6uQO2%x$s1AEIh*9NypOBo-WZZk@x56-GPZAs@f zvTJr+^>3hMboqwCg;j0CJ^nWPiXsxf4?#4ylR9YNL zjP@KZ?L>g+CL5zG)#uzogd?3Yq;Lbc)h;bTl_0Qv9k@$u;>iDq6Bve&TNZQU0$wVx zpDZVC^7e>70z+yv|LN)1B)HE82KTfiSPb2`=kJ+JW@J|TEpo*9LW@o1Nl;|fX?c)qU=|_Z=>MFiJ?5m*5**O^xYUyO zv%7dYY%VZGW)k^aap@v`=X(Ia%>w3!>J2+>?+pMT(uUH490zl*;)Bj0VgS+x@eWOZ zz*S7T?UJoRrB@5eY)Of&F9A2a@yBtEC30X@d9EMRB3+Z=sDJxOax4eGkbo*$3QJ$? zP;lye=g?g}kUmJHU+>kUwWNim9XRZh zJ#e;8+vUhZcsF23zb&WiHK}HcQK9_&c$)s>-m_qIB490|7Pi#I?fz&%OCnlxEY$1< z@*z7ZfxBptB0l=-CVW5uQsH7F~0{ zWV@GU+5Gd6rAlDGoiy$MrhQa#c{ zxBumJ=oM?6kD)O0riBASys2l)KVDvqo8L<7Cq2oA`x}^v0Y7q?pH9;OMeR7~JhY*v zT)yN7$ydvjlZ#IO8*&2Ko9}KrQL)=bo{t3a0?O}X(5{A9rc0j+{3lC)v7Ryo7#d*L zGI~k@ki47sQCg0bUajh2-^e$X7I3 z3`{j4C$sk)jNt#TgYoBrTanE28KD1^+fg?W*kw%R@&27_)Mu3uV;iBD-Mpbk-Gjc5NRb)1CD zF$z1l*Im?jQaKhJtxlWO5fm8uzh-s*VQ!6m17DM!s`Rib&b6maCMP+1KpJFtvmX%j z^Px{D;gvw8n8n$6(4j|*B^er&p%r7BMys+m0fVL3y|$#$Vpm-i8c2W-HcA4tUHvbc zNuidUg7m4@kUlc`@;|%c7Q_aHPK9t)E)R==vB6s7hleX9AQJ@p zrBwFp3Qd!Z`@a)D*<(+s1{)3UY9K)3!sV-KMRPF*R5H+&hIWai!{j~}QdIILUkY`v zCAF0wI&zLz4``CApjIBr0d7SGDd&OV#*Qa#9@siGXDU<182L80&evU_eJ}r*L)HZC zUa~lenwdhw-UQ~)2#Z62hC6ekZy6G${2PHqP4fvBbPx?HXA-!Dp~(~pXKj}4zU5{# z2s)Pj7jz86{fNTg?y)|KfOxU}${m4pbR%HG7XP)4hx(hBSqx$ol@Q_J*JtSl zDT?+Gd4!1Smh(24EbQTGlKkCuB(oat5Ck&)*Fv|c7ntvK$hp-##h&eP-7I7=O19=# z-PWd1&n(DG@gpp*{y2k3sDS=hx8%`uAyC+SM323&CN6)LcC)oUqIbkepJrHWo39;JW&YMX%Bm zkQ#L8*&98k^(miSy^&qN9b4leNG6`s6IpzWmL~>$YVg~W;WlD~a~W^JxexU9T!Tm2 zm_Ztrk`E%Sg1}guOaM*F`fh-p+y}q~?Rm!hY$1r2n{}kU!(O@qO@1DZ0hxJq4*d1SE-mFNGd6 zu^gjgDn8ff5Hy$(!AkI9uKjJPPScLS|Gd!qr)nXO_M`+*+v*92#;WeEWc{JDS7xdl zIqlxJnEO`~IAB0pF8`S_ec=qKI>n48KXl{j1RTMeG{2%QimEkC+P-XkSM`r<4p3Z7 zcpS%DJ&iZYujYpoeu}fL?=;_-xQt34;AN$=B_)j|8uDn-e#?(ZW z4idyOoC3Y-ytMOOZefQit8yb(!)5(Fw6QlI3VaItwsqya_Lnif$4&IXpaqz>ICx1* zHV_QzkcdLDls_EG5UU&TChu|6k_kWzk{wu0K8c3zYz#p`|8-YQJ*|yJbkCGm>3>g?grdh zbj=iyxzBtPCmy1~R6XWH@!aVZZ=&Dv`hvD)$(s}TKNOxk4z&Ar8`-bB9T#FLMa-0Q5aNcNQnvS|b_ikvY(SGaGQbg9In7K{uTGk|*W%nt2c6PL&d8%>U zyFZP(AaKq0rT9pRgKRw9xVvd_%# z`wX4ad4Hex@AscG=Ny@No@eg+y07cIwH3vzx^bDn^@rs;=jtBOHb}_27cFT!lC=Qr zoW!u~l8KHgip?XA=V?dz{ZAj~RL}u>@QahcO-}dLLDKzZH|DGU{kB{oc#4)dD5pOR zPC}NWokz}n*i^D{(_wK_kGD^3^4_l(2&IzW5;aV{J8TauBmC|@JOobS+cYQfPB6UT4KSe2XLD@UR)pR3uE&wJ z|6bP=9kIHi?(V#In=Nef71YNM(X9DsF~EQzKKva6lDINsE0t`i`~L{6@toXaz@5D( zQ`^_d=XHU4>D{8RlHwi?Z?= z*JKI|FUN+zZ1l|16U+DbDEpF0BjkzImzS%m>mZ&e;^vI?EcuPJ7%9w4moYD0BIhO2 zwK)#gW_<+bmST^W0b|xeqL_(N9^WW%JKDijKm5%ODi@!3HV0ZLCake%ncn9eqGps& zaHgPNYw2%ZI<2>=XU`aK7E|cae(7^btEKe#p1Z$f`NOQ5B@yQqJnJ&N%(;?ti!NAoZu^7Rmk1e@jK8gV z+ZNTIvn*M593A}jB9`(5)5sM9e7U9mLtLK`phot9o(PT{mV19oGVJtPSxqykP?tT2+l__?FM1?f%ESr~QXwlj$W z8T~?mHqjsGT#N7miN5R=HBWW{|#z0j4R9Pa7Tp(zUqH@3V|Q zi3VXxTJimD;*}s@i+11K&hU34MQh~yf(MNdl(Aj~B6qv*W#X&B#ltdv6ik3;OTemna}sMO=VY7c5$$pc>+9VfkqJiqT~{t@N7xd9uL~aYU&w|sryju1uBkH~M!(E20<78Ndw0>Y zu1M?d#@UpHk|?w|S&{N1mhRIoQp(CvY9>r?;(+~OR7_n)g$*&wEsMebi;Hcu3OH#S z(KInjly}?Jeq+z)qC$~;h7fm4#IG8;0OYo}OT;gYJ~v#3co%-O%0Fl&2fk8B-M&rn zhD&3;v)USn!IrsYY!=(HHSQ4nc;G+r?4?Q+sB;~0F7DouC`@h0H{H64yHzE1_V0{F z1f|yS7ojnneAdtU>OYi*)wA}LqS2h9S9}09G==4f94V-ELgF-%9r^vOoH9LYfq!qG z5{)_HnD1Y9t-5*Hgo@+ZO-l~IrDyI`<#M65pR&G7+lw;r$;7)Pa!&YVlG`BpSS`L; zH(qPnoNW0QDMIDTITcvl{8ibHEg`B3Xz#IER3#8=D5XtN&u#YZPMA#QqwYUUkmjFIh^KSW@1Y4$c&^GA+isq0&QQ+n6lFHyVkb^Xw<}X?h^-JXZRdB*!cp@U0 zVKJ<)7Ko>Ny9HwL&)nDFJYmXD!KZA$Y}8m5Tg06DTrT@huLinV=KF&XXHmpi-Kj^p zs89YPIre?T@#K+2QaLn>O~-Obs~CdA<#Cxkl`eDdtI6t6^5^Bv-Rp|G50a}gx?G4T z2(e#oi}0BD+!*XhsWE_}TkM&D1d6hFy6>+kC|sxK;h0dtS06t|Xyhgg&a)8waOne` z`H5D2m3xc#z$^!UKgG2pmj?hZqyt_M*AgEv5UCsHAf~0p8$bWBStPavwpnO~wvX_P z8_<8$72PSP5V(mM8k|%$J2kRvtLkzXyms8+XA)QpEop$=0X!0#(nvo$JE?41<&%REF~d5Xp>px$;HDM=btLb+E8 znQUAC_K?r{{WTgG>&No6pPec&Z~7)_2o zQ;u<`RAw1{B>hTh&r-5oS6!!hn1o779uwkFWjEwKE zABR6Z$f`YHYu_Oo&+Ku)S2Lm7I$!-Pr^gmYVKa2_^m?khL;}*=D3{#33x?y1 zZOiGCLzD}n`Z=MBT%CAi6PJe^~1~(C}sF&=!jp0qt803M(!VAXzG|w4%%ISr|NsRxYDXnAQ zW+=IEtv;S!Vj+1|OZDDfYnM#PgjF`Tttqt%68M+shP}6+lj6S7Yoq!*p9&F1bx`1R zLkh1RMH+5NM%zs7I*kJMnw^mntiyc9%TWIjar0~hL0d=~8`di&c1+xGkjOv%EEh5z zfej1qG&?eEAg3Jc4raQ?j`E_U$IR0sXmupW0$KZlT9UcZj%hveMnLJE$S)CSV?V{W z!z7-0Z4#HlM;N`D64g|H=B8OI-#Ayi4qa?{HZ{g(;RWXtZJb7D{2W-oom*sR&@B@!55vDw=bn$G6(4x+AzK{B!=789NKXtFd*C_ZZ%xac%XVdZ16xJdTe@U49cINMw~i4?=wk?zODh z?W;f6a`Vp39>ZU1hkkz`S)ziG5E{>;~Ay z&O*-UV&KxYBdj=5>7Nbt^cfPpGkM^Tuj5LJ7H{Pj(Z&REQy{MITIatJNb}LaEBgE( zbek4^zF4c*uve=Bqq2*;osfgzYV0So)sc3?Jtc>8!RW*`al~)nt1nvG(tqdAM`R~K zBm0;K%Ks56W>{->o_^e8jobn$^};rKc8^Hywhy792lVtdw!>`@#Fwhb+0-{*CBbjm zOcZy?=ryjCu(7RR$%(9I)_E}phfG$Sks)FhLx^}0DGIF%YSd$$8`hZXv^Tu! z&nV=v+?N{MViLW~C4K{CDBa(ybH_l`aJ*#;w$6#UN6 z7){;jQVj9CB@z=v&B1rFf#v!?HU5W&P;(Fmz_lE7S02m!g8I6sFb&d5+-(+TQpJP5 z^d^oeu{9b+q{DarqYj%KWYiEKG;71K1G+X?S|mnWvtyUOY_9)P9kM|cZJFo` zplRZVDk3RWLRe`BumZy93D+gl&xz)B1*6_|K6<^`;OB{&$-3qm>%5#F{*K-w8jV9r zXvQCWOF*%6XeMg5y~M8-HeAq9eophUVo~pRsYw-PjnAd|UjF9(w^`QVQvtQ}SxI?x zT+zM{@F zW)$o$JpkrITJgN<7ewR~+^U2u3+#S%BL||vJ2|zHzMY{z{&a0O(fq39IWD_pvZE)V zi(i}2+;b94{t?SW=NzAgtl3ML{v|TRXKvFaAbQ7wG30QTGMHH9=EM5OBd|5CQ!mfZ zi{RYBwkl4m_cUXX@|XpU*)xQ(ITkRnHy@YbHsat74q^0<%KOEw=0M*kpp)-wAx9tS zS^ZyW-a#$K{_cb>Nj$55@DTPAwzl8_q0M7Mto4UA4!gg}b55vmh1a>BV#3T3^_ZFT zSQBWb>dYDwKEV{l6gMwMc5%R$Ub&xvvVTS2Jq$Pg+r2PHlkH^52Oht!-R0K_Id6Ge zqQ>ZbZ(i`Z;DAMg?=!OeUt_F~zirh#E=}bk?{q#3M>-Nb37S~SI-Za&?jeK%{f3v8 z7^uQ=4E?O*mN_loJFqzo=z^^J67p+!hrS_roRd%=I^WN;E4h8Xav}fI?Bacw_)y!6 z9=x4vv!I}jzPnqN9Q0UNgqt;%ptdU|I=zwk9CpQB|7VGT5FEX*HGh^io-{O`z?URB z3y)<47E}Zm-r(5~gCchbMb7QIga6pVDV!7BpvANH7l0)eYm@I9d004VHd`0x6z+mT z1xfwQp5+k1Wdih+K0F?Iavb981(wolf7Wb#epUR!WlRjJ>QOP0&yD-d$;K|DP&j7o zhci{FhOx3p?6MLxnK&oHFc6;nfD4+bP2{KpUzAP|x0M#k>Ycx2*~G(=5i=VuBkP|1 zpX*a!?meh}eH6rMbvDJ4hSv2QZQsWBVmpGcg4pBDlc#p5=P&B;ivRSVw`J0hjaznd zV)ivXi70~zZfU};K*nRkX6^h@VSJ>T7${dWWh%;Tpn-nvy0!lZQ4Yb_M$>`urN>gx^sX zUMRpSXHRTAXg7e@X%m>(X#N-r&MnJaTBGlEJkc2B{iVmXPtv_=F{p>Prjk?K*T9L$ zG?qu5tO+wp0H3gNE~(G(OijkC6j%QW;zgjV4wQ>M~XggHGU{+%MQAXEB zE4R;<+fUMZ>qa?sU(3V=KK#TwJliQ^BgeZWy5-9o1P72*)VGmpN4hTl^uXfQg{v@Y zb+<|ISaL_ZJiLo`L&{9;>hMjJH`Bs5c|3v-C&Onk>w*}fomgy90{6vR9M5NwWI0Tozan>N`GOiEQRYaS(3Mx&?uny3Wi=@q zViwKH_Q_?8K)h%eW-@8lB-=Sxo`}+a63Qv4$bI)+0vr-|znrP3!A9XkQV=>nBI=nT z=-)bDE$iY|h~@hEnR}?@9|c#T%Yh4gsRylGCU^B%f1Vo@%Y?Lf+oU{}a+C{n#`Y4$ zPlp||Vd1kq{J6nPEv9bHUgrYR(buBI`0yg(ScKA?$~XuoZ?5E>^J>w`{r9&IB_5036S9tsiRZdm=v2lcWL2=8~gTjA**M zkJ`Pk0QY;NkfzO!wzwFAzu z+qObpb@Cys3d7YimQKjCf!+r4eXoep{xed|)|IouH~6yd^fywYjpa?_##^3LkVhuC zdG=;kDQfPqWFTN)t#(5JO4hJDNEuM@T_!C!p>IIHKBOO294XLgy%p%2H8p<;Rf?^P z0@~HFLuxbdXr&mbmC?(N_}V%@9;u;!lU+9v@dsB~BrAwiK#5~q;3oarDhq0ghZT!y z9#;LfN1L){7p9HR9Y`5XJbn_g0}DY#h6b)oWR%a3R%3m0#>rX}zO~8j41MrcQqy3S zdSgGm0V^dvLX1c{qP7ad(-VK$D526dW?nJ@v0p+j@u5GX?|u9xFXV$SD;ct|??WaM z6(TB0`z?U11QvT(*fv1%R|h-%E;XN85{8;?jrA#M-Cd|-NrGX7=(BuVi^RL0@Om_` zz41^i*@=ZtalU6G^0Y5v^vmp(EiR)Znc`!7a)d&nM~NXa`HnQ><^UEQe_Lm8Ak<6yYt# z0$-K5F<1deTK7i4MgsWJLEuLlygu5H;8Fe$@o?*NeYhl0-Bf5`*^CZ4ehmK(JS`Sj}%F3Bzt9x9IoRjKLX5F?P&0le3 zBoB{NOAnbMzJL5k5ObN-wL@2}xsj}2`(^>(R41fMqB*J6>nuTBfzQy0U=L4ys9|yM zade7<41PNR1D);@Tw85x88Gwhe*XLXDl;)Y)wd$sCw|YFv;u+4Q#v7W3PVJJDOQVG zEE=wXj^&7X&0q%cyA``)ZLQZ+y}pw21eqiK8a%N~H#pUjP5~3CU6v1DRts&y`JVli z0FPQfyq_pjVXzMw}0 z)nk}np3qfO%v^mTm!Wh`v=O?~Wr*NJOA&tp{OLool=U?TolawQ|Ljb`br;w3)&60x zzjO2W*hVkxxqmQ#Y#-19@eEMYxCvZ0{4ke8HP7OrR^*)1`*B-!KpITKQ&v-O+COr3T4d%>(`k3oCDpjP=cA4e!H1wT|7$4 zvBdktu??(^f42}Lh{Iz4wEPDA*FmF6`6MaywzUFNOy~D802l&`+&(-Zg`t5r#&y{C zsy%&}n7-a6+da#V?7c|hleNq(dYnl=a&RHenrheB7*S@-l%gh|t*GgJ9!aTPkI|}o zQ5ZQe$tFmqbJc7HL=^ciL}Z5SD7Nh_M zEh}tLzfMljHAD0MotwcJUO>yJP? zLnB)XphLYQ32Vm&%T01j$S;c*4z1dTSHk{z;-edyY6>=?tI%D)^3x6;tox!&m?(9z z={=AGSQd_1E{Sn5LS$Z2Pw0Q}p$8;B^xaWI<{x+{pv>uo3?2aBAzA{IU7V*4{BKqH zYue1@`;e#qQc1F4sVOPKe8?7Imblg@jMm6v`Nyc^i&Ioutt7WXD$(b*=fm%>#`Jy$ zC}raHCjNVNM*>4+5w;?|8Vbfn(*b46sQT_pPPkrw0v&RCBj9TR26qhFlljRnnMn=MIO*;zL#^U| zW_-^vf+J})$2tXVjvapi5(9`^ZDvz?uI_rf#fgVUe~C%93(>JuV>s7y%EjChgNA@r2GdwucW@aG>|c%g-q(sz?m zdOb0+!sYz*$EH44i!FAItSd%yuzYq#K?!02qiYxURioVA`Af;6$$ghisd8#?oXHhH zL(goh=nz0e#PMPN2$2Asu~6$bWQfe5L~kYeD_HU(1Kv1&O?m9cnCx{JB9e)`R-wtn zKd-jl`1pRs9!X`f-OjnpYK$t{((A__e2t*-V5UhiemCtmb$zq`pk_-fnizY$?54kV znfyfgLJmv|pW#h+kTvrMxN)HXO*L-Ks((Nsf734gj(O!)!OZN`Z9p1HuJF30TDIkp}i{R>scq?0^*g6_|fE%l9g&e8p`;TnmmE)aV+}V2z z@(>0i{#gP-sa18Bq03TSivesDA;bT>YP{7YK;? zD2v_l;55$DIoaosZw~T5x$lW@)tyn^vo3^qthk(^`+JsYrgmX5pcmj^C~Q@$$Zczc zKik3YPkK0~^O#=;{DuL&r~zOZazKK--vg+c-A;#&%VkOh?cWgWPU38h4I_W?rS7qC zV&3%0JvAG#w&-LWjp))S3)``ItNxmjGVoFxfct3w)jaO2R?>K^7hX)C$)YoH@hl5% z-`1hf1JdLt(4tX891+Z(0^Qfp`OA9}LrZ+`Y#!b3{Yx_pc$r-Oe*=ovOh%0*nq)Y* z{G3dlImAh8aed=UOS-QuAupH))Wc7_gf)Fg|@ZRu7*$Yo|BiXg< znp?XtY~ET9IssXH0T>&}HYg8OIyk+$O4F68hc?=ReI;cF`Q7xIY13p7c<6d2Sur<} zkLD37rp03d38sS^w`>Z8(4fOxRY2l~8z>hwLlK?ZB!`f|ILPh?Vz|g(iT03?D>ELj z8qX<)3lf0PwaV%ctcD6TO*X?|0Ci`X(SQJQ%0Xw(=EKF}c#6+k@uZ-ZyNttN&6q@8&inGmUt0I>k{=Shw?DBW3P}pQF z=r?NJT+DAH={c#cD5tCl(rNh^Z}N#;lY(cU22pZ19PdtS?XjYjgs|d3JfW&3LT}8q z#)zJjT?8OEhl43y~IFDcX|;@l0NlF;$8& zL0zl5McO#}BV{=EYvu>JKLRuNs)I0vSF{S0pzx5f;!h(NP5Z~=Y+oFn zYt(-UQpb?E&rHWn^v3=K8VBlk&Z;DtV-hoJYA8<;BvXcVgv-_Ga{{ApxG3SevNUFB zxy~*V-9fVQt=3jtpzfULoyhm$tmrzy*3o)nCeRN{D(*$qFD#I%P#EDtTz(g<;%we9@4!zivIG@7LnLfbt#5M8uQ zM(j>S;oSRpCVsTzqNl3S($9dVqc*_cFlTlQ=VsPC>8}b`*Z!nrO?<9Opxq~T?8mdt z?T)L7g`Ei%E~A1I;;O4~^OB}ZXA&t9f;>FhL~X+-S#s;CE_B8Z%qkV-`kZtR_;lh8 zHUJaIX;NlAQri8Hg~h%@8+Omcgz7V#By~FZB=y*RgKkV>e@OQ8ai65RMa(e)YUn~@1On8 zFC1~PcRb+vzyHE=OELgQf)k6?%11&2Ui# z(!qcB$^CLg%2H*5K!$FB;&=%a;N9W~KNbwXf!{>kz)6qVmvGx@0bc9FfvoPf*RrD+ zt!t%kcYNpDVeUoh3e|0wD0kcBPtGR#Bf8Dnl(iUlB-OI?@VT;6?n{*VYd(d$Dzr2o z}GjBL6tp)Ts`WdsOd#28IXEO->cnr~wS~O)^t!X@=c&X*Mi$wh93fX`A0g4y%9W z&8@6kX)^tG=#NY`^vxbkxhI@$*e7i_-geUqVM(1oJ_(jn*w+ zkP*kA=^Y!V*2mIJ`n7B0tyDRUQC{!$Ezf}3>+p9U0X0RB&Z1r?rEtrt4!^t}n$Xlz zX65YHHnGi}kQ2?SjB#s2!7hmSYWCmHG+hHBhCL?CI=8X}hE~w$+_5spSX-S7&y8=L zwi#x6cHZZg1Iy*MQUUmnDcNDyZCO7JFa7OW2;gemef_IlKQva9d@YV=k!6>zPF=eP zQA%X&F@`M1dY-`#p^NIVUVKHQyIuvRGZo~{TjYM6UQQUMfRp+ezKPlTS++BMJOB|) z$s`nPGVM@LDAvzAq+_U1-qD!A>aD!c!CEca)9j+NS0uhy$){5)|4H!gbb%R4CAiN) zFbDTEGN`@X-ZHx+&XDj>+*@j<)GCojm$YWd&@b%A zf~-_|%@GYhxNp;V(Uc`Hmopi1omT}Mt7JY;&*TCw-%IC?o<-9=wQbbn>)uwQ9{rF^DT6d1HT0;eV zZ~;+Hj`+GTMS_5=%i7{}YE;)+80`UbTk9p4gJ{tRE|eRvm{e!i=kPhkc)MxgfDEh^}0#%0w+PO32*NwIB3qkbAun@ ziq2JY6`#NdI@&ZXna&H!H?bbUKn`$Ma<{D`LVQ)a{dNR(d}QCb(a6fqm&5aF2SHr7 zlIyIvEhk<}?%0H$NRNcHNAwa^mombU!SJ+8&h$xKPmJn({UQ}Quj%V+zbSk& z;9g6bWRi@g4s|fg?VCckTj|1VQF#p_u=OPGwpWW%+CIB+1w{nNnjmEe0;+I9bQB|R zeVsVQK238o5W&d;tBiZH15uva#YA zt}N^nGkt_!Q?W>Ky@0M)7JoteS={z?-XZ?89}2oj^S^|%GkAX57&8A9GmOEc3gy~= zaVf>G{DA1-7Plh+o+y@E@9J{J8{qkRv~kG9cU-FFml8b+O^ydC$jXic1tjA| zk)4GFb=v;tYKQVwJ*R3)gnIw?+X&0Ts7rC;=rpDnJ9*`Hvc@cdIvEk5N!AqeA>K|? zoy-jcLwHw)v&gc_TzO~mcsg=Zw7*|HkIW7M&NfNolQOPA0JnMTK=!5$t{5GDlO7XG z9Vqqx5CP$$Na<7bZwD|#&WXrtZl`AKYMv+IC^{Ix5ofuxw+A`3l!)Z%%2OBe?TzZ=SVAbZ_hrw^= zib%;TE$H7~0fy||Vwdr_Ek7(J@a#>$LH4fZEv^c&QD?NKq*ahz>kK}ya3>{}2>doQ z*YjT#@4b3(2_Q&S`5?+5&aAHZD+B5L#^)Wzpxw)+=?m$sC_Y_9;BW<%gW_G7-HGxRW;QWF^yQ~qomlv)uVIaBy_4uR6 zf%fOmn*O@Zx3;g*^MkVwxm>IFGNs4$bOgWfokC}oA=#Qx-GI!I+$2v!_Kp4|VMrB` zW2oHo(@nP0O8%wONvb*-R{@=JIc9XZH@lDhGcGwsMx30dBsego3{|kJldvDv@rSEi zo}=I2m~Av)fRrtDq`K9=SnJe17}2!93*z%_zt(ViEp{q^qP_l`il452-SFq{jJ(-KtI5`8Z?<(l3dlhe!g zv76mceV6qzT~3-_eO^S|Tq?|)ZfDRn-qRb#m{WY6p1y^N0xthZZ35;|PAZvvD0b9q z)#8`gch;4?OF)S{uMqf;OSG4pk|z?NKhNel%yeCW?j60aQVRrC67uV3nU0$lo$HUMb#M>)rwpKCi<2` zZ|u~lk^5ny6nmZqagE>y(5=&ztJ8Ty)21(z8jj;Mu7Xj^>aKB9{L2Xakv1B|4g-JT zh2ObGa^WeSbxN{r>t?gL1hUX149=ooDG%xO`TaV*1V{ zXQUB7xMyQXwbnc#jVSOu2sK{GXo}UcIJiS=#M#o8%_IMp>TCpDDOcPWf3eIw`&TXH zT4DjS?a8v~GU|RzOU(97#kW@SOeHTT0>VnDxZaGgj}EwTOl8W9CZ+6Sx*1}VEHIeT$*%J+K7x2 zSbiH%F@xn}U;A&|fpbyC&zc~JA-c2bjT8SA=V=gu*va&mE>WixpSz5#xfH8e6-$4P z`bfg$T0ZeS@0xhOd!3BeuUvYGDYdHmZo#WxHIA@ks!lGD#kIPVKD}*kw>}|Oxr|!= zE5X?VljgRjGo%Z2*wOEu&X`M2QnQicDRBUBCUAAfhbMb?2DciA64px;*L=Hgx+xLQ zCr6>~nk~d13^RF!_ZGaNH^E7P#bii8!$+Kg^>#7j6GBFu_+wr7VjcLbREi{y=_GQ zy~4~a>`k|>guubxNuj|sP?5#|sM^v5L`O00eFr_ZqW&{Te?igQIMoPgauG9@qt_Mf zLyd84?eFf0Q@==zJlP(@YaDN;iJHWBn)Lk4KvQ4%Pa?xCo~P#r2Nzjnq=Qn$K~sh- zuvxN-#YreOiH)ohYY&-In?HdN#ggNv`5(Cy62*c#w5}=&^9C*T`=oNdjnJ7P@iBeM z_(OSzKuC|EGXO>iC;UNcR+_2!#yp+}KNuEM=DCP}w~W=JxVj)AANC7jG4q8irOnGG zkr~{H4XWWX&s32G4v7k;aGqM$9As;{KuN&|rvG7g^mRJYA+AhXsXcUg?LTg%ZT#lx zEMcv&nj@_hr)Ab9)vDUMg%{;RscG&GZ3az5Z4=KE%6OOl>jGD{i`@S=L|H%#rRq@wCYEKlFTW4=1tm9xE|z(M{mO?e{C1i-aG=+_` z9h}O)3bW;SW4rn0axQo`+#&-^X1Qa!l3}xSFA@QQ-S}y3OPPQ z2Xtt2i}|b%_TQKrMi~s=>c#2R2^5Wgc%Qq0Ybi(ym)dK|N_-6a^Q((p1$qPCfgafB zuRfatu@pSAGiot(;B9GidlTz29^fgJa4lQ810io!<*2_7*P8|aC>f9Ujq-Qisg2N5 zMAim9-X2aTw;ghg_bVSikFEHP?lmKwv5+2S_?O=^KrEk5?`VX)NkzJrRP*@hczQWd z!A({w<)0jxf$wTZJ#xyix~Mk;;0voMd95LSgfohvX4fZlLfG7_5gbFA&X?&F=e=@I zlD72eW><8Vyh=`kAiWbE#P@=~>1Iww>i&uPDxd$@9%!F2X*%C|YjA0=`e~T$T|Yyx z;u){>db%BQOU%z>^>V6XJ02}HMvKf`cgXJ>aDs^&5P2M4owY0{oV6lmby;43>Bn~4 zqrDK8_AgrtY2W{l7@jL>dC8sNGM-2hSmp3d>lus?{U%&uPJ*Eg9Gs}~O)5;yLA*A| zlVvf2Ggh#yjqYiZf=_cI_Lk~U@aWm6qm-ionlufqjdvC{(je9su;P_o2k0(HCWpftF>fiFX z#e>|96>mL{{U75R`gM!kr8RnfG$Wo|SCmfFt;Far7aI8)a%qOD-cUywKvWdYD zbPwcY=Cq6zkv^d5PZ_k(O(h2dRnO4 z^`z-6OF9#oiLj5n^q*h)#ruutlUUH{ow)8aVZ_rT^qhQxzMdGWGN4sW^>O6)A1QKH z$t)6w9NGIV)UN=|1T=&+j-cu`2Ac0NL(Mu6243?J0Z9(Z#y>9OTG&NM!=k6LD*Kh; zwEEo3)X?iz-BaozW8Rk?M#hL-CG=*EKKhkW$de8*By*iN zL9|Q4%j;66lc1r4p%e6^v(~Tgz|-J2aP9ROv0WZt{DbFupvtH#=g+u3@qTS9@*00T zQ`+sGQjvvlH31041z~N=$*|o6$6oYe*4`!L@ozx-vk6>B8-4$Vp#bfvCtiK|lq6a{ z{F{A@_BT`Uuai;bSGf1Yz5%uS9dAwXT)tW%NdkzW z{LsLwfC9^$R{)mBm$)g8Dej0`XC%#U&wX;TsOaDBCQ}Z^A3^^T)onu7gvwaGtI%wn!qpU#0>5?blK&%DFG6*ku?7`5jn#u@o?muwqh!HUKgXv zEJ*9uGz*JJ<{J{AY+1KUut!!1tm!GR(^Aqali0HGQJ~W?R9eVDqGE2{3?;nxmO&b2 z9`VR3&}#K>WjPsw3+N?RKwa4M$*$1%4N;&C=KGcG&ucdpdYCJf<{P5WW!cmp76EwM z1B`|^U0K`p9mXqhENIs*+?t?g03yVOkWiArl~T;uv-AA9@@kc2d!OdU8esMPQh2`n zlAWdUKs`y5t&Xy2PjUh~nHAmy^Gl}6 zg&CNxIlk`9rLQmC92GY4+ZC_CY3+pDA+8}^YD>~Kl(z0|DWE{l+n$qqsukb6t6<2H1EU@g#hy>vVsnWzWDB4(>$%neEW10eCZLYNi0q3V=Wd68IMH zyJXi?Y>wcQ3+k3aY_3W2WCtx{3TRam6k^98?H2zKQ_W$?6mHHgF?{i5W7wOJ-?ap* zL;OlKw73%_hUX z{*gRrqL0QGmBb8w<~$7R(*vO^e~bwcDGV&=Arx9~hij>BF~UZhl_0pSRh#VGPgBon z=;xfdF<`9|Swmd#1wBABv=rAjHopRyYE=#HmO6`Sd*f?!)uu8F+QRPo&tNtEZ@}Lg zV}g!H~{aM`dp@PE=R``+vi3A#T5FJ1mGo&)3YUF4<9 zcH^-hisTGGOo_&~puFVG0OPeuiIpLs>tt tIXE6m`vU*OhB3K}4dm^j4weU9wFJ2{E)Ol6_x>$`YZn#4tt+T1bnvV(dFZc4CxD zQTAytn53~Y3}cw}KHi`EzOMVa?myuE<@;r2U8>D13gR6JVP)`&Szu<{EhQVzX;E42r6_@d^(? zii(1p&;1y@L_s^itEA$8b36~eG>8%buOgB#@CrKsUK9=f&oBR<)qwwhV&f^g+4cQ1 zVd)DN?}ee=($!v0ZJUwv|9{Mw56m%Mxtu9fditt4eBYVSB_8Gcixy@x&ElK$yQy=#q^!ll`<}{XxyR%EwmW998#AjX%8kEgnzSZuyEp@}F))FRbk& z`>Tz0)OaOY@4klaQ9rL=h97P$;>sJga>bMW^_!s|`hR}3M_*3~Su5Vrf7>Bjk1Pj| ziv2ARm6h>SS=n!Bz>eQ&ZV`RZ<#O;V3|})cUGcYT(N{jVV<%NV0EhQ}$K(vc zYc&NS33nxEN&2;Nk@LbcVfh5d(TIV?$!vdw@6gHjuiy2OLdBkp`87@HkZfJ>|D4yK zvpaj4dgDUL>n9_QdB1(uYHs3-{`ky=4~xKm{p;~vi=$0`KboPUsx=yiQFDCx>>-T3 zAA>sFqIy9nykFtyP}=UQy5cs>z`IerT6nY4>{rxDi-MHS>hO&#zLTFnxv;k;9aIq6 z2KO1RD%%f*ikyQ*1#nhsrTsbI+xd3BYlMOBmOBoYQpQ#zCD9AzzC6zJIcHZ>*R;?X zxCbLecja?6yY6Jzz4ktFvSaN=$FrBvYth^Z#o<#)c}0$$dUpyIdBP>x`sooAvFyDb zNZY&7Sk9wobp6S#9huI9&uKag)xD>AS$x_b>~*$ip-u81#VF|axFmGuku~&t57x#} zh-`e1z|KP6(s$+HO7VAF`zkoZmWn@b5F@kgvxe5Ado=Rti&)OLYBr&i-FWNfg|o%= z)qc~>kG#F5OvMScuhLUHYTmFrFLrXBOw5L4wo|w0?un*gI;i>w5*n z7pgGE7T;l8zS@;O!c>3CVdDX8n!Hx!j8_IQPUbh&3W5 z=qH|m>g=I3w?OBniI%2;+mvdTcz9u!iQTo247ZqzJwft+!mwmzVhsCY(?W|cd%TkV zlKbO|v+IirboFhoh1mWAS%kfhx#uhK1h9|$#eb50kQv>?Vaw2<;r`X2et-DV(s3DtNRp)Wa5O~~1`cNfksJJ%@)_58EdQ%aG@Cb569NnuK}AEr6gx{F$> z`(%=Yb@wPMC?C0G&n-f0H1(A`bx;gGa3Hxy9)*O<`yL-v!9_m^#a&4HIQ;_R?-E227@=zfYn8G&u|XS{4R7Z zjHp-&NGIY*)(OS>HMz6D#OwG&7bo~4AV0+iaAE}@k6%dvC@=LJlhup8AvXPeDh22ui625*p9Ba;NRi*Ax2!-NpoLT?2e^LNV}{# z`0_ug);3%ubF0wd$3!!?n4kNt{A{^rJ$DPNC=06~IE`r!JZ8j@#YMB~Kbbe;~!#wd9Ve5`~Bh3%Yc5w-L*U|_Bx;U~WF;X(%4Yi9LZcI%4{Rz0M;h zp^HxFFyxi6&td*h@~u&h&0&`q1^;58-vu!1?&6ksT^m&>BJ^*)QQ{4K!ck@7-lUkK zKTvD!@W9U+v1qbyz>xkwnlHmjf8Ui6{A|(+AMk0QR9>XjmGz4Kscp5Up@N^I*0u7O z0aN33^AViuCb8{Zk2>ym2y8(|>&DlWj=ihmzVRzIBC_q8XOUJ1%L8w66hQe|TkeO3 zIZ6h5p&O2)Uxs#xA-hX!1DxcpnHnwzo>UjD`_qZn7{&c7Ax!s$^%=Gv>SNR631a~k zG}P4o%fdz*D5~2v{Q9{HG`(wnc?0Lv+~D>-2+BkgNtIWM{J}c8;+aKEr(Sm5%918o z;{DdR6>O&1H7yTD4)Hb826OYM>Dyx7$gOGI82^;wlpn(53UX&=mNG%cz~WZf89TO3 z`LDkIQn%GC;|8-UO+RAG)I_S3Qc~V7;^)+ucgPAYYPb93&MQFE+!@SlEx~Jn%TF1u zQ&UZ*oK$%8bcMjbecXPsuuk1xZ=-hMYjD0_)R+u&#y=5n+Rb84adZA~stbm<`MI#Tq-ESH^u zJ+q2u`qJ3QN+#c#&b_UKbBaW8CMWLjj6ThN>C2<0lw}O~VOy4&fqYdC8TPluF9=rz z5fm$sqPMd`NioYr9^X7_7*7tz7CEs?)o0VTPIc( z5S*$q>l$VW(+{M-ldozxB!yvV zp7-3>7MdvC8oDbHp~0v#(o5Q6(Aj-L(+v_%(301hO@c^9H5m?~H=O@(b2pmL-Li2L z+c6c^N!!LfQYv4~>Y4o#Rw64b#MA3XIuVuBXSpBN*I6^!8* zV(--~?3-eIMt0J6Ps^0*|FC%*IgV;%;#pPiLlmyGS*#wC9p;h#DP4Z_a(!lW8l zHIQS^PUN1<+jV#HO3CmhJ&eR*r^+VYF!tufw5kxZQH`cydY2bTuj{nJG^G(dv` zrJEs|8W}KC!@0JS$d&p>_a)c6*Q2djt)k*r2zF$;p}>zK47*;Vc>DEN3WB484<5Bb zWB<#3R4?k>{K>{%f#W4iYw#Y`i3%)cJVAk_u*$3Cf{nW5BW18-K0gOav%S}%VHbYX z=U!6Gll=EwBf+UM@vZnlqhGqb)pTj5Yq2N;9n{~+ zvaVj=deeQftFSi+TibJ+QX$uky-^`&S+m#Yv{Cc&YJ1@X@s2D*e>HNo75id0br^t(+X0=Obk@@Iu%eHuaOaoSq zpMC+V2#+{l@}taMUGMMNe~_*mOMNShW>eoUWBb(g+Ez2OrfGwU9H^>OoJsQC$4p!( z+28DCnCX{uzCCB6Z~4m#uU0ykgI1^|bk|ncx7hH0V!qOkH}he{Kx&nZp74cuEK2}u zjmQt@54sCNO>W*&2G1N5zjKugIJcsln}bV2JvO9Cb2IE?7TP5KJ7`p9x2t5PnHcBK zs138=`vU_Zm_GE_>9s}LmP`9$TUbzL;Y95Oe^+zD-|%ts$eM@}PDw=EBVxdpl1}_z zpR%{fmQW@Op|^@>nK2GE^IZ&}il)S@epu9jv5#%{m8XgW{wBY1lzMo6?fSndnDV`j zE8`b_CbM(UDlGw#Roz<$R}>W)Ob|b;YJ%D9x*zgGi5KlOd-?7=Y~@vk6ZIA&{%;mi zA2QcV-41!L-`fgnRlgh$_qMu7iol|!GT*o?jHF|{c(iO!qv(fc66=SDha(kQ`9tsz>y?)BG!d!|lPc`g!2c!tPG1o1CaS;6hL|Ps6q;wGR9wHvAzb zoh$ErV1Q8eZ~@4u%(v!<->7TRT5|KyKSCySex4!*%tT{bwttpaga!|u0}YE>l!B0X zu5)KubwEnDE!N!yDZM*YDP;yBQfj|v*R`77zyy-qVz;A99mSG4B2(WF>R}+C)x=_7 z(9OW;sPDt&wO!jV-#Fftl8o#vK%0P>9XBanwrfsao8Kk_0RGD=Zs1);&ByJeIT3Z9Tdu*N>^@W2J9Vo&rrO2S;t zrIhd%7x1BNO0cvuVi4`t$WZ=KoZI8wfGn#S0gwd%SO!FPsb#P^J=hU8iDD|x%8610 z;QWu1r5b;~JLA>t5u#NxXhUWZASll92T%teKyK%Av)!ei|GWtMb3`y1F|gezT|NhT zqJ+D%5inmj`AsJuwguLl!Jht9%-*B+x$5uI!3QT3bVOfp`0MwEPEB*?XhRgP9gCg3 z{TV$?-qdg7>V^cSIOPxPCie-JIma!S)1BXcmnPC+Ciy~MsL<2}rEOPVBy>Lx9-77t zOW{Aw03EGlY6zJ-$th;5>BUlBMM|{_!zA>iU&sM;_1|173Cw-$CQ4;c==>EW!chvC zjm7w{S>IxuYLY7h&wBP1dmb#9{Qo8*bU!U5zsfif)%b(&*6-E%8)=b&(yr3Gf&m4wSo%c_ zPEcavYj=Y2FWKu^H#+n4h$gd%h0p2DSfY~#?_eC{ z_Bl7Eebq+jNVDQGd7&QLMtkg$x{*e2_6wz_;T~xTK2m2c_9z-iclk=lbr^ z;MFEAFe7aVl(mP6n3kPWh(py&w6)o{)Rmfhs?wy(wMCJZdPyw{3IE&sQy}>$x=lQ2 zwGFrfXiu~3i*{lGZrNA<(s6a$Z;xZh4NvmObRTghZn&JEsfcyTlz_`W3gFbt@aF&k zWb&RV2C!d$pq3z}!}#u#B|i(t(zGkr`>!;YImdw}!XyoY0q zV8t7GzZga261>w-v;8JFw*PhE`LfwR?L)o(^{E-9jX2&R_y&w3L{<%>y1rqIV5erd z?eT=j1a1qZmuA``yPc{K-p(qdT&cg8Hqtq}r{vz)H#JR0=w1E?fW|2#hgF`@Zdhxm zIn2^s4xAsO^s#HyD~!h%CRUPT>=9~AszXYcu^;M%v5F}ZVK=;ZaJbG-B?kg+FwEdG z!H8hSt`#!cxU_M3Llk3C)s%@oa-EUzZ_O;Wo~fY4t95?_&P{z5=zXmn?Q_oNN1s|& zGH`FXQ*+mUCKg2ZU-4aloMc`osa|on9ZoN2U#S^y@okzZiuzau1M|0R#$r%NStid< zWrjIOW0x+(w$l^nFX_8>+ICxa*ddzi3Bbz3t#zX)LF+J_<-+bQhbL#A@rE56$li|^%wCgMU z^1J10#s3Bjg^*8~B9#O39!BZSaQlI5aS*zGz$TTm4<_ehk^mogYL{Y0o!Zmxr|_h7 zG9cK_AXB@!H-sPL{*(KL_)K&+5iqRqb+u7;0*;C2d-3_m_aFh@Qli|zZ4cS^J>Qxj zg;&MBcVY0jB2lyZiAKdK*2ug$mAGT@sO9XlNv>kQ3*dl)BTsjA??tU!5w&uG15Yf$L-3L=PhX%=s=H+QdU=3*fl=WN#}G20{s_Hmta}r?YZ>p#FNQa zw0Om_r+#qBF~<#{V;R=1)`Qkd8o6__g1@R2Z_m!sP0(jk^4zm$-gRQs2PFcYtQKKb z#F=xoG==TC7xnda{toA%U0lZK54aKZn^?ozs18JL+|{kuY;jjyoFb1pfJU9qdx9;F zO=T*a6NIkcc&!W9_zUW+hID3Fz0bzkh4^`6C+5_r>2bB8?ygnb9~n<+O{;)71Agz}P{QB&WEP+QqZFFG{MQbvR z(p^UiOR|^%7Cr;rR10@RVRlMwpRHJ7g!{(1jq@8qPyF#Ytn-Ygd7K_(9oH0sM;%WT zg@cfPctp^#%%$vIQOirzEuYHmJD1g5x?{pk?5e0dw+3oP-RNo+j3Xn#onx;BV!hdh zmb}LS`@TdG4<50>6}ndD(zpe*!xnnyCy+5B&{sPhk$NvFu)8Dak@v=pHXC%YUC6!D zVt_lYDOPPQE+z+d+wEC2LpQJQ_{b}VG&wBCzByJ)WLKZNMPx-pRuccrs#p4~1o2?8 znd;0Q{`eRH|LmCOx0wmk=&R=f+HxSd>=K#9(x1|c<=m%luai6g!*<_sH2s5Q@|CIu z-cUpvrgKeN(EE_V{iqh()y9?p_Bc^2Ss@VtkBnGtE*&%HW}!b@&R!~X{b!Neehw7T zZ6Mzinf`(o9#d9kioty?n(FNJo%HtBG#R&@ANoecE<`=s{`X;Nt*X?BT|hm-Cuk&A zwaDpU^S+bsqA~YHY#bQ9GE31w$nxCX zr(K%o?MUxNH~TC=58^5nZ@c71yMoU3m3-e&piKO*DWL3EOx zFHkCc@*~hgR?lG?*RYgm=eTG_)?-#L&`5T93^Zr-#ULXgL#h79%6KyaVA!*aFLA^@ zMPDgQ-ajlHko2!FKD-FKRpRk>H2M#fZ^7l z*2DW+c$IzVX8wY~bR(#nSU=P|1t893hlXub%!-@j1+bgE76Hi{dJsz8t1r^?!5M9s zDSEpm=*~uH`LND)_N5z0+mInM)7aC~YH3ON>;f@yrtTU;B5{$hSF&lbk=G$?@5T5$ z)c2)P-|EJCEs`(`hI^z4r9zwS5E!g9X8w;w)QB;A?MKry9rQrN1uO#3>!gScxG$l};u z;}pRIQ0kc(3kWHl`CzXwEUC)G=tTT;{q{WVN4qC(^t*o5QzMWDmq4(C9i_pKm^2B{$_^(TTc3{BFU#fx2OAgN(j z3@Xe-wmmJ!yLh?KwgKX-YgV8{_PNX?X_0voyUIHPI;tcb<$LXXwu?YN-6^70j9Tf@J%UU}eD z+BZk}+JTMC3d;@+rdH?0;MNP!ZKVAJyLJI85U$s%WT4i+sFtWc;2JWTA*y{PvAdpA zCsFVHM(F;o_HwTXGH!EC4wZ6J)U8on)u%Ai63zUrMwe5~FS`@7_xb6ITmr>T704$a zTF|LN_vcRZZ}5z^%x%4&x;I2GxX#EkhRoYiIszy!`HBIq9KU{h)-vvjAoLos54vS9 znL4wY>^auJ?w>bi7w5hF7Fql!o2w!9I+y=JScaG9&_Kwi=mj3}QFxHiN(~Ce2GB_js0$=NI z-DQKF)N#28+qwLp6~B0|{QQo8d_%Z&6uJ8oK|^IKsfs9Ty{JZwok9v=_ktO@VuhhK1&GqIYym5FL}&A zsCm9|hPB*-3s$Dsc43R?{s0LV$nrLfcn2Us=>8>BA#VU=wmpdAaE7TxPQC%dW<4Wc z4y0%UT_RwfmLk>F5!w^{elBk=f3E#6_EQIAV4)z zwn{>Rp05D`U=bCnW{^LWjzE>}tHqgrfp(dCxQvq%w6#1g#Q5CRm}wkj^al4a&VK5+ zvth}-RJ#MQWQzT5)(F;TD_EbikYuJrs_5f~QGck^*U`E_*fg`)f9QnSm4=b2{G*yV z9p%r!(*V#NY4iM9$}G*%r|K(;3OG6gi=^mIVQ3g=4fO{V$@5*^EqeTiK%*!1UHYr9 zJCQx({OXfZZ*VW;qfQbk>3Wiv32U6c3btl@=CXt&%wW)ZT9cFFDwa8RU-_wHWKkGq zmesL?v`~~C)f?OKS?tHLyFo5Nm=_gyOXwwcZxz*FA?MS7jv%jr05KM4ZoG^NlFSr3 zTdZ146|2#DU$Rf{gw)|a(Lk(|B5~5YV(xbUyPsi*>nQ8MFXY>C3-<60y8$#iwgVEp z<*jA_N|*AJQ02^HlzPiXYwUOQE|&fk>mQ9A5;O4aP+`Sf=3Lg?gGWhrNlr;9lcHsX z47Od^a{)+>f7{}rkiU}1;4P_4TkWdVi;-D(-jU%X4}Iq#2aKbl*NuRojqb=&DU`&a z(s#ulibouk)!S;tDQiX(5^(6V_0~coKn|~Zn=@prZ(5)Hxi~u0Z-O{qmZ7|JH>Pn@ zqfg9i_MAc%OmSCkVg-~7Y+bSWcYQDOK@4{*lRy~6e?{I-lnX812G~joxb>aY0=Pf^ zr}QLgtP*qRy_splNDA}cqw_-PSQp{a&Tg%-N;>-EW?ky24B%+};2yjs2wg%zmS4bg zoGKOSDR^wtrP?f|sXJ?7aN=br)(`hgzSAmw@sut_ho-|nlO2}cF}0d@L8V~%9JcQq zzim?q6@Wo3OJ7*ExS7yE+0!!9QRlZRfJ|!jyMOdcTqovvQIw0PyiPecK^zxn~IlG0C8YxXIsFCCuTgH5_F&Xqv(qa-1>O`SwKS~>osQj{O@htJg2 zWjcKadn@1`thyRFS`zjt19Ar+M5X7g_)ayrO*u{N+p3ZP06G4KE%}~mQsiHJ2R?u^ z@!piCAP<91T@r#7AG5wQUArIX%0*E=8`l=nIhHGWCI^A0_uT_&)B6Gnd6kYz_eu{a z?JwXaP5ICYBOFiYt)C-p_lzf`)bMfugt8&7rpsNA3#m6gZ*vmbr- zx2$Kn%F3}f`)oSax=)Jnw^(oYO8CitnAAy5UJc~Wka^b6F=<=2h(NcIEuSvoh0XJ_ zMe}unef|7rCud8}?7!_YS^1$8HZnIKK`-+C>fUiBm=!9DTNE#)HBYRMjo^luV;TRvR0j-)PwFZ=KZy~(#3cTowo zl!i0s2FM*<1zjawh@G~JPf2#q3->zugifQVHlWvU)8GwmgF%Zbnmd2fM9lO4C~UV* zKm$1AvwRz%#{d9l6c7!i8K!1QO?vZZzT%qQrljZI+b-stsmohvSLb%*UYxSl=YB#a zIiY#=2sjiWsQ_&=6Z#B-aH;TaEvvt9)TUeD@Ec>9;;lBcoXcG(-b&SS*ach%d39)3 z%$DcxVCi8&UK+vfg$B3WdI~`jpM+rm;t^yrPX%MBSNtnC$`=m4+$dz&BTuI1E-3}c zpX^?`iM?q%cGa;#*RSc$Kh=KyV+6le%ns-`CNCdEe**k-l9^{&VBOtv^tWI%df(v= z4`&`(*jeLkj$EXD$XIq70C}BVIq7B~9XN!AU#50hMy{i%FQc)8JB_9F%`Km---Hwd zx5)@zlmWu4Do)+iDe?)xGug(!sQS9+j)sF#f_T|CV|c>VOWhr59dA3*o3l4XJigngH)S3YIp03P~zI3u(HZsHICaOv!Zc(7eYA)NsUu@)rE=mXF_qj0s zl66bzJMIC8^%QxQ!Xj5d0oZ;e4rxmNHiBz(7aAXt7pf?GI3b8!yTZdR9~0q=z86i(zWN8LmRdMl)?Otw10`~5=@@MdaT-h zs8zrOSjP%pW{3g-w+6VFuCxC3NdPEvRcvroP*=<2OZ@BxcZM?<)`7XH0N`2a8B?4i zC#xeRuP=}fC@POvV@Ubk|8A2oX%+|NU+B{EW)G0p$*|h=?$o=QAq8IdPLYsyS1m)4 zI%a7{#4d{}8*P@qWObsMqp}{8hFhNsU<=eff*_|?azZ`H+u<5g|0KZA>(yCnqxAM_ zHkl;HJfZ)S!tcWG7nq;x$?S4cmSj#w?)>kx)^pmw}!VG@RVkj>azTl2O#C0m~; z4g$d0_1o`S1F}!_+Y;G)fBXs27q2!!4Sq2}w%&c0^E61Z!d+Rhe@5*p&Y9!knTHwOthF|G(vB3olIja`4T`K#uj*^?r%r#_ zq!+)l#ksp~Ok_zyzq4|IXtJ>`bYCvn86{ai(CFG?9{w@7QFOaowk3!%WWQMtYR;tV zVb`-RiJi9o9f3p~n1}Kx+fLgG%Dh`ZZ|_0Mi^3rJBxQM<^Rw~mih$=XO+pY8ri#m| zY9*c=0P66c_uWh1LvC)mx^$4!Rt-l{&ibBBcO2gT)Z!_7DF-YUW64pmXQ8Or5unHbB?9TBawO?VI5@@nMNdt64o;4tv$ z^=ufNt>cb5Vt^$H`4T;C2G;f%(`+Ka$PkKJ$QJ!>CRF(9DPUrK99uQmYaEG_zWW%S zZU@-1SaWmjCGCK4{<1J{DfKff>GjaPN$d;9^(g@exK7^fxH9n)eB>(An~U(`#x_->@q!)!3&muG0o7i0#7-a{0998hXrS+cc}v# z!(09)0#&5PJlymb@wH)7zIZ3vMTHx1u)ge1ah(x`K-7?F4gd=yyy{`ATh}q=gD;5T z*+j;~@@}qIs)4^&140t#LF=lLLD?p_(MMtKTSNt0?4P5f(t_2ig>E~F+@v|t6t=3! zZu%6HpLWLiDIIuM297sh2ySntPwiTefXjU|>mGNUn z`lmdoA3MI>QBer6R~}t2h~=fR+iMR%tycjqGH6R9f&etvx5FIuVJ5~*_tRFjVH*Z9 zpB6A*X?D2hk5iLksq~FugpIyxn(GFh{u(49^5I#=?#si)kF`6Q!Arjl(-q?vX2;a^ zn6};bYUC(-{$#7svy*AjDC{gw3#X20?|XNp^6uc7#^1v{rTBU zq}td&lJ)lwBKx9I^S;M2f{{0WUD(AlJdMUStak~^Va=#+tbsoWYjss%VNBYUBpbu4 z%mFL5VA(8%VZfr$$0L_X}_9E8?dR(aW?pwz4KQ`AY= zY|-i(USpUakAP;-K4Q^znqHK-85`@XNmH<#P%7(ZJ6jBXgjza{8D#gepLU#~-)p5e14HEfycjUdiCvq$O64vv zuj_!q)W|LBFl~N!T0{wl=PDBhBS?`?Mb&puWW4pLPaNcL(hjnp7*|M~8BV0$qlQzl zCV2|19QrtjM$Uh0(;p%EqD9U8+`Hl>pP`zr(X=`m&u?J1aOWfYheh3AajE3LL2q-$ zBo6WgI%plt4*n(pQU;L;bYE0R)IM-HM}G?dtPg;Pwb(tmlmdTz^Eg@$qi}fTb7Cjv ztK846FW5h-JI@p~8Sdy`;i(Z+C{F(w7O)Bsq#FZ1lr_bFKZL~neD1%NfU^|-0Tsu1 zVEV3;+kuYr>U^Sute*Z?G5A7#PCI=~f9(rR7}GJ8OhMJSP}Y5|!j?9{Q1=otL<(%r z$YEa?N2&F9ZR?+(#AkUWow2)x>BzL1~Ir?69 zMBrA8#wyGH;9e&Iw5pZ&5K;>=rpVZ*>ov&X)nQ`K>i@OQ!prft}Shr zT9|E>HwA$B{$Ec?$&^ktO|v2WooNZlEHjb42X$QcY5j6&iNuEnZ|IR3%~<3r{%$5c z^X`u8>k3WxA*jjITP;fY%+Ii5=1F_87Y+*}MeoXa2YiBwCm%d{|FRR~M|kELm_yO3 zp6I{xwcWQpUZ3jK392uzHdldV*J8(Gs_-Yqv2xgX88|dwY)u8#c8eIi=2&r1@Wz#8 zR!8T5UY0lC8|DkXUY9ZeUa$+ znqLcR0#VcC|GEgWc?1+GAJC-dg!)}z8XtU__PvQyx845PwfMP0O=%r@UG;q^&r=kv zc!(>yxoED$NDYaqOC-=x@jx!p^5)ENuh)SMLlk|o5-KEi7fWg$lA}mVGDa-<{ctkC zR>o@^PdoLU-j|2aKNVI?^xm0SuTXCqX|dO~!?Rnq{ML9t&Z#;f^s;rUtXFzxf_-ld7~=RU;p#@nT6#3WMt^gO6!IPGTDi4X1qgPa6>t=x7~gow3Ak#@gNSb4}HpJ1E&pUyYLbz(7CY#!HD zOJR)}ymupDaCz`f7BHo1Qk}@7^G|>;wS#tNtbm!&eD=wg3}a;^WfvWIN62u$5@~$- zyY$8ymRt@rcY;kB$Qg-S8P=@cKNYvGj?7RJjYH2LGMWGz`RWqkW1{NvYt4X1$V9OZ)9Ap z6Vk8K!qpcL-rCS`(R_hqWOs@>LIJ2VBLv`?tfB`4E6A34Z7|9sb{zZ`I7(%80mDY2m=5f1E^|-Fl<%1Lx3G0DK179%B<3SSvoYR1a&+;4#N zBvq7c9q?TkR(wfV3|?TS&O1}}tHJMP>Nn#%z=Pf;ea~IWfIvvCBxubY04>Rh_^$LB ztGDW$m2>e2X z-a`4{QOgZyM$!*QqrkFD-WMV#+rFf~6|DfS8yuT+iw^%xA6KIqb*4N^{?C<;ytoqv zUAzjk^`v}db6}G*H29!c;nrL>!%S}Je$X1c{J;Qn)xbaY0K{%yUI9%=T^Aik&!PiM zb|Al_1oT^kj`mgF@w-ajcYCxMZo0NEIH}<9Ew54Dd%X;QH_jV9RbT0~D|?%^B3Dx@UIDl&VD3`qUJl z^MP0GCg*su2y|>aKzsX%0Eau~6J1iZE0_AOfV0?t7xy-#m$%Shh8)J-Yv{guSgj9QFD)361*@)nzF;~t&E`SQCC;}&tPHG(wqss zkpq+MJnUlC$z|HPPxLefM?!k>l)97grp{v5a$`~9`a=ksIIvH!FopUMvS}sKow+~f z?>b4JIP}zcvA-6;J9<+|@Xxqi<{%NPVDH5X-9MUEkpIVQ+X#JFkG(M;D4i1KD8`q3 zCd(^p&WXt9c;bOeje3r1L^YwB$zkJ!z$5LlDV}x71C@2-D==?+-rIzi2|1p2W;Y(% zZzb)5yF@t0}k zpT!g%cwPWMvFY=0UO1Km9Zgf>LAdEB!cA(&&?DFi$#{ZnO`}ON{<%G`&kq|pjRKY{ zgdRB2;$R|4)-+>O?8B%~WjD~)INvN^JNaL0V{v?rjy`R^CLkBgj&$v2lZ?c2x`9pO zHMK-6*%-kw(c;}{$z>+o0bSpnT;q`c{883IE^oDKf)3gFrn@V?qn+M6l=j*rR!w?JjSNgw<73D$@$1nbN{o}rYR4_2PK)&H8ZIT}#|qqhE@RmN zk_pr4(2LyIp}7tG5OZPbMFq#I(H^O>`kC+(&DY@V*4?o$x9r)0$%{rGKRy%=-aqhe z=6EnGRYwnRTQZtau~2mND0}`>fIh>nto)VBKhNEBVJ8m1j|WHLPBbO*T?0Q6 z$Pr}W=Oe6pL&WFuCxZKHn`&p;uo~i-zfZI<60-Qcn>RHdv3B26UY3irxlk$^cH1e_ zX80bUuy`6iA=N&6uEmEhnpCOFp{wzI==87Hbb34$hf`8;unhaw&1J{n+_7<+b)-z9 zUhUX+I3UrwO-JqZZt0-_;N{)MndRvpX>Cz1BfXqn(@73^uEe)DZu@uUD{AAGB-F!h zuLm%pegzhV68nvl+${{8Fr8DyMkhaZ5ND9 zU7&;9llhbX+O5a8JFg8{(nZg2e5Q9=Q1@&)SM~eA0Mh69sk;TCR4IMvl9|x9i$G{w zAotVMdB=Q$lVbj|tYECC`ke}$Nw1$Ft2uW&U(Gat>mMgq6P|!>;qt5PaBKGxl1u`8 z&^EoX^6n`@&*?5}16;-m-pMg+4Eu>5O-;BC1Yx8y4 z(F2QWo0dhgoy~0PmSlwOD^6DT%S#AOQvnn70f%8g4ZNrRVxqu%4P55(Rz z>87`Nbjl)4G@dx6w6)V{6=*+l54M^0ZMPy%mmEtjTKwXhg8wML6T`eX+R_;JVF5)tfhe72% z?0`OGAl--)eM|y7qJ}Gz@6c#uRci@eBsGJ3K;J?Dr3>(!zD4AdaNhSVSN4L1D$OP3 z8=q;GX$ABytaV_4_$=C~Bw%*`vE++N^XR!ovr)%p@1s;9zYf_Bg_#DvdNcNlG8}r; zDhw|ku=!Y$Lc)no121yFNo7!NrQ z46sgaBP*S1r|>`t!BB$H#hl|a^EzY(?|ykxUIYyV8`rDj_Oja#9fS;&tY5N=qQt>P zmZ+pjpCfdW_}5p2uAJ7RVT;0wgDOML{O36WG~_w{Ux6!Uz;r$g{3q1(vTGoKHT3w+ z8g|I}#yI$uYJdFAk7Jz{zHKYKB#EF=3=P?(0`m5Z2qgI^_XMc|Tmj3Bb_ICf2UN2g z<6Xn}pzze@n9J8m#B!QbV^`zYnsFm@Q=Jcc^i^TMB4prg{gGV+F<5{Ca?BrfdZ%5x zlmn0wPAFk(&YTa4+1}Wdyt={zd{2k0AXa1x40`bL%_h+rsb&yi1jLF@*H#>thdXxY zDU9`{N&zL^Wr5{d1Fj^Q0m8W%a8x@$C_hr#C%9e|1+3gopcdGM{M?4&Z+P7g=YeZCAuhHDwTvc#CtNcHaxx7YxQ$qv8NfIs(`{ zL6G1-{v!$>_*MYqF>M&JV`$b1fI(eVk-dQ-KzCk1x1_0ZOn{H6ksSuQMZs7I%Ay-a zp(G2p7>a%R18TOCt+o|6Y+!!&@}1pQ79~x&bE%*|oGY0tohzFwpQEk7C8gky;L(|d zqNxH?@%uogrpOfffsz*eDPkg3Q(R;F#J6&%asP?b@|--*2#9|$>xo*V;1lp(Rsxx> znR0^s+nJ$;Zuz4wh3_165^sjcsKy`9nUg^wo1Q1Hit&Rm{Sw?>hVX;)P?X!Kml}}h zSUFJLuSw9OBi#*ur}lnAHu*P3CL1$(v3szSydA1=C=*EUhCTUPt}WeG^aEZK{FG1G z$>-n>ltf5+P_wcZFoJey@ftG#`8ke0;0;#Q5#ZUka$A6}-yr^?rccn6Ny@Cz{E=0? zIGv`ejjm}Iy~ZpZH*oSSCh2s`57lo#) z$R5V~+?Y+hy)k3YB+pOa!9@rvwaNihO=0C=sMGHa%s0R(N^RwiVA{pBX9^qsf~i2w^@bW7o2eo!#=u?x;vfj8(KC%3S^U#bg}A{32pW7R7iVe& z%vPIT^j#F0$9e^GZlsCQ1s3QL#|WpOqk>TDi-BX6a^ehmjO6bCu~JXD(G7aTY*r!B z=K4du>=iutgL8G3 zbFV>m{(~%DosbIzYj^x-($`Z2I*O#$@?3-0+6=akZI$y=X1hOp{Cf=y(5@$Y`yr z5^h%o8C`yTiYu+luTur~kzgRt+pi0siF*9J^VbE7#QFV#!V>b_lv(A|rJ$vd!qCi)MZMd~i-; zx(JDJ+!8Y%4pO1xo@La^avj;+cKbZvb$ax3Kij;^iXfn64wOz8_*r$ZS+Nt``>a6>3=wB`%wfVtzMZLWrHhoNSat?9 z?-mRHDsmiCwx(_GlvxZxA?|-oRwtPAE&hUwVZr-bbijC}d|O%G|5OI8qJUswJ}*5# zeCLWv$Fb_ZdFI1l$=f68fbaW%pgM`M3@a^U5R>ill@@r5l;uiN?+CRl{fvdKlCqN$ zlH~23B}n_M5?E|_TbE&}mbKFaownr7;jmCgU;_$hp45#PgQm{*a0Apo3qZ>?cAjO1{bi?Fgn{<%4 zEkH=h47F+gQQ(^36!bi~)-||(SlMFA)f8v6y}!z`9f$*6BWrLy`i(Y@cJBIiPZ?!Z zZ8?bkI@u{C|B4)GVE$P3u<}!?Zx5g?M5d72TG5&>_zr>43y2-bdw)j0w=8c*UyNVY zW3BC-qSsH$yW&qIMFM4d=RRoNiC}KTGwr{QA5ta2fx1-7=9bn+!@E6TZzNvG$TY^= zS)kOYEi1L}=`7J`A!ka*bU6l@{M?Dmm!Z1E*nE&uz5IPd2-ndL1MR(L1P@wG@@O@` zt&W%xZX7qb0)9Wo%z6pH%yM_trG4__V$}BHjdd<4G~UHP2p&)@jeCyVVD*9Kb3nmq z`-#sQd=EKG9E-D8l#Ej2O>oq{usv6Mv&W~^U}8`5=*5}TMpf_p=GQjKtHF(1{4X@w z0@PO1Yq?Zo*5F_8L?O&^y%(koxE3pw=z}Fx^TO0d<|*S0LW&nHbBqD4y5@|d#x)xe z#=`;iU0xm#&B3{`^%nco?&4nob9Ui-#rsJD&?Q4WAaus*kaUEZN9 z;s2%s1y?$6wr}g(uH3wY{2}R{?S|(HYEJOUOyY4Bh(t@^NVtQdI<{o6U9_3=Srj_F z1cD^a3!~yJtMMc}5sJ2%Y~!;CSl$myHOiG5Al9NxF`>KQ-|IYz%@3*WybT-fLmt|V zAIeUWlS44~AY?=;6ls!dv8nApO`$j#Z`y#nKUPyavjIV9?sk!3>BceE!6RKyE{wvK zI3BgY&n872V$WXk(+`%CfQ}^ zyoa?Pik?n!K}uoaJ$yic;F0jdHv7skG~Yqx`?5`;XdK`v!Sw< z`nLu6UyQo5X=hT8Pe9Ajbeqt$tE^hnz!igzloe*C-O%%|j-v1_Igo$a}IH5d36H88SQSDM<$1t#`I2+lSdq8HD z_!lT?yfAM+&5Xai$n>R<^d!A+rc%eBMJdr+9(L61PoGsCbBpMJ7WO*kH9~!|?A+4M zcNbw-^yj5hdF&Q1_pu+xW5~SYxfutB)Yg#eAqGOT5&F=gYcON{92d`YV;4Pke%hF! zcF5;y-=Fw%CqcUt`0+AA*lUuL+;c>IQ4@MRq&INy8G7T1Hd64rvDaHpKd6ne@o=vZbRx z;!rh+44!hRo%D@|9^?~4o&j+aS2B6wJa%#bFGu``m`(s$4^+U4 zNw|xZwb#uM#Kj4E1;1Em6oT!RWTE_xL%q#u+*(-6gBm72G+uv zxEr?ehK*;}b$N9U0dYD{wXi>T{7~Ac)SPSZqp@C|$u*OA3xYScSKHl=pKGy;m;3ka5JT+iXv>66Ee9Y&$bPd)L>7B8drpkUjg;) zt>1t!z-obmDa2b0C+pAR|NfhRq0^hxal`FjETimFjVDkR^q~ZM%Lpbe63%&cuCW&y z#IpK)o|;ChWH!&t-hz*x91r`p0dmB0dkt)vIh+w5CQi5S)G9Ok)me$ZCnT>$TQXIh06aX6I3s)b#`Oiz|K&JWSSjKV>)CRs9S83 z-GFmB)O3Ppfp|(GjOJSf7Yt{aOFEo;uqyI}sUDeCx2Ch@fM0IvFTOFW`R-jxm zz$55dAkvTx=n`X&9HdUec6l{J#XRw53>EL$DpxwsmI}PmxEC9p+H*r!#j`dO(jG`)aS*k;c41}hV$p!>Upvn~obud;}bRfgQoe|u(jB2rVnPu^a^ zj^nCC+%s$Yt5Rk4V3MzyZF@tsIs+570|Z>2m#c;$8iCz44W5N-PkRcbL|cV@1ND`q zP--8Pr;w}5{!-{P>SDly2CCYj{;s974*T$b6fo}3#L}{vUF{rKARcOFp2zXb%jO%& ztR4{b!qC^i&|h!lkI4?iCk}R*VGXp04AXmZ3bzYRDmZ;svoiYFtbd6LIti6M5a(jb zd)&7lwR@Fzu3_Q*7(kxzBb6vr^&CI>+R;)M!iEmDlq}dUFlTPU?T-4o&ngpkIK$Y{ zwiNQZ0NJ4x(1U__WJ0H7> zQtw^cDNl)*zuGv3=V*N{Cn{K8P-~(BO;8dhY4*Urw}bOr+{V!Yb+bNlN_I9uLf!ws z$Adk$D5;NsS0$)l(4?+gj>w{wlf?M1zo^(->PJ?2@3Ym-^|e$Vp9)c#D{kmei^e54 zNh6lSnqwhz7eW6{R9DH=2~+48h}LxgXVDF`0Zl-IBU+e)-to+VxQP$1Z#1Ndg5Gm+ zYAC=Pjo?+RffOV_cLM0^v`?+=CxC!24LX7zXtebSm+zMVytAG!%l$YLlOK>XKPCADu5xq3l0m8g4`PwnJ$>dqD;lH zBM};C_VP|7eD8oDuGb%t3f&xKaPxgYVT^?;(D?ECJcfh1kM#u*Lk5T^HVa0`8V?Ps z4Uo4vvf{sf%>akwR%9-RLxY+R7Y6opcb`ottG3-{tAu(jl*AUGK5`;#%BckYK5oeKgJ-DYv&oy^1$0#l64mkuP!EHlOo+JZ8esNn8(>a$Lg1z6zxl8- zL$|(#5(xV8*X2!qiX}L|x$zv0(0%hPgH~oAJ@}?YV=m~d4jt%tAh-y`3z4m5fxM|B zF2>ZpK%*<6C2#%+kZ~mM1Oxxk>vEw;^}txsUfCz$_-3SMPnWT{yVdGE*1}J!YBkPL zQ+ovt#2?b&K)gH~t^H>bCM=zIFW(e02Q=X+B}d(Ka(krQg&b~2+b$W_)#@=~s^x_k z=`=@RlqHxY%|7LB9hlQw=bcBjP8Hmc_G0IwwBmY+_FA(+h`_(& zK(&A?feu+;z;jE99{?2gfB)gwf9ZzaOvH(AeTxo-&;H1~?j6M_q literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-120x120.png b/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-120x120.png new file mode 100644 index 0000000000000000000000000000000000000000..1427cf62752646ad7217df0a61aa01fdef7475d1 GIT binary patch literal 3369 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 ROru=^AazZ3N)e9H{|11FNXq~K literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-152x152.png b/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-152x152.png new file mode 100644 index 0000000000000000000000000000000000000000..f24d454a2ecb8851bb893192b64ee09386d30e24 GIT binary patch literal 4046 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 cK^5JQ0?3d{m_4Kdj*!1;003@kYpI!lw*K!+ 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�MrHbYR_buu=L>f*wO=Er8~{qfkYT+HoHag8)VqJoC-#@ zNT})4xRE%sP-B9?xmL5!2Y8VLa?yj@Y@r1C)6o~9GF9nWG!SI2VJ$>ejtUE%Qv&r_ zYLgZ0h3iIrw7{TyurC(g^$XT%PP5`FB3aFpP&fM-8!J#3I_ujG?;7(Xv5ni%BjYP4 z^+oydy=)_&bdxYJx`X%G5PFkUB%3h6RiOs^F?#ojsB%DbfhqzGhuv4)S1%vw@PDyE z3xWF{Y^0>+=Wg! z{>z@$rD6ej*V- z^$zKIOWOfdN4~7@ndhru01+3cxwD&_Muyja({*O;-5VnF(e$WDALNStE{1{F#ts+VR{o zSlQ*@U=Du8fgKW$lU~)O)b6FS?H1SSnKVIC=DOvbo8IUvM zVf+U4YxG%qLGd%ew7Jp8>@U`ew+A#Q=2oJHNH@_f!WadS20$KZEZ+BHAvU@FB zzRCYN5r+Z#g`C^hrH$yW7ABstwjvMM*CHGzY41bbo2zy$6E8DAOPn zUnHG?e7?u7pQ}Kqbu1jEd+=mcGea4aL6V4g(m*b7x}z|ijsjb3e|tf-3&^JK{=sWz z8sqIu9jy)#J}n}cXqtXmkb-NDVPcAKn=G9uX42zYvufu_OCr>xJ=oTNp8WA5wEqvM z{r~m8;7_C>U68iRr@|rd7UYhON#(-S_+Uf>s)hhPU{{exlxc&eD literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-60x60.png b/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/apple-touch-icon-60x60.png new file mode 100644 index 0000000000000000000000000000000000000000..cf10a5602e653bb126332934e2b7f34081c19a01 GIT binary patch literal 1491 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

aZW9cb|x>1jZDoAu$NpeWiVk@{x{! zmmBmDgx|qNN?LyIrl9$qmj{KjZ8zpa=4edK3FuFS$KFl}bWPoO*Ax#Z1c2#3JAN(O zYhi>`%H9fSnLkAq|5vs>+?U*bdfMc6TmDu+QqnN9xgfZsG25($^;v7U1nBl9Q^o*i z)&?UaYZ=~7XZa75xPKB1s~MB1m<*dN08pqiy*q!)_Kc|;EZs3&nNdMQ5#LFu+J z?*($vO)$hkMOVc16f-ep;K@_~&Y6t?0t9I0(lBkZBfic|u)3pK$Xv=A@jUQnB2sC` zbI)L9m;VNkWOao}2c3b4_u4+bg zuf-@d1$?asdD1~mORQ02#!&1Xm#41*xz}wETNqKb;kueQ*~OpcAXTpJFYUYcKoA&Z z8Ke=2Vh~cu_uTb&6AH75L!k8zo~&wRsDLs^3YkD2!~;%u6sFrzV2A5(FQ|3}+0-K- zWX)W2yq%?^)iKhyMGPB5*DnWBaLqAHLJ47;r5nvkeq3u_?J{Xaf_}6I+xpLwKS7NC z|KYU%zup)8i85jc)^Yt*I0W8;+zHUI3V7@o;3DUYasdq>DFK%im4J)F?;|B-<=}8R z>HESGa5)KyCnGII|E+YX&h4Y+xCRvyX@oGhhG4 j58+{W$RJv~NLLKlV4)8v^7hU(R-4l(}$teLl` literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/favicon-16x16.png b/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..42af00963d81b8e39a30435c60ac482d1f8756e0 GIT binary patch literal 799 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!63?wyl`GbKJOS+@4BLl<6e(pbstU$g(vPY0F z14ES>14Ba#1H&(%P{RubhEf9thF1v;3|2E37{m+a>WRE8{w#)hawXn|-Xp4{E;v!=;4B^%-x&;Cm1 zP>^*#n_J!T^1SBMI!C4h-R53dN8`?ylD}d{L%(vZvUKT)~-CgWFQy3lt zIqW5#zOL*K8HL%o&D;R|TePl5?VWhq^wrj^qed%lKKkpp-FogeyEi+p zE?K8rW7E1fuEJ{5jaaAp0~aIt+keS?T)@vXM=*X}V#VGMCm1~v-+0wr{w3CJ-R8wG zS@XVpzqP-5Mf0H?y-zh=XVL>S6E;rKnDmrMQlmoKbK9p$evXN`oe{6g>lvi)-+#c) zb+Al&$zRqtWk1@VTt6MPmq9d7^!kmXZn8k{sFt`!l%ynwlArU1(iRB6fMfqu& zIjIUIl?AB^nFS@u3=9=>9)IHDC=AokIOTu(jOWuJ24-b$y<~1-Wnu5hBFw@HE)6D! wQ<#-EhbWxBaplC3Ge=~Ou%B-5Sm33{@Jd{;RG<|Mp00i_>zopr0DGh}-~a#s literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/favicon-32x32.png b/orange-demo-flowable/orange-demo-flowable-web/public/img/icons/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..46ca04dee251a4fa85a2891a145fbe20cc619d96 GIT binary patch literal 1271 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 + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + diff --git a/orange-demo-flowable/orange-demo-flowable-web/public/index.html b/orange-demo-flowable/orange-demo-flowable-web/public/index.html new file mode 100644 index 00000000..011aade2 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/public/index.html @@ -0,0 +1,16 @@ + + + + + + + 橙单代码生成平台 + + + +

+ + + diff --git a/orange-demo-flowable/orange-demo-flowable-web/public/robots.txt b/orange-demo-flowable/orange-demo-flowable-web/public/robots.txt new file mode 100644 index 00000000..eb053628 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/public/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/App.vue b/orange-demo-flowable/orange-demo-flowable-web/src/App.vue new file mode 100644 index 00000000..7e16a155 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/App.vue @@ -0,0 +1,21 @@ + + + diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/DictionaryController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/DictionaryController.js new file mode 100644 index 00000000..834ab047 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/DictionaryController.js @@ -0,0 +1,84 @@ +import * as staticDict from '@/staticDict' + +export default class DictionaryController { + static dictSysUserStatus () { + return new Promise((resolve) => { + resolve(staticDict.SysUserStatus); + }); + } + static dictSysUserType () { + return new Promise((resolve) => { + resolve(staticDict.SysUserType); + }); + } + static dictSysDept (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/upms/sysDept/listDict', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase('部门字典'); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictSysDeptByParentId (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/upms/sysDept/listDictByParentId', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase('部门字典'); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictAreaCode (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/app/areaCode/listDict', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase('行政区划'); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictAreaCodeByParentId (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/app/areaCode/listDictByParentId', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase('行政区划'); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } + static dictAddAreaCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'post', params, axiosOption, httpOption); + } + static dictDeleteAreaCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'post', params, axiosOption, httpOption); + } + static dictUpdateAreaCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'post', params, axiosOption, httpOption); + } + static dictReloadAreaCodeCachedData (sender, params, axiosOption, httpOption) { + return sender.doUrl('', 'get', params, axiosOption, httpOption); + } + static dictSysDataPermType () { + return new Promise((resolve) => { + resolve(staticDict.SysDataPermType); + }); + } + static dictDeptPost (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('admin/upms/sysDept/listSysDeptPostWithRelation', 'get', params, axiosOption, httpOption).then(res => { + resolve(res.data); + }).catch(err => { + reject(err); + }); + }); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysDataPermController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysDataPermController.js new file mode 100644 index 00000000..15fd5ccc --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysDataPermController.js @@ -0,0 +1,61 @@ +export default class SysDataPermController { + /** + * @param params {dataPermId, dataPermName, deptIdListString} + */ + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/add', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId, dataPermName, deptIdListString} + */ + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/update', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId} + */ + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/delete', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermName} + */ + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/list', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId} + */ + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/view', 'get', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId, searchString} + */ + static listDataPermUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/listDataPermUser', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId, userIdListString} + */ + static addDataPermUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/addDataPermUser', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {dataPermId, userId} + */ + static deleteDataPermUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/deleteDataPermUser', 'post', params, axiosOption, httpOption); + } + + static listNotInDataPermUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDataPerm/listNotInDataPermUser', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysDeptController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysDeptController.js new file mode 100644 index 00000000..caabeedd --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysDeptController.js @@ -0,0 +1,49 @@ +export default class SysDeptController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('admin/upms/sysDept/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/delete', 'post', params, axiosOption, httpOption); + } + + static listNotInSysDeptPost (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/listNotInSysDeptPost', 'post', params, axiosOption, httpOption); + } + + static listSysDeptPost (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/listSysDeptPost', 'post', params, axiosOption, httpOption); + } + + static addSysDeptPost (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/addSysDeptPost', 'post', params, axiosOption, httpOption); + } + + static updateSysDeptPost (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/updateSysDeptPost', 'post', params, axiosOption, httpOption); + } + + static deleteSysDeptPost (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/deleteSysDeptPost', 'post', params, axiosOption, httpOption); + } + + static viewSysDeptPost (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/viewSysDeptPost', 'get', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysPostController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysPostController.js new file mode 100644 index 00000000..665dcf7b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysPostController.js @@ -0,0 +1,21 @@ +export default class SysPostController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysPost/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysPost/view', 'get', params, axiosOption, httpOption); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysPost/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysPost/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/upms/sysPost/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysUserController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysUserController.js new file mode 100644 index 00000000..92d627d3 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SysUserController.js @@ -0,0 +1,25 @@ +export default class SysUserController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('admin/upms/sysUser/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SystemController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SystemController.js new file mode 100644 index 00000000..75a4fd01 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/Controller/SystemController.js @@ -0,0 +1,252 @@ +export default class SystemController { + static login (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/login/doLogin', 'post', params, axiosOption, httpOption); + } + + static logout (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/login/doLogout', 'post', params, axiosOption, httpOption); + } + + static changePassword (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/login/changePassword', 'post', params, axiosOption, httpOption); + } + + static getLoginInfo (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/login/getLoginInfo', 'get', params, axiosOption, httpOption); + } + + static getDictList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDict/list', 'post', params, axiosOption, httpOption); + } + + static getRoleList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/list', 'post', params, axiosOption, httpOption); + } + + static getRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/view', 'get', params, axiosOption, httpOption); + } + + static deleteRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/delete', 'post', params, axiosOption, httpOption); + } + + static addRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/add', 'post', params, axiosOption, httpOption); + } + + static updateRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/update', 'post', params, axiosOption, httpOption); + } + + static getUserList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/list', 'post', params, axiosOption, httpOption); + } + + static getUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/view', 'get', params, axiosOption, httpOption); + } + + static resetUserPassword (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/resetPassword', 'post', params, axiosOption, httpOption); + } + + static deleteUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/delete', 'post', params, axiosOption, httpOption); + } + + static addUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/add', 'post', params, axiosOption, httpOption); + } + + static updateUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/update', 'post', params, axiosOption, httpOption); + } + + static addDepartment (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/add', 'post', params, axiosOption, httpOption); + } + + static deleteDepartment (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/delete', 'post', params, axiosOption, httpOption); + } + + static updateDepartment (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/update', 'post', params, axiosOption, httpOption); + } + + static getDepartmentList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysDept/list', 'post', params, axiosOption, httpOption); + } + + // 菜单接口 + static getMenuPermList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/list', 'post', params, axiosOption, httpOption); + } + static addMenu (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/add', 'post', params, axiosOption, httpOption); + } + + static updateMenu (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/update', 'post', params, axiosOption, httpOption); + } + static deleteMenu (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/delete', 'post', params, axiosOption, httpOption); + } + + static viewMenu (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/view', 'get', params, axiosOption, httpOption); + } + // 权限字接口 + static getPermCodeList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/list', 'post', params, axiosOption, httpOption); + } + + static addPermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/add', 'post', params, axiosOption, httpOption); + } + + static updatePermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/update', 'post', params, axiosOption, httpOption); + } + + static deletePermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/delete', 'post', params, axiosOption, httpOption); + } + + static viewPermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/view', 'get', params, axiosOption, httpOption); + } + + // 权限资源接口 + static getAllPermList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/listAll', 'post', params, axiosOption, httpOption); + } + + static getPermGroupList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/list', 'post', params, axiosOption, httpOption); + } + + static addPermGroup (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/add', 'post', params, axiosOption, httpOption); + } + + static updatePermGroup (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/update', 'post', params, axiosOption, httpOption); + } + + static deletePermGroup (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermModule/delete', 'post', params, axiosOption, httpOption); + } + + static getPermList (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/list', 'post', params, axiosOption, httpOption); + } + + static viewPerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/view', 'get', params, axiosOption, httpOption); + } + + static addPerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/add', 'post', params, axiosOption, httpOption); + } + + static updatePerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/update', 'post', params, axiosOption, httpOption); + } + + static deletePerm (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/delete', 'post', params, axiosOption, httpOption); + } + /** + * @param params {roleId, searchString} + */ + static listRoleUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/listUserRole', 'post', params, axiosOption, httpOption); + } + + static listNotInUserRole (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/listNotInUserRole', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {roleId, userIdListString} + */ + static addRoleUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/addUserRole', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {roleId, userId} + */ + static deleteRoleUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/deleteUserRole', 'post', params, axiosOption, httpOption); + } + + /** + * @param params {} + */ + static queryRoleByPermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/listAllRolesByPermCode', 'post', params, axiosOption, httpOption); + } + // 权限查询 + static listSysPermWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/listSysPermWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysPermCodeWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/listSysPermCodeWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysMenuWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysUser/listSysMenuWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysPermByRoleIdWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/listSysPermWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysPermCodeByRoleIdWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysRole/listSysPermCodeWithDetail', 'get', params, axiosOption, httpOption); + } + + static listMenuPermCode (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/listMenuPerm', 'get', params, axiosOption, httpOption); + } + + static listSysPermByMenuIdWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/listSysPermWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysUserByMenuIdWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysMenu/listSysUserWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysUserByPermCodeIdWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/listSysUserWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysRoleByPermCodeIdWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPermCode/listSysRoleWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysUserByPermIdWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/listSysUserWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysRoleByPermIdWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/listSysRoleWithDetail', 'get', params, axiosOption, httpOption); + } + + static listSysMenuByPermIdWithDetail (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/sysPerm/listSysMenuWithDetail', 'get', params, axiosOption, httpOption); + } + // 在线用户 + static listSysLoginUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/loginUser/list', 'post', params, axiosOption, httpOption); + } + + static deleteSysLoginUser (sender, params, axiosOption, httpOption) { + return sender.doUrl('admin/upms/loginUser/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowCategoryController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowCategoryController.js new file mode 100644 index 00000000..52098e56 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowCategoryController.js @@ -0,0 +1,21 @@ +export default class FlowCategoryController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowCategory/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowCategory/view', 'get', params, axiosOption, httpOption); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowCategory/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowCategory/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowCategory/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowDictionaryController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowDictionaryController.js new file mode 100644 index 00000000..e453c9c9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowDictionaryController.js @@ -0,0 +1,15 @@ +import * as staticDict from '@/staticDict'; + +export default class FlowDictionaryController { + static dictFlowCategory (sender, params, axiosOption, httpOption) { + return new Promise((resolve, reject) => { + sender.doUrl('/admin/flow/flowCategory/listDict', 'get', params, axiosOption, httpOption).then(res => { + let dictData = new staticDict.DictionaryBase(); + dictData.setList(res.data); + resolve(dictData); + }).catch(err => { + reject(err); + }); + }); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowEntryController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowEntryController.js new file mode 100644 index 00000000..e72a328d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowEntryController.js @@ -0,0 +1,49 @@ +export default class FlowEntryController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/view', 'get', params, axiosOption, httpOption); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/delete', 'post', params, axiosOption, httpOption); + } + + static publish (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/publish', 'post', params, axiosOption, httpOption); + } + + static listFlowEntryPublish (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/listFlowEntryPublish', 'get', params, axiosOption, httpOption); + } + + static updateMainVersion (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/updateMainVersion', 'post', params, axiosOption, httpOption); + } + + static suspendFlowEntryPublish (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/suspendFlowEntryPublish', 'post', params, axiosOption, httpOption); + } + + static activateFlowEntryPublish (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/activateFlowEntryPublish', 'post', params, axiosOption, httpOption); + } + + static viewDict (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/viewDict', 'get', params, axiosOption, httpOption); + } + + static listDict (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntry/listDict', 'get', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowEntryVariableController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowEntryVariableController.js new file mode 100644 index 00000000..d85d7ce9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowEntryVariableController.js @@ -0,0 +1,21 @@ +export default class FlowEntryVariableController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntryVariable/list', 'post', params, axiosOption, httpOption); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntryVariable/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntryVariable/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntryVariable/delete', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowEntryVariable/view', 'get', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowOperationController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowOperationController.js new file mode 100644 index 00000000..080f6a96 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/FlowController/FlowOperationController.js @@ -0,0 +1,98 @@ +export default class FlowOperationController { + // 启动流程实例并且提交表单信息 + static startAndTakeUserTask (sender, params, axiosOption, httpOption) { + let url = '/admin/flow/flowOnlineOperation/startAndTakeUserTask'; + if (axiosOption && axiosOption.processDefinitionKey) { + url += '/' + axiosOption.processDefinitionKey; + } + return sender.doUrl(url, 'post', params, axiosOption, httpOption); + } + // 获得流程以及工单信息 + static listWorkOrder (sender, params, axiosOption, httpOption) { + let url = '/admin/flow/flowOnlineOperation/listWorkOrder'; + if (axiosOption && axiosOption.processDefinitionKey) { + url += '/' + axiosOption.processDefinitionKey; + } + return sender.doUrl(url, 'post', params, axiosOption, httpOption); + } + // 撤销工单 + static cancelWorkOrder (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/cancelWorkOrder', 'post', params, axiosOption, httpOption); + } + // 提交用户任务数据 + static submitUserTask (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOnlineOperation/submitUserTask', 'post', params, axiosOption, httpOption); + } + // 获取历史流程数据 + static viewHistoricProcessInstance (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOnlineOperation/viewHistoricProcessInstance', 'get', params, axiosOption, httpOption); + } + // 获取用户任务数据 + static viewUserTask (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOnlineOperation/viewUserTask', 'get', params, axiosOption, httpOption); + } + // 获取在线表单工作流以及工作流下表单列表 + static listFlowEntryForm (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOnlineOperation/listFlowEntryForm', 'get', params, axiosOption, httpOption); + } + // 多实例加签 + static submitConsign (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/submitConsign', 'post', params, axiosOption, httpOption); + } + // 已办任务列表 + static listHistoricTask (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/listHistoricTask', 'post', params, axiosOption, httpOption); + } + // 获取已办任务信息 + static viewHistoricTaskInfo (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/viewHistoricTaskInfo', 'get', params, axiosOption, httpOption); + } + // 仅启动流程实例 + static startOnly (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/startOnly', 'post', params, axiosOption, httpOption); + } + // 获得流程定义初始化用户任务信息 * + static viewInitialTaskInfo (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/viewInitialTaskInfo', 'get', params, axiosOption, httpOption); + } + // 获取待办任务信息 * + static viewRuntimeTaskInfo (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/viewRuntimeTaskInfo', 'get', params, axiosOption, httpOption); + } + // 获取流程实例审批历史 * + static listFlowTaskComment (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/listFlowTaskComment', 'get', params, axiosOption, httpOption); + } + // 获取历史任务信息 * + static viewInitialHistoricTaskInfo (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/viewInitialHistoricTaskInfo', 'get', params, axiosOption, httpOption); + } + // 获取所有待办任务 * + static listRuntimeTask (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/listRuntimeTask', 'post', params, axiosOption, httpOption); + } + // 获得流程实例审批路径 * + static viewHighlightFlowData (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/viewHighlightFlowData', 'get', params, axiosOption, httpOption); + } + // 获得流程实例的配置XML * + static viewProcessBpmn (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/viewProcessBpmn', 'get', params, axiosOption, httpOption); + } + // 获得所有历史流程实例 * + static listAllHistoricProcessInstance (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/listAllHistoricProcessInstance', 'post', params, axiosOption, httpOption); + } + // 获得当前用户历史流程实例 * + static listHistoricProcessInstance (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/listHistoricProcessInstance', 'post', params, axiosOption, httpOption); + } + // 终止流程 * + static stopProcessInstance (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/stopProcessInstance', 'post', params, axiosOption, httpOption); + } + // 删除流程实例 * + static deleteProcessInstance (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/flow/flowOperation/deleteProcessInstance', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineColumnController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineColumnController.js new file mode 100644 index 00000000..93c31961 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineColumnController.js @@ -0,0 +1,53 @@ +export default class OnlineColumnController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/online/onlineColumn/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/update', 'post', params, axiosOption, httpOption); + } + + static refreshColumn (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/refresh', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/delete', 'post', params, axiosOption, httpOption); + } + + static listOnlineColumnRule (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/listOnlineColumnRule', 'post', params, axiosOption, httpOption); + } + + static listNotInOnlineColumnRule (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/listNotInOnlineColumnRule', 'post', params, axiosOption, httpOption); + } + + static addOnlineColumnRule (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/addOnlineColumnRule', 'post', params, axiosOption, httpOption); + } + + static deleteOnlineColumnRule (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/deleteOnlineColumnRule', 'post', params, axiosOption, httpOption); + } + + static updateOnlineColumnRule (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/updateOnlineColumnRule', 'post', params, axiosOption, httpOption); + } + + static viewOnlineColumnRule (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineColumn/viewOnlineColumnRule', 'get', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDatasourceController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDatasourceController.js new file mode 100644 index 00000000..c29a9c79 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDatasourceController.js @@ -0,0 +1,25 @@ +export default class OnlineDatasourceController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasource/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasource/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/online/onlineDatasource/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasource/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasource/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasource/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDatasourceRelationController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDatasourceRelationController.js new file mode 100644 index 00000000..8c300193 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDatasourceRelationController.js @@ -0,0 +1,25 @@ +export default class OnlineDatasourceRelationController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasourceRelation/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasourceRelation/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/online/onlineDatasourceRelation/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasourceRelation/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasourceRelation/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDatasourceRelation/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDblinkController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDblinkController.js new file mode 100644 index 00000000..6bb2b067 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDblinkController.js @@ -0,0 +1,13 @@ +export default class OnlineDblinkController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDblink/list', 'post', params, axiosOption, httpOption); + } + + static listDblinkTables (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDblink/listDblinkTables', 'get', params, axiosOption, httpOption); + } + + static listDblinkTableColumns (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDblink/listDblinkTableColumns', 'get', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDictController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDictController.js new file mode 100644 index 00000000..aab324af --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineDictController.js @@ -0,0 +1,25 @@ +export default class OnlineDictController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDict/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDict/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/online/onlineDict/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDict/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDict/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineDict/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineFormController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineFormController.js new file mode 100644 index 00000000..13d555b1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineFormController.js @@ -0,0 +1,29 @@ +export default class OnlineFormController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineForm/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineForm/view', 'get', params, axiosOption, httpOption); + } + + static render (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineForm/render', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/online/onlineForm/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineForm/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineForm/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineForm/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineOperation.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineOperation.js new file mode 100644 index 00000000..5b010818 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineOperation.js @@ -0,0 +1,45 @@ +export default class OnlineOperation { + static listDict (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/listDict', 'post', params, axiosOption, httpOption); + } + + static listByDatasourceId (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/listByDatasourceId', 'post', params, axiosOption, httpOption); + } + + static listByOneToManyRelationId (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/listByOneToManyRelationId', 'post', params, axiosOption, httpOption); + } + + static addDatasource (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/addDatasource', 'post', params, axiosOption, httpOption); + } + + static addOneToManyRelation (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/addOneToManyRelation', 'post', params, axiosOption, httpOption); + } + + static updateDatasource (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/updateDatasource', 'post', params, axiosOption, httpOption); + } + + static updateOneToManyRelation (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/updateOneToManyRelation', 'post', params, axiosOption, httpOption); + } + + static viewByDatasourceId (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/viewByDatasourceId', 'get', params, axiosOption, httpOption); + } + + static viewByOneToManyRelationId (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/viewByOneToManyRelationId', 'get', params, axiosOption, httpOption); + } + + static deleteDatasource (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/deleteDatasource', 'post', params, axiosOption, httpOption); + } + + static deleteOneToManyRelation (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineOperation/deleteOneToManyRelation', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlinePageController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlinePageController.js new file mode 100644 index 00000000..257280d6 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlinePageController.js @@ -0,0 +1,61 @@ +export default class OnlinePageController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/list', 'post', params, axiosOption, httpOption); + } + + static listAllPageAndForm (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/listAllPageAndForm', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/online/onlinePage/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/update', 'post', params, axiosOption, httpOption); + } + + static updatePublished (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/updatePublished', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/delete', 'post', params, axiosOption, httpOption); + } + + static updateStatus (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/updateStatus', 'post', params, axiosOption, httpOption); + } + + static listOnlinePageDatasource (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/listOnlinePageDatasource', 'post', params, axiosOption, httpOption); + } + + static listNotInOnlinePageDatasource (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/listNotInOnlinePageDatasource', 'post', params, axiosOption, httpOption); + } + + static addOnlinePageDatasource (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/addOnlinePageDatasource', 'post', params, axiosOption, httpOption); + } + + static deleteOnlinePageDatasource (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/deleteOnlinePageDatasource', 'post', params, axiosOption, httpOption); + } + + static updateOnlinePageDatasource (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/updateOnlinePageDatasource', 'post', params, axiosOption, httpOption); + } + + static viewOnlinePageDatasource (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlinePage/viewOnlinePageDatasource', 'get', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineRuleController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineRuleController.js new file mode 100644 index 00000000..54eff4fe --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineRuleController.js @@ -0,0 +1,25 @@ +export default class OnlineRuleController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineRule/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineRule/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/online/onlineRule/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineRule/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineRule/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineRule/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineTableController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineTableController.js new file mode 100644 index 00000000..84f1065d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineTableController.js @@ -0,0 +1,25 @@ +export default class OnlineTableController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineTable/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineTable/view', 'get', params, axiosOption, httpOption); + } + + static export (sender, params, fileName) { + return sender.download('/admin/online/onlineTable/export', params, fileName); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineTable/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineTable/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineTable/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineVirtualColumnController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineVirtualColumnController.js new file mode 100644 index 00000000..903dd3c1 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/OnlineFormController/OnlineVirtualColumnController.js @@ -0,0 +1,21 @@ +export default class OnlineVirtualColumnController { + static list (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineVirtualColumn/list', 'post', params, axiosOption, httpOption); + } + + static view (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineVirtualColumn/view', 'get', params, axiosOption, httpOption); + } + + static add (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineVirtualColumn/add', 'post', params, axiosOption, httpOption); + } + + static update (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineVirtualColumn/update', 'post', params, axiosOption, httpOption); + } + + static delete (sender, params, axiosOption, httpOption) { + return sender.doUrl('/admin/online/onlineVirtualColumn/delete', 'post', params, axiosOption, httpOption); + } +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/flowController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/flowController.js new file mode 100644 index 00000000..eb57e436 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/flowController.js @@ -0,0 +1,13 @@ +import FlowDictionaryController from './FlowController/FlowDictionaryController.js'; +import FlowCategoryController from './FlowController/FlowCategoryController.js'; +import FlowEntryController from './FlowController/FlowEntryController.js'; +import FlowEntryVariableController from './FlowController/FlowEntryVariableController.js'; +import FlowOperationController from './FlowController/FlowOperationController.js'; + +export { + FlowDictionaryController, + FlowCategoryController, + FlowEntryController, + FlowEntryVariableController, + FlowOperationController +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/index.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/index.js new file mode 100644 index 00000000..cfe2238b --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/index.js @@ -0,0 +1,15 @@ +import SystemController from './Controller/SystemController' +import SysDataPermController from './Controller/SysDataPermController' +import SysPostController from './Controller/SysPostController.js'; +import DictionaryController from './Controller/DictionaryController' +import SysDeptController from './Controller/SysDeptController.js'; +import SysUserController from './Controller/SysUserController.js'; + +export { + SystemController, + SysDataPermController, + SysPostController, + DictionaryController, + SysDeptController, + SysUserController +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/api/onlineController.js b/orange-demo-flowable/orange-demo-flowable-web/src/api/onlineController.js new file mode 100644 index 00000000..dcbee0d9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/api/onlineController.js @@ -0,0 +1,25 @@ +import OnlineDblinkController from './OnlineFormController/OnlineDblinkController.js'; +import OnlineDictController from './OnlineFormController/OnlineDictController.js'; +import OnlineTableController from './OnlineFormController/OnlineTableController.js'; +import OnlineColumnController from './OnlineFormController/OnlineColumnController.js'; +import OnlinePageController from './OnlineFormController/OnlinePageController.js'; +import OnlineFormController from './OnlineFormController/OnlineFormController.js'; +import OnlineDatasourceController from './OnlineFormController/OnlineDatasourceController.js'; +import OnlineDatasourceRelationController from './OnlineFormController/OnlineDatasourceRelationController.js'; +import OnlineRuleController from './OnlineFormController/OnlineRuleController.js'; +import OnlineVirtualColumnController from './OnlineFormController/OnlineVirtualColumnController.js'; +import OnlineOperation from './OnlineFormController/OnlineOperation.js'; + +export { + OnlineDblinkController, + OnlineDictController, + OnlineColumnController, + OnlineTableController, + OnlinePageController, + OnlineFormController, + OnlineDatasourceController, + OnlineDatasourceRelationController, + OnlineRuleController, + OnlineVirtualColumnController, + OnlineOperation +} diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-blue.scss b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-blue.scss new file mode 100644 index 00000000..5e4966bb --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-blue.scss @@ -0,0 +1,1014 @@ +/* Element Chalk Variables */ + +@mixin linear-gradient ($from, $to, $direction) { + @if variable-exists(to) { + @if variable-exists(direction) { + background: linear-gradient($direction, $from, $to); + } @else { + background: linear-gradient($from, $to); + } + } @else { + background: $from; + } +} + +// Special comment for theme configurator +// type|skipAutoTranslation|Category|Order +// skipAutoTranslation 1 + +/* Transition +-------------------------- */ +$--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default; +$--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--fade-linear-transition: opacity 200ms linear !default; +$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default; +$--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default; + +/* Color +-------------------------- */ +/// color|1|Brand Color|0 +$--color-primary: #0092FF !default; +/// color|1|Background Color|4 +$--color-white: #FFFFFF !default; +/// color|1|Background Color|4 +$--color-black: #000000 !default; +$--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */ +$--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */ +$--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */ +$--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* 8cc5ff */ +$--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* a0cfff */ +$--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* b3d8ff */ +$--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */ +$--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */ +$--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */ +/// color|1|Functional Color|1 +$--color-success: #67C23A !default; +/// color|1|Functional Color|1 +$--color-warning: #E6A23C !default; +/// color|1|Functional Color|1 +$--color-danger: #F56C6C !default; +/// color|1|Functional Color|1 +$--color-info: #909399 !default; + +$--color-success-light: mix($--color-white, $--color-success, 80%) !default; +$--color-warning-light: mix($--color-white, $--color-warning, 80%) !default; +$--color-danger-light: mix($--color-white, $--color-danger, 80%) !default; +$--color-info-light: mix($--color-white, $--color-info, 80%) !default; + +$--color-success-lighter: mix($--color-white, $--color-success, 90%) !default; +$--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default; +$--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default; +$--color-info-lighter: mix($--color-white, $--color-info, 90%) !default; +/// color|1|Font Color|2 +$--color-text-primary: #303133 !default; +/// color|1|Font Color|2 +$--color-text-regular: #606266 !default; +/// color|1|Font Color|2 +$--color-text-secondary: #909399 !default; +/// color|1|Font Color|2 +$--color-text-placeholder: #C0C4CC !default; +/// color|1|Border Color|3 +$--border-color-base: #DCDFE6 !default; +/// color|1|Border Color|3 +$--border-color-light: #E4E7ED !default; +/// color|1|Border Color|3 +$--border-color-lighter: #EBEEF5 !default; +/// color|1|Border Color|3 +$--border-color-extra-light: #F2F6FC !default; + +// Background +/// color|1|Background Color|4 +$--background-color-base: #F5F7FA !default; + +// color for left sidebar title +$--color-sidebar-title-text: #FFFFFF; +// color for left sidebar background +$--color-menu-background: $--color-primary; +$--color-menu-item-active-text-color: #FFFFFF; +$--color-menu-item-active-background: rgba(255, 255, 255, 0.01); +$--color-menu-item-active-background-to: rgba(255, 255, 255, 0.3); + +/* Link +-------------------------- */ +$--link-color: $--color-primary-light-2 !default; +$--link-hover-color: $--color-primary !default; + +/* Border +-------------------------- */ +$--border-width-base: 1px !default; +$--border-style-base: solid !default; +$--border-color-hover: $--color-text-placeholder !default; +$--border-base: $--border-width-base $--border-style-base $--border-color-base !default; +/// borderRadius|1|Radius|0 +$--border-radius-base: 4px !default; +/// borderRadius|1|Radius|0 +$--border-radius-small: 2px !default; +/// borderRadius|1|Radius|0 +$--border-radius-circle: 100% !default; +/// borderRadius|1|Radius|0 +$--border-radius-zero: 0 !default; + +// Box-shadow +/// boxShadow|1|Shadow|1 +$--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default; +// boxShadow|1|Shadow|1 +$--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default; +/// boxShadow|1|Shadow|1 +$--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default; + +/* Fill +-------------------------- */ +$--fill-base: $--color-white !default; + +/* Typography +-------------------------- */ +$--font-path: 'fonts' !default; +$--font-display: 'auto' !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-large: 20px !default; +/// fontSize|1|Font Size|0 +$--font-size-large: 18px !default; +/// fontSize|1|Font Size|0 +$--font-size-medium: 16px !default; +/// fontSize|1|Font Size|0 +$--font-size-base: 14px !default; +/// fontSize|1|Font Size|0 +$--font-size-small: 13px !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-small: 12px !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-primary: 500 !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-secondary: 100 !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-primary: 24px !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-secondary: 16px !default; +$--font-color-disabled-base: #bbb !default; +/* Size +-------------------------- */ +$--size-base: 14px !default; + +/* z-index +-------------------------- */ +$--index-normal: 1 !default; +$--index-top: 1000 !default; +$--index-popper: 2000 !default; + +/* Disable base +-------------------------- */ +$--disabled-fill-base: $--background-color-base !default; +$--disabled-color-base: $--color-text-placeholder !default; +$--disabled-border-base: $--border-color-light !default; + +/* Icon +-------------------------- */ +$--icon-color: #666 !default; +$--icon-color-base: $--color-info !default; + +/* Checkbox +-------------------------- */ +/// fontSize||Font|1 +$--checkbox-font-size: 14px !default; +/// fontWeight||Font|1 +$--checkbox-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--checkbox-font-color: $--color-text-regular !default; +$--checkbox-input-height: 14px !default; +$--checkbox-input-width: 14px !default; +/// borderRadius||Border|2 +$--checkbox-border-radius: $--border-radius-small !default; +/// color||Color|0 +$--checkbox-background-color: $--color-white !default; +$--checkbox-input-border: $--border-base !default; + +/// color||Color|0 +$--checkbox-disabled-border-color: $--border-color-base !default; +$--checkbox-disabled-input-fill: #edf2fc !default; +$--checkbox-disabled-icon-color: $--color-text-placeholder !default; + +$--checkbox-disabled-checked-input-fill: $--border-color-extra-light !default; +$--checkbox-disabled-checked-input-border-color: $--border-color-base !default; +$--checkbox-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--checkbox-checked-font-color: $--color-primary !default; +$--checkbox-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-checked-background-color: $--color-primary !default; +$--checkbox-checked-icon-color: $--fill-base !default; + +$--checkbox-input-border-color-hover: $--color-primary !default; +/// height||Other|4 +$--checkbox-bordered-height: 40px !default; +/// padding||Spacing|3 +$--checkbox-bordered-padding: 9px 20px 9px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-small-padding: 5px 15px 5px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default; +$--checkbox-bordered-medium-input-height: 14px !default; +$--checkbox-bordered-medium-input-width: 14px !default; +/// height||Other|4 +$--checkbox-bordered-medium-height: 36px !default; +$--checkbox-bordered-small-input-height: 12px !default; +$--checkbox-bordered-small-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-small-height: 32px !default; +$--checkbox-bordered-mini-input-height: 12px !default; +$--checkbox-bordered-mini-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-mini-height: 28px !default; + +/// color||Color|0 +$--checkbox-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--checkbox-button-checked-border-color: $--color-primary !default; + + + +/* Radio +-------------------------- */ +/// fontSize||Font|1 +$--radio-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--radio-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--radio-font-color: $--color-text-regular !default; +$--radio-input-height: 14px !default; +$--radio-input-width: 14px !default; +/// borderRadius||Border|2 +$--radio-input-border-radius: $--border-radius-circle !default; +/// color||Color|0 +$--radio-input-background-color: $--color-white !default; +$--radio-input-border: $--border-base !default; +/// color||Color|0 +$--radio-input-border-color: $--border-color-base !default; +/// color||Color|0 +$--radio-icon-color: $--color-white !default; + +$--radio-disabled-input-border-color: $--disabled-border-base !default; +$--radio-disabled-input-fill: $--disabled-fill-base !default; +$--radio-disabled-icon-color: $--disabled-fill-base !default; + +$--radio-disabled-checked-input-border-color: $--disabled-border-base !default; +$--radio-disabled-checked-input-fill: $--disabled-fill-base !default; +$--radio-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--radio-checked-font-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-background-color: $--color-white !default; +/// color||Color|0 +$--radio-checked-icon-color: $--color-primary !default; + +$--radio-input-border-color-hover: $--color-primary !default; + +$--radio-bordered-height: 40px !default; +$--radio-bordered-padding: 12px 20px 0 10px !default; +$--radio-bordered-medium-padding: 10px 20px 0 10px !default; +$--radio-bordered-small-padding: 8px 15px 0 10px !default; +$--radio-bordered-mini-padding: 6px 15px 0 10px !default; +$--radio-bordered-medium-input-height: 14px !default; +$--radio-bordered-medium-input-width: 14px !default; +$--radio-bordered-medium-height: 36px !default; +$--radio-bordered-small-input-height: 12px !default; +$--radio-bordered-small-input-width: 12px !default; +$--radio-bordered-small-height: 32px !default; +$--radio-bordered-mini-input-height: 12px !default; +$--radio-bordered-mini-input-width: 12px !default; +$--radio-bordered-mini-height: 28px !default; + +/// fontSize||Font|1 +$--radio-button-font-size: $--font-size-base !default; +/// color||Color|0 +$--radio-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--radio-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--radio-button-checked-border-color: $--color-primary !default; +$--radio-button-disabled-checked-fill: $--border-color-extra-light !default; + +/* Select +-------------------------- */ +$--select-border-color-hover: $--border-color-hover !default; +$--select-disabled-border: $--disabled-border-base !default; +/// fontSize||Font|1 +$--select-font-size: $--font-size-base !default; +$--select-close-hover-color: $--color-text-secondary !default; + +$--select-input-color: $--color-text-placeholder !default; +$--select-multiple-input-color: #666 !default; +/// color||Color|0 +$--select-input-focus-border-color: $--color-primary !default; +/// fontSize||Font|1 +$--select-input-font-size: 14px !default; + +$--select-option-color: $--color-text-regular !default; +$--select-option-disabled-color: $--color-text-placeholder !default; +$--select-option-disabled-background: $--color-white !default; +/// height||Other|4 +$--select-option-height: 34px !default; +$--select-option-hover-background: $--background-color-base !default; +/// color||Color|0 +$--select-option-selected-font-color: $--color-primary !default; +$--select-option-selected-hover: $--background-color-base !default; + +$--select-group-color: $--color-info !default; +$--select-group-height: 30px !default; +$--select-group-font-size: 12px !default; + +$--select-dropdown-background: $--color-white !default; +$--select-dropdown-shadow: $--box-shadow-light !default; +$--select-dropdown-empty-color: #999 !default; +/// height||Other|4 +$--select-dropdown-max-height: 274px !default; +$--select-dropdown-padding: 6px 0 !default; +$--select-dropdown-empty-padding: 10px 0 !default; +$--select-dropdown-border: solid 1px $--border-color-light !default; + +/* Alert +-------------------------- */ +$--alert-padding: 8px 16px !default; +/// borderRadius||Border|2 +$--alert-border-radius: $--border-radius-base !default; +/// fontSize||Font|1 +$--alert-title-font-size: 13px !default; +/// fontSize||Font|1 +$--alert-description-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-customed-font-size: 13px !default; + +$--alert-success-color: $--color-success-lighter !default; +$--alert-info-color: $--color-info-lighter !default; +$--alert-warning-color: $--color-warning-lighter !default; +$--alert-danger-color: $--color-danger-lighter !default; + +/// height||Other|4 +$--alert-icon-size: 16px !default; +/// height||Other|4 +$--alert-icon-large-size: 28px !default; + +/* MessageBox +-------------------------- */ +/// color||Color|0 +$--messagebox-title-color: $--color-text-primary !default; +$--msgbox-width: 420px !default; +$--msgbox-border-radius: 4px !default; +/// fontSize||Font|1 +$--messagebox-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--messagebox-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--messagebox-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--messagebox-error-font-size: 12px !default; +$--msgbox-padding-primary: 15px !default; +/// color||Color|0 +$--messagebox-success-color: $--color-success !default; +/// color||Color|0 +$--messagebox-info-color: $--color-info !default; +/// color||Color|0 +$--messagebox-warning-color: $--color-warning !default; +/// color||Color|0 +$--messagebox-danger-color: $--color-danger !default; + +/* Message +-------------------------- */ +$--message-shadow: $--box-shadow-base !default; +$--message-min-width: 380px !default; +$--message-background-color: #edf2fc !default; +$--message-padding: 15px 15px 15px 20px !default; +/// color||Color|0 +$--message-close-icon-color: $--color-text-placeholder !default; +/// height||Other|4 +$--message-close-size: 16px !default; +/// color||Color|0 +$--message-close-hover-color: $--color-text-secondary !default; + +/// color||Color|0 +$--message-success-font-color: $--color-success !default; +/// color||Color|0 +$--message-info-font-color: $--color-info !default; +/// color||Color|0 +$--message-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--message-danger-font-color: $--color-danger !default; + +/* Notification +-------------------------- */ +$--notification-width: 330px !default; +/// padding||Spacing|3 +$--notification-padding: 14px 26px 14px 13px !default; +$--notification-radius: 8px !default; +$--notification-shadow: $--box-shadow-light !default; +/// color||Color|0 +$--notification-border-color: $--border-color-lighter !default; +$--notification-icon-size: 24px !default; +$--notification-close-font-size: $--message-close-size !default; +$--notification-group-margin-left: 13px !default; +$--notification-group-margin-right: 8px !default; +/// fontSize||Font|1 +$--notification-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--notification-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--notification-title-font-size: 16px !default; +/// color||Color|0 +$--notification-title-color: $--color-text-primary !default; + +/// color||Color|0 +$--notification-close-color: $--color-text-secondary !default; +/// color||Color|0 +$--notification-close-hover-color: $--color-text-regular !default; + +/// color||Color|0 +$--notification-success-icon-color: $--color-success !default; +/// color||Color|0 +$--notification-info-icon-color: $--color-info !default; +/// color||Color|0 +$--notification-warning-icon-color: $--color-warning !default; +/// color||Color|0 +$--notification-danger-icon-color: $--color-danger !default; + +/* Input +-------------------------- */ +$--input-font-size: $--font-size-base !default; +/// color||Color|0 +$--input-font-color: $--color-text-regular !default; +/// height||Other|4 +$--input-width: 140px !default; +/// height||Other|4 +$--input-height: 40px !default; +$--input-border: $--border-base !default; +$--input-border-color: $--border-color-base !default; +/// borderRadius||Border|2 +$--input-border-radius: $--border-radius-base !default; +$--input-border-color-hover: $--border-color-hover !default; +/// color||Color|0 +$--input-background-color: $--color-white !default; +$--input-fill-disabled: $--disabled-fill-base !default; +$--input-color-disabled: $--font-color-disabled-base !default; +/// color||Color|0 +$--input-icon-color: $--color-text-placeholder !default; +/// color||Color|0 +$--input-placeholder-color: $--color-text-placeholder !default; +$--input-max-width: 314px !default; + +$--input-hover-border: $--border-color-hover !default; +$--input-clear-hover-color: $--color-text-secondary !default; + +$--input-focus-border: $--color-primary !default; +$--input-focus-fill: $--color-white !default; + +$--input-disabled-fill: $--disabled-fill-base !default; +$--input-disabled-border: $--disabled-border-base !default; +$--input-disabled-color: $--disabled-color-base !default; +$--input-disabled-placeholder-color: $--color-text-placeholder !default; + +/// fontSize||Font|1 +$--input-medium-font-size: 14px !default; +/// height||Other|4 +$--input-medium-height: 36px !default; +/// fontSize||Font|1 +$--input-small-font-size: 13px !default; +/// height||Other|4 +$--input-small-height: 32px !default; +/// fontSize||Font|1 +$--input-mini-font-size: 12px !default; +/// height||Other|4 +$--input-mini-height: 28px !default; + +/* Cascader +-------------------------- */ +/// color||Color|0 +$--cascader-menu-font-color: $--color-text-regular !default; +/// color||Color|0 +$--cascader-menu-selected-font-color: $--color-primary !default; +$--cascader-menu-fill: $--fill-base !default; +$--cascader-menu-font-size: $--font-size-base !default; +$--cascader-menu-radius: $--border-radius-base !default; +$--cascader-menu-border: solid 1px $--border-color-light !default; +$--cascader-menu-shadow: $--box-shadow-light !default; +$--cascader-node-background-hover: $--background-color-base !default; +$--cascader-node-color-disabled:$--color-text-placeholder !default; +$--cascader-color-empty:$--color-text-placeholder !default; +$--cascader-tag-background: #f0f2f5; + +/* Group +-------------------------- */ +$--group-option-flex: 0 0 (1/5) * 100% !default; +$--group-option-offset-bottom: 12px !default; +$--group-option-fill-hover: rgba($--color-black, 0.06) !default; +$--group-title-color: $--color-black !default; +$--group-title-font-size: $--font-size-base !default; +$--group-title-width: 66px !default; + +/* Tab +-------------------------- */ +$--tab-font-size: $--font-size-base !default; +$--tab-border-line: 1px solid #e4e4e4 !default; +$--tab-header-color-active: $--color-text-secondary !default; +$--tab-header-color-hover: $--color-text-regular !default; +$--tab-header-color: $--color-text-regular !default; +$--tab-header-fill-active: rgba($--color-black, 0.06) !default; +$--tab-header-fill-hover: rgba($--color-black, 0.06) !default; +$--tab-vertical-header-width: 90px !default; +$--tab-vertical-header-count-color: $--color-white !default; +$--tab-vertical-header-count-fill: $--color-text-secondary !default; + +/* Button +-------------------------- */ +/// fontSize||Font|1 +$--button-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--button-font-weight: $--font-weight-primary !default; +/// borderRadius||Border|2 +$--button-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-padding-vertical: 12px !default; +/// padding||Spacing|3 +$--button-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-medium-font-size: $--font-size-base !default; +/// borderRadius||Border|2 +$--button-medium-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-medium-padding-vertical: 10px !default; +/// padding||Spacing|3 +$--button-medium-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-small-font-size: 12px !default; +$--button-small-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-small-padding-vertical: 9px !default; +/// padding||Spacing|3 +$--button-small-padding-horizontal: 15px !default; +/// fontSize||Font|1 +$--button-mini-font-size: 12px !default; +$--button-mini-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-mini-padding-vertical: 7px !default; +/// padding||Spacing|3 +$--button-mini-padding-horizontal: 15px !default; + +/// color||Color|0 +$--button-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--button-default-background-color: $--color-white !default; +/// color||Color|0 +$--button-default-border-color: $--border-color-base !default; + +/// color||Color|0 +$--button-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--button-disabled-border-color: $--border-color-lighter !default; + +/// color||Color|0 +$--button-primary-border-color: $--color-primary !default; +/// color||Color|0 +$--button-primary-font-color: $--color-white !default; +/// color||Color|0 +$--button-primary-background-color: $--color-primary !default; +/// color||Color|0 +$--button-success-border-color: $--color-success !default; +/// color||Color|0 +$--button-success-font-color: $--color-white !default; +/// color||Color|0 +$--button-success-background-color: $--color-success !default; +/// color||Color|0 +$--button-warning-border-color: $--color-warning !default; +/// color||Color|0 +$--button-warning-font-color: $--color-white !default; +/// color||Color|0 +$--button-warning-background-color: $--color-warning !default; +/// color||Color|0 +$--button-danger-border-color: $--color-danger !default; +/// color||Color|0 +$--button-danger-font-color: $--color-white !default; +/// color||Color|0 +$--button-danger-background-color: $--color-danger !default; +/// color||Color|0 +$--button-info-border-color: $--color-info !default; +/// color||Color|0 +$--button-info-font-color: $--color-white !default; +/// color||Color|0 +$--button-info-background-color: $--color-info !default; + +$--button-hover-tint-percent: 20% !default; +$--button-active-shade-percent: 10% !default; + + +/* cascader +-------------------------- */ +$--cascader-height: 200px !default; + +/* Switch +-------------------------- */ +/// color||Color|0 +$--switch-on-color: $--color-primary !default; +/// color||Color|0 +$--switch-off-color: $--border-color-base !default; +/// fontSize||Font|1 +$--switch-font-size: $--font-size-base !default; +$--switch-core-border-radius: 10px !default; +// height||Other|4 TODO: width 代码写死的40px 所以下面这三个属性都没意义 +$--switch-width: 40px !default; +// height||Other|4 +$--switch-height: 20px !default; +// height||Other|4 +$--switch-button-size: 16px !default; + +/* Dialog +-------------------------- */ +$--dialog-background-color: $--color-white !default; +$--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !default; +/// fontSize||Font|1 +$--dialog-title-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--dialog-content-font-size: 14px !default; +/// fontLineHeight||LineHeight|2 +$--dialog-font-line-height: $--font-line-height-primary !default; +/// padding||Spacing|3 +$--dialog-padding-primary: 20px !default; + +/* Table +-------------------------- */ +/// color||Color|0 +$--table-border-color: $--border-color-lighter !default; +$--table-border: 1px solid $--table-border-color !default; +/// color||Color|0 +$--table-font-color: $--color-text-regular !default; +/// color||Color|0 +$--table-header-font-color: $--color-text-secondary !default; +/// color||Color|0 +$--table-row-hover-background-color: $--background-color-base !default; +$--table-current-row-background-color: rgba(255, 255, 255, .12) !default; +/// color||Color|0 +$--table-header-background-color: $--color-white !default; +$--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, .12) !default; + +/* Pagination +-------------------------- */ +/// fontSize||Font|1 +$--pagination-font-size: 13px !default; +/// color||Color|0 +$--pagination-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-font-color: $--color-text-primary !default; +$--pagination-border-radius: 3px !default; +/// color||Color|0 +$--pagination-button-color: $--color-text-primary !default; +/// height||Other|4 +$--pagination-button-width: 35.5px !default; +/// height||Other|4 +$--pagination-button-height: 28px !default; +/// color||Color|0 +$--pagination-button-disabled-color: $--color-text-placeholder !default; +/// color||Color|0 +$--pagination-button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-hover-color: $--color-primary !default; + +/* Popup +-------------------------- */ +/// color||Color|0 +$--popup-modal-background-color: $--color-black !default; +/// opacity||Other|1 +$--popup-modal-opacity: 0.5 !default; + +/* Popover +-------------------------- */ +/// color||Color|0 +$--popover-background-color: $--color-white !default; +/// fontSize||Font|1 +$--popover-font-size: $--font-size-base !default; +/// color||Color|0 +$--popover-border-color: $--border-color-lighter !default; +$--popover-arrow-size: 6px !default; +/// padding||Spacing|3 +$--popover-padding: 12px !default; +$--popover-padding-large: 18px 20px !default; +/// fontSize||Font|1 +$--popover-title-font-size: 16px !default; +/// color||Color|0 +$--popover-title-font-color: $--color-text-primary !default; + +/* Tooltip +-------------------------- */ +/// color|1|Color|0 +$--tooltip-fill: $--color-text-primary !default; +/// color|1|Color|0 +$--tooltip-color: $--color-white !default; +/// fontSize||Font|1 +$--tooltip-font-size: 12px !default; +/// color||Color|0 +$--tooltip-border-color: $--color-text-primary !default; +$--tooltip-arrow-size: 6px !default; +/// padding||Spacing|3 +$--tooltip-padding: 10px !default; + +/* Tag +-------------------------- */ +/// color||Color|0 +$--tag-info-color: $--color-info !default; +/// color||Color|0 +$--tag-primary-color: $--color-primary !default; +/// color||Color|0 +$--tag-success-color: $--color-success !default; +/// color||Color|0 +$--tag-warning-color: $--color-warning !default; +/// color||Color|0 +$--tag-danger-color: $--color-danger !default; +/// fontSize||Font|1 +$--tag-font-size: 12px !default; +$--tag-border-radius: 4px !default; +$--tag-padding: 0 10px !default; + +/* Tree +-------------------------- */ +/// color||Color|0 +$--tree-node-hover-background-color: $--background-color-base !default; +/// color||Color|0 +$--tree-font-color: $--color-text-regular !default; +/// color||Color|0 +$--tree-expand-icon-color: $--color-text-placeholder !default; + +/* Dropdown +-------------------------- */ +$--dropdown-menu-box-shadow: $--box-shadow-light !default; +$--dropdown-menuItem-hover-fill: $--color-menu-background !default; +$--dropdown-menuItem-hover-color: $--color-white !default; + +/* Badge +-------------------------- */ +/// color||Color|0 +$--badge-background-color: $--color-danger !default; +$--badge-radius: 10px !default; +/// fontSize||Font|1 +$--badge-font-size: 12px !default; +/// padding||Spacing|3 +$--badge-padding: 6px !default; +/// height||Other|4 +$--badge-size: 18px !default; + +/* Card +--------------------------*/ +/// color||Color|0 +$--card-border-color: $--border-color-lighter !default; +$--card-border-radius: 4px !default; +/// padding||Spacing|3 +$--card-padding: 20px !default; + +/* Slider +--------------------------*/ +/// color||Color|0 +$--slider-main-background-color: $--color-primary !default; +/// color||Color|0 +$--slider-runway-background-color: $--border-color-light !default; +$--slider-button-hover-color: mix($--color-primary, black, 97%) !default; +$--slider-stop-background-color: $--color-white !default; +$--slider-disable-color: $--color-text-placeholder !default; +$--slider-margin: 16px 0 !default; +$--slider-border-radius: 3px !default; +/// height|1|Other|4 +$--slider-height: 6px !default; +/// height||Other|4 +$--slider-button-size: 16px !default; +$--slider-button-wrapper-size: 36px !default; +$--slider-button-wrapper-offset: -15px !default; + +/* Steps +--------------------------*/ +$--steps-border-color: $--disabled-border-base !default; +$--steps-border-radius: 4px !default; +$--steps-padding: 20px !default; + +/* Menu +--------------------------*/ +/// fontSize||Font|1 +$--menu-item-font-size: $--font-size-base !default; +/// color||Color|0 +$--menu-item-font-color: $--color-white !default; +/// color||Color|0 +$--menu-background-color: $--color-menu-background !default; +$--menu-item-hover-fill: $--color-menu-item-active-background !default; + +/* Rate +--------------------------*/ +$--rate-height: 20px !default; +/// fontSize||Font|1 +$--rate-font-size: $--font-size-base !default; +/// height||Other|3 +$--rate-icon-size: 18px !default; +/// margin||Spacing|2 +$--rate-icon-margin: 6px !default; +$--rate-icon-color: $--color-text-placeholder !default; + +/* DatePicker +--------------------------*/ +$--datepicker-font-color: $--color-text-regular !default; +/// color|1|Color|0 +$--datepicker-off-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--datepicker-header-font-color: $--color-text-regular !default; +$--datepicker-icon-color: $--color-text-primary !default; +$--datepicker-border-color: $--disabled-border-base !default; +$--datepicker-inner-border-color: #e4e4e4 !default; +/// color||Color|0 +$--datepicker-inrange-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-inrange-hover-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-active-color: $--color-primary !default; +/// color||Color|0 +$--datepicker-hover-font-color: $--color-primary !default; +$--datepicker-cell-hover-color: #fff !default; + +/* Loading +--------------------------*/ +/// height||Other|4 +$--loading-spinner-size: 42px !default; +/// height||Other|4 +$--loading-fullscreen-spinner-size: 50px !default; + +/* Scrollbar +--------------------------*/ +$--scrollbar-background-color: rgba($--color-text-secondary, .3) !default; +$--scrollbar-hover-background-color: rgba($--color-text-secondary, .5) !default; + +/* Carousel +--------------------------*/ +/// fontSize||Font|1 +$--carousel-arrow-font-size: 12px !default; +$--carousel-arrow-size: 36px !default; +$--carousel-arrow-background: rgba(31, 45, 61, 0.11) !default; +$--carousel-arrow-hover-background: rgba(31, 45, 61, 0.23) !default; +/// width||Other|4 +$--carousel-indicator-width: 30px !default; +/// height||Other|4 +$--carousel-indicator-height: 2px !default; +$--carousel-indicator-padding-horizontal: 4px !default; +$--carousel-indicator-padding-vertical: 12px !default; +$--carousel-indicator-out-color: $--border-color-hover !default; + +/* Collapse +--------------------------*/ +/// color||Color|0 +$--collapse-border-color: $--border-color-lighter !default; +/// height||Other|4 +$--collapse-header-height: 48px !default; +/// color||Color|0 +$--collapse-header-background-color: $--color-white !default; +/// color||Color|0 +$--collapse-header-font-color: $--color-text-primary !default; +/// fontSize||Font|1 +$--collapse-header-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-background-color: $--color-white !default; +/// fontSize||Font|1 +$--collapse-content-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-font-color: $--color-text-primary !default; + +/* Transfer +--------------------------*/ +$--transfer-border-color: $--border-color-lighter !default; +$--transfer-border-radius: $--border-radius-base !default; +/// height||Other|4 +$--transfer-panel-width: 200px !default; +/// height||Other|4 +$--transfer-panel-header-height: 40px !default; +/// color||Color|0 +$--transfer-panel-header-background-color: $--background-color-base !default; +/// height||Other|4 +$--transfer-panel-footer-height: 40px !default; +/// height||Other|4 +$--transfer-panel-body-height: 246px !default; +/// height||Other|4 +$--transfer-item-height: 30px !default; +/// height||Other|4 +$--transfer-filter-height: 32px !default; + +/* Header + --------------------------*/ +$--header-padding: 0 20px !default; + +/* Footer +--------------------------*/ +$--footer-padding: 0 20px !default; + +/* Main +--------------------------*/ +$--main-padding: 20px !default; + +/* Timeline +--------------------------*/ +$--timeline-node-size-normal: 12px !default; +$--timeline-node-size-large: 14px !default; +$--timeline-node-color: $--border-color-light !default; + +/* Backtop +--------------------------*/ +/// color||Color|0 +$--backtop-background-color: $--color-white !default; +/// color||Color|0 +$--backtop-font-color: $--color-primary !default; +/// color||Color|0 +$--backtop-hover-background-color: $--border-color-extra-light !default; + +/* Link +--------------------------*/ +/// fontSize||Font|1 +$--link-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--link-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--link-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--link-default-active-color: $--color-primary !default; +/// color||Color|0 +$--link-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--link-primary-font-color: $--color-primary !default; +/// color||Color|0 +$--link-success-font-color: $--color-success !default; +/// color||Color|0 +$--link-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--link-danger-font-color: $--color-danger !default; +/// color||Color|0 +$--link-info-font-color: $--color-info !default; +/* Calendar +--------------------------*/ +/// border||Other|4 +$--calendar-border: $--table-border !default; +/// color||Other|4 +$--calendar-selected-background-color: #F2F8FE !default; +$--calendar-cell-width: 85px !default; + +/* Form +-------------------------- */ +/// fontSize||Font|1 +$--form-label-font-size: $--font-size-base !default; + +/* Avatar +--------------------------*/ +/// color||Color|0 +$--avatar-font-color: #fff !default; +/// color||Color|0 +$--avatar-background-color: #C0C4CC !default; +/// fontSize||Font Size|1 +$--avatar-text-font-size: 14px !default; +/// fontSize||Font Size|1 +$--avatar-icon-font-size: 18px !default; +/// borderRadius||Border|2 +$--avatar-border-radius: $--border-radius-base !default; +/// size|1|Avatar Size|3 +$--avatar-large-size: 40px !default; +/// size|1|Avatar Size|3 +$--avatar-medium-size: 36px !default; +/// size|1|Avatar Size|3 +$--avatar-small-size: 28px !default; + +/* Break-point +--------------------------*/ +$--sm: 768px !default; +$--md: 992px !default; +$--lg: 1200px !default; +$--xl: 1920px !default; + +$--breakpoints: ( + 'xs' : (max-width: $--sm - 1), + 'sm' : (min-width: $--sm), + 'md' : (min-width: $--md), + 'lg' : (min-width: $--lg), + 'xl' : (min-width: $--xl) +); + +$--breakpoints-spec: ( + 'xs-only' : (max-width: $--sm - 1), + 'sm-and-up' : (min-width: $--sm), + 'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md - 1})", + 'sm-and-down': (max-width: $--md - 1), + 'md-and-up' : (min-width: $--md), + 'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg - 1})", + 'md-and-down': (max-width: $--lg - 1), + 'lg-and-up' : (min-width: $--lg), + 'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})", + 'lg-and-down': (max-width: $--xl - 1), + 'xl-only' : (min-width: $--xl), +); diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-dark.scss b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-dark.scss new file mode 100644 index 00000000..ed98457d --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-dark.scss @@ -0,0 +1,1000 @@ +/* Element Chalk Variables */ + +// Special comment for theme configurator +// type|skipAutoTranslation|Category|Order +// skipAutoTranslation 1 + +/* Transition +-------------------------- */ +$--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default; +$--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--fade-linear-transition: opacity 200ms linear !default; +$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default; +$--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default; + +/* Color +-------------------------- */ +/// color|1|Brand Color|0 +$--color-primary: #409EFF !default; +/// color|1|Background Color|4 +$--color-white: #FFFFFF !default; +/// color|1|Background Color|4 +$--color-black: #000000 !default; +$--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */ +$--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */ +$--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */ +$--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* 8cc5ff */ +$--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* a0cfff */ +$--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* b3d8ff */ +$--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */ +$--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */ +$--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */ +/// color|1|Functional Color|1 +$--color-success: #67C23A !default; +/// color|1|Functional Color|1 +$--color-warning: #E6A23C !default; +/// color|1|Functional Color|1 +$--color-danger: #F56C6C !default; +/// color|1|Functional Color|1 +$--color-info: #909399 !default; + +$--color-success-light: mix($--color-white, $--color-success, 80%) !default; +$--color-warning-light: mix($--color-white, $--color-warning, 80%) !default; +$--color-danger-light: mix($--color-white, $--color-danger, 80%) !default; +$--color-info-light: mix($--color-white, $--color-info, 80%) !default; + +$--color-success-lighter: mix($--color-white, $--color-success, 90%) !default; +$--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default; +$--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default; +$--color-info-lighter: mix($--color-white, $--color-info, 90%) !default; +/// color|1|Font Color|2 +$--color-text-primary: #303133 !default; +/// color|1|Font Color|2 +$--color-text-regular: #606266 !default; +/// color|1|Font Color|2 +$--color-text-secondary: #909399 !default; +/// color|1|Font Color|2 +$--color-text-placeholder: #C0C4CC !default; +/// color|1|Border Color|3 +$--border-color-base: #DCDFE6 !default; +/// color|1|Border Color|3 +$--border-color-light: #E4E7ED !default; +/// color|1|Border Color|3 +$--border-color-lighter: #EBEEF5 !default; +/// color|1|Border Color|3 +$--border-color-extra-light: #F2F6FC !default; + +// Background +/// color|1|Background Color|4 +$--background-color-base: #F5F7FA !default; + +// color for left sidebar title +$--color-sidebar-title-text: #FFFFFF; +// color for left sidebar background +$--color-menu-background: #272C34; +$--color-menu-item-active-text-color: #FFFFFF; +$--color-menu-item-active-background: $--color-primary; +/* Link +-------------------------- */ +$--link-color: $--color-primary-light-2 !default; +$--link-hover-color: $--color-primary !default; + +/* Border +-------------------------- */ +$--border-width-base: 1px !default; +$--border-style-base: solid !default; +$--border-color-hover: $--color-text-placeholder !default; +$--border-base: $--border-width-base $--border-style-base $--border-color-base !default; +/// borderRadius|1|Radius|0 +$--border-radius-base: 4px !default; +/// borderRadius|1|Radius|0 +$--border-radius-small: 2px !default; +/// borderRadius|1|Radius|0 +$--border-radius-circle: 100% !default; +/// borderRadius|1|Radius|0 +$--border-radius-zero: 0 !default; + +// Box-shadow +/// boxShadow|1|Shadow|1 +$--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default; +// boxShadow|1|Shadow|1 +$--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default; +/// boxShadow|1|Shadow|1 +$--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default; + +/* Fill +-------------------------- */ +$--fill-base: $--color-white !default; + +/* Typography +-------------------------- */ +$--font-path: 'fonts' !default; +$--font-display: 'auto' !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-large: 20px !default; +/// fontSize|1|Font Size|0 +$--font-size-large: 18px !default; +/// fontSize|1|Font Size|0 +$--font-size-medium: 16px !default; +/// fontSize|1|Font Size|0 +$--font-size-base: 14px !default; +/// fontSize|1|Font Size|0 +$--font-size-small: 13px !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-small: 12px !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-primary: 500 !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-secondary: 100 !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-primary: 24px !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-secondary: 16px !default; +$--font-color-disabled-base: #bbb !default; +/* Size +-------------------------- */ +$--size-base: 14px !default; + +/* z-index +-------------------------- */ +$--index-normal: 1 !default; +$--index-top: 1000 !default; +$--index-popper: 2000 !default; + +/* Disable base +-------------------------- */ +$--disabled-fill-base: $--background-color-base !default; +$--disabled-color-base: $--color-text-placeholder !default; +$--disabled-border-base: $--border-color-light !default; + +/* Icon +-------------------------- */ +$--icon-color: #666 !default; +$--icon-color-base: $--color-info !default; + +/* Checkbox +-------------------------- */ +/// fontSize||Font|1 +$--checkbox-font-size: 14px !default; +/// fontWeight||Font|1 +$--checkbox-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--checkbox-font-color: $--color-text-regular !default; +$--checkbox-input-height: 14px !default; +$--checkbox-input-width: 14px !default; +/// borderRadius||Border|2 +$--checkbox-border-radius: $--border-radius-small !default; +/// color||Color|0 +$--checkbox-background-color: $--color-white !default; +$--checkbox-input-border: $--border-base !default; + +/// color||Color|0 +$--checkbox-disabled-border-color: $--border-color-base !default; +$--checkbox-disabled-input-fill: #edf2fc !default; +$--checkbox-disabled-icon-color: $--color-text-placeholder !default; + +$--checkbox-disabled-checked-input-fill: $--border-color-extra-light !default; +$--checkbox-disabled-checked-input-border-color: $--border-color-base !default; +$--checkbox-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--checkbox-checked-font-color: $--color-primary !default; +$--checkbox-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-checked-background-color: $--color-primary !default; +$--checkbox-checked-icon-color: $--fill-base !default; + +$--checkbox-input-border-color-hover: $--color-primary !default; +/// height||Other|4 +$--checkbox-bordered-height: 40px !default; +/// padding||Spacing|3 +$--checkbox-bordered-padding: 9px 20px 9px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-small-padding: 5px 15px 5px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default; +$--checkbox-bordered-medium-input-height: 14px !default; +$--checkbox-bordered-medium-input-width: 14px !default; +/// height||Other|4 +$--checkbox-bordered-medium-height: 36px !default; +$--checkbox-bordered-small-input-height: 12px !default; +$--checkbox-bordered-small-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-small-height: 32px !default; +$--checkbox-bordered-mini-input-height: 12px !default; +$--checkbox-bordered-mini-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-mini-height: 28px !default; + +/// color||Color|0 +$--checkbox-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--checkbox-button-checked-border-color: $--color-primary !default; + + + +/* Radio +-------------------------- */ +/// fontSize||Font|1 +$--radio-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--radio-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--radio-font-color: $--color-text-regular !default; +$--radio-input-height: 14px !default; +$--radio-input-width: 14px !default; +/// borderRadius||Border|2 +$--radio-input-border-radius: $--border-radius-circle !default; +/// color||Color|0 +$--radio-input-background-color: $--color-white !default; +$--radio-input-border: $--border-base !default; +/// color||Color|0 +$--radio-input-border-color: $--border-color-base !default; +/// color||Color|0 +$--radio-icon-color: $--color-white !default; + +$--radio-disabled-input-border-color: $--disabled-border-base !default; +$--radio-disabled-input-fill: $--disabled-fill-base !default; +$--radio-disabled-icon-color: $--disabled-fill-base !default; + +$--radio-disabled-checked-input-border-color: $--disabled-border-base !default; +$--radio-disabled-checked-input-fill: $--disabled-fill-base !default; +$--radio-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--radio-checked-font-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-background-color: $--color-white !default; +/// color||Color|0 +$--radio-checked-icon-color: $--color-primary !default; + +$--radio-input-border-color-hover: $--color-primary !default; + +$--radio-bordered-height: 40px !default; +$--radio-bordered-padding: 12px 20px 0 10px !default; +$--radio-bordered-medium-padding: 10px 20px 0 10px !default; +$--radio-bordered-small-padding: 8px 15px 0 10px !default; +$--radio-bordered-mini-padding: 6px 15px 0 10px !default; +$--radio-bordered-medium-input-height: 14px !default; +$--radio-bordered-medium-input-width: 14px !default; +$--radio-bordered-medium-height: 36px !default; +$--radio-bordered-small-input-height: 12px !default; +$--radio-bordered-small-input-width: 12px !default; +$--radio-bordered-small-height: 32px !default; +$--radio-bordered-mini-input-height: 12px !default; +$--radio-bordered-mini-input-width: 12px !default; +$--radio-bordered-mini-height: 28px !default; + +/// fontSize||Font|1 +$--radio-button-font-size: $--font-size-base !default; +/// color||Color|0 +$--radio-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--radio-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--radio-button-checked-border-color: $--color-primary !default; +$--radio-button-disabled-checked-fill: $--border-color-extra-light !default; + +/* Select +-------------------------- */ +$--select-border-color-hover: $--border-color-hover !default; +$--select-disabled-border: $--disabled-border-base !default; +/// fontSize||Font|1 +$--select-font-size: $--font-size-base !default; +$--select-close-hover-color: $--color-text-secondary !default; + +$--select-input-color: $--color-text-placeholder !default; +$--select-multiple-input-color: #666 !default; +/// color||Color|0 +$--select-input-focus-border-color: $--color-primary !default; +/// fontSize||Font|1 +$--select-input-font-size: 14px !default; + +$--select-option-color: $--color-text-regular !default; +$--select-option-disabled-color: $--color-text-placeholder !default; +$--select-option-disabled-background: $--color-white !default; +/// height||Other|4 +$--select-option-height: 34px !default; +$--select-option-hover-background: $--background-color-base !default; +/// color||Color|0 +$--select-option-selected-font-color: $--color-primary !default; +$--select-option-selected-hover: $--background-color-base !default; + +$--select-group-color: $--color-info !default; +$--select-group-height: 30px !default; +$--select-group-font-size: 12px !default; + +$--select-dropdown-background: $--color-white !default; +$--select-dropdown-shadow: $--box-shadow-light !default; +$--select-dropdown-empty-color: #999 !default; +/// height||Other|4 +$--select-dropdown-max-height: 274px !default; +$--select-dropdown-padding: 6px 0 !default; +$--select-dropdown-empty-padding: 10px 0 !default; +$--select-dropdown-border: solid 1px $--border-color-light !default; + +/* Alert +-------------------------- */ +$--alert-padding: 8px 16px !default; +/// borderRadius||Border|2 +$--alert-border-radius: $--border-radius-base !default; +/// fontSize||Font|1 +$--alert-title-font-size: 13px !default; +/// fontSize||Font|1 +$--alert-description-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-customed-font-size: 13px !default; + +$--alert-success-color: $--color-success-lighter !default; +$--alert-info-color: $--color-info-lighter !default; +$--alert-warning-color: $--color-warning-lighter !default; +$--alert-danger-color: $--color-danger-lighter !default; + +/// height||Other|4 +$--alert-icon-size: 16px !default; +/// height||Other|4 +$--alert-icon-large-size: 28px !default; + +/* MessageBox +-------------------------- */ +/// color||Color|0 +$--messagebox-title-color: $--color-text-primary !default; +$--msgbox-width: 420px !default; +$--msgbox-border-radius: 4px !default; +/// fontSize||Font|1 +$--messagebox-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--messagebox-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--messagebox-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--messagebox-error-font-size: 12px !default; +$--msgbox-padding-primary: 15px !default; +/// color||Color|0 +$--messagebox-success-color: $--color-success !default; +/// color||Color|0 +$--messagebox-info-color: $--color-info !default; +/// color||Color|0 +$--messagebox-warning-color: $--color-warning !default; +/// color||Color|0 +$--messagebox-danger-color: $--color-danger !default; + +/* Message +-------------------------- */ +$--message-shadow: $--box-shadow-base !default; +$--message-min-width: 380px !default; +$--message-background-color: #edf2fc !default; +$--message-padding: 15px 15px 15px 20px !default; +/// color||Color|0 +$--message-close-icon-color: $--color-text-placeholder !default; +/// height||Other|4 +$--message-close-size: 16px !default; +/// color||Color|0 +$--message-close-hover-color: $--color-text-secondary !default; + +/// color||Color|0 +$--message-success-font-color: $--color-success !default; +/// color||Color|0 +$--message-info-font-color: $--color-info !default; +/// color||Color|0 +$--message-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--message-danger-font-color: $--color-danger !default; + +/* Notification +-------------------------- */ +$--notification-width: 330px !default; +/// padding||Spacing|3 +$--notification-padding: 14px 26px 14px 13px !default; +$--notification-radius: 8px !default; +$--notification-shadow: $--box-shadow-light !default; +/// color||Color|0 +$--notification-border-color: $--border-color-lighter !default; +$--notification-icon-size: 24px !default; +$--notification-close-font-size: $--message-close-size !default; +$--notification-group-margin-left: 13px !default; +$--notification-group-margin-right: 8px !default; +/// fontSize||Font|1 +$--notification-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--notification-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--notification-title-font-size: 16px !default; +/// color||Color|0 +$--notification-title-color: $--color-text-primary !default; + +/// color||Color|0 +$--notification-close-color: $--color-text-secondary !default; +/// color||Color|0 +$--notification-close-hover-color: $--color-text-regular !default; + +/// color||Color|0 +$--notification-success-icon-color: $--color-success !default; +/// color||Color|0 +$--notification-info-icon-color: $--color-info !default; +/// color||Color|0 +$--notification-warning-icon-color: $--color-warning !default; +/// color||Color|0 +$--notification-danger-icon-color: $--color-danger !default; + +/* Input +-------------------------- */ +$--input-font-size: $--font-size-base !default; +/// color||Color|0 +$--input-font-color: $--color-text-regular !default; +/// height||Other|4 +$--input-width: 140px !default; +/// height||Other|4 +$--input-height: 40px !default; +$--input-border: $--border-base !default; +$--input-border-color: $--border-color-base !default; +/// borderRadius||Border|2 +$--input-border-radius: $--border-radius-base !default; +$--input-border-color-hover: $--border-color-hover !default; +/// color||Color|0 +$--input-background-color: $--color-white !default; +$--input-fill-disabled: $--disabled-fill-base !default; +$--input-color-disabled: $--font-color-disabled-base !default; +/// color||Color|0 +$--input-icon-color: $--color-text-placeholder !default; +/// color||Color|0 +$--input-placeholder-color: $--color-text-placeholder !default; +$--input-max-width: 314px !default; + +$--input-hover-border: $--border-color-hover !default; +$--input-clear-hover-color: $--color-text-secondary !default; + +$--input-focus-border: $--color-primary !default; +$--input-focus-fill: $--color-white !default; + +$--input-disabled-fill: $--disabled-fill-base !default; +$--input-disabled-border: $--disabled-border-base !default; +$--input-disabled-color: $--disabled-color-base !default; +$--input-disabled-placeholder-color: $--color-text-placeholder !default; + +/// fontSize||Font|1 +$--input-medium-font-size: 14px !default; +/// height||Other|4 +$--input-medium-height: 36px !default; +/// fontSize||Font|1 +$--input-small-font-size: 13px !default; +/// height||Other|4 +$--input-small-height: 32px !default; +/// fontSize||Font|1 +$--input-mini-font-size: 12px !default; +/// height||Other|4 +$--input-mini-height: 28px !default; + +/* Cascader +-------------------------- */ +/// color||Color|0 +$--cascader-menu-font-color: $--color-text-regular !default; +/// color||Color|0 +$--cascader-menu-selected-font-color: $--color-primary !default; +$--cascader-menu-fill: $--fill-base !default; +$--cascader-menu-font-size: $--font-size-base !default; +$--cascader-menu-radius: $--border-radius-base !default; +$--cascader-menu-border: solid 1px $--border-color-light !default; +$--cascader-menu-shadow: $--box-shadow-light !default; +$--cascader-node-background-hover: $--background-color-base !default; +$--cascader-node-color-disabled:$--color-text-placeholder !default; +$--cascader-color-empty:$--color-text-placeholder !default; +$--cascader-tag-background: #f0f2f5; + +/* Group +-------------------------- */ +$--group-option-flex: 0 0 (1/5) * 100% !default; +$--group-option-offset-bottom: 12px !default; +$--group-option-fill-hover: rgba($--color-black, 0.06) !default; +$--group-title-color: $--color-black !default; +$--group-title-font-size: $--font-size-base !default; +$--group-title-width: 66px !default; + +/* Tab +-------------------------- */ +$--tab-font-size: $--font-size-base !default; +$--tab-border-line: 1px solid #e4e4e4 !default; +$--tab-header-color-active: $--color-text-secondary !default; +$--tab-header-color-hover: $--color-text-regular !default; +$--tab-header-color: $--color-text-regular !default; +$--tab-header-fill-active: rgba($--color-black, 0.06) !default; +$--tab-header-fill-hover: rgba($--color-black, 0.06) !default; +$--tab-vertical-header-width: 90px !default; +$--tab-vertical-header-count-color: $--color-white !default; +$--tab-vertical-header-count-fill: $--color-text-secondary !default; + +/* Button +-------------------------- */ +/// fontSize||Font|1 +$--button-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--button-font-weight: $--font-weight-primary !default; +/// borderRadius||Border|2 +$--button-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-padding-vertical: 12px !default; +/// padding||Spacing|3 +$--button-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-medium-font-size: $--font-size-base !default; +/// borderRadius||Border|2 +$--button-medium-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-medium-padding-vertical: 10px !default; +/// padding||Spacing|3 +$--button-medium-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-small-font-size: 12px !default; +$--button-small-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-small-padding-vertical: 9px !default; +/// padding||Spacing|3 +$--button-small-padding-horizontal: 15px !default; +/// fontSize||Font|1 +$--button-mini-font-size: 12px !default; +$--button-mini-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-mini-padding-vertical: 7px !default; +/// padding||Spacing|3 +$--button-mini-padding-horizontal: 15px !default; + +/// color||Color|0 +$--button-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--button-default-background-color: $--color-white !default; +/// color||Color|0 +$--button-default-border-color: $--border-color-base !default; + +/// color||Color|0 +$--button-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--button-disabled-border-color: $--border-color-lighter !default; + +/// color||Color|0 +$--button-primary-border-color: $--color-primary !default; +/// color||Color|0 +$--button-primary-font-color: $--color-white !default; +/// color||Color|0 +$--button-primary-background-color: $--color-primary !default; +/// color||Color|0 +$--button-success-border-color: $--color-success !default; +/// color||Color|0 +$--button-success-font-color: $--color-white !default; +/// color||Color|0 +$--button-success-background-color: $--color-success !default; +/// color||Color|0 +$--button-warning-border-color: $--color-warning !default; +/// color||Color|0 +$--button-warning-font-color: $--color-white !default; +/// color||Color|0 +$--button-warning-background-color: $--color-warning !default; +/// color||Color|0 +$--button-danger-border-color: $--color-danger !default; +/// color||Color|0 +$--button-danger-font-color: $--color-white !default; +/// color||Color|0 +$--button-danger-background-color: $--color-danger !default; +/// color||Color|0 +$--button-info-border-color: $--color-info !default; +/// color||Color|0 +$--button-info-font-color: $--color-white !default; +/// color||Color|0 +$--button-info-background-color: $--color-info !default; + +$--button-hover-tint-percent: 20% !default; +$--button-active-shade-percent: 10% !default; + + +/* cascader +-------------------------- */ +$--cascader-height: 200px !default; + +/* Switch +-------------------------- */ +/// color||Color|0 +$--switch-on-color: $--color-primary !default; +/// color||Color|0 +$--switch-off-color: $--border-color-base !default; +/// fontSize||Font|1 +$--switch-font-size: $--font-size-base !default; +$--switch-core-border-radius: 10px !default; +// height||Other|4 TODO: width 代码写死的40px 所以下面这三个属性都没意义 +$--switch-width: 40px !default; +// height||Other|4 +$--switch-height: 20px !default; +// height||Other|4 +$--switch-button-size: 16px !default; + +/* Dialog +-------------------------- */ +$--dialog-background-color: $--color-white !default; +$--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !default; +/// fontSize||Font|1 +$--dialog-title-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--dialog-content-font-size: 14px !default; +/// fontLineHeight||LineHeight|2 +$--dialog-font-line-height: $--font-line-height-primary !default; +/// padding||Spacing|3 +$--dialog-padding-primary: 20px !default; + +/* Table +-------------------------- */ +/// color||Color|0 +$--table-border-color: $--border-color-lighter !default; +$--table-border: 1px solid $--table-border-color !default; +/// color||Color|0 +$--table-font-color: $--color-text-regular !default; +/// color||Color|0 +$--table-header-font-color: $--color-text-secondary !default; +/// color||Color|0 +$--table-row-hover-background-color: $--background-color-base !default; +$--table-current-row-background-color: $--color-primary-light-9 !default; +/// color||Color|0 +$--table-header-background-color: $--color-white !default; +$--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, .12) !default; + +/* Pagination +-------------------------- */ +/// fontSize||Font|1 +$--pagination-font-size: 13px !default; +/// color||Color|0 +$--pagination-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-font-color: $--color-text-primary !default; +$--pagination-border-radius: 3px !default; +/// color||Color|0 +$--pagination-button-color: $--color-text-primary !default; +/// height||Other|4 +$--pagination-button-width: 35.5px !default; +/// height||Other|4 +$--pagination-button-height: 28px !default; +/// color||Color|0 +$--pagination-button-disabled-color: $--color-text-placeholder !default; +/// color||Color|0 +$--pagination-button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-hover-color: $--color-primary !default; + +/* Popup +-------------------------- */ +/// color||Color|0 +$--popup-modal-background-color: $--color-black !default; +/// opacity||Other|1 +$--popup-modal-opacity: 0.5 !default; + +/* Popover +-------------------------- */ +/// color||Color|0 +$--popover-background-color: $--color-white !default; +/// fontSize||Font|1 +$--popover-font-size: $--font-size-base !default; +/// color||Color|0 +$--popover-border-color: $--border-color-lighter !default; +$--popover-arrow-size: 6px !default; +/// padding||Spacing|3 +$--popover-padding: 12px !default; +$--popover-padding-large: 18px 20px !default; +/// fontSize||Font|1 +$--popover-title-font-size: 16px !default; +/// color||Color|0 +$--popover-title-font-color: $--color-text-primary !default; + +/* Tooltip +-------------------------- */ +/// color|1|Color|0 +$--tooltip-fill: $--color-text-primary !default; +/// color|1|Color|0 +$--tooltip-color: $--color-white !default; +/// fontSize||Font|1 +$--tooltip-font-size: 12px !default; +/// color||Color|0 +$--tooltip-border-color: $--color-text-primary !default; +$--tooltip-arrow-size: 6px !default; +/// padding||Spacing|3 +$--tooltip-padding: 10px !default; + +/* Tag +-------------------------- */ +/// color||Color|0 +$--tag-info-color: $--color-info !default; +/// color||Color|0 +$--tag-primary-color: $--color-primary !default; +/// color||Color|0 +$--tag-success-color: $--color-success !default; +/// color||Color|0 +$--tag-warning-color: $--color-warning !default; +/// color||Color|0 +$--tag-danger-color: $--color-danger !default; +/// fontSize||Font|1 +$--tag-font-size: 12px !default; +$--tag-border-radius: 4px !default; +$--tag-padding: 0 10px !default; + +/* Tree +-------------------------- */ +/// color||Color|0 +$--tree-node-hover-background-color: $--background-color-base !default; +/// color||Color|0 +$--tree-font-color: $--color-text-regular !default; +/// color||Color|0 +$--tree-expand-icon-color: $--color-text-placeholder !default; + +/* Dropdown +-------------------------- */ +$--dropdown-menu-box-shadow: $--box-shadow-light !default; +$--dropdown-menuItem-hover-fill: $--color-menu-item-active-background !default; +$--dropdown-menuItem-hover-color: $--color-white !default; + +/* Badge +-------------------------- */ +/// color||Color|0 +$--badge-background-color: $--color-danger !default; +$--badge-radius: 10px !default; +/// fontSize||Font|1 +$--badge-font-size: 12px !default; +/// padding||Spacing|3 +$--badge-padding: 6px !default; +/// height||Other|4 +$--badge-size: 18px !default; + +/* Card +--------------------------*/ +/// color||Color|0 +$--card-border-color: $--border-color-lighter !default; +$--card-border-radius: 4px !default; +/// padding||Spacing|3 +$--card-padding: 20px !default; + +/* Slider +--------------------------*/ +/// color||Color|0 +$--slider-main-background-color: $--color-primary !default; +/// color||Color|0 +$--slider-runway-background-color: $--border-color-light !default; +$--slider-button-hover-color: mix($--color-primary, black, 97%) !default; +$--slider-stop-background-color: $--color-white !default; +$--slider-disable-color: $--color-text-placeholder !default; +$--slider-margin: 16px 0 !default; +$--slider-border-radius: 3px !default; +/// height|1|Other|4 +$--slider-height: 6px !default; +/// height||Other|4 +$--slider-button-size: 16px !default; +$--slider-button-wrapper-size: 36px !default; +$--slider-button-wrapper-offset: -15px !default; + +/* Steps +--------------------------*/ +$--steps-border-color: $--disabled-border-base !default; +$--steps-border-radius: 4px !default; +$--steps-padding: 20px !default; + +/* Menu +--------------------------*/ +/// fontSize||Font|1 +$--menu-item-font-size: $--font-size-base !default; +/// color||Color|0 +$--menu-item-font-color: $--color-white !default; +/// color||Color|0 +$--menu-background-color: $--color-menu-background !default; +$--menu-item-hover-fill: $--color-primary !default; + +/* Rate +--------------------------*/ +$--rate-height: 20px !default; +/// fontSize||Font|1 +$--rate-font-size: $--font-size-base !default; +/// height||Other|3 +$--rate-icon-size: 18px !default; +/// margin||Spacing|2 +$--rate-icon-margin: 6px !default; +$--rate-icon-color: $--color-text-placeholder !default; + +/* DatePicker +--------------------------*/ +$--datepicker-font-color: $--color-text-regular !default; +/// color|1|Color|0 +$--datepicker-off-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--datepicker-header-font-color: $--color-text-regular !default; +$--datepicker-icon-color: $--color-text-primary !default; +$--datepicker-border-color: $--disabled-border-base !default; +$--datepicker-inner-border-color: #e4e4e4 !default; +/// color||Color|0 +$--datepicker-inrange-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-inrange-hover-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-active-color: $--color-primary !default; +/// color||Color|0 +$--datepicker-hover-font-color: $--color-primary !default; +$--datepicker-cell-hover-color: #fff !default; + +/* Loading +--------------------------*/ +/// height||Other|4 +$--loading-spinner-size: 42px !default; +/// height||Other|4 +$--loading-fullscreen-spinner-size: 50px !default; + +/* Scrollbar +--------------------------*/ +$--scrollbar-background-color: rgba($--color-text-secondary, .3) !default; +$--scrollbar-hover-background-color: rgba($--color-text-secondary, .5) !default; + +/* Carousel +--------------------------*/ +/// fontSize||Font|1 +$--carousel-arrow-font-size: 12px !default; +$--carousel-arrow-size: 36px !default; +$--carousel-arrow-background: rgba(31, 45, 61, 0.11) !default; +$--carousel-arrow-hover-background: rgba(31, 45, 61, 0.23) !default; +/// width||Other|4 +$--carousel-indicator-width: 30px !default; +/// height||Other|4 +$--carousel-indicator-height: 2px !default; +$--carousel-indicator-padding-horizontal: 4px !default; +$--carousel-indicator-padding-vertical: 12px !default; +$--carousel-indicator-out-color: $--border-color-hover !default; + +/* Collapse +--------------------------*/ +/// color||Color|0 +$--collapse-border-color: $--border-color-lighter !default; +/// height||Other|4 +$--collapse-header-height: 48px !default; +/// color||Color|0 +$--collapse-header-background-color: $--color-white !default; +/// color||Color|0 +$--collapse-header-font-color: $--color-text-primary !default; +/// fontSize||Font|1 +$--collapse-header-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-background-color: $--color-white !default; +/// fontSize||Font|1 +$--collapse-content-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-font-color: $--color-text-primary !default; + +/* Transfer +--------------------------*/ +$--transfer-border-color: $--border-color-lighter !default; +$--transfer-border-radius: $--border-radius-base !default; +/// height||Other|4 +$--transfer-panel-width: 200px !default; +/// height||Other|4 +$--transfer-panel-header-height: 40px !default; +/// color||Color|0 +$--transfer-panel-header-background-color: $--background-color-base !default; +/// height||Other|4 +$--transfer-panel-footer-height: 40px !default; +/// height||Other|4 +$--transfer-panel-body-height: 246px !default; +/// height||Other|4 +$--transfer-item-height: 30px !default; +/// height||Other|4 +$--transfer-filter-height: 32px !default; + +/* Header + --------------------------*/ +$--header-padding: 0 20px !default; + +/* Footer +--------------------------*/ +$--footer-padding: 0 20px !default; + +/* Main +--------------------------*/ +$--main-padding: 20px !default; + +/* Timeline +--------------------------*/ +$--timeline-node-size-normal: 12px !default; +$--timeline-node-size-large: 14px !default; +$--timeline-node-color: $--border-color-light !default; + +/* Backtop +--------------------------*/ +/// color||Color|0 +$--backtop-background-color: $--color-white !default; +/// color||Color|0 +$--backtop-font-color: $--color-primary !default; +/// color||Color|0 +$--backtop-hover-background-color: $--border-color-extra-light !default; + +/* Link +--------------------------*/ +/// fontSize||Font|1 +$--link-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--link-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--link-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--link-default-active-color: $--color-primary !default; +/// color||Color|0 +$--link-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--link-primary-font-color: $--color-primary !default; +/// color||Color|0 +$--link-success-font-color: $--color-success !default; +/// color||Color|0 +$--link-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--link-danger-font-color: $--color-danger !default; +/// color||Color|0 +$--link-info-font-color: $--color-info !default; +/* Calendar +--------------------------*/ +/// border||Other|4 +$--calendar-border: $--table-border !default; +/// color||Other|4 +$--calendar-selected-background-color: #F2F8FE !default; +$--calendar-cell-width: 85px !default; + +/* Form +-------------------------- */ +/// fontSize||Font|1 +$--form-label-font-size: $--font-size-base !default; + +/* Avatar +--------------------------*/ +/// color||Color|0 +$--avatar-font-color: #fff !default; +/// color||Color|0 +$--avatar-background-color: #C0C4CC !default; +/// fontSize||Font Size|1 +$--avatar-text-font-size: 14px !default; +/// fontSize||Font Size|1 +$--avatar-icon-font-size: 18px !default; +/// borderRadius||Border|2 +$--avatar-border-radius: $--border-radius-base !default; +/// size|1|Avatar Size|3 +$--avatar-large-size: 40px !default; +/// size|1|Avatar Size|3 +$--avatar-medium-size: 36px !default; +/// size|1|Avatar Size|3 +$--avatar-small-size: 28px !default; + +/* Break-point +--------------------------*/ +$--sm: 768px !default; +$--md: 992px !default; +$--lg: 1200px !default; +$--xl: 1920px !default; + +$--breakpoints: ( + 'xs' : (max-width: $--sm - 1), + 'sm' : (min-width: $--sm), + 'md' : (min-width: $--md), + 'lg' : (min-width: $--lg), + 'xl' : (min-width: $--xl) +); + +$--breakpoints-spec: ( + 'xs-only' : (max-width: $--sm - 1), + 'sm-and-up' : (min-width: $--sm), + 'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md - 1})", + 'sm-and-down': (max-width: $--md - 1), + 'md-and-up' : (min-width: $--md), + 'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg - 1})", + 'md-and-down': (max-width: $--lg - 1), + 'lg-and-up' : (min-width: $--lg), + 'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})", + 'lg-and-down': (max-width: $--xl - 1), + 'xl-only' : (min-width: $--xl), +); diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-green.scss b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-green.scss new file mode 100644 index 00000000..e51e10f9 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-green.scss @@ -0,0 +1,1000 @@ +/* Element Chalk Variables */ + +// Special comment for theme configurator +// type|skipAutoTranslation|Category|Order +// skipAutoTranslation 1 + +/* Transition +-------------------------- */ +$--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default; +$--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--fade-linear-transition: opacity 200ms linear !default; +$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default; +$--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default; + +/* Color +-------------------------- */ +/// color|1|Brand Color|0 +$--color-primary: #00988B !default; +/// color|1|Background Color|4 +$--color-white: #FFFFFF !default; +/// color|1|Background Color|4 +$--color-black: #000000 !default; +$--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */ +$--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */ +$--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */ +$--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* 8cc5ff */ +$--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* a0cfff */ +$--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* b3d8ff */ +$--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */ +$--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */ +$--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */ +/// color|1|Functional Color|1 +$--color-success: #67C23A !default; +/// color|1|Functional Color|1 +$--color-warning: #E6A23C !default; +/// color|1|Functional Color|1 +$--color-danger: #F56C6C !default; +/// color|1|Functional Color|1 +$--color-info: #909399 !default; + +$--color-success-light: mix($--color-white, $--color-success, 80%) !default; +$--color-warning-light: mix($--color-white, $--color-warning, 80%) !default; +$--color-danger-light: mix($--color-white, $--color-danger, 80%) !default; +$--color-info-light: mix($--color-white, $--color-info, 80%) !default; + +$--color-success-lighter: mix($--color-white, $--color-success, 90%) !default; +$--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default; +$--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default; +$--color-info-lighter: mix($--color-white, $--color-info, 90%) !default; +/// color|1|Font Color|2 +$--color-text-primary: #303133 !default; +/// color|1|Font Color|2 +$--color-text-regular: #606266 !default; +/// color|1|Font Color|2 +$--color-text-secondary: #909399 !default; +/// color|1|Font Color|2 +$--color-text-placeholder: #C0C4CC !default; +/// color|1|Border Color|3 +$--border-color-base: #DCDFE6 !default; +/// color|1|Border Color|3 +$--border-color-light: #E4E7ED !default; +/// color|1|Border Color|3 +$--border-color-lighter: #EBEEF5 !default; +/// color|1|Border Color|3 +$--border-color-extra-light: #F2F6FC !default; + +// Background +/// color|1|Background Color|4 +$--background-color-base: #F5F7FA !default; + +// color for left sidebar title +$--color-sidebar-title-text: #FFFFFF; +// color for left sidebar background +$--color-menu-background: #272C34; +$--color-menu-item-active-text-color: #FFFFFF; +$--color-menu-item-active-background: $--color-primary; +/* Link +-------------------------- */ +$--link-color: $--color-primary-light-2 !default; +$--link-hover-color: $--color-primary !default; + +/* Border +-------------------------- */ +$--border-width-base: 1px !default; +$--border-style-base: solid !default; +$--border-color-hover: $--color-text-placeholder !default; +$--border-base: $--border-width-base $--border-style-base $--border-color-base !default; +/// borderRadius|1|Radius|0 +$--border-radius-base: 4px !default; +/// borderRadius|1|Radius|0 +$--border-radius-small: 2px !default; +/// borderRadius|1|Radius|0 +$--border-radius-circle: 100% !default; +/// borderRadius|1|Radius|0 +$--border-radius-zero: 0 !default; + +// Box-shadow +/// boxShadow|1|Shadow|1 +$--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default; +// boxShadow|1|Shadow|1 +$--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default; +/// boxShadow|1|Shadow|1 +$--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default; + +/* Fill +-------------------------- */ +$--fill-base: $--color-white !default; + +/* Typography +-------------------------- */ +$--font-path: 'fonts' !default; +$--font-display: 'auto' !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-large: 20px !default; +/// fontSize|1|Font Size|0 +$--font-size-large: 18px !default; +/// fontSize|1|Font Size|0 +$--font-size-medium: 16px !default; +/// fontSize|1|Font Size|0 +$--font-size-base: 14px !default; +/// fontSize|1|Font Size|0 +$--font-size-small: 13px !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-small: 12px !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-primary: 500 !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-secondary: 100 !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-primary: 24px !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-secondary: 16px !default; +$--font-color-disabled-base: #bbb !default; +/* Size +-------------------------- */ +$--size-base: 14px !default; + +/* z-index +-------------------------- */ +$--index-normal: 1 !default; +$--index-top: 1000 !default; +$--index-popper: 2000 !default; + +/* Disable base +-------------------------- */ +$--disabled-fill-base: $--background-color-base !default; +$--disabled-color-base: $--color-text-placeholder !default; +$--disabled-border-base: $--border-color-light !default; + +/* Icon +-------------------------- */ +$--icon-color: #666 !default; +$--icon-color-base: $--color-info !default; + +/* Checkbox +-------------------------- */ +/// fontSize||Font|1 +$--checkbox-font-size: 14px !default; +/// fontWeight||Font|1 +$--checkbox-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--checkbox-font-color: $--color-text-regular !default; +$--checkbox-input-height: 14px !default; +$--checkbox-input-width: 14px !default; +/// borderRadius||Border|2 +$--checkbox-border-radius: $--border-radius-small !default; +/// color||Color|0 +$--checkbox-background-color: $--color-white !default; +$--checkbox-input-border: $--border-base !default; + +/// color||Color|0 +$--checkbox-disabled-border-color: $--border-color-base !default; +$--checkbox-disabled-input-fill: #edf2fc !default; +$--checkbox-disabled-icon-color: $--color-text-placeholder !default; + +$--checkbox-disabled-checked-input-fill: $--border-color-extra-light !default; +$--checkbox-disabled-checked-input-border-color: $--border-color-base !default; +$--checkbox-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--checkbox-checked-font-color: $--color-primary !default; +$--checkbox-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-checked-background-color: $--color-primary !default; +$--checkbox-checked-icon-color: $--fill-base !default; + +$--checkbox-input-border-color-hover: $--color-primary !default; +/// height||Other|4 +$--checkbox-bordered-height: 40px !default; +/// padding||Spacing|3 +$--checkbox-bordered-padding: 9px 20px 9px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-small-padding: 5px 15px 5px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default; +$--checkbox-bordered-medium-input-height: 14px !default; +$--checkbox-bordered-medium-input-width: 14px !default; +/// height||Other|4 +$--checkbox-bordered-medium-height: 36px !default; +$--checkbox-bordered-small-input-height: 12px !default; +$--checkbox-bordered-small-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-small-height: 32px !default; +$--checkbox-bordered-mini-input-height: 12px !default; +$--checkbox-bordered-mini-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-mini-height: 28px !default; + +/// color||Color|0 +$--checkbox-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--checkbox-button-checked-border-color: $--color-primary !default; + + + +/* Radio +-------------------------- */ +/// fontSize||Font|1 +$--radio-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--radio-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--radio-font-color: $--color-text-regular !default; +$--radio-input-height: 14px !default; +$--radio-input-width: 14px !default; +/// borderRadius||Border|2 +$--radio-input-border-radius: $--border-radius-circle !default; +/// color||Color|0 +$--radio-input-background-color: $--color-white !default; +$--radio-input-border: $--border-base !default; +/// color||Color|0 +$--radio-input-border-color: $--border-color-base !default; +/// color||Color|0 +$--radio-icon-color: $--color-white !default; + +$--radio-disabled-input-border-color: $--disabled-border-base !default; +$--radio-disabled-input-fill: $--disabled-fill-base !default; +$--radio-disabled-icon-color: $--disabled-fill-base !default; + +$--radio-disabled-checked-input-border-color: $--disabled-border-base !default; +$--radio-disabled-checked-input-fill: $--disabled-fill-base !default; +$--radio-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--radio-checked-font-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-background-color: $--color-white !default; +/// color||Color|0 +$--radio-checked-icon-color: $--color-primary !default; + +$--radio-input-border-color-hover: $--color-primary !default; + +$--radio-bordered-height: 40px !default; +$--radio-bordered-padding: 12px 20px 0 10px !default; +$--radio-bordered-medium-padding: 10px 20px 0 10px !default; +$--radio-bordered-small-padding: 8px 15px 0 10px !default; +$--radio-bordered-mini-padding: 6px 15px 0 10px !default; +$--radio-bordered-medium-input-height: 14px !default; +$--radio-bordered-medium-input-width: 14px !default; +$--radio-bordered-medium-height: 36px !default; +$--radio-bordered-small-input-height: 12px !default; +$--radio-bordered-small-input-width: 12px !default; +$--radio-bordered-small-height: 32px !default; +$--radio-bordered-mini-input-height: 12px !default; +$--radio-bordered-mini-input-width: 12px !default; +$--radio-bordered-mini-height: 28px !default; + +/// fontSize||Font|1 +$--radio-button-font-size: $--font-size-base !default; +/// color||Color|0 +$--radio-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--radio-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--radio-button-checked-border-color: $--color-primary !default; +$--radio-button-disabled-checked-fill: $--border-color-extra-light !default; + +/* Select +-------------------------- */ +$--select-border-color-hover: $--border-color-hover !default; +$--select-disabled-border: $--disabled-border-base !default; +/// fontSize||Font|1 +$--select-font-size: $--font-size-base !default; +$--select-close-hover-color: $--color-text-secondary !default; + +$--select-input-color: $--color-text-placeholder !default; +$--select-multiple-input-color: #666 !default; +/// color||Color|0 +$--select-input-focus-border-color: $--color-primary !default; +/// fontSize||Font|1 +$--select-input-font-size: 14px !default; + +$--select-option-color: $--color-text-regular !default; +$--select-option-disabled-color: $--color-text-placeholder !default; +$--select-option-disabled-background: $--color-white !default; +/// height||Other|4 +$--select-option-height: 34px !default; +$--select-option-hover-background: $--background-color-base !default; +/// color||Color|0 +$--select-option-selected-font-color: $--color-primary !default; +$--select-option-selected-hover: $--background-color-base !default; + +$--select-group-color: $--color-info !default; +$--select-group-height: 30px !default; +$--select-group-font-size: 12px !default; + +$--select-dropdown-background: $--color-white !default; +$--select-dropdown-shadow: $--box-shadow-light !default; +$--select-dropdown-empty-color: #999 !default; +/// height||Other|4 +$--select-dropdown-max-height: 274px !default; +$--select-dropdown-padding: 6px 0 !default; +$--select-dropdown-empty-padding: 10px 0 !default; +$--select-dropdown-border: solid 1px $--border-color-light !default; + +/* Alert +-------------------------- */ +$--alert-padding: 8px 16px !default; +/// borderRadius||Border|2 +$--alert-border-radius: $--border-radius-base !default; +/// fontSize||Font|1 +$--alert-title-font-size: 13px !default; +/// fontSize||Font|1 +$--alert-description-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-customed-font-size: 13px !default; + +$--alert-success-color: $--color-success-lighter !default; +$--alert-info-color: $--color-info-lighter !default; +$--alert-warning-color: $--color-warning-lighter !default; +$--alert-danger-color: $--color-danger-lighter !default; + +/// height||Other|4 +$--alert-icon-size: 16px !default; +/// height||Other|4 +$--alert-icon-large-size: 28px !default; + +/* MessageBox +-------------------------- */ +/// color||Color|0 +$--messagebox-title-color: $--color-text-primary !default; +$--msgbox-width: 420px !default; +$--msgbox-border-radius: 4px !default; +/// fontSize||Font|1 +$--messagebox-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--messagebox-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--messagebox-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--messagebox-error-font-size: 12px !default; +$--msgbox-padding-primary: 15px !default; +/// color||Color|0 +$--messagebox-success-color: $--color-success !default; +/// color||Color|0 +$--messagebox-info-color: $--color-info !default; +/// color||Color|0 +$--messagebox-warning-color: $--color-warning !default; +/// color||Color|0 +$--messagebox-danger-color: $--color-danger !default; + +/* Message +-------------------------- */ +$--message-shadow: $--box-shadow-base !default; +$--message-min-width: 380px !default; +$--message-background-color: #edf2fc !default; +$--message-padding: 15px 15px 15px 20px !default; +/// color||Color|0 +$--message-close-icon-color: $--color-text-placeholder !default; +/// height||Other|4 +$--message-close-size: 16px !default; +/// color||Color|0 +$--message-close-hover-color: $--color-text-secondary !default; + +/// color||Color|0 +$--message-success-font-color: $--color-success !default; +/// color||Color|0 +$--message-info-font-color: $--color-info !default; +/// color||Color|0 +$--message-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--message-danger-font-color: $--color-danger !default; + +/* Notification +-------------------------- */ +$--notification-width: 330px !default; +/// padding||Spacing|3 +$--notification-padding: 14px 26px 14px 13px !default; +$--notification-radius: 8px !default; +$--notification-shadow: $--box-shadow-light !default; +/// color||Color|0 +$--notification-border-color: $--border-color-lighter !default; +$--notification-icon-size: 24px !default; +$--notification-close-font-size: $--message-close-size !default; +$--notification-group-margin-left: 13px !default; +$--notification-group-margin-right: 8px !default; +/// fontSize||Font|1 +$--notification-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--notification-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--notification-title-font-size: 16px !default; +/// color||Color|0 +$--notification-title-color: $--color-text-primary !default; + +/// color||Color|0 +$--notification-close-color: $--color-text-secondary !default; +/// color||Color|0 +$--notification-close-hover-color: $--color-text-regular !default; + +/// color||Color|0 +$--notification-success-icon-color: $--color-success !default; +/// color||Color|0 +$--notification-info-icon-color: $--color-info !default; +/// color||Color|0 +$--notification-warning-icon-color: $--color-warning !default; +/// color||Color|0 +$--notification-danger-icon-color: $--color-danger !default; + +/* Input +-------------------------- */ +$--input-font-size: $--font-size-base !default; +/// color||Color|0 +$--input-font-color: $--color-text-regular !default; +/// height||Other|4 +$--input-width: 140px !default; +/// height||Other|4 +$--input-height: 40px !default; +$--input-border: $--border-base !default; +$--input-border-color: $--border-color-base !default; +/// borderRadius||Border|2 +$--input-border-radius: $--border-radius-base !default; +$--input-border-color-hover: $--border-color-hover !default; +/// color||Color|0 +$--input-background-color: $--color-white !default; +$--input-fill-disabled: $--disabled-fill-base !default; +$--input-color-disabled: $--font-color-disabled-base !default; +/// color||Color|0 +$--input-icon-color: $--color-text-placeholder !default; +/// color||Color|0 +$--input-placeholder-color: $--color-text-placeholder !default; +$--input-max-width: 314px !default; + +$--input-hover-border: $--border-color-hover !default; +$--input-clear-hover-color: $--color-text-secondary !default; + +$--input-focus-border: $--color-primary !default; +$--input-focus-fill: $--color-white !default; + +$--input-disabled-fill: $--disabled-fill-base !default; +$--input-disabled-border: $--disabled-border-base !default; +$--input-disabled-color: $--disabled-color-base !default; +$--input-disabled-placeholder-color: $--color-text-placeholder !default; + +/// fontSize||Font|1 +$--input-medium-font-size: 14px !default; +/// height||Other|4 +$--input-medium-height: 36px !default; +/// fontSize||Font|1 +$--input-small-font-size: 13px !default; +/// height||Other|4 +$--input-small-height: 32px !default; +/// fontSize||Font|1 +$--input-mini-font-size: 12px !default; +/// height||Other|4 +$--input-mini-height: 28px !default; + +/* Cascader +-------------------------- */ +/// color||Color|0 +$--cascader-menu-font-color: $--color-text-regular !default; +/// color||Color|0 +$--cascader-menu-selected-font-color: $--color-primary !default; +$--cascader-menu-fill: $--fill-base !default; +$--cascader-menu-font-size: $--font-size-base !default; +$--cascader-menu-radius: $--border-radius-base !default; +$--cascader-menu-border: solid 1px $--border-color-light !default; +$--cascader-menu-shadow: $--box-shadow-light !default; +$--cascader-node-background-hover: $--background-color-base !default; +$--cascader-node-color-disabled:$--color-text-placeholder !default; +$--cascader-color-empty:$--color-text-placeholder !default; +$--cascader-tag-background: #f0f2f5; + +/* Group +-------------------------- */ +$--group-option-flex: 0 0 (1/5) * 100% !default; +$--group-option-offset-bottom: 12px !default; +$--group-option-fill-hover: rgba($--color-black, 0.06) !default; +$--group-title-color: $--color-black !default; +$--group-title-font-size: $--font-size-base !default; +$--group-title-width: 66px !default; + +/* Tab +-------------------------- */ +$--tab-font-size: $--font-size-base !default; +$--tab-border-line: 1px solid #e4e4e4 !default; +$--tab-header-color-active: $--color-text-secondary !default; +$--tab-header-color-hover: $--color-text-regular !default; +$--tab-header-color: $--color-text-regular !default; +$--tab-header-fill-active: rgba($--color-black, 0.06) !default; +$--tab-header-fill-hover: rgba($--color-black, 0.06) !default; +$--tab-vertical-header-width: 90px !default; +$--tab-vertical-header-count-color: $--color-white !default; +$--tab-vertical-header-count-fill: $--color-text-secondary !default; + +/* Button +-------------------------- */ +/// fontSize||Font|1 +$--button-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--button-font-weight: $--font-weight-primary !default; +/// borderRadius||Border|2 +$--button-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-padding-vertical: 12px !default; +/// padding||Spacing|3 +$--button-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-medium-font-size: $--font-size-base !default; +/// borderRadius||Border|2 +$--button-medium-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-medium-padding-vertical: 10px !default; +/// padding||Spacing|3 +$--button-medium-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-small-font-size: 12px !default; +$--button-small-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-small-padding-vertical: 9px !default; +/// padding||Spacing|3 +$--button-small-padding-horizontal: 15px !default; +/// fontSize||Font|1 +$--button-mini-font-size: 12px !default; +$--button-mini-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-mini-padding-vertical: 7px !default; +/// padding||Spacing|3 +$--button-mini-padding-horizontal: 15px !default; + +/// color||Color|0 +$--button-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--button-default-background-color: $--color-white !default; +/// color||Color|0 +$--button-default-border-color: $--border-color-base !default; + +/// color||Color|0 +$--button-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--button-disabled-border-color: $--border-color-lighter !default; + +/// color||Color|0 +$--button-primary-border-color: $--color-primary !default; +/// color||Color|0 +$--button-primary-font-color: $--color-white !default; +/// color||Color|0 +$--button-primary-background-color: $--color-primary !default; +/// color||Color|0 +$--button-success-border-color: $--color-success !default; +/// color||Color|0 +$--button-success-font-color: $--color-white !default; +/// color||Color|0 +$--button-success-background-color: $--color-success !default; +/// color||Color|0 +$--button-warning-border-color: $--color-warning !default; +/// color||Color|0 +$--button-warning-font-color: $--color-white !default; +/// color||Color|0 +$--button-warning-background-color: $--color-warning !default; +/// color||Color|0 +$--button-danger-border-color: $--color-danger !default; +/// color||Color|0 +$--button-danger-font-color: $--color-white !default; +/// color||Color|0 +$--button-danger-background-color: $--color-danger !default; +/// color||Color|0 +$--button-info-border-color: $--color-info !default; +/// color||Color|0 +$--button-info-font-color: $--color-white !default; +/// color||Color|0 +$--button-info-background-color: $--color-info !default; + +$--button-hover-tint-percent: 20% !default; +$--button-active-shade-percent: 10% !default; + + +/* cascader +-------------------------- */ +$--cascader-height: 200px !default; + +/* Switch +-------------------------- */ +/// color||Color|0 +$--switch-on-color: $--color-primary !default; +/// color||Color|0 +$--switch-off-color: $--border-color-base !default; +/// fontSize||Font|1 +$--switch-font-size: $--font-size-base !default; +$--switch-core-border-radius: 10px !default; +// height||Other|4 TODO: width 代码写死的40px 所以下面这三个属性都没意义 +$--switch-width: 40px !default; +// height||Other|4 +$--switch-height: 20px !default; +// height||Other|4 +$--switch-button-size: 16px !default; + +/* Dialog +-------------------------- */ +$--dialog-background-color: $--color-white !default; +$--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !default; +/// fontSize||Font|1 +$--dialog-title-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--dialog-content-font-size: 14px !default; +/// fontLineHeight||LineHeight|2 +$--dialog-font-line-height: $--font-line-height-primary !default; +/// padding||Spacing|3 +$--dialog-padding-primary: 20px !default; + +/* Table +-------------------------- */ +/// color||Color|0 +$--table-border-color: $--border-color-lighter !default; +$--table-border: 1px solid $--table-border-color !default; +/// color||Color|0 +$--table-font-color: $--color-text-regular !default; +/// color||Color|0 +$--table-header-font-color: $--color-text-secondary !default; +/// color||Color|0 +$--table-row-hover-background-color: $--background-color-base !default; +$--table-current-row-background-color: $--color-primary-light-9 !default; +/// color||Color|0 +$--table-header-background-color: $--color-white !default; +$--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, .12) !default; + +/* Pagination +-------------------------- */ +/// fontSize||Font|1 +$--pagination-font-size: 13px !default; +/// color||Color|0 +$--pagination-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-font-color: $--color-text-primary !default; +$--pagination-border-radius: 3px !default; +/// color||Color|0 +$--pagination-button-color: $--color-text-primary !default; +/// height||Other|4 +$--pagination-button-width: 35.5px !default; +/// height||Other|4 +$--pagination-button-height: 28px !default; +/// color||Color|0 +$--pagination-button-disabled-color: $--color-text-placeholder !default; +/// color||Color|0 +$--pagination-button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-hover-color: $--color-primary !default; + +/* Popup +-------------------------- */ +/// color||Color|0 +$--popup-modal-background-color: $--color-black !default; +/// opacity||Other|1 +$--popup-modal-opacity: 0.5 !default; + +/* Popover +-------------------------- */ +/// color||Color|0 +$--popover-background-color: $--color-white !default; +/// fontSize||Font|1 +$--popover-font-size: $--font-size-base !default; +/// color||Color|0 +$--popover-border-color: $--border-color-lighter !default; +$--popover-arrow-size: 6px !default; +/// padding||Spacing|3 +$--popover-padding: 12px !default; +$--popover-padding-large: 18px 20px !default; +/// fontSize||Font|1 +$--popover-title-font-size: 16px !default; +/// color||Color|0 +$--popover-title-font-color: $--color-text-primary !default; + +/* Tooltip +-------------------------- */ +/// color|1|Color|0 +$--tooltip-fill: $--color-text-primary !default; +/// color|1|Color|0 +$--tooltip-color: $--color-white !default; +/// fontSize||Font|1 +$--tooltip-font-size: 12px !default; +/// color||Color|0 +$--tooltip-border-color: $--color-text-primary !default; +$--tooltip-arrow-size: 6px !default; +/// padding||Spacing|3 +$--tooltip-padding: 10px !default; + +/* Tag +-------------------------- */ +/// color||Color|0 +$--tag-info-color: $--color-info !default; +/// color||Color|0 +$--tag-primary-color: $--color-primary !default; +/// color||Color|0 +$--tag-success-color: $--color-success !default; +/// color||Color|0 +$--tag-warning-color: $--color-warning !default; +/// color||Color|0 +$--tag-danger-color: $--color-danger !default; +/// fontSize||Font|1 +$--tag-font-size: 12px !default; +$--tag-border-radius: 4px !default; +$--tag-padding: 0 10px !default; + +/* Tree +-------------------------- */ +/// color||Color|0 +$--tree-node-hover-background-color: $--background-color-base !default; +/// color||Color|0 +$--tree-font-color: $--color-text-regular !default; +/// color||Color|0 +$--tree-expand-icon-color: $--color-text-placeholder !default; + +/* Dropdown +-------------------------- */ +$--dropdown-menu-box-shadow: $--box-shadow-light !default; +$--dropdown-menuItem-hover-fill: $--color-menu-item-active-background !default; +$--dropdown-menuItem-hover-color: $--color-white !default; + +/* Badge +-------------------------- */ +/// color||Color|0 +$--badge-background-color: $--color-danger !default; +$--badge-radius: 10px !default; +/// fontSize||Font|1 +$--badge-font-size: 12px !default; +/// padding||Spacing|3 +$--badge-padding: 6px !default; +/// height||Other|4 +$--badge-size: 18px !default; + +/* Card +--------------------------*/ +/// color||Color|0 +$--card-border-color: $--border-color-lighter !default; +$--card-border-radius: 4px !default; +/// padding||Spacing|3 +$--card-padding: 20px !default; + +/* Slider +--------------------------*/ +/// color||Color|0 +$--slider-main-background-color: $--color-primary !default; +/// color||Color|0 +$--slider-runway-background-color: $--border-color-light !default; +$--slider-button-hover-color: mix($--color-primary, black, 97%) !default; +$--slider-stop-background-color: $--color-white !default; +$--slider-disable-color: $--color-text-placeholder !default; +$--slider-margin: 16px 0 !default; +$--slider-border-radius: 3px !default; +/// height|1|Other|4 +$--slider-height: 6px !default; +/// height||Other|4 +$--slider-button-size: 16px !default; +$--slider-button-wrapper-size: 36px !default; +$--slider-button-wrapper-offset: -15px !default; + +/* Steps +--------------------------*/ +$--steps-border-color: $--disabled-border-base !default; +$--steps-border-radius: 4px !default; +$--steps-padding: 20px !default; + +/* Menu +--------------------------*/ +/// fontSize||Font|1 +$--menu-item-font-size: $--font-size-base !default; +/// color||Color|0 +$--menu-item-font-color: $--color-white !default; +/// color||Color|0 +$--menu-background-color: $--color-menu-background !default; +$--menu-item-hover-fill: $--color-primary !default; + +/* Rate +--------------------------*/ +$--rate-height: 20px !default; +/// fontSize||Font|1 +$--rate-font-size: $--font-size-base !default; +/// height||Other|3 +$--rate-icon-size: 18px !default; +/// margin||Spacing|2 +$--rate-icon-margin: 6px !default; +$--rate-icon-color: $--color-text-placeholder !default; + +/* DatePicker +--------------------------*/ +$--datepicker-font-color: $--color-text-regular !default; +/// color|1|Color|0 +$--datepicker-off-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--datepicker-header-font-color: $--color-text-regular !default; +$--datepicker-icon-color: $--color-text-primary !default; +$--datepicker-border-color: $--disabled-border-base !default; +$--datepicker-inner-border-color: #e4e4e4 !default; +/// color||Color|0 +$--datepicker-inrange-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-inrange-hover-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-active-color: $--color-primary !default; +/// color||Color|0 +$--datepicker-hover-font-color: $--color-primary !default; +$--datepicker-cell-hover-color: #fff !default; + +/* Loading +--------------------------*/ +/// height||Other|4 +$--loading-spinner-size: 42px !default; +/// height||Other|4 +$--loading-fullscreen-spinner-size: 50px !default; + +/* Scrollbar +--------------------------*/ +$--scrollbar-background-color: rgba($--color-text-secondary, .3) !default; +$--scrollbar-hover-background-color: rgba($--color-text-secondary, .5) !default; + +/* Carousel +--------------------------*/ +/// fontSize||Font|1 +$--carousel-arrow-font-size: 12px !default; +$--carousel-arrow-size: 36px !default; +$--carousel-arrow-background: rgba(31, 45, 61, 0.11) !default; +$--carousel-arrow-hover-background: rgba(31, 45, 61, 0.23) !default; +/// width||Other|4 +$--carousel-indicator-width: 30px !default; +/// height||Other|4 +$--carousel-indicator-height: 2px !default; +$--carousel-indicator-padding-horizontal: 4px !default; +$--carousel-indicator-padding-vertical: 12px !default; +$--carousel-indicator-out-color: $--border-color-hover !default; + +/* Collapse +--------------------------*/ +/// color||Color|0 +$--collapse-border-color: $--border-color-lighter !default; +/// height||Other|4 +$--collapse-header-height: 48px !default; +/// color||Color|0 +$--collapse-header-background-color: $--color-white !default; +/// color||Color|0 +$--collapse-header-font-color: $--color-text-primary !default; +/// fontSize||Font|1 +$--collapse-header-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-background-color: $--color-white !default; +/// fontSize||Font|1 +$--collapse-content-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-font-color: $--color-text-primary !default; + +/* Transfer +--------------------------*/ +$--transfer-border-color: $--border-color-lighter !default; +$--transfer-border-radius: $--border-radius-base !default; +/// height||Other|4 +$--transfer-panel-width: 200px !default; +/// height||Other|4 +$--transfer-panel-header-height: 40px !default; +/// color||Color|0 +$--transfer-panel-header-background-color: $--background-color-base !default; +/// height||Other|4 +$--transfer-panel-footer-height: 40px !default; +/// height||Other|4 +$--transfer-panel-body-height: 246px !default; +/// height||Other|4 +$--transfer-item-height: 30px !default; +/// height||Other|4 +$--transfer-filter-height: 32px !default; + +/* Header + --------------------------*/ +$--header-padding: 0 20px !default; + +/* Footer +--------------------------*/ +$--footer-padding: 0 20px !default; + +/* Main +--------------------------*/ +$--main-padding: 20px !default; + +/* Timeline +--------------------------*/ +$--timeline-node-size-normal: 12px !default; +$--timeline-node-size-large: 14px !default; +$--timeline-node-color: $--border-color-light !default; + +/* Backtop +--------------------------*/ +/// color||Color|0 +$--backtop-background-color: $--color-white !default; +/// color||Color|0 +$--backtop-font-color: $--color-primary !default; +/// color||Color|0 +$--backtop-hover-background-color: $--border-color-extra-light !default; + +/* Link +--------------------------*/ +/// fontSize||Font|1 +$--link-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--link-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--link-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--link-default-active-color: $--color-primary !default; +/// color||Color|0 +$--link-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--link-primary-font-color: $--color-primary !default; +/// color||Color|0 +$--link-success-font-color: $--color-success !default; +/// color||Color|0 +$--link-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--link-danger-font-color: $--color-danger !default; +/// color||Color|0 +$--link-info-font-color: $--color-info !default; +/* Calendar +--------------------------*/ +/// border||Other|4 +$--calendar-border: $--table-border !default; +/// color||Other|4 +$--calendar-selected-background-color: #F2F8FE !default; +$--calendar-cell-width: 85px !default; + +/* Form +-------------------------- */ +/// fontSize||Font|1 +$--form-label-font-size: $--font-size-base !default; + +/* Avatar +--------------------------*/ +/// color||Color|0 +$--avatar-font-color: #fff !default; +/// color||Color|0 +$--avatar-background-color: #C0C4CC !default; +/// fontSize||Font Size|1 +$--avatar-text-font-size: 14px !default; +/// fontSize||Font Size|1 +$--avatar-icon-font-size: 18px !default; +/// borderRadius||Border|2 +$--avatar-border-radius: $--border-radius-base !default; +/// size|1|Avatar Size|3 +$--avatar-large-size: 40px !default; +/// size|1|Avatar Size|3 +$--avatar-medium-size: 36px !default; +/// size|1|Avatar Size|3 +$--avatar-small-size: 28px !default; + +/* Break-point +--------------------------*/ +$--sm: 768px !default; +$--md: 992px !default; +$--lg: 1200px !default; +$--xl: 1920px !default; + +$--breakpoints: ( + 'xs' : (max-width: $--sm - 1), + 'sm' : (min-width: $--sm), + 'md' : (min-width: $--md), + 'lg' : (min-width: $--lg), + 'xl' : (min-width: $--xl) +); + +$--breakpoints-spec: ( + 'xs-only' : (max-width: $--sm - 1), + 'sm-and-up' : (min-width: $--sm), + 'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md - 1})", + 'sm-and-down': (max-width: $--md - 1), + 'md-and-up' : (min-width: $--md), + 'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg - 1})", + 'md-and-down': (max-width: $--lg - 1), + 'lg-and-up' : (min-width: $--lg), + 'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})", + 'lg-and-down': (max-width: $--xl - 1), + 'xl-only' : (min-width: $--xl), +); diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-light.scss b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-light.scss new file mode 100644 index 00000000..2c6cdad8 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-light.scss @@ -0,0 +1,998 @@ +/* Element Chalk Variables */ + +// Special comment for theme configurator +// type|skipAutoTranslation|Category|Order +// skipAutoTranslation 1 + +/* Transition +-------------------------- */ +$--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default; +$--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--fade-linear-transition: opacity 200ms linear !default; +$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default; +$--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default; + +/* Color +-------------------------- */ +// color for left sidebar title +$--color-sidebar-title-text: #381524; +// color for left sidebar background +$--color-menu-background: #FFFFFF; +/// color|1|Brand Color|0 +$--color-primary: #409EFF !default; +/// color|1|Background Color|4 +$--color-white: #FFFFFF !default; +/// color|1|Background Color|4 +$--color-black: #000000 !default; +$--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */ +$--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */ +$--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */ +$--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* 8cc5ff */ +$--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* a0cfff */ +$--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* b3d8ff */ +$--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */ +$--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */ +$--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */ +/// color|1|Functional Color|1 +$--color-success: #67C23A !default; +/// color|1|Functional Color|1 +$--color-warning: #E6A23C !default; +/// color|1|Functional Color|1 +$--color-danger: #F56C6C !default; +/// color|1|Functional Color|1 +$--color-info: #909399 !default; + +$--color-success-light: mix($--color-white, $--color-success, 80%) !default; +$--color-warning-light: mix($--color-white, $--color-warning, 80%) !default; +$--color-danger-light: mix($--color-white, $--color-danger, 80%) !default; +$--color-info-light: mix($--color-white, $--color-info, 80%) !default; + +$--color-success-lighter: mix($--color-white, $--color-success, 90%) !default; +$--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default; +$--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default; +$--color-info-lighter: mix($--color-white, $--color-info, 90%) !default; +/// color|1|Font Color|2 +$--color-text-primary: #303133 !default; +/// color|1|Font Color|2 +$--color-text-regular: #606266 !default; +/// color|1|Font Color|2 +$--color-text-secondary: #909399 !default; +/// color|1|Font Color|2 +$--color-text-placeholder: #C0C4CC !default; +/// color|1|Border Color|3 +$--border-color-base: #DCDFE6 !default; +/// color|1|Border Color|3 +$--border-color-light: #E4E7ED !default; +/// color|1|Border Color|3 +$--border-color-lighter: #EBEEF5 !default; +/// color|1|Border Color|3 +$--border-color-extra-light: #F2F6FC !default; + +// Background +/// color|1|Background Color|4 +$--background-color-base: #F5F7FA !default; + +/* Link +-------------------------- */ +$--link-color: $--color-primary-light-2 !default; +$--link-hover-color: $--color-primary !default; + +/* Border +-------------------------- */ +$--border-width-base: 1px !default; +$--border-style-base: solid !default; +$--border-color-hover: $--color-text-placeholder !default; +$--border-base: $--border-width-base $--border-style-base $--border-color-base !default; +/// borderRadius|1|Radius|0 +$--border-radius-base: 4px !default; +/// borderRadius|1|Radius|0 +$--border-radius-small: 2px !default; +/// borderRadius|1|Radius|0 +$--border-radius-circle: 100% !default; +/// borderRadius|1|Radius|0 +$--border-radius-zero: 0 !default; + +// Box-shadow +/// boxShadow|1|Shadow|1 +$--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default; +// boxShadow|1|Shadow|1 +$--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default; +/// boxShadow|1|Shadow|1 +$--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default; + +/* Fill +-------------------------- */ +$--fill-base: $--color-white !default; + +/* Typography +-------------------------- */ +$--font-path: 'fonts' !default; +$--font-display: 'auto' !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-large: 20px !default; +/// fontSize|1|Font Size|0 +$--font-size-large: 18px !default; +/// fontSize|1|Font Size|0 +$--font-size-medium: 16px !default; +/// fontSize|1|Font Size|0 +$--font-size-base: 14px !default; +/// fontSize|1|Font Size|0 +$--font-size-small: 13px !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-small: 12px !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-primary: 500 !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-secondary: 100 !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-primary: 24px !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-secondary: 16px !default; +$--font-color-disabled-base: #bbb !default; +/* Size +-------------------------- */ +$--size-base: 14px !default; + +/* z-index +-------------------------- */ +$--index-normal: 1 !default; +$--index-top: 1000 !default; +$--index-popper: 2000 !default; + +/* Disable base +-------------------------- */ +$--disabled-fill-base: $--background-color-base !default; +$--disabled-color-base: $--color-text-placeholder !default; +$--disabled-border-base: $--border-color-light !default; + +/* Icon +-------------------------- */ +$--icon-color: #666 !default; +$--icon-color-base: $--color-info !default; + +/* Checkbox +-------------------------- */ +/// fontSize||Font|1 +$--checkbox-font-size: 14px !default; +/// fontWeight||Font|1 +$--checkbox-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--checkbox-font-color: $--color-text-regular !default; +$--checkbox-input-height: 14px !default; +$--checkbox-input-width: 14px !default; +/// borderRadius||Border|2 +$--checkbox-border-radius: $--border-radius-small !default; +/// color||Color|0 +$--checkbox-background-color: $--color-white !default; +$--checkbox-input-border: $--border-base !default; + +/// color||Color|0 +$--checkbox-disabled-border-color: $--border-color-base !default; +$--checkbox-disabled-input-fill: #edf2fc !default; +$--checkbox-disabled-icon-color: $--color-text-placeholder !default; + +$--checkbox-disabled-checked-input-fill: $--border-color-extra-light !default; +$--checkbox-disabled-checked-input-border-color: $--border-color-base !default; +$--checkbox-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--checkbox-checked-font-color: $--color-primary !default; +$--checkbox-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-checked-background-color: $--color-primary !default; +$--checkbox-checked-icon-color: $--fill-base !default; + +$--checkbox-input-border-color-hover: $--color-primary !default; +/// height||Other|4 +$--checkbox-bordered-height: 40px !default; +/// padding||Spacing|3 +$--checkbox-bordered-padding: 9px 20px 9px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-small-padding: 5px 15px 5px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default; +$--checkbox-bordered-medium-input-height: 14px !default; +$--checkbox-bordered-medium-input-width: 14px !default; +/// height||Other|4 +$--checkbox-bordered-medium-height: 36px !default; +$--checkbox-bordered-small-input-height: 12px !default; +$--checkbox-bordered-small-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-small-height: 32px !default; +$--checkbox-bordered-mini-input-height: 12px !default; +$--checkbox-bordered-mini-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-mini-height: 28px !default; + +/// color||Color|0 +$--checkbox-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--checkbox-button-checked-border-color: $--color-primary !default; + + + +/* Radio +-------------------------- */ +/// fontSize||Font|1 +$--radio-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--radio-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--radio-font-color: $--color-text-regular !default; +$--radio-input-height: 14px !default; +$--radio-input-width: 14px !default; +/// borderRadius||Border|2 +$--radio-input-border-radius: $--border-radius-circle !default; +/// color||Color|0 +$--radio-input-background-color: $--color-white !default; +$--radio-input-border: $--border-base !default; +/// color||Color|0 +$--radio-input-border-color: $--border-color-base !default; +/// color||Color|0 +$--radio-icon-color: $--color-white !default; + +$--radio-disabled-input-border-color: $--disabled-border-base !default; +$--radio-disabled-input-fill: $--disabled-fill-base !default; +$--radio-disabled-icon-color: $--disabled-fill-base !default; + +$--radio-disabled-checked-input-border-color: $--disabled-border-base !default; +$--radio-disabled-checked-input-fill: $--disabled-fill-base !default; +$--radio-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--radio-checked-font-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-background-color: $--color-white !default; +/// color||Color|0 +$--radio-checked-icon-color: $--color-primary !default; + +$--radio-input-border-color-hover: $--color-primary !default; + +$--radio-bordered-height: 40px !default; +$--radio-bordered-padding: 12px 20px 0 10px !default; +$--radio-bordered-medium-padding: 10px 20px 0 10px !default; +$--radio-bordered-small-padding: 8px 15px 0 10px !default; +$--radio-bordered-mini-padding: 6px 15px 0 10px !default; +$--radio-bordered-medium-input-height: 14px !default; +$--radio-bordered-medium-input-width: 14px !default; +$--radio-bordered-medium-height: 36px !default; +$--radio-bordered-small-input-height: 12px !default; +$--radio-bordered-small-input-width: 12px !default; +$--radio-bordered-small-height: 32px !default; +$--radio-bordered-mini-input-height: 12px !default; +$--radio-bordered-mini-input-width: 12px !default; +$--radio-bordered-mini-height: 28px !default; + +/// fontSize||Font|1 +$--radio-button-font-size: $--font-size-base !default; +/// color||Color|0 +$--radio-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--radio-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--radio-button-checked-border-color: $--color-primary !default; +$--radio-button-disabled-checked-fill: $--border-color-extra-light !default; + +/* Select +-------------------------- */ +$--select-border-color-hover: $--border-color-hover !default; +$--select-disabled-border: $--disabled-border-base !default; +/// fontSize||Font|1 +$--select-font-size: $--font-size-base !default; +$--select-close-hover-color: $--color-text-secondary !default; + +$--select-input-color: $--color-text-placeholder !default; +$--select-multiple-input-color: #666 !default; +/// color||Color|0 +$--select-input-focus-border-color: $--color-primary !default; +/// fontSize||Font|1 +$--select-input-font-size: 14px !default; + +$--select-option-color: $--color-text-regular !default; +$--select-option-disabled-color: $--color-text-placeholder !default; +$--select-option-disabled-background: $--color-white !default; +/// height||Other|4 +$--select-option-height: 34px !default; +$--select-option-hover-background: $--background-color-base !default; +/// color||Color|0 +$--select-option-selected-font-color: $--color-primary !default; +$--select-option-selected-hover: $--background-color-base !default; + +$--select-group-color: $--color-info !default; +$--select-group-height: 30px !default; +$--select-group-font-size: 12px !default; + +$--select-dropdown-background: $--color-white !default; +$--select-dropdown-shadow: $--box-shadow-light !default; +$--select-dropdown-empty-color: #999 !default; +/// height||Other|4 +$--select-dropdown-max-height: 274px !default; +$--select-dropdown-padding: 6px 0 !default; +$--select-dropdown-empty-padding: 10px 0 !default; +$--select-dropdown-border: solid 1px $--border-color-light !default; + +/* Alert +-------------------------- */ +$--alert-padding: 8px 16px !default; +/// borderRadius||Border|2 +$--alert-border-radius: $--border-radius-base !default; +/// fontSize||Font|1 +$--alert-title-font-size: 13px !default; +/// fontSize||Font|1 +$--alert-description-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-customed-font-size: 13px !default; + +$--alert-success-color: $--color-success-lighter !default; +$--alert-info-color: $--color-info-lighter !default; +$--alert-warning-color: $--color-warning-lighter !default; +$--alert-danger-color: $--color-danger-lighter !default; + +/// height||Other|4 +$--alert-icon-size: 16px !default; +/// height||Other|4 +$--alert-icon-large-size: 28px !default; + +/* MessageBox +-------------------------- */ +/// color||Color|0 +$--messagebox-title-color: $--color-text-primary !default; +$--msgbox-width: 420px !default; +$--msgbox-border-radius: 4px !default; +/// fontSize||Font|1 +$--messagebox-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--messagebox-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--messagebox-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--messagebox-error-font-size: 12px !default; +$--msgbox-padding-primary: 15px !default; +/// color||Color|0 +$--messagebox-success-color: $--color-success !default; +/// color||Color|0 +$--messagebox-info-color: $--color-info !default; +/// color||Color|0 +$--messagebox-warning-color: $--color-warning !default; +/// color||Color|0 +$--messagebox-danger-color: $--color-danger !default; + +/* Message +-------------------------- */ +$--message-shadow: $--box-shadow-base !default; +$--message-min-width: 380px !default; +$--message-background-color: #edf2fc !default; +$--message-padding: 15px 15px 15px 20px !default; +/// color||Color|0 +$--message-close-icon-color: $--color-text-placeholder !default; +/// height||Other|4 +$--message-close-size: 16px !default; +/// color||Color|0 +$--message-close-hover-color: $--color-text-secondary !default; + +/// color||Color|0 +$--message-success-font-color: $--color-success !default; +/// color||Color|0 +$--message-info-font-color: $--color-info !default; +/// color||Color|0 +$--message-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--message-danger-font-color: $--color-danger !default; + +/* Notification +-------------------------- */ +$--notification-width: 330px !default; +/// padding||Spacing|3 +$--notification-padding: 14px 26px 14px 13px !default; +$--notification-radius: 8px !default; +$--notification-shadow: $--box-shadow-light !default; +/// color||Color|0 +$--notification-border-color: $--border-color-lighter !default; +$--notification-icon-size: 24px !default; +$--notification-close-font-size: $--message-close-size !default; +$--notification-group-margin-left: 13px !default; +$--notification-group-margin-right: 8px !default; +/// fontSize||Font|1 +$--notification-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--notification-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--notification-title-font-size: 16px !default; +/// color||Color|0 +$--notification-title-color: $--color-text-primary !default; + +/// color||Color|0 +$--notification-close-color: $--color-text-secondary !default; +/// color||Color|0 +$--notification-close-hover-color: $--color-text-regular !default; + +/// color||Color|0 +$--notification-success-icon-color: $--color-success !default; +/// color||Color|0 +$--notification-info-icon-color: $--color-info !default; +/// color||Color|0 +$--notification-warning-icon-color: $--color-warning !default; +/// color||Color|0 +$--notification-danger-icon-color: $--color-danger !default; + +/* Input +-------------------------- */ +$--input-font-size: $--font-size-base !default; +/// color||Color|0 +$--input-font-color: $--color-text-regular !default; +/// height||Other|4 +$--input-width: 140px !default; +/// height||Other|4 +$--input-height: 40px !default; +$--input-border: $--border-base !default; +$--input-border-color: $--border-color-base !default; +/// borderRadius||Border|2 +$--input-border-radius: $--border-radius-base !default; +$--input-border-color-hover: $--border-color-hover !default; +/// color||Color|0 +$--input-background-color: $--color-white !default; +$--input-fill-disabled: $--disabled-fill-base !default; +$--input-color-disabled: $--font-color-disabled-base !default; +/// color||Color|0 +$--input-icon-color: $--color-text-placeholder !default; +/// color||Color|0 +$--input-placeholder-color: $--color-text-placeholder !default; +$--input-max-width: 314px !default; + +$--input-hover-border: $--border-color-hover !default; +$--input-clear-hover-color: $--color-text-secondary !default; + +$--input-focus-border: $--color-primary !default; +$--input-focus-fill: $--color-white !default; + +$--input-disabled-fill: $--disabled-fill-base !default; +$--input-disabled-border: $--disabled-border-base !default; +$--input-disabled-color: $--disabled-color-base !default; +$--input-disabled-placeholder-color: $--color-text-placeholder !default; + +/// fontSize||Font|1 +$--input-medium-font-size: 14px !default; +/// height||Other|4 +$--input-medium-height: 36px !default; +/// fontSize||Font|1 +$--input-small-font-size: 13px !default; +/// height||Other|4 +$--input-small-height: 32px !default; +/// fontSize||Font|1 +$--input-mini-font-size: 12px !default; +/// height||Other|4 +$--input-mini-height: 28px !default; + +/* Cascader +-------------------------- */ +/// color||Color|0 +$--cascader-menu-font-color: $--color-text-regular !default; +/// color||Color|0 +$--cascader-menu-selected-font-color: $--color-primary !default; +$--cascader-menu-fill: $--fill-base !default; +$--cascader-menu-font-size: $--font-size-base !default; +$--cascader-menu-radius: $--border-radius-base !default; +$--cascader-menu-border: solid 1px $--border-color-light !default; +$--cascader-menu-shadow: $--box-shadow-light !default; +$--cascader-node-background-hover: $--background-color-base !default; +$--cascader-node-color-disabled:$--color-text-placeholder !default; +$--cascader-color-empty:$--color-text-placeholder !default; +$--cascader-tag-background: #f0f2f5; + +/* Group +-------------------------- */ +$--group-option-flex: 0 0 (1/5) * 100% !default; +$--group-option-offset-bottom: 12px !default; +$--group-option-fill-hover: rgba($--color-black, 0.06) !default; +$--group-title-color: $--color-black !default; +$--group-title-font-size: $--font-size-base !default; +$--group-title-width: 66px !default; + +/* Tab +-------------------------- */ +$--tab-font-size: $--font-size-base !default; +$--tab-border-line: 1px solid #e4e4e4 !default; +$--tab-header-color-active: $--color-text-secondary !default; +$--tab-header-color-hover: $--color-text-regular !default; +$--tab-header-color: $--color-text-regular !default; +$--tab-header-fill-active: rgba($--color-black, 0.06) !default; +$--tab-header-fill-hover: rgba($--color-black, 0.06) !default; +$--tab-vertical-header-width: 90px !default; +$--tab-vertical-header-count-color: $--color-white !default; +$--tab-vertical-header-count-fill: $--color-text-secondary !default; + +/* Button +-------------------------- */ +/// fontSize||Font|1 +$--button-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--button-font-weight: $--font-weight-primary !default; +/// borderRadius||Border|2 +$--button-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-padding-vertical: 12px !default; +/// padding||Spacing|3 +$--button-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-medium-font-size: $--font-size-base !default; +/// borderRadius||Border|2 +$--button-medium-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-medium-padding-vertical: 10px !default; +/// padding||Spacing|3 +$--button-medium-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-small-font-size: 12px !default; +$--button-small-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-small-padding-vertical: 9px !default; +/// padding||Spacing|3 +$--button-small-padding-horizontal: 15px !default; +/// fontSize||Font|1 +$--button-mini-font-size: 12px !default; +$--button-mini-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-mini-padding-vertical: 7px !default; +/// padding||Spacing|3 +$--button-mini-padding-horizontal: 15px !default; + +/// color||Color|0 +$--button-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--button-default-background-color: $--color-white !default; +/// color||Color|0 +$--button-default-border-color: $--border-color-base !default; + +/// color||Color|0 +$--button-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--button-disabled-border-color: $--border-color-lighter !default; + +/// color||Color|0 +$--button-primary-border-color: $--color-primary !default; +/// color||Color|0 +$--button-primary-font-color: $--color-white !default; +/// color||Color|0 +$--button-primary-background-color: $--color-primary !default; +/// color||Color|0 +$--button-success-border-color: $--color-success !default; +/// color||Color|0 +$--button-success-font-color: $--color-white !default; +/// color||Color|0 +$--button-success-background-color: $--color-success !default; +/// color||Color|0 +$--button-warning-border-color: $--color-warning !default; +/// color||Color|0 +$--button-warning-font-color: $--color-white !default; +/// color||Color|0 +$--button-warning-background-color: $--color-warning !default; +/// color||Color|0 +$--button-danger-border-color: $--color-danger !default; +/// color||Color|0 +$--button-danger-font-color: $--color-white !default; +/// color||Color|0 +$--button-danger-background-color: $--color-danger !default; +/// color||Color|0 +$--button-info-border-color: $--color-info !default; +/// color||Color|0 +$--button-info-font-color: $--color-white !default; +/// color||Color|0 +$--button-info-background-color: $--color-info !default; + +$--button-hover-tint-percent: 20% !default; +$--button-active-shade-percent: 10% !default; + + +/* cascader +-------------------------- */ +$--cascader-height: 200px !default; + +/* Switch +-------------------------- */ +/// color||Color|0 +$--switch-on-color: $--color-primary !default; +/// color||Color|0 +$--switch-off-color: $--border-color-base !default; +/// fontSize||Font|1 +$--switch-font-size: $--font-size-base !default; +$--switch-core-border-radius: 10px !default; +// height||Other|4 TODO: width 代码写死的40px 所以下面这三个属性都没意义 +$--switch-width: 40px !default; +// height||Other|4 +$--switch-height: 20px !default; +// height||Other|4 +$--switch-button-size: 16px !default; + +/* Dialog +-------------------------- */ +$--dialog-background-color: $--color-white !default; +$--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !default; +/// fontSize||Font|1 +$--dialog-title-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--dialog-content-font-size: 14px !default; +/// fontLineHeight||LineHeight|2 +$--dialog-font-line-height: $--font-line-height-primary !default; +/// padding||Spacing|3 +$--dialog-padding-primary: 20px !default; + +/* Table +-------------------------- */ +/// color||Color|0 +$--table-border-color: $--border-color-lighter !default; +$--table-border: 1px solid $--table-border-color !default; +/// color||Color|0 +$--table-font-color: $--color-text-regular !default; +/// color||Color|0 +$--table-header-font-color: $--color-text-secondary !default; +/// color||Color|0 +$--table-row-hover-background-color: $--background-color-base !default; +$--table-current-row-background-color: $--color-primary-light-9 !default; +/// color||Color|0 +$--table-header-background-color: $--color-white !default; +$--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, .12) !default; + +/* Pagination +-------------------------- */ +/// fontSize||Font|1 +$--pagination-font-size: 13px !default; +/// color||Color|0 +$--pagination-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-font-color: $--color-text-primary !default; +$--pagination-border-radius: 3px !default; +/// color||Color|0 +$--pagination-button-color: $--color-text-primary !default; +/// height||Other|4 +$--pagination-button-width: 35.5px !default; +/// height||Other|4 +$--pagination-button-height: 28px !default; +/// color||Color|0 +$--pagination-button-disabled-color: $--color-text-placeholder !default; +/// color||Color|0 +$--pagination-button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-hover-color: $--color-primary !default; + +/* Popup +-------------------------- */ +/// color||Color|0 +$--popup-modal-background-color: $--color-black !default; +/// opacity||Other|1 +$--popup-modal-opacity: 0.5 !default; + +/* Popover +-------------------------- */ +/// color||Color|0 +$--popover-background-color: $--color-white !default; +/// fontSize||Font|1 +$--popover-font-size: $--font-size-base !default; +/// color||Color|0 +$--popover-border-color: $--border-color-lighter !default; +$--popover-arrow-size: 6px !default; +/// padding||Spacing|3 +$--popover-padding: 12px !default; +$--popover-padding-large: 18px 20px !default; +/// fontSize||Font|1 +$--popover-title-font-size: 16px !default; +/// color||Color|0 +$--popover-title-font-color: $--color-text-primary !default; + +/* Tooltip +-------------------------- */ +/// color|1|Color|0 +$--tooltip-fill: $--color-text-primary !default; +/// color|1|Color|0 +$--tooltip-color: $--color-white !default; +/// fontSize||Font|1 +$--tooltip-font-size: 12px !default; +/// color||Color|0 +$--tooltip-border-color: $--color-text-primary !default; +$--tooltip-arrow-size: 6px !default; +/// padding||Spacing|3 +$--tooltip-padding: 10px !default; + +/* Tag +-------------------------- */ +/// color||Color|0 +$--tag-info-color: $--color-info !default; +/// color||Color|0 +$--tag-primary-color: $--color-primary !default; +/// color||Color|0 +$--tag-success-color: $--color-success !default; +/// color||Color|0 +$--tag-warning-color: $--color-warning !default; +/// color||Color|0 +$--tag-danger-color: $--color-danger !default; +/// fontSize||Font|1 +$--tag-font-size: 12px !default; +$--tag-border-radius: 4px !default; +$--tag-padding: 0 10px !default; + +/* Tree +-------------------------- */ +/// color||Color|0 +$--tree-node-hover-background-color: $--background-color-base !default; +/// color||Color|0 +$--tree-font-color: $--color-text-regular !default; +/// color||Color|0 +$--tree-expand-icon-color: $--color-text-placeholder !default; + +/* Dropdown +-------------------------- */ +$--dropdown-menu-box-shadow: $--box-shadow-light !default; +$--dropdown-menuItem-hover-fill: $--color-primary-light-9 !default; +$--dropdown-menuItem-hover-color: $--link-color !default; + +/* Badge +-------------------------- */ +/// color||Color|0 +$--badge-background-color: $--color-danger !default; +$--badge-radius: 10px !default; +/// fontSize||Font|1 +$--badge-font-size: 12px !default; +/// padding||Spacing|3 +$--badge-padding: 6px !default; +/// height||Other|4 +$--badge-size: 18px !default; + +/* Card +--------------------------*/ +/// color||Color|0 +$--card-border-color: $--border-color-lighter !default; +$--card-border-radius: 4px !default; +/// padding||Spacing|3 +$--card-padding: 20px !default; + +/* Slider +--------------------------*/ +/// color||Color|0 +$--slider-main-background-color: $--color-primary !default; +/// color||Color|0 +$--slider-runway-background-color: $--border-color-light !default; +$--slider-button-hover-color: mix($--color-primary, black, 97%) !default; +$--slider-stop-background-color: $--color-white !default; +$--slider-disable-color: $--color-text-placeholder !default; +$--slider-margin: 16px 0 !default; +$--slider-border-radius: 3px !default; +/// height|1|Other|4 +$--slider-height: 6px !default; +/// height||Other|4 +$--slider-button-size: 16px !default; +$--slider-button-wrapper-size: 36px !default; +$--slider-button-wrapper-offset: -15px !default; + +/* Steps +--------------------------*/ +$--steps-border-color: $--disabled-border-base !default; +$--steps-border-radius: 4px !default; +$--steps-padding: 20px !default; + +/* Menu +--------------------------*/ +/// fontSize||Font|1 +$--menu-item-font-size: $--font-size-base !default; +/// color||Color|0 +$--menu-item-font-color: $--color-text-primary !default; +/// color||Color|0 +$--menu-background-color: $--color-menu-background !default; +$--menu-item-hover-fill: $--color-primary-light-9 !default; + +/* Rate +--------------------------*/ +$--rate-height: 20px !default; +/// fontSize||Font|1 +$--rate-font-size: $--font-size-base !default; +/// height||Other|3 +$--rate-icon-size: 18px !default; +/// margin||Spacing|2 +$--rate-icon-margin: 6px !default; +$--rate-icon-color: $--color-text-placeholder !default; + +/* DatePicker +--------------------------*/ +$--datepicker-font-color: $--color-text-regular !default; +/// color|1|Color|0 +$--datepicker-off-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--datepicker-header-font-color: $--color-text-regular !default; +$--datepicker-icon-color: $--color-text-primary !default; +$--datepicker-border-color: $--disabled-border-base !default; +$--datepicker-inner-border-color: #e4e4e4 !default; +/// color||Color|0 +$--datepicker-inrange-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-inrange-hover-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-active-color: $--color-primary !default; +/// color||Color|0 +$--datepicker-hover-font-color: $--color-primary !default; +$--datepicker-cell-hover-color: #fff !default; + +/* Loading +--------------------------*/ +/// height||Other|4 +$--loading-spinner-size: 42px !default; +/// height||Other|4 +$--loading-fullscreen-spinner-size: 50px !default; + +/* Scrollbar +--------------------------*/ +$--scrollbar-background-color: rgba($--color-text-secondary, .3) !default; +$--scrollbar-hover-background-color: rgba($--color-text-secondary, .5) !default; + +/* Carousel +--------------------------*/ +/// fontSize||Font|1 +$--carousel-arrow-font-size: 12px !default; +$--carousel-arrow-size: 36px !default; +$--carousel-arrow-background: rgba(31, 45, 61, 0.11) !default; +$--carousel-arrow-hover-background: rgba(31, 45, 61, 0.23) !default; +/// width||Other|4 +$--carousel-indicator-width: 30px !default; +/// height||Other|4 +$--carousel-indicator-height: 2px !default; +$--carousel-indicator-padding-horizontal: 4px !default; +$--carousel-indicator-padding-vertical: 12px !default; +$--carousel-indicator-out-color: $--border-color-hover !default; + +/* Collapse +--------------------------*/ +/// color||Color|0 +$--collapse-border-color: $--border-color-lighter !default; +/// height||Other|4 +$--collapse-header-height: 48px !default; +/// color||Color|0 +$--collapse-header-background-color: $--color-white !default; +/// color||Color|0 +$--collapse-header-font-color: $--color-text-primary !default; +/// fontSize||Font|1 +$--collapse-header-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-background-color: $--color-white !default; +/// fontSize||Font|1 +$--collapse-content-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-font-color: $--color-text-primary !default; + +/* Transfer +--------------------------*/ +$--transfer-border-color: $--border-color-lighter !default; +$--transfer-border-radius: $--border-radius-base !default; +/// height||Other|4 +$--transfer-panel-width: 200px !default; +/// height||Other|4 +$--transfer-panel-header-height: 40px !default; +/// color||Color|0 +$--transfer-panel-header-background-color: $--background-color-base !default; +/// height||Other|4 +$--transfer-panel-footer-height: 40px !default; +/// height||Other|4 +$--transfer-panel-body-height: 246px !default; +/// height||Other|4 +$--transfer-item-height: 30px !default; +/// height||Other|4 +$--transfer-filter-height: 32px !default; + +/* Header + --------------------------*/ +$--header-padding: 0 20px !default; + +/* Footer +--------------------------*/ +$--footer-padding: 0 20px !default; + +/* Main +--------------------------*/ +$--main-padding: 20px !default; + +/* Timeline +--------------------------*/ +$--timeline-node-size-normal: 12px !default; +$--timeline-node-size-large: 14px !default; +$--timeline-node-color: $--border-color-light !default; + +/* Backtop +--------------------------*/ +/// color||Color|0 +$--backtop-background-color: $--color-white !default; +/// color||Color|0 +$--backtop-font-color: $--color-primary !default; +/// color||Color|0 +$--backtop-hover-background-color: $--border-color-extra-light !default; + +/* Link +--------------------------*/ +/// fontSize||Font|1 +$--link-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--link-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--link-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--link-default-active-color: $--color-primary !default; +/// color||Color|0 +$--link-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--link-primary-font-color: $--color-primary !default; +/// color||Color|0 +$--link-success-font-color: $--color-success !default; +/// color||Color|0 +$--link-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--link-danger-font-color: $--color-danger !default; +/// color||Color|0 +$--link-info-font-color: $--color-info !default; +/* Calendar +--------------------------*/ +/// border||Other|4 +$--calendar-border: $--table-border !default; +/// color||Other|4 +$--calendar-selected-background-color: #F2F8FE !default; +$--calendar-cell-width: 85px !default; + +/* Form +-------------------------- */ +/// fontSize||Font|1 +$--form-label-font-size: $--font-size-base !default; + +/* Avatar +--------------------------*/ +/// color||Color|0 +$--avatar-font-color: #fff !default; +/// color||Color|0 +$--avatar-background-color: #C0C4CC !default; +/// fontSize||Font Size|1 +$--avatar-text-font-size: 14px !default; +/// fontSize||Font Size|1 +$--avatar-icon-font-size: 18px !default; +/// borderRadius||Border|2 +$--avatar-border-radius: $--border-radius-base !default; +/// size|1|Avatar Size|3 +$--avatar-large-size: 40px !default; +/// size|1|Avatar Size|3 +$--avatar-medium-size: 36px !default; +/// size|1|Avatar Size|3 +$--avatar-small-size: 28px !default; + +/* Break-point +--------------------------*/ +$--sm: 768px !default; +$--md: 992px !default; +$--lg: 1200px !default; +$--xl: 1920px !default; + +$--breakpoints: ( + 'xs' : (max-width: $--sm - 1), + 'sm' : (min-width: $--sm), + 'md' : (min-width: $--md), + 'lg' : (min-width: $--lg), + 'xl' : (min-width: $--xl) +); + +$--breakpoints-spec: ( + 'xs-only' : (max-width: $--sm - 1), + 'sm-and-up' : (min-width: $--sm), + 'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md - 1})", + 'sm-and-down': (max-width: $--md - 1), + 'md-and-up' : (min-width: $--md), + 'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg - 1})", + 'md-and-down': (max-width: $--lg - 1), + 'lg-and-up' : (min-width: $--lg), + 'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})", + 'lg-and-down': (max-width: $--xl - 1), + 'xl-only' : (min-width: $--xl), +); diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-orange.scss b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-orange.scss new file mode 100644 index 00000000..26da27c0 --- /dev/null +++ b/orange-demo-flowable/orange-demo-flowable-web/src/assets/element-variables-orange.scss @@ -0,0 +1,1001 @@ +/* Element Chalk Variables */ + +// Special comment for theme configurator +// type|skipAutoTranslation|Category|Order +// skipAutoTranslation 1 + +/* Transition +-------------------------- */ +$--all-transition: all .3s cubic-bezier(.645,.045,.355,1) !default; +$--fade-transition: opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--fade-linear-transition: opacity 200ms linear !default; +$--md-fade-transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1), opacity 300ms cubic-bezier(0.23, 1, 0.32, 1) !default; +$--border-transition-base: border-color .2s cubic-bezier(.645,.045,.355,1) !default; +$--color-transition-base: color .2s cubic-bezier(.645,.045,.355,1) !default; + +/* Color +-------------------------- */ +/// color|1|Brand Color|0 +$--color-primary: #FCA834 !default; +/// color|1|Background Color|4 +$--color-white: #FFFFFF !default; +/// color|1|Background Color|4 +$--color-black: #000000 !default; +$--color-primary-light-1: mix($--color-white, $--color-primary, 10%) !default; /* 53a8ff */ +$--color-primary-light-2: mix($--color-white, $--color-primary, 20%) !default; /* 66b1ff */ +$--color-primary-light-3: mix($--color-white, $--color-primary, 30%) !default; /* 79bbff */ +$--color-primary-light-4: mix($--color-white, $--color-primary, 40%) !default; /* 8cc5ff */ +$--color-primary-light-5: mix($--color-white, $--color-primary, 50%) !default; /* a0cfff */ +$--color-primary-light-6: mix($--color-white, $--color-primary, 60%) !default; /* b3d8ff */ +$--color-primary-light-7: mix($--color-white, $--color-primary, 70%) !default; /* c6e2ff */ +$--color-primary-light-8: mix($--color-white, $--color-primary, 80%) !default; /* d9ecff */ +$--color-primary-light-9: mix($--color-white, $--color-primary, 90%) !default; /* ecf5ff */ +/// color|1|Functional Color|1 +$--color-success: #6DC741 !default; +/// color|1|Functional Color|1 +$--color-warning: #E6A23C !default; +/// color|1|Functional Color|1 +$--color-danger: #F56C6C !default; +/// color|1|Functional Color|1 +$--color-info: #909399 !default; + +$--color-success-light: mix($--color-white, $--color-success, 80%) !default; +$--color-warning-light: mix($--color-white, $--color-warning, 80%) !default; +$--color-danger-light: mix($--color-white, $--color-danger, 80%) !default; +$--color-info-light: mix($--color-white, $--color-info, 80%) !default; + +$--color-success-lighter: mix($--color-white, $--color-success, 90%) !default; +$--color-warning-lighter: mix($--color-white, $--color-warning, 90%) !default; +$--color-danger-lighter: mix($--color-white, $--color-danger, 90%) !default; +$--color-info-lighter: mix($--color-white, $--color-info, 90%) !default; +/// color|1|Font Color|2 +$--color-text-primary: #303133 !default; +/// color|1|Font Color|2 +$--color-text-regular: #606266 !default; +/// color|1|Font Color|2 +$--color-text-secondary: #909399 !default; +/// color|1|Font Color|2 +$--color-text-placeholder: #C0C4CC !default; +/// color|1|Border Color|3 +$--border-color-base: #DCDFE6 !default; +/// color|1|Border Color|3 +$--border-color-light: #E4E7ED !default; +/// color|1|Border Color|3 +$--border-color-lighter: #EBEEF5 !default; +/// color|1|Border Color|3 +$--border-color-extra-light: #F2F6FC !default; + +// Background +/// color|1|Background Color|4 +$--background-color-base: #F5F7FA !default; + +// color for left sidebar title +$--color-sidebar-title-text: #FFFFFF; +// color for left sidebar background +$--color-menu-background: #042345; +$--color-menu-item-active-text-color: #FFFFFF; +$--color-menu-item-active-background: $--color-primary; +$--color-submenu-background: #021F3B; +/* Link +-------------------------- */ +$--link-color: $--color-primary-light-2 !default; +$--link-hover-color: $--color-primary !default; + +/* Border +-------------------------- */ +$--border-width-base: 1px !default; +$--border-style-base: solid !default; +$--border-color-hover: $--color-text-placeholder !default; +$--border-base: $--border-width-base $--border-style-base $--border-color-base !default; +/// borderRadius|1|Radius|0 +$--border-radius-base: 4px !default; +/// borderRadius|1|Radius|0 +$--border-radius-small: 2px !default; +/// borderRadius|1|Radius|0 +$--border-radius-circle: 100% !default; +/// borderRadius|1|Radius|0 +$--border-radius-zero: 0 !default; + +// Box-shadow +/// boxShadow|1|Shadow|1 +$--box-shadow-base: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .04) !default; +// boxShadow|1|Shadow|1 +$--box-shadow-dark: 0 2px 4px rgba(0, 0, 0, .12), 0 0 6px rgba(0, 0, 0, .12) !default; +/// boxShadow|1|Shadow|1 +$--box-shadow-light: 0 2px 12px 0 rgba(0, 0, 0, 0.1) !default; + +/* Fill +-------------------------- */ +$--fill-base: $--color-white !default; + +/* Typography +-------------------------- */ +$--font-path: 'fonts' !default; +$--font-display: 'auto' !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-large: 20px !default; +/// fontSize|1|Font Size|0 +$--font-size-large: 18px !default; +/// fontSize|1|Font Size|0 +$--font-size-medium: 16px !default; +/// fontSize|1|Font Size|0 +$--font-size-base: 14px !default; +/// fontSize|1|Font Size|0 +$--font-size-small: 13px !default; +/// fontSize|1|Font Size|0 +$--font-size-extra-small: 12px !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-primary: 500 !default; +/// fontWeight|1|Font Weight|1 +$--font-weight-secondary: 100 !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-primary: 24px !default; +/// fontLineHeight|1|Line Height|2 +$--font-line-height-secondary: 16px !default; +$--font-color-disabled-base: #bbb !default; +/* Size +-------------------------- */ +$--size-base: 14px !default; + +/* z-index +-------------------------- */ +$--index-normal: 1 !default; +$--index-top: 1000 !default; +$--index-popper: 2000 !default; + +/* Disable base +-------------------------- */ +$--disabled-fill-base: $--background-color-base !default; +$--disabled-color-base: $--color-text-placeholder !default; +$--disabled-border-base: $--border-color-light !default; + +/* Icon +-------------------------- */ +$--icon-color: #666 !default; +$--icon-color-base: $--color-info !default; + +/* Checkbox +-------------------------- */ +/// fontSize||Font|1 +$--checkbox-font-size: 14px !default; +/// fontWeight||Font|1 +$--checkbox-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--checkbox-font-color: $--color-text-regular !default; +$--checkbox-input-height: 14px !default; +$--checkbox-input-width: 14px !default; +/// borderRadius||Border|2 +$--checkbox-border-radius: $--border-radius-small !default; +/// color||Color|0 +$--checkbox-background-color: $--color-white !default; +$--checkbox-input-border: $--border-base !default; + +/// color||Color|0 +$--checkbox-disabled-border-color: $--border-color-base !default; +$--checkbox-disabled-input-fill: #edf2fc !default; +$--checkbox-disabled-icon-color: $--color-text-placeholder !default; + +$--checkbox-disabled-checked-input-fill: $--border-color-extra-light !default; +$--checkbox-disabled-checked-input-border-color: $--border-color-base !default; +$--checkbox-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--checkbox-checked-font-color: $--color-primary !default; +$--checkbox-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-checked-background-color: $--color-primary !default; +$--checkbox-checked-icon-color: $--fill-base !default; + +$--checkbox-input-border-color-hover: $--color-primary !default; +/// height||Other|4 +$--checkbox-bordered-height: 40px !default; +/// padding||Spacing|3 +$--checkbox-bordered-padding: 9px 20px 9px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-medium-padding: 7px 20px 7px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-small-padding: 5px 15px 5px 10px !default; +/// padding||Spacing|3 +$--checkbox-bordered-mini-padding: 3px 15px 3px 10px !default; +$--checkbox-bordered-medium-input-height: 14px !default; +$--checkbox-bordered-medium-input-width: 14px !default; +/// height||Other|4 +$--checkbox-bordered-medium-height: 36px !default; +$--checkbox-bordered-small-input-height: 12px !default; +$--checkbox-bordered-small-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-small-height: 32px !default; +$--checkbox-bordered-mini-input-height: 12px !default; +$--checkbox-bordered-mini-input-width: 12px !default; +/// height||Other|4 +$--checkbox-bordered-mini-height: 28px !default; + +/// color||Color|0 +$--checkbox-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--checkbox-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--checkbox-button-checked-border-color: $--color-primary !default; + + + +/* Radio +-------------------------- */ +/// fontSize||Font|1 +$--radio-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--radio-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--radio-font-color: $--color-text-regular !default; +$--radio-input-height: 14px !default; +$--radio-input-width: 14px !default; +/// borderRadius||Border|2 +$--radio-input-border-radius: $--border-radius-circle !default; +/// color||Color|0 +$--radio-input-background-color: $--color-white !default; +$--radio-input-border: $--border-base !default; +/// color||Color|0 +$--radio-input-border-color: $--border-color-base !default; +/// color||Color|0 +$--radio-icon-color: $--color-white !default; + +$--radio-disabled-input-border-color: $--disabled-border-base !default; +$--radio-disabled-input-fill: $--disabled-fill-base !default; +$--radio-disabled-icon-color: $--disabled-fill-base !default; + +$--radio-disabled-checked-input-border-color: $--disabled-border-base !default; +$--radio-disabled-checked-input-fill: $--disabled-fill-base !default; +$--radio-disabled-checked-icon-color: $--color-text-placeholder !default; + +/// color||Color|0 +$--radio-checked-font-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-border-color: $--color-primary !default; +/// color||Color|0 +$--radio-checked-input-background-color: $--color-white !default; +/// color||Color|0 +$--radio-checked-icon-color: $--color-primary !default; + +$--radio-input-border-color-hover: $--color-primary !default; + +$--radio-bordered-height: 40px !default; +$--radio-bordered-padding: 12px 20px 0 10px !default; +$--radio-bordered-medium-padding: 10px 20px 0 10px !default; +$--radio-bordered-small-padding: 8px 15px 0 10px !default; +$--radio-bordered-mini-padding: 6px 15px 0 10px !default; +$--radio-bordered-medium-input-height: 14px !default; +$--radio-bordered-medium-input-width: 14px !default; +$--radio-bordered-medium-height: 36px !default; +$--radio-bordered-small-input-height: 12px !default; +$--radio-bordered-small-input-width: 12px !default; +$--radio-bordered-small-height: 32px !default; +$--radio-bordered-mini-input-height: 12px !default; +$--radio-bordered-mini-input-width: 12px !default; +$--radio-bordered-mini-height: 28px !default; + +/// fontSize||Font|1 +$--radio-button-font-size: $--font-size-base !default; +/// color||Color|0 +$--radio-button-checked-background-color: $--color-primary !default; +/// color||Color|0 +$--radio-button-checked-font-color: $--color-white !default; +/// color||Color|0 +$--radio-button-checked-border-color: $--color-primary !default; +$--radio-button-disabled-checked-fill: $--border-color-extra-light !default; + +/* Select +-------------------------- */ +$--select-border-color-hover: $--border-color-hover !default; +$--select-disabled-border: $--disabled-border-base !default; +/// fontSize||Font|1 +$--select-font-size: $--font-size-base !default; +$--select-close-hover-color: $--color-text-secondary !default; + +$--select-input-color: $--color-text-placeholder !default; +$--select-multiple-input-color: #666 !default; +/// color||Color|0 +$--select-input-focus-border-color: $--color-primary !default; +/// fontSize||Font|1 +$--select-input-font-size: 14px !default; + +$--select-option-color: $--color-text-regular !default; +$--select-option-disabled-color: $--color-text-placeholder !default; +$--select-option-disabled-background: $--color-white !default; +/// height||Other|4 +$--select-option-height: 34px !default; +$--select-option-hover-background: $--background-color-base !default; +/// color||Color|0 +$--select-option-selected-font-color: $--color-primary !default; +$--select-option-selected-hover: $--background-color-base !default; + +$--select-group-color: $--color-info !default; +$--select-group-height: 30px !default; +$--select-group-font-size: 12px !default; + +$--select-dropdown-background: $--color-white !default; +$--select-dropdown-shadow: $--box-shadow-light !default; +$--select-dropdown-empty-color: #999 !default; +/// height||Other|4 +$--select-dropdown-max-height: 274px !default; +$--select-dropdown-padding: 6px 0 !default; +$--select-dropdown-empty-padding: 10px 0 !default; +$--select-dropdown-border: solid 1px $--border-color-light !default; + +/* Alert +-------------------------- */ +$--alert-padding: 8px 16px !default; +/// borderRadius||Border|2 +$--alert-border-radius: $--border-radius-base !default; +/// fontSize||Font|1 +$--alert-title-font-size: 13px !default; +/// fontSize||Font|1 +$--alert-description-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-font-size: 12px !default; +/// fontSize||Font|1 +$--alert-close-customed-font-size: 13px !default; + +$--alert-success-color: $--color-success-lighter !default; +$--alert-info-color: $--color-info-lighter !default; +$--alert-warning-color: $--color-warning-lighter !default; +$--alert-danger-color: $--color-danger-lighter !default; + +/// height||Other|4 +$--alert-icon-size: 16px !default; +/// height||Other|4 +$--alert-icon-large-size: 28px !default; + +/* MessageBox +-------------------------- */ +/// color||Color|0 +$--messagebox-title-color: $--color-text-primary !default; +$--msgbox-width: 420px !default; +$--msgbox-border-radius: 4px !default; +/// fontSize||Font|1 +$--messagebox-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--messagebox-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--messagebox-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--messagebox-error-font-size: 12px !default; +$--msgbox-padding-primary: 15px !default; +/// color||Color|0 +$--messagebox-success-color: $--color-success !default; +/// color||Color|0 +$--messagebox-info-color: $--color-info !default; +/// color||Color|0 +$--messagebox-warning-color: $--color-warning !default; +/// color||Color|0 +$--messagebox-danger-color: $--color-danger !default; + +/* Message +-------------------------- */ +$--message-shadow: $--box-shadow-base !default; +$--message-min-width: 380px !default; +$--message-background-color: #edf2fc !default; +$--message-padding: 15px 15px 15px 20px !default; +/// color||Color|0 +$--message-close-icon-color: $--color-text-placeholder !default; +/// height||Other|4 +$--message-close-size: 16px !default; +/// color||Color|0 +$--message-close-hover-color: $--color-text-secondary !default; + +/// color||Color|0 +$--message-success-font-color: $--color-success !default; +/// color||Color|0 +$--message-info-font-color: $--color-info !default; +/// color||Color|0 +$--message-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--message-danger-font-color: $--color-danger !default; + +/* Notification +-------------------------- */ +$--notification-width: 330px !default; +/// padding||Spacing|3 +$--notification-padding: 14px 26px 14px 13px !default; +$--notification-radius: 8px !default; +$--notification-shadow: $--box-shadow-light !default; +/// color||Color|0 +$--notification-border-color: $--border-color-lighter !default; +$--notification-icon-size: 24px !default; +$--notification-close-font-size: $--message-close-size !default; +$--notification-group-margin-left: 13px !default; +$--notification-group-margin-right: 8px !default; +/// fontSize||Font|1 +$--notification-content-font-size: $--font-size-base !default; +/// color||Color|0 +$--notification-content-color: $--color-text-regular !default; +/// fontSize||Font|1 +$--notification-title-font-size: 16px !default; +/// color||Color|0 +$--notification-title-color: $--color-text-primary !default; + +/// color||Color|0 +$--notification-close-color: $--color-text-secondary !default; +/// color||Color|0 +$--notification-close-hover-color: $--color-text-regular !default; + +/// color||Color|0 +$--notification-success-icon-color: $--color-success !default; +/// color||Color|0 +$--notification-info-icon-color: $--color-info !default; +/// color||Color|0 +$--notification-warning-icon-color: $--color-warning !default; +/// color||Color|0 +$--notification-danger-icon-color: $--color-danger !default; + +/* Input +-------------------------- */ +$--input-font-size: $--font-size-base !default; +/// color||Color|0 +$--input-font-color: $--color-text-regular !default; +/// height||Other|4 +$--input-width: 140px !default; +/// height||Other|4 +$--input-height: 40px !default; +$--input-border: $--border-base !default; +$--input-border-color: $--border-color-base !default; +/// borderRadius||Border|2 +$--input-border-radius: $--border-radius-base !default; +$--input-border-color-hover: $--border-color-hover !default; +/// color||Color|0 +$--input-background-color: $--color-white !default; +$--input-fill-disabled: $--disabled-fill-base !default; +$--input-color-disabled: $--font-color-disabled-base !default; +/// color||Color|0 +$--input-icon-color: $--color-text-placeholder !default; +/// color||Color|0 +$--input-placeholder-color: $--color-text-placeholder !default; +$--input-max-width: 314px !default; + +$--input-hover-border: $--border-color-hover !default; +$--input-clear-hover-color: $--color-text-secondary !default; + +$--input-focus-border: $--color-primary !default; +$--input-focus-fill: $--color-white !default; + +$--input-disabled-fill: $--disabled-fill-base !default; +$--input-disabled-border: $--disabled-border-base !default; +$--input-disabled-color: $--disabled-color-base !default; +$--input-disabled-placeholder-color: $--color-text-placeholder !default; + +/// fontSize||Font|1 +$--input-medium-font-size: 14px !default; +/// height||Other|4 +$--input-medium-height: 36px !default; +/// fontSize||Font|1 +$--input-small-font-size: 13px !default; +/// height||Other|4 +$--input-small-height: 32px !default; +/// fontSize||Font|1 +$--input-mini-font-size: 12px !default; +/// height||Other|4 +$--input-mini-height: 28px !default; + +/* Cascader +-------------------------- */ +/// color||Color|0 +$--cascader-menu-font-color: $--color-text-regular !default; +/// color||Color|0 +$--cascader-menu-selected-font-color: $--color-primary !default; +$--cascader-menu-fill: $--fill-base !default; +$--cascader-menu-font-size: $--font-size-base !default; +$--cascader-menu-radius: $--border-radius-base !default; +$--cascader-menu-border: solid 1px $--border-color-light !default; +$--cascader-menu-shadow: $--box-shadow-light !default; +$--cascader-node-background-hover: $--background-color-base !default; +$--cascader-node-color-disabled:$--color-text-placeholder !default; +$--cascader-color-empty:$--color-text-placeholder !default; +$--cascader-tag-background: #f0f2f5; + +/* Group +-------------------------- */ +$--group-option-flex: 0 0 (1/5) * 100% !default; +$--group-option-offset-bottom: 12px !default; +$--group-option-fill-hover: rgba($--color-black, 0.06) !default; +$--group-title-color: $--color-black !default; +$--group-title-font-size: $--font-size-base !default; +$--group-title-width: 66px !default; + +/* Tab +-------------------------- */ +$--tab-font-size: $--font-size-base !default; +$--tab-border-line: 1px solid #e4e4e4 !default; +$--tab-header-color-active: $--color-text-secondary !default; +$--tab-header-color-hover: $--color-text-regular !default; +$--tab-header-color: $--color-text-regular !default; +$--tab-header-fill-active: rgba($--color-black, 0.06) !default; +$--tab-header-fill-hover: rgba($--color-black, 0.06) !default; +$--tab-vertical-header-width: 90px !default; +$--tab-vertical-header-count-color: $--color-white !default; +$--tab-vertical-header-count-fill: $--color-text-secondary !default; + +/* Button +-------------------------- */ +/// fontSize||Font|1 +$--button-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--button-font-weight: $--font-weight-primary !default; +/// borderRadius||Border|2 +$--button-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-padding-vertical: 12px !default; +/// padding||Spacing|3 +$--button-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-medium-font-size: $--font-size-base !default; +/// borderRadius||Border|2 +$--button-medium-border-radius: $--border-radius-base !default; +/// padding||Spacing|3 +$--button-medium-padding-vertical: 10px !default; +/// padding||Spacing|3 +$--button-medium-padding-horizontal: 20px !default; + +/// fontSize||Font|1 +$--button-small-font-size: 12px !default; +$--button-small-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-small-padding-vertical: 9px !default; +/// padding||Spacing|3 +$--button-small-padding-horizontal: 15px !default; +/// fontSize||Font|1 +$--button-mini-font-size: 12px !default; +$--button-mini-border-radius: #{$--border-radius-base - 1} !default; +/// padding||Spacing|3 +$--button-mini-padding-vertical: 7px !default; +/// padding||Spacing|3 +$--button-mini-padding-horizontal: 15px !default; + +/// color||Color|0 +$--button-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--button-default-background-color: $--color-white !default; +/// color||Color|0 +$--button-default-border-color: $--border-color-base !default; + +/// color||Color|0 +$--button-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--button-disabled-border-color: $--border-color-lighter !default; + +/// color||Color|0 +$--button-primary-border-color: $--color-primary !default; +/// color||Color|0 +$--button-primary-font-color: $--color-white !default; +/// color||Color|0 +$--button-primary-background-color: $--color-primary !default; +/// color||Color|0 +$--button-success-border-color: $--color-success !default; +/// color||Color|0 +$--button-success-font-color: $--color-white !default; +/// color||Color|0 +$--button-success-background-color: $--color-success !default; +/// color||Color|0 +$--button-warning-border-color: $--color-warning !default; +/// color||Color|0 +$--button-warning-font-color: $--color-white !default; +/// color||Color|0 +$--button-warning-background-color: $--color-warning !default; +/// color||Color|0 +$--button-danger-border-color: $--color-danger !default; +/// color||Color|0 +$--button-danger-font-color: $--color-white !default; +/// color||Color|0 +$--button-danger-background-color: $--color-danger !default; +/// color||Color|0 +$--button-info-border-color: $--color-info !default; +/// color||Color|0 +$--button-info-font-color: $--color-white !default; +/// color||Color|0 +$--button-info-background-color: $--color-info !default; + +$--button-hover-tint-percent: 20% !default; +$--button-active-shade-percent: 10% !default; + + +/* cascader +-------------------------- */ +$--cascader-height: 200px !default; + +/* Switch +-------------------------- */ +/// color||Color|0 +$--switch-on-color: $--color-primary !default; +/// color||Color|0 +$--switch-off-color: $--border-color-base !default; +/// fontSize||Font|1 +$--switch-font-size: $--font-size-base !default; +$--switch-core-border-radius: 10px !default; +// height||Other|4 TODO: width 代码写死的40px 所以下面这三个属性都没意义 +$--switch-width: 40px !default; +// height||Other|4 +$--switch-height: 20px !default; +// height||Other|4 +$--switch-button-size: 16px !default; + +/* Dialog +-------------------------- */ +$--dialog-background-color: $--color-white !default; +$--dialog-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3) !default; +/// fontSize||Font|1 +$--dialog-title-font-size: $--font-size-large !default; +/// fontSize||Font|1 +$--dialog-content-font-size: 14px !default; +/// fontLineHeight||LineHeight|2 +$--dialog-font-line-height: $--font-line-height-primary !default; +/// padding||Spacing|3 +$--dialog-padding-primary: 20px !default; + +/* Table +-------------------------- */ +/// color||Color|0 +$--table-border-color: $--border-color-lighter !default; +$--table-border: 1px solid $--table-border-color !default; +/// color||Color|0 +$--table-font-color: $--color-text-regular !default; +/// color||Color|0 +$--table-header-font-color: $--color-text-secondary !default; +/// color||Color|0 +$--table-row-hover-background-color: $--background-color-base !default; +$--table-current-row-background-color: rgba(255, 255, 255, .12) !default; +/// color||Color|0 +$--table-header-background-color: $--color-white !default; +$--table-fixed-box-shadow: 0 0 10px rgba(0, 0, 0, .12) !default; + +/* Pagination +-------------------------- */ +/// fontSize||Font|1 +$--pagination-font-size: 13px !default; +/// color||Color|0 +$--pagination-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-font-color: $--color-text-primary !default; +$--pagination-border-radius: 3px !default; +/// color||Color|0 +$--pagination-button-color: $--color-text-primary !default; +/// height||Other|4 +$--pagination-button-width: 35.5px !default; +/// height||Other|4 +$--pagination-button-height: 28px !default; +/// color||Color|0 +$--pagination-button-disabled-color: $--color-text-placeholder !default; +/// color||Color|0 +$--pagination-button-disabled-background-color: $--color-white !default; +/// color||Color|0 +$--pagination-hover-color: $--color-primary !default; + +/* Popup +-------------------------- */ +/// color||Color|0 +$--popup-modal-background-color: $--color-black !default; +/// opacity||Other|1 +$--popup-modal-opacity: 0.5 !default; + +/* Popover +-------------------------- */ +/// color||Color|0 +$--popover-background-color: $--color-white !default; +/// fontSize||Font|1 +$--popover-font-size: $--font-size-base !default; +/// color||Color|0 +$--popover-border-color: $--border-color-lighter !default; +$--popover-arrow-size: 6px !default; +/// padding||Spacing|3 +$--popover-padding: 12px !default; +$--popover-padding-large: 18px 20px !default; +/// fontSize||Font|1 +$--popover-title-font-size: 16px !default; +/// color||Color|0 +$--popover-title-font-color: $--color-text-primary !default; + +/* Tooltip +-------------------------- */ +/// color|1|Color|0 +$--tooltip-fill: $--color-text-primary !default; +/// color|1|Color|0 +$--tooltip-color: $--color-white !default; +/// fontSize||Font|1 +$--tooltip-font-size: 12px !default; +/// color||Color|0 +$--tooltip-border-color: $--color-text-primary !default; +$--tooltip-arrow-size: 6px !default; +/// padding||Spacing|3 +$--tooltip-padding: 10px !default; + +/* Tag +-------------------------- */ +/// color||Color|0 +$--tag-info-color: $--color-info !default; +/// color||Color|0 +$--tag-primary-color: $--color-primary !default; +/// color||Color|0 +$--tag-success-color: $--color-success !default; +/// color||Color|0 +$--tag-warning-color: $--color-warning !default; +/// color||Color|0 +$--tag-danger-color: $--color-danger !default; +/// fontSize||Font|1 +$--tag-font-size: 12px !default; +$--tag-border-radius: 4px !default; +$--tag-padding: 0 10px !default; + +/* Tree +-------------------------- */ +/// color||Color|0 +$--tree-node-hover-background-color: $--background-color-base !default; +/// color||Color|0 +$--tree-font-color: $--color-text-regular !default; +/// color||Color|0 +$--tree-expand-icon-color: $--color-text-placeholder !default; + +/* Dropdown +-------------------------- */ +$--dropdown-menu-box-shadow: $--box-shadow-light !default; +$--dropdown-menuItem-hover-fill: $--color-primary !default; +$--dropdown-menuItem-hover-color: $--color-white !default; + +/* Badge +-------------------------- */ +/// color||Color|0 +$--badge-background-color: $--color-danger !default; +$--badge-radius: 10px !default; +/// fontSize||Font|1 +$--badge-font-size: 12px !default; +/// padding||Spacing|3 +$--badge-padding: 6px !default; +/// height||Other|4 +$--badge-size: 18px !default; + +/* Card +--------------------------*/ +/// color||Color|0 +$--card-border-color: $--border-color-lighter !default; +$--card-border-radius: 4px !default; +/// padding||Spacing|3 +$--card-padding: 20px !default; + +/* Slider +--------------------------*/ +/// color||Color|0 +$--slider-main-background-color: $--color-primary !default; +/// color||Color|0 +$--slider-runway-background-color: $--border-color-light !default; +$--slider-button-hover-color: mix($--color-primary, black, 97%) !default; +$--slider-stop-background-color: $--color-white !default; +$--slider-disable-color: $--color-text-placeholder !default; +$--slider-margin: 16px 0 !default; +$--slider-border-radius: 3px !default; +/// height|1|Other|4 +$--slider-height: 6px !default; +/// height||Other|4 +$--slider-button-size: 16px !default; +$--slider-button-wrapper-size: 36px !default; +$--slider-button-wrapper-offset: -15px !default; + +/* Steps +--------------------------*/ +$--steps-border-color: $--disabled-border-base !default; +$--steps-border-radius: 4px !default; +$--steps-padding: 20px !default; + +/* Menu +--------------------------*/ +/// fontSize||Font|1 +$--menu-item-font-size: $--font-size-base !default; +/// color||Color|0 +$--menu-item-font-color: $--color-white !default; +/// color||Color|0 +$--menu-background-color: $--color-menu-background !default; +$--menu-item-hover-fill: $--color-menu-item-active-background !default; + +/* Rate +--------------------------*/ +$--rate-height: 20px !default; +/// fontSize||Font|1 +$--rate-font-size: $--font-size-base !default; +/// height||Other|3 +$--rate-icon-size: 18px !default; +/// margin||Spacing|2 +$--rate-icon-margin: 6px !default; +$--rate-icon-color: $--color-text-placeholder !default; + +/* DatePicker +--------------------------*/ +$--datepicker-font-color: $--color-text-regular !default; +/// color|1|Color|0 +$--datepicker-off-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--datepicker-header-font-color: $--color-text-regular !default; +$--datepicker-icon-color: $--color-text-primary !default; +$--datepicker-border-color: $--disabled-border-base !default; +$--datepicker-inner-border-color: #e4e4e4 !default; +/// color||Color|0 +$--datepicker-inrange-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-inrange-hover-background-color: $--border-color-extra-light !default; +/// color||Color|0 +$--datepicker-active-color: $--color-primary !default; +/// color||Color|0 +$--datepicker-hover-font-color: $--color-primary !default; +$--datepicker-cell-hover-color: #fff !default; + +/* Loading +--------------------------*/ +/// height||Other|4 +$--loading-spinner-size: 42px !default; +/// height||Other|4 +$--loading-fullscreen-spinner-size: 50px !default; + +/* Scrollbar +--------------------------*/ +$--scrollbar-background-color: rgba($--color-text-secondary, .3) !default; +$--scrollbar-hover-background-color: rgba($--color-text-secondary, .5) !default; + +/* Carousel +--------------------------*/ +/// fontSize||Font|1 +$--carousel-arrow-font-size: 12px !default; +$--carousel-arrow-size: 36px !default; +$--carousel-arrow-background: rgba(31, 45, 61, 0.11) !default; +$--carousel-arrow-hover-background: rgba(31, 45, 61, 0.23) !default; +/// width||Other|4 +$--carousel-indicator-width: 30px !default; +/// height||Other|4 +$--carousel-indicator-height: 2px !default; +$--carousel-indicator-padding-horizontal: 4px !default; +$--carousel-indicator-padding-vertical: 12px !default; +$--carousel-indicator-out-color: $--border-color-hover !default; + +/* Collapse +--------------------------*/ +/// color||Color|0 +$--collapse-border-color: $--border-color-lighter !default; +/// height||Other|4 +$--collapse-header-height: 48px !default; +/// color||Color|0 +$--collapse-header-background-color: $--color-white !default; +/// color||Color|0 +$--collapse-header-font-color: $--color-text-primary !default; +/// fontSize||Font|1 +$--collapse-header-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-background-color: $--color-white !default; +/// fontSize||Font|1 +$--collapse-content-font-size: 13px !default; +/// color||Color|0 +$--collapse-content-font-color: $--color-text-primary !default; + +/* Transfer +--------------------------*/ +$--transfer-border-color: $--border-color-lighter !default; +$--transfer-border-radius: $--border-radius-base !default; +/// height||Other|4 +$--transfer-panel-width: 200px !default; +/// height||Other|4 +$--transfer-panel-header-height: 40px !default; +/// color||Color|0 +$--transfer-panel-header-background-color: $--background-color-base !default; +/// height||Other|4 +$--transfer-panel-footer-height: 40px !default; +/// height||Other|4 +$--transfer-panel-body-height: 246px !default; +/// height||Other|4 +$--transfer-item-height: 30px !default; +/// height||Other|4 +$--transfer-filter-height: 32px !default; + +/* Header + --------------------------*/ +$--header-padding: 0 20px !default; + +/* Footer +--------------------------*/ +$--footer-padding: 0 20px !default; + +/* Main +--------------------------*/ +$--main-padding: 20px !default; + +/* Timeline +--------------------------*/ +$--timeline-node-size-normal: 12px !default; +$--timeline-node-size-large: 14px !default; +$--timeline-node-color: $--border-color-light !default; + +/* Backtop +--------------------------*/ +/// color||Color|0 +$--backtop-background-color: $--color-white !default; +/// color||Color|0 +$--backtop-font-color: $--color-primary !default; +/// color||Color|0 +$--backtop-hover-background-color: $--border-color-extra-light !default; + +/* Link +--------------------------*/ +/// fontSize||Font|1 +$--link-font-size: $--font-size-base !default; +/// fontWeight||Font|1 +$--link-font-weight: $--font-weight-primary !default; +/// color||Color|0 +$--link-default-font-color: $--color-text-regular !default; +/// color||Color|0 +$--link-default-active-color: $--color-primary !default; +/// color||Color|0 +$--link-disabled-font-color: $--color-text-placeholder !default; +/// color||Color|0 +$--link-primary-font-color: $--color-primary !default; +/// color||Color|0 +$--link-success-font-color: $--color-success !default; +/// color||Color|0 +$--link-warning-font-color: $--color-warning !default; +/// color||Color|0 +$--link-danger-font-color: $--color-danger !default; +/// color||Color|0 +$--link-info-font-color: $--color-info !default; +/* Calendar +--------------------------*/ +/// border||Other|4 +$--calendar-border: $--table-border !default; +/// color||Other|4 +$--calendar-selected-background-color: #F2F8FE !default; +$--calendar-cell-width: 85px !default; + +/* Form +-------------------------- */ +/// fontSize||Font|1 +$--form-label-font-size: $--font-size-base !default; + +/* Avatar +--------------------------*/ +/// color||Color|0 +$--avatar-font-color: #fff !default; +/// color||Color|0 +$--avatar-background-color: #C0C4CC !default; +/// fontSize||Font Size|1 +$--avatar-text-font-size: 14px !default; +/// fontSize||Font Size|1 +$--avatar-icon-font-size: 18px !default; +/// borderRadius||Border|2 +$--avatar-border-radius: $--border-radius-base !default; +/// size|1|Avatar Size|3 +$--avatar-large-size: 40px !default; +/// size|1|Avatar Size|3 +$--avatar-medium-size: 36px !default; +/// size|1|Avatar Size|3 +$--avatar-small-size: 28px !default; + +/* Break-point +--------------------------*/ +$--sm: 768px !default; +$--md: 992px !default; +$--lg: 1200px !default; +$--xl: 1920px !default; + +$--breakpoints: ( + 'xs' : (max-width: $--sm - 1), + 'sm' : (min-width: $--sm), + 'md' : (min-width: $--md), + 'lg' : (min-width: $--lg), + 'xl' : (min-width: $--xl) +); + +$--breakpoints-spec: ( + 'xs-only' : (max-width: $--sm - 1), + 'sm-and-up' : (min-width: $--sm), + 'sm-only': "(min-width: #{$--sm}) and (max-width: #{$--md - 1})", + 'sm-and-down': (max-width: $--md - 1), + 'md-and-up' : (min-width: $--md), + 'md-only': "(min-width: #{$--md}) and (max-width: #{$--lg - 1})", + 'md-and-down': (max-width: $--lg - 1), + 'lg-and-up' : (min-width: $--lg), + 'lg-only': "(min-width: #{$--lg}) and (max-width: #{$--xl - 1})", + 'lg-and-down': (max-width: $--xl - 1), + 'xl-only' : (min-width: $--xl), +); diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/assets/img/default-header.jpg b/orange-demo-flowable/orange-demo-flowable-web/src/assets/img/default-header.jpg new file mode 100644 index 0000000000000000000000000000000000000000..222d18daf17197a6cfe48c403c79532ef0e97337 GIT binary patch literal 14882 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 literal 0 HcmV?d00001 diff --git a/orange-demo-flowable/orange-demo-flowable-web/src/assets/img/login.png b/orange-demo-flowable/orange-demo-flowable-web/src/assets/img/login.png new file mode 100644 index 0000000000000000000000000000000000000000..87130950f1e18b6c5fc4938ab356693fc847daba GIT binary patch literal 728962 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 z ztZC{i&*Clb-o+PwpKrK}%X4{bI62{MU;gskFe+Z&#t+}D=shj8OVe{5T6?@-!@+^K zJx`UbF!8OA<+FJ&|KQ*)t@6dj8s1ZzY(q3-Z6^6N=O_5KV_Es2XS0%_hY6mwdLN!r z&AB-TkxnJ!i|~`*s2;t?d-NMnfEmVkHwi7x`c}w|oPag|`aq)x^#q)6N_@zq+03vf zEo0b>x514`LnQGUqVqo6wlt)|YAS`DEC(+(vw>>1ymyU1#iw*5hF z%X*me8_Ht(7BI<^@-&%D_m;i}Z)iG8d(UBg_M4E%a3;o*!<_J)Rg`zH&JS;%J)g=1}t}?Y|enZ&bg77Ih=kge4oXR3z`gea#_;rmw|NUaweBuhZ_oN`4H^j z10&>+G9O^?{>k20VTq(Do?W2}p%E-pQPs#N3ByEesrXUoyx+;Wg2`xv=NeYCvM?G1 zMBTDAD1PAXMQGwq3_?PLL1y4#AmZJ#8T6@eTRg?EvVuqSErorF(!k-}w;4VkTMdaK zht{WD1*KqBc=gGCNrRrt2*~eQ4DG+4pT{UaJv@w{;LthYpCqTS;|rs-ZCKhU;f)*k z_-%kjar0g{SLurL&f#C<8BM=VOSS`(_=Jw)TV4f+Z^nH7PvfD?Gz{y`?aU&?u$kF! z`!ZFSY*~v{oHPc7pK>t$^zcLWD*lkl@-hnhE;9U**@LqzVHmi{2hPk&D9e1_EAI^Q zC~y>#VeA7+4$j@4W#ZshVWWsS_>r3?&LbnRt5Z@uQ;}1a29dWi2z993jJ!s6X8DzS zW?Z~miO?ufEazM_9(2^9yE^$5N0%m;Jd$L|KA{swMk>;hE1b|WqJ&wAFbGfr;K^~p zD()>!e1=TRRK=Wf4y+|h1lLn#!TRxZ=bQ*L?1Af)QU{z!YAX=kfzqT4DT|S=DZBI#Sw0EPwv9cVRW03&*dl zJeN-SFCXI2_0I2m;o}weBe(=LvKD>K|TYq@n7UtQv9ZsDM zN&o0#ll3`*@STZ8wK$RwE;y%Bq8eS;>KZ!Y)7~xKa3v4ql$eMItZ#!Y`z^8AYGqJ! zJCS&u6v3m?JMfHegC(mWpD(kGIG+XZRd0sq^;V|nqJG@(DE5LnHoG_UbzAw^MPrNh z?d*byWGDaf3kByXDQh4u4eX?clO+!q`5Gz#O8ydXr6>kjS$W8@VN*{pG z@Q-7ZPB<9`=jY^m3~fpojz{KED62E%oPZgP&j${J!oV=nn#!J2`}r!m0beSB+$N0* zbQ-1mDV62-`NI0YXEo%t{gBQ^Sk}lO<}Uq+K+#X=x}hs8BW5tn_@88E<}`A0yck;{mFDs4LJ@Mo#Q18)-OsGV!>o#2*!OB>D}XxPIcqZ`{iPoh7XGSB(_n^I1F2y$^pvCRZ*a)} z%=&JTBcp^VF0RH6Sg!uy*kmA$_u}LCy{9Mb1&@AYZgb`Gw@s`dHNZBTNZA6)X4hoEL&C|6r-7`@H{e276jU)7EQ>aetKl;I4gnfN=o z0O-`0--FX2VqG$mm5AhtuFBIobDTaj@8qj)yFJpm2LllH0ONSv);s5cZS3cj}M>nrF8ryBUiEIl%4+DN{9Yg9>!?^NKV2pP9mS^|5+w@AAS4H;W#&Bon#fl&1T2hU2{9TRF)C9WYP)2 zH7PFjD#s~<$V?fsG-Ri)@^iA$$7CMtk(+ zNh(!zRT)M$ckVc_u70mol!Q+Cj$Vh(vg_Fz`XKdxO-PRp1lG4oT#BSTzsps`&Ml2y z6P$M7d_2!8P54Ry#(rNbM+T_sg_WAKoaeU6M^}$-{nJ1GGNZT%c?1+DNpl+VsnjEz zX!{b}FdI`AGaTh7eu85-$MTwjjh5w6Wr^__g)>^b7h}}cEMG2nrsFJ`vrWLE@CW(b zk5T$)o@3ln+Tgn%gH;-%yxGbUMY9^R3Mv&Ocx4P949saj@RS0K>dc6X5gGR9r{i^R zbW}RrM~U-34TeIG0O9)(_$#Y8fjGtQEKwQJo5hD4TnysmO(jf{DX2CywqUg(sLwu$A}ZKYXOP3d-iZ56L$?|Q?;1Vj(iM|6n4ypm#VCqCVjZPaw+Wx+){r8TnFSC1 zx}lwXfHuhRKB?)f#xj-oD&=HguFm>;?li`sK*uzs^^22i;9)2=o_?q=(`f<>nZA34 zW6@p%qdtrK+DX^6e6W6SaDC^Omunsq#?=@uY~hO6`|!HuMYu3OWhy^S+dRVCFn+`N zT+b^73+e23J8DTgiJOShKpG1Qvx=4E6MaJVanO?=mSAiR0i zkxDaiiJXe3c*)%Fnz!(xE^~$Db71`7LZ2(Gh7a9TI`x(V_gg%xeoD8OPhs%oSzVrk z?V&ee8@@rBKj?uI=b6)Cukgj+lFvj9Y~lHST;<>yJXbjH<%eI_u*#tC;?ZxOCp={> ztT3MYyIK9Yfhi4TQatz}bM=fX|M18~VZ{l%_LI&#+WRst-_0Kw@!a%%p*8xl;VM3G z#V>97fFC?pp7%Jxg)__z-0-V^O8APqksG|y3MZdB@6|iceryMNR{E9k@UrnbaCzpM zC;q@B48MDtaG)C4zs@O{i#)eo5&zsj|- zS6LOYGBO9u(^r3tO%l|Z#dl?Y@|@KZw`ZE+$D_W^YR9LMeE>$biOWST7jNF@TG(~I zz;`^ze2x>a^^%sYaur8cxVyml;0N_28XG^|* zNV$CbZ4O-LjL1n0>j-D^^&z*ay6mPCVG^2%=A=QNfp1dvBsXJy^ZOqU_Z~kuoPC>* zB0dOxD-luA5$lwbluM^ZZ-N6a^r5;jWf#L$onSv-#m=)G>qBInz`3$FBcWLd@x}Nr znVkKY^Dwi0jow5S>?dvT!{q6k+}3pxo??c_c3?-r9SNpT404xELZ8|xYumX)pJRPxgY-(-0$t0L18htRIt(5<3x+(&dY-qka`s2rO*IINvXW*7t3iaWG}CBHuYBVBF3t?b zl2#ZU9sN>{`JrJ%3}2#yhoLkIc%v&`A)olwIMO)R0iM6j3TSXr3oO+k0g?`Y3Muc~@?HKdx8xmd4~W;f)8=bnp(ngcVNw z{uwRs4eR?g-^pvkR@uPt+cHF>zZILj2QSB8#(&BuxWM77@eKpJ;Fh6;r~XP8Y~dRw zUBmYI@XVF>`e2n69>{j&lQ8hpj%~6KF3p~%usU&mb>dn!!X_@@?V!A?-$O4tqWrJZ zZ)i(Xc=KNRe05^!^J?eN8GTIM)80rwd5YdQ9b7{@dRv^*fep~4_YNK$x$NCu&ce$h ze{?=jhnBoFaJldl2Tm6<_@Em;m_lA`goYK{mo_EiqZyV3jG)y|bu@e$s8IwzZ1`d4r z5HD?A-vt#Hp92N<24=@c;=t{37q75=ntixu@nkhOALSiy&OtcfY-ZakzDs%B(x`u< zW2v|+FRWoTAl}r3wDtHvk4>O|wLf3})lG1Lo`2xXRA1TdlYh2p_26=H6TBhA{z>AQ z9NB1ocHkmBm?8J2?D=L`X3Cwfm=%Rh4oNg<^ke$?sV`uXE==ZKdwnk*lUeHk+nEmwA?+=f^%{M+`th;j7K+rtlk_~YT^!C7|JDCgK$8R)sO%0x5$pi68C zbm@gHSm3OztZiD0f48chKg&1h{{A#OH69(l|KrbxTgm6A>{j^Vf`SZ~-fZz#S%nJP zWG55mS&2H&Dw#=C0}%OSPn%#pI{d>w{xVy57&TLj3fMEBtcW@PQqapq@U!ZHDFA6S zV+iw;lNfHP95Iv>^!*Uaw!Im2I0){n!rW{X|11h&HRN85P&Y8G^B_xMX0ITjq%b0m z@Udu9s8taXOi;lyBlN)Hk-Á_Jaf#O*Lgh3^=H*S`Lrt`)2ieuQ1ku9IWYsJJD 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%0DCDks3JEJGjr!X~}X3Hl6!4N&KDa5g@R2P@40 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

Wml6w{ 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�p0AVGf=jE9Gr=!U+Hmvl4Huh7U>=Ipe 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