From b3a2aa3c99dea2387742d03bdee1bea8f37a257f Mon Sep 17 00:00:00 2001 From: zwt13703 Date: Sat, 21 Mar 2026 22:01:03 +0800 Subject: [PATCH] default --- .gitignore | 12 + README.md | 189 + docs/51dx_school.json | 211 + docs/art_school_api_for_frontend.md | 163 + docs/art_school_db_adjustments_2026_03_12.md | 169 + docs/art_school_jsonb_api_spec.md | 282 ++ docs/art_sports_volunteer_pgsql.sql | 1567 +++++++ docs/score_new_table.sql | 145 + docs/score_newtable_task.md | 93 + pom.xml | 505 +++ ruoyi-admin/Dockerfile | 31 + ruoyi-admin/pom.xml | 165 + .../java/org/dromara/DromaraApplication.java | 23 + .../dromara/DromaraServletInitializer.java | 18 + .../web/controller/AuthController.java | 243 ++ .../web/controller/CaptchaController.java | 160 + .../web/controller/IndexController.java | 28 + .../org/dromara/web/domain/vo/CaptchaVo.java | 25 + .../dromara/web/domain/vo/LoginTenantVo.java | 25 + .../org/dromara/web/domain/vo/LoginVo.java | 54 + .../dromara/web/domain/vo/TenantListVo.java | 31 + .../web/listener/UserActionListener.java | 163 + .../dromara/web/service/IAuthStrategy.java | 46 + .../dromara/web/service/SysLoginService.java | 251 ++ .../web/service/SysRegisterService.java | 115 + .../web/service/impl/EmailAuthStrategy.java | 102 + .../service/impl/PasswordAuthStrategy.java | 123 + .../web/service/impl/SmsAuthStrategy.java | 102 + .../web/service/impl/SocialAuthStrategy.java | 119 + .../web/service/impl/XcxAuthStrategy.java | 111 + .../src/main/resources/application-dev.yml | 270 ++ .../src/main/resources/application-prod.yml | 272 ++ .../src/main/resources/application-test.yml | 270 ++ .../src/main/resources/application.yml | 266 ++ .../resources/art-school-import-export-api.md | 197 + .../resources/art-school-tag-major-tag-api.md | 117 + ruoyi-admin/src/main/resources/banner.txt | 8 + .../main/resources/i18n/messages.properties | 62 + .../resources/i18n/messages_en_US.properties | 62 + .../resources/i18n/messages_zh_CN.properties | 62 + .../src/main/resources/ip2region_v4.xdb | Bin 0 -> 11042429 bytes .../src/main/resources/logback-plus.xml | 129 + .../src/main/resources/school_generate.md | 249 ++ .../java/org/dromara/test/AssertUnitTest.java | 45 + .../java/org/dromara/test/DemoUnitTest.java | 70 + .../java/org/dromara/test/ParamUnitTest.java | 72 + .../java/org/dromara/test/TagUnitTest.java | 54 + ruoyi-common/pom.xml | 46 + ruoyi-common/ruoyi-common-bom/pom.xml | 185 + ruoyi-common/ruoyi-common-core/pom.xml | 99 + .../common/core/config/ApplicationConfig.java | 17 + .../common/core/config/ThreadPoolConfig.java | 109 + .../common/core/config/ValidatorConfig.java | 41 + .../common/core/constant/CacheConstants.java | 30 + .../common/core/constant/CacheNames.java | 89 + .../common/core/constant/Constants.java | 81 + .../common/core/constant/GlobalConstants.java | 34 + .../common/core/constant/HttpStatus.java | 93 + .../common/core/constant/RegexConstants.java | 59 + .../common/core/constant/SystemConstants.java | 91 + .../common/core/constant/TenantConstants.java | 35 + .../org/dromara/common/core/domain/R.java | 110 + .../core/domain/dto/CompleteTaskDTO.java | 77 + .../common/core/domain/dto/DeptDTO.java | 36 + .../common/core/domain/dto/DictDataDTO.java | 41 + .../common/core/domain/dto/DictTypeDTO.java | 41 + .../common/core/domain/dto/FlowCopyDTO.java | 30 + .../domain/dto/FlowInstanceBizExtDTO.java | 45 + .../common/core/domain/dto/OssDTO.java | 46 + .../common/core/domain/dto/PostDTO.java | 46 + .../common/core/domain/dto/RoleDTO.java | 42 + .../core/domain/dto/StartProcessDTO.java | 63 + .../domain/dto/StartProcessReturnDTO.java | 30 + .../core/domain/dto/TaskAssigneeDTO.java | 101 + .../common/core/domain/dto/UserDTO.java | 73 + .../common/core/domain/dto/UserOnlineDTO.java | 72 + .../core/domain/event/ProcessDeleteEvent.java | 34 + .../core/domain/event/ProcessEvent.java | 70 + .../core/domain/event/ProcessTaskEvent.java | 70 + .../core/domain/model/EmailLoginBody.java | 31 + .../common/core/domain/model/LoginBody.java | 48 + .../common/core/domain/model/LoginUser.java | 148 + .../core/domain/model/PasswordLoginBody.java | 32 + .../core/domain/model/RegisterBody.java | 37 + .../core/domain/model/SmsLoginBody.java | 29 + .../core/domain/model/SocialLoginBody.java | 35 + .../core/domain/model/TaskAssigneeBody.java | 56 + .../core/domain/model/XcxLoginBody.java | 28 + .../core/domain/model/XcxLoginUser.java | 27 + .../common/core/enums/BusinessStatusEnum.java | 215 + .../dromara/common/core/enums/DeviceType.java | 39 + .../common/core/enums/FormatsType.java | 146 + .../dromara/common/core/enums/LoginType.java | 44 + .../dromara/common/core/enums/UserStatus.java | 30 + .../dromara/common/core/enums/UserType.java | 39 + .../core/exception/ServiceException.java | 67 + .../common/core/exception/SseException.java | 62 + .../core/exception/base/BaseException.java | 74 + .../core/exception/file/FileException.java | 21 + .../FileNameLengthLimitExceededException.java | 18 + .../file/FileSizeLimitExceededException.java | 18 + .../core/exception/user/CaptchaException.java | 18 + .../user/CaptchaExpireException.java | 18 + .../core/exception/user/UserException.java | 20 + .../core/factory/RegexPatternPoolFactory.java | 52 + .../factory/YmlPropertySourceFactory.java | 31 + .../common/core/service/ConfigService.java | 100 + .../common/core/service/DeptService.java | 46 + .../common/core/service/DictService.java | 87 + .../common/core/service/OssService.java | 29 + .../core/service/PermissionService.java | 28 + .../common/core/service/PostService.java | 21 + .../common/core/service/RoleService.java | 21 + .../core/service/TaskAssigneeService.java | 45 + .../common/core/service/UserService.java | 103 + .../common/core/service/WorkflowService.java | 105 + .../dromara/common/core/utils/DateUtils.java | 378 ++ .../common/core/utils/DesensitizedUtils.java | 87 + .../common/core/utils/MapstructUtils.java | 93 + .../common/core/utils/MessageUtils.java | 33 + .../dromara/common/core/utils/NetUtils.java | 84 + .../common/core/utils/ObjectUtils.java | 60 + .../common/core/utils/ServletUtils.java | 289 ++ .../common/core/utils/SpringUtils.java | 67 + .../common/core/utils/StreamUtils.java | 328 ++ .../common/core/utils/StringUtils.java | 384 ++ .../common/core/utils/TreeBuildUtils.java | 123 + .../common/core/utils/ValidatorUtils.java | 35 + .../common/core/utils/file/FileUtils.java | 43 + .../common/core/utils/file/MimeTypeUtils.java | 40 + .../common/core/utils/ip/AddressUtils.java | 43 + .../common/core/utils/ip/RegionUtils.java | 155 + .../core/utils/reflect/ReflectUtils.java | 56 + .../common/core/utils/regex/RegexUtils.java | 31 + .../core/utils/regex/RegexValidator.java | 105 + .../common/core/utils/sql/SqlUtil.java | 56 + .../common/core/validate/AddGroup.java | 9 + .../common/core/validate/EditGroup.java | 9 + .../common/core/validate/QueryGroup.java | 9 + .../core/validate/dicts/DictPattern.java | 40 + .../validate/dicts/DictPatternValidator.java | 55 + .../core/validate/enumd/EnumPattern.java | 48 + .../validate/enumd/EnumPatternValidator.java | 37 + .../java/org/dromara/common/core/xss/Xss.java | 26 + .../dromara/common/core/xss/XssValidator.java | 21 + ...ot.autoconfigure.AutoConfiguration.imports | 4 + ruoyi-common/ruoyi-common-doc/pom.xml | 41 + .../common/doc/config/SpringDocConfig.java | 127 + .../properties/SpringDocProperties.java | 94 + .../common/doc/handler/OpenApiHandler.java | 253 ++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-encrypt/pom.xml | 54 + .../common/encrypt/annotation/ApiEncrypt.java | 20 + .../encrypt/annotation/EncryptField.java | 44 + .../config/ApiDecryptAutoConfiguration.java | 34 + .../config/EncryptorAutoConfiguration.java | 49 + .../common/encrypt/core/EncryptContext.java | 41 + .../common/encrypt/core/EncryptorManager.java | 168 + .../common/encrypt/core/IEncryptor.java | 35 + .../core/encryptor/AbstractEncryptor.java | 18 + .../encrypt/core/encryptor/AesEncryptor.java | 55 + .../core/encryptor/Base64Encryptor.java | 48 + .../encrypt/core/encryptor/RsaEncryptor.java | 62 + .../encrypt/core/encryptor/Sm2Encryptor.java | 61 + .../encrypt/core/encryptor/Sm4Encryptor.java | 55 + .../common/encrypt/enumd/AlgorithmType.java | 48 + .../common/encrypt/enumd/EncodeType.java | 26 + .../common/encrypt/filter/CryptoFilter.java | 110 + .../filter/DecryptRequestBodyWrapper.java | 94 + .../filter/EncryptResponseBodyWrapper.java | 123 + .../MybatisDecryptInterceptor.java | 132 + .../MybatisEncryptInterceptor.java | 124 + .../properties/ApiDecryptProperties.java | 34 + .../properties/EncryptorProperties.java | 48 + .../common/encrypt/utils/EncryptUtils.java | 313 ++ ...ot.autoconfigure.AutoConfiguration.imports | 3 + ruoyi-common/ruoyi-common-excel/pom.xml | 30 + .../common/excel/annotation/CellMerge.java | 29 + .../excel/annotation/ExcelDictFormat.java | 32 + .../excel/annotation/ExcelDynamicOptions.java | 23 + .../excel/annotation/ExcelEnumFormat.java | 30 + .../excel/annotation/ExcelNotation.java | 20 + .../excel/annotation/ExcelRequired.java | 22 + .../excel/convert/ExcelBigNumberConvert.java | 52 + .../excel/convert/ExcelDictConvert.java | 73 + .../excel/convert/ExcelEnumConvert.java | 87 + .../common/excel/core/CellMergeHandler.java | 217 + .../common/excel/core/CellMergeStrategy.java | 65 + .../excel/core/DefaultExcelListener.java | 104 + .../common/excel/core/DefaultExcelResult.java | 73 + .../common/excel/core/DropDownOptions.java | 150 + .../common/excel/core/ExcelDownHandler.java | 412 ++ .../common/excel/core/ExcelListener.java | 14 + .../excel/core/ExcelOptionsProvider.java | 19 + .../common/excel/core/ExcelResult.java | 26 + .../excel/handler/DataWriteHandler.java | 123 + .../dromara/common/excel/utils/ExcelUtil.java | 479 +++ .../excel/utils/ExcelWriterWrapper.java | 127 + ruoyi-common/ruoyi-common-idempotent/pom.xml | 41 + .../idempotent/annotation/RepeatSubmit.java | 29 + .../aspectj/RepeatSubmitAspect.java | 146 + .../idempotent/config/IdempotentConfig.java | 21 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-job/pom.xml | 46 + .../common/job/config/SnailJobConfig.java | 37 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-json/pom.xml | 37 + .../common/json/config/JacksonConfig.java | 55 + .../json/handler/BigNumberSerializer.java | 42 + .../json/handler/CustomDateDeserializer.java | 37 + .../dromara/common/json/utils/JsonUtils.java | 225 + .../common/json/validate/JsonPattern.java | 33 + .../json/validate/JsonPatternValidator.java | 51 + .../common/json/validate/JsonType.java | 30 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-log/pom.xml | 32 + .../dromara/common/log/annotation/Log.java | 48 + .../dromara/common/log/aspect/LogAspect.java | 226 + .../common/log/enums/BusinessStatus.java | 18 + .../common/log/enums/BusinessType.java | 58 + .../common/log/enums/OperatorType.java | 23 + .../common/log/event/LogininforEvent.java | 52 + .../common/log/event/OperLogEvent.java | 115 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-mail/pom.xml | 34 + .../common/mail/config/MailConfig.java | 37 + .../config/properties/MailProperties.java | 75 + .../dromara/common/mail/utils/MailUtils.java | 469 +++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-mybatis/pom.xml | 52 + .../common/mybatis/annotation/DataColumn.java | 40 + .../mybatis/annotation/DataPermission.java | 30 + .../mybatis/aspect/DataPermissionAdvice.java | 54 + .../aspect/DataPermissionPointcut.java | 39 + .../aspect/DataPermissionPointcutAdvisor.java | 33 + .../mybatis/config/MybatisPlusConfig.java | 142 + .../mybatis/core/domain/BaseEntity.java | 70 + .../mybatis/core/mapper/BaseMapperPlus.java | 334 ++ .../common/mybatis/core/page/PageQuery.java | 127 + .../mybatis/core/page/TableDataInfo.java | 107 + .../common/mybatis/enums/DataBaseType.java | 87 + .../common/mybatis/enums/DataScopeType.java | 87 + .../handler/InjectionMetaObjectHandler.java | 113 + .../handler/MybatisExceptionHandler.java | 89 + .../handler/PlusDataPermissionHandler.java | 261 ++ .../handler/PlusPostInitTableInfoHandler.java | 27 + .../common/mybatis/helper/DataBaseHelper.java | 82 + .../mybatis/helper/DataPermissionHelper.java | 176 + .../PlusDataPermissionInterceptor.java | 172 + .../common/mybatis/utils/IdGeneratorUtil.java | 129 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../src/main/resources/common-mybatis.yml | 33 + .../src/main/resources/spy.properties | 20 + ruoyi-common/ruoyi-common-oss/pom.xml | 66 + .../common/oss/constant/OssConstant.java | 40 + .../dromara/common/oss/core/OssClient.java | 564 +++ .../common/oss/core/WriteOutSubscriber.java | 15 + .../common/oss/entity/UploadResult.java | 30 + .../common/oss/enums/AccessPolicyType.java | 56 + .../common/oss/exception/OssException.java | 19 + .../common/oss/factory/OssFactory.java | 73 + .../common/oss/properties/OssProperties.java | 63 + ruoyi-common/ruoyi-common-ratelimiter/pom.xml | 30 + .../ratelimiter/annotation/RateLimiter.java | 47 + .../aspectj/RateLimiterAspect.java | 112 + .../ratelimiter/config/RateLimiterConfig.java | 20 + .../common/ratelimiter/enums/LimitType.java | 24 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../src/main/resources/spel-extension.json | 7 + ruoyi-common/ruoyi-common-redis/pom.xml | 55 + .../common/redis/config/CacheConfig.java | 45 + .../common/redis/config/RedisConfig.java | 160 + .../config/properties/RedissonProperties.java | 135 + .../redis/handler/KeyPrefixHandler.java | 50 + .../redis/handler/RedisExceptionHandler.java | 30 + .../redis/manager/CaffeineCacheDecorator.java | 97 + .../redis/manager/PlusSpringCacheManager.java | 202 + .../common/redis/utils/CacheUtils.java | 61 + .../common/redis/utils/QueueUtils.java | 239 ++ .../common/redis/utils/RedisUtils.java | 581 +++ .../common/redis/utils/SequenceUtils.java | 351 ++ ...ot.autoconfigure.AutoConfiguration.imports | 2 + ruoyi-common/ruoyi-common-satoken/pom.xml | 46 + .../common/satoken/config/SaTokenConfig.java | 54 + .../satoken/core/dao/PlusSaTokenDao.java | 192 + .../core/service/SaPermissionImpl.java | 86 + .../handler/SaTokenExceptionHandler.java | 52 + .../common/satoken/utils/LoginHelper.java | 217 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + .../src/main/resources/common-satoken.yml | 13 + ruoyi-common/ruoyi-common-security/pom.xml | 26 + .../security/config/SecurityConfig.java | 108 + .../config/properties/SecurityProperties.java | 21 + .../security/handler/AllUrlHandler.java | 39 + ...ot.autoconfigure.AutoConfiguration.imports | 2 + ruoyi-common/ruoyi-common-sensitive/pom.xml | 25 + .../sensitive/annotation/Sensitive.java | 34 + .../sensitive/core/SensitiveService.java | 18 + .../sensitive/core/SensitiveStrategy.java | 113 + .../sensitive/handler/SensitiveHandler.java | 58 + ruoyi-common/ruoyi-common-sms/pom.xml | 33 + .../sms/config/SmsAutoConfiguration.java | 33 + .../common/sms/core/dao/PlusSmsDao.java | 72 + .../sms/handler/SmsExceptionHandler.java | 30 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-social/pom.xml | 34 + .../AbstractAuthWeChatEnterpriseRequest.java | 154 + .../oauth/request/AuthDingTalkV2Request.java | 109 + .../config/SocialAutoConfiguration.java | 23 + .../SocialLoginConfigProperties.java | 80 + .../config/properties/SocialProperties.java | 24 + .../common/social/gitea/AuthGiteaRequest.java | 92 + .../common/social/gitea/AuthGiteaSource.java | 50 + .../social/maxkey/AuthMaxKeyRequest.java | 80 + .../social/maxkey/AuthMaxKeySource.java | 52 + .../social/topiam/AuthTopIamRequest.java | 113 + .../social/topiam/AuthTopIamSource.java | 51 + .../social/utils/AuthRedisStateCache.java | 61 + .../common/social/utils/SocialUtils.java | 75 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-sse/pom.xml | 36 + .../sse/config/SseAutoConfiguration.java | 36 + .../common/sse/config/SseProperties.java | 21 + .../common/sse/controller/SseController.java | 88 + .../common/sse/core/SseEmitterManager.java | 230 ++ .../dromara/common/sse/dto/SseMessageDto.java | 29 + .../common/sse/listener/SseTopicListener.java | 48 + .../common/sse/utils/SseMessageUtils.java | 84 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-tenant/pom.xml | 32 + .../common/tenant/config/TenantConfig.java | 86 + .../common/tenant/core/TenantEntity.java | 21 + .../common/tenant/core/TenantSaTokenDao.java | 158 + .../tenant/exception/TenantException.java | 20 + .../tenant/handle/PlusTenantLineHandler.java | 56 + .../tenant/handle/TenantKeyPrefixHandler.java | 83 + .../common/tenant/helper/TenantHelper.java | 231 ++ .../manager/TenantSpringCacheManager.java | 41 + .../tenant/properties/TenantProperties.java | 27 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-common/ruoyi-common-translation/pom.xml | 27 + .../translation/annotation/Translation.java | 39 + .../annotation/TranslationType.java | 23 + .../translation/config/TranslationConfig.java | 50 + .../translation/constant/TransConstant.java | 35 + .../core/TranslationInterface.java | 20 + .../TranslationBeanSerializerModifier.java | 29 + .../core/handler/TranslationHandler.java | 71 + .../core/impl/DeptNameTranslationImpl.java | 29 + .../core/impl/DictTypeTranslationImpl.java | 28 + .../core/impl/NicknameTranslationImpl.java | 29 + .../core/impl/OssUrlTranslationImpl.java | 29 + .../core/impl/UserNameTranslationImpl.java | 25 + ...ot.autoconfigure.AutoConfiguration.imports | 6 + ruoyi-common/ruoyi-common-web/pom.xml | 57 + .../common/web/config/CaptchaConfig.java | 16 + .../common/web/config/FilterConfig.java | 41 + .../dromara/common/web/config/I18nConfig.java | 22 + .../common/web/config/ResourcesConfig.java | 79 + .../common/web/config/UndertowConfig.java | 63 + .../config/properties/CaptchaProperties.java | 31 + .../web/config/properties/XssProperties.java | 28 + .../common/web/core/BaseController.java | 40 + .../common/web/core/I18nLocaleResolver.java | 31 + .../common/web/core/WaveAndCircleCaptcha.java | 197 + .../common/web/filter/RepeatableFilter.java | 40 + .../web/filter/RepeatedlyRequestWrapper.java | 68 + .../dromara/common/web/filter/XssFilter.java | 59 + .../filter/XssHttpServletRequestWrapper.java | 134 + .../web/handler/GlobalExceptionHandler.java | 235 ++ .../PlusWebInvokeTimeInterceptor.java | 127 + ...ot.autoconfigure.AutoConfiguration.imports | 5 + ruoyi-common/ruoyi-common-websocket/pom.xml | 46 + .../websocket/config/WebSocketConfig.java | 63 + .../properties/WebSocketProperties.java | 26 + .../constant/WebSocketConstants.java | 29 + .../websocket/dto/WebSocketMessageDto.java | 29 + .../handler/PlusWebSocketHandler.java | 123 + .../holder/WebSocketSessionHolder.java | 74 + .../interceptor/PlusWebSocketInterceptor.java | 75 + .../listener/WebSocketTopicListener.java | 50 + .../websocket/utils/WebSocketUtils.java | 127 + ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-extend/pom.xml | 19 + ruoyi-extend/ruoyi-monitor-admin/Dockerfile | 22 + ruoyi-extend/ruoyi-monitor-admin/pom.xml | 73 + .../admin/MonitorAdminApplication.java | 21 + .../monitor/admin/config/SecurityConfig.java | 54 + .../admin/notifier/CustomNotifier.java | 55 + .../src/main/resources/application.yml | 51 + .../src/main/resources/banner.txt | 8 + .../src/main/resources/logback-plus.xml | 34 + ruoyi-extend/ruoyi-snailjob-server/Dockerfile | 23 + ruoyi-extend/ruoyi-snailjob-server/pom.xml | 58 + .../starter/filter/ActuatorAuthFilter.java | 64 + .../server/starter/filter/SecurityConfig.java | 29 + .../snailjob/SnailJobServerApplication.java | 19 + .../src/main/resources/application-dev.yml | 51 + .../src/main/resources/application-prod.yml | 51 + .../src/main/resources/application.yml | 39 + .../src/main/resources/banner.txt | 11 + .../src/main/resources/logback-plus.xml | 93 + ruoyi-modules/pom.xml | 28 + ruoyi-modules/ruoyi-art/pom.xml | 113 + .../ArtHistoryScoreControlLineController.java | 105 + .../art/controller/ArtMajorController.java | 105 + .../controller/ArtSchoolCampusController.java | 105 + .../ArtSchoolCollegeController.java | 105 + .../art/controller/ArtSchoolController.java | 137 + .../controller/ArtSchoolDetailController.java | 604 +++ .../controller/ArtSchoolDormController.java | 105 + .../ArtSchoolEnrollPlanController.java | 105 + .../controller/ArtSchoolMajorController.java | 105 + .../ArtSchoolMajorTagController.java | 105 + .../controller/ArtSchoolMediaController.java | 105 + .../controller/ArtSchoolNameController.java | 105 + .../ArtSchoolRecruitMajorController.java | 105 + ...rtSchoolRecruitMajorHistoryController.java | 105 + .../controller/ArtSchoolTagController.java | 105 + .../art/controller/ArtTestController.java | 747 ++++ .../domain/ArtHistoryScoreControlLine.java | 92 + .../java/org/dromara/art/domain/ArtMajor.java | 92 + .../org/dromara/art/domain/ArtSchool.java | 92 + .../dromara/art/domain/ArtSchoolCampus.java | 77 + .../dromara/art/domain/ArtSchoolCollege.java | 67 + .../dromara/art/domain/ArtSchoolDetail.java | 384 ++ .../org/dromara/art/domain/ArtSchoolDorm.java | 72 + .../art/domain/ArtSchoolEnrollCode.java | 36 + .../art/domain/ArtSchoolEnrollPlan.java | 82 + .../dromara/art/domain/ArtSchoolMajor.java | 92 + .../dromara/art/domain/ArtSchoolMajorTag.java | 52 + .../dromara/art/domain/ArtSchoolMedia.java | 72 + .../org/dromara/art/domain/ArtSchoolName.java | 57 + .../art/domain/ArtSchoolRecruitMajor.java | 177 + .../domain/ArtSchoolRecruitMajorHistory.java | 167 + .../org/dromara/art/domain/ArtSchoolTag.java | 52 + .../bo/ArtHistoryScoreControlLineBo.java | 91 + .../org/dromara/art/domain/bo/ArtMajorBo.java | 87 + .../dromara/art/domain/bo/ArtSchoolBo.java | 87 + .../art/domain/bo/ArtSchoolCampusBo.java | 72 + .../art/domain/bo/ArtSchoolCollegeBo.java | 67 + .../art/domain/bo/ArtSchoolDetailBo.java | 361 ++ .../art/domain/bo/ArtSchoolDormBo.java | 66 + .../art/domain/bo/ArtSchoolEnrollCodeBo.java | 41 + .../art/domain/bo/ArtSchoolEnrollPlanBo.java | 80 + .../art/domain/bo/ArtSchoolMajorBo.java | 99 + .../art/domain/bo/ArtSchoolMajorTagBo.java | 47 + .../art/domain/bo/ArtSchoolMediaBo.java | 69 + .../art/domain/bo/ArtSchoolNameBo.java | 53 + .../domain/bo/ArtSchoolRecruitMajorBo.java | 178 + .../bo/ArtSchoolRecruitMajorHistoryBo.java | 167 + .../art/domain/bo/ArtSchoolSubmitBo.java | 41 + .../dromara/art/domain/bo/ArtSchoolTagBo.java | 47 + .../excel/ArtSchoolCampusSheetExcel.java | 43 + .../excel/ArtSchoolCollegeSheetExcel.java | 37 + .../excel/ArtSchoolDetailSheetExcel.java | 102 + .../excel/ArtSchoolEnrollPlanSheetExcel.java | 46 + .../excel/ArtSchoolMajorSheetExcel.java | 58 + .../art/domain/excel/ArtSchoolSheetExcel.java | 49 + .../ArtSchoolTemplateGuideSheetExcel.java | 32 + .../vo/ArtHistoryScoreControlLineVo.java | 104 + .../org/dromara/art/domain/vo/ArtMajorVo.java | 104 + .../art/domain/vo/ArtSchoolCampusVo.java | 86 + .../art/domain/vo/ArtSchoolCollegeVo.java | 74 + .../art/domain/vo/ArtSchoolDetailVo.java | 432 ++ .../art/domain/vo/ArtSchoolDormVo.java | 80 + .../art/domain/vo/ArtSchoolEnrollCodeVo.java | 43 + .../art/domain/vo/ArtSchoolEnrollPlanVo.java | 92 + .../domain/vo/ArtSchoolImportDetailVo.java | 36 + .../domain/vo/ArtSchoolImportPreviewVo.java | 37 + .../domain/vo/ArtSchoolImportResultVo.java | 42 + .../vo/ArtSchoolJsonImportPreviewVo.java | 98 + .../art/domain/vo/ArtSchoolMajorTagVo.java | 56 + .../art/domain/vo/ArtSchoolMajorVo.java | 128 + .../art/domain/vo/ArtSchoolMediaVo.java | 80 + .../art/domain/vo/ArtSchoolNameVo.java | 63 + .../vo/ArtSchoolRecruitMajorHistoryVo.java | 194 + .../domain/vo/ArtSchoolRecruitMajorVo.java | 206 + .../domain/vo/ArtSchoolSubmitResultVo.java | 49 + .../dromara/art/domain/vo/ArtSchoolTagVo.java | 57 + .../dromara/art/domain/vo/ArtSchoolVo.java | 116 + .../dromara/art/handler/JsonbTypeHandler.java | 39 + .../ArtHistoryScoreControlLineMapper.java | 15 + .../dromara/art/mapper/ArtMajorMapper.java | 15 + .../art/mapper/ArtSchoolCampusMapper.java | 19 + .../art/mapper/ArtSchoolCollegeMapper.java | 19 + .../art/mapper/ArtSchoolDetailMapper.java | 19 + .../art/mapper/ArtSchoolDormMapper.java | 15 + .../art/mapper/ArtSchoolEnrollCodeMapper.java | 19 + .../art/mapper/ArtSchoolEnrollPlanMapper.java | 19 + .../art/mapper/ArtSchoolMajorMapper.java | 19 + .../art/mapper/ArtSchoolMajorTagMapper.java | 19 + .../dromara/art/mapper/ArtSchoolMapper.java | 23 + .../art/mapper/ArtSchoolMediaMapper.java | 15 + .../art/mapper/ArtSchoolNameMapper.java | 15 + .../ArtSchoolRecruitMajorHistoryMapper.java | 15 + .../mapper/ArtSchoolRecruitMajorMapper.java | 15 + .../art/mapper/ArtSchoolTagMapper.java | 19 + .../IArtHistoryScoreControlLineService.java | 68 + .../dromara/art/service/IArtMajorService.java | 68 + .../art/service/IArtSchoolCampusService.java | 68 + .../art/service/IArtSchoolCollegeService.java | 71 + .../art/service/IArtSchoolDetailService.java | 85 + .../art/service/IArtSchoolDormService.java | 68 + .../service/IArtSchoolEnrollCodeService.java | 68 + .../service/IArtSchoolEnrollPlanService.java | 68 + .../art/service/IArtSchoolMajorService.java | 71 + .../service/IArtSchoolMajorTagService.java | 68 + .../art/service/IArtSchoolMediaService.java | 68 + .../art/service/IArtSchoolNameService.java | 68 + .../IArtSchoolRecruitMajorHistoryService.java | 68 + .../IArtSchoolRecruitMajorService.java | 68 + .../art/service/IArtSchoolService.java | 124 + .../art/service/IArtSchoolTagService.java | 68 + ...ArtHistoryScoreControlLineServiceImpl.java | 141 + .../art/service/impl/ArtMajorServiceImpl.java | 141 + .../impl/ArtSchoolCampusServiceImpl.java | 138 + .../impl/ArtSchoolCollegeServiceImpl.java | 156 + .../impl/ArtSchoolDetailServiceImpl.java | 205 + .../impl/ArtSchoolDormServiceImpl.java | 137 + .../impl/ArtSchoolEnrollCodeServiceImpl.java | 133 + .../impl/ArtSchoolEnrollPlanServiceImpl.java | 139 + .../impl/ArtSchoolMajorServiceImpl.java | 290 ++ .../impl/ArtSchoolMajorTagServiceImpl.java | 133 + .../impl/ArtSchoolMediaServiceImpl.java | 137 + .../impl/ArtSchoolNameServiceImpl.java | 134 + ...tSchoolRecruitMajorHistoryServiceImpl.java | 156 + .../ArtSchoolRecruitMajorServiceImpl.java | 158 + .../service/impl/ArtSchoolServiceImpl.java | 1343 ++++++ .../service/impl/ArtSchoolTagServiceImpl.java | 133 + .../art/ArtHistoryScoreControlLineMapper.xml | 6 + .../resources/mapper/art/ArtMajorMapper.xml | 6 + .../mapper/art/ArtSchoolCampusMapper.xml | 6 + .../mapper/art/ArtSchoolCollegeMapper.xml | 6 + .../mapper/art/ArtSchoolDetailMapper.xml | 6 + .../mapper/art/ArtSchoolDormMapper.xml | 6 + .../mapper/art/ArtSchoolEnrollCodeMapper.xml | 6 + .../mapper/art/ArtSchoolEnrollPlanMapper.xml | 6 + .../mapper/art/ArtSchoolMajorMapper.xml | 6 + .../mapper/art/ArtSchoolMajorTagMapper.xml | 6 + .../resources/mapper/art/ArtSchoolMapper.xml | 6 + .../mapper/art/ArtSchoolMediaMapper.xml | 6 + .../mapper/art/ArtSchoolNameMapper.xml | 6 + .../ArtSchoolRecruitMajorHistoryMapper.xml | 6 + .../art/ArtSchoolRecruitMajorMapper.xml | 6 + .../mapper/art/ArtSchoolTagMapper.xml | 6 + ruoyi-modules/ruoyi-demo/pom.xml | 108 + .../demo/controller/MailSendController.java | 69 + .../demo/controller/RedisCacheController.java | 92 + .../demo/controller/RedisLockController.java | 64 + .../controller/RedisPubSubController.java | 47 + .../RedisRateLimiterController.java | 64 + .../demo/controller/SmsController.java | 82 + .../controller/Swagger3DemoController.java | 31 + .../demo/controller/TestBatchController.java | 90 + .../demo/controller/TestDemoController.java | 147 + .../controller/TestEncryptController.java | 55 + .../demo/controller/TestExcelController.java | 172 + .../demo/controller/TestI18nController.java | 71 + .../controller/TestSensitiveController.java | 76 + .../demo/controller/TestTreeController.java | 107 + .../demo/controller/WebSocketController.java | 33 + .../dromara/demo/controller/package-info.java | 1 + .../queue/BoundedQueueController.java | 92 + .../queue/DelayedQueueController.java | 97 + .../demo/controller/queue/PriorityDemo.java | 24 + .../queue/PriorityQueueController.java | 91 + .../org/dromara/demo/domain/TestDemo.java | 68 + .../dromara/demo/domain/TestDemoEncrypt.java | 29 + .../org/dromara/demo/domain/TestTree.java | 65 + .../dromara/demo/domain/bo/TestDemoBo.java | 67 + .../demo/domain/bo/TestDemoImportVo.java | 53 + .../dromara/demo/domain/bo/TestTreeBo.java | 54 + .../org/dromara/demo/domain/package-info.java | 1 + .../dromara/demo/domain/vo/ExportDemoVo.java | 122 + .../dromara/demo/domain/vo/TestDemoVo.java | 119 + .../dromara/demo/domain/vo/TestTreeVo.java | 64 + .../demo/listener/ExportDemoListener.java | 68 + .../demo/mapper/TestDemoEncryptMapper.java | 13 + .../dromara/demo/mapper/TestDemoMapper.java | 64 + .../dromara/demo/mapper/TestTreeMapper.java | 21 + .../org/dromara/demo/mapper/package-info.java | 1 + .../demo/service/IExportExcelService.java | 27 + .../demo/service/ITestDemoService.java | 71 + .../demo/service/ITestTreeService.java | 52 + .../service/impl/ExportExcelServiceImpl.java | 297 ++ .../service/impl/TestDemoServiceImpl.java | 118 + .../service/impl/TestTreeServiceImpl.java | 90 + .../demo/service/impl/package-info.java | 1 + .../dromara/demo/service/package-info.java | 1 + .../src/main/resources/excel/单列表.xlsx | Bin 0 -> 10787 bytes .../src/main/resources/excel/多sheet列表.xlsx | Bin 0 -> 13359 bytes .../src/main/resources/excel/多列表.xlsx | Bin 0 -> 10761 bytes .../resources/mapper/demo/TestDemoMapper.xml | 11 + .../resources/mapper/demo/TestTreeMapper.xml | 7 + .../src/main/resources/mapper/package-info.md | 3 + ruoyi-modules/ruoyi-generator/pom.xml | 89 + .../dromara/generator/config/GenConfig.java | 73 + .../config/MyBatisDataSourceMonitor.java | 105 + .../generator/constant/GenConstants.java | 186 + .../generator/controller/GenController.java | 222 + .../dromara/generator/domain/GenTable.java | 196 + .../generator/domain/GenTableColumn.java | 222 + .../mapper/GenTableColumnMapper.java | 15 + .../generator/mapper/GenTableMapper.java | 51 + .../service/GenTableServiceImpl.java | 575 +++ .../generator/service/IGenTableService.java | 141 + .../org/dromara/generator/util/GenUtils.java | 219 + .../generator/util/VelocityInitializer.java | 35 + .../dromara/generator/util/VelocityUtils.java | 389 ++ .../src/main/resources/generator.yml | 10 + .../mapper/generator/GenTableColumnMapper.xml | 10 + .../mapper/generator/GenTableMapper.xml | 42 + .../src/main/resources/mapper/package-info.md | 3 + .../src/main/resources/vm/java/bo.java.vm | 50 + .../main/resources/vm/java/controller.java.vm | 115 + .../src/main/resources/vm/java/domain.java.vm | 60 + .../src/main/resources/vm/java/mapper.java.vm | 15 + .../main/resources/vm/java/service.java.vm | 72 + .../resources/vm/java/serviceImpl.java.vm | 160 + .../src/main/resources/vm/java/vo.java.vm | 66 + .../src/main/resources/vm/soy/api/api.ts.vm | 41 + .../main/resources/vm/soy/index-tree.vue.vm | 232 ++ .../src/main/resources/vm/soy/index.vue.vm | 198 + .../vm/soy/modules/operate-drawer.vue.vm | 257 ++ .../resources/vm/soy/modules/search.vue.vm | 130 + .../main/resources/vm/soy/typings/api.d.ts.vm | 51 + .../src/main/resources/vm/sql/oracle/sql.vm | 19 + .../src/main/resources/vm/sql/postgres/sql.vm | 20 + .../src/main/resources/vm/sql/sql.vm | 19 + .../main/resources/vm/sql/sqlserver/sql.vm | 19 + .../src/main/resources/vm/ts/api.ts.vm | 63 + .../src/main/resources/vm/ts/types.ts.vm | 61 + .../main/resources/vm/vue/index-tree.vue.vm | 499 +++ .../src/main/resources/vm/vue/index.vue.vm | 459 +++ .../src/main/resources/vm/xml/mapper.xml.vm | 6 + ruoyi-modules/ruoyi-job/pom.xml | 34 + .../java/org/dromara/job/entity/BillDto.java | 30 + .../java/org/dromara/job/package-info.java | 1 + .../dromara/job/snailjob/AlipayBillTask.java | 42 + .../dromara/job/snailjob/SummaryBillTask.java | 45 + .../job/snailjob/TestAnnoJobExecutor.java | 25 + .../job/snailjob/TestBroadcastJob.java | 37 + .../job/snailjob/TestClassJobExecutor.java | 19 + .../job/snailjob/TestMapJobAnnotation.java | 53 + .../snailjob/TestMapReduceAnnotation1.java | 60 + .../job/snailjob/TestStaticShardingJob.java | 37 + .../dromara/job/snailjob/WechatBillTask.java | 43 + ruoyi-modules/ruoyi-system/pom.xml | 105 + .../controller/monitor/CacheController.java | 65 + .../monitor/SysLogininforController.java | 93 + .../monitor/SysOperlogController.java | 77 + .../monitor/SysUserOnlineController.java | 134 + .../system/SysClientController.java | 122 + .../system/SysConfigController.java | 142 + .../controller/system/SysDeptController.java | 146 + .../system/SysDictDataController.java | 127 + .../system/SysDictTypeController.java | 131 + .../controller/system/SysMenuController.java | 213 + .../system/SysNoticeController.java | 93 + .../system/SysOssConfigController.java | 106 + .../controller/system/SysOssController.java | 104 + .../controller/system/SysPostController.java | 151 + .../system/SysProfileController.java | 149 + .../controller/system/SysRoleController.java | 246 ++ .../system/SysSocialController.java | 38 + .../system/SysTenantController.java | 211 + .../system/SysTenantPackageController.java | 143 + .../controller/system/SysUserController.java | 308 ++ .../org/dromara/system/domain/SysCache.java | 47 + .../org/dromara/system/domain/SysClient.java | 77 + .../org/dromara/system/domain/SysConfig.java | 51 + .../org/dromara/system/domain/SysDept.java | 92 + .../dromara/system/domain/SysDictData.java | 71 + .../dromara/system/domain/SysDictType.java | 41 + .../dromara/system/domain/SysLogininfor.java | 85 + .../org/dromara/system/domain/SysMenu.java | 191 + .../org/dromara/system/domain/SysNotice.java | 51 + .../org/dromara/system/domain/SysOperLog.java | 115 + .../org/dromara/system/domain/SysOss.java | 55 + .../dromara/system/domain/SysOssConfig.java | 89 + .../org/dromara/system/domain/SysOssExt.java | 75 + .../org/dromara/system/domain/SysPost.java | 61 + .../org/dromara/system/domain/SysRole.java | 79 + .../dromara/system/domain/SysRoleDept.java | 29 + .../dromara/system/domain/SysRoleMenu.java | 29 + .../org/dromara/system/domain/SysSocial.java | 136 + .../org/dromara/system/domain/SysTenant.java | 103 + .../system/domain/SysTenantPackage.java | 60 + .../org/dromara/system/domain/SysUser.java | 115 + .../dromara/system/domain/SysUserOnline.java | 63 + .../dromara/system/domain/SysUserPost.java | 29 + .../dromara/system/domain/SysUserRole.java | 29 + .../dromara/system/domain/bo/SysClientBo.java | 80 + .../dromara/system/domain/bo/SysConfigBo.java | 59 + .../dromara/system/domain/bo/SysDeptBo.java | 81 + .../system/domain/bo/SysDictDataBo.java | 80 + .../system/domain/bo/SysDictTypeBo.java | 50 + .../system/domain/bo/SysLogininforBo.java | 87 + .../dromara/system/domain/bo/SysMenuBo.java | 113 + .../dromara/system/domain/bo/SysNoticeBo.java | 61 + .../system/domain/bo/SysOperLogBo.java | 127 + .../dromara/system/domain/bo/SysOssBo.java | 54 + .../system/domain/bo/SysOssConfigBo.java | 109 + .../dromara/system/domain/bo/SysPostBo.java | 75 + .../dromara/system/domain/bo/SysRoleBo.java | 94 + .../dromara/system/domain/bo/SysSocialBo.java | 142 + .../dromara/system/domain/bo/SysTenantBo.java | 115 + .../system/domain/bo/SysTenantPackageBo.java | 59 + .../dromara/system/domain/bo/SysUserBo.java | 124 + .../system/domain/bo/SysUserPasswordBo.java | 29 + .../system/domain/bo/SysUserProfileBo.java | 53 + .../org/dromara/system/domain/vo/MetaVo.java | 78 + .../system/domain/vo/ProfileUserVo.java | 90 + .../dromara/system/domain/vo/RouterVo.java | 62 + .../dromara/system/domain/vo/SysClientVo.java | 90 + .../dromara/system/domain/vo/SysConfigVo.java | 72 + .../dromara/system/domain/vo/SysDeptVo.java | 109 + .../system/domain/vo/SysDictDataVo.java | 88 + .../system/domain/vo/SysDictTypeVo.java | 59 + .../system/domain/vo/SysLogininforVo.java | 106 + .../dromara/system/domain/vo/SysMenuVo.java | 116 + .../dromara/system/domain/vo/SysNoticeVo.java | 73 + .../system/domain/vo/SysOperLogVo.java | 144 + .../system/domain/vo/SysOssConfigVo.java | 97 + .../system/domain/vo/SysOssUploadVo.java | 28 + .../dromara/system/domain/vo/SysOssVo.java | 77 + .../dromara/system/domain/vo/SysPostVo.java | 91 + .../dromara/system/domain/vo/SysRoleVo.java | 100 + .../dromara/system/domain/vo/SysSocialVo.java | 144 + .../system/domain/vo/SysTenantPackageVo.java | 66 + .../dromara/system/domain/vo/SysTenantVo.java | 115 + .../system/domain/vo/SysUserExportVo.java | 96 + .../system/domain/vo/SysUserImportVo.java | 76 + .../system/domain/vo/SysUserInfoVo.java | 40 + .../dromara/system/domain/vo/SysUserVo.java | 142 + .../dromara/system/domain/vo/UserInfoVo.java | 30 + .../listener/SysUserImportListener.java | 127 + .../system/mapper/SysClientMapper.java | 15 + .../system/mapper/SysConfigMapper.java | 14 + .../dromara/system/mapper/SysDeptMapper.java | 143 + .../system/mapper/SysDictDataMapper.java | 29 + .../system/mapper/SysDictTypeMapper.java | 14 + .../system/mapper/SysLogininforMapper.java | 14 + .../dromara/system/mapper/SysMenuMapper.java | 147 + .../system/mapper/SysNoticeMapper.java | 14 + .../system/mapper/SysOperLogMapper.java | 14 + .../system/mapper/SysOssConfigMapper.java | 16 + .../dromara/system/mapper/SysOssMapper.java | 13 + .../dromara/system/mapper/SysPostMapper.java | 75 + .../system/mapper/SysRoleDeptMapper.java | 13 + .../dromara/system/mapper/SysRoleMapper.java | 105 + .../system/mapper/SysRoleMenuMapper.java | 26 + .../system/mapper/SysSocialMapper.java | 14 + .../system/mapper/SysTenantMapper.java | 14 + .../system/mapper/SysTenantPackageMapper.java | 14 + .../dromara/system/mapper/SysUserMapper.java | 131 + .../system/mapper/SysUserPostMapper.java | 13 + .../system/mapper/SysUserRoleMapper.java | 28 + .../runner/SystemApplicationRunner.java | 28 + .../system/service/ISysClientService.java | 66 + .../system/service/ISysConfigService.java | 93 + .../system/service/ISysDataScopeService.java | 26 + .../system/service/ISysDeptService.java | 137 + .../system/service/ISysDictDataService.java | 82 + .../system/service/ISysDictTypeService.java | 101 + .../system/service/ISysLogininforService.java | 53 + .../system/service/ISysMenuService.java | 172 + .../system/service/ISysNoticeService.java | 73 + .../system/service/ISysOperLogService.java | 61 + .../system/service/ISysOssConfigService.java | 64 + .../system/service/ISysOssService.java | 80 + .../system/service/ISysPermissionService.java | 28 + .../system/service/ISysPostService.java | 136 + .../system/service/ISysRoleService.java | 236 ++ .../system/service/ISysSocialService.java | 53 + .../service/ISysTenantPackageService.java | 62 + .../system/service/ISysTenantService.java | 92 + .../system/service/ISysUserService.java | 231 ++ .../service/impl/SysClientServiceImpl.java | 155 + .../service/impl/SysConfigServiceImpl.java | 268 ++ .../service/impl/SysDataScopeServiceImpl.java | 72 + .../service/impl/SysDeptServiceImpl.java | 426 ++ .../service/impl/SysDictDataServiceImpl.java | 159 + .../service/impl/SysDictTypeServiceImpl.java | 304 ++ .../impl/SysLogininforServiceImpl.java | 182 + .../service/impl/SysMenuServiceImpl.java | 440 ++ .../service/impl/SysNoticeServiceImpl.java | 131 + .../service/impl/SysOperLogServiceImpl.java | 141 + .../service/impl/SysOssConfigServiceImpl.java | 177 + .../service/impl/SysOssServiceImpl.java | 284 ++ .../impl/SysPermissionServiceImpl.java | 62 + .../service/impl/SysPostServiceImpl.java | 277 ++ .../service/impl/SysRoleServiceImpl.java | 614 +++ .../service/impl/SysSensitiveServiceImpl.java | 47 + .../service/impl/SysSocialServiceImpl.java | 112 + .../impl/SysTaskAssigneeServiceImpl.java | 138 + .../impl/SysTenantPackageServiceImpl.java | 149 + .../service/impl/SysTenantServiceImpl.java | 567 +++ .../service/impl/SysUserServiceImpl.java | 772 ++++ .../src/main/resources/mapper/package-info.md | 3 + .../mapper/system/SysClientMapper.xml | 7 + .../mapper/system/SysConfigMapper.xml | 7 + .../resources/mapper/system/SysDeptMapper.xml | 7 + .../mapper/system/SysDictDataMapper.xml | 7 + .../mapper/system/SysDictTypeMapper.xml | 7 + .../mapper/system/SysLogininforMapper.xml | 7 + .../resources/mapper/system/SysMenuMapper.xml | 7 + .../mapper/system/SysNoticeMapper.xml | 7 + .../mapper/system/SysOperLogMapper.xml | 7 + .../mapper/system/SysOssConfigMapper.xml | 7 + .../resources/mapper/system/SysOssMapper.xml | 5 + .../resources/mapper/system/SysPostMapper.xml | 7 + .../mapper/system/SysRoleDeptMapper.xml | 7 + .../resources/mapper/system/SysRoleMapper.xml | 7 + .../mapper/system/SysRoleMenuMapper.xml | 7 + .../mapper/system/SysSocialMapper.xml | 7 + .../mapper/system/SysTenantMapper.xml | 7 + .../mapper/system/SysTenantPackageMapper.xml | 7 + .../resources/mapper/system/SysUserMapper.xml | 42 + .../mapper/system/SysUserPostMapper.xml | 7 + .../mapper/system/SysUserRoleMapper.xml | 7 + ruoyi-modules/ruoyi-workflow/pom.xml | 84 + .../workflow/common/ConditionalOnEnable.java | 29 + .../common/constant/FlowConstant.java | 111 + .../common/enums/ButtonPermissionEnum.java | 65 + .../common/enums/CopySettingEnum.java | 20 + .../common/enums/MessageTypeEnum.java | 53 + .../workflow/common/enums/NodeExtEnum.java | 32 + .../common/enums/TaskAssigneeEnum.java | 140 + .../common/enums/TaskAssigneeType.java | 49 + .../workflow/common/enums/TaskStatusEnum.java | 114 + .../workflow/common/enums/VariablesEnum.java | 20 + .../workflow/config/WarmFlowConfig.java | 16 + .../controller/FlwCategoryController.java | 134 + .../controller/FlwDefinitionController.java | 195 + .../controller/FlwInstanceController.java | 187 + .../controller/FlwSpelController.java | 93 + .../controller/FlwTaskController.java | 225 + .../controller/TestLeaveController.java | 119 + .../dromara/workflow/domain/FlowCategory.java | 67 + .../workflow/domain/FlowInstanceBizExt.java | 59 + .../org/dromara/workflow/domain/FlowSpel.java | 69 + .../dromara/workflow/domain/TestLeave.java | 68 + .../workflow/domain/bo/BackProcessBo.java | 69 + .../workflow/domain/bo/CompleteTaskBo.java | 85 + .../workflow/domain/bo/FlowCancelBo.java | 31 + .../workflow/domain/bo/FlowCategoryBo.java | 47 + .../workflow/domain/bo/FlowCopyBo.java | 30 + .../workflow/domain/bo/FlowInstanceBo.java | 55 + .../workflow/domain/bo/FlowInvalidBo.java | 31 + .../workflow/domain/bo/FlowNextNodeBo.java | 38 + .../workflow/domain/bo/FlowSpelBo.java | 60 + .../workflow/domain/bo/FlowTaskBo.java | 69 + .../workflow/domain/bo/FlowTerminationBo.java | 31 + .../workflow/domain/bo/FlowUrgeTaskBo.java | 38 + .../workflow/domain/bo/FlowVariableBo.java | 39 + .../workflow/domain/bo/StartProcessBo.java | 68 + .../workflow/domain/bo/TaskOperationBo.java | 48 + .../workflow/domain/bo/TestLeaveBo.java | 92 + .../domain/vo/ButtonPermissionVo.java | 43 + .../workflow/domain/vo/FlowCategoryVo.java | 69 + .../workflow/domain/vo/FlowCopyVo.java | 36 + .../workflow/domain/vo/FlowDefinitionVo.java | 104 + .../workflow/domain/vo/FlowHisTaskVo.java | 260 ++ .../workflow/domain/vo/FlowInstanceVo.java | 149 + .../workflow/domain/vo/FlowSpelVo.java | 79 + .../workflow/domain/vo/FlowTaskVo.java | 219 + .../dromara/workflow/domain/vo/NodeExtVo.java | 45 + .../workflow/domain/vo/TestLeaveVo.java | 77 + .../handler/FlowProcessEventHandler.java | 96 + .../handler/WorkflowPermissionHandler.java | 65 + .../listener/WorkflowGlobalListener.java | 272 ++ .../workflow/mapper/FlwCategoryMapper.java | 49 + .../mapper/FlwInstanceBizExtMapper.java | 61 + .../workflow/mapper/FlwInstanceMapper.java | 27 + .../workflow/mapper/FlwSpelMapper.java | 15 + .../workflow/mapper/FlwTaskMapper.java | 47 + .../workflow/mapper/TestLeaveMapper.java | 15 + .../workflow/rule/SpelRuleComponent.java | 38 + .../workflow/service/IFlwCategoryService.java | 95 + .../workflow/service/IFlwCommonService.java | 41 + .../service/IFlwDefinitionService.java | 78 + .../workflow/service/IFlwInstanceService.java | 168 + .../workflow/service/IFlwNodeExtService.java | 35 + .../workflow/service/IFlwSpelService.java | 88 + .../service/IFlwTaskAssigneeService.java | 24 + .../workflow/service/IFlwTaskService.java | 217 + .../workflow/service/ITestLeaveService.java | 52 + .../impl/CategoryNameTranslationImpl.java | 31 + .../service/impl/FlwCategoryServiceImpl.java | 261 ++ .../service/impl/FlwChartExtServiceImpl.java | 273 ++ .../service/impl/FlwCommonServiceImpl.java | 124 + .../impl/FlwDefinitionServiceImpl.java | 270 ++ .../service/impl/FlwInstanceServiceImpl.java | 469 +++ .../service/impl/FlwNodeExtServiceImpl.java | 354 ++ .../service/impl/FlwSpelServiceImpl.java | 190 + .../impl/FlwTaskAssigneeServiceImpl.java | 291 ++ .../service/impl/FlwTaskServiceImpl.java | 859 ++++ .../service/impl/TestLeaveServiceImpl.java | 242 ++ .../service/impl/WorkflowServiceImpl.java | 178 + .../src/main/resources/mapper/package-info.md | 3 + .../mapper/workflow/FlwCategoryMapper.xml | 7 + .../workflow/FlwInstanceBizExtMapper.xml | 7 + .../mapper/workflow/FlwInstanceMapper.xml | 39 + .../mapper/workflow/FlwSpelMapper.xml | 7 + .../mapper/workflow/FlwTaskMapper.xml | 127 + .../mapper/workflow/TestLeaveMapper.xml | 7 + script/bin/ry.bat | 68 + script/bin/ry.sh | 86 + script/docker/database.yml | 59 + script/docker/docker-compose.yml | 157 + script/docker/nginx/conf/nginx.conf | 156 + script/docker/redis/conf/redis.conf | 28 + script/docker/redis/data/README.md | 1 + script/leave/leave1.json | 129 + script/leave/leave2.json | 187 + script/leave/leave3.json | 211 + script/leave/leave4.json | 154 + script/leave/leave5.json | 211 + script/leave/leave6.json | 368 ++ script/sql/oracle/oracle_ry_job.sql | 940 +++++ script/sql/oracle/oracle_ry_vue_5.X.sql | 1407 +++++++ script/sql/oracle/oracle_ry_workflow.sql | 528 +++ script/sql/postgres/postgres_ry_job.sql | 871 ++++ script/sql/postgres/postgres_ry_vue_5.X.sql | 1398 +++++++ script/sql/postgres/postgres_ry_workflow.sql | 507 +++ script/sql/ry_art.sql | 87 + script/sql/ry_job.sql | 535 +++ script/sql/ry_vue_5.X.sql | 976 +++++ script/sql/ry_workflow.sql | 319 ++ script/sql/sqlserver/sqlserver_ry_job.sql | 2891 +++++++++++++ script/sql/sqlserver/sqlserver_ry_vue_5.X.sql | 3641 +++++++++++++++++ .../sql/sqlserver/sqlserver_ry_workflow.sql | 1677 ++++++++ script/sql/update/oracle/update_5.0-5.1.sql | 151 + .../sql/update/oracle/update_5.1.0-5.1.1.sql | 5 + .../sql/update/oracle/update_5.1.1-5.1.2.sql | 6 + .../sql/update/oracle/update_5.1.2-5.2.0.sql | 9 + .../sql/update/oracle/update_5.3.0-5.3.1.sql | 7 + .../sql/update/oracle/update_5.3.1-5.4.0.sql | 18 + .../sql/update/oracle/update_5.4.1-5.5.0.sql | 97 + .../sql/update/oracle/update_5.5.0-5.5.1.sql | 25 + .../sql/update/oracle/update_5.5.1-5.5.2.sql | 4 + script/sql/update/postgres/update_5.0-5.1.sql | 150 + .../update/postgres/update_5.1.0-5.1.1.sql | 5 + .../update/postgres/update_5.1.1-5.1.2.sql | 5 + .../update/postgres/update_5.1.2-5.2.0.sql | 9 + .../update/postgres/update_5.3.0-5.3.1.sql | 7 + .../update/postgres/update_5.3.1-5.4.0.sql | 18 + .../update/postgres/update_5.4.1-5.5.0.sql | 99 + .../update/postgres/update_5.5.0-5.5.1.sql | 25 + .../update/postgres/update_5.5.1-5.5.2.sql | 6 + .../sql/update/sqlserver/update_5.0-5.1.sql | 409 ++ .../update/sqlserver/update_5.1.0-5.1.1.sql | 19 + .../update/sqlserver/update_5.1.1-5.1.2.sql | 10 + .../update/sqlserver/update_5.1.2-5.2.0.sql | 29 + .../update/sqlserver/update_5.3.0-5.3.1.sql | 21 + .../update/sqlserver/update_5.3.1-5.4.0.sql | 63 + .../update/sqlserver/update_5.4.1-5.5.0.sql | 294 ++ .../update/sqlserver/update_5.5.0-5.5.1.sql | 99 + .../update/sqlserver/update_5.5.1-5.5.2.sql | 22 + script/sql/update/update_5.0-5.1.sql | 101 + script/sql/update/update_5.1.0-5.1.1.sql | 3 + script/sql/update/update_5.1.1-5.1.2.sql | 5 + script/sql/update/update_5.1.2-5.2.0.sql | 5 + script/sql/update/update_5.3.0-5.3.1.sql | 7 + script/sql/update/update_5.3.1-5.4.0.sql | 21 + script/sql/update/update_5.4.1-5.5.0.sql | 67 + script/sql/update/update_5.5.0-5.5.1.sql | 21 + script/sql/update/update_5.5.1-5.5.2.sql | 3 + .../update_art_school_major_add_campus.sql | 6 + 971 files changed, 101327 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 docs/51dx_school.json create mode 100644 docs/art_school_api_for_frontend.md create mode 100644 docs/art_school_db_adjustments_2026_03_12.md create mode 100644 docs/art_school_jsonb_api_spec.md create mode 100644 docs/art_sports_volunteer_pgsql.sql create mode 100644 docs/score_new_table.sql create mode 100644 docs/score_newtable_task.md create mode 100644 pom.xml create mode 100644 ruoyi-admin/Dockerfile create mode 100644 ruoyi-admin/pom.xml create mode 100644 ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java create mode 100644 ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java create mode 100644 ruoyi-admin/src/main/resources/application-dev.yml create mode 100644 ruoyi-admin/src/main/resources/application-prod.yml create mode 100644 ruoyi-admin/src/main/resources/application-test.yml create mode 100644 ruoyi-admin/src/main/resources/application.yml create mode 100644 ruoyi-admin/src/main/resources/art-school-import-export-api.md create mode 100644 ruoyi-admin/src/main/resources/art-school-tag-major-tag-api.md create mode 100644 ruoyi-admin/src/main/resources/banner.txt create mode 100644 ruoyi-admin/src/main/resources/i18n/messages.properties create mode 100644 ruoyi-admin/src/main/resources/i18n/messages_en_US.properties create mode 100644 ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties create mode 100644 ruoyi-admin/src/main/resources/ip2region_v4.xdb create mode 100644 ruoyi-admin/src/main/resources/logback-plus.xml create mode 100644 ruoyi-admin/src/main/resources/school_generate.md create mode 100644 ruoyi-admin/src/test/java/org/dromara/test/AssertUnitTest.java create mode 100644 ruoyi-admin/src/test/java/org/dromara/test/DemoUnitTest.java create mode 100644 ruoyi-admin/src/test/java/org/dromara/test/ParamUnitTest.java create mode 100644 ruoyi-admin/src/test/java/org/dromara/test/TagUnitTest.java create mode 100644 ruoyi-common/pom.xml create mode 100644 ruoyi-common/ruoyi-common-bom/pom.xml create mode 100644 ruoyi-common/ruoyi-common-core/pom.xml create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ApplicationConfig.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ThreadPoolConfig.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/config/ValidatorConfig.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheConstants.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/CacheNames.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/Constants.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/GlobalConstants.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/HttpStatus.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/RegexConstants.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/SystemConstants.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/constant/TenantConstants.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/R.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/CompleteTaskDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DictDataDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DictTypeDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowCopyDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/FlowInstanceBizExtDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/OssDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/RoleDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/StartProcessReturnDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/TaskAssigneeDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/UserOnlineDTO.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessDeleteEvent.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessEvent.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/event/ProcessTaskEvent.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/EmailLoginBody.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginBody.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/PasswordLoginBody.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/RegisterBody.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SmsLoginBody.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/SocialLoginBody.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/TaskAssigneeBody.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginBody.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/XcxLoginUser.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/BusinessStatusEnum.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/DeviceType.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/LoginType.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserStatus.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/UserType.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/ServiceException.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/SseException.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/base/BaseException.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileException.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileNameLengthLimitExceededException.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/file/FileSizeLimitExceededException.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaException.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/CaptchaExpireException.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/exception/user/UserException.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/RegexPatternPoolFactory.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/factory/YmlPropertySourceFactory.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/ConfigService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DictService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/OssService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PermissionService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/TaskAssigneeService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/WorkflowService.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DesensitizedUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MapstructUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/MessageUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/NetUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ObjectUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ServletUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/SpringUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StreamUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/StringUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/TreeBuildUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ValidatorUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/FileUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/file/MimeTypeUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/AddressUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/ip/RegionUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/reflect/ReflectUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexUtils.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/regex/RegexValidator.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/sql/SqlUtil.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/AddGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/EditGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/QueryGroup.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPattern.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/dicts/DictPatternValidator.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPattern.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/validate/enumd/EnumPatternValidator.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/Xss.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/xss/XssValidator.java create mode 100644 ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-doc/pom.xml create mode 100644 ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/SpringDocConfig.java create mode 100644 ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/config/properties/SpringDocProperties.java create mode 100644 ruoyi-common/ruoyi-common-doc/src/main/java/org/dromara/common/doc/handler/OpenApiHandler.java create mode 100644 ruoyi-common/ruoyi-common-doc/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-encrypt/pom.xml create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/ApiEncrypt.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/annotation/EncryptField.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/ApiDecryptAutoConfiguration.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/config/EncryptorAutoConfiguration.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptContext.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/EncryptorManager.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/IEncryptor.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AbstractEncryptor.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/AesEncryptor.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Base64Encryptor.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/RsaEncryptor.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm2Encryptor.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/core/encryptor/Sm4Encryptor.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/AlgorithmType.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/enumd/EncodeType.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/CryptoFilter.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/DecryptRequestBodyWrapper.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/filter/EncryptResponseBodyWrapper.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisDecryptInterceptor.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/interceptor/MybatisEncryptInterceptor.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/ApiDecryptProperties.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/properties/EncryptorProperties.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/java/org/dromara/common/encrypt/utils/EncryptUtils.java create mode 100644 ruoyi-common/ruoyi-common-encrypt/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-excel/pom.xml create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/CellMerge.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDictFormat.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelDynamicOptions.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelEnumFormat.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelNotation.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/annotation/ExcelRequired.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelBigNumberConvert.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelDictConvert.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/convert/ExcelEnumConvert.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeHandler.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/CellMergeStrategy.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelListener.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DefaultExcelResult.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/DropDownOptions.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelDownHandler.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelListener.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelOptionsProvider.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/core/ExcelResult.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/handler/DataWriteHandler.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelUtil.java create mode 100644 ruoyi-common/ruoyi-common-excel/src/main/java/org/dromara/common/excel/utils/ExcelWriterWrapper.java create mode 100644 ruoyi-common/ruoyi-common-idempotent/pom.xml create mode 100644 ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/annotation/RepeatSubmit.java create mode 100644 ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/aspectj/RepeatSubmitAspect.java create mode 100644 ruoyi-common/ruoyi-common-idempotent/src/main/java/org/dromara/common/idempotent/config/IdempotentConfig.java create mode 100644 ruoyi-common/ruoyi-common-idempotent/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-job/pom.xml create mode 100644 ruoyi-common/ruoyi-common-job/src/main/java/org/dromara/common/job/config/SnailJobConfig.java create mode 100644 ruoyi-common/ruoyi-common-job/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-json/pom.xml create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/config/JacksonConfig.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/BigNumberSerializer.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/handler/CustomDateDeserializer.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/utils/JsonUtils.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/validate/JsonPattern.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/validate/JsonPatternValidator.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/java/org/dromara/common/json/validate/JsonType.java create mode 100644 ruoyi-common/ruoyi-common-json/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-log/pom.xml create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/annotation/Log.java create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessStatus.java create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/BusinessType.java create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/enums/OperatorType.java create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java create mode 100644 ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/OperLogEvent.java create mode 100644 ruoyi-common/ruoyi-common-log/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-mail/pom.xml create mode 100644 ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java create mode 100644 ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java create mode 100644 ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java create mode 100644 ruoyi-common/ruoyi-common-mail/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-mybatis/pom.xml create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataColumn.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/annotation/DataPermission.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionAdvice.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionPointcut.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/aspect/DataPermissionPointcutAdvisor.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/config/MybatisPlusConfig.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/domain/BaseEntity.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/mapper/BaseMapperPlus.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/TableDataInfo.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataBaseType.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/InjectionMetaObjectHandler.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/MybatisExceptionHandler.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusDataPermissionHandler.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/handler/PlusPostInitTableInfoHandler.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataBaseHelper.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/helper/DataPermissionHelper.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/interceptor/PlusDataPermissionInterceptor.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/utils/IdGeneratorUtil.java create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/resources/common-mybatis.yml create mode 100644 ruoyi-common/ruoyi-common-mybatis/src/main/resources/spy.properties create mode 100644 ruoyi-common/ruoyi-common-oss/pom.xml create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/constant/OssConstant.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/OssClient.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/core/WriteOutSubscriber.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/entity/UploadResult.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/enums/AccessPolicyType.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/exception/OssException.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/factory/OssFactory.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/org/dromara/common/oss/properties/OssProperties.java create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/pom.xml create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/annotation/RateLimiter.java create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/aspectj/RateLimiterAspect.java create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/config/RateLimiterConfig.java create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/java/org/dromara/common/ratelimiter/enums/LimitType.java create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-ratelimiter/src/main/resources/spel-extension.json create mode 100644 ruoyi-common/ruoyi-common-redis/pom.xml create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/CacheConfig.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/RedisConfig.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/config/properties/RedissonProperties.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/KeyPrefixHandler.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/handler/RedisExceptionHandler.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/CaffeineCacheDecorator.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/manager/PlusSpringCacheManager.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/CacheUtils.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/QueueUtils.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/RedisUtils.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/SequenceUtils.java create mode 100644 ruoyi-common/ruoyi-common-redis/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-satoken/pom.xml create mode 100644 ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/config/SaTokenConfig.java create mode 100644 ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/dao/PlusSaTokenDao.java create mode 100644 ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/core/service/SaPermissionImpl.java create mode 100644 ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/handler/SaTokenExceptionHandler.java create mode 100644 ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java create mode 100644 ruoyi-common/ruoyi-common-satoken/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-satoken/src/main/resources/common-satoken.yml create mode 100644 ruoyi-common/ruoyi-common-security/pom.xml create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/SecurityConfig.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/config/properties/SecurityProperties.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/java/org/dromara/common/security/handler/AllUrlHandler.java create mode 100644 ruoyi-common/ruoyi-common-security/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-sensitive/pom.xml create mode 100644 ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/annotation/Sensitive.java create mode 100644 ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveService.java create mode 100644 ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/core/SensitiveStrategy.java create mode 100644 ruoyi-common/ruoyi-common-sensitive/src/main/java/org/dromara/common/sensitive/handler/SensitiveHandler.java create mode 100644 ruoyi-common/ruoyi-common-sms/pom.xml create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/handler/SmsExceptionHandler.java create mode 100644 ruoyi-common/ruoyi-common-sms/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-social/pom.xml create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/me/zhyd/oauth/request/AbstractAuthWeChatEnterpriseRequest.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/me/zhyd/oauth/request/AuthDingTalkV2Request.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/SocialAutoConfiguration.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialLoginConfigProperties.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/config/properties/SocialProperties.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/gitea/AuthGiteaRequest.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/gitea/AuthGiteaSource.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeySource.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamSource.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/AuthRedisStateCache.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java create mode 100644 ruoyi-common/ruoyi-common-social/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-sse/pom.xml create mode 100644 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseAutoConfiguration.java create mode 100644 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/config/SseProperties.java create mode 100644 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/controller/SseController.java create mode 100644 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/core/SseEmitterManager.java create mode 100644 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/dto/SseMessageDto.java create mode 100644 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/listener/SseTopicListener.java create mode 100644 ruoyi-common/ruoyi-common-sse/src/main/java/org/dromara/common/sse/utils/SseMessageUtils.java create mode 100644 ruoyi-common/ruoyi-common-sse/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-tenant/pom.xml create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/config/TenantConfig.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantEntity.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/core/TenantSaTokenDao.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/exception/TenantException.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/PlusTenantLineHandler.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/helper/TenantHelper.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/manager/TenantSpringCacheManager.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/properties/TenantProperties.java create mode 100644 ruoyi-common/ruoyi-common-tenant/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-translation/pom.xml create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/Translation.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/annotation/TranslationType.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/config/TranslationConfig.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/constant/TransConstant.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/TranslationInterface.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationBeanSerializerModifier.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/handler/TranslationHandler.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DeptNameTranslationImpl.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/DictTypeTranslationImpl.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/NicknameTranslationImpl.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/OssUrlTranslationImpl.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/java/org/dromara/common/translation/core/impl/UserNameTranslationImpl.java create mode 100644 ruoyi-common/ruoyi-common-translation/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-web/pom.xml create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/CaptchaConfig.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/FilterConfig.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/I18nConfig.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/ResourcesConfig.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/UndertowConfig.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/CaptchaProperties.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/config/properties/XssProperties.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/BaseController.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/I18nLocaleResolver.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/core/WaveAndCircleCaptcha.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatableFilter.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/RepeatedlyRequestWrapper.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssFilter.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/filter/XssHttpServletRequestWrapper.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/handler/GlobalExceptionHandler.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/java/org/dromara/common/web/interceptor/PlusWebInvokeTimeInterceptor.java create mode 100644 ruoyi-common/ruoyi-common-web/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-common/ruoyi-common-websocket/pom.xml create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/WebSocketConfig.java create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/config/properties/WebSocketProperties.java create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/constant/WebSocketConstants.java create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/dto/WebSocketMessageDto.java create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/handler/PlusWebSocketHandler.java create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/holder/WebSocketSessionHolder.java create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/interceptor/PlusWebSocketInterceptor.java create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/listener/WebSocketTopicListener.java create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/java/org/dromara/common/websocket/utils/WebSocketUtils.java create mode 100644 ruoyi-common/ruoyi-common-websocket/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-extend/pom.xml create mode 100644 ruoyi-extend/ruoyi-monitor-admin/Dockerfile create mode 100644 ruoyi-extend/ruoyi-monitor-admin/pom.xml create mode 100644 ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/MonitorAdminApplication.java create mode 100644 ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/config/SecurityConfig.java create mode 100644 ruoyi-extend/ruoyi-monitor-admin/src/main/java/org/dromara/monitor/admin/notifier/CustomNotifier.java create mode 100644 ruoyi-extend/ruoyi-monitor-admin/src/main/resources/application.yml create mode 100644 ruoyi-extend/ruoyi-monitor-admin/src/main/resources/banner.txt create mode 100644 ruoyi-extend/ruoyi-monitor-admin/src/main/resources/logback-plus.xml create mode 100644 ruoyi-extend/ruoyi-snailjob-server/Dockerfile create mode 100644 ruoyi-extend/ruoyi-snailjob-server/pom.xml create mode 100644 ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/ActuatorAuthFilter.java create mode 100644 ruoyi-extend/ruoyi-snailjob-server/src/main/java/com/aizuda/snailjob/server/starter/filter/SecurityConfig.java create mode 100644 ruoyi-extend/ruoyi-snailjob-server/src/main/java/org/dromara/snailjob/SnailJobServerApplication.java create mode 100644 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-dev.yml create mode 100644 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application-prod.yml create mode 100644 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/application.yml create mode 100644 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/banner.txt create mode 100644 ruoyi-extend/ruoyi-snailjob-server/src/main/resources/logback-plus.xml create mode 100644 ruoyi-modules/pom.xml create mode 100644 ruoyi-modules/ruoyi-art/pom.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtHistoryScoreControlLineController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtMajorController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolCampusController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolCollegeController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolDetailController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolDormController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolEnrollPlanController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolMajorController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolMajorTagController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolMediaController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolNameController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolRecruitMajorController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolRecruitMajorHistoryController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtSchoolTagController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/controller/ArtTestController.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtHistoryScoreControlLine.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtMajor.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchool.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolCampus.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolCollege.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolDetail.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolDorm.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolEnrollCode.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolEnrollPlan.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolMajor.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolMajorTag.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolMedia.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolName.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolRecruitMajor.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolRecruitMajorHistory.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/ArtSchoolTag.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtHistoryScoreControlLineBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtMajorBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolCampusBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolCollegeBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolDetailBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolDormBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolEnrollCodeBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolEnrollPlanBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolMajorBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolMajorTagBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolMediaBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolNameBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolRecruitMajorBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolRecruitMajorHistoryBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolSubmitBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/bo/ArtSchoolTagBo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/excel/ArtSchoolCampusSheetExcel.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/excel/ArtSchoolCollegeSheetExcel.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/excel/ArtSchoolDetailSheetExcel.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/excel/ArtSchoolEnrollPlanSheetExcel.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/excel/ArtSchoolMajorSheetExcel.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/excel/ArtSchoolSheetExcel.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/excel/ArtSchoolTemplateGuideSheetExcel.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtHistoryScoreControlLineVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtMajorVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolCampusVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolCollegeVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolDetailVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolDormVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolEnrollCodeVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolEnrollPlanVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolImportDetailVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolImportPreviewVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolImportResultVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolJsonImportPreviewVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolMajorTagVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolMajorVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolMediaVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolNameVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolRecruitMajorHistoryVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolRecruitMajorVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolSubmitResultVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolTagVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/domain/vo/ArtSchoolVo.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/handler/JsonbTypeHandler.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtHistoryScoreControlLineMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtMajorMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolCampusMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolCollegeMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolDetailMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolDormMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolEnrollCodeMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolEnrollPlanMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolMajorMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolMajorTagMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolMediaMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolNameMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolRecruitMajorHistoryMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolRecruitMajorMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/mapper/ArtSchoolTagMapper.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtHistoryScoreControlLineService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtMajorService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolCampusService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolCollegeService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolDetailService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolDormService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolEnrollCodeService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolEnrollPlanService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolMajorService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolMajorTagService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolMediaService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolNameService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolRecruitMajorHistoryService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolRecruitMajorService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/IArtSchoolTagService.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtHistoryScoreControlLineServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtMajorServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolCampusServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolCollegeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolDetailServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolDormServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolEnrollCodeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolEnrollPlanServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolMajorServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolMajorTagServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolMediaServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolNameServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolRecruitMajorHistoryServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolRecruitMajorServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/java/org/dromara/art/service/impl/ArtSchoolTagServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtHistoryScoreControlLineMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtMajorMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolCampusMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolCollegeMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolDetailMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolDormMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolEnrollCodeMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolEnrollPlanMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolMajorMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolMajorTagMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolMediaMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolNameMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolRecruitMajorHistoryMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolRecruitMajorMapper.xml create mode 100644 ruoyi-modules/ruoyi-art/src/main/resources/mapper/art/ArtSchoolTagMapper.xml create mode 100644 ruoyi-modules/ruoyi-demo/pom.xml create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/MailSendController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisPubSubController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisRateLimiterController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/Swagger3DemoController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestBatchController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestDemoController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestEncryptController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestExcelController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestI18nController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestSensitiveController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/TestTreeController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/WebSocketController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/package-info.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/BoundedQueueController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/DelayedQueueController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityDemo.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/queue/PriorityQueueController.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemo.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestDemoEncrypt.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/TestTree.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoBo.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestDemoImportVo.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/bo/TestTreeBo.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/package-info.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/ExportDemoVo.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestDemoVo.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/domain/vo/TestTreeVo.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/listener/ExportDemoListener.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoEncryptMapper.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestDemoMapper.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/TestTreeMapper.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/mapper/package-info.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/IExportExcelService.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestDemoService.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/ITestTreeService.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/ExportExcelServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestDemoServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/TestTreeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/impl/package-info.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/service/package-info.java create mode 100644 ruoyi-modules/ruoyi-demo/src/main/resources/excel/单列表.xlsx create mode 100644 ruoyi-modules/ruoyi-demo/src/main/resources/excel/多sheet列表.xlsx create mode 100644 ruoyi-modules/ruoyi-demo/src/main/resources/excel/多列表.xlsx create mode 100644 ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestDemoMapper.xml create mode 100644 ruoyi-modules/ruoyi-demo/src/main/resources/mapper/demo/TestTreeMapper.xml create mode 100644 ruoyi-modules/ruoyi-demo/src/main/resources/mapper/package-info.md create mode 100644 ruoyi-modules/ruoyi-generator/pom.xml create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/GenConfig.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/config/MyBatisDataSourceMonitor.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/constant/GenConstants.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/controller/GenController.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTable.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/domain/GenTableColumn.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableColumnMapper.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/mapper/GenTableMapper.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/GenTableServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/service/IGenTableService.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/GenUtils.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityInitializer.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/generator.yml create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/mapper/package-info.md create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/bo.java.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/controller.java.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/domain.java.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/service.java.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/soy/api/api.ts.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/soy/index-tree.vue.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/soy/index.vue.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/soy/modules/operate-drawer.vue.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/soy/modules/search.vue.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/soy/typings/api.d.ts.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/oracle/sql.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/postgres/sql.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sql.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/sql/sqlserver/sql.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/api.ts.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm create mode 100644 ruoyi-modules/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm create mode 100644 ruoyi-modules/ruoyi-job/pom.xml create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/entity/BillDto.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/package-info.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/AlipayBillTask.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/SummaryBillTask.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestAnnoJobExecutor.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestBroadcastJob.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestClassJobExecutor.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapJobAnnotation.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestMapReduceAnnotation1.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/TestStaticShardingJob.java create mode 100644 ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/snailjob/WechatBillTask.java create mode 100644 ruoyi-modules/ruoyi-system/pom.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssConfigController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysOssController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysCache.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOss.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssConfig.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOssExt.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserOnline.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOssConfigBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileUserVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssConfigVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssUploadVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOssVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssConfigMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOssMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/runner/SystemApplicationRunner.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDataScopeService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssConfigService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOssService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssConfigServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOssServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTaskAssigneeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssConfigMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOssMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml create mode 100644 ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml create mode 100644 ruoyi-modules/ruoyi-workflow/pom.xml create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/ConditionalOnEnable.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/constant/FlowConstant.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/ButtonPermissionEnum.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/CopySettingEnum.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/MessageTypeEnum.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/NodeExtEnum.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeEnum.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskAssigneeType.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/TaskStatusEnum.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/common/enums/VariablesEnum.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/config/WarmFlowConfig.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwCategoryController.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwDefinitionController.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwInstanceController.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwSpelController.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/FlwTaskController.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/controller/TestLeaveController.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowCategory.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowInstanceBizExt.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/FlowSpel.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/TestLeave.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/BackProcessBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/CompleteTaskBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCancelBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCategoryBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowCopyBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInstanceBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowInvalidBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowNextNodeBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowSpelBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTaskBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowTerminationBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowUrgeTaskBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/FlowVariableBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/StartProcessBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TaskOperationBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/bo/TestLeaveBo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/ButtonPermissionVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCategoryVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowCopyVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowDefinitionVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowHisTaskVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowInstanceVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowSpelVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/FlowTaskVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/NodeExtVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/domain/vo/TestLeaveVo.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/FlowProcessEventHandler.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/handler/WorkflowPermissionHandler.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/listener/WorkflowGlobalListener.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwCategoryMapper.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceBizExtMapper.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwInstanceMapper.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwSpelMapper.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/FlwTaskMapper.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/mapper/TestLeaveMapper.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/rule/SpelRuleComponent.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCategoryService.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwCommonService.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwDefinitionService.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwInstanceService.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwNodeExtService.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwSpelService.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskAssigneeService.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/IFlwTaskService.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/ITestLeaveService.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/CategoryNameTranslationImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCategoryServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwChartExtServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwDefinitionServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwInstanceServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwNodeExtServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwSpelServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskAssigneeServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwTaskServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/TestLeaveServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/WorkflowServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/package-info.md create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwCategoryMapper.xml create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceBizExtMapper.xml create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwInstanceMapper.xml create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwSpelMapper.xml create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/FlwTaskMapper.xml create mode 100644 ruoyi-modules/ruoyi-workflow/src/main/resources/mapper/workflow/TestLeaveMapper.xml create mode 100644 script/bin/ry.bat create mode 100644 script/bin/ry.sh create mode 100644 script/docker/database.yml create mode 100644 script/docker/docker-compose.yml create mode 100644 script/docker/nginx/conf/nginx.conf create mode 100644 script/docker/redis/conf/redis.conf create mode 100644 script/docker/redis/data/README.md create mode 100644 script/leave/leave1.json create mode 100644 script/leave/leave2.json create mode 100644 script/leave/leave3.json create mode 100644 script/leave/leave4.json create mode 100644 script/leave/leave5.json create mode 100644 script/leave/leave6.json create mode 100644 script/sql/oracle/oracle_ry_job.sql create mode 100644 script/sql/oracle/oracle_ry_vue_5.X.sql create mode 100644 script/sql/oracle/oracle_ry_workflow.sql create mode 100644 script/sql/postgres/postgres_ry_job.sql create mode 100644 script/sql/postgres/postgres_ry_vue_5.X.sql create mode 100644 script/sql/postgres/postgres_ry_workflow.sql create mode 100644 script/sql/ry_art.sql create mode 100644 script/sql/ry_job.sql create mode 100644 script/sql/ry_vue_5.X.sql create mode 100644 script/sql/ry_workflow.sql create mode 100644 script/sql/sqlserver/sqlserver_ry_job.sql create mode 100644 script/sql/sqlserver/sqlserver_ry_vue_5.X.sql create mode 100644 script/sql/sqlserver/sqlserver_ry_workflow.sql create mode 100644 script/sql/update/oracle/update_5.0-5.1.sql create mode 100644 script/sql/update/oracle/update_5.1.0-5.1.1.sql create mode 100644 script/sql/update/oracle/update_5.1.1-5.1.2.sql create mode 100644 script/sql/update/oracle/update_5.1.2-5.2.0.sql create mode 100644 script/sql/update/oracle/update_5.3.0-5.3.1.sql create mode 100644 script/sql/update/oracle/update_5.3.1-5.4.0.sql create mode 100644 script/sql/update/oracle/update_5.4.1-5.5.0.sql create mode 100644 script/sql/update/oracle/update_5.5.0-5.5.1.sql create mode 100644 script/sql/update/oracle/update_5.5.1-5.5.2.sql create mode 100644 script/sql/update/postgres/update_5.0-5.1.sql create mode 100644 script/sql/update/postgres/update_5.1.0-5.1.1.sql create mode 100644 script/sql/update/postgres/update_5.1.1-5.1.2.sql create mode 100644 script/sql/update/postgres/update_5.1.2-5.2.0.sql create mode 100644 script/sql/update/postgres/update_5.3.0-5.3.1.sql create mode 100644 script/sql/update/postgres/update_5.3.1-5.4.0.sql create mode 100644 script/sql/update/postgres/update_5.4.1-5.5.0.sql create mode 100644 script/sql/update/postgres/update_5.5.0-5.5.1.sql create mode 100644 script/sql/update/postgres/update_5.5.1-5.5.2.sql create mode 100644 script/sql/update/sqlserver/update_5.0-5.1.sql create mode 100644 script/sql/update/sqlserver/update_5.1.0-5.1.1.sql create mode 100644 script/sql/update/sqlserver/update_5.1.1-5.1.2.sql create mode 100644 script/sql/update/sqlserver/update_5.1.2-5.2.0.sql create mode 100644 script/sql/update/sqlserver/update_5.3.0-5.3.1.sql create mode 100644 script/sql/update/sqlserver/update_5.3.1-5.4.0.sql create mode 100644 script/sql/update/sqlserver/update_5.4.1-5.5.0.sql create mode 100644 script/sql/update/sqlserver/update_5.5.0-5.5.1.sql create mode 100644 script/sql/update/sqlserver/update_5.5.1-5.5.2.sql create mode 100644 script/sql/update/update_5.0-5.1.sql create mode 100644 script/sql/update/update_5.1.0-5.1.1.sql create mode 100644 script/sql/update/update_5.1.1-5.1.2.sql create mode 100644 script/sql/update/update_5.1.2-5.2.0.sql create mode 100644 script/sql/update/update_5.3.0-5.3.1.sql create mode 100644 script/sql/update/update_5.3.1-5.4.0.sql create mode 100644 script/sql/update/update_5.4.1-5.5.0.sql create mode 100644 script/sql/update/update_5.5.0-5.5.1.sql create mode 100644 script/sql/update/update_5.5.1-5.5.2.sql create mode 100644 script/sql/update/update_art_school_major_add_campus.sql diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2276063 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*.class +**/target +**/target/** +target/** +logs/** +.DS_Store +**/.DS_Store + +get_univ2/** +get_univ/** + +.idea diff --git a/README.md b/README.md new file mode 100644 index 0000000..acd1400 --- /dev/null +++ b/README.md @@ -0,0 +1,189 @@ + +
+ +- - - +## 平台简介 + +[![码云Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus) +[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus) +[![Star](https://gitcode.com/dromara/RuoYi-Vue-Plus/star/badge.svg)](https://gitcode.com/dromara/RuoYi-Vue-Plus) +[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/5.X/LICENSE) +
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.5.3-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) +[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.5-blue.svg)]() +[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() +[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() + +> Dromara RuoYi-Vue-Plus 是重写 RuoYi-Vue 针对 `分布式集群与多租户` 场景全方位升级(不兼容原框架) + +> 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可
+活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 + +> 系统演示: [传送门](https://plus-doc.dromara.org/#/common/demo_system) + +> 官方前端项目地址: [gitee](https://gitee.com/JavaLionLi/plus-ui) - [github](https://github.com/JavaLionLi/plus-ui) - [gitcode](https://gitcode.com/dromara/plus-ui)
+> 成员前端项目地址: 基于vben5 [ruoyi-plus-vben5](https://gitee.com/dapppp/ruoyi-plus-vben5)
+> 成员前端项目地址: 基于soybean [ruoyi-plus-soybean](https://gitee.com/xlsea/ruoyi-plus-soybean)
+> 成员项目地址: 删除多租户与工作流 [RuoYi-Vue-Plus-Single](https://gitee.com/ColorDreams/RuoYi-Vue-Plus-Single)
+ +> 文档地址: [plus-doc](https://plus-doc.dromara.org) 国内加速: [plus-doc.top](https://plus-doc.top) + +## 赞助商 + +MaxKey 业界领先单点登录产品 - https://gitee.com/dromara/MaxKey
+CCFlow 驰聘低代码-流程-表单 - https://gitee.com/opencc/RuoYi-JFlow
+数舵科技 软件定制开发APP小程序等 - https://www.shuduokeji.com/
+引迈信息 软件开发平台 - https://www.jnpfsoft.com/index.html?from=plus-doc
+Mall4J 高质量Java商城系统 - https://www.mall4j.com/cn/?statId=11
+aizuda flowlong 工作流 - https://gitee.com/aizuda/flowlong
+Ruoyi-Plus-Uniapp - https://ruoyi.plus
+Topiam IAM/IDaaS身份管理平台 - https://www.topiam.cn/
+ +[如何成为赞助商 加群联系作者详谈 每日PV2500-3000 IP1700-2500](https://plus-doc.dromara.org/#/common/add_group) + +# 本框架与RuoYi的功能差异 + +| 功能 | 本框架 | RuoYi | +|-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| +| 前端项目 | 采用 Vue3 + TS + ElementPlus 重写 | 基于Vue2/Vue3 + JS | +| 后端项目结构 | 采用插件化 + 扩展包形式 结构解耦 易于扩展 | 模块相互注入耦合严重难以扩展 | +| 后端代码风格 | 严格遵守Alibaba规范与项目统一配置的代码格式化 | 代码书写与常规结构不同阅读障碍大 | +| Web容器 | 采用 Undertow 基于 XNIO 的高性能容器 | 采用 Tomcat | +| 权限认证 | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展 | Spring Security 配置繁琐扩展性极差 | +| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验
角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 | +| 三方鉴权 | 采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证 | 无 | +| 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer
可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例) | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 | +| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | +| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具
支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan
支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐
连接池采用 common-pool Bug多经常性出问题 | +| 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能
例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 | +| ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多
例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL | +| SQL监控 | 采用 p6spy 可输出完整SQL与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 | +| 数据分页 | 采用 Mybatis-Plus 分页插件
框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序 | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好 | +| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤
只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展
生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 | +| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件
支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 | +| 数据加解密 | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密
支持多种策略 如BASE64、AES、RSA、SM2、SM4等 | 无 | +| 接口传输加密 | 采用 动态 AES + RSA 加密请求 body 每一次请求秘钥都不同大幅度降低可破解性 | 无 | +| 数据翻译 | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译
支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现 | 无 | +| 多数据源框架 | 采用 dynamic-datasource 支持市面大部分数据库
通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源
支持spel表达式从请求头参数等条件切换数据源 | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差 | +| 多数据源事务 | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚 | 不支持 | +| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 | +| 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 | +| WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 | +| SSE推送 | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步 | 无 | +| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 | +| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 | +| 分布式锁 | 采用 Lock4j 底层基于 Redisson | 无 | +| 分布式任务调度 | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 | +| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储
支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 | +| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 | +| 短信 | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用 | 不支持 | +| 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 | +| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释
只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 | +| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 | +| Excel框架 | 采用 FastExcel(原Alibaba EasyExcel) 基于插件化
框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 | +| 工作流支持 | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能 | 无 | +| 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 | +| 监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制
实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 | +| 链路追踪 | 采用 Apache SkyWalking 还在为请求不知道去哪了 到哪出了问题而烦恼吗
用了它即可实时查看请求经过的每一处每一个节点 | 无 | +| 代码生成器 | 只需设计好表结构 一键生成所有crud代码与页面
降低80%的开发量 把精力都投入到业务设计上
框架为其适配MP、SpringDoc规范化代码 同时支持动态多数据源代码生成 | 代码生成原生结构 只支持单数据源生成 | +| 部署方式 | 支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼 | 原生jar部署 其他环境需手动下载安装 自行搭建 | +| 项目路径修改 | 提供详细的修改方案文档 并为其做了一些改动 非常简单即可修改成自己想要的 | 需要做很多改造 文档说明有限 | +| 国际化 | 基于请求头动态返回不同语种的文本内容 开发难度低 有对应的工具类 支持大部分注解内容国际化 | 只提供基础功能 其他需自行编写扩展 | +| 代码单例测试 | 提供单例测试 使用方式编写方法与maven多环境单测插件 | 只提供基础功能 其他需自行编写扩展 | +| Demo案例 | 提供框架功能的实际使用案例 单独一个模块提供了很多很全 | 无 | + + +## 本框架与RuoYi的业务差异 + +| 业务 | 功能说明 | 本框架 | RuoYi | +|--------|----------------------------------------------------------------------|-----|------------------| +| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 | +| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 | +| 客户端管理 | 系统内对接的所有客户端管理 如: pc端、小程序端等
支持动态授权登录方式 如: 短信登录、密码登录等 支持动态控制token时效 | 支持 | 无 | +| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 | +| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 | +| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 | +| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 | +| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 | +| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 | +| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 | +| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 | +| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 | +| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 | +| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 | +| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 | +| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 | +| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 | +| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 | +| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 | +| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 | +| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 | +| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 | + +## 参考文档 + +使用框架前请仔细阅读文档重点注意事项 +
+>[初始化项目 必看](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) +>>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/init) +> +>[专栏与视频 入门必看](https://plus-doc.dromara.org/#/common/column) +>>[https://plus-doc.dromara.org/#/common/column](https://plus-doc.dromara.org/#/common/column) +> +>[部署项目 必看](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) +>>[https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy](https://plus-doc.dromara.org/#/ruoyi-vue-plus/quickstart/deploy) +> +>[如何加群](https://plus-doc.dromara.org/#/common/add_group) +>>[https://plus-doc.dromara.org/#/common/add_group](https://plus-doc.dromara.org/#/common/add_group) +> +>[参考文档 Wiki](https://plus-doc.dromara.org) +>>[https://plus-doc.dromara.org](https://plus-doc.dromara.org) + +## 软件架构图 + +![Plus部署架构图](https://foruda.gitee.com/images/1678981882624240692/ae2a3f3e_1766278.png "Plus部署架构图.png") + +## 如何参与贡献 + +[参与贡献的方式 https://plus-doc.dromara.org/#/common/contribution](https://plus-doc.dromara.org/#/common/contribution) + +## 捐献作者 +作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭 + + + +## 演示图例 + +| | | +|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| ![输入图片说明](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1735829153637063344/3c21fd4c_1419627.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1735829181303499815/4522cefa_1419627.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1735829377205259767/76a705d7_1419627.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1722959592856812900/e2d0d342_1419627.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "屏幕截图") | + + + + + + + + + + + + diff --git a/docs/51dx_school.json b/docs/51dx_school.json new file mode 100644 index 0000000..9990a6a --- /dev/null +++ b/docs/51dx_school.json @@ -0,0 +1,211 @@ +{ + "univId": 10001, + "univName": "北京大学", + "departType": 1, + "competentDepart": "教育部", + "url": "https://www.pku.edu.cn/", + "contact": "010-62751407", + "univAddress": "北京市海淀区颐和园路5号", + "logo": "https://sdxedu.oss-cn-beijing.aliyuncs.com/univ/logo/02b0cead21d44a3cbfb7707ca7928b95.png", + "backGround": "https://sdxedu.oss-cn-beijing.aliyuncs.com/univ/backGround/f67833522f814ad4ad3ac169957c8236.jpg", + "provId": 1, + "provName": "北京", + "city": 1, + "cityName": "北京市", + "is985": 1, + "is211": 1, + "isFirstClass": 1, + "isFirstLevel": 1, + "isPublic": 1, + "univType": 1, + "univTypeName": "综合", + "establishYear": 1898, + "rank": 2, + "combinedScore": 99, + "photoJson": { + "scenerys": [ + { + "cover": "https://sdxedu.oss-cn-beijing.aliyuncs.com/univ/scenerys/d7c0b4e9a0c746d2a23f45c24793db94.jpeg", + "size": 1, + "scenery": "河流" + } + ], + "staticUrl": "https://static.51sdx.com" + }, + "univDesc": "

                      北京大学创办于1898年,初名京师大学堂,是中国第一所国立综合性大学,也是当时中国最高教育行政机关。辛亥革命后,于1912年改为现名。
作为新文化运动的中心和“五四”运动的策源地,作为中国最早传播马克思主义和民主科学思想的发祥地,作为中国共产党最早的活动基地,北京大学为民族的振兴和解放、国家的建设和发展、社会的文明和进步做出了不可替代的贡献,在中国走向现代化的进程中起到了重要的先锋作用。爱国、进步、民主、科学的传统精神和勤奋、严谨、求实、创新的学风在这里生生不息、代代相传。
1917年,著名教育家蔡元培出任北京大学校长,他“循思想自由原则,取兼容并包主义”,对北京大学进行了卓有成效的改革,促进了思想解放和学术繁荣。陈独秀、李大钊、毛泽东以及鲁迅、胡适等一批杰出人才都曾在北京大学任职或任教。
1937年卢沟桥事变后,北京大学与清华大学、南开大学南迁长沙,共同组成长沙临时大学。不久,临时大学又迁到昆明,改称国立西南联合大学。抗日战争胜利后,北京大学于1946年10月在北平复学。中华人民共和国成立后,全国高校于1952年进行院系调整,北京大学成为一所以文理基础教学和研究为主的综合性大学,为国家培养了大批人才。据不完全统计,北京大学的校友和教师有400多位两院院士,中国人文社科界有影响的人士相当多也出自北京大学。
改革开放以来,北京大学进入了一个前所未有的大发展、大建设的新时期,并成为国家“211工程”重点建设的两所大学之一。
1998年5月4日,北京大学百年校庆之际,国家主席江泽民在庆祝北京大学建校一百周年大会上发表讲话,发出了“为了实现现代化,我国要有若干所具有世界先进水平的一流大学”的号召。在国家的支持下,北京大学适时启动“创建世界一流大学计划”,从此,北京大学的历史翻开了新的一页。2000年4月3日,北京大学与原北京医科大学合并,组建了新的北京大学。原北京医科大学的前身是国立北京医学专门学校,创建于1912年10月26日。20世纪三、四十年代,学校一度名为北平大学医学院,并于1946年7月并入北京大学。1952年在全国高校院系调整中,北京大学医学院脱离北京大学,独立为北京医学院。1985年更名为北京医科大学,1996年成为国家首批“211工程”重点支持的医科大学。两校合并进一步拓宽了北京大学的学科结构,为促进医学与人文社会科学及理科的结合,改革医学教育奠定了基础。
近年来,在“211工程”和“985工程”的支持下,北京大学进入了一个新的历史发展阶段,在学科建设、人才培养、师资队伍建设、教学科研等各方面都取得了显著成绩,为将北大建设成为世界一流大学奠定了坚实的基础。今天的北京大学已经成为国家培养高素质、创造性人才的摇篮、科学研究的前沿和知识创新的重要基地和国际交流的重要桥梁和窗口。现任校党委书记郝平、校长龚旗煌。         

", + "researchJson": { + "features": { + "name": "国家级特色专业", + "value": "经济学、西班牙语、非通用语种群(印地语、乌尔都语、孟加拉语、梵文、巴利文5个语种)、地质学、核技术、临床医学(与北京大学第一医院结合)、口腔医学、法学、阿拉伯语、非通用语种群(蒙古语、菲律宾语、泰国语、波斯语、西伯莱语等12个语种)、微电子学、软件工程(设5个专业方向)、临床医学(与北京大学人民医院结合)、哲学、化学、药学、保险、信息与计算科学、生物科学、智能科学与技术、城市管理、汉语言文学、考古学、世界历史、预防医学、国际政治、地球物理学、地理科学、理论与应用力学、新闻学、环境科学、金融学、电子信息科学与技术、能源与资源工程、环境工程" + }, + "teacher": { + "name": "师资力量", + "value": "北京大学以雄厚的师资力量和先进的研究条件著称,全校专任教师6441人,其中教授1701人,副教授2037人,中国科学院院士68人,工程院院士12人。学校每年邀请大批世界著名学者来校讲学。目前,北京大学有11个国家重点实验室,86个省部级重点实验室,2个国家工程研究中心,8所附属医院。" + }, + "laboratory": [ + { + "name": "国家实验室", + "value": "北京分子科学国家实验室" + } + ], + "subject": [ + { + "name": "一级学科国家重点学科", + "value": "计算机科学与技术,药学,口腔医学,电子科学与技术,力学,生物学,大气科学,地理学,化学,物理学,数学,历史学,社会学,政治学,法学,理论经济学,哲学,中国语言文学" + } + ], + "featuresProv": {}, + "program": [ + { + "name": "硕士点说明", + "value": "硕士学位授权一级学科点51,硕士学位点(含一级学科覆盖)282" + } + ], + "base": { + "硕士点数量": "333", + "博士点数量": "307", + "重点专业数量": "35", + "重点学科数量": "51", + "重点实验室数量": "55" + } + }, + "girlProportion": 47.37, + "isGirlMore": 0, + "scholarshipArray": [ + { + "奖学金": "北京大学奖学金共分两类:一:学校设置:奖励种类和方式学校设立以下若干个人奖:(一)学生“五·四”奖章;(二)三好学生标兵;(三)创新奖;(四)三好学生;(五)优秀学生干部;(六)学习优秀奖;(七)红楼艺术奖;(八)“五·四”体育奖;(九)社会工作奖;(十)优秀毕业生;(十一)其他奖。学校设立以下若干集体奖:(一)学生工作先进单位;(二)班级“五·四”奖杯;(三)优秀班集体;(四)先进学风班。二、社会设置:奖学金名称有上百种,最低1000元/次/人,最高可达12000元/次/人,进入北京大学只要努力学习,综合素质优秀基本上都可以获得奖学金,大二以后平均下来北京大学就没有了所谓的“贫困生”。安心学习,报效国家!" + } + ], + "accommodationArray": [ + { + "name": "食堂", + "value": "北大的食堂,数目很多,各具特色。主要使用饭卡结算的食堂有:学一食堂:位于宿舍区,提供早餐。特点是价格便宜,但是风味不是很突出。基本都是大众菜。午饭和晚饭时会有免费汤提供。招牌菜肴:酱肘子、冬菜包、辣子鸡丁,肉丸子。学三食堂(Campus快餐):位于学一食堂北侧。分为中式快餐部、西式快餐部、水饺快餐部、面食快餐部。价格相对较高,环境较好,一般经常有社团等选择在此开会。上午十点开门一直到晚上九点半。也有不少同学选择在内自习。其中面食部有早餐,全天供应鲜豆浆。推荐面食部的刀削面。学五食堂:位于澡堂对面。也供应早餐。一楼按类别出售主食、炒菜、冷饮等;二楼提供营养套餐。学五食堂的食品分量一般较足。开放时间比学一食堂稍长一点。招牌菜肴:银耳玉米羹,香辣鸡丸子,炖排骨,小炒鸡丝。学四食堂(燕南美食):位于图书馆、哲学楼、光华楼、大讲堂交汇处。一般中午人会较多招牌菜肴:煎包,炒年糕,四川窗口的炒肥肠农园食堂:北大校内最大的学生食堂。地理位置得天独厚,位于三教、四教、电教、理教交汇处。距这几大教学楼都很近,故吃饭时间、特别是午饭时间,农园总是人满为患。家园食堂:一层分特色窗口。餐卡结算。招牌菜肴:炒牛肉、鱼香茄条。二楼是聚餐的好场所,餐卡和现金结算均可。饭量一般很足。口味也不错。艺园食堂:一楼的布局和学五差不多。餐卡结算。招牌菜肴:梅菜炒饭,京酱鸡丝,清蒸的鸡腿,煎饼,三鲜豆腐或家常豆腐烧烤涮:推荐那里的早餐,有馄炖,小笼包,煮鸡蛋,火腿煎蛋。这些食堂除了各自的特色,还有一个共同的特点,就是尽量为学生提供方便。北大校内所有食堂都不用现金支付,而是使用学生餐卡,卫生方便。从分布位置看,农园靠近教学楼,学四与图书馆相邻,其他的食堂则都设在宿舍附近。无论是上课、自习,还是在宿舍休息的同学都可以就近就餐。另外,除了上面提到的几个提供餐具的食堂外,其他食堂都出售方便饭盒,可以让辛苦了一天的同学们偶尔也偷偷不刷饭盒的小懒使用现金结算的食校内餐厅有:药膳:位于二体网球场南面。推荐药膳的馄炖和麻辣鲇鱼。佟园:校内的清真风味餐厅。回民同学可以去看看。华美:位于42楼后,位置比较偏僻。主要经营炒菜,也就是家常菜为主。价格基本合理。北京大学有学生食堂近10个,种类齐全,可以品尝到全国各地优秀风味。伙食标准因人而异,平均约350~400元/生/月。" + } + ], + "masterProportion": 56, + "abroadProportion": 20.19, + "hasRegular": 1, + "hasJunior": 0, + "hasMaster": 1, + "envSatisfaction": 4.6, + "envVote": 1394, + "liveSatisfaction": 4.4, + "liveVote": 1376, + "combinedSatisfaction": 4.7, + "combinedVote": 1411, + "satisfactionJson": { + "details": [ + { + "s3": "3", + "score": "4.8", + "s4": "7", + "s5": "87", + "name": "综合满意度", + "votes": "1207", + "s1": "2", + "s2": "1" + } + ] + }, + "flag": 0, + "isEight": 0, + "isThirty": 0, + "isEighteen": 0, + "subjectReviews": [ + { + "subList": [ + { + "assessGrade": "1档", + "assessLevel": "A+", + "subjectName": "统计学" + } + ], + "type": "第四轮" + } + ], + "specialMajor": [ + { + "majorList": [ + { + "majorId": "247", + "majorName": "智能科学与技术" + } + ], + "type": "国家级" + } + ], + "specialMajorCount": 41, + "college": [ + { + "collegeName": "数学科学学院", + "collegeId": 55, + "majorList": [ + { + "isMajorClass": "0", + "majorLevel": "(本)", + "majorId": "2077", + "majorName": "数据科学与大数据技术" + } + ] + } + ], + "employmentReport": [ + { + "reportName": "北京大学2021年度就业报告", + "onlinePreview": "https://m.51sdx.com/images/employment_report/PDF/北京大学2021年度就业报告.PDF", + "reportUrl": "https://scc.pku.edu.cn/home!downloadCenter.action" + } + ], + "doctoralProgram": 56, + "doctorExplain": "一级学科博士学位授权点56个", + "mastersDegree": 56, + "masterExplain": "一级学科硕士学位授权点56个", + "teachers": "北京大学以雄厚的师资力量和先进的研究条件著称,全校专任教师6441人,其中教授1701人,副教授2037人,中国科学院院士68人,工程院院士12人。学校每年邀请大批世界著名学者来校讲学。目前,北京大学有12个国家重点实验室,3个国家工程研究中心,6所附属医院。", + "scholarship": "北京大学本科生的奖学金种类丰富多样,主要包括以下几类:\n国家级奖学金:\n国家奖学金:一次性奖励 8000 元,用于奖励学习成绩优异、综合素质突出的学生,全国共奖励 6 万人。\n国家励志奖学金:一次性奖励 5000 元,约占大二大三大四在校生人数的 4.5%,奖励对象为品学兼优的家庭经济困难学生。\n校级奖学金:\n优秀新生奖学金:为支持优秀高中毕业生顺利进入北京大学完成本科学业而设立。该奖学金分为新生一等奖学金(总金额 50000 元每生)、新生二等奖学金(总金额 25000 元每生)、新生三等奖学金(总金额 10000 元每生)。凡被北京大学录取的全日制本科新生均有资格申请,由新生奖学金提名小组就新生的申请材料从新生高中平时成绩、高考成绩、获奖情况、学生工作情况和社会公益事业参与情况等几个方面进行初步审核,并形成初步获奖名单,最终报奖学金评审委员会评审通过。\n综合奖学金:每年金额为 4000 元 - 12000 元不等,占参评总人数的 9%,用于奖励在学业、品德、社会实践等多方面表现优秀的学生。\n五四奖学金:包括 “五・四” 奖章、“三好学生标兵”“创新奖”“三好学生”“优秀学生干部”“学习优秀奖”“红楼艺术奖”“‘五四’体育奖”“社会工作奖”“优秀毕业生” 等个人奖项以及 “学生工作先进单位”“班级‘五・四’奖杯”“优秀班集体”“先进学风班” 等集体奖项,奖励在不同方面有突出表现的学生个人和集体。\n社会捐赠奖学金:由社会各界爱心人士、企业或机构捐赠设立,每年金额为 2000 元 - 20000 元不等,占参评总人数的 6%。例如,国家开发银行设立的奖励金,嘉里集团马来西亚本科留学生全奖等。这些奖学金的具体名称、金额、评选标准等因捐赠方的要求而有所不同,旨在鼓励学生在学术、科研、社会服务等方面取得优异成绩。", + "grant": "北京大学本科生的助学金种类主要有以下几种:\n国家助学金:由中央与地方政府共同出资设立,用于资助家庭经济困难的全日制普通本专科(含高职、第二学士学位)在校学生。每人每年 3300 元,分十个月发放。\n国家励志奖学金:由中央和地方政府共同出资设立,奖励资助品学兼优的家庭经济困难学生。每人每年 5000 元,不过它兼具奖学金和助学金的性质。\n五四助学金:由北京大学出资设立,用于帮助家庭经济困难学生更好地完成学业。\n社会捐赠助学金:由社会各界爱心人士、企业或机构捐赠设立,额度从 4000 元到 1 万元不等。多项助学金配套各类助学类奖学金、攻读双学位奖学金、境内外交流奖学金等成才项目,以 “自助、他助、助人” 的价值理念扶助学生成长成才。不同的社会捐赠助学金可能有不同的具体要求和评选标准。\n此外,北京大学还有一些其他针对家庭经济困难学生的资助项目,如减免学费、借款、临时困难补助等。具体的助学金种类和申请条件可能会根据学校政策和社会捐赠情况有所变化,学生可以关注学校学生资助中心的相关通知和信息,以便及时了解和申请适合自己的助学金。", + "canteen": "北京大学有多个食堂,以下是一些食堂的条件情况:\n家园食堂:\n规模与环境:北大校内最大的学生食堂,2019 年新建,共有四层,能容纳四千多人。内部环境优美整洁明亮,有人认为其环境堪比图书馆。\n菜品特色:提供丰富多样的菜品,包括快餐、中式简餐、各地特色风味美食小吃、西式简餐等。菜品种类繁多,有大众家常菜,如西红柿炒鸡蛋、红烧肉、土豆炖鸡块等;也有一些相对 “小奢华” 的菜品,如小龙虾、大闸蟹、鱼肉等;还涵盖了各种特色粉面,如柳州螺蛳粉、桂林米粉、重庆酸辣粉等;以及其他特色美食品类,如咖喱牛肉饭、麻辣香锅、新疆大盘鸡、韩式石锅拌饭、日式拉面等,甚至包括各大菜系的经典名菜,如东北的锅包肉、北京的烤鸭、四川的毛血旺等。\n农园食堂:\n地理位置与环境:地理位置得天独厚,位于三教、四教、电教、理教交汇处,距这几大教学楼都很近。有三大层,能保证两千多名学生和教师的就餐。\n菜品供应:提供早、午、晚餐,菜品丰富多样,以满足师生的不同需求。\n学一食堂:\n位置与早餐供应:位于宿舍区,提供早餐,方便学生就餐。\n菜品与价格:价格相对便宜,主要是大众菜,风味不是很突出,但基本能满足日常饮食需求。午饭和晚饭时会有免费汤提供。招牌菜肴有酱肘子、冬菜包、辣子鸡丁、肉丸子等。\n学三食堂(campus 快餐):\n餐厅布局:位于学一食堂北侧,分为中式快餐部、西式快餐部、水饺快餐部、面食快餐部。\n营业时间与环境:上午十点开门一直到晚上九点半,营业时间较长,环境较好,经常有社团等选择在此开会,也有不少同学选择在内自习。其中面食部有早餐,全天供应鲜豆浆。推荐面食部的刀削面。\n学五食堂:\n位置与营业时长:位于澡堂对面,也供应早餐,开放时间比学一食堂稍长一点。\n菜品与特色:一楼按类别出售主食、炒菜、冷饮等;二楼提供营养套餐。食品分量一般较足。招牌菜肴有银耳玉米羹,香辣鸡丸子,炖排骨,小炒鸡丝。\n燕南美食(学四食堂):\n位置与特色:位于图书馆、哲学楼、光华楼、大讲堂交汇处,一般中午人会较多。经过重装后,环境有很大改善,如一层原先的中心岛被改为就餐区域,座位数增加;采用侧面采光和顶面采光相结合的方式引入自然采光,创造出宜人的自然光环境;新增景观楼梯,坡度设计平缓,方便端餐盘行走;餐桌椅布局形成多种空间形式,座椅设计考虑了同学们书包的放置问题等。\n菜品:提供多种美食选择,如奶黄酥、榴莲酥、牛肉酥饼、玉米汁、橙汁藕块、鲮鱼虎皮椒、烤肉烧饼、油淋鲷鱼藕条、香蒜肉片鸡蛋干、酱牛蹄筋、红椒肉汤拌饭、擂椒卤肉饭、白切鸡套餐饭、港式控肉饭、重庆小面、鳗鱼虾卷寿司、芝士辛拉面、日式和牛饭、麻辣香锅、麻辣烫等(部分为开业当天菜品)。\n此外,北京大学还有松林餐厅(很多学生的早餐首选食堂)、艺园餐厅(供应烧烤,是学生吃夜宵的好去处)、佟园食堂(清真餐厅,照顾少数民族学生)等。并且近两三年,学校还专门在校园内开设了移动餐车,提供快餐盒饭、豆浆、包子早点、面包、水果等,为同学们提供了很大的便捷性。同时,北大的食堂也进入到了 “智能时代”,有 “食堂神器” 可以实时监测各食堂的就餐人数,方便学生合理安排就餐时间和地点,学生们在食堂里还可以体验自动米饭机定量打饭、通过自动结算机器人结账以及机器人送餐、收餐盘传输带等智能服务。", + "dormitory": "北京大学本科生的宿舍条件如下:\n宿舍布局:通常为四人一间,全部住校内。床铺为上下床,左右两侧配备大衣柜、书柜,进门处有储物柜。\n家具设施:\n每位同学有一个书柜书桌衣柜一体柜,书柜容量较大,前有插座,可自行安排使用空间。\n衣柜分三层,可收纳较多衣物,同时配备有挂衣杆。\n储物柜分上下两层,进深约 75cm,宽约 85cm,高约 60cm,能容纳下 24 寸行李箱,也可放置不常用衣物、被褥等。\n其他设施:\n宿舍内配有暖气、空调、阳台等。阳台有两排晾衣杆以及空调外机。\n每层楼设有 1 - 2 个公共盥洗室和浴室。盥洗室有两排水池可供洗漱、一个可供洗拖把的小水池、热水器、洗衣机、洗鞋机以及烘干机等,部分宿舍的部分楼层还有洗鞋机、甩干机,部分楼可以领取专用洗衣桶。40 楼西侧和 36 楼东侧设有洗衣店,提供洗衣、洗鞋、干洗等服务。浴室每个有 6 个隔间,热水供应时间为 7:00 - 9:00 和 15:20 - 23:00,浴室外设有吹风机插座。31 楼地下有公共浴室,15:20 - 22:50 开放。\n一楼大厅常设微波炉,还设有自动贩卖机,楼长阿姨平时也在一楼大厅工作,若需要应急物品例如寝室钥匙、药品等也可向楼长阿姨求助。\n用电及网络:\n宿舍用电采用定额管理,计量收费的方式。每间宿舍每月有 32 度免费电可使用,超过该定额需前往 28 楼地下的后勤服务大厅缴纳超额电费以及进行充值,目前的电价为 0.5103 元每度。不可以使用热得快、电热锅等大功率电器,也不要在宿舍进行电动车电池充电,如需使用电吹风可到盥洗室或一楼大厅的专用插头处。\n每个宿舍将有 2 个网口,若每人都有上网要求,则需自己准备 hub。\n熄灯制度:周日至周四每晚 23 点熄灯,第二天 6 点恢复,周五周六晚不统一熄灯。目前新建的宿舍楼熄灯不断电,有些宿舍后熄灯后会断电,不过走廊等公共设施仍有电力供应。考试周期间也会根据时间推迟熄灯时间方便大家复习。\n宿舍管理:\n每个宿舍都设有楼长,楼长办公室设在一楼入门处,一般是几位楼长轮班值守,有困难或者问题可以随时求助。\n宿舍的卫生检查由楼长组织成立的楼委会负责,每月一次,为每个宿舍进行打分,每一学年进行总评,选出卫生好的宿舍进行全校评比,如果被评为 “安全文明卫生宿舍”,门上会贴有标志,宿舍每位成员也会得到奖励。\n需要注意的是,不同宿舍楼的具体条件可能会略有差异,且学校也可能会根据实际情况进行调整和改善。", + "guojiatese": "35", + "shuoshidian": "50", + "jiuyelu": "94.90", + "twsdl": "1", + "twsdlYear": 2022, + "yuanshi": "58", + "boshidian": "53", + "xyh": "1", + "xyhYear": 2025, + "wsl": "3", + "wslYear": 2025, + "kaoyanlu": "52.26", + "chuguolu": "18.90", + "usdalu": "2", + "usdaluYear": 2022, + "xuekea": "56", + "qsdalu": "2", + "qsdaluYear": 2022, + "gjzdxk": "54", + "univMajors": [ + { + "majorList": [ + { + "bzk": "1", + "classId": 1, + "subClassId": 1, + "majorId": "1", + "year": "四年", + "majorName": "哲学", + "majorTag": "国家特色" + } + ], + "className": "国家特色" + } + ], + "univPostgraduateList": [ + { + "year": 2024, + "exemption": 64.6 + } + ], + "isDoubleHighPlan": 0, + "isStrongPlan": 1 +} diff --git a/docs/art_school_api_for_frontend.md b/docs/art_school_api_for_frontend.md new file mode 100644 index 0000000..ecc602c --- /dev/null +++ b/docs/art_school_api_for_frontend.md @@ -0,0 +1,163 @@ +# 学校模块接口与字段说明(给前端) + +## 1. 数据字段一览 + +### 1.1 school(art_school) +用于学校基础信息展示与编辑。 +- `school_id` 学校主键ID +- `main_code` 学校编码(国标代码) +- `main_name` 官方全称 +- `short_name` 简称 +- `province` 省份 +- `city` 城市 +- `district` 区县 +- `university_type` 院校类型(综合/工科/艺术/财经等) +- `education_level` 学历层次(本科/专科) +- `school_nature` 办学性质(公办/民办/中外合作) +- `supervisor_dept` 主管部门 +- `remark` 备注 + +### 1.2 school_detail(art_school_detail) +用于学校详情展示与编辑(JSONB 字段不直接返回)。 + +基础展示字段: +- `detail_id` 详情主键ID +- `school_id` 学校ID +- `introduction` 学校介绍(富文本) +- `school_icon` 校徽 +- `back_ground` 背景图 +- `address` 地址 +- `contact` 联系方式 +- `email` 邮箱 +- `website` 官网 +- `postcode` 邮编 +- `establish_year` 建校年份 +- `campus_area_mu` 占地面积(亩) +- `library_collection` 图书馆藏书量 +- `male_ratio` 男生比例 +- `female_ratio` 女生比例 +- `is_985` 是否985 +- `is_211` 是否211 +- `is_double_first_class` 是否双一流 +- `is_key_university` 是否省重点 +- `is_public` 是否公办 +- `tags` 学校标签数组 +- `student_count` 在校学生数 +- `teacher_count` 教职工人数 +- `master_point` 硕士点数量 +- `doctor_point` 博士点数量 +- `key_major_count` 国家级重点专业数 +- `employment_rate` 就业率 +- `satisfaction_rate` 院校满意度 +- `univ_id` 外部院校ID +- `master_proportion_rate` 考研率 +- `abroad_proportion_rate` 出国率 +- `has_regular` 是否有普通本科 +- `has_junior` 是否有专科 +- `has_master` 是否有硕士点 +- `is_double_high_plan` 是否双高计划 +- `is_strong_plan` 是否强基计划 +- `twsdl_rank` 泰晤士中国排名 +- `xyh_rank` 校友会排名 +- `wsl_rank` 武书连排名 +- `usdalu_rank` US中国排名 +- `qsdalu_rank` QS排名 +- `combined_score` 综合评分 +- `overall_rank` 综合排名 +- `env_satisfaction` 环境满意度 +- `env_vote` 环境满意度投票数 +- `live_satisfaction` 生活满意度 +- `live_vote` 生活满意度投票数 +- `combined_satisfaction` 综合满意度(原始分) +- `combined_vote` 综合满意度投票数 +- `teachers` 师资力量描述 +- `scholarship` 奖学金说明 +- `grant_desc` 助学金说明 +- `canteen` 食堂说明 +- `dormitory` 宿舍说明 +- `master_explain` 硕士点说明 +- `doctor_explain` 博士点说明 + +隐藏字段(仅通过单独接口获取): +- `satisfaction_json` 满意度明细(JSONB) +- `scholarship_json` 奖学金数组(JSONB) +- `special_major_json` 特色专业(JSONB) +- `employment_report_json` 就业报告(JSONB) +- `photo_json` 图片(JSONB) +- `accommodation_json` 建筑/配套(JSONB) +- `subject_reviews_json` 学科评估(JSONB) +- `research_json` 科研信息(JSONB) +- `univ_majors_json` 专业标签(JSONB) +- `univ_postgraduate_json` 保研信息(JSONB) + +## 2. 接口说明 + +### 2.1 基础信息接口(已存在) +- 学校列表:`GET /art/school/list` +- 学校详情:`GET /art/school/{schoolId}` +- 新增学校:`POST /art/school` +- 修改学校:`PUT /art/school` + +- 详情列表:`GET /art/schoolDetail/list` +- 详情详情:`GET /art/schoolDetail/{detailId}` +- 新增详情:`POST /art/schoolDetail` +- 修改详情:`PUT /art/schoolDetail` + +说明:上述 school_detail 的返回默认不包含 JSONB 隐藏字段。 + +### 2.2 JSONB 单独接口(需新增) +以下接口用于前端按需加载/编辑 JSONB 字段: + +1. 满意度明细 + - `GET /art/schoolDetail/json/satisfaction?schoolId=` + - `PUT /art/schoolDetail/json/satisfaction` + - 请求体:`{ "schoolId": 1, "satisfactionJson": {...} }` + +2. 奖学金数组 + - `GET /art/schoolDetail/json/scholarship?schoolId=` + - `PUT /art/schoolDetail/json/scholarship` + - 请求体:`{ "schoolId": 1, "scholarshipJson": [...] }` + +3. 特色专业 + - `GET /art/schoolDetail/json/specialMajor?schoolId=` + - `PUT /art/schoolDetail/json/specialMajor` + - 请求体:`{ "schoolId": 1, "specialMajorJson": [...] }` + +4. 就业报告 + - `GET /art/schoolDetail/json/employmentReport?schoolId=` + - `PUT /art/schoolDetail/json/employmentReport` + - 请求体:`{ "schoolId": 1, "employmentReportJson": [...] }` + +5. 学校图片 + - `GET /art/schoolDetail/json/photo?schoolId=` + - `PUT /art/schoolDetail/json/photo` + - 请求体:`{ "schoolId": 1, "photoJson": {...} }` + +6. 建筑/配套 + - `GET /art/schoolDetail/json/accommodation?schoolId=` + - `PUT /art/schoolDetail/json/accommodation` + - 请求体:`{ "schoolId": 1, "accommodationJson": [...] }` + +7. 学科评估 + - `GET /art/schoolDetail/json/subjectReviews?schoolId=` + - `PUT /art/schoolDetail/json/subjectReviews` + - 请求体:`{ "schoolId": 1, "subjectReviewsJson": [...] }` + +8. 科研信息 + - `GET /art/schoolDetail/json/research?schoolId=` + - `PUT /art/schoolDetail/json/research` + - 请求体:`{ "schoolId": 1, "researchJson": {...} }` + +9. 专业标签 + - `GET /art/schoolDetail/json/univMajors?schoolId=` + - `PUT /art/schoolDetail/json/univMajors` + - 请求体:`{ "schoolId": 1, "univMajorsJson": [...] }` + +10. 保研信息 + - `GET /art/schoolDetail/json/univPostgraduate?schoolId=` + - `PUT /art/schoolDetail/json/univPostgraduate` + - 请求体:`{ "schoolId": 1, "univPostgraduateJson": [...] }` + +## 3. 前端展示建议 +- 详情主页面展示“基础字段 + 文本说明字段”即可。 +- JSONB 字段按需加载,独立页/弹窗编辑更清晰。 diff --git a/docs/art_school_db_adjustments_2026_03_12.md b/docs/art_school_db_adjustments_2026_03_12.md new file mode 100644 index 0000000..b679065 --- /dev/null +++ b/docs/art_school_db_adjustments_2026_03_12.md @@ -0,0 +1,169 @@ +# art_school 数据结构适配调整清单 + +## 1. 调整概览 +本次根据 `docs/51dx_school.json` 的结构补齐学校详情字段,主要涉及 `art_school_detail` 表新增若干 JSONB/文本/数值字段,用于保存特色专业、就业报告、图片、学科评估、科研信息、满意度明细等。 + +## 2. 需要新增/修改的表结构 + +### 2.0 `art_school_detail` 已覆盖字段(无需新增) +以下字段在你当前的 `art_school_detail` 表中已经存在,可直接复用: +`back_ground`、`is_public`、`master_proportion_rate`、`abroad_proportion_rate`、`has_regular`、`has_junior`、`has_master`、`is_double_high_plan`、`is_strong_plan`、`twsdl_rank`、`xyh_rank`、`wsl_rank`、`usdalu_rank`、`qsdalu_rank`、`employment_rate`、`satisfaction_rate`、`master_point`、`doctor_point`、`key_major_count`、`tags`、`univ_id` 等。 + +### 2.1 `art_school_detail` 需要新增字段 +用途:承载 51dx 学校详情中的结构化字段与长文本字段。 + +| 字段名 | 类型(建议) | 含义 | 来源字段 | 调整原因 | +| --- | --- | --- | --- | --- | +| `combined_score` | DECIMAL(10,2) | 综合评分 | `combinedScore` | 评分指标缺失 | +| `overall_rank` | INT | 综合排名 | `rank` | 排名指标缺失 | +| `env_satisfaction` | DECIMAL(10,2) | 环境满意度 | `envSatisfaction` | 满意度细分缺失 | +| `env_vote` | INT | 环境满意度投票数 | `envVote` | 满意度细分缺失 | +| `live_satisfaction` | DECIMAL(10,2) | 生活满意度 | `liveSatisfaction` | 满意度细分缺失 | +| `live_vote` | INT | 生活满意度投票数 | `liveVote` | 满意度细分缺失 | +| `combined_satisfaction` | DECIMAL(10,2) | 综合满意度(原始分) | `combinedSatisfaction` | 保留原始评分 | +| `combined_vote` | INT | 综合满意度投票数 | `combinedVote` | 满意度细分缺失 | +| `satisfaction_json` | JSONB | 满意度明细 JSON | `satisfactionJson` | 结构化明细未存储 | +| `teachers` | LONGTEXT | 师资力量说明 | `teachers` | 文字说明缺失 | +| `scholarship` | LONGTEXT | 奖学金说明 | `scholarship` | 文字说明缺失 | +| `scholarship_json` | JSONB | 奖学金数组 JSON | `scholarshipArray` | 结构化说明缺失 | +| `grant_desc` | LONGTEXT | 助学金说明 | `grant` | 文字说明缺失 | +| `canteen` | LONGTEXT | 食堂说明 | `canteen` | 文字说明缺失 | +| `dormitory` | LONGTEXT | 宿舍说明 | `dormitory` | 文字说明缺失 | +| `master_explain` | TEXT | 硕士点说明 | `masterExplain` | 说明字段缺失 | +| `doctor_explain` | TEXT | 博士点说明 | `doctorExplain` | 说明字段缺失 | +| `special_major_json` | JSONB | 特色专业 JSON | `specialMajor` | 结构化内容缺失 | +| `employment_report_json` | JSONB | 就业报告 JSON | `employmentReport` | 结构化内容缺失 | +| `photo_json` | JSONB | 图片 JSON | `photoJson` | 结构化内容缺失 | +| `accommodation_json` | JSONB | 建筑/配套 JSON | `accommodationArray` | 结构化内容缺失 | +| `subject_reviews_json` | JSONB | 学科评估 JSON | `subjectReviews` | 结构化内容缺失 | +| `research_json` | JSONB | 科研信息 JSON | `researchJson` | 结构化内容缺失 | +| `univ_majors_json` | JSONB | 专业标签 JSON | `univMajors` | 结构化内容缺失 | +| `univ_postgraduate_json` | JSONB | 保研信息 JSON | `univPostgraduateList` | 结构化内容缺失 | + +### 2.2 关联关系调整 +本次未新增关系。新增字段均挂在 `art_school_detail`,与 `art_school.school_id` 关系保持不变。 + +## 3. 是否需要新增实体/表的评估 +短期不必新增独立表,理由: +1. 51dx 的结构性字段(如 `specialMajor`、`employmentReport`、`subjectReviews`)主要用于展示,不涉及复杂查询与统计,存 JSON 字段可以满足当前需求。 +2. 当前已有 `art_school_media`、`art_school_major_tag` 等表,但与 51dx 数据结构不完全匹配,新增映射成本高且收益有限。 + +若后续有以下需求,建议拆表: +1. 需要对特色专业/学科评估进行检索与排序。 +2. 就业报告需要独立管理、下载或审核。 +3. 图片需要按类型、排序进行管理(可复用 `art_school_media`,增加 `biz_type=school` 的批量导入逻辑)。 + +## 4. SQL 参考(PostgreSQL + JSONB + COMMENT) + +```sql +-- 如果已经创建了 rank/grant 列,先重命名避免关键字冲突 +ALTER TABLE art_school_detail + RENAME COLUMN "rank" TO overall_rank; +ALTER TABLE art_school_detail + RENAME COLUMN "grant" TO grant_desc; + +ALTER TABLE art_school_detail + ADD COLUMN combined_score NUMERIC(10,2), + ADD COLUMN overall_rank INTEGER, + ADD COLUMN env_satisfaction NUMERIC(10,2), + ADD COLUMN env_vote INTEGER, + ADD COLUMN live_satisfaction NUMERIC(10,2), + ADD COLUMN live_vote INTEGER, + ADD COLUMN combined_satisfaction NUMERIC(10,2), + ADD COLUMN combined_vote INTEGER, + ADD COLUMN satisfaction_json JSONB, + ADD COLUMN teachers TEXT, + ADD COLUMN scholarship TEXT, + ADD COLUMN scholarship_json JSONB, + ADD COLUMN grant_desc TEXT, + ADD COLUMN canteen TEXT, + ADD COLUMN dormitory TEXT, + ADD COLUMN master_explain TEXT, + ADD COLUMN doctor_explain TEXT, + ADD COLUMN special_major_json JSONB, + ADD COLUMN employment_report_json JSONB, + ADD COLUMN photo_json JSONB, + ADD COLUMN accommodation_json JSONB, + ADD COLUMN subject_reviews_json JSONB, + ADD COLUMN research_json JSONB, + ADD COLUMN univ_majors_json JSONB, + ADD COLUMN univ_postgraduate_json JSONB; + +COMMENT ON COLUMN art_school_detail.combined_score IS '综合评分'; +COMMENT ON COLUMN art_school_detail.overall_rank IS '综合排名'; +COMMENT ON COLUMN art_school_detail.env_satisfaction IS '环境满意度'; +COMMENT ON COLUMN art_school_detail.env_vote IS '环境满意度投票数'; +COMMENT ON COLUMN art_school_detail.live_satisfaction IS '生活满意度'; +COMMENT ON COLUMN art_school_detail.live_vote IS '生活满意度投票数'; +COMMENT ON COLUMN art_school_detail.combined_satisfaction IS '综合满意度(原始分)'; +COMMENT ON COLUMN art_school_detail.combined_vote IS '综合满意度投票数'; +COMMENT ON COLUMN art_school_detail.satisfaction_json IS '满意度明细JSON'; +COMMENT ON COLUMN art_school_detail.teachers IS '师资力量描述'; +COMMENT ON COLUMN art_school_detail.scholarship IS '奖学金说明'; +COMMENT ON COLUMN art_school_detail.scholarship_json IS '奖学金数组JSON'; +COMMENT ON COLUMN art_school_detail.grant_desc IS '助学金说明'; +COMMENT ON COLUMN art_school_detail.canteen IS '食堂说明'; +COMMENT ON COLUMN art_school_detail.dormitory IS '宿舍说明'; +COMMENT ON COLUMN art_school_detail.master_explain IS '硕士点说明'; +COMMENT ON COLUMN art_school_detail.doctor_explain IS '博士点说明'; +COMMENT ON COLUMN art_school_detail.special_major_json IS '特色专业JSON'; +COMMENT ON COLUMN art_school_detail.employment_report_json IS '就业报告JSON'; +COMMENT ON COLUMN art_school_detail.photo_json IS '图片JSON'; +COMMENT ON COLUMN art_school_detail.accommodation_json IS '建筑/配套JSON'; +COMMENT ON COLUMN art_school_detail.subject_reviews_json IS '学科评估JSON'; +COMMENT ON COLUMN art_school_detail.research_json IS '科研信息JSON'; +COMMENT ON COLUMN art_school_detail.univ_majors_json IS '专业标签JSON'; +COMMENT ON COLUMN art_school_detail.univ_postgraduate_json IS '保研信息JSON'; +``` + +## 5. JSONB 性能简要说明 +一般情况下,PostgreSQL 的 JSONB 比 TEXT 存 JSON 更适合查询与索引,读写成本略高但查询性能更好;若仅做原样展示且几乎不查询,可用 TEXT 降低写入开销。当前场景包含后续检索可能性,建议使用 JSONB。 + +## 6. 前端表单与接口调整建议 + +### 6.1 前端需要新增的字段(按展示/编辑分组) +以下字段建议直接在学校详情页(或学校详情编辑页)增加表单项;展示为主、无需复杂查询: +- 文本/富文本:`teachers`、`scholarship`、`grant_desc`、`canteen`、`dormitory`、`master_explain`、`doctor_explain` +- 数值:`combined_score`、`overall_rank`、`env_satisfaction`、`env_vote`、`live_satisfaction`、`live_vote`、`combined_satisfaction`、`combined_vote` +- JSONB 原样展示(可选做 JSON 编辑器/分块表单):`satisfaction_json`、`research_json`、`univ_majors_json`、`univ_postgraduate_json` + +### 6.2 建议拆表并提供独立编辑的模块(可增删列表) +如果需要列表化编辑、排序、筛选,则建议拆表并提供独立接口: +- 特色专业(`special_major_json`) + - 建议拆表字段:`school_id`、`type`、`major_id`、`major_name`、`sort_no`、`remark` +- 学科评估(`subject_reviews_json`) + - 建议拆表字段:`school_id`、`review_type`、`subject_name`、`assess_level`、`assess_grade`、`sort_no`、`remark` +- 就业报告(`employment_report_json`) + - 建议拆表字段:`school_id`、`report_name`、`online_preview`、`report_url`、`year`、`sort_no`、`remark` +- 图片(`photo_json`) + - 建议直接使用现有 `art_school_media`(`biz_type=school`)做多图管理 + +### 6.3 接口调整建议(最小改动) +如果先不拆表,推荐在现有学校详情保存接口中直接读写 JSONB 字段: +- 新增/更新:`ArtSchoolService.insertWithDetailByBo` / `updateWithDetailByBo` +- 查询:`ArtSchoolDetailController` 的 `getInfo` / `list` 保持返回 JSONB 字段 + +如拆表,则建议新增独立模块接口(示例): +1. 特色专业 + - `GET /art/school/specialMajor/list?schoolId=` + - `POST /art/school/specialMajor` + - `PUT /art/school/specialMajor` + - `DELETE /art/school/specialMajor/{id}` +2. 学科评估 + - `GET /art/school/subjectReview/list?schoolId=` + - `POST /art/school/subjectReview` + - `PUT /art/school/subjectReview` + - `DELETE /art/school/subjectReview/{id}` +3. 就业报告 + - `GET /art/school/employmentReport/list?schoolId=` + - `POST /art/school/employmentReport` + - `PUT /art/school/employmentReport` + - `DELETE /art/school/employmentReport/{id}` +4. 学校图片(复用) + - `GET /art/school/media/list?bizType=school&bizId=` + - `POST /art/school/media` + - `DELETE /art/school/media/{id}` + +### 6.4 前端表单交互建议 +- JSONB 字段:可用「分组表单 + 预览 JSON」或直接 JSON 编辑器组件,提交时序列化为字符串。 +- 列表型字段:使用可增删行的表单组件,对应独立接口,避免整条详情表单过大。 diff --git a/docs/art_school_jsonb_api_spec.md b/docs/art_school_jsonb_api_spec.md new file mode 100644 index 0000000..b82d9b8 --- /dev/null +++ b/docs/art_school_jsonb_api_spec.md @@ -0,0 +1,282 @@ +# 学校详情 JSONB 接口对接文档(前端) + +## 1. 目标 +JSONB 字段不在 school_detail 基础接口中返回,仅通过以下接口按需获取与编辑。 +管理端页面需要呈现“可视化表单 + JSON 预览(可选)”的效果。 + +## 2. 通用规范 +### 2.1 URL 规则 +- 基础路径:`/art/schoolDetail/json/*` + +### 2.2 通用响应 +```json +{ + "code": 200, + "msg": "success", + "data": { ... } +} +``` + +### 2.3 通用请求 +- `schoolId` 必填 +- PUT 请求体统一为:`{ "schoolId": 1, "": }` + +### 2.4 字段命名 +后端字段统一使用: +- `satisfactionJson` +- `scholarshipJson` +- `specialMajorJson` +- `employmentReportJson` +- `photoJson` +- `accommodationJson` +- `subjectReviewsJson` +- `researchJson` +- `univMajorsJson` +- `univPostgraduateJson` + +## 3. 页面效果与接口格式 + +### 3.1 满意度明细(satisfactionJson) +#### 页面效果 +- 展示“综合满意度明细”列表:维度名称、投票数、分档人数等 +- 支持新增/删除/编辑一行 + +#### 接口 +- GET `/art/schoolDetail/json/satisfaction?schoolId=1` +- PUT `/art/schoolDetail/json/satisfaction` + +#### 返回格式(示例) +```json +{ + "satisfactionJson": { + "details": [ + { + "name": "综合满意度", + "votes": "1207", + "score": "4.8", + "s1": "2", + "s2": "1", + "s3": "3", + "s4": "7", + "s5": "87" + } + ] + } +} +``` + +### 3.2 奖学金数组(scholarshipJson) +#### 页面效果 +- 展示可编辑文本列表(支持多条) + +#### 接口 +- GET `/art/schoolDetail/json/scholarship?schoolId=1` +- PUT `/art/schoolDetail/json/scholarship` + +#### 返回格式(示例) +```json +{ + "scholarshipJson": [ + { "奖学金": "奖学金说明文本..." } + ] +} +``` + +### 3.3 特色专业(specialMajorJson) +#### 页面效果 +- 按“类型”分组展示(国家级/省级等) +- 每组内为专业列表 + +#### 接口 +- GET `/art/schoolDetail/json/specialMajor?schoolId=1` +- PUT `/art/schoolDetail/json/specialMajor` + +#### 返回格式(示例) +```json +{ + "specialMajorJson": [ + { + "type": "国家级", + "majorList": [ + { "majorId": "247", "majorName": "智能科学与技术" } + ] + } + ] +} +``` + +### 3.4 就业报告(employmentReportJson) +#### 页面效果 +- 列表编辑:报告名称 + 预览链接 + 下载链接 + +#### 接口 +- GET `/art/schoolDetail/json/employmentReport?schoolId=1` +- PUT `/art/schoolDetail/json/employmentReport` + +#### 返回格式(示例) +```json +{ + "employmentReportJson": [ + { + "reportName": "北京大学2021年度就业报告", + "onlinePreview": "https://m.51sdx.com/images/employment_report/PDF/北京大学2021年度就业报告.PDF", + "reportUrl": "https://scc.pku.edu.cn/home!downloadCenter.action" + } + ] +} +``` + +### 3.5 学校图片(photoJson) +#### 页面效果 +- 分类展示(如校园风光) +- 支持上传/删除/排序 + +#### 接口 +- GET `/art/schoolDetail/json/photo?schoolId=1` +- PUT `/art/schoolDetail/json/photo` + +#### 返回格式(示例) +```json +{ + "photoJson": { + "staticUrl": "https://static.51sdx.com", + "scenerys": [ + { + "cover": "https://sdxedu.oss-cn-beijing.aliyuncs.com/univ/scenerys/d7c0b4e9a0c746d2a23f45c24793db94.jpeg", + "size": 1, + "scenery": "河流" + } + ] + } +} +``` + +### 3.6 建筑/配套(accommodationJson) +#### 页面效果 +- 图文块列表(如食堂/宿舍/配套) + +#### 接口 +- GET `/art/schoolDetail/json/accommodation?schoolId=1` +- PUT `/art/schoolDetail/json/accommodation` + +#### 返回格式(示例) +```json +{ + "accommodationJson": [ + { "name": "食堂", "value": "..." } + ] +} +``` +**** +### 3.7 学科评估(subjectReviewsJson) +#### 页面效果 +- 评估轮次分组 +- 每组内展示学科名称与评级 + +#### 接口 +- GET `/art/schoolDetail/json/subjectReviews?schoolId=1` +- PUT `/art/schoolDetail/json/subjectReviews` + +#### 返回格式(示例) +```json +{ + "subjectReviewsJson": [ + { + "type": "第四轮", + "subList": [ + { "subjectName": "统计学", "assessLevel": "A+", "assessGrade": "1档" } + ] + } + ] +} +``` + +### 3.8 科研信息(researchJson) +#### 页面效果 +- 展示“师资力量/特色/学科/实验室”等区块 +- 支持富文本编辑 + +#### 接口 +- GET `/art/schoolDetail/json/research?schoolId=1` +- PUT `/art/schoolDetail/json/research` + +#### 返回格式(示例) +```json +{ + "researchJson": { + "features": { "name": "国家级特色专业", "value": "..." }, + "teacher": { "name": "师资力量", "value": "..." }, + "laboratory": [ { "name": "国家实验室", "value": "..." } ], + "subject": [ { "name": "一级学科国家重点学科", "value": "..." } ], + "program": [ { "name": "硕士点说明", "value": "..." } ], + "base": { "硕士点数量": "333", "博士点数量": "307" } + } +} +``` + +### 3.9 专业标签(univMajorsJson) +#### 页面效果 +- 标签分组 + 专业列表 + +#### 接口 +- GET `/art/schoolDetail/json/univMajors?schoolId=1` +- PUT `/art/schoolDetail/json/univMajors` + +#### 返回格式(示例) +```json +{ + "univMajorsJson": [ + { + "className": "国家特色", + "majorList": [ + { "majorId": "1", "majorName": "哲学", "majorTag": "国家特色", "year": "四年" } + ] + } + ] +} +``` + +### 3.10 保研信息(univPostgraduateJson) +#### 页面效果 +- 年份列表 + 保研率 + +#### 接口 +- GET `/art/schoolDetail/json/univPostgraduate?schoolId=1` +- PUT `/art/schoolDetail/json/univPostgraduate` + +#### 返回格式(示例) +```json +{ + "univPostgraduateJson": [ + { "year": 2024, "exemption": 64.6 } + ] +} +``` + +### 3.11 JSONB 全量获取(all) +#### 页面效果 +- 管理端初始化时一次性加载所有 JSONB 数据(用于整页编辑或预览) + +#### 接口 +- GET `/art/schoolDetail/json/all?schoolId=1` + +#### 返回格式(示例) +```json +{ + "satisfactionJson": { "details": [] }, + "scholarshipJson": [], + "specialMajorJson": [], + "employmentReportJson": [], + "photoJson": {}, + "accommodationJson": [], + "subjectReviewsJson": [], + "researchJson": {}, + "univMajorsJson": [], + "univPostgraduateJson": [] +} +``` + +## 4. 前端交互建议 +- JSONB 独立页/弹窗编辑,保存后局部刷新。 +- 列表型 JSON 建议用“可增删行”的表单组件。 +- 保留原始 JSON 结构,避免字段名变更。 diff --git a/docs/art_sports_volunteer_pgsql.sql b/docs/art_sports_volunteer_pgsql.sql new file mode 100644 index 0000000..d0a38ad --- /dev/null +++ b/docs/art_sports_volunteer_pgsql.sql @@ -0,0 +1,1567 @@ +/* + Navicat Premium Dump SQL + + Source Server : 10.13.13.1_pgsql + Source Server Type : PostgreSQL + Source Server Version : 180003 (180003) + Source Host : 10.13.13.1:5432 + Source Catalog : art_sports_volunteer + Source Schema : public + + Target Server Type : PostgreSQL + Target Server Version : 180003 (180003) + File Encoding : 65001 + + Date: 12/03/2026 09:38:54 +*/ + + +-- ---------------------------- +-- Table structure for art_history_score_control_line +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_history_score_control_line"; +CREATE TABLE "public"."art_history_score_control_line" +( + "control_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '000000'::character varying, + "del_flag" char(1) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '0'::bpchar, + "province_code" varchar(6) COLLATE "pg_catalog"."default" NOT NULL, + "province_name" varchar(32) COLLATE "pg_catalog"."default" NOT NULL, + "year" int2 NOT NULL, + "major_category" varchar(25) COLLATE "pg_catalog"."default" NOT NULL, + "batch_name" varchar(25) COLLATE "pg_catalog"."default" NOT NULL, + "subject_type" varchar(16) COLLATE "pg_catalog"."default" NOT NULL, + "culture_score" numeric(6, 2) DEFAULT NULL::numeric, + "major_score" numeric(6, 2) DEFAULT NULL::numeric, + "culture_score_exam" numeric(6, 2) DEFAULT NULL::numeric, + "major_score_exam" numeric(6, 2) DEFAULT NULL::numeric, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying +) +; +ALTER TABLE "public"."art_history_score_control_line" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."control_id" IS '省控线主键'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."del_flag" IS '删除标志(0存在 1删除)'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."province_code" IS '省份行政区划代码'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."province_name" IS '省份名称'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."year" IS '年份'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."major_category" IS '专业类别'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."batch_name" IS '批次'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."subject_type" IS '科类(文/理)'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."culture_score" IS '文化成绩分数'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."major_score" IS '专业成绩分数'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."culture_score_exam" IS '文化成绩校考分数'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."major_score_exam" IS '专业成绩校考分数'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_history_score_control_line"."remark" IS '备注'; +COMMENT +ON TABLE "public"."art_history_score_control_line" IS '历年省控线表'; + +-- ---------------------------- +-- Table structure for art_major +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_major"; +CREATE TABLE "public"."art_major" +( + "major_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '000000'::character varying, + "del_flag" char(1) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '0'::bpchar, + "major_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, + "education_level" varchar(16) COLLATE "pg_catalog"."default" NOT NULL, + "major_icon" varchar(255) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "schooling_years" int2, + "discipline_primary" varchar(64) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "discipline_secondary" varchar(64) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "degree_awarded" varchar(64) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "summary" varchar(1000) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "training_direction" text COLLATE "pg_catalog"."default", + "core_courses" text COLLATE "pg_catalog"."default", + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying +) +; +ALTER TABLE "public"."art_major" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_major"."major_id" IS '专业主键ID'; +COMMENT +ON COLUMN "public"."art_major"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_major"."del_flag" IS '删除标志(0存在 1删除)'; +COMMENT +ON COLUMN "public"."art_major"."major_name" IS '专业名称'; +COMMENT +ON COLUMN "public"."art_major"."education_level" IS '学历层次'; +COMMENT +ON COLUMN "public"."art_major"."major_icon" IS '专业图标'; +COMMENT +ON COLUMN "public"."art_major"."schooling_years" IS '学制(年)'; +COMMENT +ON COLUMN "public"."art_major"."discipline_primary" IS '所属一级学科'; +COMMENT +ON COLUMN "public"."art_major"."discipline_secondary" IS '所属二级学科'; +COMMENT +ON COLUMN "public"."art_major"."degree_awarded" IS '授予学士学位'; +COMMENT +ON COLUMN "public"."art_major"."summary" IS '专业概括'; +COMMENT +ON COLUMN "public"."art_major"."training_direction" IS '培养方向'; +COMMENT +ON COLUMN "public"."art_major"."core_courses" IS '主要课程'; +COMMENT +ON COLUMN "public"."art_major"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_major"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_major"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_major"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_major"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_major"."remark" IS '备注'; +COMMENT +ON TABLE "public"."art_major" IS '艺术专业库'; + +-- ---------------------------- +-- Table structure for art_school +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school"; +CREATE TABLE "public"."art_school" +( + "school_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" DEFAULT '000000'::character varying, + "main_code" varchar(32) COLLATE "pg_catalog"."default" NOT NULL, + "main_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, + "short_name" varchar(64) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "province" varchar(32) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "city" varchar(32) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "district" varchar(32) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "university_type" varchar(32) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "education_level" varchar(16) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "school_nature" varchar(16) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "supervisor_dept" varchar(64) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "del_flag" char(1) COLLATE "pg_catalog"."default" DEFAULT '0'::bpchar, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" +) +; +ALTER TABLE "public"."art_school" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school"."school_id" IS '学校主键ID'; +COMMENT +ON COLUMN "public"."art_school"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school"."main_code" IS '学校国标代码'; +COMMENT +ON COLUMN "public"."art_school"."main_name" IS '官方全称'; +COMMENT +ON COLUMN "public"."art_school"."short_name" IS '简称'; +COMMENT +ON COLUMN "public"."art_school"."province" IS '省份'; +COMMENT +ON COLUMN "public"."art_school"."city" IS '城市'; +COMMENT +ON COLUMN "public"."art_school"."district" IS '区县'; +COMMENT +ON COLUMN "public"."art_school"."university_type" IS '院校类型:综合/工科/艺术/财经等'; +COMMENT +ON COLUMN "public"."art_school"."education_level" IS '学历层次:本科/专科'; +COMMENT +ON COLUMN "public"."art_school"."school_nature" IS '办学性质:公办/民办/中外合作'; +COMMENT +ON COLUMN "public"."art_school"."supervisor_dept" IS '主管部门'; +COMMENT +ON TABLE "public"."art_school" IS '学校基础信息主表(精简版)'; + +-- ---------------------------- +-- Table structure for art_school_campus +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_campus"; +CREATE TABLE "public"."art_school_campus" +( + "campus_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" DEFAULT '000000'::character varying, + "school_id" int8 NOT NULL, + "campus_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, + "location" varchar(256) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "address" varchar(256) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "lng" numeric(10, 6) DEFAULT NULL::numeric, + "lat" numeric(10, 6) DEFAULT NULL::numeric, + "introduction" text COLLATE "pg_catalog"."default", + "del_flag" char(1) COLLATE "pg_catalog"."default" DEFAULT '0'::bpchar, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying +) +; +ALTER TABLE "public"."art_school_campus" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_campus"."campus_id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_campus"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_campus"."school_id" IS '学校ID'; +COMMENT +ON COLUMN "public"."art_school_campus"."campus_name" IS '校区名称'; +COMMENT +ON COLUMN "public"."art_school_campus"."location" IS '校区位置(文本)'; +COMMENT +ON COLUMN "public"."art_school_campus"."address" IS '校区地址'; +COMMENT +ON COLUMN "public"."art_school_campus"."lng" IS '经度'; +COMMENT +ON COLUMN "public"."art_school_campus"."lat" IS '纬度'; +COMMENT +ON COLUMN "public"."art_school_campus"."introduction" IS '校区介绍'; +COMMENT +ON COLUMN "public"."art_school_campus"."del_flag" IS '删除标志(0代表存在 1代表删除)'; +COMMENT +ON COLUMN "public"."art_school_campus"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_campus"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_school_campus"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_campus"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_school_campus"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_school_campus"."remark" IS '备注'; +COMMENT +ON TABLE "public"."art_school_campus" IS '学校校区表'; + +-- ---------------------------- +-- Table structure for art_school_college +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_college"; +CREATE TABLE "public"."art_school_college" +( + "college_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" DEFAULT '000000'::character varying, + "school_id" int8 NOT NULL, + "college_code" varchar(32) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "college_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, + "introduction" text COLLATE "pg_catalog"."default", + "sort_no" int4 DEFAULT 0, + "del_flag" char(1) COLLATE "pg_catalog"."default" DEFAULT '0'::bpchar, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "college51sdx_id" int4 +) +; +ALTER TABLE "public"."art_school_college" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_college"."college_id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_college"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_college"."school_id" IS '学校ID'; +COMMENT +ON COLUMN "public"."art_school_college"."college_code" IS '学院编码(可选)'; +COMMENT +ON COLUMN "public"."art_school_college"."college_name" IS '学院名称'; +COMMENT +ON COLUMN "public"."art_school_college"."introduction" IS '学院介绍'; +COMMENT +ON COLUMN "public"."art_school_college"."sort_no" IS '排序'; +COMMENT +ON COLUMN "public"."art_school_college"."del_flag" IS '删除标志(0代表存在 1代表删除)'; +COMMENT +ON COLUMN "public"."art_school_college"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_college"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_school_college"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_college"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_school_college"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_school_college"."remark" IS '备注'; +COMMENT +ON TABLE "public"."art_school_college" IS '学校学院(院系)表'; + +-- ---------------------------- +-- Table structure for art_school_detail +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_detail"; +CREATE TABLE "public"."art_school_detail" +( + "detail_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" DEFAULT '000000'::character varying, + "school_id" int8 NOT NULL, + "introduction" text COLLATE "pg_catalog"."default", + "school_icon" varchar(512) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "address" varchar(256) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "contact" varchar(64) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "email" varchar(128) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "website" varchar(128) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "postcode" varchar(16) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "establish_year" int2, + "campus_area_mu" numeric(12, 2), + "library_collection" int8, + "male_ratio" numeric(5, 2), + "female_ratio" numeric(5, 2), + "is_985" int2 DEFAULT 0, + "is_211" int2 DEFAULT 0, + "is_double_first_class" int2 DEFAULT 0, + "is_key_university" int2 DEFAULT 0, + "tags" text[] COLLATE "pg_catalog"."default", + "student_count" int8, + "teacher_count" int8, + "master_point" int4, + "doctor_point" int4, + "key_major_count" int4, + "employment_rate" numeric(5, 2), + "satisfaction_rate" numeric(5, 2), + "univ_id" int4, + "del_flag" char(1) COLLATE "pg_catalog"."default" DEFAULT '0'::bpchar, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP, + "remark" varchar(500) COLLATE "pg_catalog"."default", + "back_ground" varchar(512) COLLATE "pg_catalog"."default", + "is_public" int2 DEFAULT 0, + "master_proportion_rate" numeric(5, 2), + "abroad_proportion_rate" numeric(5, 2), + "has_regular" int2 DEFAULT 0, + "has_junior" int2 DEFAULT 0, + "has_master" int2 DEFAULT 0, + "is_double_high_plan" int2 DEFAULT 0, + "is_strong_plan" int2 DEFAULT 0, + "twsdl_rank" int2 DEFAULT 0, + "xyh_rank" int2 DEFAULT 0, + "wsl_rank" int2 DEFAULT 0, + "usdalu_rank" int2 DEFAULT 0, + "qsdalu_rank" int2 DEFAULT 0 +) +; +ALTER TABLE "public"."art_school_detail" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_detail"."school_id" IS '学校ID'; +COMMENT +ON COLUMN "public"."art_school_detail"."school_icon" IS '校徽图标'; +COMMENT +ON COLUMN "public"."art_school_detail"."postcode" IS '邮政编码'; +COMMENT +ON COLUMN "public"."art_school_detail"."establish_year" IS '建校年份'; +COMMENT +ON COLUMN "public"."art_school_detail"."campus_area_mu" IS '占地面积(亩)'; +COMMENT +ON COLUMN "public"."art_school_detail"."library_collection" IS '图书馆藏书量'; +COMMENT +ON COLUMN "public"."art_school_detail"."is_985" IS '是否985:0否1是'; +COMMENT +ON COLUMN "public"."art_school_detail"."is_211" IS '是否211:0否1是'; +COMMENT +ON COLUMN "public"."art_school_detail"."is_double_first_class" IS '是否双一流:0否1是'; +COMMENT +ON COLUMN "public"."art_school_detail"."is_key_university" IS '省重点高校'; +COMMENT +ON COLUMN "public"."art_school_detail"."tags" IS '学校标签数组'; +COMMENT +ON COLUMN "public"."art_school_detail"."student_count" IS '在校学生数'; +COMMENT +ON COLUMN "public"."art_school_detail"."teacher_count" IS '教职工人数'; +COMMENT +ON COLUMN "public"."art_school_detail"."master_point" IS '硕士点数量'; +COMMENT +ON COLUMN "public"."art_school_detail"."doctor_point" IS '博士点数量'; +COMMENT +ON COLUMN "public"."art_school_detail"."key_major_count" IS '国家级重点专业数'; +COMMENT +ON COLUMN "public"."art_school_detail"."employment_rate" IS '就业率%'; +COMMENT +ON COLUMN "public"."art_school_detail"."satisfaction_rate" IS '院校满意度%'; +COMMENT +ON COLUMN "public"."art_school_detail"."back_ground" IS '页面显示背景图'; +COMMENT +ON COLUMN "public"."art_school_detail"."is_public" IS '是否公办:0 否 1 是'; +COMMENT +ON COLUMN "public"."art_school_detail"."master_proportion_rate" IS '考研率'; +COMMENT +ON COLUMN "public"."art_school_detail"."abroad_proportion_rate" IS '出国率'; +COMMENT +ON COLUMN "public"."art_school_detail"."has_regular" IS '是否有普通本科:0否1是'; +COMMENT +ON COLUMN "public"."art_school_detail"."has_junior" IS '是否有专科:0否1是'; +COMMENT +ON COLUMN "public"."art_school_detail"."has_master" IS '是否有硕士点:0否1是'; +COMMENT +ON COLUMN "public"."art_school_detail"."is_double_high_plan" IS '是否双高计划:0否1是'; +COMMENT +ON COLUMN "public"."art_school_detail"."is_strong_plan" IS '是否强基计划:0否1是'; +COMMENT +ON COLUMN "public"."art_school_detail"."twsdl_rank" IS '泰晤士中国排名'; +COMMENT +ON COLUMN "public"."art_school_detail"."xyh_rank" IS '校友会排名'; +COMMENT +ON COLUMN "public"."art_school_detail"."wsl_rank" IS '武书连排名'; +COMMENT +ON COLUMN "public"."art_school_detail"."usdalu_rank" IS 'US中国排名'; +COMMENT +ON COLUMN "public"."art_school_detail"."qsdalu_rank" IS 'QS排名'; +COMMENT +ON TABLE "public"."art_school_detail" IS '学校完整详情表(扩展字段全部放这里)'; + +-- ---------------------------- +-- Table structure for art_school_dorm +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_dorm"; +CREATE TABLE "public"."art_school_dorm" +( + "dorm_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" DEFAULT '000000'::character varying, + "campus_id" int8 NOT NULL, + "room_size" int2, + "bunk_bed_desk" int2 DEFAULT '0'::smallint, + "private_bath" int2 DEFAULT '0'::smallint, + "tags" varchar(256) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "description" varchar(512) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "del_flag" char(1) COLLATE "pg_catalog"."default" DEFAULT '0'::bpchar, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying +) +; +ALTER TABLE "public"."art_school_dorm" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_dorm"."dorm_id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_dorm"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_dorm"."campus_id" IS '校区ID'; +COMMENT +ON COLUMN "public"."art_school_dorm"."room_size" IS '几人间(4/6/8...)'; +COMMENT +ON COLUMN "public"."art_school_dorm"."bunk_bed_desk" IS '是否上床下桌(0否1是)'; +COMMENT +ON COLUMN "public"."art_school_dorm"."private_bath" IS '是否独立卫浴(0否1是)'; +COMMENT +ON COLUMN "public"."art_school_dorm"."tags" IS '宿舍标签(冗余文本:空调/热水/洗衣房...)'; +COMMENT +ON COLUMN "public"."art_school_dorm"."description" IS '补充说明'; +COMMENT +ON COLUMN "public"."art_school_dorm"."del_flag" IS '删除标志(0代表存在 1代表删除)'; +COMMENT +ON COLUMN "public"."art_school_dorm"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_dorm"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_school_dorm"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_dorm"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_school_dorm"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_school_dorm"."remark" IS '备注'; +COMMENT +ON TABLE "public"."art_school_dorm" IS '校区宿舍条件表'; + +-- ---------------------------- +-- Table structure for art_school_enroll_code +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_enroll_code"; +CREATE TABLE "public"."art_school_enroll_code" +( + "id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "school_id" int8 NOT NULL, + "enroll_code" varchar(32) COLLATE "pg_catalog"."default" NOT NULL +) +; +ALTER TABLE "public"."art_school_enroll_code" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_enroll_code"."id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_enroll_code"."school_id" IS '关联学校主表ID'; +COMMENT +ON COLUMN "public"."art_school_enroll_code"."enroll_code" IS '招生代码/学校代码(旧表核心关联字段)'; +COMMENT +ON TABLE "public"."art_school_enroll_code" IS '学校招生代码表'; + +-- ---------------------------- +-- Table structure for art_school_enroll_plan +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_enroll_plan"; +CREATE TABLE "public"."art_school_enroll_plan" +( + "plan_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" DEFAULT '000000'::character varying, + "school_id" int8 NOT NULL, + "year" int2 NOT NULL, + "province" varchar(32) COLLATE "pg_catalog"."default" NOT NULL, + "subject_type" varchar(16) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "major_id" int8, + "major_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, + "education_level" varchar(16) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "plan_num" int4 NOT NULL, + "del_flag" char(1) COLLATE "pg_catalog"."default" DEFAULT '0'::bpchar, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying +) +; +ALTER TABLE "public"."art_school_enroll_plan" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."plan_id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."school_id" IS '学校ID'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."year" IS '年份'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."province" IS '招生省份'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."subject_type" IS '分科:文/理/综(或物理/历史...)'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."major_id" IS '专业ID(可选,有则填)'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."major_name" IS '专业名称(冗余,没专业ID也能落库)'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."education_level" IS '学历层次:本科/专科'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."plan_num" IS '计划数'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."del_flag" IS '删除标志(0代表存在 1代表删除)'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_school_enroll_plan"."remark" IS '备注'; +COMMENT +ON TABLE "public"."art_school_enroll_plan" IS '学校招生计划表'; + +-- ---------------------------- +-- Table structure for art_school_major +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_major"; +CREATE TABLE "public"."art_school_major" +( + "school_major_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" DEFAULT '000000'::character varying, + "school_id" int8 NOT NULL, + "college_id" int8, + "major_code" varchar(32) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "major_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, + "education_level" varchar(16) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "duration_years" int2, + "major_category" varchar(32) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "degree_type" varchar(32) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "introduction" text COLLATE "pg_catalog"."default", + "tags" varchar(128) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "del_flag" char(1) COLLATE "pg_catalog"."default" DEFAULT '0'::bpchar, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "major51sdx_id" varchar(32) COLLATE "pg_catalog"."default" +) +; +ALTER TABLE "public"."art_school_major" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_major"."school_major_id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_major"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_major"."school_id" IS '学校ID(冗余便于查)'; +COMMENT +ON COLUMN "public"."art_school_major"."college_id" IS '学院ID'; +COMMENT +ON COLUMN "public"."art_school_major"."major_code" IS '专业编码(可选)'; +COMMENT +ON COLUMN "public"."art_school_major"."major_name" IS '专业名称'; +COMMENT +ON COLUMN "public"."art_school_major"."education_level" IS '学历层次:本科/专科'; +COMMENT +ON COLUMN "public"."art_school_major"."duration_years" IS '学制(3/4/5)'; +COMMENT +ON COLUMN "public"."art_school_major"."major_category" IS '专业类别:工学/理学/艺术学...'; +COMMENT +ON COLUMN "public"."art_school_major"."degree_type" IS '学位类型:工学学士/理学学士/艺术学学士...'; +COMMENT +ON COLUMN "public"."art_school_major"."introduction" IS '专业介绍'; +COMMENT +ON COLUMN "public"."art_school_major"."tags" IS '专业标签'; +COMMENT +ON COLUMN "public"."art_school_major"."del_flag" IS '删除标志(0代表存在 1代表删除)'; +COMMENT +ON COLUMN "public"."art_school_major"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_major"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_school_major"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_major"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_school_major"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_school_major"."remark" IS '备注'; +COMMENT +ON TABLE "public"."art_school_major" IS '学校专业表'; + +-- ---------------------------- +-- Table structure for art_school_major_tag +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_major_tag"; +CREATE TABLE "public"."art_school_major_tag" +( + "major_tag_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '000000'::character varying, + "major_id" int8 NOT NULL, + "tag_name" varchar(64) COLLATE "pg_catalog"."default" NOT NULL, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "del_flag" char(1) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '0'::bpchar, + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "active_key" int2 GENERATED ALWAYS AS ( + + CASE + WHEN (del_flag = '0'::bpchar) THEN 1 + ELSE NULL ::integer +END +) STORED +) +; +ALTER TABLE "public"."art_school_major_tag" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_major_tag"."major_tag_id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."major_id" IS '专业ID'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."tag_name" IS '标签名称'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."create_by" IS '创建人'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."update_by" IS '更新人'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."del_flag" IS '删除标志(0存在 1删除)'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."remark" IS '备注'; +COMMENT +ON COLUMN "public"."art_school_major_tag"."active_key" IS '仅用于唯一约束'; +COMMENT +ON TABLE "public"."art_school_major_tag" IS '专业标签表'; + +-- ---------------------------- +-- Table structure for art_school_media +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_media"; +CREATE TABLE "public"."art_school_media" +( + "media_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" DEFAULT '000000'::character varying, + "biz_type" varchar(32) COLLATE "pg_catalog"."default" NOT NULL, + "biz_id" int8 NOT NULL, + "media_type" int2 NOT NULL, + "url" varchar(512) COLLATE "pg_catalog"."default" NOT NULL, + "cover_url" varchar(512) COLLATE "pg_catalog"."default" DEFAULT ''::character varying, + "sort_no" int4 DEFAULT 0, + "del_flag" char(1) COLLATE "pg_catalog"."default" DEFAULT '0'::bpchar, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying +) +; +ALTER TABLE "public"."art_school_media" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_media"."media_id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_media"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_media"."biz_type" IS '业务类型:school/campus/college/major/dorm'; +COMMENT +ON COLUMN "public"."art_school_media"."biz_id" IS '业务主键ID'; +COMMENT +ON COLUMN "public"."art_school_media"."media_type" IS '媒体类型:1-图片 2-视频'; +COMMENT +ON COLUMN "public"."art_school_media"."url" IS '资源URL'; +COMMENT +ON COLUMN "public"."art_school_media"."cover_url" IS '封面URL(视频可用)'; +COMMENT +ON COLUMN "public"."art_school_media"."sort_no" IS '排序'; +COMMENT +ON COLUMN "public"."art_school_media"."del_flag" IS '删除标志(0代表存在 1代表删除)'; +COMMENT +ON COLUMN "public"."art_school_media"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_media"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_school_media"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_media"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_school_media"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_school_media"."remark" IS '备注'; +COMMENT +ON TABLE "public"."art_school_media" IS '学校媒体资源表(图片/视频)'; + +-- ---------------------------- +-- Table structure for art_school_name +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_name"; +CREATE TABLE "public"."art_school_name" +( + "school_name_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" DEFAULT '000000'::character varying, + "school_id" int8 NOT NULL, + "name" varchar(64) COLLATE "pg_catalog"."default" NOT NULL, + "name_type" int2 NOT NULL, + "name_update_date" int4, + "del_flag" char(1) COLLATE "pg_catalog"."default" DEFAULT '0'::bpchar, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying +) +; +ALTER TABLE "public"."art_school_name" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_name"."school_name_id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_name"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_name"."school_id" IS '关联学校主表ID'; +COMMENT +ON COLUMN "public"."art_school_name"."name" IS '学校名称(曾用名/别名)'; +COMMENT +ON COLUMN "public"."art_school_name"."name_type" IS '名称类型:1-官方全称 2-曾用名 3-别名 4-英文名称'; +COMMENT +ON COLUMN "public"."art_school_name"."name_update_date" IS '更新日期'; +COMMENT +ON COLUMN "public"."art_school_name"."del_flag" IS '删除标志(0代表存在 1代表删除)'; +COMMENT +ON COLUMN "public"."art_school_name"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_name"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_school_name"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_name"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_school_name"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_school_name"."remark" IS '备注'; +COMMENT +ON TABLE "public"."art_school_name" IS '学校多名称表'; + +-- ---------------------------- +-- Table structure for art_school_recruit_major +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_recruit_major"; +CREATE TABLE "public"."art_school_recruit_major" +( + "recruit_major_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '000000'::character varying, + "del_flag" char(1) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '0'::bpchar, + "school_id" int8 NOT NULL, + "school_code" varchar(32) COLLATE "pg_catalog"."default" NOT NULL, + "school_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying, + "year" int2 NOT NULL, + "major_id" int8, + "major_code" varchar(32) COLLATE "pg_catalog"."default" NOT NULL, + "major_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, + "enroll_code" varchar(64) COLLATE "pg_catalog"."default" NOT NULL DEFAULT ''::character varying, + "data_status" varchar(16) COLLATE "pg_catalog"."default" NOT NULL, + "batch_name" varchar(32) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "major_type" varchar(32) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "major_type_sub" varchar(32) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "subject_type" varchar(16) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "admission_way_short" varchar(32) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "admission_way_external" varchar(64) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "admission_way_external_op" varchar(8) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "admission_way_internal" varchar(64) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "admission_way_internal_op" varchar(8) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "plan_enroll" int4, + "main_exam_subject" varchar(64) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "schooling_years" int2, + "enroll_limit_desc" text COLLATE "pg_catalog"."default", + "tuition_fee" numeric(10, 2) DEFAULT NULL::numeric, + "culture_score_limit" numeric(6, 2) DEFAULT NULL::numeric, + "major_score_limit" numeric(6, 2) DEFAULT NULL::numeric, + "chinese_score_limit" numeric(6, 2) DEFAULT NULL::numeric, + "english_score_limit" numeric(6, 2) DEFAULT NULL::numeric, + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6) +) +; +ALTER TABLE "public"."art_school_recruit_major" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."recruit_major_id" IS '院校招录专业ID'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."del_flag" IS '删除标志(0存在 1删除)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."school_id" IS '学校ID'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."school_code" IS '学校代码'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."school_name" IS '学校名称(冗余)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."year" IS '年份'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."major_id" IS '专业ID'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."major_code" IS '专业代码'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."major_name" IS '专业名称'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."enroll_code" IS '招生代码(为空则存空串)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."data_status" IS '数据状态(停招/新招/新增)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."batch_name" IS '批次'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."major_type" IS '专业类型'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."major_type_sub" IS '二级专业类型'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."subject_type" IS '科类(文/理)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."admission_way_short" IS '录取方式缩写'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."admission_way_external" IS '对外录取方式'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."admission_way_external_op" IS '对外录取方式运算符'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."admission_way_internal" IS '内部录取方式'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."admission_way_internal_op" IS '内部录取方式运算符'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."plan_enroll" IS '计划招生人数'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."main_exam_subject" IS '主考科目'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."schooling_years" IS '学制(年)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."enroll_limit_desc" IS '院校限制说明'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."tuition_fee" IS '学费(元/年)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."culture_score_limit" IS '文化分数限制'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."major_score_limit" IS '专业分数限制'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."chinese_score_limit" IS '语文成绩限制'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."english_score_limit" IS '英语成绩限制'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."remark" IS '备注'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_school_recruit_major"."update_time" IS '更新时间'; +COMMENT +ON TABLE "public"."art_school_recruit_major" IS '院校招录专业'; + +-- ---------------------------- +-- Table structure for art_school_recruit_major_history +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_recruit_major_history"; +CREATE TABLE "public"."art_school_recruit_major_history" +( + "history_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '000000'::character varying, + "del_flag" char(1) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '0'::bpchar, + "recruit_major_id" int8 NOT NULL, + "school_id" int8 NOT NULL, + "school_code" varchar(32) COLLATE "pg_catalog"."default" NOT NULL, + "college_code" varchar(32) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "school_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, + "major_id" int8, + "major_code" varchar(32) COLLATE "pg_catalog"."default" NOT NULL, + "major_name" varchar(128) COLLATE "pg_catalog"."default" NOT NULL, + "enroll_code" varchar(64) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "major_type" varchar(32) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "major_type_sub" varchar(32) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "main_exam_subject" varchar(64) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "year" int2 NOT NULL, + "subject_type" varchar(16) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "batch_name" varchar(32) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "admission_formula" varchar(64) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "probability_operator" varchar(16) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "control_score" numeric(6, 2) DEFAULT NULL::numeric, + "admission_score" numeric(6, 2) DEFAULT NULL::numeric, + "plan_enroll" int4, + "filed_amount" int4, + "admit_amount" int4, + "first_choice_admit_amount" int4, + "min_score_diff" numeric(6, 2) DEFAULT NULL::numeric, + "tuition_fee" numeric(10, 2) DEFAULT NULL::numeric, + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6) +) +; +ALTER TABLE "public"."art_school_recruit_major_history" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."history_id" IS '历年录取数据ID'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."del_flag" IS '删除标志(0存在 1删除)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."recruit_major_id" IS '对应招录专业ID'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."school_id" IS '学校ID'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."school_code" IS '学校代码'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."college_code" IS '院校代码'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."school_name" IS '学校名称'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."major_id" IS '专业ID'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."major_code" IS '专业代码'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."major_name" IS '专业名称'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."enroll_code" IS '招生代码'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."major_type" IS '专业类型'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."major_type_sub" IS '专业类别子级'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."main_exam_subject" IS '主考科目'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."year" IS '年份'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."subject_type" IS '科类(文/理)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."batch_name" IS '批次'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."admission_formula" IS '录取方式(文*x+专*y)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."probability_operator" IS '录取概率规则运算符'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."control_score" IS '省控线'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."admission_score" IS '录取线'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."plan_enroll" IS '招生人数'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."filed_amount" IS '实际投档人数'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."admit_amount" IS '录取数'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."first_choice_admit_amount" IS '一志愿录取数'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."min_score_diff" IS '最低分数差'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."tuition_fee" IS '学费(元/年)'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."remark" IS '备注'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."create_by" IS '创建者'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."update_by" IS '更新者'; +COMMENT +ON COLUMN "public"."art_school_recruit_major_history"."update_time" IS '更新时间'; +COMMENT +ON TABLE "public"."art_school_recruit_major_history" IS '院校招录专业历年录取数据'; + +-- ---------------------------- +-- Table structure for art_school_tag +-- ---------------------------- +DROP TABLE IF EXISTS "public"."art_school_tag"; +CREATE TABLE "public"."art_school_tag" +( + "school_tag_id" int8 NOT NULL GENERATED BY DEFAULT AS IDENTITY ( + INCREMENT 1 +MINVALUE 1 +MAXVALUE 9223372036854775807 +START 1 +CACHE 1 +), + "tenant_id" varchar(20) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '000000'::character varying, + "school_id" int8 NOT NULL, + "tag_name" varchar(64) COLLATE "pg_catalog"."default" NOT NULL, + "create_dept" int8, + "create_by" int8, + "create_time" timestamp(6), + "update_by" int8, + "update_time" timestamp(6), + "del_flag" char(1) COLLATE "pg_catalog"."default" NOT NULL DEFAULT '0'::bpchar, + "remark" varchar(500) COLLATE "pg_catalog"."default" DEFAULT NULL::character varying, + "active_key" int2 GENERATED ALWAYS AS ( + + CASE + WHEN (del_flag = '0'::bpchar) THEN 1 + ELSE NULL ::integer +END +) STORED +) +; +ALTER TABLE "public"."art_school_tag" OWNER TO "user_3W72AM"; +COMMENT +ON COLUMN "public"."art_school_tag"."school_tag_id" IS '主键ID'; +COMMENT +ON COLUMN "public"."art_school_tag"."tenant_id" IS '租户编号'; +COMMENT +ON COLUMN "public"."art_school_tag"."school_id" IS '学校ID'; +COMMENT +ON COLUMN "public"."art_school_tag"."tag_name" IS '标签名称'; +COMMENT +ON COLUMN "public"."art_school_tag"."create_dept" IS '创建部门'; +COMMENT +ON COLUMN "public"."art_school_tag"."create_by" IS '创建人'; +COMMENT +ON COLUMN "public"."art_school_tag"."create_time" IS '创建时间'; +COMMENT +ON COLUMN "public"."art_school_tag"."update_by" IS '更新人'; +COMMENT +ON COLUMN "public"."art_school_tag"."update_time" IS '更新时间'; +COMMENT +ON COLUMN "public"."art_school_tag"."del_flag" IS '删除标志(0存在 1删除)'; +COMMENT +ON COLUMN "public"."art_school_tag"."remark" IS '备注'; +COMMENT +ON COLUMN "public"."art_school_tag"."active_key" IS '仅用于唯一约束'; +COMMENT +ON TABLE "public"."art_school_tag" IS '学校标签表'; + +-- ---------------------------- +-- Indexes structure for table art_history_score_control_line +-- ---------------------------- +CREATE INDEX "idx_control_tenant" ON "public"."art_history_score_control_line" USING btree ( + "tenant_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_control_year" ON "public"."art_history_score_control_line" USING btree ( + "year" "pg_catalog"."int2_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_history_score_control_line +-- ---------------------------- +ALTER TABLE "public"."art_history_score_control_line" + ADD CONSTRAINT "uk_control_province_year" UNIQUE ("province_code", "year", "subject_type", "major_category", + "batch_name"); + +-- ---------------------------- +-- Primary Key structure for table art_history_score_control_line +-- ---------------------------- +ALTER TABLE "public"."art_history_score_control_line" + ADD CONSTRAINT "art_history_score_control_line_pkey" PRIMARY KEY ("control_id"); + +-- ---------------------------- +-- Indexes structure for table art_major +-- ---------------------------- +CREATE INDEX "idx_major_level" ON "public"."art_major" USING btree ( + "education_level" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_major_tenant" ON "public"."art_major" USING btree ( + "tenant_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_major +-- ---------------------------- +ALTER TABLE "public"."art_major" + ADD CONSTRAINT "uk_major_name_level" UNIQUE ("major_name", "education_level"); + +-- ---------------------------- +-- Primary Key structure for table art_major +-- ---------------------------- +ALTER TABLE "public"."art_major" + ADD CONSTRAINT "art_major_pkey" PRIMARY KEY ("major_id"); + +-- ---------------------------- +-- Indexes structure for table art_school +-- ---------------------------- +CREATE INDEX "idx_main_name" ON "public"."art_school" USING btree ( + "main_name" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_school_level_nature" ON "public"."art_school" USING btree ( + "education_level" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "school_nature" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_school_region" ON "public"."art_school" USING btree ( + "province" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "city" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "district" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_school_type" ON "public"."art_school" USING btree ( + "university_type" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_school +-- ---------------------------- +ALTER TABLE "public"."art_school" + ADD CONSTRAINT "uk_code" UNIQUE ("main_code"); + +-- ---------------------------- +-- Primary Key structure for table art_school +-- ---------------------------- +ALTER TABLE "public"."art_school" + ADD CONSTRAINT "art_school_pkey" PRIMARY KEY ("school_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_campus +-- ---------------------------- +CREATE INDEX "idx_campus_school_id" ON "public"."art_school_campus" USING btree ( + "school_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_school_campus +-- ---------------------------- +ALTER TABLE "public"."art_school_campus" + ADD CONSTRAINT "uk_school_campus_name" UNIQUE ("school_id", "campus_name"); + +-- ---------------------------- +-- Primary Key structure for table art_school_campus +-- ---------------------------- +ALTER TABLE "public"."art_school_campus" + ADD CONSTRAINT "art_school_campus_pkey" PRIMARY KEY ("campus_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_college +-- ---------------------------- +CREATE INDEX "idx_college_school_id" ON "public"."art_school_college" USING btree ( + "school_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_school_college +-- ---------------------------- +ALTER TABLE "public"."art_school_college" + ADD CONSTRAINT "uk_school_college_name" UNIQUE ("school_id", "college_name"); + +-- ---------------------------- +-- Primary Key structure for table art_school_college +-- ---------------------------- +ALTER TABLE "public"."art_school_college" + ADD CONSTRAINT "art_school_college_pkey" PRIMARY KEY ("college_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_detail +-- ---------------------------- +CREATE INDEX "idx_school_detail_school_id" ON "public"."art_school_detail" USING btree ( + "school_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_school_detail_tags" ON "public"."art_school_detail" USING gin ( + "tags" COLLATE "pg_catalog"."default" "pg_catalog"."array_ops" + ); + +-- ---------------------------- +-- Uniques structure for table art_school_detail +-- ---------------------------- +ALTER TABLE "public"."art_school_detail" + ADD CONSTRAINT "uk_school_id" UNIQUE ("school_id"); + +-- ---------------------------- +-- Primary Key structure for table art_school_detail +-- ---------------------------- +ALTER TABLE "public"."art_school_detail" + ADD CONSTRAINT "art_school_detail_pkey" PRIMARY KEY ("detail_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_dorm +-- ---------------------------- +CREATE INDEX "idx_dorm_campus_id" ON "public"."art_school_dorm" USING btree ( + "campus_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Primary Key structure for table art_school_dorm +-- ---------------------------- +ALTER TABLE "public"."art_school_dorm" + ADD CONSTRAINT "art_school_dorm_pkey" PRIMARY KEY ("dorm_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_enroll_code +-- ---------------------------- +CREATE INDEX "idx_enroll_code" ON "public"."art_school_enroll_code" USING btree ( + "enroll_code" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_school_enroll_code +-- ---------------------------- +ALTER TABLE "public"."art_school_enroll_code" + ADD CONSTRAINT "uk_school_code" UNIQUE ("school_id", "enroll_code"); + +-- ---------------------------- +-- Primary Key structure for table art_school_enroll_code +-- ---------------------------- +ALTER TABLE "public"."art_school_enroll_code" + ADD CONSTRAINT "art_school_enroll_code_pkey" PRIMARY KEY ("id"); + +-- ---------------------------- +-- Indexes structure for table art_school_enroll_plan +-- ---------------------------- +CREATE INDEX "idx_plan_school_year" ON "public"."art_school_enroll_plan" USING btree ( + "school_id" "pg_catalog"."int8_ops" ASC NULLS LAST, + "year" "pg_catalog"."int2_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_plan_year_province" ON "public"."art_school_enroll_plan" USING btree ( + "year" "pg_catalog"."int2_ops" ASC NULLS LAST, + "province" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_school_enroll_plan +-- ---------------------------- +ALTER TABLE "public"."art_school_enroll_plan" + ADD CONSTRAINT "uk_plan_unique" UNIQUE ("school_id", "year", "province", "subject_type", "major_name", + "education_level"); + +-- ---------------------------- +-- Primary Key structure for table art_school_enroll_plan +-- ---------------------------- +ALTER TABLE "public"."art_school_enroll_plan" + ADD CONSTRAINT "art_school_enroll_plan_pkey" PRIMARY KEY ("plan_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_major +-- ---------------------------- +CREATE INDEX "idx_major_college_id" ON "public"."art_school_major" USING btree ( + "college_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_major_school_id" ON "public"."art_school_major" USING btree ( + "school_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_school_major +-- ---------------------------- +ALTER TABLE "public"."art_school_major" + ADD CONSTRAINT "uk_college_major_name" UNIQUE ("college_id", "major_name"); + +-- ---------------------------- +-- Primary Key structure for table art_school_major +-- ---------------------------- +ALTER TABLE "public"."art_school_major" + ADD CONSTRAINT "art_school_major_pkey" PRIMARY KEY ("school_major_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_major_tag +-- ---------------------------- +CREATE INDEX "idx_major_tag_filter" ON "public"."art_school_major_tag" USING btree ( + "tenant_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "del_flag" COLLATE "pg_catalog"."default" "pg_catalog"."bpchar_ops" ASC NULLS LAST, + "tag_name" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "major_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_major_tag_major" ON "public"."art_school_major_tag" USING btree ( + "tenant_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "del_flag" COLLATE "pg_catalog"."default" "pg_catalog"."bpchar_ops" ASC NULLS LAST, + "major_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_school_major_tag +-- ---------------------------- +ALTER TABLE "public"."art_school_major_tag" + ADD CONSTRAINT "uk_major_tag_active" UNIQUE ("tenant_id", "major_id", "tag_name", "active_key"); + +-- ---------------------------- +-- Primary Key structure for table art_school_major_tag +-- ---------------------------- +ALTER TABLE "public"."art_school_major_tag" + ADD CONSTRAINT "art_school_major_tag_pkey" PRIMARY KEY ("major_tag_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_media +-- ---------------------------- +CREATE INDEX "idx_media_biz" ON "public"."art_school_media" USING btree ( + "biz_type" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "biz_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_media_type" ON "public"."art_school_media" USING btree ( + "media_type" "pg_catalog"."int2_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Primary Key structure for table art_school_media +-- ---------------------------- +ALTER TABLE "public"."art_school_media" + ADD CONSTRAINT "art_school_media_pkey" PRIMARY KEY ("media_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_name +-- ---------------------------- +CREATE INDEX "idx_name" ON "public"."art_school_name" USING btree ( + "name" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_school_name_id" ON "public"."art_school_name" USING btree ( + "school_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Primary Key structure for table art_school_name +-- ---------------------------- +ALTER TABLE "public"."art_school_name" + ADD CONSTRAINT "art_school_name_pkey" PRIMARY KEY ("school_name_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_recruit_major +-- ---------------------------- +CREATE INDEX "idx_recruit_major_code" ON "public"."art_school_recruit_major" USING btree ( + "major_code" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "year" "pg_catalog"."int2_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_recruit_school_code" ON "public"."art_school_recruit_major" USING btree ( + "school_code" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "year" "pg_catalog"."int2_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_recruit_tenant" ON "public"."art_school_recruit_major" USING btree ( + "tenant_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_school_recruit_major +-- ---------------------------- +ALTER TABLE "public"."art_school_recruit_major" + ADD CONSTRAINT "uk_recruit_school_year" UNIQUE ("school_id", "year", "major_code", "enroll_code"); + +-- ---------------------------- +-- Primary Key structure for table art_school_recruit_major +-- ---------------------------- +ALTER TABLE "public"."art_school_recruit_major" + ADD CONSTRAINT "art_school_recruit_major_pkey" PRIMARY KEY ("recruit_major_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_recruit_major_history +-- ---------------------------- +CREATE INDEX "idx_history_recruit_year" ON "public"."art_school_recruit_major_history" USING btree ( + "recruit_major_id" "pg_catalog"."int8_ops" ASC NULLS LAST, + "year" "pg_catalog"."int2_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_history_school_year" ON "public"."art_school_recruit_major_history" USING btree ( + "school_id" "pg_catalog"."int8_ops" ASC NULLS LAST, + "year" "pg_catalog"."int2_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_history_subject_batch" ON "public"."art_school_recruit_major_history" USING btree ( + "subject_type" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "batch_name" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_history_tenant" ON "public"."art_school_recruit_major_history" USING btree ( + "tenant_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Primary Key structure for table art_school_recruit_major_history +-- ---------------------------- +ALTER TABLE "public"."art_school_recruit_major_history" + ADD CONSTRAINT "art_school_recruit_major_history_pkey" PRIMARY KEY ("history_id"); + +-- ---------------------------- +-- Indexes structure for table art_school_tag +-- ---------------------------- +CREATE INDEX "idx_school_tag_filter" ON "public"."art_school_tag" USING btree ( + "tenant_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "del_flag" COLLATE "pg_catalog"."default" "pg_catalog"."bpchar_ops" ASC NULLS LAST, + "tag_name" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "school_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); +CREATE INDEX "idx_school_tag_school" ON "public"."art_school_tag" USING btree ( + "tenant_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST, + "del_flag" COLLATE "pg_catalog"."default" "pg_catalog"."bpchar_ops" ASC NULLS LAST, + "school_id" "pg_catalog"."int8_ops" ASC NULLS LAST + ); + +-- ---------------------------- +-- Uniques structure for table art_school_tag +-- ---------------------------- +ALTER TABLE "public"."art_school_tag" + ADD CONSTRAINT "uk_school_tag_active" UNIQUE ("tenant_id", "school_id", "tag_name", "active_key"); + +-- ---------------------------- +-- Primary Key structure for table art_school_tag +-- ---------------------------- +ALTER TABLE "public"."art_school_tag" + ADD CONSTRAINT "art_school_tag_pkey" PRIMARY KEY ("school_tag_id"); + +-- ---------------------------- +-- Foreign Keys structure for table art_school_recruit_major_history +-- ---------------------------- +ALTER TABLE "public"."art_school_recruit_major_history" + ADD CONSTRAINT "fk_history_recruit" FOREIGN KEY ("recruit_major_id") REFERENCES "public"."art_school_recruit_major" ("recruit_major_id") ON DELETE NO ACTION ON UPDATE NO ACTION; diff --git a/docs/score_new_table.sql b/docs/score_new_table.sql new file mode 100644 index 0000000..0182ce2 --- /dev/null +++ b/docs/score_new_table.sql @@ -0,0 +1,145 @@ +DROP TABLE IF EXISTS `art_history_score_control_line`; +CREATE TABLE `art_history_score_control_line` ( + `control_id` bigint NOT NULL AUTO_INCREMENT COMMENT '省控线主键', + `tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号', + `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 1删除)', + `province_code` varchar(6) NOT NULL COMMENT '省份行政区划代码', + `province_name` varchar(32) NOT NULL COMMENT '省份名称', + `year` smallint NOT NULL COMMENT '年份', + `major_category` varchar(25) NOT NULL COMMENT '专业类别', + `batch_name` varchar(25) NOT NULL COMMENT '批次', + `subject_type` varchar(16) NOT NULL COMMENT '科类(文/理)', + `culture_score` decimal(6,2) DEFAULT NULL COMMENT '文化成绩分数', + `major_score` decimal(6,2) DEFAULT NULL COMMENT '专业成绩分数', + `culture_score_exam` decimal(6,2) DEFAULT NULL COMMENT '文化成绩校考分数', + `major_score_exam` decimal(6,2) DEFAULT NULL COMMENT '专业成绩校考分数', + `create_dept` bigint DEFAULT NULL COMMENT '创建部门', + `create_by` bigint DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`control_id`), + UNIQUE KEY `uk_control_province_year` + (`province_code`,`year`,`subject_type`,`major_category`,`batch_name`), + KEY `idx_control_year` (`year`), + KEY `idx_control_tenant` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='历 + 年省控线表'; + +DROP TABLE IF EXISTS `art_major`; +CREATE TABLE `art_major` ( + `major_id` bigint NOT NULL AUTO_INCREMENT COMMENT '专业主键ID', + `tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号', + `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 1删除)', + `major_name` varchar(128) NOT NULL COMMENT '专业名称', + `education_level` varchar(16) NOT NULL COMMENT '学历层次', + `major_icon` varchar(255) DEFAULT NULL COMMENT '专业图标', + `schooling_years` tinyint DEFAULT NULL COMMENT '学制(年)', + `discipline_primary` varchar(64) DEFAULT NULL COMMENT '所属一级学科', + `discipline_secondary` varchar(64) DEFAULT NULL COMMENT '所属二级学科', + `degree_awarded` varchar(64) DEFAULT NULL COMMENT '授予学士学位', + `summary` varchar(1000) DEFAULT NULL COMMENT '专业概括', + `training_direction` text COMMENT '培养方向', + `core_courses` text COMMENT '主要课程', + `create_dept` bigint DEFAULT NULL COMMENT '创建部门', + `create_by` bigint DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`major_id`), + UNIQUE KEY `uk_major_name_level` (`major_name`,`education_level`), + KEY `idx_major_level` (`education_level`), + KEY `idx_major_tenant` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='艺 + 术专业库'; + +DROP TABLE IF EXISTS `art_school_recruit_major`; +CREATE TABLE `art_school_recruit_major` ( + `recruit_major_id` bigint NOT NULL AUTO_INCREMENT COMMENT '院校招录专业ID', + `tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号', + `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 1删除)', + `school_id` bigint NOT NULL COMMENT '学校ID', + `school_code` varchar(32) NOT NULL COMMENT '学校代码', + `school_name` varchar(128) NOT NULL DEFAULT '' COMMENT '学校名称(冗余)', + `year` smallint NOT NULL COMMENT '年份', + `major_id` bigint DEFAULT NULL COMMENT '专业ID', + `major_code` varchar(32) NOT NULL COMMENT '专业代码', + `major_name` varchar(128) NOT NULL COMMENT '专业名称', + `enroll_code` varchar(64) NOT NULL DEFAULT '' COMMENT '招生代码(为空则存空串)', + `data_status` varchar(16) NOT NULL COMMENT '数据状态(停招/新招/新增)', + `batch_name` varchar(32) DEFAULT NULL COMMENT '批次', + `major_type` varchar(32) DEFAULT NULL COMMENT '专业类型', + `major_type_sub` varchar(32) DEFAULT NULL COMMENT '二级专业类型', + `subject_type` varchar(16) DEFAULT NULL COMMENT '科类(文/理)', + `admission_way_short` varchar(32) DEFAULT NULL COMMENT '录取方式缩写', + `admission_way_external` varchar(64) DEFAULT NULL COMMENT '对外录取方式', + `admission_way_external_op` varchar(8) DEFAULT NULL COMMENT '对外录取方式运算符', + `admission_way_internal` varchar(64) DEFAULT NULL COMMENT '内部录取方式', + `admission_way_internal_op` varchar(8) DEFAULT NULL COMMENT '内部录取方式运算符', + `plan_enroll` int DEFAULT NULL COMMENT '计划招生人数', + `main_exam_subject` varchar(64) DEFAULT NULL COMMENT '主考科目', + `schooling_years` tinyint DEFAULT NULL COMMENT '学制(年)', + `enroll_limit_desc` text COMMENT '院校限制说明', + `tuition_fee` decimal(10,2) DEFAULT NULL COMMENT '学费(元/年)', + `culture_score_limit` decimal(6,2) DEFAULT NULL COMMENT '文化分数限制', + `major_score_limit` decimal(6,2) DEFAULT NULL COMMENT '专业分数限制', + `chinese_score_limit` decimal(6,2) DEFAULT NULL COMMENT '语文成绩限制', + `english_score_limit` decimal(6,2) DEFAULT NULL COMMENT '英语成绩限制', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `create_dept` bigint DEFAULT NULL COMMENT '创建部门', + `create_by` bigint DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`recruit_major_id`), + UNIQUE KEY `uk_recruit_school_year` (`school_id`,`year`,`major_code`,`enroll_code`), + KEY `idx_recruit_school_code` (`school_code`,`year`), + KEY `idx_recruit_major_code` (`major_code`,`year`), + KEY `idx_recruit_tenant` (`tenant_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='院校招录专业'; + +DROP TABLE IF EXISTS `art_school_recruit_history`; +CREATE TABLE `art_school_recruit_history` ( + `history_id` bigint NOT NULL AUTO_INCREMENT COMMENT '历年录取数据ID', + `tenant_id` varchar(20) NOT NULL DEFAULT '000000' COMMENT '租户编号', + `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 1删除)', + `recruit_major_id` bigint NOT NULL COMMENT '对应招录专业ID', + `school_id` bigint NOT NULL COMMENT '学校ID', + `school_code` varchar(32) NOT NULL COMMENT '学校代码', + `college_code` varchar(32) DEFAULT NULL COMMENT '院校代码', + `school_name` varchar(128) NOT NULL COMMENT '学校名称', + `major_id` bigint DEFAULT NULL COMMENT '专业ID', + `major_code` varchar(32) NOT NULL COMMENT '专业代码', + `major_name` varchar(128) NOT NULL COMMENT '专业名称', + `enroll_code` varchar(64) DEFAULT NULL COMMENT '招生代码', + `major_type` varchar(32) DEFAULT NULL COMMENT '专业类型', + `major_type_sub` varchar(32) DEFAULT NULL COMMENT '专业类别子级', + `main_exam_subject` varchar(64) DEFAULT NULL COMMENT '主考科目', + `year` smallint NOT NULL COMMENT '年份', + `subject_type` varchar(16) DEFAULT NULL COMMENT '科类(文/理)', + `batch_name` varchar(32) DEFAULT NULL COMMENT '批次', + `admission_formula` varchar(64) DEFAULT NULL COMMENT '录取方式(文*x+专*y)', + `probability_operator` varchar(16) DEFAULT NULL COMMENT '录取概率规则运算符', + `control_score` decimal(6,2) DEFAULT NULL COMMENT '省控线', + `admission_score` decimal(6,2) DEFAULT NULL COMMENT '录取线', + `plan_enroll` int DEFAULT NULL COMMENT '招生人数', + `filed_amount` int DEFAULT NULL COMMENT '实际投档人数', + `admit_amount` int DEFAULT NULL COMMENT '录取数', + `first_choice_admit_amount` int DEFAULT NULL COMMENT '一志愿录取数', + `min_score_diff` decimal(6,2) DEFAULT NULL COMMENT '最低分数差', + `tuition_fee` decimal(10,2) DEFAULT NULL COMMENT '学费(元/年)', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + `create_dept` bigint DEFAULT NULL COMMENT '创建部门', + `create_by` bigint DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + PRIMARY KEY (`history_id`), + KEY `idx_history_school_year` (`school_id`,`year`), + KEY `idx_history_recruit_year` (`recruit_major_id`,`year`), + KEY `idx_history_subject_batch` (`subject_type`,`batch_name`), + KEY `idx_history_tenant` (`tenant_id`), + CONSTRAINT `fk_history_recruit` FOREIGN KEY (`recruit_major_id`) REFERENCES `art_school_recruit_major` (`recruit_major_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='院校招录专业历年录取数据'; \ No newline at end of file diff --git a/docs/score_newtable_task.md b/docs/score_newtable_task.md new file mode 100644 index 0000000..c67baa7 --- /dev/null +++ b/docs/score_newtable_task.md @@ -0,0 +1,93 @@ +参考当前通用实体类表 +```sql +CREATE TABLE `sys_xxx` ( + `xxx_id` bigint NOT NULL COMMENT 'XXXID', + `tenant_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '000000' COMMENT '租户编号', + `del_flag` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '0' COMMENT '删除标志(0代表存在 1代表删除)', + `create_dept` bigint DEFAULT NULL COMMENT '创建部门', + `create_by` bigint DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`xxx_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='基础信息表'; +``` + + +#### 新建 历年省控线表 artHistoryScoreControlLine +年份(4位) +专业类别(25位) +批次(25位) +文科/理科 +文化成绩分数(0.00 ~ 1000.00) +专业成绩分数(0.00 ~ 1000.00) +文化成绩分数校考(0.00 ~ 1000.00) +专业成绩分数校考(0.00 ~ 1000.00) + +#### 新建专业库 artMajor +专业名称 +学历层次(本科/高职高专/职业本科) +专业图标 +学制 +所属一级学科 +所属二级学科 +所得学士学位 +专业概括 +培养方向 +主要课程 + +#### 院校招录专业 +数据状态(停招/新招/新增) +学校代码 +专业代码 +专业名称 +招生代码 +学费 +备注 +科类(文科/理科) +录取方式缩写(用于筛选条件) +对外录取方式 +对外录取方式运算符 +内部录取方式 +内部录取方式运算符 +批次 +专业类型 +二级专业类型 +计划招生(人数) +主考科目 +学制(1/2/3/4/5) +院校限制(文本) +文化分数限制(0.00 ~ 1000.00) +专业分数限制(0.00 ~ 1000.00) +语文成绩限制(0.00 ~ 1000.00) +英语成绩限制(0.00 ~ 1000.00) + + +#### 历年录取数据(针对院校招录专业表的历年录取分数信息) +学校代码 +院校代码 +学校名称 +专业代码 +专业名称 +招生代码 +专业类型 +专业类别子级 +主考科目 +年份 +科类(文科/理科) +批次 +录取方式(文*x+专*y) +录取概率计算规则运算符 +省控线 +录取线 +招生人数 +实际投档人数 +录取数 +一志愿录取数 +最低分数差 +学费 +备注 + + +我原本想法是,招录专业和历年数据是用 院校代码跟学校的代码表关联,这俩表数据是直接展示给前台用户,你觉得设计上有问题吗? diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d649201 --- /dev/null +++ b/pom.xml @@ -0,0 +1,505 @@ + + + 4.0.0 + + org.dromara + ruoyi-vue-plus + ${revision} + + RuoYi-Vue-Plus + https://gitee.com/dromara/RuoYi-Vue-Plus + Dromara RuoYi-Vue-Plus多租户管理系统 + + + 5.5.3 + 3.5.9 + UTF-8 + UTF-8 + 17 + 3.5.19 + 2.8.15 + 0.15.0 + 1.3.0 + 2.3 + 1.44.0 + 3.5.16 + 3.9.1 + 5.8.43 + 3.5.6 + 3.52.0 + 2.2.7 + 4.3.1 + 1.9.0 + 1.5.0 + 0.2.0 + 1.18.42 + 1.80 + 1.16.7 + + 3.3.2 + + 2.28.22 + + 3.3.5 + + 1.2.83 + + 8.7.3-20251210 + + 1.8.4 + + + 3.4.2 + 3.4.0 + 3.14.0 + 3.5.3 + 1.3.0 + + true + + + + + local + + + local + info + ruoyi + 123456 + + + + dev + + + dev + info + ruoyi + 123456 + + + + true + + + + prod + + prod + warn + ruoyi + 123456 + + + + + + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + + cn.hutool + hutool-bom + ${hutool.version} + pom + import + + + + + org.dromara + ruoyi-common-bom + ${revision} + pom + import + + + + org.springdoc + springdoc-openapi-starter-webmvc-api + ${springdoc.version} + + + + com.github.therapi + therapi-runtime-javadoc + ${therapi-javadoc.version} + + + + org.projectlombok + lombok + ${lombok.version} + + + + cn.idev.excel + fastexcel + ${fastexcel.version} + + + + + org.apache.velocity + velocity-engine-core + ${velocity.version} + + + + + cn.dev33 + sa-token-spring-boot3-starter + ${satoken.version} + + + + cn.dev33 + sa-token-jwt + ${satoken.version} + + + cn.hutool + hutool-all + + + + + cn.dev33 + sa-token-core + ${satoken.version} + + + + + com.baomidou + dynamic-datasource-spring-boot3-starter + ${dynamic-ds.version} + + + + org.mybatis + mybatis + ${mybatis.version} + + + + com.baomidou + mybatis-plus-spring-boot3-starter + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-jsqlparser + ${mybatis-plus.version} + + + + com.baomidou + mybatis-plus-annotation + ${mybatis-plus.version} + + + + + p6spy + p6spy + ${p6spy.version} + + + + + software.amazon.awssdk + s3 + ${aws.sdk.version} + + + + software.amazon.awssdk + s3-transfer-manager + ${aws.sdk.version} + + + + software.amazon.awssdk + netty-nio-client + ${aws.sdk.version} + + + + org.dromara.sms4j + sms4j-spring-boot-starter + ${sms4j.version} + + + + de.codecentric + spring-boot-admin-starter-server + ${spring-boot-admin.version} + + + de.codecentric + spring-boot-admin-starter-client + ${spring-boot-admin.version} + + + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + + com.baomidou + lock4j-redisson-spring-boot-starter + ${lock4j.version} + + + + + com.aizuda + snail-job-client-starter + ${snailjob.version} + + + com.aizuda + snail-job-client-job-core + ${snailjob.version} + + + + + org.bouncycastle + bcprov-jdk15to18 + ${bouncycastle.version} + + + + io.github.linpeilie + mapstruct-plus-spring-boot-starter + ${mapstruct-plus.version} + + + + + org.dromara.warm + warm-flow-mybatis-plus-sb3-starter + ${warm-flow.version} + + + org.dromara.warm + warm-flow-plugin-ui-sb-web + ${warm-flow.version} + + + + + me.zhyd.oauth + JustAuth + ${justauth.version} + + + + + org.lionsoul + ip2region + ${ip2region.version} + + + + com.alibaba + fastjson + ${fastjson.version} + + + + org.dromara + ruoyi-system + ${revision} + + + + org.dromara + ruoyi-job + ${revision} + + + + org.dromara + ruoyi-generator + ${revision} + + + + org.dromara + ruoyi-demo + ${revision} + + + + org.dromara + ruoyi-art + ${revision} + + + + + org.dromara + ruoyi-workflow + ${revision} + + + + + + + ruoyi-admin + ruoyi-common + ruoyi-extend + ruoyi-modules + + pom + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + ${java.version} + ${project.build.sourceEncoding} + + + com.github.therapi + therapi-runtime-javadoc-scribe + ${therapi-javadoc.version} + + + org.projectlombok + lombok + ${lombok.version} + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + + + io.github.linpeilie + mapstruct-plus-processor + ${mapstruct-plus.version} + + + org.projectlombok + lombok-mapstruct-binding + ${mapstruct-plus.lombok.version} + + + + -parameters + + + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + -Dfile.encoding=UTF-8 + + ${profiles.active} + + exclude + + + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten-maven-plugin.version} + + true + resolveCiFriendliesOnly + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + + + src/main/resources + + false + + + src/main/resources + + + application* + bootstrap* + banner* + + + true + + + + + + + public + huawei nexus + https://mirrors.huaweicloud.com/repository/maven/ + + true + + + + + + + public + huawei nexus + https://mirrors.huaweicloud.com/repository/maven/ + + true + + + false + + + + + + diff --git a/ruoyi-admin/Dockerfile b/ruoyi-admin/Dockerfile new file mode 100644 index 0000000..0394ccb --- /dev/null +++ b/ruoyi-admin/Dockerfile @@ -0,0 +1,31 @@ +# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/ +FROM bellsoft/liberica-openjdk-rocky:17.0.16-cds +#FROM bellsoft/liberica-openjdk-rocky:21.0.8-cds +#FROM findepi/graalvm:java17-native + +LABEL maintainer="Lion Li" + +RUN mkdir -p /ruoyi/server/logs \ + /ruoyi/server/temp \ + /ruoyi/skywalking/agent + +WORKDIR /ruoyi/server + +ENV SERVER_PORT=8080 SNAIL_PORT=28080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS="" + +EXPOSE ${SERVER_PORT} +# 暴露 snail job 客户端端口 用于定时任务调度中心通信 +EXPOSE ${SNAIL_PORT} + +ADD ./target/ruoyi-admin.jar ./app.jar + +SHELL ["/bin/bash", "-c"] + +ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \ + -Dsnail-job.port=${SNAIL_PORT} \ + # 应用名称 如果想区分集群节点监控 改成不同的名称即可 + #-Dskywalking.agent.service_name=ruoyi-server \ + #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \ + -XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \ + -jar app.jar + diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml new file mode 100644 index 0000000..bd6388c --- /dev/null +++ b/ruoyi-admin/pom.xml @@ -0,0 +1,165 @@ + + + + ruoyi-vue-plus + org.dromara + ${revision} + + 4.0.0 + jar + ruoyi-admin + + + web服务入口 + + + + + + + com.mysql + mysql-connector-j + + + + + org.postgresql + postgresql + + + + + + + + + + + + + + + + + + + + + + + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-social + + + + org.dromara + ruoyi-common-ratelimiter + + + + org.dromara + ruoyi-common-mail + + + + org.dromara + ruoyi-system + + + + org.dromara + ruoyi-job + + + + + org.dromara + ruoyi-generator + + + + + org.dromara + ruoyi-demo + + + + + org.dromara + ruoyi-art + + + + + org.dromara + ruoyi-workflow + + + + de.codecentric + spring-boot-admin-starter-client + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + + + + + + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + ${project.artifactId} + + + + + + diff --git a/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java b/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java new file mode 100644 index 0000000..8ef33fe --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java @@ -0,0 +1,23 @@ +package org.dromara; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; + +/** + * 启动程序 + * + * @author Lion Li + */ + +@SpringBootApplication +public class DromaraApplication { + + public static void main(String[] args) { + SpringApplication application = new SpringApplication(DromaraApplication.class); + application.setApplicationStartup(new BufferingApplicationStartup(2048)); + application.run(args); + System.out.println("(♥◠‿◠)ノ゙ RuoYi-Vue-Plus启动成功 ლ(´ڡ`ლ)゙"); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java b/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java new file mode 100644 index 0000000..066a683 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/DromaraServletInitializer.java @@ -0,0 +1,18 @@ +package org.dromara; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; + +/** + * web容器中进行部署 + * + * @author Lion Li + */ +public class DromaraServletInitializer extends SpringBootServletInitializer { + + @Override + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { + return application.sources(DromaraApplication.class); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java new file mode 100644 index 0000000..c448a60 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/AuthController.java @@ -0,0 +1,243 @@ +package org.dromara.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.codec.Base64; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.utils.AuthStateUtils; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.domain.model.LoginBody; +import org.dromara.common.core.domain.model.RegisterBody; +import org.dromara.common.core.domain.model.SocialLoginBody; +import org.dromara.common.core.utils.*; +import org.dromara.common.encrypt.annotation.ApiEncrypt; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.ratelimiter.annotation.RateLimiter; +import org.dromara.common.ratelimiter.enums.LimitType; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.social.config.properties.SocialLoginConfigProperties; +import org.dromara.common.social.config.properties.SocialProperties; +import org.dromara.common.social.utils.SocialUtils; +import org.dromara.common.sse.dto.SseMessageDto; +import org.dromara.common.sse.utils.SseMessageUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.bo.SysTenantBo; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysTenantVo; +import org.dromara.system.service.ISysClientService; +import org.dromara.system.service.ISysConfigService; +import org.dromara.system.service.ISysSocialService; +import org.dromara.system.service.ISysTenantService; +import org.dromara.web.domain.vo.LoginTenantVo; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.domain.vo.TenantListVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.dromara.web.service.SysRegisterService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * 认证 + * + * @author Lion Li + */ +@Slf4j +@SaIgnore +@RequiredArgsConstructor +@RestController +@RequestMapping("/auth") +public class AuthController { + + private final SocialProperties socialProperties; + private final SysLoginService loginService; + private final SysRegisterService registerService; + private final ISysConfigService configService; + private final ISysTenantService tenantService; + private final ISysSocialService socialUserService; + private final ISysClientService clientService; + private final ScheduledExecutorService scheduledExecutorService; + + + /** + * 登录方法 + * + * @param body 登录信息 + * @return 结果 + */ + @ApiEncrypt + @PostMapping("/login") + public R login(@RequestBody String body) { + LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class); + ValidatorUtils.validate(loginBody); + // 授权类型和客户端id + String clientId = loginBody.getClientId(); + String grantType = loginBody.getGrantType(); + SysClientVo client = clientService.queryByClientId(clientId); + // 查询不到 client 或 client 内不包含 grantType + if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) { + log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType); + return R.fail(MessageUtils.message("auth.grant.type.error")); + } else if (!SystemConstants.NORMAL.equals(client.getStatus())) { + return R.fail(MessageUtils.message("auth.grant.type.blocked")); + } + // 校验租户 + loginService.checkTenant(loginBody.getTenantId()); + // 登录 + LoginVo loginVo = IAuthStrategy.login(body, client, grantType); + + Long userId = LoginHelper.getUserId(); + scheduledExecutorService.schedule(() -> { + SseMessageDto dto = new SseMessageDto(); + dto.setMessage(DateUtils.getTodayHour(new Date()) + "好,欢迎登录 RuoYi-Vue-Plus 后台管理系统"); + dto.setUserIds(List.of(userId)); + SseMessageUtils.publishMessage(dto); + }, 5, TimeUnit.SECONDS); + return R.ok(loginVo); + } + + /** + * 获取跳转URL + * + * @param source 登录来源 + * @return 结果 + */ + @GetMapping("/binding/{source}") + public R authBinding(@PathVariable("source") String source, + @RequestParam String tenantId, @RequestParam String domain) { + SocialLoginConfigProperties obj = socialProperties.getType().get(source); + if (ObjectUtil.isNull(obj)) { + return R.fail(source + "平台账号暂不支持"); + } + AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties); + Map map = new HashMap<>(); + map.put("tenantId", tenantId); + map.put("domain", domain); + map.put("state", AuthStateUtils.createState()); + String authorizeUrl = authRequest.authorize(Base64.encode(JsonUtils.toJsonString(map), StandardCharsets.UTF_8)); + return R.ok("操作成功", authorizeUrl); + } + + /** + * 前端回调绑定授权(需要token) + * + * @param loginBody 请求体 + * @return 结果 + */ + @PostMapping("/social/callback") + public R socialCallback(@RequestBody SocialLoginBody loginBody) { + // 校验token + StpUtil.checkLogin(); + // 获取第三方登录信息 + AuthResponse response = SocialUtils.loginAuth( + loginBody.getSource(), loginBody.getSocialCode(), + loginBody.getSocialState(), socialProperties); + AuthUser authUserData = response.getData(); + // 判断授权响应是否成功 + if (!response.ok()) { + return R.fail(response.getMsg()); + } + loginService.socialRegister(authUserData); + return R.ok(); + } + + + /** + * 取消授权(需要token) + * + * @param socialId socialId + */ + @DeleteMapping(value = "/unlock/{socialId}") + public R unlockSocial(@PathVariable Long socialId) { + // 校验token + StpUtil.checkLogin(); + Boolean rows = socialUserService.deleteWithValidById(socialId); + return rows ? R.ok() : R.fail("取消授权失败"); + } + + + /** + * 退出登录 + */ + @PostMapping("/logout") + public R logout() { + loginService.logout(); + return R.ok("退出成功"); + } + + /** + * 用户注册 + */ + @ApiEncrypt + @PostMapping("/register") + public R register(@Validated @RequestBody RegisterBody user) { + if (!configService.selectRegisterEnabled(user.getTenantId())) { + return R.fail("当前系统没有开启注册功能!"); + } + registerService.register(user); + return R.ok(); + } + + /** + * 登录页面租户下拉框 + * + * @return 租户列表 + */ + @RateLimiter(time = 60, count = 20, limitType = LimitType.IP) + @GetMapping("/tenant/list") + public R tenantList(HttpServletRequest request) throws Exception { + // 返回对象 + LoginTenantVo result = new LoginTenantVo(); + boolean enable = TenantHelper.isEnable(); + result.setTenantEnabled(enable); + // 如果未开启租户这直接返回 + if (!enable) { + return R.ok(result); + } + + List tenantList = tenantService.queryList(new SysTenantBo()); + List voList = MapstructUtils.convert(tenantList, TenantListVo.class); + try { + // 如果只超管返回所有租户 + if (LoginHelper.isSuperAdmin()) { + result.setVoList(voList); + return R.ok(result); + } + } catch (NotLoginException ignored) { + } + + // 获取域名 + String host; + String referer = request.getHeader("referer"); + if (StringUtils.isNotBlank(referer)) { + // 这里从referer中取值是为了本地使用hosts添加虚拟域名,方便本地环境调试 + host = referer.split("//")[1].split("/")[0]; + } else { + host = new URL(request.getRequestURL().toString()).getHost(); + } + // 根据域名进行筛选 + List list = StreamUtils.filter(voList, vo -> + StringUtils.equalsIgnoreCase(vo.getDomain(), host)); + result.setVoList(CollUtil.isNotEmpty(list) ? list : voList); + return R.ok(result); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java new file mode 100644 index 0000000..2586add --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java @@ -0,0 +1,160 @@ +package org.dromara.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import cn.hutool.captcha.generator.CodeGenerator; +import cn.hutool.captcha.generator.MathGenerator; +import cn.hutool.captcha.generator.RandomGenerator; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; +import jakarta.validation.constraints.NotBlank; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mail.config.properties.MailProperties; +import org.dromara.common.mail.utils.MailUtils; +import org.dromara.common.ratelimiter.annotation.RateLimiter; +import org.dromara.common.ratelimiter.enums.LimitType; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.web.core.WaveAndCircleCaptcha; +import org.dromara.common.web.config.properties.CaptchaProperties; +import org.dromara.sms4j.api.SmsBlend; +import org.dromara.sms4j.api.entity.SmsResponse; +import org.dromara.sms4j.core.factory.SmsFactory; +import org.dromara.web.domain.vo.CaptchaVo; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.awt.*; +import java.time.Duration; +import java.util.LinkedHashMap; + +/** + * 验证码操作处理 + * + * @author Lion Li + */ +@SaIgnore +@Slf4j +@Validated +@RequiredArgsConstructor +@RestController +public class CaptchaController { + + private final CaptchaProperties captchaProperties; + private final MailProperties mailProperties; + + /** + * 短信验证码 + * + * @param phonenumber 用户手机号 + */ + @RateLimiter(key = "#phonenumber", time = 60, count = 1) + @GetMapping("/resource/sms/code") + public R smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { + String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber; + String code = RandomUtil.randomNumbers(4); + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + // 验证码模板id 自行处理 (查数据库或写死均可) + String templateId = ""; + LinkedHashMap map = new LinkedHashMap<>(1); + map.put("code", code); + SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); + SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map); + if (!smsResponse.isSuccess()) { + log.error("验证码短信发送异常 => {}", smsResponse); + return R.fail(smsResponse.getData().toString()); + } + return R.ok(); + } + + /** + * 邮箱验证码 + * + * @param email 邮箱 + */ + @GetMapping("/resource/email/code") + public R emailCode(@NotBlank(message = "{user.email.not.blank}") String email) { + if (!mailProperties.getEnabled()) { + return R.fail("当前系统没有开启邮箱功能!"); + } + SpringUtils.getAopProxy(this).emailCodeImpl(email); + return R.ok(); + } + + /** + * 邮箱验证码 + * 独立方法避免验证码关闭之后仍然走限流 + */ + @RateLimiter(key = "#email", time = 60, count = 1) + public void emailCodeImpl(String email) { + String key = GlobalConstants.CAPTCHA_CODE_KEY + email; + String code = RandomUtil.randomNumbers(4); + RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + try { + MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。"); + } catch (Exception e) { + log.error("验证码短信发送异常 => {}", e.getMessage()); + throw new ServiceException(e.getMessage()); + } + } + + /** + * 生成验证码 + */ + @GetMapping("/auth/code") + public R getCode() { + boolean captchaEnabled = captchaProperties.getEnable(); + if (!captchaEnabled) { + CaptchaVo captchaVo = new CaptchaVo(); + captchaVo.setCaptchaEnabled(false); + return R.ok(captchaVo); + } + return R.ok(SpringUtils.getAopProxy(this).getCodeImpl()); + } + + /** + * 生成验证码 + * 独立方法避免验证码关闭之后仍然走限流 + */ + @RateLimiter(time = 60, count = 10, limitType = LimitType.IP) + public CaptchaVo getCodeImpl() { + // 保存验证码信息 + String uuid = IdUtil.simpleUUID(); + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; + // 生成验证码 + String captchaType = captchaProperties.getType(); + CodeGenerator codeGenerator; + if ("math".equals(captchaType)) { + codeGenerator = new MathGenerator(captchaProperties.getNumberLength(), false); + } else { + codeGenerator = new RandomGenerator(captchaProperties.getCharLength()); + } + WaveAndCircleCaptcha captcha = new WaveAndCircleCaptcha(160, 60); + // captcha.setBackground(Color.WHITE); // 不设置就是透明底 + captcha.setFont(new Font("Arial", Font.BOLD, 45)); + captcha.setGenerator(codeGenerator); + captcha.createCode(); + // 如果是数学验证码,使用SpEL表达式处理验证码结果 + String code = captcha.getCode(); + if ("math".equals(captchaType)) { + ExpressionParser parser = new SpelExpressionParser(); + Expression exp = parser.parseExpression(StringUtils.remove(code, "=")); + code = exp.getValue(String.class); + } + RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); + CaptchaVo captchaVo = new CaptchaVo(); + captchaVo.setUuid(uuid); + captchaVo.setImg(captcha.getImageBase64()); + return captchaVo; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java b/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java new file mode 100644 index 0000000..cdcfed6 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/controller/IndexController.java @@ -0,0 +1,28 @@ +package org.dromara.web.controller; + +import cn.dev33.satoken.annotation.SaIgnore; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 首页 + * + * @author Lion Li + */ +@SaIgnore +@RequiredArgsConstructor +@RestController +public class IndexController { + + /** + * 访问首页,提示语 + */ + @GetMapping("/") + public String index() { + return StringUtils.format("欢迎使用{}后台管理框架,请通过前端地址访问。", SpringUtils.getApplicationName()); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java new file mode 100644 index 0000000..664df1e --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/CaptchaVo.java @@ -0,0 +1,25 @@ +package org.dromara.web.domain.vo; + +import lombok.Data; + +/** + * 验证码信息 + * + * @author Michelle.Chung + */ +@Data +public class CaptchaVo { + + /** + * 是否开启验证码 + */ + private Boolean captchaEnabled = true; + + private String uuid; + + /** + * 验证码图片 + */ + private String img; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java new file mode 100644 index 0000000..0a83ace --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginTenantVo.java @@ -0,0 +1,25 @@ +package org.dromara.web.domain.vo; + +import lombok.Data; + +import java.util.List; + +/** + * 登录租户对象 + * + * @author Michelle.Chung + */ +@Data +public class LoginTenantVo { + + /** + * 租户开关 + */ + private Boolean tenantEnabled; + + /** + * 租户对象列表 + */ + private List voList; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java new file mode 100644 index 0000000..834afe5 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/LoginVo.java @@ -0,0 +1,54 @@ +package org.dromara.web.domain.vo; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 登录验证信息 + * + * @author Michelle.Chung + */ +@Data +public class LoginVo { + + /** + * 授权令牌 + */ + @JsonProperty("access_token") + private String accessToken; + + /** + * 刷新令牌 + */ + @JsonProperty("refresh_token") + private String refreshToken; + + /** + * 授权令牌 access_token 的有效期 + */ + @JsonProperty("expire_in") + private Long expireIn; + + /** + * 刷新令牌 refresh_token 的有效期 + */ + @JsonProperty("refresh_expire_in") + private Long refreshExpireIn; + + /** + * 应用id + */ + @JsonProperty("client_id") + private String clientId; + + /** + * 令牌权限 + */ + private String scope; + + /** + * 用户 openid + */ + private String openid; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java new file mode 100644 index 0000000..db9c271 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/domain/vo/TenantListVo.java @@ -0,0 +1,31 @@ +package org.dromara.web.domain.vo; + +import org.dromara.system.domain.vo.SysTenantVo; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; + +/** + * 租户列表 + * + * @author Lion Li + */ +@Data +@AutoMapper(target = SysTenantVo.class) +public class TenantListVo { + + /** + * 租户编号 + */ + private String tenantId; + + /** + * 企业名称 + */ + private String companyName; + + /** + * 域名 + */ + private String domain; + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java new file mode 100644 index 0000000..6c8accb --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java @@ -0,0 +1,163 @@ +package org.dromara.web.listener; + +import cn.dev33.satoken.listener.SaTokenListener; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.hutool.core.convert.Convert; +import cn.hutool.http.useragent.UserAgent; +import cn.hutool.http.useragent.UserAgentUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.domain.dto.UserOnlineDTO; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.ip.AddressUtils; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Component; + +import java.time.Duration; + +/** + * 用户行为 侦听器的实现 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Component +@Slf4j +public class UserActionListener implements SaTokenListener { + + private final SysLoginService loginService; + + /** + * 每次登录时触发 + */ + @Override + public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginParameter loginParameter) { + UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent")); + String ip = ServletUtils.getClientIP(); + UserOnlineDTO dto = new UserOnlineDTO(); + dto.setIpaddr(ip); + dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); + dto.setBrowser(userAgent.getBrowser().getName()); + dto.setOs(userAgent.getOs().getName()); + dto.setLoginTime(System.currentTimeMillis()); + dto.setTokenId(tokenValue); + String username = (String) loginParameter.getExtra(LoginHelper.USER_NAME_KEY); + String tenantId = (String) loginParameter.getExtra(LoginHelper.TENANT_KEY); + dto.setUserName(username); + dto.setClientKey((String) loginParameter.getExtra(LoginHelper.CLIENT_KEY)); + dto.setDeviceType(loginParameter.getDeviceType()); + dto.setDeptName((String) loginParameter.getExtra(LoginHelper.DEPT_NAME_KEY)); + TenantHelper.dynamic(tenantId, () -> { + if(loginParameter.getTimeout() == -1) { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto); + } else { + RedisUtils.setCacheObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(loginParameter.getTimeout())); + } + }); + // 记录登录日志 + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(Constants.LOGIN_SUCCESS); + logininforEvent.setMessage(MessageUtils.message("user.login.success")); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + // 更新登录信息 + loginService.recordLoginInfo((Long) loginParameter.getExtra(LoginHelper.USER_KEY), ip); + log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次注销时触发 + */ + @Override + public void doLogout(String loginType, Object loginId, String tokenValue) { + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); + log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被踢下线时触发 + */ + @Override + public void doKickout(String loginType, Object loginId, String tokenValue) { + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); + log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被顶下线时触发 + */ + @Override + public void doReplaced(String loginType, Object loginId, String tokenValue) { + String tenantId = Convert.toStr(StpUtil.getExtra(tokenValue, LoginHelper.TENANT_KEY)); + TenantHelper.dynamic(tenantId, () -> { + RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue); + }); + log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue); + } + + /** + * 每次被封禁时触发 + */ + @Override + public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) { + } + + /** + * 每次被解封时触发 + */ + @Override + public void doUntieDisable(String loginType, Object loginId, String service) { + } + + /** + * 每次打开二级认证时触发 + */ + @Override + public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) { + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCloseSafe(String loginType, String tokenValue, String service) { + } + + /** + * 每次创建Session时触发 + */ + @Override + public void doCreateSession(String id) { + } + + /** + * 每次注销Session时触发 + */ + @Override + public void doLogoutSession(String id) { + } + + /** + * 每次Token续期时触发 + */ + @Override + public void doRenewTimeout(String loginType, Object loginId, String tokenValue, long timeout) { + } +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java new file mode 100644 index 0000000..a75b913 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/IAuthStrategy.java @@ -0,0 +1,46 @@ +package org.dromara.web.service; + + +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.system.domain.SysClient; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.web.domain.vo.LoginVo; + +/** + * 授权策略 + * + * @author Michelle.Chung + */ +public interface IAuthStrategy { + + String BASE_NAME = "AuthStrategy"; + + /** + * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @param grantType 授权类型 + * @return 登录验证信息 + */ + static LoginVo login(String body, SysClientVo client, String grantType) { + // 授权类型和客户端id + String beanName = grantType + BASE_NAME; + if (!SpringUtils.containsBean(beanName)) { + throw new ServiceException("授权类型不正确!"); + } + IAuthStrategy instance = SpringUtils.getBean(beanName); + return instance.login(body, client); + } + + /** + * 登录 + * + * @param body 登录对象 + * @param client 授权管理视图对象 + * @return 登录验证信息 + */ + LoginVo login(String body, SysClientVo client); + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java new file mode 100644 index 0000000..41a802b --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java @@ -0,0 +1,251 @@ +package org.dromara.web.service; + +import cn.dev33.satoken.exception.NotLoginException; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.lang.Opt; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.lock.annotation.Lock4j; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthUser; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.dto.PostDTO; +import org.dromara.common.core.domain.dto.RoleDTO; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.*; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.mybatis.helper.DataPermissionHelper; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.exception.TenantException; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysSocialBo; +import org.dromara.system.domain.vo.*; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.util.Date; +import java.util.List; +import java.util.function.Supplier; + +/** + * 登录校验方法 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Slf4j +@Service +public class SysLoginService { + + @Value("${user.password.maxRetryCount}") + private Integer maxRetryCount; + + @Value("${user.password.lockTime}") + private Integer lockTime; + + private final ISysTenantService tenantService; + private final ISysPermissionService permissionService; + private final ISysSocialService sysSocialService; + private final ISysRoleService roleService; + private final ISysDeptService deptService; + private final ISysPostService postService; + private final SysUserMapper userMapper; + + + /** + * 绑定第三方用户 + * + * @param authUserData 授权响应实体 + */ + @Lock4j + public void socialRegister(AuthUser authUserData) { + String authId = authUserData.getSource() + authUserData.getUuid(); + // 第三方用户信息 + SysSocialBo bo = BeanUtil.toBean(authUserData, SysSocialBo.class); + BeanUtil.copyProperties(authUserData.getToken(), bo); + Long userId = LoginHelper.getUserId(); + bo.setUserId(userId); + bo.setAuthId(authId); + bo.setOpenId(authUserData.getUuid()); + bo.setUserName(authUserData.getUsername()); + bo.setNickName(authUserData.getNickname()); + List checkList = sysSocialService.selectByAuthId(authId); + if (CollUtil.isNotEmpty(checkList)) { + throw new ServiceException("此三方账号已经被绑定!"); + } + // 查询是否已经绑定用户 + SysSocialBo params = new SysSocialBo(); + params.setUserId(userId); + params.setSource(bo.getSource()); + List list = sysSocialService.queryList(params); + if (CollUtil.isEmpty(list)) { + // 没有绑定用户, 新增用户信息 + sysSocialService.insertByBo(bo); + } else { + // 更新用户信息 + bo.setId(list.get(0).getId()); + sysSocialService.updateByBo(bo); + // 如果要绑定的平台账号已经被绑定过了 是否抛异常自行决断 + // throw new ServiceException("此平台账号已经被绑定!"); + } + } + + + /** + * 退出登录 + */ + public void logout() { + try { + LoginUser loginUser = LoginHelper.getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + return; + } + if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) { + // 超级管理员 登出清除动态租户 + TenantHelper.clearDynamic(); + } + recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success")); + } catch (NotLoginException ignored) { + } finally { + try { + StpUtil.logout(); + } catch (NotLoginException ignored) { + } + } + } + + /** + * 记录登录信息 + * + * @param tenantId 租户ID + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + */ + public void recordLogininfor(String tenantId, String username, String status, String message) { + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(status); + logininforEvent.setMessage(message); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + } + + /** + * 构建登录用户 + */ + public LoginUser buildLoginUser(SysUserVo user) { + LoginUser loginUser = new LoginUser(); + Long userId = user.getUserId(); + loginUser.setTenantId(user.getTenantId()); + loginUser.setUserId(userId); + loginUser.setDeptId(user.getDeptId()); + loginUser.setUsername(user.getUserName()); + loginUser.setNickname(user.getNickName()); + loginUser.setUserType(user.getUserType()); + loginUser.setMenuPermission(permissionService.getMenuPermission(userId)); + loginUser.setRolePermission(permissionService.getRolePermission(userId)); + if (ObjectUtil.isNotNull(user.getDeptId())) { + Opt deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById); + loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY)); + loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY)); + } + List roles = roleService.selectRolesByUserId(userId); + List posts = postService.selectPostsByUserId(userId); + loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class)); + loginUser.setPosts(BeanUtil.copyToList(posts, PostDTO.class)); + return loginUser; + } + + /** + * 记录登录信息 + * + * @param userId 用户ID + */ + public void recordLoginInfo(Long userId, String ip) { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(ip); + sysUser.setLoginDate(DateUtils.getNowDate()); + sysUser.setUpdateBy(userId); + DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser)); + } + + /** + * 登录校验 + */ + public void checkLogin(LoginType loginType, String tenantId, String username, Supplier supplier) { + String errorKey = CacheConstants.PWD_ERR_CNT_KEY + username; + String loginFail = Constants.LOGIN_FAIL; + + // 获取用户登录错误次数,默认为0 (可自定义限制策略 例如: key + username + ip) + int errorNumber = ObjectUtil.defaultIfNull(RedisUtils.getCacheObject(errorKey), 0); + // 锁定时间内登录 则踢出 + if (errorNumber >= maxRetryCount) { + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } + + if (supplier.get()) { + // 错误次数递增 + errorNumber++; + RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(lockTime)); + // 达到规定错误次数 则锁定登录 + if (errorNumber >= maxRetryCount) { + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), maxRetryCount, lockTime)); + throw new UserException(loginType.getRetryLimitExceed(), maxRetryCount, lockTime); + } else { + // 未达到规定错误次数 + recordLogininfor(tenantId, username, loginFail, MessageUtils.message(loginType.getRetryLimitCount(), errorNumber)); + throw new UserException(loginType.getRetryLimitCount(), errorNumber); + } + } + + // 登录成功 清空错误次数 + RedisUtils.deleteObject(errorKey); + } + + /** + * 校验租户 + * + * @param tenantId 租户ID + */ + public void checkTenant(String tenantId) { + if (!TenantHelper.isEnable()) { + return; + } + if (StringUtils.isBlank(tenantId)) { + throw new TenantException("tenant.number.not.blank"); + } + if (TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) { + return; + } + SysTenantVo tenant = tenantService.queryByTenantId(tenantId); + if (ObjectUtil.isNull(tenant)) { + log.info("登录租户:{} 不存在.", tenantId); + throw new TenantException("tenant.not.exists"); + } else if (SystemConstants.DISABLE.equals(tenant.getStatus())) { + log.info("登录租户:{} 已被停用.", tenantId); + throw new TenantException("tenant.blocked"); + } else if (ObjectUtil.isNotNull(tenant.getExpireTime()) + && new Date().after(tenant.getExpireTime())) { + log.info("登录租户:{} 已超过有效期.", tenantId); + throw new TenantException("tenant.expired"); + } + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java new file mode 100644 index 0000000..5a3351d --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java @@ -0,0 +1,115 @@ +package org.dromara.web.service; + +import cn.hutool.crypto.digest.BCrypt; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.domain.model.RegisterBody; +import org.dromara.common.core.enums.UserType; +import org.dromara.common.core.exception.user.CaptchaException; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.ServletUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.log.event.LogininforEvent; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.web.config.properties.CaptchaProperties; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.bo.SysUserBo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysUserService; +import org.springframework.stereotype.Service; + +/** + * 注册校验方法 + * + * @author Lion Li + */ +@RequiredArgsConstructor +@Service +public class SysRegisterService { + + private final ISysUserService userService; + private final SysUserMapper userMapper; + private final CaptchaProperties captchaProperties; + + /** + * 注册 + */ + public void register(RegisterBody registerBody) { + String tenantId = registerBody.getTenantId(); + String username = registerBody.getUsername(); + String password = registerBody.getPassword(); + // 校验用户类型是否存在 + String userType = UserType.getUserType(registerBody.getUserType()).getUserType(); + + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(tenantId, username, registerBody.getCode(), registerBody.getUuid()); + } + SysUserBo sysUser = new SysUserBo(); + sysUser.setUserName(username); + sysUser.setNickName(username); + sysUser.setPassword(BCrypt.hashpw(password)); + sysUser.setUserType(userType); + + boolean exist = TenantHelper.dynamic(tenantId, () -> { + return userMapper.exists(new LambdaQueryWrapper() + .eq(SysUser::getUserName, sysUser.getUserName())); + }); + if (exist) { + throw new UserException("user.register.save.error", username); + } + boolean regFlag = userService.registerUser(sysUser, tenantId); + if (!regFlag) { + throw new UserException("user.register.error"); + } + recordLogininfor(tenantId, username, Constants.REGISTER, MessageUtils.message("user.register.success")); + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + public void validateCaptcha(String tenantId, String username, String code, String uuid) { + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); + String captcha = RedisUtils.getCacheObject(verifyKey); + RedisUtils.deleteObject(verifyKey); + if (captcha == null) { + recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!StringUtils.equalsIgnoreCase(code, captcha)) { + recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + + /** + * 记录登录信息 + * + * @param tenantId 租户ID + * @param username 用户名 + * @param status 状态 + * @param message 消息内容 + * @return + */ + private void recordLogininfor(String tenantId, String username, String status, String message) { + LogininforEvent logininforEvent = new LogininforEvent(); + logininforEvent.setTenantId(tenantId); + logininforEvent.setUsername(username); + logininforEvent.setStatus(status); + logininforEvent.setMessage(message); + logininforEvent.setRequest(ServletUtils.getRequest()); + SpringUtils.context().publishEvent(logininforEvent); + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java new file mode 100644 index 0000000..e4315dc --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/EmailAuthStrategy.java @@ -0,0 +1,102 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.EmailLoginBody; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 邮件认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("email" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class EmailAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public LoginVo login(String body, SysClientVo client) { + EmailLoginBody loginBody = JsonUtils.parseObject(body, EmailLoginBody.class); + ValidatorUtils.validate(loginBody); + String tenantId = loginBody.getTenantId(); + String email = loginBody.getEmail(); + String emailCode = loginBody.getEmailCode(); + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + SysUserVo user = loadUserByEmail(email); + loginService.checkLogin(LoginType.EMAIL, tenantId, user.getUserName(), () -> !validateEmailCode(tenantId, email, emailCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginParameter model = new SaLoginParameter(); + model.setDeviceType(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + /** + * 校验邮箱验证码 + */ + private boolean validateEmailCode(String tenantId, String email, String emailCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + email); + if (StringUtils.isBlank(code)) { + loginService.recordLogininfor(tenantId, email, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(emailCode); + } + + private SysUserVo loadUserByEmail(String email) { + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getEmail, email)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", email); + throw new UserException("user.not.exists", email); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", email); + throw new UserException("user.blocked", email); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java new file mode 100644 index 0000000..abf590b --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/PasswordAuthStrategy.java @@ -0,0 +1,123 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.crypto.digest.BCrypt; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.domain.model.PasswordLoginBody; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.user.CaptchaException; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.common.web.config.properties.CaptchaProperties; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 密码认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("password" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class PasswordAuthStrategy implements IAuthStrategy { + + private final CaptchaProperties captchaProperties; + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public LoginVo login(String body, SysClientVo client) { + PasswordLoginBody loginBody = JsonUtils.parseObject(body, PasswordLoginBody.class); + ValidatorUtils.validate(loginBody); + String tenantId = loginBody.getTenantId(); + String username = loginBody.getUsername(); + String password = loginBody.getPassword(); + String code = loginBody.getCode(); + String uuid = loginBody.getUuid(); + + boolean captchaEnabled = captchaProperties.getEnable(); + // 验证码开关 + if (captchaEnabled) { + validateCaptcha(tenantId, username, code, uuid); + } + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + SysUserVo user = loadUserByUsername(username); + loginService.checkLogin(LoginType.PASSWORD, tenantId, username, () -> !BCrypt.checkpw(password, user.getPassword())); + // 此处可根据登录用户的数据不同 自行创建 loginUser + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginParameter model = new SaLoginParameter(); + model.setDeviceType(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + */ + private void validateCaptcha(String tenantId, String username, String code, String uuid) { + String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + StringUtils.blankToDefault(uuid, ""); + String captcha = RedisUtils.getCacheObject(verifyKey); + RedisUtils.deleteObject(verifyKey); + if (captcha == null) { + loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + if (!StringUtils.equalsIgnoreCase(code, captcha)) { + loginService.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")); + throw new CaptchaException(); + } + } + + private SysUserVo loadUserByUsername(String username) { + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getUserName, username)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", username); + throw new UserException("user.not.exists", username); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", username); + throw new UserException("user.blocked", username); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java new file mode 100644 index 0000000..597a601 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SmsAuthStrategy.java @@ -0,0 +1,102 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.constant.Constants; +import org.dromara.common.core.constant.GlobalConstants; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.domain.model.SmsLoginBody; +import org.dromara.common.core.enums.LoginType; +import org.dromara.common.core.exception.user.CaptchaExpireException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.MessageUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.SysUser; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 短信认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("sms" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class SmsAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + private final SysUserMapper userMapper; + + @Override + public LoginVo login(String body, SysClientVo client) { + SmsLoginBody loginBody = JsonUtils.parseObject(body, SmsLoginBody.class); + ValidatorUtils.validate(loginBody); + String tenantId = loginBody.getTenantId(); + String phonenumber = loginBody.getPhonenumber(); + String smsCode = loginBody.getSmsCode(); + LoginUser loginUser = TenantHelper.dynamic(tenantId, () -> { + SysUserVo user = loadUserByPhonenumber(phonenumber); + loginService.checkLogin(LoginType.SMS, tenantId, user.getUserName(), () -> !validateSmsCode(tenantId, phonenumber, smsCode)); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginParameter model = new SaLoginParameter(); + model.setDeviceType(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + /** + * 校验短信验证码 + */ + private boolean validateSmsCode(String tenantId, String phonenumber, String smsCode) { + String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phonenumber); + if (StringUtils.isBlank(code)) { + loginService.recordLogininfor(tenantId, phonenumber, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")); + throw new CaptchaExpireException(); + } + return code.equals(smsCode); + } + + private SysUserVo loadUserByPhonenumber(String phonenumber) { + SysUserVo user = userMapper.selectVoOne(new LambdaQueryWrapper().eq(SysUser::getPhonenumber, phonenumber)); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", phonenumber); + throw new UserException("user.not.exists", phonenumber); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", phonenumber); + throw new UserException("user.blocked", phonenumber); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java new file mode 100644 index 0000000..e01666e --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/SocialAuthStrategy.java @@ -0,0 +1,119 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthUser; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.LoginUser; +import org.dromara.common.core.domain.model.SocialLoginBody; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.exception.user.UserException; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.common.social.config.properties.SocialProperties; +import org.dromara.common.social.utils.SocialUtils; +import org.dromara.common.tenant.helper.TenantHelper; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysSocialVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.system.mapper.SysUserMapper; +import org.dromara.system.service.ISysSocialService; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; + +/** + * 第三方授权策略 + * + * @author thiszhc is 三三 + */ +@Slf4j +@Service("social" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class SocialAuthStrategy implements IAuthStrategy { + + private final SocialProperties socialProperties; + private final ISysSocialService sysSocialService; + private final SysUserMapper userMapper; + private final SysLoginService loginService; + + /** + * 登录-第三方授权登录 + * + * @param body 登录信息 + * @param client 客户端信息 + */ + @Override + public LoginVo login(String body, SysClientVo client) { + SocialLoginBody loginBody = JsonUtils.parseObject(body, SocialLoginBody.class); + ValidatorUtils.validate(loginBody); + AuthResponse response = SocialUtils.loginAuth( + loginBody.getSource(), loginBody.getSocialCode(), + loginBody.getSocialState(), socialProperties); + if (!response.ok()) { + throw new ServiceException(response.getMsg()); + } + AuthUser authUserData = response.getData(); + + List list = sysSocialService.selectByAuthId(authUserData.getSource() + authUserData.getUuid()); + if (CollUtil.isEmpty(list)) { + throw new ServiceException("你还没有绑定第三方账号,绑定后才可以登录!"); + } + SysSocialVo social; + if (TenantHelper.isEnable()) { + Optional opt = StreamUtils.findAny(list, x -> x.getTenantId().equals(loginBody.getTenantId())); + if (opt.isEmpty()) { + throw new ServiceException("对不起,你没有权限登录当前租户!"); + } + social = opt.get(); + } else { + social = list.get(0); + } + LoginUser loginUser = TenantHelper.dynamic(social.getTenantId(), () -> { + SysUserVo user = loadUser(social.getUserId()); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + return loginService.buildLoginUser(user); + }); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + SaLoginParameter model = new SaLoginParameter(); + model.setDeviceType(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + return loginVo; + } + + private SysUserVo loadUser(Long userId) { + SysUserVo user = userMapper.selectVoById(userId); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", ""); + throw new UserException("user.not.exists", ""); + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", ""); + throw new UserException("user.blocked", ""); + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java new file mode 100644 index 0000000..f223dd8 --- /dev/null +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java @@ -0,0 +1,111 @@ +package org.dromara.web.service.impl; + +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.stp.parameter.SaLoginParameter; +import cn.hutool.core.util.ObjectUtil; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthResponse; +import me.zhyd.oauth.model.AuthToken; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.request.AuthWechatMiniProgramRequest; +import org.dromara.common.core.constant.SystemConstants; +import org.dromara.common.core.domain.model.XcxLoginBody; +import org.dromara.common.core.domain.model.XcxLoginUser; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.ValidatorUtils; +import org.dromara.common.json.utils.JsonUtils; +import org.dromara.common.satoken.utils.LoginHelper; +import org.dromara.system.domain.vo.SysClientVo; +import org.dromara.system.domain.vo.SysUserVo; +import org.dromara.web.domain.vo.LoginVo; +import org.dromara.web.service.IAuthStrategy; +import org.dromara.web.service.SysLoginService; +import org.springframework.stereotype.Service; + +/** + * 小程序认证策略 + * + * @author Michelle.Chung + */ +@Slf4j +@Service("xcx" + IAuthStrategy.BASE_NAME) +@RequiredArgsConstructor +public class XcxAuthStrategy implements IAuthStrategy { + + private final SysLoginService loginService; + + @Override + public LoginVo login(String body, SysClientVo client) { + XcxLoginBody loginBody = JsonUtils.parseObject(body, XcxLoginBody.class); + ValidatorUtils.validate(loginBody); + // xcxCode 为 小程序调用 wx.login 授权后获取 + String xcxCode = loginBody.getXcxCode(); + // 多个小程序识别使用 + String appid = loginBody.getAppid(); + + // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid + AuthRequest authRequest = new AuthWechatMiniProgramRequest(AuthConfig.builder() + .clientId(appid).clientSecret("自行填写密钥 可根据不同appid填入不同密钥") + .ignoreCheckRedirectUri(true).ignoreCheckState(true).build()); + AuthCallback authCallback = new AuthCallback(); + authCallback.setCode(xcxCode); + AuthResponse resp = authRequest.login(authCallback); + String openid, unionId; + if (resp.ok()) { + AuthToken token = resp.getData().getToken(); + openid = token.getOpenId(); + // 微信小程序只有关联到微信开放平台下之后才能获取到 unionId,因此unionId不一定能返回。 + unionId = token.getUnionId(); + } else { + throw new ServiceException(resp.getMsg()); + } + // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可 + SysUserVo user = loadUserByOpenid(openid); + // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了 + XcxLoginUser loginUser = new XcxLoginUser(); + loginUser.setTenantId(user.getTenantId()); + loginUser.setUserId(user.getUserId()); + loginUser.setUsername(user.getUserName()); + loginUser.setNickname(user.getNickName()); + loginUser.setUserType(user.getUserType()); + loginUser.setClientKey(client.getClientKey()); + loginUser.setDeviceType(client.getDeviceType()); + loginUser.setOpenid(openid); + + SaLoginParameter model = new SaLoginParameter(); + model.setDeviceType(client.getDeviceType()); + // 自定义分配 不同用户体系 不同 token 授权时间 不设置默认走全局 yml 配置 + // 例如: 后台用户30分钟过期 app用户1天过期 + model.setTimeout(client.getTimeout()); + model.setActiveTimeout(client.getActiveTimeout()); + model.setExtra(LoginHelper.CLIENT_KEY, client.getClientId()); + // 生成token + LoginHelper.login(loginUser, model); + + LoginVo loginVo = new LoginVo(); + loginVo.setAccessToken(StpUtil.getTokenValue()); + loginVo.setExpireIn(StpUtil.getTokenTimeout()); + loginVo.setClientId(client.getClientId()); + loginVo.setOpenid(openid); + return loginVo; + } + + private SysUserVo loadUserByOpenid(String openid) { + // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户 + // todo 自行实现 userService.selectUserByOpenid(openid); + SysUserVo user = new SysUserVo(); + if (ObjectUtil.isNull(user)) { + log.info("登录用户:{} 不存在.", openid); + // todo 用户不存在 业务逻辑自行实现 + } else if (SystemConstants.DISABLE.equals(user.getStatus())) { + log.info("登录用户:{} 已被停用.", openid); + // todo 用户已被停用 业务逻辑自行实现 + } + return user; + } + +} diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml new file mode 100644 index 0000000..df26f24 --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -0,0 +1,270 @@ +--- # 监控中心配置 +spring.boot.admin.client: + # 增加客户端开关 + enabled: ${SPRING_BOOT_ADMIN_CLIENT_ENABLED:false} + url: http://localhost:9090/admin + instance: + service-host-type: IP + metadata: + username: ${spring.boot.admin.client.username} + userpassword: ${spring.boot.admin.client.password} + username: ruoyi + password: 123456 +--- # snail-job 配置 +snail-job: + enabled: ${SNAIL_JOB_ENABLED:false} + # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 + group: "ruoyi_group" + # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表 + token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" + server: + host: 127.0.0.1 + port: 17888 + # 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 + namespace: ${spring.profiles.active} + # 随主应用端口漂移 + port: 2${server.port} + # 客户端ip指定 + host: +--- # 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: true + # 设置默认的数据源或者数据源组,默认值即为 master + primary: postgres + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + # master: + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + # url: jdbc:mysql://10.13.13.1:3306/yitisheng_ry_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: root + # password: Db$7Hn#4Jm9Pq2!Xz + # # 从库数据源 + # slave: + # lazy: true + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: + # password: + # oracle: + # type: ${spring.datasource.type} + # driverClassName: oracle.jdbc.OracleDriver + # url: jdbc:oracle:thin:@//localhost:1521/XE + # username: ROOT + # password: root + postgres: + type: ${spring.datasource.type} + driverClassName: org.postgresql.Driver + url: jdbc:postgresql://10.13.13.1:5432/art_sports_volunteer?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true + username: art_sports_volunteer + password: t56kX86WMQ8eNjRz + # sqlserver: + # type: ${spring.datasource.type} + # driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver + # url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true + # username: SA + # password: root + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 30000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 600000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 1800000 + # 多久检查一次连接的活性 + keepaliveTime: 30000 +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring.data: + redis: + # 地址 + host: 10.13.13.1 + # 端口,默认为6379 + port: 56379 + # 数据库索引 + database: 2 + # redis 密码必须配置 + password: Rd@5Wk8#Nv3Yt6$Bm + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl.enabled: false + +# redisson 配置 +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 4 + # Netty线程池数量 + nettyThreads: 8 + # 单节点配置 + singleServerConfig: + # 客户端名称 不能用中文 + clientName: RuoYi-Vue-Plus + # 最小空闲连接数 + connectionMinimumIdleSize: 8 + # 连接池大小 + connectionPoolSize: 32 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + +--- # mail 邮件发送 +mail: + enabled: false + host: smtp.163.com + port: 465 + # 是否需要用户名密码验证 + auth: true +--- # 艺术院校导入配置 +art: + import: + # 学校JSON数据目录(为空则默认使用 {user.dir}/get_univ) + schoolJsonDir: /Users/zhouwentao/Workspaces/Yitisheng/art-management-backend/get_univ + # 发送方,遵循RFC-822标准 + from: xxx@163.com + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) + user: xxx@163.com + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) + pass: xxxxxxxxxx + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 + starttlsEnable: true + # 使用SSL安全连接 + sslEnable: true + # SMTP超时时长,单位毫秒,缺省值不超时 + timeout: 0 + # Socket连接超时值,单位毫秒,缺省值不超时 + connectionTimeout: 0 +--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 +# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 +sms: + # 配置源类型用于标定配置来源(interface,yaml) + config-type: yaml + # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 + restricted: true + # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 + minute-max: 1 + # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 + account-max: 30 + # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 + blends: + # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 + # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 + config1: + # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: alibaba + # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 + access-key-id: 您的accessKey + # 称为accessSecret有些称之为apiSecret + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + config2: + # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: tencent + access-key-id: 您的accessKey + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + +--- # 三方授权 +justauth: + # 前端外网访问地址 + address: http://localhost:80 + type: + maxkey: + # maxkey 服务器地址 + # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 + server-url: http://sso.maxkey.top + client-id: 876892492581044224 + client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 + redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [openid, email, phone, profile] + qq: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=qq + union-id: false + weibo: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=weibo + gitee: + client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 + client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac + redirect-uri: ${justauth.address}/social-callback?source=gitee + dingtalk: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=dingtalk + baidu: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=baidu + csdn: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=csdn + coding: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=coding + coding-group-name: xx + oschina: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=oschina + alipay_wallet: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet + alipay-public-key: MIIB**************DAQAB + wechat_open: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_open + wechat_mp: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_mp + wechat_enterprise: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise + agent-id: 1000002 + gitlab: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitlab + gitea: + # 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204 + # gitea 服务器地址 + server-url: https://demo.gitea.com + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitea diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml new file mode 100644 index 0000000..d77ddf5 --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-prod.yml @@ -0,0 +1,272 @@ +--- # 临时文件存储位置 避免临时文件被系统清理报错 +spring.servlet.multipart.location: /ruoyi/server/temp + +--- # 监控中心配置 +spring.boot.admin.client: + # 增加客户端开关 + enabled: true + url: http://localhost:9090/admin + instance: + service-host-type: IP + metadata: + username: ${spring.boot.admin.client.username} + userpassword: ${spring.boot.admin.client.password} + username: @monitor.username@ + password: @monitor.password@ + +--- # snail-job 配置 +snail-job: + enabled: true + # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 + group: "ruoyi_group" + # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表 + token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" + server: + host: 127.0.0.1 + port: 17888 + # 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 + namespace: ${spring.profiles.active} + # 随主应用端口漂移 + port: 2${server.port} + # 客户端ip指定 + host: + +--- # 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: false + # 设置默认的数据源或者数据源组,默认值即为 master + primary: master + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + master: + type: ${spring.datasource.type} + driverClassName: com.mysql.cj.jdbc.Driver + # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + username: root + password: root +# # 从库数据源 +# slave: +# lazy: true +# type: ${spring.datasource.type} +# driverClassName: com.mysql.cj.jdbc.Driver +# url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true +# username: +# password: +# oracle: +# type: ${spring.datasource.type} +# driverClassName: oracle.jdbc.OracleDriver +# url: jdbc:oracle:thin:@//localhost:1521/XE +# username: ROOT +# password: root +# postgres: +# type: ${spring.datasource.type} +# driverClassName: org.postgresql.Driver +# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true +# username: root +# password: root +# sqlserver: +# type: ${spring.datasource.type} +# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver +# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true +# username: SA +# password: root + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 30000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 600000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 1800000 + # 多久检查一次连接的活性 + keepaliveTime: 30000 + +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring.data: + redis: + # 地址 + host: localhost + # 端口,默认为6379 + port: 6379 + # 数据库索引 + database: 0 + # redis 密码必须配置 + password: ruoyi123 + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl.enabled: false + +# redisson 配置 +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 16 + # Netty线程池数量 + nettyThreads: 32 + # 单节点配置 + singleServerConfig: + # 客户端名称 不能用中文 + clientName: RuoYi-Vue-Plus + # 最小空闲连接数 + connectionMinimumIdleSize: 32 + # 连接池大小 + connectionPoolSize: 64 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + +--- # mail 邮件发送 +mail: + enabled: false + host: smtp.163.com + port: 465 + # 是否需要用户名密码验证 + auth: true + # 发送方,遵循RFC-822标准 + from: xxx@163.com + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) + user: xxx@163.com + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) + pass: xxxxxxxxxx + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 + starttlsEnable: true + # 使用SSL安全连接 + sslEnable: true + # SMTP超时时长,单位毫秒,缺省值不超时 + timeout: 0 + # Socket连接超时值,单位毫秒,缺省值不超时 + connectionTimeout: 0 + +--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 +# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 +sms: + # 配置源类型用于标定配置来源(interface,yaml) + config-type: yaml + # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 + restricted: true + # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 + minute-max: 1 + # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 + account-max: 30 + # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 + blends: + # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 + # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 + config1: + # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: alibaba + # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 + access-key-id: 您的accessKey + # 称为accessSecret有些称之为apiSecret + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + config2: + # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: tencent + access-key-id: 您的accessKey + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + +--- # 三方授权 +justauth: + # 前端外网访问地址 + address: http://localhost:80 + type: + maxkey: + # maxkey 服务器地址 + # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 + server-url: http://sso.maxkey.top + client-id: 876892492581044224 + client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 + redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [ openid, email, phone, profile ] + qq: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=qq + union-id: false + weibo: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=weibo + gitee: + client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 + client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac + redirect-uri: ${justauth.address}/social-callback?source=gitee + dingtalk: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=dingtalk + baidu: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=baidu + csdn: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=csdn + coding: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=coding + coding-group-name: xx + oschina: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=oschina + alipay_wallet: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet + alipay-public-key: MIIB**************DAQAB + wechat_open: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_open + wechat_mp: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_mp + wechat_enterprise: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise + agent-id: 1000002 + gitlab: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitlab + gitea: + # 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204 + # gitea 服务器地址 + server-url: https://demo.gitea.com + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitea diff --git a/ruoyi-admin/src/main/resources/application-test.yml b/ruoyi-admin/src/main/resources/application-test.yml new file mode 100644 index 0000000..df26f24 --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-test.yml @@ -0,0 +1,270 @@ +--- # 监控中心配置 +spring.boot.admin.client: + # 增加客户端开关 + enabled: ${SPRING_BOOT_ADMIN_CLIENT_ENABLED:false} + url: http://localhost:9090/admin + instance: + service-host-type: IP + metadata: + username: ${spring.boot.admin.client.username} + userpassword: ${spring.boot.admin.client.password} + username: ruoyi + password: 123456 +--- # snail-job 配置 +snail-job: + enabled: ${SNAIL_JOB_ENABLED:false} + # 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务 + group: "ruoyi_group" + # SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表 + token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT" + server: + host: 127.0.0.1 + port: 17888 + # 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段 + namespace: ${spring.profiles.active} + # 随主应用端口漂移 + port: 2${server.port} + # 客户端ip指定 + host: +--- # 数据源配置 +spring: + datasource: + type: com.zaxxer.hikari.HikariDataSource + # 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content + dynamic: + # 性能分析插件(有性能损耗 不建议生产环境使用) + p6spy: true + # 设置默认的数据源或者数据源组,默认值即为 master + primary: postgres + # 严格模式 匹配不到数据源则报错 + strict: true + datasource: + # 主库数据源 + # master: + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562 + # # rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题) + # url: jdbc:mysql://10.13.13.1:3306/yitisheng_ry_vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: root + # password: Db$7Hn#4Jm9Pq2!Xz + # # 从库数据源 + # slave: + # lazy: true + # type: ${spring.datasource.type} + # driverClassName: com.mysql.cj.jdbc.Driver + # url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true + # username: + # password: + # oracle: + # type: ${spring.datasource.type} + # driverClassName: oracle.jdbc.OracleDriver + # url: jdbc:oracle:thin:@//localhost:1521/XE + # username: ROOT + # password: root + postgres: + type: ${spring.datasource.type} + driverClassName: org.postgresql.Driver + url: jdbc:postgresql://10.13.13.1:5432/art_sports_volunteer?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true + username: art_sports_volunteer + password: t56kX86WMQ8eNjRz + # sqlserver: + # type: ${spring.datasource.type} + # driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver + # url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true + # username: SA + # password: root + hikari: + # 最大连接池数量 + maxPoolSize: 20 + # 最小空闲线程数量 + minIdle: 10 + # 配置获取连接等待超时的时间 + connectionTimeout: 30000 + # 校验超时时间 + validationTimeout: 5000 + # 空闲连接存活最大时间,默认10分钟 + idleTimeout: 600000 + # 此属性控制池中连接的最长生命周期,值0表示无限生命周期,默认30分钟 + maxLifetime: 1800000 + # 多久检查一次连接的活性 + keepaliveTime: 30000 +--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) +spring.data: + redis: + # 地址 + host: 10.13.13.1 + # 端口,默认为6379 + port: 56379 + # 数据库索引 + database: 2 + # redis 密码必须配置 + password: Rd@5Wk8#Nv3Yt6$Bm + # 连接超时时间 + timeout: 10s + # 是否开启ssl + ssl.enabled: false + +# redisson 配置 +redisson: + # redis key前缀 + keyPrefix: + # 线程池数量 + threads: 4 + # Netty线程池数量 + nettyThreads: 8 + # 单节点配置 + singleServerConfig: + # 客户端名称 不能用中文 + clientName: RuoYi-Vue-Plus + # 最小空闲连接数 + connectionMinimumIdleSize: 8 + # 连接池大小 + connectionPoolSize: 32 + # 连接空闲超时,单位:毫秒 + idleConnectionTimeout: 10000 + # 命令等待超时,单位:毫秒 + timeout: 3000 + # 发布和订阅连接池大小 + subscriptionConnectionPoolSize: 50 + +--- # mail 邮件发送 +mail: + enabled: false + host: smtp.163.com + port: 465 + # 是否需要用户名密码验证 + auth: true +--- # 艺术院校导入配置 +art: + import: + # 学校JSON数据目录(为空则默认使用 {user.dir}/get_univ) + schoolJsonDir: /Users/zhouwentao/Workspaces/Yitisheng/art-management-backend/get_univ + # 发送方,遵循RFC-822标准 + from: xxx@163.com + # 用户名(注意:如果使用foxmail邮箱,此处user为qq号) + user: xxx@163.com + # 密码(注意,某些邮箱需要为SMTP服务单独设置密码,详情查看相关帮助) + pass: xxxxxxxxxx + # 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。 + starttlsEnable: true + # 使用SSL安全连接 + sslEnable: true + # SMTP超时时长,单位毫秒,缺省值不超时 + timeout: 0 + # Socket连接超时值,单位毫秒,缺省值不超时 + connectionTimeout: 0 +--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商 +# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用 +sms: + # 配置源类型用于标定配置来源(interface,yaml) + config-type: yaml + # 用于标定yml中的配置是否开启短信拦截,接口配置不受此限制 + restricted: true + # 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效 + minute-max: 1 + # 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效 + account-max: 30 + # 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中 + blends: + # 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可 + # 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户 + config1: + # 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: alibaba + # 有些称为accessKey有些称之为apiKey,也有称为sdkKey或者appId。 + access-key-id: 您的accessKey + # 称为accessSecret有些称之为apiSecret + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + config2: + # 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分 + supplier: tencent + access-key-id: 您的accessKey + access-key-secret: 您的accessKeySecret + signature: 您的短信签名 + sdk-app-id: 您的sdkAppId + +--- # 三方授权 +justauth: + # 前端外网访问地址 + address: http://localhost:80 + type: + maxkey: + # maxkey 服务器地址 + # 注意 如下均配置均不需要修改 maxkey 已经内置好了数据 + server-url: http://sso.maxkey.top + client-id: 876892492581044224 + client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8 + redirect-uri: ${justauth.address}/social-callback?source=maxkey + topiam: + # topiam 服务器地址 + server-url: http://127.0.0.1:1898/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [openid, email, phone, profile] + qq: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=qq + union-id: false + weibo: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=weibo + gitee: + client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98 + client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac + redirect-uri: ${justauth.address}/social-callback?source=gitee + dingtalk: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=dingtalk + baidu: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=baidu + csdn: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=csdn + coding: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=coding + coding-group-name: xx + oschina: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=oschina + alipay_wallet: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet + alipay-public-key: MIIB**************DAQAB + wechat_open: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_open + wechat_mp: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_mp + wechat_enterprise: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise + agent-id: 1000002 + gitlab: + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitlab + gitea: + # 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204 + # gitea 服务器地址 + server-url: https://demo.gitea.com + client-id: 10**********6 + client-secret: 1f7d08**********5b7**********29e + redirect-uri: ${justauth.address}/social-callback?source=gitea diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml new file mode 100644 index 0000000..efdef5a --- /dev/null +++ b/ruoyi-admin/src/main/resources/application.yml @@ -0,0 +1,266 @@ +# 开发环境配置 +server: + # 服务器的HTTP端口,默认为8080 + port: 8080 + servlet: + # 应用的访问路径 + context-path: / + # undertow 配置 + undertow: + # HTTP post内容的最大大小。当值为-1时,默认值为大小是无限的 + max-http-post-size: -1 + # 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理 + # 每块buffer的空间大小,越小的空间被利用越充分 + buffer-size: 512 + # 是否分配的直接内存 + direct-buffers: true + threads: + # 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程 + io: 8 + # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 + worker: 256 + +captcha: + # 是否启用验证码校验 + enable: true + # 验证码类型 math 数组计算 char 字符验证 + type: math + # 数字验证码位数 + numberLength: 1 + # 字符验证码长度 + charLength: 4 + +# 日志配置 +logging: + level: + org.dromara: info + org.springframework: warn + org.mybatis.spring.mapper: error + org.apache.fury: warn + config: classpath:logback-plus.xml + +# 用户配置 +user: + password: + # 密码最大错误次数 + maxRetryCount: 5 + # 密码锁定时间(默认10分钟) + lockTime: 10 + +# Spring配置 +spring: + application: + name: RuoYi-Vue-Plus + threads: + # 开启虚拟线程 仅jdk21可用 + virtual: + enabled: false + task: + execution: + # 从 springboot 3.5 开始 spring自带线程池 + # 不再需要 AsyncConfig与ThreadPoolConfig 可直接注入线程池使用 + thread-name-prefix: async- + # 由spring自己初始化线程池 + mode: force + # 资源信息 + messages: + # 国际化资源文件路径 + basename: i18n/messages + profiles: + active: dev + # 文件上传 + servlet: + multipart: + # 单个文件大小 + max-file-size: 10MB + # 设置总上传的文件大小 + max-request-size: 20MB + mvc: + # 设置静态资源路径 防止所有请求都去查静态资源 + static-path-pattern: /static/** + format: + date-time: yyyy-MM-dd HH:mm:ss + jackson: + # 日期格式化 + date-format: yyyy-MM-dd HH:mm:ss + serialization: + # 格式化输出 + indent_output: false + # 忽略无法转换的对象 + fail_on_empty_beans: false + deserialization: + # 允许对象忽略json中不存在的属性 + fail_on_unknown_properties: false + +# Sa-Token配置 +sa-token: + # token名称 (同时也是cookie名称) + token-name: Authorization + # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) + is-share: false + # jwt秘钥 + jwt-secret-key: abcdefghijklmnopqrstuvwxyz + +# security配置 +security: + # 排除路径 + excludes: + - /*.html + - /**/*.html + - /**/*.css + - /**/*.js + - /favicon.ico + - /error + - /*/api-docs + - /*/api-docs/** + - /warm-flow-ui/config + +# 多租户配置 +tenant: + # 是否开启 + enable: true + # 排除表 + excludes: + - sys_menu + - sys_tenant + - sys_tenant_package + - sys_role_dept + - sys_role_menu + - sys_user_post + - sys_user_role + - sys_client + - sys_oss_config + - flow_spel + - art_school_enroll_code + +# MyBatisPlus配置 +# https://baomidou.com/config/ +mybatis-plus: + # 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效 + enableLogicDelete: true + # 多包名使用 例如 org.dromara.**.mapper,org.xxx.**.mapper + mapperPackage: org.dromara.**.mapper + # 对应的 XML 文件位置 + mapperLocations: classpath*:mapper/**/*Mapper.xml + # 实体扫描,多个package用逗号或者分号分隔 + typeAliasesPackage: org.dromara.**.domain + global-config: + dbConfig: + # 主键类型 + # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID + # 如需改为自增 需要将数据库表全部设置为自增 + idType: ASSIGN_ID + +# 数据加密 +mybatis-encryptor: + # 是否开启加密 + enable: false + # 默认加密算法 + algorithm: BASE64 + # 编码方式 BASE64/HEX。默认BASE64 + encode: BASE64 + # 安全秘钥 对称算法的秘钥 如:AES,SM4 + password: + # 公私钥 非对称算法的公私钥 如:SM2,RSA + publicKey: + privateKey: + +# api接口加密 +api-decrypt: + # 是否开启全局接口加密 + enabled: true + # AES 加密头标识 + headerFlag: encrypt-key + # 响应加密公钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 + # 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE= + publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ== + # 请求解密私钥 非对称算法的公私钥 如:SM2,RSA 使用者请自行更换 + # 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ== + privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y= + +springdoc: + api-docs: + # 是否开启接口文档 + enabled: true + info: + # 标题 + title: '标题:RuoYi-Vue-Plus多租户管理系统_接口文档' + # 描述 + description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...' + # 版本 + version: '版本号: ${project.version}' + # 作者信息 + contact: + name: Lion Li + email: crazylionli@163.com + url: https://gitee.com/dromara/RuoYi-Vue-Plus + #这里定义了两个分组,可定义多个,也可以不定义 + group-configs: + - group: 1.演示模块 + packages-to-scan: org.dromara.demo + - group: 2.通用模块 + packages-to-scan: org.dromara.web + - group: 3.系统模块 + packages-to-scan: org.dromara.system + - group: 4.代码生成模块 + packages-to-scan: org.dromara.generator + - group: 5.工作流模块 + packages-to-scan: org.dromara.workflow + - group: 6.艺术数据模块 + packages-to-scan: org.dromara.art + +# 防止XSS攻击 +xss: + # 过滤开关 + enabled: true + # 排除链接 + excludeUrls: + - /system/notice + +--- # 分布式锁 lock4j 全局配置 +lock4j: + # 获取分布式锁超时时间,默认为 3000 毫秒 + acquire-timeout: 3000 + # 分布式锁的超时时间,默认为 30 秒 + expire: 30000 + +--- # Actuator 监控端点的配置项 +management: + endpoints: + web: + exposure: + include: '*' + endpoint: + health: + show-details: ALWAYS + logfile: + external-file: ./logs/sys-console.log + +--- # 默认/推荐使用sse推送 +sse: + enabled: true + path: /resource/sse + +--- # websocket +websocket: + # 如果关闭 需要和前端开关一起关闭 + enabled: false + # 路径 + path: /resource/websocket + # 设置访问源地址 + allowedOrigins: '*' + +--- # warm-flow工作流配置 +warm-flow: + # 是否开启工作流,默认true + enabled: true + # 是否开启设计器ui + ui: true + # 是否显示流程图顶部文字 + top-text-show: true + # 是否渲染节点悬浮提示,默认true + node-tooltip: true + # 默认Authorization,如果有多个token,用逗号分隔 + token-name: ${sa-token.token-name},clientid diff --git a/ruoyi-admin/src/main/resources/art-school-import-export-api.md b/ruoyi-admin/src/main/resources/art-school-import-export-api.md new file mode 100644 index 0000000..6a1f978 --- /dev/null +++ b/ruoyi-admin/src/main/resources/art-school-import-export-api.md @@ -0,0 +1,197 @@ +# 学校主子表导入导出接口文档(art/school) + +## 1. 目标 + +面向前端提供“学校主表 + 子表(详情/校区/学院/专业/招生计划)”的一体化导出与导入能力,支持: + +- 多 Sheet 标准模板导出 +- 导入前冲突预检 +- 按学校编码选择性替换(原子事务) +- 子表导入按“业务键优先 + ID映射兜底”自动重建关联(避免替换后ID变化导致错绑) +- 导入明细反馈(成功/失败/跳过与原因) + +--- + +## 2. 接口清单 + +### 2.1 导出模板数据(含业务数据) + +- **URL**: `POST /art/school/export` +- **权限**: `art:school:export` +- **Content-Type**: `application/x-www-form-urlencoded` +- **响应**: Excel 文件下载(`.xlsx`) + +#### 查询参数(同学校列表) + +| 参数 | 类型 | 必填 | 说明 | +|---|---|---|---| +| mainCode | string | 否 | 学校编码 | +| mainName | string | 否 | 学校名称(模糊) | +| shortName | string | 否 | 学校简称(模糊) | +| province/city/district | string | 否 | 行政区 | +| universityType | string | 否 | 大学类型 | +| educationLevel | string | 否 | 学历层次 | +| schoolNature | string | 否 | 办学性质 | + +#### 导出 Sheet 结构 + +1. `学校基本信息` +2. `学校详情信息` +3. `校区信息` +4. `学院信息` +5. `专业信息` +6. `招生计划信息` +7. `模板说明` + +> 子表均包含 `学校编码*`、`学校名称*` 用于与主表关联。 + +--- + +### 2.2 导出空模板 + +- **URL**: `POST /art/school/importTemplate` +- **权限**: `art:school:export` +- **响应**: 空模板 Excel(仅表头 + 模板说明) + +--- + +### 2.3 导入预检 + +- **URL**: `POST /art/school/importPreview` +- **权限**: `art:school:import` +- **Content-Type**: `multipart/form-data` +- **入参**: + - `file`(Excel 文件,必填) + +#### 返回示例 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "totalSchoolCount": 10, + "conflictCount": 3, + "invalidCount": 1, + "details": [ + { + "mainCode": "1001", + "mainName": "测试学校01", + "status": "CONFLICT", + "message": "系统已存在该学校数据,导入时需确认是否替换" + }, + { + "mainCode": "", + "mainName": "", + "status": "INVALID", + "message": "必填字段缺失:学校编码/学校名称不能为空" + } + ] + } +} +``` + +#### 状态说明 + +- `CONFLICT`: 系统已存在(按学校编码/名称命中) +- `INVALID`: 模板数据无效(缺失、重复、子表关联不到主表) + +--- + +### 2.4 导入执行 + +- **URL**: `POST /art/school/importData` +- **权限**: `art:school:import` +- **Content-Type**: `multipart/form-data` +- **入参**: + - `file`(Excel 文件,必填) + - `replaceAll`(boolean,选填,默认 `false`) + - `replaceMainCodes`(string[],选填,可多值传参) + +#### 前端推荐调用逻辑 + +1. 先调 `importPreview`。 +2. 对 `CONFLICT` 学校弹窗询问“是否替换”。 +3. 将用户同意替换的学校编码组装为 `replaceMainCodes`,再调 `importData`。 +4. 用户全量替换时可直接传 `replaceAll=true`。 + +#### 返回示例 + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "totalSchoolCount": 10, + "successCount": 8, + "failCount": 1, + "skippedCount": 1, + "details": [ + { + "mainCode": "1001", + "mainName": "测试学校01", + "status": "SUCCESS", + "message": "替换成功" + }, + { + "mainCode": "1002", + "mainName": "测试学校02", + "status": "SKIPPED", + "message": "学校名称重复且用户取消替换" + }, + { + "mainCode": "1003", + "mainName": "测试学校03", + "status": "FAILED", + "message": "学院保存失败" + } + ] + } +} +``` + +#### 状态说明 + +- `SUCCESS`: 导入/替换成功 +- `SKIPPED`: 冲突且用户未选择替换 +- `FAILED`: 导入失败(事务回滚) +- `INVALID`: 文件预校验失败 + +--- + +## 3. 原子性与一致性 + +- 导入按“单学校”为最小事务单元: + - 该学校主表 + 子表(详情/校区/学院/专业/招生计划)要么全部成功,要么全部回滚。 +- 替换逻辑: + 1. 删除该学校历史主表及上述子表数据 + 2. 插入新主表数据 + 3. 插入新子表数据 + +--- + +## 4. 模板必填规则(简表) + +- `学校基本信息`: `学校编码*`、`学校名称*` +- `学校详情信息`: `学校编码*`、`学校名称*` +- `校区信息`: `学校编码*`、`学校名称*`、`校区名称*` +- `学院信息`: `学校编码*`、`学校名称*`、`学院名称*` +- `专业信息`: `学校编码*`、`学校名称*`、`专业名称*`,且需提供 `学院ID` 或 `学院编码/学院名称` +- `招生计划信息`: `学校编码*`、`学校名称*`、`年份*`、`招生省份*`、`专业名称*`、`计划数*` + +> `*` 表示模板必填字段。 + +--- + +## 5. 兼容说明 + +- 现有 `POST /art/school` 与 `PUT /art/school` 仍用于单学校编辑(`school + detail` 统一结构)。 +- 本文档新增导入导出接口可与现有列表/编辑功能并行使用。 + +--- + +## 6. 子表关联规则(导入执行) + +- 学院:导入时重新生成 `college_id`,并建立 `旧学院ID -> 新学院ID` 映射。 +- 专业:优先使用 `学院ID` 映射;若无效则按 `学院编码+学院名称`(或仅学院名称)匹配学院,再插入专业并建立 `旧专业ID -> 新专业ID` 映射。 +- 招生计划:优先使用 `专业ID` 映射;若无效则按 `专业名称+学历层次` 匹配;仍匹配不到则 `major_id` 置空,仅保留 `major_name` 入库。 diff --git a/ruoyi-admin/src/main/resources/art-school-tag-major-tag-api.md b/ruoyi-admin/src/main/resources/art-school-tag-major-tag-api.md new file mode 100644 index 0000000..c74ae9b --- /dev/null +++ b/ruoyi-admin/src/main/resources/art-school-tag-major-tag-api.md @@ -0,0 +1,117 @@ +# 学校与专业标签联动接口补充文档 + +本文档仅说明本次新增字段: + +- `/art/school`:新增 `schoolTags` +- `/art/schoolMajor`:新增 `majorTags` + +## 1. /art/school 接口补充 + +### 1.1 GET `/art/school/{schoolId}` + +返回对象 `data` 中新增: + +| 字段 | 类型 | 说明 | +|---|---|---| +| schoolTags | string[] | 学校标签列表 | + +示例: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "schoolId": 1001, + "mainCode": "10531", + "mainName": "某某大学", + "enrollCodes": ["10531", "A10531"], + "schoolTags": ["985", "211", "双一流"] + } +} +``` + +### 1.2 POST `/art/school` + +请求体 `ArtSchoolSubmitBo` 新增: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| schoolTags | string[] | 否 | 学校标签列表(全量替换语义) | + +### 1.3 PUT `/art/school` + +请求体 `ArtSchoolSubmitBo` 新增: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| schoolTags | string[] | 否 | 学校标签列表(全量替换语义) | + +### 1.4 `schoolTags` 处理语义 + +- `schoolTags = null`:不修改已有标签 +- `schoolTags = []`:清空该学校全部标签 +- `schoolTags = ["985","211"]`:按传入值全量覆盖(去重后保存) + +--- + +## 2. /art/schoolMajor 接口补充 + +### 2.1 GET `/art/schoolMajor/{majorId}` + +返回对象 `data` 中新增: + +| 字段 | 类型 | 说明 | +|---|---|---| +| majorTags | string[] | 专业标签列表 | + +示例: + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "majorId": 9001, + "majorName": "视觉传达设计", + "majorTags": ["国家级特色专业", "一流本科专业"] + } +} +``` + +### 2.2 GET `/art/schoolMajor/list` + +列表项中新增字段: + +| 字段 | 类型 | 说明 | +|---|---|---| +| majorTags | string[] | 专业标签列表 | + +### 2.3 POST `/art/schoolMajor` + +请求体 `ArtSchoolMajorBo` 新增: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| majorTags | string[] | 否 | 专业标签列表(全量替换语义) | + +### 2.4 PUT `/art/schoolMajor` + +请求体 `ArtSchoolMajorBo` 新增: + +| 字段 | 类型 | 必填 | 说明 | +|---|---|---|---| +| majorTags | string[] | 否 | 专业标签列表(全量替换语义) | + +### 2.5 `majorTags` 处理语义 + +- `majorTags = null`:不修改已有标签 +- `majorTags = []`:清空该专业全部标签 +- `majorTags = ["A","B"]`:按传入值全量覆盖(去重后保存) + +--- + +## 3. 与旧字段兼容说明 + +- `ArtSchoolMajorBo` / `ArtSchoolMajorVo` 中旧字段 `tags` 仍保留,便于兼容历史前端。 +- 新增推荐字段为 `majorTags`(数组),后续前端优先使用该字段。 diff --git a/ruoyi-admin/src/main/resources/banner.txt b/ruoyi-admin/src/main/resources/banner.txt new file mode 100644 index 0000000..21b1126 --- /dev/null +++ b/ruoyi-admin/src/main/resources/banner.txt @@ -0,0 +1,8 @@ +Application Version: ${revision} +Spring Boot Version: ${spring-boot.version} +__________ _____.___.__ ____ ____ __________.__ +\______ \__ __ ____\__ | |__| \ \ / /_ __ ____ \______ \ | __ __ ______ + | _/ | \/ _ \/ | | | ______ \ Y / | \_/ __ \ ______ | ___/ | | | \/ ___/ + | | \ | ( <_> )____ | | /_____/ \ /| | /\ ___/ /_____/ | | | |_| | /\___ \ + |____|_ /____/ \____// ______|__| \___/ |____/ \___ > |____| |____/____//____ > + \/ \/ \/ \/ diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties new file mode 100644 index 0000000..e1e5263 --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages.properties @@ -0,0 +1,62 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,账户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符 +user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +auth.grant.type.error=认证权限类型错误 +auth.grant.type.blocked=认证权限类型已禁用 +auth.grant.type.not.blank=认证权限类型不能为空 +auth.clientid.not.blank=认证客户端id不能为空 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,账户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,账户锁定{1}分钟 +xcx.code.not.blank=小程序[code]不能为空 +social.source.not.blank=第三方登录平台[source]不能为空 +social.code.not.blank=第三方登录平台[code]不能为空 +social.state.not.blank=第三方登录平台[state]不能为空 +##租户 +tenant.number.not.blank=租户编号不能为空 +tenant.not.exists=对不起, 您的租户不存在,请联系管理员 +tenant.blocked=对不起,您的租户已禁用,请联系管理员 +tenant.expired=对不起,您的租户已过期,请联系管理员 diff --git a/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties new file mode 100644 index 0000000..306a48f --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties @@ -0,0 +1,62 @@ +#错误消息 +not.null=* Required fill in +user.jcaptcha.error=Captcha error +user.jcaptcha.expire=Captcha invalid +user.not.exists=Sorry, your account: {0} does not exist +user.password.not.match=User does not exist/Password error +user.password.retry.limit.count=Password input error {0} times +user.password.retry.limit.exceed=Password input error {0} times, account locked for {1} minutes +user.password.delete=Sorry, your account:{0} has been deleted +user.blocked=Sorry, your account: {0} has been disabled. Please contact the administrator +role.blocked=Role disabled,please contact administrators +user.logout.success=Exit successful +length.not.valid=The length must be between {min} and {max} characters +user.username.not.blank=Username cannot be blank +user.username.not.valid=* 2 to 20 chinese characters, letters, numbers or underscores, and must start with a non number +user.username.length.valid=Account length must be between {min} and {max} characters +user.password.not.blank=Password cannot be empty +user.password.length.valid=Password length must be between {min} and {max} characters +user.password.not.valid=* 5-50 characters +user.password.format.valid=Password must contain uppercase, lowercase, digit, and special character +user.email.not.valid=Mailbox format error +user.email.not.blank=Mailbox cannot be blank +user.phonenumber.not.blank=Phone number cannot be blank +user.mobile.phone.number.not.valid=Phone number format error +user.login.success=Login successful +user.register.success=Register successful +user.register.save.error=Failed to save user {0}, The registered account already exists +user.register.error=Register failed, please contact system administrator +user.notfound=Please login again +user.forcelogout=The administrator is forced to exit,please login again +user.unknown.error=Unknown error, please login again +auth.grant.type.error=Auth grant type error +auth.grant.type.blocked=Auth grant type disabled +auth.grant.type.not.blank=Auth grant type cannot be blank +auth.clientid.not.blank=Auth clientid cannot be blank +##文件上传消息 +upload.exceed.maxSize=The uploaded file size exceeds the limit file size!
the maximum allowed file size is:{0}MB! +upload.filename.exceed.length=The maximum length of uploaded file name is {0} characters +##权限 +no.permission=You do not have permission to the data,please contact your administrator to add permissions [{0}] +no.create.permission=You do not have permission to create data,please contact your administrator to add permissions [{0}] +no.update.permission=You do not have permission to modify data,please contact your administrator to add permissions [{0}] +no.delete.permission=You do not have permission to delete data,please contact your administrator to add permissions [{0}] +no.export.permission=You do not have permission to export data,please contact your administrator to add permissions [{0}] +no.view.permission=You do not have permission to view data,please contact your administrator to add permissions [{0}] +repeat.submit.message=Repeat submit is not allowed, please try again later +rate.limiter.message=Visit too frequently, please try again later +sms.code.not.blank=Sms code cannot be blank +sms.code.retry.limit.count=Sms code input error {0} times +sms.code.retry.limit.exceed=Sms code input error {0} times, account locked for {1} minutes +email.code.not.blank=Email code cannot be blank +email.code.retry.limit.count=Email code input error {0} times +email.code.retry.limit.exceed=Email code input error {0} times, account locked for {1} minutes +xcx.code.not.blank=Mini program [code] cannot be blank +social.source.not.blank=Social login platform [source] cannot be blank +social.code.not.blank=Social login platform [code] cannot be blank +social.state.not.blank=Social login platform [state] cannot be blank +##租户 +tenant.number.not.blank=Tenant number cannot be blank +tenant.not.exists=Sorry, your tenant does not exist. Please contact the administrator +tenant.blocked=Sorry, your tenant is disabled. Please contact the administrator +tenant.expired=Sorry, your tenant has expired. Please contact the administrator. diff --git a/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties new file mode 100644 index 0000000..e1e5263 --- /dev/null +++ b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties @@ -0,0 +1,62 @@ +#错误消息 +not.null=* 必须填写 +user.jcaptcha.error=验证码错误 +user.jcaptcha.expire=验证码已失效 +user.not.exists=对不起, 您的账号:{0} 不存在. +user.password.not.match=用户不存在/密码错误 +user.password.retry.limit.count=密码输入错误{0}次 +user.password.retry.limit.exceed=密码输入错误{0}次,账户锁定{1}分钟 +user.password.delete=对不起,您的账号:{0} 已被删除 +user.blocked=对不起,您的账号:{0} 已禁用,请联系管理员 +role.blocked=角色已封禁,请联系管理员 +user.logout.success=退出成功 +length.not.valid=长度必须在{min}到{max}个字符之间 +user.username.not.blank=用户名不能为空 +user.username.not.valid=* 2到20个汉字、字母、数字或下划线组成,且必须以非数字开头 +user.username.length.valid=账户长度必须在{min}到{max}个字符之间 +user.password.not.blank=用户密码不能为空 +user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 +user.password.not.valid=* 5-50个字符 +user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符 +user.email.not.valid=邮箱格式错误 +user.email.not.blank=邮箱不能为空 +user.phonenumber.not.blank=用户手机号不能为空 +user.mobile.phone.number.not.valid=手机号格式错误 +user.login.success=登录成功 +user.register.success=注册成功 +user.register.save.error=保存用户 {0} 失败,注册账号已存在 +user.register.error=注册失败,请联系系统管理人员 +user.notfound=请重新登录 +user.forcelogout=管理员强制退出,请重新登录 +user.unknown.error=未知错误,请重新登录 +auth.grant.type.error=认证权限类型错误 +auth.grant.type.blocked=认证权限类型已禁用 +auth.grant.type.not.blank=认证权限类型不能为空 +auth.clientid.not.blank=认证客户端id不能为空 +##文件上传消息 +upload.exceed.maxSize=上传的文件大小超出限制的文件大小!
允许的文件最大大小是:{0}MB! +upload.filename.exceed.length=上传的文件名最长{0}个字符 +##权限 +no.permission=您没有数据的权限,请联系管理员添加权限 [{0}] +no.create.permission=您没有创建数据的权限,请联系管理员添加权限 [{0}] +no.update.permission=您没有修改数据的权限,请联系管理员添加权限 [{0}] +no.delete.permission=您没有删除数据的权限,请联系管理员添加权限 [{0}] +no.export.permission=您没有导出数据的权限,请联系管理员添加权限 [{0}] +no.view.permission=您没有查看数据的权限,请联系管理员添加权限 [{0}] +repeat.submit.message=不允许重复提交,请稍候再试 +rate.limiter.message=访问过于频繁,请稍候再试 +sms.code.not.blank=短信验证码不能为空 +sms.code.retry.limit.count=短信验证码输入错误{0}次 +sms.code.retry.limit.exceed=短信验证码输入错误{0}次,账户锁定{1}分钟 +email.code.not.blank=邮箱验证码不能为空 +email.code.retry.limit.count=邮箱验证码输入错误{0}次 +email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,账户锁定{1}分钟 +xcx.code.not.blank=小程序[code]不能为空 +social.source.not.blank=第三方登录平台[source]不能为空 +social.code.not.blank=第三方登录平台[code]不能为空 +social.state.not.blank=第三方登录平台[state]不能为空 +##租户 +tenant.number.not.blank=租户编号不能为空 +tenant.not.exists=对不起, 您的租户不存在,请联系管理员 +tenant.blocked=对不起,您的租户已禁用,请联系管理员 +tenant.expired=对不起,您的租户已过期,请联系管理员 diff --git a/ruoyi-admin/src/main/resources/ip2region_v4.xdb b/ruoyi-admin/src/main/resources/ip2region_v4.xdb new file mode 100644 index 0000000000000000000000000000000000000000..6f86c7d9b5ea27ecbe808e2be198bac1aaee0b92 GIT binary patch literal 11042429 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%0AxdRZi&BepqSP<9P@0l? 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