From 069b9892c6281b5919fdb9115a049972cc12aa26 Mon Sep 17 00:00:00 2001 From: tangwei Date: Tue, 31 Mar 2026 11:32:10 +0800 Subject: [PATCH] 11 --- backend/pom.xml | 416 ++++------- .../com/yfd/platform/PlatformApplication.java | 46 -- .../com/yfd/platform/ServletInitializer.java | 13 - .../platform/annotation/AnonymousAccess.java | 30 - .../java/com/yfd/platform/annotation/Log.java | 20 - .../annotation/rest/AnonymousGetMapping.java | 86 --- .../com/yfd/platform/aspect/LogAspect.java | 93 --- .../component/ServerSendEventServer.java | 147 ---- .../platform/component/WebSocketServer.java | 106 --- .../platform/config/AppInitProperties.java | 17 - .../yfd/platform/config/DataInitializer.java | 129 ---- .../yfd/platform/config/FileProperties.java | 59 -- .../platform/config/FileSpaceProperties.java | 17 - .../config/GlobalExceptionHandler.java | 25 - .../com/yfd/platform/config/JobRunner.java | 59 -- .../config/JwtAuthenticationTokenFilter.java | 83 --- .../yfd/platform/config/MessageConfig.java | 50 -- .../yfd/platform/config/MybitsPlusConfig.java | 35 - .../platform/config/ProdApiPrefixFilter.java | 44 -- .../com/yfd/platform/config/QuartzConfig.java | 77 -- .../yfd/platform/config/ResponseResult.java | 57 -- .../yfd/platform/config/SecurityConfig.java | 90 --- .../yfd/platform/config/SwaggerConfig.java | 49 -- .../com/yfd/platform/config/WebConfig.java | 61 -- .../yfd/platform/config/WebSocketConfig.java | 16 - .../yfd/platform/config/bean/LoginCode.java | 61 -- .../platform/config/bean/LoginCodeEnum.java | 43 -- .../platform/config/bean/LoginProperties.java | 110 --- .../config/thread/AsyncTaskExecutePool.java | 70 -- .../config/thread/AsyncTaskProperties.java | 39 - .../config/thread/TheadFactoryName.java | 62 -- .../config/thread/ThreadPoolExecutorUtil.java | 44 -- .../com/yfd/platform/constant/Constant.java | 42 -- .../yfd/platform/datasource/DataSource.java | 17 - .../platform/datasource/DataSourceAspect.java | 55 -- .../datasource/DynamicDataSource.java | 40 - .../datasource/DynamicDataSourceConfig.java | 51 -- .../exception/AccessDeniedHandExcetion.java | 27 - .../exception/AuthenticationException.java | 32 - .../exception/BadConfigurationException.java | 98 --- .../exception/BadRequestException.java | 41 -- .../exception/ChildrenExistException.java | 20 - .../exception/EntityExistException.java | 34 - .../exception/EntityNotFoundException.java | 34 - .../controller/DataSourceController.java | 42 -- .../system/controller/LoginController.java | 238 ------ .../system/controller/MessageController.java | 150 ---- .../controller/QuartzJobController.java | 183 ----- .../system/controller/SSEController.java | 59 -- .../controller/SysConfigController.java | 68 -- .../controller/SysDictionaryController.java | 142 ---- .../SysDictionaryItemsController.java | 201 ----- .../system/controller/SysLogController.java | 74 -- .../system/controller/SysMenuController.java | 310 -------- .../controller/SysOrganizationController.java | 213 ------ .../system/controller/SysRoleController.java | 318 -------- .../system/controller/UserController.java | 188 ----- .../platform/system/domain/Dictionary.java | 78 -- .../yfd/platform/system/domain/LoginUser.java | 76 -- .../yfd/platform/system/domain/Message.java | 117 --- .../yfd/platform/system/domain/QuartzJob.java | 118 --- .../yfd/platform/system/domain/SysConfig.java | 78 -- .../platform/system/domain/SysDictionary.java | 73 -- .../system/domain/SysDictionaryItems.java | 79 -- .../yfd/platform/system/domain/SysLog.java | 94 --- .../yfd/platform/system/domain/SysMenu.java | 114 --- .../system/domain/SysOrganization.java | 93 --- .../yfd/platform/system/domain/SysRole.java | 99 --- .../yfd/platform/system/domain/SysUser.java | 120 --- .../platform/system/mapper/MessageMapper.java | 16 - .../system/mapper/QuartzJobMapper.java | 16 - .../system/mapper/SysConfigMapper.java | 17 - .../mapper/SysDictionaryItemsMapper.java | 17 - .../system/mapper/SysDictionaryMapper.java | 22 - .../platform/system/mapper/SysLogMapper.java | 16 - .../platform/system/mapper/SysMenuMapper.java | 59 -- .../system/mapper/SysOrganizationMapper.java | 33 - .../platform/system/mapper/SysRoleMapper.java | 112 --- .../platform/system/mapper/SysUserMapper.java | 96 --- .../system/service/IMessageService.java | 16 - .../system/service/IQuartzJobService.java | 43 -- .../system/service/ISysConfigService.java | 22 - .../service/ISysDictionaryItemsService.java | 47 -- .../system/service/ISysDictionaryService.java | 45 -- .../system/service/ISysLogService.java | 52 -- .../system/service/ISysMenuService.java | 101 --- .../service/ISysOrganizationService.java | 60 -- .../system/service/ISysRoleService.java | 68 -- .../platform/system/service/IUserService.java | 143 ---- .../service/impl/MessageServiceImpl.java | 20 - .../service/impl/QuartzJobServiceImpl.java | 114 --- .../service/impl/SysConfigServiceImpl.java | 34 - .../impl/SysDictionaryItemsServiceImpl.java | 123 ---- .../impl/SysDictionaryServiceImpl.java | 114 --- .../service/impl/SysLogServiceImpl.java | 219 ------ .../service/impl/SysMenuServiceImpl.java | 695 ------------------ .../impl/SysOrganizationServiceImpl.java | 363 --------- .../service/impl/SysRoleServiceImpl.java | 174 ----- .../service/impl/UserDetailsServiceImpl.java | 52 -- .../system/service/impl/UserServiceImpl.java | 579 --------------- .../com/yfd/platform/task/TaskMessage.java | 57 -- .../java/com/yfd/platform/utils/CallBack.java | 43 -- .../com/yfd/platform/utils/CodeGenerator.java | 75 -- .../yfd/platform/utils/EncryptConfigUtil.java | 28 - .../com/yfd/platform/utils/EncryptUtils.java | 100 --- .../com/yfd/platform/utils/ExecutionJob.java | 103 --- .../java/com/yfd/platform/utils/FileUtil.java | 398 ---------- .../com/yfd/platform/utils/MpGenerator.java | 79 -- .../platform/utils/ObjectConverterUtil.java | 149 ---- .../yfd/platform/utils/PropertiesUtils.java | 29 - .../com/yfd/platform/utils/QuartzManage.java | 187 ----- .../yfd/platform/utils/QuartzRunnable.java | 58 -- .../com/yfd/platform/utils/RequestHolder.java | 34 - .../java/com/yfd/platform/utils/RsaUtils.java | 190 ----- .../com/yfd/platform/utils/SecurityUtils.java | 84 --- .../platform/utils/SpringContextHolder.java | 145 ---- .../com/yfd/platform/utils/StringUtils.java | 305 -------- .../src/main/resources/application-dev.yml | 94 --- .../src/main/resources/application-devtw.yml | 94 --- .../main/resources/application-framework.yml | 30 - .../src/main/resources/application-server.yml | 52 -- backend/src/main/resources/application.yml | 34 - backend/src/main/resources/banner.txt | 8 - .../src/main/resources/ip2region/ip2region.db | 0 .../main/resources/log4jdbc.log4j2.properties | 4 - backend/src/main/resources/logback-spring.xml | 38 - backend/src/main/resources/logback.xml | 45 -- .../mapper/system/DictionaryMapper.xml | 5 - .../resources/mapper/system/MessageMapper.xml | 5 - .../resources/mapper/system/Model3dMapper.xml | 5 - .../mapper/system/QuartzJobMapper.xml | 5 - .../mapper/system/SysConfigMapper.xml | 5 - .../system/SysDictionaryItemsMapper.xml | 5 - .../mapper/system/SysDictionaryMapper.xml | 15 - .../resources/mapper/system/SysLogMapper.xml | 5 - .../resources/mapper/system/SysMenuMapper.xml | 103 --- .../mapper/system/SysMessageMapper.xml | 5 - .../mapper/system/SysOrganizationMapper.xml | 14 - .../mapper/system/SysQuartzJobMapper.xml | 5 - .../resources/mapper/system/SysRoleMapper.xml | 150 ---- .../resources/mapper/system/SysUserMapper.xml | 116 --- backend/src/main/resources/quartz.properties | 21 - .../resources/static/assets/401-099a3a32.js | 1 - .../resources/static/assets/401-485a4475.js | 1 - .../resources/static/assets/401-a61ddb94.gif | Bin 164227 -> 0 bytes .../resources/static/assets/401-fffd1e4b.css | 1 - .../resources/static/assets/404-51ac6f86.css | 1 - .../resources/static/assets/404-538aa4d7.png | Bin 98071 -> 0 bytes .../resources/static/assets/404-6dcbdda2.js | 1 - .../resources/static/assets/404-ae343fa7.js | 1 - .../static/assets/404_cloud-98e7ac66.png | Bin 4766 -> 0 bytes .../static/assets/BarChart-a4765ae3.js | 1 - .../static/assets/BarChart-efd5cbe1.js | 1 - .../static/assets/FunnelChart-79f3d5f7.js | 1 - .../static/assets/FunnelChart-8e41d306.js | 1 - .../static/assets/PieChart-bffd7bcc.js | 1 - .../static/assets/PieChart-f0d9d351.js | 1 - .../static/assets/RadarChart-94b1112a.js | 1 - .../static/assets/RadarChart-e43ec971.js | 1 - .../static/assets/editor-501cf061.css | 1 - .../static/assets/editor-b13c93a6.js | 186 ----- .../static/assets/editor-ec3491e5.js | 186 ----- .../static/assets/index-013c92bf.css | 1 - .../resources/static/assets/index-01e2cfa9.js | 1 - .../resources/static/assets/index-04bb232d.js | 1 - .../resources/static/assets/index-0985e541.js | 1 - .../resources/static/assets/index-09ad406e.js | 1 - .../resources/static/assets/index-175944b3.js | 18 - .../static/assets/index-1a396a09.css | 1 - .../resources/static/assets/index-1e7d81fe.js | 1 - .../resources/static/assets/index-2814df08.js | 1 - .../resources/static/assets/index-2a2e686f.js | 1 - .../static/assets/index-2b88764d.css | 1 - .../resources/static/assets/index-2be13ce1.js | 1 - .../static/assets/index-362b32fa.css | 1 - .../resources/static/assets/index-373114d3.js | 1 - .../static/assets/index-3e4e0c0c.css | 1 - .../static/assets/index-3ea31a03.css | 1 - .../resources/static/assets/index-486d1d98.js | 1 - .../static/assets/index-4e36f11e.css | 1 - .../resources/static/assets/index-5282e30f.js | 1 - .../resources/static/assets/index-5682e1da.js | 1 - .../static/assets/index-5a5afaa7.css | 1 - .../resources/static/assets/index-5c62e6c4.js | 83 --- .../resources/static/assets/index-63bba755.js | 1 - .../resources/static/assets/index-6cf33161.js | 1 - .../static/assets/index-6ee17396.css | 1 - .../resources/static/assets/index-70f67d2a.js | 18 - .../resources/static/assets/index-86feac6e.js | 1 - .../resources/static/assets/index-9057b190.js | 1 - .../static/assets/index-968257e1.css | 1 - .../resources/static/assets/index-98c36269.js | 1 - .../static/assets/index-9c04fca4.css | 1 - .../resources/static/assets/index-a59640f3.js | 1 - .../static/assets/index-a7bce641.css | 1 - .../resources/static/assets/index-b25f0d08.js | 96 --- .../static/assets/index-b5bae886.css | 1 - .../static/assets/index-b5bb9b55.css | 1 - .../resources/static/assets/index-b98a9d85.js | 1 - .../resources/static/assets/index-bca4e108.js | 1 - .../resources/static/assets/index-bcf8ef0f.js | 1 - .../resources/static/assets/index-c03bc2fe.js | 1 - .../resources/static/assets/index-c2e52e75.js | 1 - .../resources/static/assets/index-ca91e236.js | 1 - .../resources/static/assets/index-cbe38f69.js | 1 - .../static/assets/index-cdc0bc49.css | 1 - .../resources/static/assets/index-ce8e85c4.js | 1 - .../static/assets/index-dd0c8cf0.css | 1 - .../resources/static/assets/index-de9a584a.js | 1 - .../resources/static/assets/index-e051e64c.js | 1 - .../resources/static/assets/index-e5abaec0.js | 1 - .../resources/static/assets/index-eb03182a.js | 1 - .../resources/static/assets/index-f43bf226.js | 1 - .../resources/static/assets/index-f52936ec.js | 1 - .../resources/static/assets/index-f88fe59a.js | 1 - .../resources/static/assets/index-fa740669.js | 1 - .../resources/static/assets/index-fc9ca505.js | 1 - .../static/assets/index1-5c7d9d99.js | 1 - .../static/assets/index1-ac4606af.js | 1 - .../static/assets/index2-26043b81.js | 1 - .../static/assets/index2-46aebe19.js | 1 - .../static/assets/indicator-5b15d0d1.png | Bin 341643 -> 0 bytes .../static/assets/lbcz_sc-0ed76926.js | 1 - .../static/assets/lbcz_td-b5984317.js | 1 - .../static/assets/lbcz_xg-6b0694a6.js | 1 - .../resources/static/assets/logo-03d6d6da.png | Bin 6849 -> 0 bytes ...ue_type_script_setup_true_lang-42348387.js | 1 - ...ue_type_script_setup_true_lang-7a09a11a.js | 1 - .../static/assets/personalCenter-a026f3ae.js | 1 - .../static/assets/personalCenter-a1e83f26.js | 1 - .../static/assets/personalCenter-ad68cb91.css | 1 - .../static/assets/resize-24879ea2.js | 60 -- .../static/assets/resize-9f0962b6.js | 60 -- .../static/assets/rsaEncrypt-96cab0ea.js | 29 - .../static/assets/sortable.esm-616533ae.js | 6 - .../static/assets/tagsView-319ee48a.js | 1 - .../static/assets/tagsView-6df0ea3e.js | 1 - .../static/assets/top_tx-3cab94c6.png | Bin 28367 -> 0 bytes .../resources/static/assets/u287-9a3328bc.gif | Bin 246181 -> 0 bytes .../static/assets/uploader-0562c8e7.js | 1 - .../static/assets/uploader-343a71b2.js | 1 - .../static/assets/uploader-4183de44.css | 1 - backend/src/main/resources/static/favicon.ico | Bin 4286 -> 0 bytes .../icon/0312cfde741a47ad9dfd2b6379c24229.png | Bin 630 -> 0 bytes .../icon/1376916838a345799b96ac1eacc8608f.png | Bin 520 -> 0 bytes .../icon/1449347c56414681a321dc3c84302b00.png | Bin 630 -> 0 bytes .../icon/56b7117b688a40699246aa378119c005.png | Bin 520 -> 0 bytes .../icon/78e0a2de1f8e4354ad4bc46101ff7b1d.png | Bin 570 -> 0 bytes .../icon/88d05ff3ffa74bcd9f80584c9edf300d.png | Bin 630 -> 0 bytes .../icon/91a883092f2a40ee84b135aea9640fd1.png | Bin 431 -> 0 bytes .../icon/aff16e96f9164e5196942b3738c55c10.png | Bin 630 -> 0 bytes .../icon/beaea0bdfd514f61b451d400e93f81b4.png | Bin 498 -> 0 bytes .../icon/c6cdc92296c24d168c8c08aa2009d7ca.png | Bin 527 -> 0 bytes .../icon/cc9abc741e7d444e9d8736056d76cb49.png | Bin 414 -> 0 bytes .../icon/cf3e2b0ace7a42a7b627cdd4929b21d1.png | Bin 640 -> 0 bytes backend/src/main/resources/static/index.html | 17 - .../platform/PlatformApplicationTests.java | 49 -- .../test/java/com/yfd/platform/TestGuaVA.java | 73 -- 258 files changed, 154 insertions(+), 13295 deletions(-) delete mode 100644 backend/src/main/java/com/yfd/platform/PlatformApplication.java delete mode 100644 backend/src/main/java/com/yfd/platform/ServletInitializer.java delete mode 100644 backend/src/main/java/com/yfd/platform/annotation/AnonymousAccess.java delete mode 100644 backend/src/main/java/com/yfd/platform/annotation/Log.java delete mode 100644 backend/src/main/java/com/yfd/platform/annotation/rest/AnonymousGetMapping.java delete mode 100644 backend/src/main/java/com/yfd/platform/aspect/LogAspect.java delete mode 100644 backend/src/main/java/com/yfd/platform/component/ServerSendEventServer.java delete mode 100644 backend/src/main/java/com/yfd/platform/component/WebSocketServer.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/AppInitProperties.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/DataInitializer.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/FileProperties.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/FileSpaceProperties.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/GlobalExceptionHandler.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/JobRunner.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/JwtAuthenticationTokenFilter.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/MessageConfig.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/MybitsPlusConfig.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/ProdApiPrefixFilter.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/QuartzConfig.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/ResponseResult.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/SecurityConfig.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/WebConfig.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/WebSocketConfig.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/bean/LoginCode.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/bean/LoginCodeEnum.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/bean/LoginProperties.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/thread/AsyncTaskExecutePool.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/thread/AsyncTaskProperties.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/thread/TheadFactoryName.java delete mode 100644 backend/src/main/java/com/yfd/platform/config/thread/ThreadPoolExecutorUtil.java delete mode 100644 backend/src/main/java/com/yfd/platform/constant/Constant.java delete mode 100644 backend/src/main/java/com/yfd/platform/datasource/DataSource.java delete mode 100644 backend/src/main/java/com/yfd/platform/datasource/DataSourceAspect.java delete mode 100644 backend/src/main/java/com/yfd/platform/datasource/DynamicDataSource.java delete mode 100644 backend/src/main/java/com/yfd/platform/datasource/DynamicDataSourceConfig.java delete mode 100644 backend/src/main/java/com/yfd/platform/exception/AccessDeniedHandExcetion.java delete mode 100644 backend/src/main/java/com/yfd/platform/exception/AuthenticationException.java delete mode 100644 backend/src/main/java/com/yfd/platform/exception/BadConfigurationException.java delete mode 100644 backend/src/main/java/com/yfd/platform/exception/BadRequestException.java delete mode 100644 backend/src/main/java/com/yfd/platform/exception/ChildrenExistException.java delete mode 100644 backend/src/main/java/com/yfd/platform/exception/EntityExistException.java delete mode 100644 backend/src/main/java/com/yfd/platform/exception/EntityNotFoundException.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/DataSourceController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/LoginController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/MessageController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/QuartzJobController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/SSEController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/SysConfigController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/SysDictionaryController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/SysDictionaryItemsController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/SysLogController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/SysMenuController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/SysOrganizationController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/SysRoleController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/controller/UserController.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/Dictionary.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/LoginUser.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/Message.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/QuartzJob.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/SysConfig.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/SysDictionary.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/SysDictionaryItems.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/SysLog.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/SysMenu.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/SysOrganization.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/SysRole.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/domain/SysUser.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/MessageMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/QuartzJobMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/SysConfigMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/SysDictionaryItemsMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/SysDictionaryMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/SysLogMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/SysMenuMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/SysOrganizationMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/IMessageService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/IQuartzJobService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/ISysConfigService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/ISysDictionaryItemsService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/ISysDictionaryService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/ISysLogService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/ISysMenuService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/ISysOrganizationService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/ISysRoleService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/IUserService.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/MessageServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/QuartzJobServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/SysConfigServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/SysDictionaryItemsServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/SysDictionaryServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/SysLogServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/SysMenuServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/SysRoleServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java delete mode 100644 backend/src/main/java/com/yfd/platform/task/TaskMessage.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/CallBack.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/CodeGenerator.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/EncryptConfigUtil.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/EncryptUtils.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/ExecutionJob.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/FileUtil.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/MpGenerator.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/ObjectConverterUtil.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/PropertiesUtils.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/QuartzManage.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/QuartzRunnable.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/RequestHolder.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/RsaUtils.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/SecurityUtils.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/SpringContextHolder.java delete mode 100644 backend/src/main/java/com/yfd/platform/utils/StringUtils.java delete mode 100644 backend/src/main/resources/application-dev.yml delete mode 100644 backend/src/main/resources/application-devtw.yml delete mode 100644 backend/src/main/resources/application-framework.yml delete mode 100644 backend/src/main/resources/application-server.yml delete mode 100644 backend/src/main/resources/application.yml delete mode 100644 backend/src/main/resources/banner.txt delete mode 100644 backend/src/main/resources/ip2region/ip2region.db delete mode 100644 backend/src/main/resources/log4jdbc.log4j2.properties delete mode 100644 backend/src/main/resources/logback-spring.xml delete mode 100644 backend/src/main/resources/logback.xml delete mode 100644 backend/src/main/resources/mapper/system/DictionaryMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/MessageMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/Model3dMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/QuartzJobMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysConfigMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysDictionaryItemsMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysDictionaryMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysLogMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysMenuMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysMessageMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysOrganizationMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysQuartzJobMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysRoleMapper.xml delete mode 100644 backend/src/main/resources/mapper/system/SysUserMapper.xml delete mode 100644 backend/src/main/resources/quartz.properties delete mode 100644 backend/src/main/resources/static/assets/401-099a3a32.js delete mode 100644 backend/src/main/resources/static/assets/401-485a4475.js delete mode 100644 backend/src/main/resources/static/assets/401-a61ddb94.gif delete mode 100644 backend/src/main/resources/static/assets/401-fffd1e4b.css delete mode 100644 backend/src/main/resources/static/assets/404-51ac6f86.css delete mode 100644 backend/src/main/resources/static/assets/404-538aa4d7.png delete mode 100644 backend/src/main/resources/static/assets/404-6dcbdda2.js delete mode 100644 backend/src/main/resources/static/assets/404-ae343fa7.js delete mode 100644 backend/src/main/resources/static/assets/404_cloud-98e7ac66.png delete mode 100644 backend/src/main/resources/static/assets/BarChart-a4765ae3.js delete mode 100644 backend/src/main/resources/static/assets/BarChart-efd5cbe1.js delete mode 100644 backend/src/main/resources/static/assets/FunnelChart-79f3d5f7.js delete mode 100644 backend/src/main/resources/static/assets/FunnelChart-8e41d306.js delete mode 100644 backend/src/main/resources/static/assets/PieChart-bffd7bcc.js delete mode 100644 backend/src/main/resources/static/assets/PieChart-f0d9d351.js delete mode 100644 backend/src/main/resources/static/assets/RadarChart-94b1112a.js delete mode 100644 backend/src/main/resources/static/assets/RadarChart-e43ec971.js delete mode 100644 backend/src/main/resources/static/assets/editor-501cf061.css delete mode 100644 backend/src/main/resources/static/assets/editor-b13c93a6.js delete mode 100644 backend/src/main/resources/static/assets/editor-ec3491e5.js delete mode 100644 backend/src/main/resources/static/assets/index-013c92bf.css delete mode 100644 backend/src/main/resources/static/assets/index-01e2cfa9.js delete mode 100644 backend/src/main/resources/static/assets/index-04bb232d.js delete mode 100644 backend/src/main/resources/static/assets/index-0985e541.js delete mode 100644 backend/src/main/resources/static/assets/index-09ad406e.js delete mode 100644 backend/src/main/resources/static/assets/index-175944b3.js delete mode 100644 backend/src/main/resources/static/assets/index-1a396a09.css delete mode 100644 backend/src/main/resources/static/assets/index-1e7d81fe.js delete mode 100644 backend/src/main/resources/static/assets/index-2814df08.js delete mode 100644 backend/src/main/resources/static/assets/index-2a2e686f.js delete mode 100644 backend/src/main/resources/static/assets/index-2b88764d.css delete mode 100644 backend/src/main/resources/static/assets/index-2be13ce1.js delete mode 100644 backend/src/main/resources/static/assets/index-362b32fa.css delete mode 100644 backend/src/main/resources/static/assets/index-373114d3.js delete mode 100644 backend/src/main/resources/static/assets/index-3e4e0c0c.css delete mode 100644 backend/src/main/resources/static/assets/index-3ea31a03.css delete mode 100644 backend/src/main/resources/static/assets/index-486d1d98.js delete mode 100644 backend/src/main/resources/static/assets/index-4e36f11e.css delete mode 100644 backend/src/main/resources/static/assets/index-5282e30f.js delete mode 100644 backend/src/main/resources/static/assets/index-5682e1da.js delete mode 100644 backend/src/main/resources/static/assets/index-5a5afaa7.css delete mode 100644 backend/src/main/resources/static/assets/index-5c62e6c4.js delete mode 100644 backend/src/main/resources/static/assets/index-63bba755.js delete mode 100644 backend/src/main/resources/static/assets/index-6cf33161.js delete mode 100644 backend/src/main/resources/static/assets/index-6ee17396.css delete mode 100644 backend/src/main/resources/static/assets/index-70f67d2a.js delete mode 100644 backend/src/main/resources/static/assets/index-86feac6e.js delete mode 100644 backend/src/main/resources/static/assets/index-9057b190.js delete mode 100644 backend/src/main/resources/static/assets/index-968257e1.css delete mode 100644 backend/src/main/resources/static/assets/index-98c36269.js delete mode 100644 backend/src/main/resources/static/assets/index-9c04fca4.css delete mode 100644 backend/src/main/resources/static/assets/index-a59640f3.js delete mode 100644 backend/src/main/resources/static/assets/index-a7bce641.css delete mode 100644 backend/src/main/resources/static/assets/index-b25f0d08.js delete mode 100644 backend/src/main/resources/static/assets/index-b5bae886.css delete mode 100644 backend/src/main/resources/static/assets/index-b5bb9b55.css delete mode 100644 backend/src/main/resources/static/assets/index-b98a9d85.js delete mode 100644 backend/src/main/resources/static/assets/index-bca4e108.js delete mode 100644 backend/src/main/resources/static/assets/index-bcf8ef0f.js delete mode 100644 backend/src/main/resources/static/assets/index-c03bc2fe.js delete mode 100644 backend/src/main/resources/static/assets/index-c2e52e75.js delete mode 100644 backend/src/main/resources/static/assets/index-ca91e236.js delete mode 100644 backend/src/main/resources/static/assets/index-cbe38f69.js delete mode 100644 backend/src/main/resources/static/assets/index-cdc0bc49.css delete mode 100644 backend/src/main/resources/static/assets/index-ce8e85c4.js delete mode 100644 backend/src/main/resources/static/assets/index-dd0c8cf0.css delete mode 100644 backend/src/main/resources/static/assets/index-de9a584a.js delete mode 100644 backend/src/main/resources/static/assets/index-e051e64c.js delete mode 100644 backend/src/main/resources/static/assets/index-e5abaec0.js delete mode 100644 backend/src/main/resources/static/assets/index-eb03182a.js delete mode 100644 backend/src/main/resources/static/assets/index-f43bf226.js delete mode 100644 backend/src/main/resources/static/assets/index-f52936ec.js delete mode 100644 backend/src/main/resources/static/assets/index-f88fe59a.js delete mode 100644 backend/src/main/resources/static/assets/index-fa740669.js delete mode 100644 backend/src/main/resources/static/assets/index-fc9ca505.js delete mode 100644 backend/src/main/resources/static/assets/index1-5c7d9d99.js delete mode 100644 backend/src/main/resources/static/assets/index1-ac4606af.js delete mode 100644 backend/src/main/resources/static/assets/index2-26043b81.js delete mode 100644 backend/src/main/resources/static/assets/index2-46aebe19.js delete mode 100644 backend/src/main/resources/static/assets/indicator-5b15d0d1.png delete mode 100644 backend/src/main/resources/static/assets/lbcz_sc-0ed76926.js delete mode 100644 backend/src/main/resources/static/assets/lbcz_td-b5984317.js delete mode 100644 backend/src/main/resources/static/assets/lbcz_xg-6b0694a6.js delete mode 100644 backend/src/main/resources/static/assets/logo-03d6d6da.png delete mode 100644 backend/src/main/resources/static/assets/page.vue_vue_type_script_setup_true_lang-42348387.js delete mode 100644 backend/src/main/resources/static/assets/page.vue_vue_type_script_setup_true_lang-7a09a11a.js delete mode 100644 backend/src/main/resources/static/assets/personalCenter-a026f3ae.js delete mode 100644 backend/src/main/resources/static/assets/personalCenter-a1e83f26.js delete mode 100644 backend/src/main/resources/static/assets/personalCenter-ad68cb91.css delete mode 100644 backend/src/main/resources/static/assets/resize-24879ea2.js delete mode 100644 backend/src/main/resources/static/assets/resize-9f0962b6.js delete mode 100644 backend/src/main/resources/static/assets/rsaEncrypt-96cab0ea.js delete mode 100644 backend/src/main/resources/static/assets/sortable.esm-616533ae.js delete mode 100644 backend/src/main/resources/static/assets/tagsView-319ee48a.js delete mode 100644 backend/src/main/resources/static/assets/tagsView-6df0ea3e.js delete mode 100644 backend/src/main/resources/static/assets/top_tx-3cab94c6.png delete mode 100644 backend/src/main/resources/static/assets/u287-9a3328bc.gif delete mode 100644 backend/src/main/resources/static/assets/uploader-0562c8e7.js delete mode 100644 backend/src/main/resources/static/assets/uploader-343a71b2.js delete mode 100644 backend/src/main/resources/static/assets/uploader-4183de44.css delete mode 100644 backend/src/main/resources/static/favicon.ico delete mode 100644 backend/src/main/resources/static/icon/0312cfde741a47ad9dfd2b6379c24229.png delete mode 100644 backend/src/main/resources/static/icon/1376916838a345799b96ac1eacc8608f.png delete mode 100644 backend/src/main/resources/static/icon/1449347c56414681a321dc3c84302b00.png delete mode 100644 backend/src/main/resources/static/icon/56b7117b688a40699246aa378119c005.png delete mode 100644 backend/src/main/resources/static/icon/78e0a2de1f8e4354ad4bc46101ff7b1d.png delete mode 100644 backend/src/main/resources/static/icon/88d05ff3ffa74bcd9f80584c9edf300d.png delete mode 100644 backend/src/main/resources/static/icon/91a883092f2a40ee84b135aea9640fd1.png delete mode 100644 backend/src/main/resources/static/icon/aff16e96f9164e5196942b3738c55c10.png delete mode 100644 backend/src/main/resources/static/icon/beaea0bdfd514f61b451d400e93f81b4.png delete mode 100644 backend/src/main/resources/static/icon/c6cdc92296c24d168c8c08aa2009d7ca.png delete mode 100644 backend/src/main/resources/static/icon/cc9abc741e7d444e9d8736056d76cb49.png delete mode 100644 backend/src/main/resources/static/icon/cf3e2b0ace7a42a7b627cdd4929b21d1.png delete mode 100644 backend/src/main/resources/static/index.html delete mode 100644 backend/src/test/java/com/yfd/platform/PlatformApplicationTests.java delete mode 100644 backend/src/test/java/com/yfd/platform/TestGuaVA.java diff --git a/backend/pom.xml b/backend/pom.xml index daccb25..71e10ab 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -11,7 +11,7 @@ com.yfd platform 1.0 - jar + pom platform springboot 项目基础框架4.0.3 @@ -46,6 +46,7 @@ + org.mybatis mybatis @@ -56,260 +57,151 @@ mybatis-spring 3.0.3 + + org.mybatis.spring.boot + mybatis-spring-boot-starter + ${mybatis.spring.boot.starter.version} + + + + + com.baomidou + mybatis-plus-spring-boot4-starter + ${mybatis-plus.version} + + + com.baomidou + mybatis-plus-jsqlparser + ${mybatis-plus.version} + + + com.baomidou + mybatis-plus-generator + ${mybatis-plus.version} + + + + + com.alibaba + druid + ${druid.version} + + + com.dameng + DmJdbcDriver18 + 8.1.2.79 + runtime + + + com.oracle.database.jdbc + ojdbc8 + 21.9.0.0 + runtime + + + com.oracle.database.nls + orai18n + 21.9.0.0 + runtime + + + org.xerial + sqlite-jdbc + ${sqlite-jdbc.version} + + + + + com.google.guava + guava + ${guava.version} + + + org.apache.commons + commons-lang3 + + + org.projectlombok + lombok + 1.18.42 + true + + + cn.hutool + hutool-all + ${hutool.version} + + + org.apache.poi + poi + ${poi.version} + + + org.apache.poi + poi-ooxml + ${poi.ooxml.version} + + + com.alibaba + fastjson + ${fastjson.version} + + + org.freemarker + freemarker + ${freemarker.version} + compile + + + org.jsoup + jsoup + ${jsoup.version} + + + com.github.ulisesbocchio + jasypt-spring-boot-starter + ${jasypt.version} + + + org.lionsoul + ip2region + ${ip2region.version} + + + com.github.whvcse + easy-captcha + ${easy.captcha.version} + + + eu.bitwalker + UserAgentUtils + ${useragentutils.version} + + + org.openjdk.nashorn + nashorn-core + 15.4 + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + ${springdoc.version} + - - - org.springframework.boot - spring-boot-starter-actuator - - - - - org.springframework.boot - spring-boot-starter-web - - - - - org.springframework.boot - spring-boot-starter-security - - - - - org.springframework.boot - spring-boot-starter-data-redis - - - - - org.springframework.boot - spring-boot-starter-websocket - - - - - org.springframework.boot - spring-boot-starter-cache - - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - com.google.guava - guava - ${guava.version} - - - - - - - org.springframework.boot - spring-boot-starter-quartz - - - - - - - - - - - org.mybatis.spring.boot - mybatis-spring-boot-starter - ${mybatis.spring.boot.starter.version} - - - - - org.mybatis - mybatis - ${mybatis.version} - - - - - com.alibaba - druid - ${druid.version} - - - - - org.springframework.boot - spring-boot-starter-jdbc - - - - - com.mysql - mysql-connector-j - runtime - - - - - com.dameng - DmJdbcDriver18 - 8.1.2.79 - runtime - - - - - com.oracle.database.jdbc - ojdbc8 - 21.9.0.0 - runtime - - - - - com.oracle.database.nls - orai18n - 21.9.0.0 - runtime - - - - - org.xerial - sqlite-jdbc - ${sqlite-jdbc.version} - - - - - com.baomidou - mybatis-plus-spring-boot4-starter - ${mybatis-plus.version} - - - - com.baomidou - mybatis-plus-jsqlparser - ${mybatis-plus.version} - - - - com.baomidou - mybatis-plus-generator - ${mybatis-plus.version} - - - - - org.apache.commons - commons-lang3 - - - - - org.projectlombok - lombok - true - - - - - org.springframework.boot - spring-boot-starter-aspectj - - - - - cn.hutool - hutool-all - ${hutool.version} - - - - - org.apache.poi - poi - ${poi.version} - - - org.apache.poi - poi-ooxml - ${poi.ooxml.version} - - - - - com.alibaba - fastjson - ${fastjson.version} - - - - - org.springdoc - springdoc-openapi-starter-webmvc-ui - ${springdoc.version} - - - - io.micrometer - micrometer-registry-prometheus - - - - org.freemarker - freemarker - ${freemarker.version} - compile - - - org.jsoup - jsoup - ${jsoup.version} - - - - - com.github.ulisesbocchio - jasypt-spring-boot-starter - ${jasypt.version} - - - - org.lionsoul - ip2region - ${ip2region.version} - - - - - com.github.whvcse - easy-captcha - ${easy.captcha.version} - - - - - eu.bitwalker - UserAgentUtils - ${useragentutils.version} - - - - org.openjdk.nashorn - nashorn-core - 15.4 - + + + platform-system + platform-common + qgc-env-server + qgc-eng-server + + @@ -408,18 +300,18 @@ enforce - - - - [3.6.3,) - - - [21,) - - - - - + + + + [3.6.3,) + + + [21,) + + + + + diff --git a/backend/src/main/java/com/yfd/platform/PlatformApplication.java b/backend/src/main/java/com/yfd/platform/PlatformApplication.java deleted file mode 100644 index 03ca484..0000000 --- a/backend/src/main/java/com/yfd/platform/PlatformApplication.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.yfd.platform; - -import com.yfd.platform.annotation.rest.AnonymousGetMapping; -import com.yfd.platform.datasource.DynamicDataSourceConfig; -import com.yfd.platform.utils.SpringContextHolder; -import org.mybatis.spring.annotation.MapperScan; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration; -import org.springframework.boot.jdbc.autoconfigure.DataSourceAutoConfiguration; -import org.springframework.boot.web.server.servlet.context.ServletComponentScan; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; -import org.springframework.transaction.annotation.EnableTransactionManagement; -import org.springframework.web.bind.annotation.RestController; - -//@SpringBootApplication -@RestController -@EnableTransactionManagement -@ServletComponentScan("com.yfd.platform.config") -@MapperScan(basePackages = "com.yfd.platform.*.mapper") -@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class, DataRedisAutoConfiguration.class}) -@Import({DynamicDataSourceConfig.class}) -@EnableCaching -public class PlatformApplication { - - public static void main(String[] args) { - SpringApplication.run(PlatformApplication.class, args); - } - - @Bean - public SpringContextHolder springContextHolder() { - return new SpringContextHolder(); - } - - /** - * 访问首页提示 - * - * @return / - */ - @AnonymousGetMapping("/") - public String index() { - return "Backend service started successfully"; - } -} diff --git a/backend/src/main/java/com/yfd/platform/ServletInitializer.java b/backend/src/main/java/com/yfd/platform/ServletInitializer.java deleted file mode 100644 index 0234b48..0000000 --- a/backend/src/main/java/com/yfd/platform/ServletInitializer.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.yfd.platform; - -import org.springframework.boot.builder.SpringApplicationBuilder; -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; - -public class ServletInitializer extends SpringBootServletInitializer { - - @Override - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { - return application.sources(PlatformApplication.class); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/annotation/AnonymousAccess.java b/backend/src/main/java/com/yfd/platform/annotation/AnonymousAccess.java deleted file mode 100644 index 2fbd4c0..0000000 --- a/backend/src/main/java/com/yfd/platform/annotation/AnonymousAccess.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.annotation; - -import java.lang.annotation.*; - -/** - * @author jacky - * 用于标记匿名访问方法 - */ -@Inherited -@Documented -@Target({ElementType.METHOD,ElementType.ANNOTATION_TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface AnonymousAccess { - -} diff --git a/backend/src/main/java/com/yfd/platform/annotation/Log.java b/backend/src/main/java/com/yfd/platform/annotation/Log.java deleted file mode 100644 index 6739494..0000000 --- a/backend/src/main/java/com/yfd/platform/annotation/Log.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.yfd.platform.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * @author TangWei - * @date 2018-11-24 - */ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface Log { - - String value() default ""; - - String module() default ""; -} - diff --git a/backend/src/main/java/com/yfd/platform/annotation/rest/AnonymousGetMapping.java b/backend/src/main/java/com/yfd/platform/annotation/rest/AnonymousGetMapping.java deleted file mode 100644 index 01fcc32..0000000 --- a/backend/src/main/java/com/yfd/platform/annotation/rest/AnonymousGetMapping.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2002-2016 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.yfd.platform.annotation.rest; - -import com.yfd.platform.annotation.AnonymousAccess; -import org.springframework.core.annotation.AliasFor; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; - -import java.lang.annotation.*; - -/** - * Annotation for mapping HTTP {@code GET} requests onto specific handler - * methods. - *

- * 支持匿名访问 GetMapping - * - * @author liaojinlong - * @see RequestMapping - */ -@AnonymousAccess -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@Documented -@RequestMapping(method = RequestMethod.GET) -public @interface AnonymousGetMapping { - - /** - * Alias for {@link RequestMapping#name}. - */ - @AliasFor(annotation = RequestMapping.class) - String name() default ""; - - /** - * Alias for {@link RequestMapping#value}. - */ - @AliasFor(annotation = RequestMapping.class) - String[] value() default {}; - - /** - * Alias for {@link RequestMapping#path}. - */ - @AliasFor(annotation = RequestMapping.class) - String[] path() default {}; - - /** - * Alias for {@link RequestMapping#params}. - */ - @AliasFor(annotation = RequestMapping.class) - String[] params() default {}; - - /** - * Alias for {@link RequestMapping#headers}. - */ - @AliasFor(annotation = RequestMapping.class) - String[] headers() default {}; - - /** - * Alias for {@link RequestMapping#consumes}. - * - * @since 4.3.5 - */ - @AliasFor(annotation = RequestMapping.class) - String[] consumes() default {}; - - /** - * Alias for {@link RequestMapping#produces}. - */ - @AliasFor(annotation = RequestMapping.class) - String[] produces() default {}; - -} diff --git a/backend/src/main/java/com/yfd/platform/aspect/LogAspect.java b/backend/src/main/java/com/yfd/platform/aspect/LogAspect.java deleted file mode 100644 index 0c52a21..0000000 --- a/backend/src/main/java/com/yfd/platform/aspect/LogAspect.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.aspect; - -import com.yfd.platform.system.domain.SysLog; -import com.yfd.platform.system.mapper.SysUserMapper; -import com.yfd.platform.system.service.ISysLogService; -import com.yfd.platform.system.service.IUserService; -import com.yfd.platform.utils.RequestHolder; -import com.yfd.platform.utils.SecurityUtils; -import com.yfd.platform.utils.StringUtils; -import lombok.extern.slf4j.Slf4j; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Pointcut; -import org.springframework.stereotype.Component; - -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import java.util.Map; - -/** - * @author - * @date 2018-11-24 - */ -@Component -@Aspect -@Slf4j -public class LogAspect { - - @Resource - private final ISysLogService sysLogService; - - @Resource - private IUserService userService; - - ThreadLocal currentTime = new ThreadLocal<>(); - - public LogAspect(ISysLogService sysLogService) { - this.sysLogService = sysLogService; - } - - /** - * 配置切入点 - */ - @Pointcut("@annotation(com.yfd.platform.annotation.Log)") - public void logPointcut() { - // 该方法无方法体,主要为了让同类中其他方法使用此切入点 - } - - /** - * 配置环绕通知,使用在方法logPointcut()上注册的切入点 - * - * @param joinPoint join point for advice - */ - @Around("logPointcut()") - public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { - Object result; - currentTime.set(System.currentTimeMillis()); - result = joinPoint.proceed(); - SysLog log = new SysLog("INFO"); - currentTime.remove(); - HttpServletRequest request = RequestHolder.getHttpServletRequest(); - Map nameInfo = userService.getNameInfo(); - String nickname = nameInfo.get("nickname"); - String username = nameInfo.get("username"); - sysLogService.save(nickname, username, StringUtils.getBrowser(request), - StringUtils.getIp(request), joinPoint, log); - return result; - } - - public String getUsername() { - try { - return SecurityUtils.getCurrentUsername(); - } catch (Exception e) { - return ""; - } - } -} diff --git a/backend/src/main/java/com/yfd/platform/component/ServerSendEventServer.java b/backend/src/main/java/com/yfd/platform/component/ServerSendEventServer.java deleted file mode 100644 index ca1b1fe..0000000 --- a/backend/src/main/java/com/yfd/platform/component/ServerSendEventServer.java +++ /dev/null @@ -1,147 +0,0 @@ -package com.yfd.platform.component; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.MediaType; -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; - -/** - * @author Huhailong - * SSE Server send Event 服务器推送服务 - */ -@Slf4j -public class ServerSendEventServer { - - /** - * 当前连接数 - */ - private static AtomicInteger count = new AtomicInteger(0); - - private static Map sseEmitterMap = - new ConcurrentHashMap<>(); - - public static SseEmitter connect(String userId) { - //设置超时时间,0表示不过期,默认是30秒,超过时间未完成会抛出异常 - SseEmitter sseEmitter = new SseEmitter(0L); - //SseEmitter sseEmitter = new SseEmitter(); - //注册回调 - sseEmitter.onCompletion(completionCallBack(userId)); - sseEmitter.onError(errorCallBack(userId)); - sseEmitter.onTimeout(timeOutCallBack(userId)); - sseEmitterMap.put(userId, sseEmitter); - //数量+1 - count.getAndIncrement(); - log.info("create new sse connect ,current user:{}", userId); - return sseEmitter; - } - - /** - * 给指定用户发消息 - */ - public static void sendMessage(String userId, String message) { - if (sseEmitterMap.containsKey(userId)) { - try { - sseEmitterMap.get(userId).send(message); - } catch (IOException e) { - log.error("user id:{}, send message error:{}", userId, - e.getMessage()); - e.printStackTrace(); - } - } - } - - /** - * 给所有用户发消息 - */ - public static void sendMessage(String message) { - if (sseEmitterMap != null && !sseEmitterMap.isEmpty()) { - sseEmitterMap.forEach((k, v) -> { - // 发送消息 - sendMessage(k, message); - - }); - } - } - - /** - * 想多人发送消息,组播 - */ - public static void groupSendMessage(String groupId, String message) { - if (sseEmitterMap != null && !sseEmitterMap.isEmpty()) { - sseEmitterMap.forEach((k, v) -> { - try { - if (k.startsWith(groupId)) { - v.send(message, MediaType.APPLICATION_JSON); - } - } catch (IOException e) { - log.error("user id:{}, send message error:{}", groupId, - message); - removeUser(k); - } - }); - } - } - - public static void batchSendMessage(String message) { - sseEmitterMap.forEach((k, v) -> { - try { - v.send(message, MediaType.APPLICATION_JSON); - } catch (IOException e) { - log.error("user id:{}, send message error:{}", k, - e.getMessage()); - removeUser(k); - } - }); - } - - /** - * 群发消息 - */ - public static void batchSendMessage(String message, Set userIds) { - userIds.forEach(userId -> sendMessage(userId, message)); - } - - public static void removeUser(String userId) { - sseEmitterMap.remove(userId); - //数量-1 - count.getAndDecrement(); - log.info("remove user id:{}", userId); - } - - public static List getIds() { - return new ArrayList<>(sseEmitterMap.keySet()); - } - - public static int getUserCount() { - return count.intValue(); - } - - private static Runnable completionCallBack(String userId) { - return () -> { - log.info("结束连接,{}", userId); - removeUser(userId); - }; - } - - private static Runnable timeOutCallBack(String userId) { - return () -> { - log.info("连接超时,{}", userId); - removeUser(userId); - }; - } - - private static Consumer errorCallBack(String userId) { - return throwable -> { - log.error("连接异常,{}", userId); - removeUser(userId); - }; - } -} diff --git a/backend/src/main/java/com/yfd/platform/component/WebSocketServer.java b/backend/src/main/java/com/yfd/platform/component/WebSocketServer.java deleted file mode 100644 index 1d0b913..0000000 --- a/backend/src/main/java/com/yfd/platform/component/WebSocketServer.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.yfd.platform.component; - -import org.springframework.stereotype.Component; - -import jakarta.websocket.*; -import jakarta.websocket.server.PathParam; -import jakarta.websocket.server.ServerEndpoint; -import java.io.IOException; -import java.util.concurrent.CopyOnWriteArrayList; - -@ServerEndpoint("/websocket/{token}") -@Component -public class WebSocketServer { - private static int onlineCount=0;//在线人数 - private static CopyOnWriteArrayList webSocketSet=new CopyOnWriteArrayList();//在线用户集合 - private Session session;//与某个客户端的连接会话 - private String currentUser; - - @OnOpen - public void onOpen(@PathParam("token") String token, Session session){ - this.currentUser = token; - this.session=session; - webSocketSet.add(this);//加入set中 - addOnlineCount(); - System.out.println("有新连接加入!当前在线人数为"+getOnlineCount()); - allCurrentOnline(); - } - - @OnClose - public void onClose(){ - webSocketSet.remove(this); - subOnlineCount(); - System.out.println("有一连接关闭!当前在线人数为" + getOnlineCount()); - allCurrentOnline(); - } - - @OnMessage - public void onMessage(String message, Session session){ - System.out.println("来自客户端的消息:"+message); - for (WebSocketServer item:webSocketSet){ - try { - item.sendMessage(message); - } catch (IOException e) { - e.printStackTrace(); - continue; - } - } - } - - @OnError - public void onError(Session session, Throwable throwable){ - System.out.println("发生错误!"); - throwable.printStackTrace(); - } - - public void sendMessage(String message) throws IOException { - this.session.getBasicRemote().sendText(message); - } - - /** - * 获取当前所有在线用户名 - */ - public static void allCurrentOnline(){ - for (WebSocketServer item : webSocketSet) { - System.out.println(item.currentUser); - } - } - - /** - * 发送给指定用户 - */ - public static void sendMessageTo(String message,String token) throws IOException { - for (WebSocketServer item : webSocketSet) { - if(item.currentUser.equals(token)){ - item.session.getBasicRemote().sendText(message); - } - } - } - - /** - * 群发自定义消息 - */ - public static void sendInfo(String message) throws IOException { - System.out.println(message); - for (WebSocketServer item : webSocketSet) { - try { - item.sendMessage(message); - } catch (IOException e) { - continue; - } - } - } - - public static synchronized int getOnlineCount(){ - return onlineCount; - } - public static synchronized void addOnlineCount(){ - WebSocketServer.onlineCount++; - } - public static synchronized void subOnlineCount(){ - WebSocketServer.onlineCount--; - } - -} - - diff --git a/backend/src/main/java/com/yfd/platform/config/AppInitProperties.java b/backend/src/main/java/com/yfd/platform/config/AppInitProperties.java deleted file mode 100644 index 4ee304f..0000000 --- a/backend/src/main/java/com/yfd/platform/config/AppInitProperties.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.yfd.platform.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -@Data -@Configuration -@ConfigurationProperties(prefix = "app.init") -public class AppInitProperties { - private boolean enabled = false; - private String schema; - private String data; - // 用于判断是否已初始化:默认检查是否存在核心表 - private String markerTable = "sys_user"; - private String markerVersion = "v1.0.0"; -} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/config/DataInitializer.java b/backend/src/main/java/com/yfd/platform/config/DataInitializer.java deleted file mode 100644 index b5dab5a..0000000 --- a/backend/src/main/java/com/yfd/platform/config/DataInitializer.java +++ /dev/null @@ -1,129 +0,0 @@ -package com.yfd.platform.config; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.context.annotation.Profile; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.core.io.ByteArrayResource; -import org.springframework.core.io.Resource; -import org.springframework.core.io.ResourceLoader; -import org.springframework.core.io.support.EncodedResource; -import org.springframework.jdbc.datasource.init.ScriptUtils; -import org.springframework.jdbc.datasource.init.ScriptException; -import org.springframework.jdbc.datasource.init.ScriptStatementFailedException; -import org.springframework.stereotype.Component; - -import javax.sql.DataSource; -import java.nio.charset.StandardCharsets; -import java.util.stream.Collectors; -import org.springframework.util.StreamUtils; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; - -@Slf4j -@Component -@Profile({"dev","server"}) -@RequiredArgsConstructor -@Order(Ordered.HIGHEST_PRECEDENCE) -public class DataInitializer implements ApplicationRunner { - - private final DataSource dataSource; - private final AppInitProperties properties; - private final ResourceLoader resourceLoader; - - @Override - public void run(ApplicationArguments args) throws Exception { - if (!properties.isEnabled()) { - log.info("[DataInit] 自动初始化已关闭 app.init.enabled=false"); - return; - } - - try (Connection conn = dataSource.getConnection()) { - boolean initialized = tableExists(conn, properties.getMarkerTable()); - if (initialized) { - log.info("[DataInit] 检测到标记表已存在: {},跳过初始化", properties.getMarkerTable()); - return; - } - - log.info("[DataInit] 未检测到标记表: {},开始导入 schema 与 data", properties.getMarkerTable()); - executeIfPresent(conn, properties.getSchema()); - executeIfPresent(conn, properties.getData()); - log.info("[DataInit] 导入完成。marker={} version={}", properties.getMarkerTable(), properties.getMarkerVersion()); - } catch (Exception ex) { - log.error("[DataInit] 初始化失败: {}", ex.getMessage(), ex); - throw ex; - } - } - - private boolean tableExists(Connection conn, String tableName) { - if (tableName == null || tableName.isEmpty()) return false; - try { - DatabaseMetaData meta = conn.getMetaData(); - try (ResultSet rs = meta.getTables(conn.getCatalog(), null, tableName, null)) { - return rs.next(); - } - } catch (Exception e) { - log.warn("[DataInit] 检查表存在异常: {}", e.getMessage()); - return false; - } - } - - private void executeIfPresent(Connection conn, String location) throws Exception { - if (location == null || location.isEmpty()) return; - Resource resource = resourceLoader.getResource(location); - if (!resource.exists()) { - log.warn("[DataInit] 资源不存在: {}", location); - return; - } - log.info("[DataInit] 执行脚本: {}", location); - // 读取并清理脚本首部的 BOM 和危险语句(CREATE DATABASE / USE schema) - String sql = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8); - if (sql != null && !sql.isEmpty()) { - // 移除 UTF-8 BOM(\uFEFF) - if (sql.charAt(0) == '\uFEFF') { - sql = sql.substring(1); - } - // 移除 "USE xxx;" 和 "CREATE DATABASE" 等与连接无关的语句 - sql = sql.lines() - .filter(line -> { - String raw = line; - String t = raw.trim(); - String u = t.toUpperCase(); - // 过滤与连接无关或可能引发解析问题的语句/注释 - if (u.startsWith("USE ")) return false; - if (u.startsWith("CREATE DATABASE")) return false; - if (t.startsWith("--")) return false; // 单行注释 - if (t.startsWith("/*") || t.startsWith("*/")) return false; // 多行注释行 - if (t.startsWith("/*!")) return false; // MySQL 版本注释 - if (t.matches("^-+$")) return false; // 分隔线 - return true; - }) - .collect(Collectors.joining("\n")); - } - if (sql != null && !sql.trim().isEmpty()) { - try { - ScriptUtils.executeSqlScript(conn, new EncodedResource(new ByteArrayResource(sql.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8)); - } catch (ScriptStatementFailedException e) { - String preview = sql.lines() - .filter(s -> !s.trim().isEmpty()) - .limit(10) - .collect(Collectors.joining("\n")); - log.error("[DataInit] SQL语句执行失败: {}\n前10行预览:\n{}", e.getMessage(), preview); - throw e; - } catch (ScriptException e) { - String preview = sql.lines() - .filter(s -> !s.trim().isEmpty()) - .limit(10) - .collect(Collectors.joining("\n")); - log.error("[DataInit] 脚本执行失败: {}\n前10行预览:\n{}", e.getMessage(), preview); - throw e; - } - } else { - log.warn("[DataInit] 脚本在清理后为空,跳过执行: {}", location); - } - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/config/FileProperties.java b/backend/src/main/java/com/yfd/platform/config/FileProperties.java deleted file mode 100644 index c179499..0000000 --- a/backend/src/main/java/com/yfd/platform/config/FileProperties.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -/** - * @author - */ -@Data -@Configuration -@ConfigurationProperties(prefix = "file") -public class FileProperties { - - /** 文件大小限制 */ - private Long maxSize; - - /** 头像大小限制 */ - private Long avatarMaxSize; - - private ElPath mac; - - private ElPath linux; - - private ElPath windows; - - public ElPath getPath(){ - String os = System.getProperty("os.name"); - if(os.toLowerCase().startsWith("win")) { - return windows; - } else if(os.toLowerCase().startsWith("mac")){ - return mac; - } - return linux; - } - - @Data - public static class ElPath{ - - private String path; - - private String avatar; - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/FileSpaceProperties.java b/backend/src/main/java/com/yfd/platform/config/FileSpaceProperties.java deleted file mode 100644 index 74aab7d..0000000 --- a/backend/src/main/java/com/yfd/platform/config/FileSpaceProperties.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.yfd.platform.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Configuration; - -/** - * 文件空间相关配置,替换 @Value("${file-space.system}") 用法 - */ -@Data -@Configuration -@ConfigurationProperties(prefix = "file-space") -public class FileSpaceProperties { - - /** 基础目录,例如 D:/data/platform/ */ - private String system; -} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/config/GlobalExceptionHandler.java b/backend/src/main/java/com/yfd/platform/config/GlobalExceptionHandler.java deleted file mode 100644 index d241883..0000000 --- a/backend/src/main/java/com/yfd/platform/config/GlobalExceptionHandler.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.yfd.platform.config; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; - -/** - * @author TangWei - * @Date: 2023/3/27 18:07 - * @Description: - */ -@Slf4j -@ControllerAdvice -public class GlobalExceptionHandler { - - @ResponseBody - @ExceptionHandler(value = Throwable.class) - public ResponseResult handleException(Throwable e) { - log.error("message:{}", e.getMessage()); - e.printStackTrace(); - return ResponseResult.error(e.getMessage()); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/config/JobRunner.java b/backend/src/main/java/com/yfd/platform/config/JobRunner.java deleted file mode 100644 index 74bf8db..0000000 --- a/backend/src/main/java/com/yfd/platform/config/JobRunner.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.yfd.platform.system.domain.QuartzJob; -import com.yfd.platform.system.mapper.QuartzJobMapper; -import com.yfd.platform.utils.QuartzManage; -import lombok.RequiredArgsConstructor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.core.Ordered; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.List; - -/** - * @author - * @date 2019-01-07 - */ -@Component -@RequiredArgsConstructor -@Order(Ordered.LOWEST_PRECEDENCE) -public class JobRunner implements ApplicationRunner { - - private static final Logger log = LoggerFactory.getLogger(JobRunner.class); - private final QuartzJobMapper quartzJobMapper; - private final QuartzManage quartzManage; - - /** - * 项目启动时重新激活启用的定时任务 - * - * @param applicationArguments / - */ - @Override - public void run(ApplicationArguments applicationArguments) { - log.info("--------------------注入定时任务---------------------"); - List quartzJobs = - quartzJobMapper.selectList(new LambdaQueryWrapper().eq(QuartzJob::getStatus, "1")); - quartzJobs.forEach(quartzManage::addJob); - log.info("--------------------定时任务注入完成---------------------"); - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/JwtAuthenticationTokenFilter.java b/backend/src/main/java/com/yfd/platform/config/JwtAuthenticationTokenFilter.java deleted file mode 100644 index bcb79c0..0000000 --- a/backend/src/main/java/com/yfd/platform/config/JwtAuthenticationTokenFilter.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.yfd.platform.config; - -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.jwt.JWT; -import cn.hutool.jwt.JWTUtil; -import com.alibaba.fastjson.JSON; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.yfd.platform.component.ServerSendEventServer; -import com.yfd.platform.constant.Constant; -import com.yfd.platform.system.domain.LoginUser; -import com.yfd.platform.system.domain.Message; -import com.yfd.platform.system.service.IMessageService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; - -import jakarta.annotation.Resource; -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; - -@Component -public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { - - @Autowired - private WebConfig webConfig; - - @Override - protected void doFilterInternal(HttpServletRequest httpServletRequest, - HttpServletResponse httpServletResponse, - FilterChain filterChain) throws ServletException, IOException { - //获取token - String uri = httpServletRequest.getRequestURI(); - String token = httpServletRequest.getHeader("token"); - if (StrUtil.isEmpty(token) || "/user/login".equals(uri)) { - filterChain.doFilter(httpServletRequest, httpServletResponse); - return; - } - //解析token - boolean isok = JWTUtil.verify(token, "12345678".getBytes()); - String userid = ""; - if (isok) { - final JWT jwt = JWTUtil.parseToken(token); - userid = jwt.getPayload("userid").toString(); - //从cachekey中获取用户信息失效时间 - String cachekey = "expire_time:" + userid; - if(StrUtil.isNotEmpty(webConfig.loginuserCache().get(cachekey))){ - long expire_time =Long.parseLong(webConfig.loginuserCache().get(cachekey)); - if (System.currentTimeMillis() > expire_time) { - httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Token超过期限!"); - return; - } - } - } - - //从cachekey中获取用户信息 - String cachekey = "login:" + userid; - String jsonstr = webConfig.loginuserCache().get(cachekey); - LoginUser loginUser = JSON.parseObject(jsonstr, LoginUser.class); - if (ObjectUtil.isEmpty(loginUser)) { - httpServletResponse.sendError(HttpServletResponse.SC_FORBIDDEN, - "登录用户已失效!"); - return; - } - //存入SecurityContextHolder - UsernamePasswordAuthenticationToken authenticationToken = - new UsernamePasswordAuthenticationToken(loginUser, null, - loginUser.getAuthorities()); - SecurityContextHolder.getContext().setAuthentication(authenticationToken); - webConfig.loginuserCache().put(Constant.TOKEN + userid, token); - //更新了超期时间 - long expireTime =System.currentTimeMillis() + ( 30L * 60L * 1000L); - webConfig.loginuserCache().put("expire_time:" + userid, String.valueOf(expireTime)); - //放行过滤器 - filterChain.doFilter(httpServletRequest, httpServletResponse); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/config/MessageConfig.java b/backend/src/main/java/com/yfd/platform/config/MessageConfig.java deleted file mode 100644 index e079d02..0000000 --- a/backend/src/main/java/com/yfd/platform/config/MessageConfig.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.yfd.platform.config; - -import cn.hutool.cache.Cache; -import cn.hutool.cache.impl.CacheObj; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.yfd.platform.component.ServerSendEventServer; -import com.yfd.platform.constant.Constant; -import com.yfd.platform.system.domain.Message; -import com.yfd.platform.system.domain.SysUser; -import com.yfd.platform.system.service.IMessageService; -import com.yfd.platform.system.service.IUserService; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; - -import jakarta.annotation.Resource; -import java.util.Iterator; - -/** - * @author TangWei - * @Date: 2023/3/24 15:56 - * @Description: - */ -@Component -public class MessageConfig { - - @Resource - private IMessageService messageService; - - @Resource - private IUserService userService; - - @Resource - private WebConfig webConfig; - - public void sendMessage() { - long count = - messageService.count(new LambdaQueryWrapper().eq(Message::getStatus, "1")); - String userId = userService.getUserInfo().getId(); - String token = webConfig.loginuserCache().get(Constant.TOKEN + userId); - ServerSendEventServer.sendMessage(token, count + ""); - } - - public void addMessage(Message message) { - messageService.save(message); - long count = - messageService.count(new LambdaQueryWrapper().eq(Message::getStatus, "1")); - ServerSendEventServer.sendMessage(count + ""); - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/MybitsPlusConfig.java b/backend/src/main/java/com/yfd/platform/config/MybitsPlusConfig.java deleted file mode 100644 index 99d4330..0000000 --- a/backend/src/main/java/com/yfd/platform/config/MybitsPlusConfig.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.yfd.platform.config; - -import com.baomidou.mybatisplus.annotation.DbType; -import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; -import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -/****************************** - * 用途说明: - * 作者姓名: pcj - * 创建时间: 2022/10/24 10:50 - ******************************/ -@Configuration -public class MybitsPlusConfig { - -// @Bean -// public MybatisPlusInterceptor mybatisPlusInterceptor() { -// MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor(); -// mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); -// return mybatisPlusInterceptor; -// } - - /** - * 分页插件配置(Oracle 兼容) - */ - @Bean - public MybatisPlusInterceptor mybatisPlusInterceptor() { - MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); - // 添加分页拦截器,指定数据库类型为 Oracle - interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.ORACLE)); - return interceptor; - } - -} diff --git a/backend/src/main/java/com/yfd/platform/config/ProdApiPrefixFilter.java b/backend/src/main/java/com/yfd/platform/config/ProdApiPrefixFilter.java deleted file mode 100644 index 4c1680a..0000000 --- a/backend/src/main/java/com/yfd/platform/config/ProdApiPrefixFilter.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.yfd.platform.config; - -import jakarta.servlet.Filter; -import jakarta.servlet.FilterChain; -import jakarta.servlet.RequestDispatcher; -import jakarta.servlet.ServletException; -import jakarta.servlet.ServletRequest; -import jakarta.servlet.ServletResponse; -import jakarta.servlet.annotation.WebFilter; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; - -/** - * 将以 /prod-api/ 开头的请求转发到去掉前缀的真实后端接口路径。 - * 例如:/prod-api/user/code -> /user/code - * 这样可以兼容前端生产环境仍使用 /prod-api 作为网关前缀的情况。 - */ -@WebFilter(urlPatterns = "/prod-api/*", filterName = "prodApiPrefixFilter") -public class ProdApiPrefixFilter implements Filter { - - private static final String PREFIX = "/prod-api"; - - @Override - public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { - if (!(req instanceof HttpServletRequest) || !(res instanceof HttpServletResponse)) { - chain.doFilter(req, res); - return; - } - - HttpServletRequest request = (HttpServletRequest) req; - String uri = request.getRequestURI(); - - // 仅拦截 /prod-api/* 的接口请求并进行内部 forward - if (uri.startsWith(PREFIX + "/")) { - String forwardUri = uri.substring(PREFIX.length()); - RequestDispatcher dispatcher = request.getRequestDispatcher(forwardUri); - dispatcher.forward(req, res); - return; - } - - chain.doFilter(req, res); - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/config/QuartzConfig.java b/backend/src/main/java/com/yfd/platform/config/QuartzConfig.java deleted file mode 100644 index 41a36db..0000000 --- a/backend/src/main/java/com/yfd/platform/config/QuartzConfig.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config; - -import org.quartz.Scheduler; -import org.quartz.spi.TriggerFiredBundle; -import org.springframework.beans.factory.config.AutowireCapableBeanFactory; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.quartz.AdaptableJobFactory; -import org.springframework.scheduling.quartz.SchedulerFactoryBean; -import org.springframework.stereotype.Component; - -import java.time.LocalDateTime; - -/** - * 定时任务配置 - * - * @author / - * @date 2019-01-07 - */ -@Configuration -public class QuartzConfig { - - /** - * 解决Job中注入Spring Bean为null的问题 - */ - @Component("quartzJobFactory") - public static class QuartzJobFactory extends AdaptableJobFactory { - - private final AutowireCapableBeanFactory capableBeanFactory; - - public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) { - this.capableBeanFactory = capableBeanFactory; - } - - @Override - protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { - - //调用父类的方法 - Object jobInstance = super.createJobInstance(bundle); - capableBeanFactory.autowireBean(jobInstance); - return jobInstance; - } - } - - /** - * 注入scheduler到spring - * - * @param quartzJobFactory / - * @return Scheduler - * @throws Exception / - */ - @Bean(name = "scheduler") - public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception { - SchedulerFactoryBean factoryBean = new SchedulerFactoryBean(); - factoryBean.setJobFactory(quartzJobFactory); - factoryBean.afterPropertiesSet(); - Scheduler scheduler = factoryBean.getScheduler(); - scheduler.start(); - return scheduler; - } - -} diff --git a/backend/src/main/java/com/yfd/platform/config/ResponseResult.java b/backend/src/main/java/com/yfd/platform/config/ResponseResult.java deleted file mode 100644 index 9638fcf..0000000 --- a/backend/src/main/java/com/yfd/platform/config/ResponseResult.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.yfd.platform.config; - -import java.util.HashMap; - -public class ResponseResult extends HashMap { - private static final long serialVersionUID = 1L; - - public ResponseResult() { - } - - public static ResponseResult unlogin() { - return message("401", "未登录"); - } - - public static ResponseResult error() { - return error("操作失败"); - } - - public static ResponseResult success() { - return success("操作成功"); - } - - public static ResponseResult error(String msg) { - ResponseResult json = new ResponseResult(); - json.put((String)"code", "1");//错误 - json.put((String)"msg", msg); - return json; - } - - public static ResponseResult message(String code, String msg) { - ResponseResult json = new ResponseResult(); - json.put((String)"code", code); - json.put((String)"msg", msg); - return json; - } - - public static ResponseResult success(String msg) { - ResponseResult json = new ResponseResult(); - json.put((String)"code", "0");//正常 - json.put((String)"msg", msg); - return json; - } - - public static ResponseResult successData(Object obj) { - ResponseResult json = new ResponseResult(); - json.put((String)"code", "0");//正常 - json.put((String)"msg", "操作成功"); - json.put("data", obj); - return json; - } - - - public ResponseResult put(String key, Object value) { - super.put(key, value); - return this; - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java b/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java deleted file mode 100644 index 37aa470..0000000 --- a/backend/src/main/java/com/yfd/platform/config/SecurityConfig.java +++ /dev/null @@ -1,90 +0,0 @@ -package com.yfd.platform.config; - -import com.yfd.platform.config.bean.LoginProperties; -import com.yfd.platform.exception.AccessDeniedHandExcetion; -import com.yfd.platform.exception.AuthenticationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -@Configuration -public class SecurityConfig { - - @Bean - public PasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Bean - @ConfigurationProperties(prefix = "login", ignoreUnknownFields = true) - public LoginProperties loginProperties() { - return new LoginProperties(); - } - - @Bean - public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { - return authenticationConfiguration.getAuthenticationManager(); - } - - @Autowired - private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; - - @Autowired - private AuthenticationException authenticationException; - - @Autowired - private AccessDeniedHandExcetion accessDeniedHandExcetion; - - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { - http - .csrf(csrf -> csrf.disable()) - .sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .authorizeHttpRequests(auth -> auth - .requestMatchers("/user/login").anonymous() - .requestMatchers("/user/code").permitAll() - .requestMatchers(HttpMethod.GET, "/").permitAll() - .requestMatchers(HttpMethod.GET, - "/*.html", - "/webSocket/**", - "/assets/**", - "/icon/**").permitAll() - .requestMatchers( - "/swagger-ui.html", - "/swagger-ui/**", - "/v3/api-docs/**", - "/v3/api-docs.yaml", - "/swagger-resources/**", - "/webjars/**", - "/*/api-docs").permitAll() - .requestMatchers( - "/report/**", - "/images/**", - "/pageimage/**", - "/avatar/**", - "/systemurl/**", - "/api/imageserver/upload").permitAll() - .anyRequest().authenticated() - ) - .cors(cors -> {}); - - http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); - - http.exceptionHandling(ex -> ex - .authenticationEntryPoint(authenticationException) - .accessDeniedHandler(accessDeniedHandExcetion) - ); - - return http.build(); - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java b/backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java deleted file mode 100644 index bdfe72a..0000000 --- a/backend/src/main/java/com/yfd/platform/config/SwaggerConfig.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.yfd.platform.config; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springdoc.core.models.GroupedOpenApi; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.info.Contact; - -/** - * Springdoc OpenAPI 配置 - */ -@Configuration -public class SwaggerConfig { - - @Bean - public OpenAPI projectOpenAPI() { - return new OpenAPI() - .info(new Info() - .title("项目API 接口文档") - .version("3.0") - .description("") - .contact(new Contact().name("郑顺利").email("13910913995@163.com")) - ); - } - - @Bean - public GroupedOpenApi groupWebsiteApi() { - return GroupedOpenApi.builder() - .group("1. 平台模块") - .packagesToScan("com.yfd.platform.modules.platformdb.controller") - .build(); - } - - @Bean - public GroupedOpenApi groupQuartzApi() { - return GroupedOpenApi.builder() - .group("2. 定时任务") - .packagesToScan("com.yfd.platform.modules.quartz.controller") - .build(); - } - - @Bean - public GroupedOpenApi groupSystemApi() { - return GroupedOpenApi.builder() - .group("3. 系统管理") - .packagesToScan("com.yfd.platform.system.controller") - .build(); - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/WebConfig.java b/backend/src/main/java/com/yfd/platform/config/WebConfig.java deleted file mode 100644 index 45b051a..0000000 --- a/backend/src/main/java/com/yfd/platform/config/WebConfig.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.yfd.platform.config; - -import cn.hutool.cache.Cache; -import cn.hutool.cache.CacheUtil; -import lombok.SneakyThrows; -import jakarta.annotation.Resource; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.cors.CorsConfiguration; -import org.springframework.web.cors.UrlBasedCorsConfigurationSource; -import org.springframework.web.filter.CorsFilter; -import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - -@Configuration -public class WebConfig implements WebMvcConfigurer { - @Resource - private FileSpaceProperties fileSpaceProperties; - - - - @Bean - public Cache loginuserCache() { - return CacheUtil.newLRUCache(200);//用户登录缓存数 缺省200 - } - - @Bean - public CorsFilter corsFilter() { - UrlBasedCorsConfigurationSource source = - new UrlBasedCorsConfigurationSource(); - CorsConfiguration config = new CorsConfiguration(); - config.setAllowCredentials(true); - config.addAllowedOriginPattern("*"); - config.addAllowedHeader("*"); - config.addAllowedMethod("*"); - config.setMaxAge(3600L); - source.registerCorsConfiguration("/**", config); - return new CorsFilter(source); - } - - @SneakyThrows - @Override - public void addResourceHandlers(ResourceHandlerRegistry registry) { - registry.addResourceHandler("/icon/**") - .addResourceLocations("classpath:/static/icon/") - .setCachePeriod(0); - - registry.addResourceHandler("/assets/**") - .addResourceLocations("classpath:/static/assets/") - .setCachePeriod(0); - - registry.addResourceHandler("swagger-ui.html").addResourceLocations( - "classpath:/META-INF/resources/"); - - String systemUrl = "file:" + fileSpaceProperties.getSystem().replace("\\", "/")+"user\\"; - registry.addResourceHandler("/avatar/**").addResourceLocations(systemUrl).setCachePeriod(0); - - - } - -} diff --git a/backend/src/main/java/com/yfd/platform/config/WebSocketConfig.java b/backend/src/main/java/com/yfd/platform/config/WebSocketConfig.java deleted file mode 100644 index 349ead0..0000000 --- a/backend/src/main/java/com/yfd/platform/config/WebSocketConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.yfd.platform.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.web.socket.server.standard.ServerEndpointExporter; - -@Configuration -public class WebSocketConfig { - - @Bean - public ServerEndpointExporter serverEndpointExporter() { - - return new ServerEndpointExporter(); - } -} - diff --git a/backend/src/main/java/com/yfd/platform/config/bean/LoginCode.java b/backend/src/main/java/com/yfd/platform/config/bean/LoginCode.java deleted file mode 100644 index 2a7586b..0000000 --- a/backend/src/main/java/com/yfd/platform/config/bean/LoginCode.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2019-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config.bean; - -import lombok.Data; - -/** - * 登录验证码配置信息 - * - * @author: liaojinlong - * @date: 2020/6/10 18:53 - */ -@Data -public class LoginCode { - - /** - * 验证码配置 - */ - private LoginCodeEnum codeType; - /** - * 验证码有效期 分钟 - */ - private Long expiration = 2L; - /** - * 验证码内容长度 - */ - private int length = 2; - /** - * 验证码宽度 - */ - private int width = 111; - /** - * 验证码高度 - */ - private int height = 36; - /** - * 验证码字体 - */ - private String fontName; - /** - * 字体大小 - */ - private int fontSize = 25; - - public LoginCodeEnum getCodeType() { - return codeType; - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/bean/LoginCodeEnum.java b/backend/src/main/java/com/yfd/platform/config/bean/LoginCodeEnum.java deleted file mode 100644 index d9ade21..0000000 --- a/backend/src/main/java/com/yfd/platform/config/bean/LoginCodeEnum.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config.bean; - -/** - * 验证码配置枚举 - * - * @author: liaojinlong - * @date: 2020/6/10 17:40 - */ - -public enum LoginCodeEnum { - /** - * 算数 - */ - arithmetic, - /** - * 中文 - */ - chinese, - /** - * 中文闪图 - */ - chinese_gif, - /** - * 闪图 - */ - gif, - spec -} diff --git a/backend/src/main/java/com/yfd/platform/config/bean/LoginProperties.java b/backend/src/main/java/com/yfd/platform/config/bean/LoginProperties.java deleted file mode 100644 index b16644d..0000000 --- a/backend/src/main/java/com/yfd/platform/config/bean/LoginProperties.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright 2019-2020 the original author or authors. - * - * Licensed under the Apache License, Version loginCode.length.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-loginCode.length.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config.bean; - -import cn.hutool.core.util.StrUtil; -import com.wf.captcha.*; -import com.wf.captcha.base.Captcha; -import com.yfd.platform.exception.BadConfigurationException; -import lombok.Data; -import java.awt.*; -import java.util.Objects; - -/** - * 配置文件读取 - * - * @author liaojinlong - * @date loginCode.length0loginCode.length0/6/10 17:loginCode.length6 - */ -@Data -public class LoginProperties { - - /** - * 账号单用户 登录 - */ - private boolean singleLogin = false; - - private LoginCode loginCode; - /** - * 用户登录信息缓存 - */ - private boolean cacheEnable; - - public boolean isSingleLogin() { - return singleLogin; - } - - public boolean isCacheEnable() { - return cacheEnable; - } - - /** - * 获取验证码生产类 - * - * @return / - */ - public Captcha getCaptcha() { - if (Objects.isNull(loginCode)) { - loginCode = new LoginCode(); - if (Objects.isNull(loginCode.getCodeType())) { - loginCode.setCodeType(LoginCodeEnum.arithmetic); - } - } - return switchCaptcha(loginCode); - } - - /** - * 依据配置信息生产验证码 - * - * @param loginCode 验证码配置信息 - * @return / - */ - private Captcha switchCaptcha(LoginCode loginCode) { - Captcha captcha; - synchronized (this) { - switch (loginCode.getCodeType()) { - case arithmetic: - // 算术类型 https://gitee.com/whvse/EasyCaptcha - captcha = new ArithmeticCaptcha(loginCode.getWidth(), loginCode.getHeight()); - // 几位数运算,默认是两位 - captcha.setLen(loginCode.getLength()); - break; - case chinese: - captcha = new ChineseCaptcha(loginCode.getWidth(), loginCode.getHeight()); - captcha.setLen(loginCode.getLength()); - break; - case chinese_gif: - captcha = new ChineseGifCaptcha(loginCode.getWidth(), loginCode.getHeight()); - captcha.setLen(loginCode.getLength()); - break; - case gif: - captcha = new GifCaptcha(loginCode.getWidth(), loginCode.getHeight()); - captcha.setLen(loginCode.getLength()); - break; - case spec: - captcha = new SpecCaptcha(loginCode.getWidth(), loginCode.getHeight()); - captcha.setLen(loginCode.getLength()); - break; - default: - throw new BadConfigurationException("验证码配置信息错误!正确配置查看 LoginCodeEnum "); - } - } - if(StrUtil.isNotBlank(loginCode.getFontName())){ - captcha.setFont(new Font(loginCode.getFontName(), Font.PLAIN, loginCode.getFontSize())); - } - return captcha; - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/thread/AsyncTaskExecutePool.java b/backend/src/main/java/com/yfd/platform/config/thread/AsyncTaskExecutePool.java deleted file mode 100644 index ff10654..0000000 --- a/backend/src/main/java/com/yfd/platform/config/thread/AsyncTaskExecutePool.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config.thread; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.annotation.AsyncConfigurer; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; - -import java.util.concurrent.Executor; -import java.util.concurrent.ThreadPoolExecutor; - -/** - * 异步任务线程池装配类 - * @author https://juejin.im/entry/5abb8f6951882555677e9da2 - * @date 2019年10月31日15:06:18 - */ -@Slf4j -@Configuration -public class AsyncTaskExecutePool implements AsyncConfigurer { - - /** 注入配置类 */ - private final AsyncTaskProperties config; - - public AsyncTaskExecutePool(AsyncTaskProperties config) { - this.config = config; - } - - @Override - public Executor getAsyncExecutor() { - ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); - //核心线程池大小 - executor.setCorePoolSize(config.getCorePoolSize()); - //最大线程数 - executor.setMaxPoolSize(config.getMaxPoolSize()); - //队列容量 - executor.setQueueCapacity(config.getQueueCapacity()); - //活跃时间 - executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); - //线程名字前缀 - executor.setThreadNamePrefix("el-async-"); - // setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务 - // CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行 - executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); - executor.initialize(); - return executor; - } - - @Override - public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { - return (throwable, method, objects) -> { - log.error("===="+throwable.getMessage()+"====", throwable); - log.error("exception method:"+method.getName()); - }; - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/thread/AsyncTaskProperties.java b/backend/src/main/java/com/yfd/platform/config/thread/AsyncTaskProperties.java deleted file mode 100644 index a5bc7d2..0000000 --- a/backend/src/main/java/com/yfd/platform/config/thread/AsyncTaskProperties.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config.thread; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; - -/** - * 线程池配置属性类 - * @author https://juejin.im/entry/5abb8f6951882555677e9da2 - * @date 2019年10月31日14:58:18 - */ -@Data -@Component -@ConfigurationProperties(prefix = "task.pool") -public class AsyncTaskProperties { - - private int corePoolSize; - - private int maxPoolSize; - - private int keepAliveSeconds; - - private int queueCapacity; -} diff --git a/backend/src/main/java/com/yfd/platform/config/thread/TheadFactoryName.java b/backend/src/main/java/com/yfd/platform/config/thread/TheadFactoryName.java deleted file mode 100644 index 118faba..0000000 --- a/backend/src/main/java/com/yfd/platform/config/thread/TheadFactoryName.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config.thread; - -import org.springframework.stereotype.Component; - -import java.util.concurrent.ThreadFactory; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * 自定义线程名称 - * @author - * @date 2019年10月31日17:49:55 - */ -@Component -public class TheadFactoryName implements ThreadFactory { - - private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); - private final ThreadGroup group; - private final AtomicInteger threadNumber = new AtomicInteger(1); - private final String namePrefix; - - public TheadFactoryName() { - this("el-pool"); - } - - private TheadFactoryName(String name){ - // 使用当前线程的线程组,避免依赖已弃用的 SecurityManager - group = Thread.currentThread().getThreadGroup(); - //此时namePrefix就是 name + 第几个用这个工厂创建线程池的 - this.namePrefix = name + - POOL_NUMBER.getAndIncrement(); - } - - @Override - public Thread newThread(Runnable r) { - //此时线程的名字 就是 namePrefix + -thread- + 这个线程池中第几个执行的线程 - Thread t = new Thread(group, r, - namePrefix + "-thread-"+threadNumber.getAndIncrement(), - 0); - if (t.isDaemon()) { - t.setDaemon(false); - } - if (t.getPriority() != Thread.NORM_PRIORITY) { - t.setPriority(Thread.NORM_PRIORITY); - } - return t; - } -} diff --git a/backend/src/main/java/com/yfd/platform/config/thread/ThreadPoolExecutorUtil.java b/backend/src/main/java/com/yfd/platform/config/thread/ThreadPoolExecutorUtil.java deleted file mode 100644 index cb84cc4..0000000 --- a/backend/src/main/java/com/yfd/platform/config/thread/ThreadPoolExecutorUtil.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.config.thread; - - - -import com.yfd.platform.utils.SpringContextHolder; - -import java.util.concurrent.ArrayBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -/** - * 用于获取自定义线程池 - * @author - * @date 2019年10月31日18:16:47 - */ -public class ThreadPoolExecutorUtil { - - public static ThreadPoolExecutor getPoll(){ - AsyncTaskProperties properties = SpringContextHolder.getBean(AsyncTaskProperties.class); - return new ThreadPoolExecutor( - properties.getCorePoolSize(), - properties.getMaxPoolSize(), - properties.getKeepAliveSeconds(), - TimeUnit.SECONDS, - new ArrayBlockingQueue<>(properties.getQueueCapacity()), - new TheadFactoryName() - ); - } -} diff --git a/backend/src/main/java/com/yfd/platform/constant/Constant.java b/backend/src/main/java/com/yfd/platform/constant/Constant.java deleted file mode 100644 index c460999..0000000 --- a/backend/src/main/java/com/yfd/platform/constant/Constant.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.yfd.platform.constant; - -/** - * @author TangWei - * @Date: 2023/3/3 17:40 - * @Description: 常量类 - */ -public class Constant { - - public static final String LOGIN = "login:"; - public static final String TOKEN = "token:"; - public static final String USER_ID = "userid"; - public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; - - public static final String CODE_KEY = "code-key-"; - public static final long CODE_EXPIRATION_TIME = 1000 * 60; - /** - * 用于IP定位转换 - */ - public static final String REGION = "内网IP|内网IP"; - /** - * win 系统 - */ - public static final String WIN = "win"; - - /** - * mac 系统 - */ - public static final String MAC = "mac"; - - /** - * 常用接口 - */ - public static class Url { - - // IP归属地查询 - // public static final String IP_URL = "http://whois.pconline.com - // .cn/ipJson.jsp?ip=%s&json=true"; - public static final String IP_URL = "http://whois.pconline.com" + - ".cn/ipJson.jsp?ip=%s&json=true"; - } -} diff --git a/backend/src/main/java/com/yfd/platform/datasource/DataSource.java b/backend/src/main/java/com/yfd/platform/datasource/DataSource.java deleted file mode 100644 index 7c6d795..0000000 --- a/backend/src/main/java/com/yfd/platform/datasource/DataSource.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.yfd.platform.datasource; - -import java.lang.annotation.*; - -/****************************** - * 用途说明: - * 作者姓名: wxy - * 创建时间: 2022/9/23 17:48 - ******************************/ -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -@Documented -public @interface DataSource { - - String name() default ""; - -} diff --git a/backend/src/main/java/com/yfd/platform/datasource/DataSourceAspect.java b/backend/src/main/java/com/yfd/platform/datasource/DataSourceAspect.java deleted file mode 100644 index f20c0f8..0000000 --- a/backend/src/main/java/com/yfd/platform/datasource/DataSourceAspect.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.yfd.platform.datasource; - -import cn.hutool.core.util.StrUtil; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.annotation.Around; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Pointcut; -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.stereotype.Component; - -import java.lang.reflect.Method; - -/****************************** - * 用途说明: - * 作者姓名: wxy - * 创建时间: 2022/9/23 17:50 - ******************************/ -@Aspect -@Component -public class DataSourceAspect { - - @Pointcut("@annotation(com.yfd.platform.datasource.DataSource)") - public void dataSourcePointCut() { - - } - - private String DataBaseName; - - @Around("dataSourcePointCut()") - public Object around(ProceedingJoinPoint point) throws Throwable { - MethodSignature signature = (MethodSignature) point.getSignature(); - Method method = signature.getMethod(); - if (StrUtil.isNotBlank(DataBaseName)){ - DynamicDataSource.setDataSource(DataBaseName); - }else { - DynamicDataSource.setDataSource("master"); - } - - try { - return point.proceed(); - } finally { - DynamicDataSource.clearDataSource(); - } - } - - public String getDataBase(Integer type){ - if (type == 1){ - DataBaseName="master"; - }else { - DataBaseName="slave"; - } - return DataBaseName; - } - -} diff --git a/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSource.java b/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSource.java deleted file mode 100644 index 8b52521..0000000 --- a/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSource.java +++ /dev/null @@ -1,40 +0,0 @@ -package com.yfd.platform.datasource; - -import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; - -import javax.sql.DataSource; -import java.util.Map; - -/****************************** - * 用途说明: - * 作者姓名: wxy - * 创建时间: 2022/9/23 17:47 - ******************************/ -public class DynamicDataSource extends AbstractRoutingDataSource { - private static final ThreadLocal contextHolder = new ThreadLocal<>(); - - public DynamicDataSource(DataSource defaultTargetDataSource, Map targetDataSources) { - super.setDefaultTargetDataSource(defaultTargetDataSource); - super.setTargetDataSources(targetDataSources); - super.afterPropertiesSet(); - } - - @Override - protected Object determineCurrentLookupKey() { - return getDataSource(); - } - - public static void setDataSource(String dataSource) { - contextHolder.set(dataSource); - } - - public static String getDataSource() { - return contextHolder.get(); - } - - public static void clearDataSource() { - contextHolder.remove(); - } - - -} diff --git a/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSourceConfig.java b/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSourceConfig.java deleted file mode 100644 index f559443..0000000 --- a/backend/src/main/java/com/yfd/platform/datasource/DynamicDataSourceConfig.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.yfd.platform.datasource; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.stereotype.Component; -import com.alibaba.druid.pool.DruidDataSource; - -import javax.sql.DataSource; -import java.util.HashMap; -import java.util.Map; - -/****************************** - * 用途说明: - * 作者姓名: wxy - * 创建时间: 2022/9/23 17:45 - ******************************/ -@Configuration -@Component -public class DynamicDataSourceConfig { - - @Bean - @ConfigurationProperties("spring.datasource.druid.master") - public DataSource wglMasterDataSource(){ - DruidDataSource dataSource = new DruidDataSource(); - dataSource.setBreakAfterAcquireFailure(true); - dataSource.setConnectionErrorRetryAttempts(0); - return dataSource; - } - - @Bean - @ConfigurationProperties("spring.datasource.druid.slave") - public DataSource wglSlaveDataSource(){ - DruidDataSource dataSource = new DruidDataSource(); - dataSource.setBreakAfterAcquireFailure(true); - dataSource.setConnectionErrorRetryAttempts(0); - return dataSource; - } - - @Bean - @Primary - public DynamicDataSource dataSource(DataSource wglMasterDataSource, DataSource wglSlaveDataSource) { - Map targetDataSources = new HashMap<>(); - targetDataSources.put("master",wglMasterDataSource); - targetDataSources.put("slave",wglSlaveDataSource); - return new DynamicDataSource(wglMasterDataSource, targetDataSources); - } - - -} diff --git a/backend/src/main/java/com/yfd/platform/exception/AccessDeniedHandExcetion.java b/backend/src/main/java/com/yfd/platform/exception/AccessDeniedHandExcetion.java deleted file mode 100644 index 0bb0ed3..0000000 --- a/backend/src/main/java/com/yfd/platform/exception/AccessDeniedHandExcetion.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.yfd.platform.exception; - -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.web.access.AccessDeniedHandler; -import org.springframework.stereotype.Component; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -@Component -public class AccessDeniedHandExcetion implements AccessDeniedHandler { - @Override - public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { - JSONObject jobj=new JSONObject(); - jobj.putOnce("status","403"); - jobj.putOnce("msg","用户权限不足,不能访问"); - response.setStatus(200); - response.setContentType("application/json"); - response.setCharacterEncoding("utf-8"); - response.getWriter().println(JSONUtil.toJsonStr(jobj)); - } -} diff --git a/backend/src/main/java/com/yfd/platform/exception/AuthenticationException.java b/backend/src/main/java/com/yfd/platform/exception/AuthenticationException.java deleted file mode 100644 index 15e8e97..0000000 --- a/backend/src/main/java/com/yfd/platform/exception/AuthenticationException.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.yfd.platform.exception; - -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import com.yfd.platform.config.ResponseResult; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -@Component -public class AuthenticationException implements AuthenticationEntryPoint { - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, org.springframework.security.core.AuthenticationException authException) throws IOException, ServletException { - JSONObject jobj=new JSONObject(); - if(authException.getMessage().equals("用户账号不存在!")){ - jobj.putOnce("code","401"); - jobj.putOnce("msg","用户账号不存在/密码错误,登录失败!"); - }else{ - jobj.putOnce("code","401"); - jobj.putOnce("msg","用户Token失效,请重新登录!"); - } - response.setStatus(200); - response.setContentType("application/json"); - response.setCharacterEncoding("utf-8"); - response.getWriter().println(JSONUtil.toJsonStr(jobj)); - } -} diff --git a/backend/src/main/java/com/yfd/platform/exception/BadConfigurationException.java b/backend/src/main/java/com/yfd/platform/exception/BadConfigurationException.java deleted file mode 100644 index 92ffac0..0000000 --- a/backend/src/main/java/com/yfd/platform/exception/BadConfigurationException.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright 2019-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.exception; - -/** - * 统一关于错误配置信息 异常 - * - * @author: liaojinlong - * @date: 2020/6/10 18:06 - */ -public class BadConfigurationException extends RuntimeException { - /** - * Constructs a new runtime exception with {@code null} as its - * detail message. The cause is not initialized, and may subsequently be - * initialized by a call to {@link #initCause}. - */ - public BadConfigurationException() { - super(); - } - - /** - * Constructs a new runtime exception with the specified detail message. - * The cause is not initialized, and may subsequently be initialized by a - * call to {@link #initCause}. - * - * @param message the detail message. The detail message is saved for - * later retrieval by the {@link #getMessage()} method. - */ - public BadConfigurationException(String message) { - super(message); - } - - /** - * Constructs a new runtime exception with the specified detail message and - * cause.

Note that the detail message associated with - * {@code cause} is not automatically incorporated in - * this runtime exception's detail message. - * - * @param message the detail message (which is saved for later retrieval - * by the {@link #getMessage()} method). - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method). (A {@code null} value is - * permitted, and indicates that the cause is nonexistent or - * unknown.) - * @since 1.4 - */ - public BadConfigurationException(String message, Throwable cause) { - super(message, cause); - } - - /** - * Constructs a new runtime exception with the specified cause and a - * detail message of {@code (cause==null ? null : cause.toString())} - * (which typically contains the class and detail message of - * {@code cause}). This constructor is useful for runtime exceptions - * that are little more than wrappers for other throwables. - * - * @param cause the cause (which is saved for later retrieval by the - * {@link #getCause()} method). (A {@code null} value is - * permitted, and indicates that the cause is nonexistent or - * unknown.) - * @since 1.4 - */ - public BadConfigurationException(Throwable cause) { - super(cause); - } - - /** - * Constructs a new runtime exception with the specified detail - * message, cause, suppression enabled or disabled, and writable - * stack trace enabled or disabled. - * - * @param message the detail message. - * @param cause the cause. (A {@code null} value is permitted, - * and indicates that the cause is nonexistent or unknown.) - * @param enableSuppression whether or not suppression is enabled - * or disabled - * @param writableStackTrace whether or not the stack trace should - * be writable - * @since 1.7 - */ - protected BadConfigurationException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { - super(message, cause, enableSuppression, writableStackTrace); - } -} diff --git a/backend/src/main/java/com/yfd/platform/exception/BadRequestException.java b/backend/src/main/java/com/yfd/platform/exception/BadRequestException.java deleted file mode 100644 index f2202ec..0000000 --- a/backend/src/main/java/com/yfd/platform/exception/BadRequestException.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.exception; - -import lombok.Getter; -import org.springframework.http.HttpStatus; - -import static org.springframework.http.HttpStatus.BAD_REQUEST; - -/** - * @author - * @date 2018-11-23 - * 统一异常处理 - */ -@Getter -public class BadRequestException extends RuntimeException{ - - private Integer status = BAD_REQUEST.value(); - - public BadRequestException(String msg){ - super(msg); - } - - public BadRequestException(HttpStatus status, String msg){ - super(msg); - this.status = status.value(); - } -} diff --git a/backend/src/main/java/com/yfd/platform/exception/ChildrenExistException.java b/backend/src/main/java/com/yfd/platform/exception/ChildrenExistException.java deleted file mode 100644 index 18eca34..0000000 --- a/backend/src/main/java/com/yfd/platform/exception/ChildrenExistException.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.yfd.platform.exception; - -import org.springframework.util.StringUtils; - -/** - * @Author pcj - * @Date 2021/1/26 9:07 - * @Version 1.0 - */ -public class ChildrenExistException extends RuntimeException{ - - public ChildrenExistException(Class clazz, String field, String val) { - super(ChildrenExistException.generateMessage(clazz.getSimpleName(), field, val)); - } - - private static String generateMessage(String entity, String field, String val) { - return StringUtils.capitalize(entity) - + " with " + field + " "+ val + " Children Exist"; - } -} diff --git a/backend/src/main/java/com/yfd/platform/exception/EntityExistException.java b/backend/src/main/java/com/yfd/platform/exception/EntityExistException.java deleted file mode 100644 index 028aeed..0000000 --- a/backend/src/main/java/com/yfd/platform/exception/EntityExistException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.exception; - -import org.springframework.util.StringUtils; - -/** - * @author - * @date 2018-11-23 - */ -public class EntityExistException extends RuntimeException { - - public EntityExistException(Class clazz, String field, String val) { - super(EntityExistException.generateMessage(clazz.getSimpleName(), field, val)); - } - - private static String generateMessage(String entity, String field, String val) { - return StringUtils.capitalize(entity) - + " with " + field + " "+ val + " existed"; - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/exception/EntityNotFoundException.java b/backend/src/main/java/com/yfd/platform/exception/EntityNotFoundException.java deleted file mode 100644 index 8f5e1c5..0000000 --- a/backend/src/main/java/com/yfd/platform/exception/EntityNotFoundException.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.exception; - -import org.springframework.util.StringUtils; - -/** - * @author - * @date 2018-11-23 - */ -public class EntityNotFoundException extends RuntimeException { - - public EntityNotFoundException(Class clazz, String field, String val) { - super(EntityNotFoundException.generateMessage(clazz.getSimpleName(), field, val)); - } - - private static String generateMessage(String entity, String field, String val) { - return StringUtils.capitalize(entity) - + " with " + field + " "+ val + " does not exist"; - } -} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/system/controller/DataSourceController.java b/backend/src/main/java/com/yfd/platform/system/controller/DataSourceController.java deleted file mode 100644 index b34b37c..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/DataSourceController.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.yfd.platform.system.controller; - -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.datasource.DataSource; -import com.yfd.platform.datasource.DataSourceAspect; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; - -import jakarta.annotation.Resource; - -/** - * @author zhengsl - * @since 2022-09-20 - */ -@RestController -@RequestMapping("/system") -@Tag(name = "切换数据库") -public class DataSourceController { - - @Resource - DataSourceAspect dataSourceAspect; - - /** - * 切换数据库 - * - * @DataSource(name="master") 可以通过注解方式切换数据库 - */ - @GetMapping("/changeDataSource") - @Operation(summary = "切换数据库") - public ResponseResult changeDataSource(Integer type) { - if (type == null) { - return ResponseResult.error("参数为空"); - } - String dataBase = dataSourceAspect.getDataBase(type); - String mess = "已切换为" + dataBase + "数据库"; - return ResponseResult.success(mess); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/LoginController.java b/backend/src/main/java/com/yfd/platform/system/controller/LoginController.java deleted file mode 100644 index ac08378..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/LoginController.java +++ /dev/null @@ -1,238 +0,0 @@ -package com.yfd.platform.system.controller; - -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONUtil; -import cn.hutool.jwt.JWTUtil; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; -import com.wf.captcha.base.Captcha; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.config.WebConfig; -import com.yfd.platform.config.bean.LoginCodeEnum; -import com.yfd.platform.config.bean.LoginProperties; -import com.yfd.platform.constant.Constant; -import com.yfd.platform.system.domain.LoginUser; -import com.yfd.platform.system.domain.SysLog; -import com.yfd.platform.system.domain.SysUser; -import com.yfd.platform.system.service.ISysLogService; -import com.yfd.platform.system.service.IUserService; -import com.yfd.platform.utils.RequestHolder; -import com.yfd.platform.utils.RsaUtils; -import com.yfd.platform.utils.StringUtils; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletRequest; -import java.sql.Timestamp; -import java.util.HashMap; -import java.util.Map; - -/** - * @author TangWei - */ -@RestController -@RequestMapping("/user") -@Tag(name = "用户登录") -public class LoginController { - - @Autowired - private AuthenticationManager authenticationManager; - - @Autowired - private WebConfig webConfig; - - @Resource - private IUserService userService; - - @Value("${rsa.private_key}") - private String privateKey; - - @Resource - private ISysLogService sysLogService; - - @Resource - private LoginProperties loginProperties; - - @PostMapping("/login") - @Operation(summary = "登录用户") - @ResponseBody - public ResponseResult login(SysUser user) throws Exception { - // 密码解密 - String password = RsaUtils.decryptByPrivateKey(privateKey, - user.getPassword()); - - // 是否需要验证码不需要改成false - boolean hascode = true; - if (hascode) { - // 查询验证码 - String code = webConfig.loginuserCache().get(user.getUuid()); - // 清除验证码 - webConfig.loginuserCache().remove(user.getUuid()); - if (StrUtil.isBlank(code)) { - return ResponseResult.error("验证码不存在或已过期"); - } - if (StrUtil.isBlank(user.getCode()) || !user.getCode().equalsIgnoreCase(code)) { - return ResponseResult.error("验证码错误"); - } - } - //如果认证通过了,使用userId生成token token存入ResponseResult返回 - UsernamePasswordAuthenticationToken authenticationToken = - new UsernamePasswordAuthenticationToken(user.getUsername(), - password); - Authentication authenticate = - authenticationManager.authenticate(authenticationToken); - if (ObjectUtil.isNull(authenticate)) { - return ResponseResult.unlogin(); - } - LoginUser loginUser = (LoginUser) authenticate.getPrincipal(); - Integer status = loginUser.getUser().getStatus(); - if ("0".equals(status.toString())) { - return ResponseResult.error("账号已停用"); - } - HttpServletRequest request = RequestHolder.getHttpServletRequest(); - SysLog sysLog = new SysLog(); - sysLog.setUsercode(user.getUsername()); - sysLog.setUsername(loginUser.getUser().getNickname()); - sysLog.setRequestip(StringUtils.getIp(request)); - sysLog.setBrowser(StringUtils.getBrowser(request)); - sysLog.setOpttype("登录(login)"); - sysLog.setModule("用户登录"); - String className = this.getClass().getName(); - String method = - Thread.currentThread().getStackTrace()[1].getMethodName(); - sysLog.setMethod(className + "." + method + "()"); - //sysLog.setParams(user.toString()); - sysLog.setDescription(loginUser.getUser().getNickname() + "登录系统!"); - sysLog.setLogtime(new Timestamp(System.currentTimeMillis())); - sysLogService.save(sysLog); - String userId = loginUser.getUser().getId(); - Map map = new HashMap(10) { - private static final long serialVersionUID = 1L; - - { - put("userid", userId); - put("username", loginUser.getUsername()); - long expireTime = - System.currentTimeMillis() + (long) (30L * 24L * 60L * 60L * 1000L); - put("expire_time", expireTime);//个月过期 - } - }; - - String token = JWTUtil.createToken(map, "12345678".getBytes()); - map.put("token", token); - //把完整的用户信息存入到HuTool缓存中,userId作为key - String jsonStr = JSONUtil.toJsonStr(loginUser); - webConfig.loginuserCache().put("login:" + userId, jsonStr); - webConfig.loginuserCache().put("expire_time:" + userId, map.get("expire_time").toString()); - return ResponseResult.successData(map); - } - - @Operation(summary = "获取验证码") - @GetMapping(value = "/code") - public ResponseResult getCode() { - // 获取运算的结果 - Captcha captcha = loginProperties.getCaptcha(); - String uuid = Constant.CODE_KEY + IdUtil.simpleUUID(); - //当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型 - String captchaValue = captcha.text(); - if (captcha.getCharType() - 1 == LoginCodeEnum.arithmetic.ordinal() && captchaValue.contains(".")) { - captchaValue = captchaValue.split("\\.")[0]; - } - // 保存 - //redisUtils.set(uuid, captchaValue, loginProperties.getLoginCode() - // .getExpiration(), TimeUnit.MINUTES); - // 将验证码放入缓存,设置失效时间为60秒 - webConfig.loginuserCache().put(uuid, captchaValue, - Constant.CODE_EXPIRATION_TIME); - // 验证码信息 - Map imgResult = new HashMap(2) {{ - put("img", captcha.toBase64()); - put("uuid", uuid); - }}; - return ResponseResult.successData(imgResult); - } - - @PostMapping("/logout") - @Operation(summary = "退出登录") - @ResponseBody - public ResponseResult logout() { - //获取SecurityContextHolder中的用户id - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - String userId = loginuser.getUser().getId(); - //删除redis中的登陆用户信息 - webConfig.loginuserCache().remove("login:" + userId); - //记录退出日志 - HttpServletRequest request = RequestHolder.getHttpServletRequest(); - SysLog sysLog = new SysLog(); - sysLog.setUsercode(loginuser.getUsername()); - sysLog.setUsername(loginuser.getUser().getNickname()); - sysLog.setRequestip(StringUtils.getIp(request)); - sysLog.setBrowser(StringUtils.getBrowser(request)); - sysLog.setOpttype("其他(other)"); - sysLog.setModule("注销退出"); - sysLog.setDescription("注销退出系统!"); - sysLog.setLogtime(new Timestamp(System.currentTimeMillis())); - sysLogService.save(sysLog); - return ResponseResult.success(); - } - - @Log(module = "用户登录", value = "更改用户密码") - @GetMapping("/updatePassword") - @Operation(summary = "更改用户密码") - @ResponseBody - public ResponseResult updatePassword(@RequestBody SysUser user) throws Exception { - // 密码解密 - String password = RsaUtils.decryptByPrivateKey(privateKey, - user.getPassword()); - BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); - String cryptPassword = passwordEncoder.encode(password); - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - updateWrapper.set("password", cryptPassword); - updateWrapper.eq("id", user.getId()); - userService.update(updateWrapper); - return ResponseResult.success(); - } - - @GetMapping("/me") - @Operation(summary = "查询当前用户信息") - @ResponseBody - public ResponseResult getUserInfo() { - ResponseResult responseResult = userService.getLoginUserInfo(); - return ResponseResult.successData(responseResult); - } - - @Log(module = "用户登录", value = "修改个人信息") - @PostMapping("/updatePersonalInfo") - @Operation(summary = "修改个人信息") - @ResponseBody - public ResponseResult updateUser(@org.springframework.web.bind.annotation.RequestBody SysUser user) { - if (StrUtil.isEmpty(user.getId())) { - return ResponseResult.error("没有用户ID"); - } - //填写 当前用户名称 - user.setLastmodifier(userService.getUsername()); - //填写 当前日期 - user.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - boolean ok = userService.updateById(user); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/MessageController.java b/backend/src/main/java/com/yfd/platform/system/controller/MessageController.java deleted file mode 100644 index 58f61ba..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/MessageController.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.yfd.platform.system.controller; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.MessageConfig; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.config.WebConfig; -import com.yfd.platform.system.domain.Message; -import com.yfd.platform.system.service.IMessageService; -import com.yfd.platform.system.service.IUserService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import java.sql.Timestamp; -import java.util.*; - -/** - *

- * 消息通知 前端控制器 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -@RestController -@RequestMapping("/system/message") -@Tag(name = "消息通知") -public class MessageController { - - @Resource - private IMessageService messageService; - - @Resource - private MessageConfig messageConfig; - - @Operation(summary = "查询消息") - @GetMapping("/getMessageList") - public ResponseResult getMessageList(Page page, - String status, String title, - String type, String startDate, - String endDate) { - if (StrUtil.isBlank(status)) { - return ResponseResult.error("参数为空"); - } - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - if ("0".equals(status)) { - queryWrapper.eq(Message::getStatus, "1"); - } else { - List statusList = new ArrayList<>(); - statusList.add("2"); - statusList.add("9"); - queryWrapper.in(Message::getStatus, statusList); - - if (StrUtil.isNotBlank(title)) { - queryWrapper.like(Message::getTitle, title); - } - - if (StrUtil.isNotBlank(type)) { - queryWrapper.eq(Message::getType, type); - } - - DateTime parseStartDate = DateUtil.parse(startDate); - DateTime parseEndDate = DateUtil.parse(endDate); - DateTime dateTime = DateUtil.offsetDay(parseEndDate, 1); - - if (parseStartDate != null && parseEndDate != null) { - queryWrapper.ge(Message::getCreatetime, parseStartDate).lt(Message::getCreatetime, dateTime); - } - } - queryWrapper.orderByDesc(Message::getCreatetime); - Page pageList = messageService.page(page, queryWrapper); - return ResponseResult.successData(pageList); - } - - @Operation(summary = "根据ID查询消息") - @GetMapping("/getMessageById") - public ResponseResult getMessageById(String id) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - Message message = messageService.getById(id); - Map map = new HashMap<>(); - map.put("title", message.getTitle()); - map.put("content", message.getContent()); - map.put("createtime", message.getCreatetime()); - return ResponseResult.successData(map); - } - - @Log(module = "消息通知",value = "根据ID删除消息") - @Operation(summary = "根据ID删除消息") - @PostMapping("/deleteMessageById") - public ResponseResult deleteMessageById(@RequestParam String id) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - String[] split = id.split(","); - List idList = Arrays.asList(split); - boolean ok = messageService.removeByIds(idList); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error("删除失败"); - } - - } - - @Log(module = "消息通知", value = "将消息标记为已阅状态") - @Operation(summary = "标记已阅") - @PostMapping("/setMessageStatus") - public ResponseResult setMessageStatus(@RequestParam String id) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - String[] split = id.split(","); - long time = System.currentTimeMillis(); - for (String mid : split) { - Message message = messageService.getById(mid); - if ("9".equals(message.getStatus())) { - continue; - } - message.setStatus("2"); - message.setReadtime(new Timestamp(time)); - messageService.updateById(message); - } - messageConfig.sendMessage(); - return ResponseResult.success(); - } - - @Operation(summary = "全部已阅") - @PostMapping("/setAllMessageStatus") - public ResponseResult setAllMessageStatus() { - long time = System.currentTimeMillis(); - List list = - messageService.list(new LambdaQueryWrapper().eq(Message::getStatus, "1")); - for (Message message : list) { - message.setStatus("2"); - message.setReadtime(new Timestamp(time)); - messageService.updateById(message); - } - messageConfig.sendMessage(); - return ResponseResult.success(); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/QuartzJobController.java b/backend/src/main/java/com/yfd/platform/system/controller/QuartzJobController.java deleted file mode 100644 index 9da6c89..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/QuartzJobController.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.yfd.platform.system.controller; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.QuartzJob; -import com.yfd.platform.system.service.IQuartzJobService; -import com.yfd.platform.system.service.impl.UserServiceImpl; -import com.yfd.platform.utils.QuartzManage; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.quartz.CronExpression; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import java.sql.Timestamp; -import java.time.LocalDateTime; - -/** - *

- * 定时任务 前端控制器 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -@RestController -@RequestMapping("/system/quartzjob") -@Tag(name = "定时任务") -@Transactional -public class QuartzJobController { - - @Resource - private IQuartzJobService quartzJobService; - - @Resource - private UserServiceImpl currentUser; - - @Resource - private QuartzManage quartzManage; - - @Operation(summary = "查询定时任务") - @GetMapping("/getQuartzJobList") - public ResponseResult getQuartzJobList(Page page, - String jobName) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - if (StrUtil.isNotBlank(jobName)) { - queryWrapper.like(QuartzJob::getJobName, jobName); - } - queryWrapper.orderByAsc(QuartzJob::getOrderno); - Page pageList = quartzJobService.page(page, queryWrapper); - return ResponseResult.successData(pageList); - } - - @Log(module = "定时任务管理", value = "新增定时任务") - @Operation(summary = "新增定时任务") - @PostMapping("/addQuartzJob") - public ResponseResult addQuartzJob(@RequestBody QuartzJob quartzJob) { - if (quartzJob == null) { - return ResponseResult.error("参数为空"); - } - // 添加最近修改人 - quartzJob.setLastmodifier(currentUser.getUsername()); - // 添加最近修改时间 - quartzJob.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - if (StrUtil.isBlank(quartzJob.getJobCron()) || !CronExpression.isValidExpression(quartzJob.getJobCron())) { - return ResponseResult.error("cron表达式格式错误"); - } - quartzJob.setStatus("0"); - boolean ok = quartzJobService.addQuartzJob(quartzJob); - quartzManage.addJob(quartzJob); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error("新增失败"); - } - } - - @Log(module = "定时任务管理", value = "设置定时任务是否有效") - @Operation(summary = "设置定时任务是否有效") - @PostMapping("/setQuartzStatus") - public ResponseResult setQuartzStatus(@RequestParam String id, - @RequestParam String status) { - if (StrUtil.isBlank(id) || StrUtil.isBlank(status)) { - return ResponseResult.error("参数为空"); - } - LambdaUpdateWrapper updateWrapper = - new LambdaUpdateWrapper<>(); - //根据id 更新状态,最近修改人,最近修改时间 - updateWrapper.eq(QuartzJob::getId, id).set(QuartzJob::getStatus, - status).set( - QuartzJob::getLastmodifier, currentUser.getUsername()).set(QuartzJob::getLastmodifydate, - LocalDateTime.now()); - boolean ok = quartzJobService.update(updateWrapper); - QuartzJob quartzJob = quartzJobService.getById(id); - if ("0".equals(quartzJob.getStatus())) { - quartzManage.pauseJob(quartzJob); - } else { - quartzManage.resumeJob(quartzJob); - } - - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - @Operation(summary = "根据ID查询定时任务") - @GetMapping("/getQuartzJobById") - public ResponseResult getQuartzJobById(String id) { - QuartzJob quartzJob = quartzJobService.getById(id); - return ResponseResult.successData(quartzJob); - } - - @Log(module = "定时任务管理", value = "修改定时任务") - @Operation(summary = "修改定时任务") - @PostMapping("/updateQuartzJob") - @Transactional(rollbackFor = Exception.class) - public ResponseResult updateQuartzJob(@RequestBody QuartzJob quartzJob) { - // 添加最近修改人 - quartzJob.setLastmodifier(currentUser.getUsername()); - // 添加最近修改时间 - quartzJob.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - if (StrUtil.isBlank(quartzJob.getJobCron()) || !CronExpression.isValidExpression(quartzJob.getJobCron())) { - return ResponseResult.error("cron表达式格式错误"); - } - boolean ok = quartzJobService.updateById(quartzJob); - quartzManage.updateJobCron(quartzJob); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error("修改失败"); - } - } - - @Log(module = "定时任务管理", value = "删除定时任务") - @Operation(summary = "删除定时任务") - @PostMapping("/deleteQuartzJob") - public ResponseResult deleteQuartzJob(@RequestParam String id) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - boolean ok = quartzJobService.deleteQuartzJob(id); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error("删除失败"); - } - } - - @Log(module = "定时任务管理", value = "执行定时任务") - @Operation(summary = "执行定时任务") - @PostMapping("/execution") - public ResponseResult execution(@RequestParam String id) { - quartzJobService.execution(quartzJobService.getById(id)); - return ResponseResult.success(); - } - - /********************************** - * 用途说明: 拖动修改定时顺序 - * 参数说明 fromID 当前ID toID 到达ID - * 返回值说明: com.yfd.platform.config.ResponseResult 成功或者失败 - ***********************************/ - @Log(module = "定时任务管理", value = "拖动定时任务") - @PostMapping("/changeDictOrder") - @Operation(summary = "拖动修改定时任务顺序") - public ResponseResult changeQuartzOrder(@RequestParam String fromID, - @RequestParam String toID) { - - boolean ok = quartzJobService.changeDictOrder(fromID, toID); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SSEController.java b/backend/src/main/java/com/yfd/platform/system/controller/SSEController.java deleted file mode 100644 index 41adfbb..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/SSEController.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.yfd.platform.system.controller; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.yfd.platform.component.ServerSendEventServer; -import com.yfd.platform.config.WebConfig; -import com.yfd.platform.constant.Constant; -import com.yfd.platform.system.domain.Message; -import com.yfd.platform.system.service.IMessageService; -import com.yfd.platform.system.service.IUserService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.extern.slf4j.Slf4j; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; - -import jakarta.annotation.Resource; - -/** - * @author Huhailong - */ -@Slf4j -@RestController -@CrossOrigin -@RequestMapping("/sse") -@Tag(name = "SSE推送服务") -public class SSEController { - - @Resource - private IMessageService messageService; - - @GetMapping("/connect/{token}") - @Operation(summary = "建立连接") - public SseEmitter connect(@PathVariable String token) { - SseEmitter connect = ServerSendEventServer.connect(token); - long count = - messageService.count(new LambdaQueryWrapper().eq(Message::getStatus, "1")); - ServerSendEventServer.sendMessage(token, count + ""); - return connect; - } - - @GetMapping("/sendmsg") - @Operation(summary = "发送消息") - public void sendMessage(String token, String message) throws InterruptedException { - - ServerSendEventServer.sendMessage(token, message); - } - - @GetMapping("/sendgroupmsg") - @Operation(summary = "多人发送消息") - public void sendgroupmsg(String groupid, String message) throws InterruptedException { - ServerSendEventServer.groupSendMessage(groupid, message); - } - - @GetMapping("/disconnect/{token}") - @Operation(summary = "关闭连接") - public void disconnect(@PathVariable String token) throws InterruptedException { - ServerSendEventServer.removeUser(token); - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysConfigController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysConfigController.java deleted file mode 100644 index 3cfa7cc..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysConfigController.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.yfd.platform.system.controller; - - -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.SysConfig; -import com.yfd.platform.system.service.ISysConfigService; -import com.yfd.platform.system.service.IUserService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import javax.sound.sampled.UnsupportedAudioFileException; -import java.io.IOException; -import java.sql.Timestamp; - - -/** - *

- * 系统全局配置 前端控制器 - *

- * - * @author zhengsl - * @since 2022-01-19 - */ -@RestController - @RequestMapping("/system/config") -@Tag(name = "系统全局配置") -public class SysConfigController { - @Resource - private ISysConfigService configService; - - @Resource - private IUserService userService; - - @PostMapping("/getOneById") - @Operation(summary = "根据id查询全局配置详情记录") - @ResponseBody - public SysConfig getOneById(String id){ - return configService.getById(id); - } - - @PostMapping("/addConfig") - @Operation(summary = "根据id查询全局配置详情记录") - @ResponseBody - public ResponseResult addConfig(@RequestBody SysConfig config ) throws IOException, UnsupportedAudioFileException { - if (StrUtil.isEmpty(config.getId())){ - config.setId(IdUtil.fastSimpleUUID()); } - config.setLastmodifier(userService.getUsername()); - config.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - boolean ok=configService.save(config); - return ResponseResult.success(); - } - - @PostMapping("/updateById") - @Operation(summary = "根据id修改全局配置记录") - @ResponseBody - public ResponseResult updateById(@RequestBody SysConfig config) throws IOException, UnsupportedAudioFileException { - config.setLastmodifier(userService.getUsername()); - config.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - boolean ok=configService.updateById(config); - return ResponseResult.success(); - } - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysDictionaryController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysDictionaryController.java deleted file mode 100644 index 70a5fdf..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysDictionaryController.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.yfd.platform.system.controller; - -import cn.hutool.core.util.StrUtil; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.SysDictionary; -import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; -import com.yfd.platform.system.service.ISysDictionaryService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.util.StringUtils; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import java.util.List; -import java.util.Objects; - -/** - *

- * 数据字典表 前端控制器 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -@RestController -@RequestMapping("/system/dictionary") -@Tag(name = "数据字典") -public class SysDictionaryController { - - @Resource - private ISysDictionaryService sysDictionaryService; - - /********************************** - * 用途说明: 获取数据字典列表 - * 参数说明 dictType 字典类型 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 - ***********************************/ - @GetMapping("/dictList") - @Operation(summary = "获取数据字典列表") - public ResponseResult getDictList(String dictType) { - if (StrUtil.isBlank(dictType)) { - return ResponseResult.error("参数为空"); - } - List sysDictionaries = - sysDictionaryService.getDictList(dictType); - return ResponseResult.successData(sysDictionaries); - } - - /********************************** - * 用途说明: 根据ID删除字典 - * 参数说明 id 字典ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回删除结果成功或者失败 - ***********************************/ - @Log(module = "数据字典", value = "根据ID删除字典") - @PostMapping("/deleteById") - @Operation(summary = "根据ID删除字典") - public ResponseResult deleteDictById(@RequestParam String id) { - boolean ok = sysDictionaryService.deleteDictById(id); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /********************************** - * 用途说明: 新增字典 - * 参数说明 sysDictionary 字典对象 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回增加成功或者失败 - ***********************************/ - @Log(module = "数据字典", value = "新增数据字典") - @PostMapping("/addDict") - @Operation(summary = "新增字典") - public ResponseResult addDict(@RequestBody SysDictionary sysDictionary) { - if (sysDictionary == null) { - return ResponseResult.error("参数为空"); - } - boolean ok = sysDictionaryService.addDict(sysDictionary); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /********************************** - * 用途说明: 修改字典 - * 参数说明 sysDictionary 字典对象 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败 - ***********************************/ - @Log(module = "数据字典", value = "修改数据字典") - @PostMapping("/updateDict") - @Operation(summary = "修改字典") - public ResponseResult updateDict(@RequestBody SysDictionary sysDictionary) { - if (sysDictionary == null) { - return ResponseResult.error("参数为空"); - } - boolean ok = sysDictionaryService.updateById(sysDictionary); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /********************************** - * 用途说明: 根据ID查询字典 - * 参数说明 sysDictionary 字典对象 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回查询结果 - ***********************************/ - @PostMapping("/getDictById") - @Operation(summary = "根据ID查询字典") - public ResponseResult getDictById(String id) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - SysDictionary sysDictionary = sysDictionaryService.getById(id); - return ResponseResult.successData(sysDictionary); - } - - /********************************** - * 用途说明: 拖动修改字典顺序 - * 参数说明 fromID 当前ID toID 到达ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败 - ***********************************/ - @Log(module = "数据字典", value = "拖动修改字典顺序") - @PostMapping("/changeDictOrder") - @Operation(summary = "拖动修改字典顺序") - public ResponseResult changeDictOrder(@RequestParam String fromID, - @RequestParam String toID) { - - boolean ok = sysDictionaryService.changeDictOrder(fromID, toID); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysDictionaryItemsController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysDictionaryItemsController.java deleted file mode 100644 index bf85d30..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysDictionaryItemsController.java +++ /dev/null @@ -1,201 +0,0 @@ -package com.yfd.platform.system.controller; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.SysDictionaryItems; -import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; -import com.yfd.platform.system.service.ISysDictionaryItemsService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import java.util.Arrays; -import java.util.List; - -/** - *

- * 数据字典明细 前端控制器 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -@RestController -@RequestMapping("/system/dictionaryItems") -@Tag(name = "数据字典项") -public class SysDictionaryItemsController { - - @Resource - private ISysDictionaryItemsService sysDictionaryItemsService; - - /********************************** - * 用途说明: 分页查询字典项信息 - * 参数说明 dictID 字典ID ItemName 字典项名称 pageNum 当前页 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 - ***********************************/ - @GetMapping("/page") - @Operation(summary = "分页查询字典项信息") - public ResponseResult getDictItemPage(String dictId, String dictName, - Page page) { - - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); - queryWrapper.eq(SysDictionaryItems::getDictId, dictId).orderByAsc(SysDictionaryItems::getOrderNo); - - // 查询前将序号初始化 - List list = - sysDictionaryItemsService.list(queryWrapper); - for (int i = 0; i < list.size(); i++) { - SysDictionaryItems sysDictionaryItems = list.get(i); - sysDictionaryItems.setOrderNo(i + 1); - sysDictionaryItemsService.updateById(sysDictionaryItems); - } - Page sysDictionaryItemsPage = - sysDictionaryItemsService.getDictItemPage(dictId, dictName, - page); - - return ResponseResult.successData(sysDictionaryItemsPage); - } - - /********************************** - * 用途说明: 增加字典项 - * 参数说明 sysDictionaryItems 字典项信息 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回增加成功或者失败 - ***********************************/ - @Log(module = "数据字典项", value = "增加字典项") - @PostMapping("/addDictionaryItem") - @Operation(summary = "增加字典项") - public ResponseResult addDictionaryItem(@RequestBody SysDictionaryItems sysDictionaryItems) { - if (sysDictionaryItems == null) { - return ResponseResult.error("参数为空"); - } - boolean ok = - sysDictionaryItemsService.addDictionaryItem(sysDictionaryItems); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /********************************** - * 用途说明: 修改字典项 - * 参数说明 sysDictionaryItems 字典项信息 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回修改成功或者失败 - ***********************************/ - @Log(module = "数据字典项", value = "修改字典项") - @PostMapping("/updateDictionaryItem") - @Operation(summary = "修改字典项") - public ResponseResult updateDictionaryItem(@RequestBody SysDictionaryItems sysDictionaryItems) { - if (sysDictionaryItems == null) { - return ResponseResult.error("参数为空"); - } - boolean ok = - sysDictionaryItemsService.updateById(sysDictionaryItems); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /********************************** - * 用途说明: 根据ID查询字典项 - * 参数说明 id 字典项ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回字典项信息 - ***********************************/ - @GetMapping("/getDictItemById") - @Operation(summary = "根据ID查询字典项") - public ResponseResult getDictItemById(String id) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - SysDictionaryItems sysDictionaryItems = - sysDictionaryItemsService.getById(id); - return ResponseResult.successData(sysDictionaryItems); - } - - /********************************** - * 用途说明: 根据ID删除字典项 - * 参数说明 id 字典项ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回删除成功或者失败 - ***********************************/ - @Log(module = "数据字典项", value = "根据ID删除字典项") - @PostMapping("/deleteDictItemById") - @Operation(summary = "根据ID删除字典项") - public ResponseResult deleteDictItemById(@RequestParam String id) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - boolean ok = sysDictionaryItemsService.removeById(id); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /********************************** - * 用途说明: 批量删除字典项 - * 参数说明 ids 字典项id数组 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回批量删除成功或失败 - ***********************************/ - @Log(module = "数据字典项", value = "批量删除字典项") - @PostMapping("/deleteDictItemByIds") - @Operation(summary = "批量删除字典项") - public ResponseResult deleteDictItemByIds(@RequestParam String id) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - String[] splitIds = id.split(","); - // 数组转集合 - List ids = Arrays.asList(splitIds); - boolean ok = sysDictionaryItemsService.removeByIds(ids); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /********************************** - * 用途说明: 拖动修改字典项顺序 - * 参数说明 fromID 当前ID toID 到达ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败 - ***********************************/ - @Log(module = "数据字典项", value = "拖动修改字典项顺序") - @PostMapping("/changeItemOrder") - @Operation(summary = "拖动修改字典项顺序") - public ResponseResult changeItemOrder(@RequestParam String fromID, - @RequestParam String toID) { - boolean ok = sysDictionaryItemsService.changeItemOrder(fromID, toID); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /********************************** - * 用途说明: 导出数据字典项数据 - * 参数说明 sysDictionaryItemsList 所需导出的字典项集合 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或失败 - ***********************************/ - @Log(module = "数据字典项", value = "导出字典数据到Excel") - @GetMapping("/exportExcel") - @Operation(summary = "导出数据字典项数据") - public void exportExcel(String dictID, String itemName, - Page page, - HttpServletResponse response) { - Page sysDictionaryItemsPage = - sysDictionaryItemsService.getDictItemPage(dictID, itemName, - page); - sysDictionaryItemsService.exportExcel(sysDictionaryItemsPage.getRecords(), response); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysLogController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysLogController.java deleted file mode 100644 index 9f2081a..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysLogController.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.yfd.platform.system.controller; - -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.SysLog; -import com.yfd.platform.system.service.ISysLogService; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - *

- * 系统操作日志 前端控制器 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -@RestController -@RequestMapping("/system/log") -@Tag(name = "系统日志") -public class SysLogController { - - @Resource - private ISysLogService sysLogService; - - /********************************** - * 用途说明: 分页查询日志信息 - * 参数说明 page分页对象、username(用户名)、(optType) - * 操作类型、startDate(开始日期)、endDate(结束日期) - * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 - ***********************************/ - @PostMapping("/getLogList") - @Operation(summary = "分页查询日志信息") - public ResponseResult getLogList(String username, String optType, - String startDate, - String endDate, Page page) { - - Page sysLogPage = sysLogService.getLogList(username, optType, - startDate, endDate, page); - Map map = new HashMap<>(); - map.put("list", sysLogPage.getRecords()); - map.put("total", sysLogPage.getTotal()); - map.put("size", sysLogPage.getSize()); - map.put("current", sysLogPage.getCurrent()); - return ResponseResult.successData(map); - } - - /********************************** - * 用途说明: 导出日志数据 - * 参数说明 sysLogs 所需导出的字典项集合 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或者失败 - ***********************************/ - @Log(module = "系统日志", value = "导出系统日志到Excel") - @GetMapping("/exportExcel") - @Operation(summary = "导出日志数据") - public void exportExcel(String username, String optType, - String startDate, - String endDate, Page page, - HttpServletResponse response) throws IOException { - - Page sysLogPage = sysLogService.getLogList(username, optType, - startDate, endDate, page); - sysLogService.exportExcel(sysLogPage.getRecords(), response); - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysMenuController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysMenuController.java deleted file mode 100644 index 3ac00e2..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysMenuController.java +++ /dev/null @@ -1,310 +0,0 @@ -package com.yfd.platform.system.controller; - -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.SysMenu; -import com.yfd.platform.system.domain.SysUser; -import com.yfd.platform.system.service.ISysMenuService; -import com.yfd.platform.system.service.IUserService; -import io.swagger.v3.oas.annotations.tags.Tag; -import io.swagger.v3.oas.annotations.Operation; -import org.apache.catalina.User; -import org.springframework.util.StringUtils; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import jakarta.annotation.Resource; -import java.io.File; -import java.io.FileNotFoundException; -import java.sql.Timestamp; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - *

- * 菜单及按钮 前端控制器 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -@RestController -@RequestMapping("/system/menu") -@Tag(name = "菜单及按钮") -public class SysMenuController { - - @Resource - private ISysMenuService sysMenuService; - - @Resource - private IUserService userService; - - // 菜单图片路径通过服务层配置获取,无需在控制器注入 - - /*********************************** - * 用途说明:获取菜单结构树(含按钮) - * 参数说明 - * systemcode 系统 - * name 名称 - * isdisplay 是否显示 - * 返回值说明: 菜单结构树集合 - ***********************************/ - @PostMapping("/getMenuButtonTree") - @Operation(summary = "获取菜单结构树(含按钮)") - @ResponseBody - public List> getMenuButtonTree(String systemcode, - String name, - String isdisplay) { - return sysMenuService.getMenuButtonTree(systemcode, name, isdisplay); - } - - /*********************************** - * 用途说明:获取菜单结构树(不含按钮) - * 参数说明 - * systemcode 系统 - * name 名称 - * isdisplay 是否显示 - * 返回值说明: 菜单结构树集合 - ***********************************/ - @PostMapping("/getMenuTree") - @Operation(summary = "获取菜单结构树(不含按钮)") - @ResponseBody - public List> getMenuTree(String systemcode, - String name, - String isdisplay) { - return sysMenuService.getMenuTree(systemcode, name, isdisplay); - } - - /*********************************** - * 用途说明:权限分配 - * 参数说明 - * systemcode 系统 - * name 名称 - * isdisplay 是否显示 - * 返回值说明: 菜单结构树集合 - ***********************************/ - @PostMapping("/permissionAssignment") - @Operation(summary = "获取分配权限(不含按钮)") - @ResponseBody - public List> permissionAssignment(String code, String roleId) { - if (StrUtil.isBlank(code)) { - code = "1"; - } - return sysMenuService.permissionAssignment(code,roleId); - } - - /********************************** - * 用途说明: 获取当前用户菜单结构树 - * 参数说明 - * 返回值说明: java.util.List - ***********************************/ - @GetMapping("/treeRoutes") - @Operation(summary = "获取当前用户菜单结构树") - @ResponseBody - public List> getMenuTreeByUser() { - SysUser userInfo = userService.getUserInfo(); - String id = ""; - if (0 != userInfo.getUsertype()) { - id = userInfo.getId(); - } - return sysMenuService.getMenuTree(id); - } - - /*********************************** - * 用途说明:根据id查询菜单或按钮详情 - * 参数说明 - * id 菜单或按钮表id - * 返回值说明: 菜单或按钮表对象 - ***********************************/ - @PostMapping("/getOneById") - @Operation(summary = "根据id查询菜单或按钮详情") - @ResponseBody - public ResponseResult getOneById(String id) { - SysMenu sysMenu = sysMenuService.getById(id); - return ResponseResult.successData(sysMenu); - } - - /*********************************** - * 用途说明:新增菜单及按钮 - * 参数说明 - * sysMenu 菜单或按钮表对象 - * 返回值说明: 是否添加成功提示 - ***********************************/ - @Log(module = "菜单及按钮", value = "新增菜单及按钮!") - @PostMapping("/addMenu") - @Operation(summary = "新增菜单及按钮") - @ResponseBody - public ResponseResult addMenu(@RequestBody SysMenu sysMenu) { - boolean isOk = sysMenuService.addMenu(sysMenu); - if (isOk) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:修改菜单及按钮 - * 参数说明 - * sysMenu 菜单或按钮表对象 - * 返回值说明: 是否修改成功提示 - ***********************************/ - @Log(module = "菜单及按钮", value = "修改菜单及按钮") - @PostMapping("/updateById") - @Operation(summary = "修改菜单及按钮") - @ResponseBody - public ResponseResult updateById(@RequestBody SysMenu sysMenu) { - sysMenu.setLastmodifier(userService.getUsername()); - sysMenu.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - boolean isOk = sysMenuService.updateById(sysMenu); - if (isOk) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:根据id删除单个图标 - * 参数说明 - * id 删除图标id - * icon 图标名称 - * 返回值说明: 是否删除成功 - ***********************************/ - @Log(module = "菜单及按钮", value = "根据id删除单个图标!") - @PostMapping("/deleteIcon") - @Operation(summary = "根据id删除单个图标") - @ResponseBody - public ResponseResult deleteIcon(@RequestParam String id) { - boolean ok = sysMenuService.deleteIcon(id); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:更新菜单及按钮是否有效 - * 参数说明 - * id 菜单及按钮表id - * isdisplay 是否有效字段 - * 返回值说明: 是否更新成功 - ***********************************/ - @Log(module = "菜单及按钮", value = "更新菜单及按钮是否有效!") - @PostMapping("/setIsDisplay") - @Operation(summary = "更新菜单及按钮是否有效") - @ResponseBody - public ResponseResult setIsDisplay(String id, String isdisplay) { - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - //根据id 修改是否显示 ,最近修改人,最近修改时间 - updateWrapper.eq("id", id).set("isdisplay", isdisplay).set( - "lastmodifier", userService.getUsername()).set( - "lastmodifydate", - new Timestamp(System.currentTimeMillis())); - boolean ok = sysMenuService.update(updateWrapper); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:菜单及按钮序号排序 - * 参数说明 - * parentid 上级id - * orderMap map<菜单及按钮表id,排列序号> - * 返回值说明: 是否更新成功 - ***********************************/ - @Log(module = "菜单及按钮", value = "菜单及按钮序号排序!") - @PostMapping("/moveOrderno") - @Operation(summary = "菜单及按钮序号排序") - @ResponseBody - public ResponseResult moveOrderno(@RequestParam String parentid, - @RequestParam String id, - @RequestParam int orderno) { - boolean ok = sysMenuService.moveOrderno(parentid, id, orderno); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:根据id删除菜单或按钮 - * 参数说明 - * id 删除列的id - * 返回值说明: 是否删除成功 - ***********************************/ - @Log(module = "菜单及按钮", value = "根据id删除菜单或按钮!") - @PostMapping("/deleteById") - @Operation(summary = "根据id删除菜单或按钮") - @ResponseBody - public ResponseResult deleteById(@RequestParam String id) { - boolean ok = sysMenuService.deleteById(id); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /********************************** - * 用途说明: 菜单或者按钮拖动 - * 参数说明 id - * 参数说明 id1 - * 返回值说明: com.yfd.platform.config.ResponseResult - ***********************************/ - @Log(module = "菜单及按钮", value = "拖动修改菜单或按钮同级顺序!") - @PostMapping("/changeMenuOrder") - @Operation(summary = "菜单或按钮切换") - @ResponseBody - public ResponseResult changeMenuOrder(@RequestParam String fromId, - @RequestParam String toId) { - if (StrUtil.isBlank(fromId) || StrUtil.isBlank(toId)) { - return ResponseResult.error("参数为空!"); - } - if (fromId.equals(toId)) { - return ResponseResult.error("切换失败!"); - } - boolean ok = sysMenuService.changeOderNoById(fromId, toId); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:上传单个图标 - * 参数说明 - * icon 图标 - * 返回值说明: 是否上传成功 - ***********************************/ - @PostMapping("/uploadIcon") - @Operation(summary = "上传单个图标") - @ResponseBody - public ResponseResult uploadIcon(MultipartFile icon, String menuId) throws FileNotFoundException { - if (StrUtil.isNotBlank(menuId)) { - SysMenu sysMenu = sysMenuService.getById(menuId); - //图片路径 - String iconname = - System.getProperty("user.dir") + "\\src\\main" + - "\\resources\\static\\icon" + File.separator + sysMenu.getIcon(); - //删除图标 - new File(iconname).delete(); - } - String filename = sysMenuService.uploadIcon(icon); - SysMenu sysMenu = new SysMenu(); - sysMenu.setId(menuId); - sysMenu.setIcon(filename); - sysMenuService.updateById(sysMenu); - return ResponseResult.successData(filename); - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysOrganizationController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysOrganizationController.java deleted file mode 100644 index 45c0218..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysOrganizationController.java +++ /dev/null @@ -1,213 +0,0 @@ -package com.yfd.platform.system.controller; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.SysOrganization; -import com.yfd.platform.system.domain.SysRole; -import com.yfd.platform.system.domain.SysUser; -import com.yfd.platform.system.mapper.SysRoleMapper; -import com.yfd.platform.system.service.ISysOrganizationService; -import com.yfd.platform.system.service.IUserService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import java.sql.Timestamp; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - *

- * 系统组织框架 前端控制器 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -@RestController -@RequestMapping("/system/organization") -@Tag(name = "系统组织框架") -public class SysOrganizationController { - - @Resource - private ISysOrganizationService organizationService; - - @Resource - private IUserService userService; - - /*********************************** - * 用途说明:获取组织范围树结构 - * 参数说明 - *parentid 上级id - * params 名称(根据名称查询二级) - * 返回值说明: 组织树集合 - ***********************************/ - @PostMapping("/getOrgScopeTree") - @Operation(summary = "获取组织范围树结构") - @ResponseBody - public List> getOrgScopeTree(String roleId) { - return organizationService.getOrgScopeTree(roleId); - } - - /*********************************** - * 用途说明:获取组织范围 - * 参数说明 - * 返回值说明: 组织范围集合 - ***********************************/ - @PostMapping("/getOrgTree") - @Operation(summary = "获取组织结构树") - @ResponseBody - public List> getOrgTree(String parentid, - String params) { - return organizationService.getOrgTree(parentid, params); - } - - /*********************************** - * 用途说明:根据企业ID查询组织详情 - * 参数说明 - * id 企业id - * 返回值说明: 系统组织框架对象 - ***********************************/ - @PostMapping("/getOrganizationById") - @Operation(summary = "根据企业ID查询组织信息") - @ResponseBody - public ResponseResult getOrganizationById(String id, String orgName) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("查询失败!"); - } - List sysOrganizations = - organizationService.getOrganizationById(id, orgName); - return ResponseResult.successData(sysOrganizations); - } - - /*********************************** - * 用途说明:根据ID查询组织详情 - * 参数说明 - * id 系统组织id - * 返回值说明: 系统组织框架对象 - ***********************************/ - @PostMapping("/getOneById") - @Operation(summary = "根据ID查询组织详情") - @ResponseBody - public ResponseResult getOneById(String id) { - SysOrganization sysOrganization = organizationService.getById(id); - return ResponseResult.successData(sysOrganization); - } - - /*********************************** - * 用途说明:新增系统组织框架 - * 参数说明 - * sysOrganization 系统组织框架对象 - * 返回值说明: 是否新增成功 - ***********************************/ - @Log(module = "系统组织框架", value = "新增企业或者部门!") - @PostMapping("/addOrg") - @Operation(summary = "新增系统组织框架") - @ResponseBody - public ResponseResult addOrg(@RequestBody SysOrganization sysOrganization) { - //判断是否是否填写 有效 否则默认为 1 - if (StrUtil.isEmpty(sysOrganization.getIsvaild())) { - sysOrganization.setIsvaild("1"); - } - if("".equals(sysOrganization.getId())){ - sysOrganization.setId(null); - } - //填写 当前用户名称 - sysOrganization.setLastmodifier(userService.getUsername()); - //填写 当前日期 - sysOrganization.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - //新增 系统组织R - boolean isOk = organizationService.addOrg(sysOrganization); - if (isOk) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:修改系统组织框架 - * 参数说明 - * sysOrganization 系统组织框架对象 - * 返回值说明: 是否修改成功 - ***********************************/ - @Log(module = "系统组织框架", value = "修改企业或者部门信息!") - @PostMapping("/updateById") - @Operation(summary = "修改系统组织框架") - @ResponseBody - public ResponseResult updateById(@RequestBody SysOrganization sysOrganization) { - //填写 当前用户名称 - sysOrganization.setLastmodifier(userService.getUsername()); - //填写 当前日期 - sysOrganization.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - //根据id 修改系统组织 - boolean isOk = organizationService.updateById(sysOrganization); - if (isOk) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:修改系统组织框架 - * 参数说明 - * sysOrganization 系统组织框架对象 - * 返回值说明: 是否修改成功 - ***********************************/ - @Log(module = "系统组织框架", value = "设置企业/部门是否有效!") - @PostMapping("/setIsValid") - @Operation(summary = "设置组织是否有效") - @ResponseBody - public ResponseResult setIsValid(@RequestParam String id, - @RequestParam String isvaild) { - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - //根据id 修改是否有效,最近修改人,最近修改时间 - updateWrapper.eq("id", id).set("isvaild", isvaild).set("lastmodifier" - , userService.getUsername()).set("lastmodifydate", - new Timestamp(System.currentTimeMillis())); - boolean isOk = organizationService.update(updateWrapper); - if (isOk) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:根据id删除系统组织框架 - * 参数说明 - * id 系统组织框架id - * 返回值说明: 是否删除成功 - ***********************************/ - @Log(module = "系统组织框架", value = "根据ID删除企业或者部门!") - @PostMapping("/deleteById") - @Operation(summary = "根据id删除系统组织框架") - @ResponseBody - public ResponseResult deleteById(@RequestParam String id) { - String[] orgIds = id.split(","); - for (String orgId : orgIds) { - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); - List list = - organizationService.list(queryWrapper.eq(SysOrganization::getParentid, orgId)); - List ids = - list.stream().map(SysOrganization::getId).collect(Collectors.toList()); - boolean isOk = organizationService.removeById(orgId); - if (!isOk) { - continue; - } - for (String oid : ids) { - organizationService.removeById(oid); - } - } - return ResponseResult.success(); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/SysRoleController.java b/backend/src/main/java/com/yfd/platform/system/controller/SysRoleController.java deleted file mode 100644 index dae5472..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/SysRoleController.java +++ /dev/null @@ -1,318 +0,0 @@ -package com.yfd.platform.system.controller; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.SysRole; -import com.yfd.platform.system.service.ISysRoleService; -import com.yfd.platform.system.service.IUserService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.*; - -import jakarta.annotation.Resource; -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.util.List; -import java.util.Map; - -/** - *

- * 系统角色 前端控制器 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -@RestController -@RequestMapping("/system/role") -@Tag(name = "系统角色") -public class SysRoleController { - - @Resource - private ISysRoleService roleService; - - @Resource - private IUserService userService; - - /*********************************** - * 用途说明:查询所有角色 - * 参数说明 - * roleName 角色名称 - * 返回值说明: 查询都有角色 - ***********************************/ - @PostMapping("/list") - @Operation(summary = "查询所有角色") - @ResponseBody - public List list(@RequestParam(required = false) String rolename) { - return roleService.selectRoleList(rolename); - } - - /*********************************** - * 用途说明:根据Id获取当个角色 - * 参数说明 - * id 角色表id - * 返回值说明: 根据id查询到角色详情 - ***********************************/ - @PostMapping("/getOneById") - @Operation(summary = "根据Id获取当个角色") - @ResponseBody - public ResponseResult getOneById(String id) { - SysRole sysRole = roleService.getById(id); - return ResponseResult.successData(sysRole); - } - - /*********************************** - * 用途说明:新增角色 - * 参数说明 - * sysRole 新增角色信息 - * 返回值说明: 是否新增成功 - ***********************************/ - @Log(module = "系统角色", value = "新增角色") - @PostMapping("/addRole") - @Operation(summary = "新增角色") - @ResponseBody - public ResponseResult addRole(@RequestBody SysRole sysRole) { - boolean isOk = roleService.addRole(sysRole); - if (isOk) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:分配操作权限 - * 参数说明 - * id 角色id - * optscope 分配的权限 - * 返回值说明: 是否新增成功 - ***********************************/ - @Log(module = "系统角色", value = "分配操作权限") - @PostMapping("/setOptScope") - @Operation(summary = "分配操作权限") - @ResponseBody - public ResponseResult setOptScope(@RequestParam String id, - @RequestParam String optscope) { - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - //根据id 更新权限,最近修改人,最近修改时间 - updateWrapper.eq("id", id).set("optscope", optscope).set( - "lastmodifier", userService.getUsername()).set( - "lastmodifydate", LocalDateTime.now()); - boolean ok = roleService.update(updateWrapper); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:角色菜单权限 - * 参数说明 - * id 角色id - * menuIds 权限id字符串 - * 返回值说明: 是否分配成功 - ***********************************/ - @Log(module = "系统角色", value = "角色菜单权限") - @PostMapping("/setMenuById") - @Operation(summary = "角色菜单权限") - @ResponseBody - public ResponseResult setMenuById(String id, String menuIds) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - if (StrUtil.isBlank(menuIds)) { - return ResponseResult.success(); - } - boolean ok = roleService.setMenuById(id, menuIds); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - - } - - /*********************************** - * 用途说明:设置组织范围 - * 参数说明 - * id 角色id - * orgscope 组织范围 - * 返回值说明: 是否新增成功 - ***********************************/ - @Log(module = "系统角色", value = "设置组织范围") - @PostMapping("/setOrgscope") - @Operation(summary = "设置组织范围") - @ResponseBody - public ResponseResult setOrgscope(@RequestParam String id, - @RequestParam String orgscope) { - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - //根据id 更新组织范围,最近修改人,最近修改时间 - updateWrapper.eq("id", id).set("orgscope", orgscope).set( - "lastmodifier", userService.getUsername()).set( - "lastmodifydate", LocalDateTime.now()); - boolean ok = roleService.update(updateWrapper); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:设置业务范围 - * 参数说明 - * id 角色id - * busscope 业务范围 - * 返回值说明: 是否新增成功 - ***********************************/ - @Log(module = "系统角色", value = "设置业务范围") - @PostMapping("/setBusscope") - @Operation(summary = "设置业务范围") - @ResponseBody - public ResponseResult setBusscope(@RequestParam String id, - @RequestParam String busscope) { - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - //根据id 更新业务范围,最近修改人,最近修改时间 - updateWrapper.eq("id", id).set("busscope", busscope).set( - "lastmodifier", userService.getUsername()).set( - "lastmodifydate", LocalDateTime.now()); - boolean ok = roleService.update(updateWrapper); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:角色添加用户 - * 参数说明 - * roleid 角色id - * userids 用户id组 - * 返回值说明: 是否新增成功 - ***********************************/ - @Log(module = "系统角色", value = "角色添加用户") - @PostMapping("/setRoleUsers") - @Operation(summary = "角色添加用户") - @ResponseBody - public ResponseResult setRoleUsers(String roleid, String userids) { - boolean isOk = true; - String[] temp = userids.split(","); - for (String userid : temp) { - isOk = isOk && userService.addUserRoles(roleid, userid); - } - if (isOk) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:删除角色用户 - * 参数说明 - * roleid 角色id - * 返回值说明: 是否新增成功 - ***********************************/ - @PostMapping("/deleteRoleUser") - @Operation(summary = "删除角色用户") - @ResponseBody - public ResponseResult deleteRoleUsers(@RequestParam String roleid, - @RequestParam String userids) { - //根据角色id、用户id删除 - boolean ok = roleService.deleteRoleUsers(roleid, userids); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:设置角色是否有效 - * 参数说明 - * id 角色id - *isvaild 是否有效(1 是 0 否 ) - * 返回值说明: 是否新增成功 - ***********************************/ - @PostMapping("/setIsvaild") - @Operation(summary = "设置角色是否有效") - @ResponseBody - public ResponseResult setIsvaild(String id, String isvaild) { - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - //根据id 更新业务范围,最近修改人,最近修改时间 - updateWrapper.eq("id", id).set("isvaild", isvaild).set("lastmodifier" - , userService.getUsername()).set("lastmodifydate", - LocalDateTime.now()); - boolean ok = roleService.update(updateWrapper); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:更新角色信息 - * 参数说明 - *sysRole 角色对象 - * 返回值说明: 是否修改成功 - ***********************************/ - @PostMapping("/updateById") - @Operation(summary = "更新角色信息") - @ResponseBody - public ResponseResult updateById(@RequestBody SysRole sysRole) { - //更新最近修改人 - sysRole.setLastmodifier(userService.getUsername()); - //更新最近修改时间 - sysRole.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - //根据id更新角色信息 - boolean ok = roleService.updateById(sysRole); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:根据id删除角色 - * 参数说明 - *id 角色id - * 返回值说明: 是否删除成功 - ***********************************/ - @PostMapping("/deleteById") - @Operation(summary = "根据id删除角色") - @ResponseBody - public ResponseResult deleteById(@RequestParam String id) { - roleService.deleteById(id); - return ResponseResult.success(); - } - - /*********************************** - * 用途说明:查询已分配的用户 - * 参数说明 - *orgid 所属组织 - *username 用户名称 - *status 状态 - *level 角色级别 - * rolename 角色名称 - * isvaild 角色是否有效 - * 返回值说明: 系统用户角色数据集合 - ***********************************/ - @PostMapping("/listRoleUsers") - @Operation(summary = "查询已分配的用户") - @ResponseBody - public List listRoleUsers(String orgid, String username, - String status, String level, - String rolename, String isvaild) { - return roleService.listRoleUsers(orgid, username, status, level, - rolename, isvaild); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/controller/UserController.java b/backend/src/main/java/com/yfd/platform/system/controller/UserController.java deleted file mode 100644 index ecf4003..0000000 --- a/backend/src/main/java/com/yfd/platform/system/controller/UserController.java +++ /dev/null @@ -1,188 +0,0 @@ -package com.yfd.platform.system.controller; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.datasource.DataSource; -import com.yfd.platform.system.domain.SysUser; -import com.yfd.platform.system.service.IUserService; -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import jakarta.annotation.Resource; -import java.sql.Timestamp; -import java.util.Map; - -/** - *

- * 用户信息 前端控制器 - *

- * - * @author zhengsl - * @since 2022-09-20 - */ -@RestController -@RequestMapping("/system/user") -@Tag(name = "系统用户") -public class UserController { - - @Resource - private IUserService userService; - - @Log(module = "系统用户", value = "新增系统用户") - @PostMapping("/addUser") - @Operation(summary = "新增系统用户") - @ResponseBody - public ResponseResult addUser(@RequestBody SysUser user, String roleids) { - Map reslut = userService.addUser(user, roleids); - return ResponseResult.successData(reslut); - } - - @Log(module = "系统用户", value = "修改用户信息") - @PostMapping("/updateUser") - @Operation(summary = "修改用户信息") - @ResponseBody - public ResponseResult updateUser(@RequestBody SysUser user, - String roleids) { - if (StrUtil.isEmpty(user.getId())) { - return ResponseResult.error("没有用户ID"); - } - //填写 当前用户名称 - user.setLastmodifier(userService.getUsername()); - //填写 当前日期 - user.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - Map reslut = userService.updateById(user, roleids); - return ResponseResult.successData(reslut); - } - - @GetMapping("/queryUsers") - @Operation(summary = "查询用户信息") - @ResponseBody - public ResponseResult queryUsers(String orgid, - String username, Page page) { - - Page mapPage = userService.queryUsers(orgid, - username, page); - return ResponseResult.successData(mapPage); - } - - /*********************************** - * 用途说明:用户分配角色 - * 参数说明 - *idMap 用户id与角色id - * 返回值说明: 判断是否添加成功 - ************************************/ - @Log(module = "系统用户", value = "用户分配角色") - @PostMapping("/setUserRoles") - @Operation(summary = "用户分配角色") - @ResponseBody - public ResponseResult setUserRoles(String roleid, String userids) { - boolean ok = userService.setUserRoles(roleid, userids); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:根据id删除用户 - * 参数说明 - *id 用户id - * 返回值说明: 判断是否删除成功 - ************************************/ - @Log(module = "系统用户", value = "根据ID删除用户") - @PostMapping("/deleteById") - @Operation(summary = "根据ID删除用户") - @ResponseBody - public ResponseResult deleteById(String id) { - userService.deleteById(id); - return ResponseResult.success(); - } - - /*********************************** - * 用途说明:根据ID批量删除用户 - * 参数说明 - *ids 用户id集合 - * 返回值说明: 判断是否删除成功 - ************************************/ - @Log(module = "系统用户", value = "根据ID批量删除用户") - @PostMapping("/deleteUserByIds") - @Operation(summary = "根据ID批量删除用户") - @ResponseBody - public ResponseResult deleteUserByIds(String id) { - if (StrUtil.isBlank(id)) { - return ResponseResult.error("参数为空"); - } - boolean ok = userService.deleteUserByIds(id); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:重置用户密码(管理员) - * 参数说明 - *id 重置密码的 用户id - * 返回值说明: 判断是否重置成功 - ************************************/ - @Log(module = "系统用户", value = "重置用户密码") - @PostMapping("/resetPassword") - @Operation(summary = "重置用户密码") - @ResponseBody - @DataSource - public ResponseResult resetPassword(String id) throws Exception { - if (StrUtil.isBlank(id)) { - ResponseResult.error("参数为空"); - } - boolean ok = userService.resetPassword(id); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:设置账号状态(管理员) - * 参数说明 - *id 用户id - * status 设置状态 - * 返回值说明: 判断是否设置成功 - ************************************/ - @Log(module = "系统用户", value = "设置账号状态") - @PostMapping("/setStatus") - @Operation(summary = "设置账号状态") - @ResponseBody - public ResponseResult setStatus(@RequestParam String id, - @RequestParam String status) { - boolean ok = userService.setStatus(id, status); - if (ok) { - return ResponseResult.success(); - } else { - return ResponseResult.error(); - } - } - - /*********************************** - * 用途说明:修改头像(管理员) - * 参数说明 - * multipartFile 文件对象 - * status 设置状态 - * 返回值说明: 文件名 - ************************************/ - @Operation(summary = "修改头像") - @PostMapping(value = "/updateAvatar") - public ResponseResult updateAvatar(String id, MultipartFile multipartFile) { - if (multipartFile == null) { - ResponseResult.error("参数为空"); - } - boolean ok = userService.uploadAvatar(id, multipartFile); - return ResponseResult.success(); - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/Dictionary.java b/backend/src/main/java/com/yfd/platform/system/domain/Dictionary.java deleted file mode 100644 index 9abb146..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/Dictionary.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serializable; - -/** - *

- * 数据字典表 - *

- * - * @author zhengsl - * @since 2021-10-27 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("RCA_DICTIONARY") -public class Dictionary implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * id - */ - @TableId(type = IdType.ASSIGN_UUID) - private String id; - - /** - * 类型 - */ - private String type; - - /** - * 类型名称 - */ - private String typename; - - /** - * 代码 - */ - private String code; - - /** - * 名称 - */ - private String name; - - /** - * 顺序号 - */ - private String orderno; - - /** - * 上级代码 - */ - private String parentcode; - - /** - * 备用1 - */ - private String custom1; - - /** - * 备用2 - */ - private String custom2; - - /** - * 备用3 - */ - private String custom3; - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/LoginUser.java b/backend/src/main/java/com/yfd/platform/system/domain/LoginUser.java deleted file mode 100644 index 44cfb35..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/LoginUser.java +++ /dev/null @@ -1,76 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.alibaba.fastjson.annotation.JSONField; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class LoginUser implements UserDetails { - - private SysUser user; - - private List permissions; - - public LoginUser(SysUser user, List permissions) { - this.user = user; - this.permissions = permissions; - } - - @JSONField(serialize = false) - private List authorities; - - @Override - public Collection getAuthorities() { - // 将权限信息放入集合 - authorities = permissions.stream() - .map(SimpleGrantedAuthority::new) - .collect(Collectors.toList()); - return authorities; - } - - @Override - public String getPassword() { - return user.getPassword(); - } - - @Override - public String getUsername() { - return user.getUsername(); - } - - //获取用户昵称 - public String geNickname() { - return user.getNickname(); - } - - @Override - public boolean isAccountNonExpired() { - return true; - } - - @Override - public boolean isAccountNonLocked() { - return true; - } - - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - @Override - public boolean isEnabled() { - return true; - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/Message.java b/backend/src/main/java/com/yfd/platform/system/domain/Message.java deleted file mode 100644 index 759819e..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/Message.java +++ /dev/null @@ -1,117 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; - -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.io.Serializable; - -import com.fasterxml.jackson.annotation.JsonFormat; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - *

- * 消息通知 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_MESSAGE") -public class Message implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * ID - */ - @TableId(type = IdType.ASSIGN_UUID) - @Schema(description = "ID") - private String id; - - /** - * 创建时间:排序 - */ - @Schema(description = "创建时间:排序") - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") - private Timestamp createtime; - - /** - * 消息类型:1-定时任务 2-工作流触发 3-人工触发 - */ - @Schema(description = "消息类型:1-定时任务 2-工作流触发 3-人工触发") - private String type; - - /** - * 消息标题 - */ - @Schema(description = "消息标题") - private String title; - - /** - * 消息内容 - */ - @Schema(description = "消息内容") - private String content; - - /** - * 发送者名称,定时器,人员 - */ - @Schema(description = "发送者名称,定时器,人员") - private String senderName; - - /** - * 接收者代码 人员账号列表 - */ - @Schema(description = "接收者代码 人员账号列表 ") - private String receiverCodes; - - /** - * 接收者名称:为空 即为所有人,人员名称列表 - */ - @Schema(description = "接收者名称:为空 即为所有人,人员名称列表") - private String receiverNames; - - /** - * 状态:1、初始创建 2-消息已阅 9-消息过期 - */ - @Schema(description = "状态:1、初始创建 2-消息已阅 9-消息过期") - private String status; - - /** - * 有效期:小时 - */ - @Schema(description = "有效期:小时") - private Integer validperiod; - - /** - * 已阅时间 - */ - @Schema(description = "已阅时间") - private Timestamp readtime; - - /** - * 备用1 - */ - @Schema(description = "备用1") - private String custom1; - - /** - * 备用2 - */ - @Schema(description = "备用2") - private String custom2; - - /** - * 备用3 - */ - @Schema(description = "备用3") - private String custom3; - -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/QuartzJob.java b/backend/src/main/java/com/yfd/platform/system/domain/QuartzJob.java deleted file mode 100644 index d513514..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/QuartzJob.java +++ /dev/null @@ -1,118 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; - -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.io.Serializable; - -import com.fasterxml.jackson.annotation.JsonFormat; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; -import lombok.EqualsAndHashCode; - -/** - *

- * 定时任务 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_QUARTZ_JOB") -public class QuartzJob implements Serializable { - - public static final String JOB_KEY = "JOB_KEY"; - private static final long serialVersionUID = 1L; - - /** - * ID - */ - @Schema(description = "ID") - @TableId(type = IdType.ASSIGN_UUID) - private String id; - - /** - * 排序号 - */ - @Schema(description = "排序号") - private Integer orderno; - - /** - * 任务名称 - */ - @Schema(description = "任务名称") - private String jobName; - - /** - * 执行类名称 - */ - @Schema(description = "执行类名称") - private String jobClass; - - /** - * 执行方法名称 - */ - @Schema(description = "执行方法名称") - private String jobMethod; - - /** - * 时间周期表达式 - */ - @Schema(description = "时间周期表达式") - private String jobCron; - - /** - * 方法参数 - */ - @Schema(description = "方法参数") - private String jobParams; - - /** - * 任务描述 - */ - @Schema(description = "任务描述") - private String description; - - /** - * 状态:0-暂停、1-启用 - */ - @Schema(description = "状态:0-暂停、1-启用") - private String status; - - /** - * 最近修改者 - */ - @Schema(description = "最近修改者") - private String lastmodifier; - - /** - * 最近修改日期 - */ - @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") - @Schema(description = "最近修改日期") - private Timestamp lastmodifydate; - - /** - * 备用1 - */ - @Schema(description = "备用1") - private String custom1; - - /** - * 备用2 - */ - @Schema(description = "备用2") - private String custom2; - - /** - * 备用3 - */ - @Schema(description = "备用3") - private String custom3; - -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysConfig.java b/backend/src/main/java/com/yfd/platform/system/domain/SysConfig.java deleted file mode 100644 index 3830d97..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/SysConfig.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serializable; -import java.sql.Timestamp; - -/** - *

- * 系统全局配置 - *

- * - * @author zhengsl - * @since 2022-01-19 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_CONFIG") -public class SysConfig implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * id - */ - @TableId(type = IdType.ASSIGN_UUID) - private String id; - - /** - * 欢迎词 - */ - private String welcome; - - /** - * 系统功能介绍 - */ - private String funcation; - - /** - * 系统版本信息 - */ - private String versioninfo; - - /** - * 备注 - */ - private String remark; - - /** - * 最近修改者 - */ - private String lastmodifier; - - /** - * 最近修改日期 - */ - @TableField(fill = FieldFill.UPDATE) - private Timestamp lastmodifydate; - - /** - * 备用1 - */ - private String custom1; - - /** - * 备用2 - */ - private String custom2; - - /** - * 备用3 - */ - private String custom3; - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysDictionary.java b/backend/src/main/java/com/yfd/platform/system/domain/SysDictionary.java deleted file mode 100644 index e57a13e..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/SysDictionary.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serializable; - -/** - *

- * 数据字典表 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_DICTIONARY") -public class SysDictionary implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * id - */ - @TableId(type = IdType.ASSIGN_UUID) - private String id; - - /** - * 字典类型 00-系统内置 01-用户配置 - */ - @TableField("DICTTYPE") - private String dictType; - - /** - * 顺序号 - */ - @TableField("ORDERNO") - private Integer orderNo; - - /** - * 字典编码 - */ - @TableField("DICTCODE") - private String dictCode; - - /** - * 字典名称 - */ - @TableField("DICTNAME") - private String dictName; - - /** - * 备用1 - */ - private String custom1; - - /** - * 备用2 - */ - private String custom2; - - /** - * 备用3 - */ - private String custom3; - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysDictionaryItems.java b/backend/src/main/java/com/yfd/platform/system/domain/SysDictionaryItems.java deleted file mode 100644 index 59a7c56..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/SysDictionaryItems.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serializable; - -/** - *

- * 数据字典明细 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_DICTIONARY_ITEMS") -public class SysDictionaryItems implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * id - */ - @TableId(type = IdType.ASSIGN_UUID) - private String id; - - /** - * 对应字典ID - */ - @TableField("DICTID") - private String dictId; - - /** - * 顺序号 - */ - @TableField("ORDERNO") - private Integer orderNo; - - /** - * 项编码 - */ - @TableField("ITEMCODE") - private String itemCode; - - /** - * 项名称 - */ - @TableField("DICTNAME") - private String dictName; - - /** - * 父项编码 - */ - @TableField("PARENTCODE") - private String parentCode; - - /** - * 备用1 - */ - private String custom1; - - /** - * 备用2 - */ - private String custom2; - - /** - * 备用3 - */ - private String custom3; - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysLog.java b/backend/src/main/java/com/yfd/platform/system/domain/SysLog.java deleted file mode 100644 index a359769..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/SysLog.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.NoArgsConstructor; - -import java.io.Serializable; -import java.sql.Timestamp; -import java.time.LocalDateTime; - -/** - *

- * 系统操作日志 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -@Data -@NoArgsConstructor -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_LOG") -public class SysLog implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * ID - */ - @TableId(value = "ID", type = IdType.ASSIGN_UUID) - private String id; - - /** - * 用户账号 - */ - @TableField("USERCODE") - private String usercode; - - /** - * 用户名称 - */ - private String username; - - /** - * 操作类型 00-登录 01-新增 02-修改 03-删除 06-查询 09其他 - */ - @TableField("OPTTYPE") - private String opttype; - - /** - * 模块名称 - */ - private String module; - - /** - * 日志描述 - */ - private String description; - - /** - * 操作方法 - */ - private String method; - - /** - * 方法参数 - */ - private String params; - - /** - * 创建时间 - */ - @TableField("LOGTIME") - private Timestamp logtime; - - /** - * 请求IP - */ - @TableField("REQUESTIP") - private String requestip; - - /** - * 浏览器类型 - */ - private String browser; - - public SysLog(String opttype) { - this.opttype = opttype; - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysMenu.java b/backend/src/main/java/com/yfd/platform/system/domain/SysMenu.java deleted file mode 100644 index 8392ce6..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/SysMenu.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serializable; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.List; - -/** - *

- * 菜单及按钮 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_MENU") -public class SysMenu implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * id - */ - @TableId(type = IdType.ASSIGN_UUID) - private String id; - - /** - * 1-web 2-pad 3-mobile - */ - private String systemcode; - - /** - * 1-菜单 2-按钮 - */ - private String type; - - /** - * 在系统内自动生成 - */ - private String code; - - /** - * 名称 - */ - private String name; - - /** - * 图标地址 - */ - private String icon; - - /** - * 是否外链 - */ - private String islink; - - /** - * 内部模块路径或者外链地址 - */ - private String opturl; - - /** - * 权限控制标识 - */ - private String permission; - - /** - * 顶级为0 - */ - private String parentid; - - /** - * 排序号 - */ - private Integer orderno; - - /** - * 0-不显示 1-显示 - */ - private String isdisplay; - - /** - * 最近修改者 - */ - private String lastmodifier; - - /** - * 最近修改日期 - */ - @TableField(fill = FieldFill.UPDATE) - private Timestamp lastmodifydate; - - /** - * 备用1 - */ - private String custom1; - - /** - * 备用2 - */ - private String custom2; - - /** - * 备用3 - */ - private String custom3; - -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysOrganization.java b/backend/src/main/java/com/yfd/platform/system/domain/SysOrganization.java deleted file mode 100644 index 0f9a719..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/SysOrganization.java +++ /dev/null @@ -1,93 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serializable; -import java.sql.Timestamp; - -/** - *

- * 系统组织框架 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_ORGANIZATION") -public class SysOrganization implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * id - */ - @TableId(type = IdType.ASSIGN_UUID) - private String id; - - /** - * 1-公司 -2-部门 - */ - private String orgtype; - - /** - * 两位一级 - */ - private String orgcode; - - /** - * 组织名称 - */ - private String orgname; - - /** - * 上级id - */ - private String parentid; - - /** - * 组织负责人 - */ - private String manager; - - /** - * 1-是 0-否 - */ - private String isvaild; - - /** - * 描述 - */ - private String description; - - /** - * 最近修改者 - */ - private String lastmodifier; - - /** - * 最近修改日期 - */ - @TableField(fill = FieldFill.UPDATE) - private Timestamp lastmodifydate; - - /** - * 备用1 - */ - private String custom1; - - /** - * 备用2 - */ - private String custom2; - - /** - * 备用3 - */ - private String custom3; - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysRole.java b/backend/src/main/java/com/yfd/platform/system/domain/SysRole.java deleted file mode 100644 index 68ab3ce..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/SysRole.java +++ /dev/null @@ -1,99 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serializable; -import java.sql.Timestamp; - -/** - *

- * 系统角色 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_ROLE") -public class SysRole implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * id - */ - @TableId(type = IdType.ASSIGN_UUID) - private String id; - - /** - * 系统生成,三位编号 - */ - private String rolecode; - - /** - * 角色名称 - */ - private String rolename; - - /** - * 1-超级管理员 2-单位管理员 3-普通用户 - */ - @TableField("\"LEVEL\"") - private String level; - - /** - * 描述 - */ - private String description; - - /** - * org1,org2 - */ - private String orgscope; - - /** - * 多个操作代码(菜单、按钮) - */ - private String optscope; - - /** - * json格式自定义业务范围 - */ - private String busscope; - - /** - * 1-是 0-否 - */ - private String isvaild; - - /** - * 最近修改者 - */ - private String lastmodifier; - - /** - * 最近修改日期 - */ - @TableField(fill = FieldFill.UPDATE) - private Timestamp lastmodifydate; - - /** - * 备用1 - */ - private String custom1; - - /** - * 备用2 - */ - private String custom2; - - /** - * 备用3 - */ - private String custom3; - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/domain/SysUser.java b/backend/src/main/java/com/yfd/platform/system/domain/SysUser.java deleted file mode 100644 index 57c5b85..0000000 --- a/backend/src/main/java/com/yfd/platform/system/domain/SysUser.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.yfd.platform.system.domain; - -import com.baomidou.mybatisplus.annotation.*; -import lombok.Data; -import lombok.EqualsAndHashCode; - -import java.io.Serializable; -import java.sql.Timestamp; -import java.util.List; - -/** - *

- * 系统用户 - *

- * - * @author zhengsl - * @since 2021-10-27 - */ - -@Data -@EqualsAndHashCode(callSuper = false) -@TableName("SYS_USER") -public class SysUser implements Serializable { - - private static final long serialVersionUID = 1L; - - /** - * id 主键 - */ - @TableId(type = IdType.ASSIGN_UUID) - private String id; - - /** - * 用户类型 0-管理员 1-普通用户 - */ - private Integer usertype; - - /** - * 用户名(账号) - */ - private String username; - /** - * 用户昵称 - */ - private String nickname; - - /** - * 登录密码(加密存储) - */ - private String password; - - /** - * 性别(0-男 1-女 ) - */ - private String sex; - - /** - * 邮箱 - */ - private String email; - /** - * 手机号 - */ - private String phone; - - /** - * 头像(预留) - */ - private String avatar; - - /** - * 账号状态(1-正常 0-停用) - */ - private Integer status; - - /** - * 部门ID - */ - private String orgid; - - /** - * 密码重置时间 - */ - private String pwdresettime; - - /** - * 最近修改者 - */ - private String lastmodifier; - - /** - * 最近修改日期 - */ - @TableField(fill = FieldFill.UPDATE) - private Timestamp lastmodifydate; - - @TableField(exist = false) - private String uuid; - - @TableField(exist = false) - private String code; - - /** - * 备用1 - */ - private String custom1; - - /** - * 备用2 - */ - private String custom2; - - /** - * 备用3 - */ - private String custom3; - - @TableField(exist = false) - List roles; -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/MessageMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/MessageMapper.java deleted file mode 100644 index d08fa95..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/MessageMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.yfd.platform.system.mapper; - -import com.yfd.platform.system.domain.Message; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - *

- * 消息通知 Mapper 接口 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -public interface MessageMapper extends BaseMapper { - -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/QuartzJobMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/QuartzJobMapper.java deleted file mode 100644 index ad46f1b..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/QuartzJobMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.yfd.platform.system.mapper; - -import com.yfd.platform.system.domain.QuartzJob; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; - -/** - *

- * 定时任务 Mapper 接口 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -public interface QuartzJobMapper extends BaseMapper { - -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysConfigMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysConfigMapper.java deleted file mode 100644 index 5bae048..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysConfigMapper.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.yfd.platform.system.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yfd.platform.system.domain.SysConfig; - - -/** - *

- * 系统全局配置 Mapper 接口 - *

- * - * @author zhengsl - * @since 2022-01-19 - */ -public interface SysConfigMapper extends BaseMapper { - -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysDictionaryItemsMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysDictionaryItemsMapper.java deleted file mode 100644 index de7deaa..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysDictionaryItemsMapper.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.yfd.platform.system.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yfd.platform.system.domain.SysDictionaryItems; - -/** - *

- * 数据字典明细 Mapper 接口 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -public interface SysDictionaryItemsMapper extends BaseMapper { - -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysDictionaryMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysDictionaryMapper.java deleted file mode 100644 index 7d03ca9..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysDictionaryMapper.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.yfd.platform.system.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yfd.platform.system.domain.SysDictionary; - -/** - *

- * 数据字典表 Mapper 接口 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -public interface SysDictionaryMapper extends BaseMapper { - - /********************************** - * 用途说明: 根据字典类型获取字典最大序号 - * 参数说明 sysDictionary 字典对象 - * 返回值说明: 返回增加成功或者失败 - ***********************************/ - Integer selectMaxNo(String dictType); -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysLogMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysLogMapper.java deleted file mode 100644 index 7b18518..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysLogMapper.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.yfd.platform.system.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yfd.platform.system.domain.SysLog; - -/** - *

- * 系统操作日志 Mapper 接口 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -public interface SysLogMapper extends BaseMapper { - -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysMenuMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysMenuMapper.java deleted file mode 100644 index 061feeb..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysMenuMapper.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.yfd.platform.system.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yfd.platform.system.domain.SysMenu; -import org.apache.ibatis.annotations.Param; - -import java.util.List; -import java.util.Map; - -/** - *

- * 菜单及按钮 Mapper 接口 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -public interface SysMenuMapper extends BaseMapper { - - /*********************************** - * 用途说明:菜单及按钮序号向上移动 - * 参数说明 - * parentid 上级id - *Orderno 小于序号(原序号) - *upOrderno 大于等于序号(更改的序号加一) - * 返回值说明: 是否更新成功 - ***********************************/ - boolean upMoveOrderno(@Param("parentid") String parentid, @Param("Orderno") int Orderno, @Param("upOrderno") int upOrderno); - - /*********************************** - * 用途说明:菜单及按钮序号向下移动 - * 参数说明 - * parentid 上级id - *Orderno 大于序号(原序号) - *downOrderno 小于等于序号(更改的序号减一) - * 返回值说明: 是否更新成功 - ***********************************/ - boolean downMoveOrderno(@Param("parentid") String parentid, @Param("Orderno") int Orderno, @Param("downOrderno") int downOrderno); - - - List selectPermsByUserId(String userId); - - //List selectMenuByUserId(String userId); - List selectMenuByUserId(String userId); - - /*********************************** - * 用途说明:根据权限id查找系统类型 - * 参数说明 id 权限id - * 返回值说明: 返回系统类型 - ***********************************/ - String getSystemCodeById(String id); - - /*********************************** - * 用途说明:根据角色Id查找权限 - * 参数说明 id 权限id - * 返回值说明: 返回权限集合 - ***********************************/ - List selectMenuByRoleId(String id); -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysOrganizationMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysOrganizationMapper.java deleted file mode 100644 index e856aae..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysOrganizationMapper.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.yfd.platform.system.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yfd.platform.system.domain.SysOrganization; -import org.apache.ibatis.annotations.Param; - -import java.util.List; - -/** - *

- * 系统组织框架 Mapper 接口 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -public interface SysOrganizationMapper extends BaseMapper { - - /*********************************** - * 用途说明:去重查询组织分类 - * 返回值说明: 所有组织分类 - ***********************************/ - List queryOrgtype(); - - /*********************************** - * 用途说明:根据组织分类查询上级id - * 参数说明 - * orgtype 组织分类 - * 返回值说明: 上级id - ***********************************/ - List queryParentid(@Param("orgtype") String orgtype); - -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java deleted file mode 100644 index 09201a1..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysRoleMapper.java +++ /dev/null @@ -1,112 +0,0 @@ -package com.yfd.platform.system.mapper; - -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.yfd.platform.system.domain.SysRole; -import org.apache.ibatis.annotations.Param; - -import java.util.List; -import java.util.Map; - -/** - *

- * 系统角色 Mapper 接口 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -public interface SysRoleMapper extends BaseMapper { - - /*********************************** - * 用途说明:根据角色id查询是否存在用户 - * 参数说明 - * roleid 角色id - * 返回值说明: 该角色下是否存在用户 - ************************************/ - List> isRoleUsersByroleid(String roleid); - - /*********************************** - * 用途说明:根据角色id查询是否存在权限 - * 参数说明 - * roleid 角色id - * 返回值说明: 该角色下是否存在权限 - ************************************/ - List> isRoleMenuByRoleId(String roleId); - - /*********************************** - * 用途说明:查询已分配的用户 - * 参数说明 - *orgid 所属组织 - *username 用户名称 - *status 状态 - *level 角色级别 '1-超级管理员 2-单位管理员 3-普通用户' - * rolename 角色名称 - * isvaild 角色是否有效 - * 返回值说明: 系统用户角色数据集合 - ***********************************/ - List listRoleUsers(String orgid, String username, String status, - String level, String rolename, String isvaild); - - /*********************************** - * 用途说明:根据 角色id和用户id 删除 (admin除外) - * 参数说明 - *roleid 角色id - * urserid 用户id - * 返回值说明: 是否删除成功 - ***********************************/ - boolean deleteRoleUsers(String roleid, String urserid); - - /********************************** - * 用途说明: 根据用户id获取角色信息 - * 参数说明 id 角色id - * 返回值说明: void - ***********************************/ - List getRoleByUserId(String id); - - /********************************** - * 用途说明: 根据角色ID删除菜单与角色关联信息 - * 参数说明 id 角色id - * 返回值说明: void - ***********************************/ - boolean deleteRoleMenus(String id); - - /********************************** - * 用途说明: 根据角色ID删除用户与角色关联信息 - * 参数说明 id 角色id - * 返回值说明: void - ***********************************/ - boolean deleteRoleUser(String id); - - /********************************** - * 用途说明: 根据角色id获取用户id - * 参数说明 id 角色id - * 返回值说明: 用户id - ***********************************/ - List getUserIdById(String id); - - void addRoleMenu(@Param("id") String id, @Param("roleid") String roleid, - @Param("menuid") String menuid); - - - /********************************** - * 用途说明:根据用户 id 获取角色信息 - * 参数说明 id 用户 id - * 返回值说明:角色列表 - ***********************************/ - List getRoleListByUserId(String id); - - /********************************** - * 用途说明:根据用户 id 获取角色 ID 列表 - * 参数说明 id 用户 id - * 返回值说明:角色 ID 列表 - ***********************************/ - List getRoleIdsByUserId(String id); - - /********************************** - * 用途说明:查询角色列表(Oracle 兼容) - * 参数说明:rolename - 角色名称 - * 返回值说明:角色列表 - ***********************************/ - List selectRoleList(@Param("rolename") String rolename); - -} diff --git a/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java b/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java deleted file mode 100644 index 7aae6a3..0000000 --- a/backend/src/main/java/com/yfd/platform/system/mapper/SysUserMapper.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.yfd.platform.system.mapper; - - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.mapper.BaseMapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.yfd.platform.system.domain.SysUser; -import org.apache.ibatis.annotations.Param; - -import java.util.List; -import java.util.Map; - -/** - *

- * 系统用户表 Mapper 接口 - *

- * - * @author zhengsl - * @since 2021-10-27 - */ -public interface SysUserMapper extends BaseMapper { - List list(@Param("total")String total, @Param("size")String size, @Param("orgid")String orgid, @Param("username")String username, @Param("mobile")String mobile , @Param("status")String status); - - /*********************************** - * 用途说明:新增系统角色用户对照表 对用户分配角色 - * 参数说明 - * id 生成的id - * roleid 角色id - * userid 用户id - * 返回值说明: - ************************************/ - boolean addUserRoles(@Param("id")String id,@Param("roleid") String roleid,@Param("userid") String userid); - - /*********************************** - * 用途说明:根据用户id 和角色id 查询 系统角色用户对照表 - * 参数说明 - * userid 用户id - * roleid 角色id - * 返回值说明: - ************************************/ - List getRoleUsersByid(@Param("roleid") String roleid,@Param("userid") String userid); - - /*********************************** - * 用途说明:根据用户表id查询角色表所有角色 - * 参数说明 - * userid 用户id - * 返回值说明: - ************************************/ - List getLevel(@Param("userid") String userid); - - /*********************************** - * 用途说明:根据用户表id查询角色表所有角色id - * 参数说明 - * userid 用户id - * 返回值说明: - ************************************/ - List getRoleid(@Param("userid") String userid); - - /*********************************** - * 用途说明:根据用户表id查询角色表级别 - * 参数说明 - * userid 用户id - * 返回值说明: - ************************************/ - String getMaxLevel(@Param("userid") String userid); - - /*********************************** - * 用途说明:根据用户id删除所分配的角色 - * 参数说明 - * userid 用户id - * 返回值说明: - ************************************/ - boolean delRoleUsersByUserid(@Param("userid") String userid); - - /*********************************** - * 用途说明:根据用户id删除所分配的不包含角色 - * 参数说明 - * userid 用户id - * roleids 多个角色id - * 返回值说明: - ************************************/ - boolean delInRoleUsersByUserid(@Param("userid") String userid,@Param("roleids")String[] roleids); - - Page queryUsers(String orgid, - String username, - Page page); - - Map getOrganizationByid(String id); - - /********************************** - * 用途说明: 根据ID删除用户与角色的关联信息 - * 参数说明 ids 用户id集合 - * 返回值说明: void - ***********************************/ - void delRoleUsersByUserIds(List ids); -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/IMessageService.java b/backend/src/main/java/com/yfd/platform/system/service/IMessageService.java deleted file mode 100644 index 2b4c645..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/IMessageService.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.yfd.platform.system.service; - -import com.yfd.platform.system.domain.Message; -import com.baomidou.mybatisplus.extension.service.IService; - -/** - *

- * 消息通知 服务类 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -public interface IMessageService extends IService { - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/IQuartzJobService.java b/backend/src/main/java/com/yfd/platform/system/service/IQuartzJobService.java deleted file mode 100644 index 8b71868..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/IQuartzJobService.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.yfd.platform.system.service; - -import com.yfd.platform.system.domain.QuartzJob; -import com.baomidou.mybatisplus.extension.service.IService; - -/** - *

- * 定时任务 服务类 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -public interface IQuartzJobService extends IService { - - /********************************** - * 用途说明: 新增定时任务 - * 参数说明 quartzJob 定时对象 - * 返回值说明: boolean 是否成功 - ***********************************/ - boolean addQuartzJob(QuartzJob quartzJob); - - /********************************** - * 用途说明: 删除定时任务 - * 参数说明 id id - * 返回值说明: boolean 是否成功 - ***********************************/ - boolean deleteQuartzJob(String id); - - /********************************** - * 用途说明: 拖动修改定时任务顺序 - * 参数说明 fromID 当前ID toID 到达ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败 - ***********************************/ - boolean changeDictOrder(String fromID, String toID); - - /********************************** - * 用途说明: 执行定时任务 - * 参数说明 id id - * 返回值说明: void - ***********************************/ - void execution(QuartzJob byId); -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISysConfigService.java b/backend/src/main/java/com/yfd/platform/system/service/ISysConfigService.java deleted file mode 100644 index ef3a399..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/ISysConfigService.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.yfd.platform.system.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.yfd.platform.system.domain.SysConfig; - -import javax.sound.sampled.UnsupportedAudioFileException; -import java.io.IOException; -import java.util.Map; - -/** - *

- * 系统全局配置 服务类 - *

- * - * @author zhengsl - * @since 2022-01-19 - */ -public interface ISysConfigService extends IService { - - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISysDictionaryItemsService.java b/backend/src/main/java/com/yfd/platform/system/service/ISysDictionaryItemsService.java deleted file mode 100644 index 32f9b8f..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/ISysDictionaryItemsService.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.yfd.platform.system.service; - -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yfd.platform.system.domain.SysDictionaryItems; - -import jakarta.servlet.http.HttpServletResponse; -import java.util.List; - -/** - *

- * 数据字典明细 服务类 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -public interface ISysDictionaryItemsService extends IService { - - /********************************** - * 用途说明: 分页查询字典项信息 - * 参数说明 dictID 字典ID ItemName 字典项名称 pageNum 当前页 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 - ***********************************/ - Page getDictItemPage(String dictId, String itemName, Page page); - - /********************************** - * 用途说明: 增加字典项 - * 参数说明 sysDictionaryItems 字典项信息 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回增加成功或者失败 - ***********************************/ - boolean addDictionaryItem(SysDictionaryItems sysDictionaryItems); - - /********************************** - * 用途说明: 拖动修改字典项顺序 - * 参数说明 fromID 当前ID toID 到达ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败 - ***********************************/ - boolean changeItemOrder(String fromID, String toID); - - /********************************** - * 用途说明: 导出数据字典项数据 - * 参数说明 sysDictionaryItemsList 所需导出的字典项集合 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或失败 - ***********************************/ - void exportExcel(List records, HttpServletResponse response); -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISysDictionaryService.java b/backend/src/main/java/com/yfd/platform/system/service/ISysDictionaryService.java deleted file mode 100644 index f3a4990..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/ISysDictionaryService.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.yfd.platform.system.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.yfd.platform.system.domain.SysDictionary; - -import java.util.List; - -/** - *

- * 数据字典表 服务类 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -public interface ISysDictionaryService extends IService { - - /********************************** - * 用途说明: 获取数据字典列表 - * 参数说明 dictType 字典类型 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 - ***********************************/ - List getDictList(String dictType); - - /********************************** - * 用途说明: 新增字典 - * 参数说明 sysDictionary 字典对象 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回增加成功或者失败 - ***********************************/ - boolean addDict(SysDictionary sysDictionary); - - /********************************** - * 用途说明: 根据ID删除字典 - * 参数说明 id 字典ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回删除结果成功或者失败 - ***********************************/ - boolean deleteDictById(String id); - - /********************************** - * 用途说明: 拖动修改字典顺序 - * 参数说明 fromID 当前ID toID 到达ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败 - ***********************************/ - boolean changeDictOrder(String fromID, String toID); -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISysLogService.java b/backend/src/main/java/com/yfd/platform/system/service/ISysLogService.java deleted file mode 100644 index 85fdffa..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/ISysLogService.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.yfd.platform.system.service; - -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yfd.platform.system.domain.SysLog; -import org.aspectj.lang.ProceedingJoinPoint; - -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.util.List; -import java.util.Map; - -/** - *

- * 系统操作日志 服务类 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -public interface ISysLogService extends IService { - - /********************************** - * 用途说明: 分页查询日志信息 - * 参数说明 pageNum(页码数)、pageSize(页大小,如果是固定页大小可不传)、username(用户名)、(optType) - * 操作类型、startDate(开始日期)、endDate(结束日期) - * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 - ***********************************/ - Page getLogList(String username, String optType, - String startDate, - String endDate, Page page); - - - /********************************** - * 用途说明: 导出日志数据 - * 参数说明 sysLogs 所需导出的字典项集合 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或者失败 - ***********************************/ - void exportExcel(List sysLogs, HttpServletResponse response) throws IOException; - - /********************************** - * 用途说明: 新增日志 - * 参数说明 nickname 用户名 - * 参数说明 username 用户账号 - * 参数说明 browser 浏览器 - * 参数说明 ip 本机Ip地址 - * 参数说明 joinPoint 连接点 - * 参数说明 log 日志信息 - * 返回值说明: void - ***********************************/ - void save(String nickname,String username, String browser, String ip, ProceedingJoinPoint joinPoint, SysLog log); -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISysMenuService.java b/backend/src/main/java/com/yfd/platform/system/service/ISysMenuService.java deleted file mode 100644 index b24b283..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/ISysMenuService.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.yfd.platform.system.service; - -import com.baomidou.mybatisplus.extension.service.IService; - -import com.yfd.platform.system.domain.SysMenu; -import org.springframework.web.multipart.MultipartFile; - -import java.io.FileNotFoundException; -import java.util.List; -import java.util.Map; - -/** - *

- * 菜单及按钮 服务类 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -public interface ISysMenuService extends IService { - - /*********************************** - * 用途说明:获取菜单结构树(含按钮) - * 参数说明 - * systemcode 系统 - * name 名称 - * isdisplay 是否显示 - * 返回值说明: 菜单结构树集合 - ***********************************/ - List> getMenuButtonTree(String systemcode, String name, String isdisplay); - - /*********************************** - * 用途说明:获取菜单结构树(不含按钮) - * 参数说明 - * systemcode 系统 - * name 名称 - * isdisplay 是否显示 - * 返回值说明: 菜单结构树集合 - ***********************************/ - List> getMenuTree(String systemcode, String name, String isdisplay); - - - /*********************************** - * 用途说明:新增菜单及按钮 - * 参数说明 - * sysMenu 菜单或按钮表对象 - * 返回值说明: 是否添加成功提示 - ***********************************/ - boolean addMenu(SysMenu sysMenu); - - /*********************************** - * 用途说明:上传单个图标 - * 参数说明 - * id 上传图标id - * icon 图标 - * 返回值说明: 是否上传成功 - ***********************************/ - boolean uploadIcon(String id, MultipartFile icon); - - /*********************************** - * 用途说明:根据id删除单个图标 - * 参数说明 - * id 删除图标id - * icon 图标名称 - * 返回值说明: 是否删除成功 - ***********************************/ - boolean deleteIcon(String id); - - /*********************************** - * 用途说明:菜单及按钮序号排序 - * 参数说明 - * parentid 上级id - * orderMap map<菜单及按钮表id,排列序号> - * 返回值说明: 是否更新成功 - ***********************************/ - boolean moveOrderno(String parentid, String id, int orderno); - - /*********************************** - * 用途说明:根据id删除菜单或按钮 - * 参数说明 - * id 删除列的id - * 返回值说明: 是否删除成功 - ***********************************/ - boolean deleteById(String id); - - boolean changeOderNoById(String fromId, String toId); - - List> getMenuTree(String id); - - /*********************************** - * 用途说明:权限分配 - * 参数说明 - * systemcode 系统 - * name 名称 - * isdisplay 是否显示 - * 返回值说明: 菜单结构树集合 - ***********************************/ - List> permissionAssignment(String code,String roleId); - - String uploadIcon(MultipartFile icon) throws FileNotFoundException; -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISysOrganizationService.java b/backend/src/main/java/com/yfd/platform/system/service/ISysOrganizationService.java deleted file mode 100644 index 5b03119..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/ISysOrganizationService.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.yfd.platform.system.service; - - -import com.baomidou.mybatisplus.extension.service.IService; -import com.yfd.platform.system.domain.SysOrganization; - -import java.util.List; -import java.util.Map; - -/** - *

- * 系统组织框架 服务类 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -public interface ISysOrganizationService extends IService { - - /*********************************** - * 用途说明:获取组织结构树 - * 参数说明 - *parentid 上级id - * params 名称(根据名称查询二级) - * 返回值说明: 组织树集合 - ***********************************/ - List> getOrgTree(String parentid, String params); - - /*********************************** - * 用途说明:新增系统组织框架 - * 参数说明 - * sysOrganization 系统组织框架对象 - * 返回值说明: 是否新增成功 - ***********************************/ - boolean addOrg(SysOrganization sysOrganization); - - /*********************************** - * 用途说明:根据企业ID查询组织详情 - * 参数说明 - * id 企业id - * 返回值说明: 系统组织框架对象 - ***********************************/ - List getOrganizationById(String id,String orgName); - - /*********************************** - * 用途说明:获取组织范围树结构 - * 参数说明 - *roleId 角色id - * 返回值说明: 组织树集合 - ***********************************/ - List> getOrgScopeTree(String roleId); - - /********************************** - * 用途说明: 修改角色组织范围 - * 参数说明 roleId 角色id - * 参数说明 orgscope 组织id集合 - * 返回值说明: boolean 是否修改成功 - ***********************************/ - boolean updateOrgScopeByRoleId(String roleId, String orgscope); -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/ISysRoleService.java b/backend/src/main/java/com/yfd/platform/system/service/ISysRoleService.java deleted file mode 100644 index 2065a17..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/ISysRoleService.java +++ /dev/null @@ -1,68 +0,0 @@ -package com.yfd.platform.system.service; - -import com.baomidou.mybatisplus.extension.service.IService; -import com.yfd.platform.system.domain.SysRole; - -import java.util.List; -import java.util.Map; - -/** - *

- * 系统角色 服务类 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -public interface ISysRoleService extends IService { - - /*********************************** - * 用途说明:新增角色 - * 参数说明 - * sysRole 新增角色信息 - * 返回值说明: 是否新增成功 - ***********************************/ - boolean addRole(SysRole sysRole); - - /*********************************** - * 用途说明:删除角色用户 - * 参数说明 - * id 系统角色用户对照表id - * 返回值说明: 是否新增成功 - ***********************************/ - - boolean deleteRoleUsers(String roleid, String urserids); - - /*********************************** - * 用途说明:根据id删除角色 - * 参数说明 - *id 角色id - * 返回值说明: 是否删除成功 - ***********************************/ - void deleteById(String id); - - /*********************************** - * 用途说明:查询已分配的用户 - * 参数说明 - *orgid 所属组织 - *username 用户名称 - *status 状态 - *level 角色级别 - * rolename 角色名称 - * isvaild 角色是否有效 - * 返回值说明: 系统用户角色数据集合 - ***********************************/ - List listRoleUsers(String orgid, String username, String status, String level, String rolename, String isvaild); - - - /*********************************** - * 用途说明:角色分配权限 - * 参数说明 - * id 角色id - * menuIds 权限id字符串 - * 返回值说明: 是否分配成功 - ***********************************/ - boolean setMenuById(String id, String menuIds); - - List selectRoleList(String rolename); -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/IUserService.java b/backend/src/main/java/com/yfd/platform/system/service/IUserService.java deleted file mode 100644 index e1ff507..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/IUserService.java +++ /dev/null @@ -1,143 +0,0 @@ -package com.yfd.platform.system.service; - -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.IService; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.LoginUser; -import com.yfd.platform.system.domain.SysUser; -import org.springframework.web.multipart.MultipartFile; - -import java.io.File; -import java.util.List; -import java.util.Map; - -/** - *

- * 系统用户 - *

- * - * @author zhengsl - * @since 2021-10-27 - */ -public interface IUserService extends IService { - - //获取当前用户账号及名称 - String getUsername(); - - //获取当前用户信息 - SysUser getUserInfo(); - /*********************************** - * 用途说明:获取当前用户账号与姓名 - * 返回值说明: 当前用户账号与姓名 - ************************************/ - Map getNameInfo(); - //获取当前用户信息带权限 - ResponseResult getLoginUserInfo(); - - /*********************************** - * 用途说明:新增用户 - * 参数说明 - *sysUser 新增用户对象 - * id 创建者id - * roleId 角色id - * 返回值说明: 提示字符串 - ************************************/ - Map addUser(SysUser sysUser, String roleids); - - /*********************************** - * 用途说明:查询系统用户 - * 参数说明 - *page 分页集合参数 - *orgid 所属组织 - *username 用户名称 - * mobile 手机号 - * status 状态 - * 返回值说明: 用户分页集合 - ************************************/ - List list(String total, String size, String orgid, String username, - String mobile, String status); - - /*********************************** - * 用途说明:根据ID查询用户详情 - * 参数说明 - *id 用户id - * 返回值说明: 用户表对象 - ************************************/ - Map getOneById(String id); - - /*********************************** - * 用途说明:根据ID修改用户 - * 参数说明 - *sysUser 用户对象 - *roleids 角色id - * 返回值说明: 是否更新成功 - ************************************/ - Map updateById(SysUser sysUser, String roleids); - - /*********************************** - * 用途说明:用户分配角色(多个) - * 参数说明 - *roleid 角色id - * userids 用户id数组 - * 返回值说明: 判断是否添加成功 - ************************************/ - boolean setUserRoles(String roleid, String userids); - - /*********************************** - * 用途说明:根据id删除用户 - * 参数说明 - *id 用户id - * 返回值说明: 判断是否删除成功 - ************************************/ - boolean deleteById(String id); - - /*********************************** - * 用途说明:重置用户密码(管理员) - * 参数说明 - *id 重置密码的 用户id - * 返回值说明: 判断是否重置成功 - ************************************/ - boolean resetPassword(String id) throws Exception; - - /*********************************** - * 用途说明:设置账号状态(管理员) - * 参数说明 - *id 用户id - * status 设置状态 - * 返回值说明: 判断是否设置成功 - ************************************/ - boolean setStatus(String id, String status); - - /*********************************** - * 用途说明:上传用户头像 - * 参数说明 - * id 用户id - * img 账号头像 - * 返回值说明: 判断是否上传 - ***********************************/ - boolean uploadAvatar(String id, MultipartFile img); - - /*********************************** - * 用途说明:新增系统角色用户对照表 对用户分配角色(单个) - * 参数说明 - * id 生成的id - * userid 用户id - * roleid 角色id - * 返回值说明: - ************************************/ - boolean addUserRoles(String roleid, String userid); - - //Page queryUsers(String orgid, String username, Page page); - Page queryUsers(String orgid, String username, Page page); - - /*********************************** - * 用途说明:根据ID批量删除用户 - * 参数说明 - *ids 用户id集合 - * 返回值说明: 判断是否删除成功 - ************************************/ - boolean deleteUserByIds(String ids); - - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/MessageServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/MessageServiceImpl.java deleted file mode 100644 index 0d3875f..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/MessageServiceImpl.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import com.yfd.platform.system.domain.Message; -import com.yfd.platform.system.mapper.MessageMapper; -import com.yfd.platform.system.service.IMessageService; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import org.springframework.stereotype.Service; - -/** - *

- * 消息通知 服务实现类 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -@Service -public class MessageServiceImpl extends ServiceImpl implements IMessageService { - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/QuartzJobServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/QuartzJobServiceImpl.java deleted file mode 100644 index d2a9030..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/QuartzJobServiceImpl.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.yfd.platform.system.domain.QuartzJob; -import com.yfd.platform.system.domain.SysDictionary; -import com.yfd.platform.system.mapper.QuartzJobMapper; -import com.yfd.platform.system.service.IQuartzJobService; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.utils.QuartzManage; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import java.util.Arrays; -import java.util.List; -import java.util.Set; -import java.util.stream.Collectors; - -/** - *

- * 定时任务 服务实现类 - *

- * - * @author TangWei - * @since 2023-03-19 - */ -@Service -public class QuartzJobServiceImpl extends ServiceImpl implements IQuartzJobService { - - @Resource - private QuartzJobMapper quartzJobMapper; - - @Resource - private QuartzManage quartzManage; - - /********************************** - * 用途说明: 新增定时任务 - * 参数说明 quartzJob 定时对象 - * 返回值说明: boolean 是否成功 - ***********************************/ - @Override - public boolean addQuartzJob(QuartzJob quartzJob) { - // 生成序号 - long orderNo = this.count() + 1L; - quartzJob.setOrderno((int) orderNo); - return this.save(quartzJob); - } - - /********************************** - * 用途说明: 删除定时任务 - * 参数说明 id id - * 返回值说明: boolean 是否成功 - ***********************************/ - @Override - public boolean deleteQuartzJob(String id) { - String[] split = id.split(","); - Set ids = Arrays.stream(split).collect(Collectors.toSet()); - for (String s : ids) { - QuartzJob quartzJob = this.getById(s); - quartzManage.deleteJob(quartzJob); - this.removeById(s); - } - - // 查询所有定时任务 - List list = - this.list(new LambdaQueryWrapper().orderByAsc(QuartzJob::getOrderno)); - // 更新序号 - for (int i = 0; i < list.size(); i++) { - QuartzJob quartzJob = list.get(i); - quartzJob.setOrderno(i + 1); - this.updateById(quartzJob); - } - return true; - } - - /********************************** - * 用途说明: 拖动修改定时任务顺序 - * 参数说明 fromID 当前ID toID 到达ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败 - ***********************************/ - @Override - public boolean changeDictOrder(String fromID, String toID) { - QuartzJob fromQuartzJob = - quartzJobMapper.selectById(fromID); - QuartzJob toQuartzJob = quartzJobMapper.selectById(toID); - // 如果数据字典不存在拖动失败 - if (fromQuartzJob == null || toQuartzJob == null) { - return false; - } - Integer fromOrderNo = fromQuartzJob.getOrderno(); - Integer toOrderNo = toQuartzJob.getOrderno(); - // 如果数据字典的顺序号不存在拖动失败 - if (fromOrderNo == null || toOrderNo == null) { - return false; - } - // 将顺序号放入字典对象中 - fromQuartzJob.setOrderno(toOrderNo); - toQuartzJob.setOrderno(fromOrderNo); - // 更改顺序号 - boolean fromBool = this.updateById(fromQuartzJob); - boolean toBool = this.updateById(toQuartzJob); - return fromBool && toBool; - } - - /********************************** - * 用途说明: 执行定时任务 - * 参数说明 id id - * 返回值说明: void - ***********************************/ - @Override - public void execution(QuartzJob quartzJob) { - quartzManage.runJobNow(quartzJob); - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysConfigServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysConfigServiceImpl.java deleted file mode 100644 index da15188..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysConfigServiceImpl.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.yfd.platform.system.service.impl; - - -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.system.domain.SysConfig; -import com.yfd.platform.system.mapper.SysConfigMapper; -import com.yfd.platform.system.service.ISysConfigService; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import javax.sound.sampled.UnsupportedAudioFileException; -import java.io.File; -import java.io.IOException; -import java.util.HashMap; -import java.util.Map; - -/** - *

- * 系统全局配置 服务实现类 - *

- * - * @author zhengsl - * @since 2022-01-19 - */ -@Service -public class SysConfigServiceImpl extends ServiceImpl implements ISysConfigService { - @Resource - private UserServiceImpl currentUser; - - - - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysDictionaryItemsServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysDictionaryItemsServiceImpl.java deleted file mode 100644 index 26a30ab..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysDictionaryItemsServiceImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.system.domain.SysDictionaryItems; -import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; -import com.yfd.platform.system.service.ISysDictionaryItemsService; -import com.yfd.platform.utils.FileUtil; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; - -/** - *

- * 数据字典明细 服务实现类 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -@Service -public class SysDictionaryItemsServiceImpl extends ServiceImpl implements ISysDictionaryItemsService { - - @Resource - private SysDictionaryItemsMapper sysDictionaryItemsMapper; - - /********************************** - * 用途说明: 分页查询字典项信息 - * 参数说明 dictID 字典ID ItemName 字典项名称 pageNum 当前页 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 - ***********************************/ - @Override - public Page getDictItemPage(String dictId, - String itemName, - Page page) { - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); - if (StrUtil.isNotBlank(itemName)) { - queryWrapper.like(SysDictionaryItems::getDictName, itemName); - } - queryWrapper.eq(SysDictionaryItems::getDictId, dictId).orderByAsc(SysDictionaryItems::getOrderNo); - return sysDictionaryItemsMapper.selectPage(page, queryWrapper); - } - - /********************************** - * 用途说明: 增加字典项 - * 参数说明 sysDictionaryItems 字典项信息 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回增加成功或者失败 - ***********************************/ - @Override - public boolean addDictionaryItem(SysDictionaryItems sysDictionaryItems) { - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); - queryWrapper.eq(SysDictionaryItems::getDictId,sysDictionaryItems.getDictId()); - long orderNo = this.count(queryWrapper) + 1L; - // 添加顺序号 - sysDictionaryItems.setOrderNo((int) orderNo); - return this.save(sysDictionaryItems); - } - - /********************************** - * 用途说明: 拖动修改字典项顺序 - * 参数说明 fromID 当前ID toID 到达ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败 - ***********************************/ - @Override - public boolean changeItemOrder(String fromID, String toID) { - SysDictionaryItems fromSysDictionaryItems = - sysDictionaryItemsMapper.selectById(fromID); - SysDictionaryItems toSysDictionaryItems = - sysDictionaryItemsMapper.selectById(toID); - // 如果数据字典项不存在拖动失败 - if (fromSysDictionaryItems == null || toSysDictionaryItems == null) { - return false; - } - Integer fromOrderNo = fromSysDictionaryItems.getOrderNo(); - Integer toOrderNo = toSysDictionaryItems.getOrderNo(); - // 如果数据字典的顺序号不存在拖动失败 - if (fromOrderNo == null || toOrderNo == null) { - return false; - } - // 将顺序号放入字典对象中 - fromSysDictionaryItems.setOrderNo(toOrderNo); - toSysDictionaryItems.setOrderNo(fromOrderNo); - // 更改顺序号 - boolean fromBool = this.updateById(fromSysDictionaryItems); - boolean toBool = this.updateById(toSysDictionaryItems); - return fromBool && toBool; - - } - - /********************************** - * 用途说明: 导出数据字典项数据 - * 参数说明 sysDictionaryItemsList 所需导出的字典项集合 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或失败 - ***********************************/ - @Override - public void exportExcel(List sysDictionaryItems, - HttpServletResponse response) { - try { - List> list = new LinkedList<>(); - for (SysDictionaryItems sysDictionaryItem : sysDictionaryItems) { - Map map = new LinkedHashMap<>(); - map.put("项编号", sysDictionaryItem.getItemCode()); - map.put("项名称", sysDictionaryItem.getDictName()); - map.put("父编码", sysDictionaryItem.getParentCode()); - map.put("备注", sysDictionaryItem.getCustom1()); - list.add(map); - } - FileUtil.downloadExcel(list, response); - } catch (Exception e) { - e.printStackTrace(); - } - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysDictionaryServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysDictionaryServiceImpl.java deleted file mode 100644 index 58508b3..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysDictionaryServiceImpl.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.system.domain.SysDictionary; -import com.yfd.platform.system.domain.SysDictionaryItems; -import com.yfd.platform.system.mapper.SysDictionaryItemsMapper; -import com.yfd.platform.system.mapper.SysDictionaryMapper; -import com.yfd.platform.system.service.ISysDictionaryService; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import jakarta.annotation.Resource; -import java.util.List; - -/** - *

- * 数据字典表 服务实现类 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -@Service -public class SysDictionaryServiceImpl extends ServiceImpl implements ISysDictionaryService { - - @Resource - private SysDictionaryMapper sysDictionaryMapper; - - @Resource - private SysDictionaryItemsMapper sysDictionaryItemsMapper; - - /********************************** - * 用途说明: 获取数据字典列表 - * 参数说明 dictType 字典类型 - * 返回值说明: 返回字典列表集合 - ***********************************/ - @Override - public List getDictList(String dictType) { - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); - queryWrapper.eq(SysDictionary::getDictType, dictType).orderByAsc(SysDictionary::getOrderNo); - return sysDictionaryMapper.selectList(queryWrapper); - } - - /********************************** - * 用途说明: 新增字典 - * 参数说明 sysDictionary 字典对象 - * 返回值说明: 返回增加成功或者失败 - ***********************************/ - @Override - public boolean addDict(SysDictionary sysDictionary) { - //int orderNo = this.count() + 1; - Integer maxNo = - sysDictionaryMapper.selectMaxNo(sysDictionary.getDictType()); - if (maxNo == null) { - maxNo = 0; - } - // 添加顺序号 - sysDictionary.setOrderNo(maxNo + 1); - return this.save(sysDictionary); - } - - /********************************** - * 用途说明: 根据ID删除字典 - * 参数说明 id 字典ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回删除结果成功或者失败 - ***********************************/ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean deleteDictById(String id) { - // 根据字典编码查询字典项中是否关联 - boolean isok=true; - QueryWrapper Wrapper = new QueryWrapper<>(); - Wrapper.eq("dictid", id); - if(sysDictionaryItemsMapper.delete(Wrapper)>0) { - isok=true; - } - return isok&&this.removeById(id); - } - - /********************************** - * 用途说明: 拖动修改字典顺序 - * 参数说明 fromID 当前ID toID 到达ID - * 返回值说明: com.yfd.platform.config.ResponseResult 返回拖动成功或者失败 - ***********************************/ - @Override - public boolean changeDictOrder(String fromID, String toID) { - SysDictionary fromSysDictionary = - sysDictionaryMapper.selectById(fromID); - SysDictionary toSysDictionary = sysDictionaryMapper.selectById(toID); - // 如果数据字典不存在拖动失败 - if (fromSysDictionary == null || toSysDictionary == null) { - return false; - } - Integer fromOrderNo = fromSysDictionary.getOrderNo(); - Integer toOrderNo = toSysDictionary.getOrderNo(); - // 如果数据字典的顺序号不存在拖动失败 - if (fromOrderNo == null || toOrderNo == null) { - return false; - } - // 将顺序号放入字典对象中 - fromSysDictionary.setOrderNo(toOrderNo); - toSysDictionary.setOrderNo(fromOrderNo); - // 更改顺序号 - boolean fromBool = this.updateById(fromSysDictionary); - boolean toBool = this.updateById(toSysDictionary); - return fromBool && toBool; - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysLogServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysLogServiceImpl.java deleted file mode 100644 index ee671bf..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysLogServiceImpl.java +++ /dev/null @@ -1,219 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import cn.hutool.core.date.DateTime; -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.json.JSONUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.annotation.Log; -import com.yfd.platform.system.domain.SysLog; -import com.yfd.platform.system.mapper.SysLogMapper; -import com.yfd.platform.system.mapper.SysUserMapper; -import com.yfd.platform.system.service.ISysLogService; -import com.yfd.platform.utils.FileUtil; -import com.yfd.platform.utils.StringUtils; -import org.aspectj.lang.ProceedingJoinPoint; -import org.aspectj.lang.reflect.MethodSignature; -import org.springframework.stereotype.Service; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; - -import jakarta.annotation.Resource; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.lang.reflect.AnnotatedType; -import java.lang.reflect.Method; -import java.lang.reflect.Parameter; -import java.sql.Timestamp; -import java.text.SimpleDateFormat; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.*; - -/** - *

- * 系统操作日志 服务实现类 - *

- * - * @author TangWei - * @since 2023-03-08 - */ -@Service -public class SysLogServiceImpl extends ServiceImpl implements ISysLogService { - - @Resource - private SysLogMapper sysLogMapper; - - /********************************** - * 用途说明: 分页查询日志信息 - * 参数说明 pageNum(页码数)、pageSize(页大小,如果是固定页大小可不传)、username(用户名)、(optType) - * 操作类型、startDate(开始日期)、endDate(结束日期) - * 返回值说明: com.yfd.platform.config.ResponseResult 返回分页查询结果 - ***********************************/ - @Override - public Page getLogList(String username, String optType, - String startDate, - String endDate, Page page) { - - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - // 没有传username就不按此条件查询 - if (StrUtil.isNotBlank(username)) { - queryWrapper.like(SysLog::getUsername, username); - } - // 没有传optType就不按此条件查询 - if (StrUtil.isNotBlank(optType)) { - queryWrapper.eq(SysLog::getOpttype, optType); - } - DateTime parseStartDate = DateUtil.parse(startDate); - DateTime parseEndDate = DateUtil.parse(endDate); - DateTime dateTime = DateUtil.offsetDay(parseEndDate, 1); - if (parseStartDate != null && parseEndDate != null) { - queryWrapper.ge(SysLog::getLogtime, parseStartDate).lt(SysLog::getLogtime, dateTime); - } - - queryWrapper.orderByDesc(SysLog::getLogtime); - return sysLogMapper.selectPage(page, queryWrapper); - } - - /********************************** - * 用途说明: 导出日志数据 - * 参数说明 sysLogs 所需导出的字典项集合 - * 返回值说明: com.yfd.platform.config.ResponseResult 返回导出成功或者失败 - ***********************************/ - @Override - public void exportExcel(List sysLogs, - HttpServletResponse response) { - try { - List> list = new LinkedList<>(); - for (SysLog sysLog : sysLogs) { - Map map = new LinkedHashMap<>(); - map.put("操作账号", sysLog.getUsercode()); - map.put("用户姓名", sysLog.getUsername()); - map.put("IP地址", sysLog.getRequestip()); - map.put("浏览器", sysLog.getBrowser()); - map.put("日志类型", sysLog.getOpttype()); - map.put("模块名称", sysLog.getModule()); - map.put("日志描述", sysLog.getDescription()); - Timestamp logTime = sysLog.getLogtime(); - String dateTime = ""; - if (logTime != null) { - SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd " + - "HH:mm:ss"); - dateTime = df.format(logTime); - } - - /*String dateTime = ""; - if (logTime != null) { - dateTime = logTime.format(DateTimeFormatter.ofPattern( - "yyyy-MM-dd HH:mm:ss")); - }*/ - - map.put("操作日期", dateTime); - list.add(map); - } - FileUtil.downloadExcel(list, response); - } catch (Exception e) { - e.printStackTrace(); - } - - } - - /********************************** - * 用途说明: 新增日志 - * 参数说明 nickname 用户名 - * 参数说明 username 用户账号 - * 参数说明 browser 浏览器 - * 参数说明 ip 本机Ip地址 - * 参数说明 joinPoint 连接点 - * 参数说明 log 日志信息 - * 返回值说明: void - ***********************************/ - @Override - public void save(String nickname, String username, String browser, - String ip, - ProceedingJoinPoint joinPoint, SysLog log) { - MethodSignature signature = (MethodSignature) joinPoint.getSignature(); - Method method = signature.getMethod(); - Log aopLog = method.getAnnotation(Log.class); - // 方法路径 - String methodName = - joinPoint.getTarget().getClass().getName() + "." + signature.getName() + "()"; - // 描述 - if (log != null) { - log.setDescription(aopLog.value()); - log.setModule(aopLog.module()); - } - assert log != null; - log.setUsercode(username); - log.setRequestip(ip); - log.setMethod(methodName); - log.setUsername(nickname); - log.setParams(getParameter(method, joinPoint.getArgs())); - log.setBrowser(browser); - String operationtype = getOperationtype(signature.getName()); - log.setOpttype(operationtype); - log.setLogtime(new Timestamp(System.currentTimeMillis())); - sysLogMapper.insert(log); - } - - /** - * 根据方法和传入的参数获取请求参数 - */ - private String getParameter(Method method, Object[] args) { - List argList = new ArrayList<>(); - Parameter[] parameters = method.getParameters(); - for (int i = 0; i < parameters.length; i++) { - //将RequestBody注解修饰的参数作为请求参数 - AnnotatedType type = parameters[i].getAnnotatedType(); - - RequestBody requestBody = - parameters[i].getAnnotation(RequestBody.class); - if (requestBody != null) { - argList.add(args[i]); - } - - //将RequestParam注解修饰的参数作为请求参数 - RequestParam requestParam = - parameters[i].getAnnotation(RequestParam.class); - if (requestParam != null) { - Map map = new HashMap<>(); - String key = parameters[i].getName(); - if (!StringUtils.isEmpty(requestParam.value())) { - key = requestParam.value(); - } - map.put(key, args[i]); - argList.add(map); - } - } - if (argList.size() == 0) { - return ""; - } - return argList.size() == 1 ? JSONUtil.toJsonStr(argList.get(0)) : - JSONUtil.toJsonStr(argList); - } - - public static String getOperationtype(String value) { - String type = ""; - if (value.contains("get") || value.contains("select")) { - type = "查询(select)"; - } else if (value.contains("add") || value.contains("insert")) { - type = "添加(insert)"; - } else if (value.contains("update") || value.contains("upd") || value.contains("change") || value.contains("set")) { - type = "修改(update)"; - } else if (value.contains("delete") || value.contains("del")) { - type = "删除(delete)"; - } else if (value.contains("dowload")) { - type = "下载(dowload)"; - } else if (value.contains("import")) { - type = "导入(import)"; - } else if (value.contains("word")) { - type = "word转pdf(wordToPdf)"; - } else { - type = "其他(other)"; - } - return type; - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysMenuServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysMenuServiceImpl.java deleted file mode 100644 index af5dcad..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysMenuServiceImpl.java +++ /dev/null @@ -1,695 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.system.domain.SysMenu; -import com.yfd.platform.system.domain.SysRole; -import com.yfd.platform.system.mapper.SysMenuMapper; -import com.yfd.platform.system.mapper.SysRoleMapper; -import com.yfd.platform.system.service.ISysMenuService; -import com.yfd.platform.utils.FileUtil; -import com.yfd.platform.config.FileSpaceProperties; -import com.yfd.platform.utils.ObjectConverterUtil; -import jakarta.annotation.Resource; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.ResourceUtils; -import org.springframework.web.multipart.MultipartFile; - -import jakarta.annotation.Resource; -import java.io.File; -import java.io.FileNotFoundException; -import java.sql.Timestamp; -import java.text.DecimalFormat; -import java.util.*; -import java.util.stream.Collectors; - -/** - *

- * 菜单及按钮 服务实现类 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -@Service -@Transactional -public class SysMenuServiceImpl extends ServiceImpl implements ISysMenuService { - - @Resource - private SysMenuMapper sysMenuMapper; - - @Resource - private UserServiceImpl currentUser; - - @Resource - private SysRoleMapper sysRoleMapper; - - // 菜单图片路径配置 - @Resource - private FileSpaceProperties fileSpaceProperties; - - /*********************************** - * 用途说明:查询菜单及按钮树状图 - * 参数说明 - * systemcode 系统 - *isdisplay 是否显示 - * 返回值说明: 菜单结构树集合 - ***********************************/ - @Override - public List> getMenuButtonTree(String systemcode, - String name, - String isdisplay) { - List> mapList=null; - List> listMap =new ArrayList<>(); - if(StrUtil.isEmpty(name)){//不带名称查询,返回树结构 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("parentid", "0").eq("systemcode", systemcode).orderByAsc("orderno"); - mapList = this.listMaps(queryWrapper); - listMap.addAll(ObjectConverterUtil.convertMapFieldsToEntityFormat(SysMenu.class, mapList)); - for (int i = 0; i < listMap.size(); i++) { - //查询下一子集 - List> childList = child(listMap.get(i).get( - "id").toString(), systemcode, name, null, null); - listMap.get(i).put("children", childList); //添加新列 子集 - } - }else{ //根据菜单名称查询,直接返回类别 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.like("name", name).eq("systemcode", systemcode).orderByAsc("name"); - mapList = this.listMaps(queryWrapper); - listMap.addAll(ObjectConverterUtil.convertMapFieldsToEntityFormat(SysMenu.class, mapList)); - } - return listMap; - } - - /*********************************** - * 用途说明:获取菜单结构树(不含按钮) - * 参数说明 - * systemcode 系统 - * isdisplay 是否显示 - * 返回值说明: 菜单结构树集合 - ***********************************/ - @Override - public List> getMenuTree(String systemcode, - String name, - String isdisplay) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - if (StrUtil.isNotEmpty(isdisplay)) { - queryWrapper.eq("isdisplay", isdisplay); - } else { - queryWrapper.eq("isdisplay", 1); - } - - //根据系统 ,类型不为2 显示,序号 正序排序 - queryWrapper.eq("parentid", "0").eq("systemcode", systemcode).ne( - "type", "2").orderByAsc("orderno"); - List> listMap = this.listMaps(queryWrapper); - for (int i = 0; i < listMap.size(); i++) { - List> childList = child(listMap.get(i).get( - "id").toString(), systemcode, name, isdisplay, "2");//查询下一子集 - listMap.get(i).put("children", childList); //添加新列 子集 - } - return listMap; - } - - /*********************************** - * 用途说明:查询菜单及按钮树状图 - * 参数说明 - * parentid 上级id - *systemcode 系统 - * isdisplay 是否显示 - * type 按钮 - * 返回值说明: 菜单结构树集合 - ***********************************/ - private List> child(String parentid, - String systemcode, String name, - String isdisplay, String type) { - List> mapList; - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("parentid", parentid).eq("systemcode", systemcode); - //根据上级id 系统 查询 - if (StrUtil.isNotEmpty(type)) { - queryWrapper.ne("type", type); - } - - if (StrUtil.isNotEmpty(name)) { //根据菜单名称查询 - queryWrapper.like("name", name); - } - mapList = this.listMaps(queryWrapper.orderByAsc("orderno")); - List> listMap = ObjectConverterUtil.convertMapFieldsToEntityFormat(SysMenu.class, mapList); - if (!listMap.isEmpty()) { //判断是否存在子集 - for (int i = 0; i < listMap.size(); i++) { //遍历表数据 - List> childList = - child(listMap.get(i).get("id").toString(), systemcode - , name, isdisplay, type); //循环获取下一子集 - listMap.get(i).put("children", childList); //添加新列 子集 - } - } - - return listMap; - } - - /*********************************** - * 用途说明:新增菜单及按钮 - * 参数说明 - * sysMenu 菜单或按钮表对象 - * 返回值说明: 是否添加成功提示 - ***********************************/ - @Override - public boolean addMenu(SysMenu sysMenu) { - String parentId = sysMenu.getParentid(); - QueryWrapper queryWrapper = new QueryWrapper<>(); - //根据上级id 查询到总数 并累加 - long orderno = this.count(queryWrapper.eq("parentid", - parentId)) + 1L; - // 生成排序号 - sysMenu.setOrderno((int) orderno); - // 生成编号 - QueryWrapper queryMaxCode = new QueryWrapper<>(); - queryMaxCode.eq("parentid", parentId); - - // 使用 Oracle 兼容的 NVL 函数处理空值 - List maxList = this.listObjs( - queryMaxCode.select("NVL(MAX(code), '0') as code") - .eq("systemcode", sysMenu.getSystemcode()) - ); - SysMenu parentMenu = sysMenuMapper.selectById(parentId); - // 最大编号转换成int类型 - String maxCode = !maxList.isEmpty() ? maxList.getFirst().toString() : "0"; - int max = ObjectUtil.isEmpty(maxList) ? 0 : - Integer.parseInt(maxCode); - DecimalFormat df; - if ("0".equals(sysMenu.getParentid())) { - df = new DecimalFormat("00"); - } else if (parentMenu.getCode().length() == 2) { - df = new DecimalFormat("0000"); - } else { - df = new DecimalFormat("000000"); - } - //DecimalFormat df = new DecimalFormat("00"); - //int parentCode = Integer.parseInt(parentMenu.getCode()); - String parentCode = ""; - if (parentMenu != null) { - parentCode = parentMenu.getCode(); - } - // 生成的新编号 年月日+4位编号 - String code; - if (max > 0) { - code = df.format(max + 1); - } else { - max = max + 1; - if (StrUtil.isBlank(parentCode)) { - parentCode = "0" + max; - } else { - int i = Integer.parseInt(parentCode); - parentCode = i + "0" + max; - } - - int format = Integer.parseInt(parentCode); - code = df.format(format); - } - - // 判断是否显示字段 是否填写 为空 - if (StrUtil.isEmpty(sysMenu.getIsdisplay())) { - // 默认设置成 1 显示 - sysMenu.setIsdisplay("1"); - } - // 判断是否填写父级id 为空 默认设置成 0 - if (StrUtil.isEmpty(sysMenu.getParentid())) { - sysMenu.setParentid("0"); - } - // 添加编号 - sysMenu.setCode(code); - // 添加排序号 - sysMenu.setOrderno((int) orderno); - // 添加最近修改人 - sysMenu.setLastmodifier(currentUser.getUsername()); - // 添加最近修改时间 - sysMenu.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - return this.save(sysMenu); - } - - /*********************************** - * 用途说明:上传单个图标 - * 参数说明 - * id 上传图标id - * icon 图标 - * 返回值说明: 是否上传成功 - ***********************************/ - @Override - public boolean uploadIcon(String id, MultipartFile icon) { - //根据id查询 - SysMenu sysMenu = this.getById(id); - //图片路径 - String iconPath = fileSpaceProperties.getSystem() + "menu" + File.separator; - String iconname = - IdUtil.fastSimpleUUID() + "." + FileUtil.getExtensionName(icon.getOriginalFilename()); - //上传图标并获取图标名称 (图片改为png格式) - String filename = - FileUtil.upload(icon, iconPath, iconname).getName(); - //更新图标名称 - sysMenu.setIcon(filename); - //添加最近修改人 - sysMenu.setLastmodifier(currentUser.getUsername()); - //添加最近修改时间 - sysMenu.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - //更新数据 - boolean isOk = this.updateById(sysMenu); - return isOk; - } - - /*********************************** - * 用途说明:根据id删除单个图标 - * 参数说明 - * id 删除图标id - * icon 图标名称 - * 返回值说明: 是否删除成功 - ***********************************/ - @Override - public boolean deleteIcon(String id) { - //根据id查询 - SysMenu sysMenu = this.getById(id); - //图片路径 - String iconname = - System.getProperty("user.dir") + "\\src\\main" + - "\\resources\\static\\icon" + File.separator + sysMenu.getIcon(); - //更新图标名称 - sysMenu.setIcon(""); - //添加最近修改人 - sysMenu.setLastmodifier(currentUser.getUsername()); - //添加最近修改时间 - sysMenu.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - //更新数据 - boolean isOk = this.updateById(sysMenu); - //更新成功 删除图片 - if (isOk == true) { - FileUtil.del(iconname); - } - return isOk; - } - - /*********************************** - * 用途说明:菜单及按钮序号排序 - * 参数说明 - * parentid 上级id - * id - * orderno 更改后序号 - * 返回值说明: 是否更新成功 - ***********************************/ - @Override - public boolean moveOrderno(String parentid, String id, int orderno) { - boolean ok = true; - SysMenu sysMenu = this.getById(id); //根据id查询原顺序号 - if (sysMenu.getOrderno() > orderno) { - ok = sysMenuMapper.upMoveOrderno(parentid, sysMenu.getOrderno(), - orderno); //根据 父级id 小于原序号 大于等于更改序号 - } else { - ok = sysMenuMapper.downMoveOrderno(parentid, sysMenu.getOrderno() - , orderno); //根据 父级id 大于原序号 小于等于更改序号 - } - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - ok = ok && this.update(updateWrapper.eq("id", id).set("orderno", - orderno)); //根据 id修改序号 - return ok; - } - - /*********************************** - * 用途说明:根据id删除菜单或按钮 - * 参数说明 - * id 删除列的id - * 返回值说明: 是否删除成功 - ***********************************/ - @Override - public boolean deleteById(String id) { - //根据id查询 - SysMenu sysMenu = this.getById(id); - //图片路径 - String iconname = - fileSpaceProperties.getSystem() + "menu" + File.separator + sysMenu.getIcon(); - //删除图标 - new File(iconname).delete(); - //根据id删除 - boolean isOk = this.removeById(id); - //删除成功同步更新表数据 - if (isOk) { - //1 创建list集合,用于封装所有删除目录或菜单id值 - List idList = new ArrayList<>(); - this.selectPermissionChildById(id, idList); - if (idList.size() > 0) { - sysMenuMapper.deleteBatchIds(idList); - } - QueryWrapper queryWrapper = new QueryWrapper<>(); - //根据上级id 查询 根据 orderno 正序排序 - queryWrapper.eq("parentid", sysMenu.getParentid()).orderByAsc( - "orderno"); - List list = this.list(queryWrapper); - for (int i = 0; i < list.size(); i++) { - SysMenu menu = list.get(i); - //更新序列号 - menu.setOrderno(i + 1); - } - //更新表数据 - this.updateBatchById(list); - } - return isOk; - } - - //2 根据当前菜单id,查询菜单里面子菜单id,封装到list集合 - private void selectPermissionChildById(String id, List idList) { - //查询菜单里面子菜单id - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("parentid", id); - wrapper.select("id"); - List childIdList = baseMapper.selectList(wrapper); - //把childIdList里面菜单id值获取出来,封装idList里面,做递归查询 - childIdList.stream().forEach(item -> { - //封装idList里面 - idList.add(item.getId()); - //递归查询 - this.selectPermissionChildById(item.getId(), idList); - }); - } - - /********************************** - * 用途说明: 调换菜单或按钮的位置 - * 参数说明 upperId 选中的菜单Id - * 参数说明 belowId 切换的菜单Id - * 返回值说明: boolean - ***********************************/ - @Override - @Transactional - public boolean changeOderNoById(String fromId, String toId) { - SysMenu fromSysMenu = this.getById(fromId); - SysMenu toSysMenu = this.getById(toId); - // 如果菜单或按钮不存在拖动失败 - if (fromSysMenu == null || toSysMenu == null) { - return false; - } - Integer fromOrderNo = fromSysMenu.getOrderno(); - Integer toOrderNo = toSysMenu.getOrderno(); - // 如果菜单或按钮的顺序号不存在拖动失败 - if (fromOrderNo == null || toOrderNo == null) { - return false; - } - fromSysMenu.setOrderno(toOrderNo); - toSysMenu.setOrderno(fromOrderNo); - boolean fromBool = this.updateById(fromSysMenu); - boolean toBool = this.updateById(toSysMenu); - return fromBool && toBool; - } - - /********************************** - * 用途说明: 根据用户id获取菜单树 - * 参数说明 id 用户id - * 返回值说明: 返回菜单树 - ***********************************/ - @Override - public List> getMenuTree(String id) { - // 根据id获取菜单 - //List sysMenus = sysMenuMapper.selectMenuByUserId(id); - List sysMenuList; - if (StrUtil.isBlank(id)) { - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); - sysMenuList = this.list(queryWrapper.eq(SysMenu::getIsdisplay, "1").ne(SysMenu::getType, "2").eq(SysMenu::getSystemcode, "1").orderByAsc(SysMenu::getOrderno)); - } else { - sysMenuList = sysMenuMapper.selectMenuByUserId(id); - } - // 将 SysMenu 转换为 Map 并构建树 - List> list = sysMenuList.stream() - .map(menu -> { - Map map = new HashMap<>(); - map.put("id", menu.getId()); - map.put("parentid", menu.getParentid()); - map.put("name", menu.getName()); - map.put("opturl", menu.getOpturl()); - map.put("icon", menu.getIcon()); - map.put("type", menu.getType()); - map.put("systemcode", menu.getSystemcode()); - map.put("isdisplay", menu.getIsdisplay()); - map.put("orderno", menu.getOrderno()); - return map; - }) - .collect(Collectors.toList()); - - // 将菜单转换成树 - List> sysMenus = buildTreeLeft(list); - return sysMenus; - } - - /*********************************** - * 用途说明:权限分配 - * 参数说明 - * systemcode 系统 - * name 名称 - * isdisplay 是否显示 - * 返回值说明: 菜单结构树集合 - ***********************************/ - @Override - public List> permissionAssignment(String code,String roleId) { - -// String code = sysMenuMapper.getSystemCodeById(roleId); -// if (code == null) { -// code = "1"; -// } - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysMenu::getSystemcode, code).select(SysMenu::getId, - SysMenu::getParentid, SysMenu::getName).orderByAsc - (SysMenu::getOrderno); - List> mapList = - sysMenuMapper.selectMaps(queryWrapper); - List> listAll = ObjectConverterUtil.convertMapFieldsToEntityFormat(SysMenu.class, mapList); - List listRole = - sysMenuMapper.selectMenuByRoleId(roleId); - for (Map map : listAll) { - String id = (String) map.get("id"); - if (listRole.contains(id)) { - map.put("checkinfo", true); - } else { - map.put("checkinfo", false); - } - - } - List> listTree = buildTrees(listAll); - return listTree; - } - - // 另一种方法 - /*public List> permissionAssignment(String roleId) { - - String code = sysMenuMapper.getSystemCodeById(roleId); - if (code == null) { - code = "1"; - } - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.eq(SysMenu::getSystemcode, code).select(SysMenu::getId, - SysMenu::getParentid, SysMenu::getName).orderByAsc - (SysMenu::getOrderno); - List> listAll = - sysMenuMapper.selectMaps(queryWrapper); - *//*List listRole = - sysMenuMapper.selectMenuByRoleId(roleId);*//* - SysRole sysRole = sysRoleMapper.selectById(roleId); - String optscope = sysRole.getOptscope(); - // 将当前角色所对应权限id拆分 - String[] split = optscope.split(","); - List listRole = Arrays.asList(split); - for (Map map : listAll) { - String id = (String) map.get("id"); - if (listRole.contains(id)) { - map.put("checkinfo", true); - } else { - map.put("checkinfo", false); - } - - } - List> listTree = buildTrees(listAll); - return listTree; - }*/ - - /*********************************** - * 用途说明:上传单个图标 - * 参数说明 - * icon 图标 - * 返回值说明: 是否上传成功 - ***********************************/ - @Override - public String uploadIcon(MultipartFile icon) throws FileNotFoundException { - - String path = System.getProperty("user.dir") + "\\src\\main" + - "\\resources\\"; - //图片路径 - String iconPath = path + "static\\icon" + File.separator; - String iconname = - IdUtil.fastSimpleUUID() + "." + FileUtil.getExtensionName(icon.getOriginalFilename()); - //上传图标并获取图标名称 (图片改为png格式) - String filename = - FileUtil.upload(icon, iconPath, iconname).getName(); - return filename; - } - - /** - * 菜单集合递归生成树状菜单(List) - * - * @param sysMenus 菜单对象 - * @return - */ - /* public List buildTree(List sysMenus) { - List resultMenuList = new ArrayList<>(); - for (SysMenu sysMenu : sysMenus) { - - for (SysMenu menu : sysMenus) { - if (menu.getParentid().equals(sysMenu.getId())) { - sysMenu.getChildren().add(menu); - } - } - if ("0".equals(sysMenu.getParentid())) { - resultMenuList.add(sysMenu); - } - } - return resultMenuList; - }*/ - - /** - * 菜单集合递归生成树状菜单(Map)(暂不使用该方法) - * - * @param sysMenus 菜单对象 - * @return - */ - public List> buildTree(List> sysMenus) { - List> resultMenuList = new ArrayList<>(); - for (Map sysMenu : sysMenus) { - - List> childrenList = new ArrayList<>(); - for (Map menu : sysMenus) { - if (menu.get("parentid").equals(sysMenu.get("id"))) { - childrenList.add(menu); - } - } - if ("0".equals(sysMenu.get("parentid"))) { - if (childrenList.size() > 0) { - sysMenu.put("children", childrenList); - } - resultMenuList.add(sysMenu); - } - } - return resultMenuList; - } - - /********************************** - * 用途说明: 左侧菜单树构建 - * 参数说明 sysMenus - * 返回值说明: java.util.List> - ***********************************/ - public List> buildTreeLeft(List> sysMenus) { - List> resultMenuList = new ArrayList<>(); - for (Map sysMenu : sysMenus) { - if ("0".equals(sysMenu.get("parentid"))) { - resultMenuList.add(sysMenu); - } - } - for (Map sysMenu : resultMenuList) { - List> menus = iterateMenusLeft(sysMenus, - (String) sysMenu.get("id")); - if (menus.size() > 0) { - sysMenu.put("children", menus); - } - } - return resultMenuList; - } - - /** - * 左侧多级菜单查询方法 - * - * @param menuVoList 不包含最高层次菜单的菜单集合 - * @param pid 父类id - * @return - */ - public List> iterateMenusLeft(List> menuVoList, String pid) { - List> result = new ArrayList<>(); - for (Map menu : menuVoList) { - //获取菜单的id - String menuid = (String) menu.get("id"); - //获取菜单的父id - String parentid = (String) menu.get("parentid"); - if (StrUtil.isNotBlank(parentid)) { - if (parentid.equals(pid)) { - //递归查询当前子菜单的子菜单 - List> iterateMenu = - iterateMenus(menuVoList, menuid); - if (iterateMenu.size() > 0) { - menu.put("children", iterateMenu); - } - result.add(menu); - } - } - } - return result; - } - - /********************************** - * 用途说明: 生成权菜单权限树 - * 参数说明 sysMenus - * 返回值说明: java.util.List> - ***********************************/ - public List> buildTrees(List> sysMenus) { - List> resultMenuList = new ArrayList<>(); - for (Map sysMenu : sysMenus) { - if ("0".equals(sysMenu.get("parentid"))) { - resultMenuList.add(sysMenu); - } - } - for (Map sysMenu : resultMenuList) { - List> menus = iterateMenus(sysMenus, - (String) sysMenu.get("id")); - for (Map menu : menus) { - if (!(boolean) menu.get("checkinfo")) { - sysMenu.put("checkinfo", false); - break; - } - } - sysMenu.put("children", menus); - } - return resultMenuList; - } - - /** - * 多级菜单查询方法 - * - * @param menuVoList 不包含最高层次菜单的菜单集合 - * @param pid 父类id - * @return - */ - public List> iterateMenus(List> menuVoList, String pid) { - List> result = new ArrayList<>(); - for (Map menu : menuVoList) { - //获取菜单的id - String menuid = (String) menu.get("id"); - //获取菜单的父id - String parentid = (String) menu.get("parentid"); - if (StrUtil.isNotBlank(parentid)) { - if (parentid.equals(pid)) { - //递归查询当前子菜单的子菜单 - List> iterateMenu = - iterateMenus(menuVoList, menuid); - for (Map map : iterateMenu) { - boolean checkinfo = (boolean) map.get("checkinfo"); - if (!checkinfo) { - menu.put("checkinfo", false); - } - } - menu.put("children", iterateMenu); - result.add(menu); - } - } - } - return result; - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java deleted file mode 100644 index 4bc9925..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysOrganizationServiceImpl.java +++ /dev/null @@ -1,363 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.SysOrganization; -import com.yfd.platform.system.domain.SysRole; -import com.yfd.platform.system.domain.SysUser; -import com.yfd.platform.system.mapper.SysOrganizationMapper; -import com.yfd.platform.system.mapper.SysRoleMapper; -import com.yfd.platform.system.service.ISysOrganizationService; -import com.yfd.platform.system.service.IUserService; -import com.yfd.platform.utils.ObjectConverterUtil; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import java.sql.Timestamp; -import java.text.DecimalFormat; -import java.util.*; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -/** - *

- * 系统组织框架 服务实现类 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -@Service -public class SysOrganizationServiceImpl extends ServiceImpl implements ISysOrganizationService { - - @Resource - private UserServiceImpl currentUser; - - @Resource - private IUserService userService; - - @Resource - private SysRoleMapper sysRoleMapper; - - @Resource - private SysOrganizationMapper sysOrganizationMapper; - - /*********************************** - * 用途说明:获取组织结构树 - * 参数说明 - *parentid 上级id - * params 名称(根据名称查询二级) - * 返回值说明: 组织树集合 - ***********************************/ - @Override - public List> getOrgTree(String parentid, - String params) { - List orgList = new ArrayList<>(); - QueryWrapper queryWrapper = new QueryWrapper<>(); - //根据父级id查询 - queryWrapper.eq("parentid", parentid); - if (StrUtil.isNotEmpty(params)) { - queryWrapper.like("orgname", params); // 根据 部门名称 - } - SysUser userInfo = userService.getUserInfo(); - if (userInfo.getUsertype() != 0) { - List roleByUserId = - sysRoleMapper.getRoleByUserId(userInfo.getId()); - List ids = new ArrayList<>(); - // 循环当前角色 - for (SysRole sysRole : roleByUserId) { - // 获取角色的组织Id - String orgscope = sysRole.getOrgscope(); - if (StrUtil.isBlank(orgscope)) { - continue; - } - // 拆分组织Id - String[] split = orgscope.split(","); - List stringList = Arrays.asList(split); - Set set = new HashSet<>(); - if (stringList.size() > 0) { - List list = - sysOrganizationMapper.selectList(new LambdaQueryWrapper().in(SysOrganization::getId, stringList)); - list.forEach(l -> set.add(l.getParentid())); - } - ids.addAll(stringList); - ids.addAll(set); - } - queryWrapper.in("id", ids); - } - orgList = this.list(queryWrapper.orderByAsc("orgcode")); - // 将实体对象转换为 Map,确保字段名与实体类一致 - // 将实体对象转换为 Map,确保字段名与实体类一致 - List> listMap = orgList.stream().map(org -> { - Map map = new HashMap<>(); - map.put("id", org.getId()); - map.put("orgtype", org.getOrgtype()); - map.put("orgcode", org.getOrgcode()); - map.put("orgname", org.getOrgname()); - map.put("parentid", org.getParentid()); - map.put("manager", org.getManager()); - map.put("isvaild", org.getIsvaild()); - map.put("description", org.getDescription()); - map.put("lastmodifier", org.getLastmodifier()); - map.put("lastmodifydate", org.getLastmodifydate()); - map.put("custom1", org.getCustom1()); - map.put("custom2", org.getCustom2()); - map.put("custom3", org.getCustom3()); - return map; - }).collect(Collectors.toList()); - for (Map map : listMap) { - List> childList = child(map.get( - "id").toString());//查询下一子集 - map.put("childList", childList); //添加新列 子集 - } - return listMap; - } - - /*********************************** - * 用途说明:获取组织结构树 - * 参数说明 - *parentid 上级id - * params (根据参数查询 组织名称 负责人 描述) - * 返回值说明: 组织树集合 - ***********************************/ - private List> child(String parentid) { - List> listMap = new ArrayList<>(); - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("parentid", parentid); //根据上级id 查询 - listMap = this.listMaps(queryWrapper.orderByAsc("orgcode")); - - if (!listMap.isEmpty()) { - List> mapList = ObjectConverterUtil.convertMapFieldsToEntityFormat(SysOrganization.class, listMap);//判断是否存在子集 - for (int i = 0; i < mapList.size(); i++) { //遍历表数据 - List> childList = - child(mapList.get(i).get("id").toString()); //循环获取下一子集 - mapList.get(i).put("childList", childList); //添加新列 子集 - } - return mapList; - } - return listMap; - } - - /*********************************** - * 用途说明:新增系统组织框架 - * 参数说明 - * sysOrganization 系统组织框架对象 - * 返回值说明: 是否新增成功 - ***********************************/ - @Override - public boolean addOrg(SysOrganization sysOrganization) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - SysOrganization parent = null; - int codeMax = 0; - //查询最大的编号 判断是否存在父级id 有值 根据父级id查询 否则 根据父级id为0 查询 - queryWrapper.select("max(orgcode)"); - if (StrUtil.isNotEmpty(sysOrganization.getParentid())) { - //根据父级id查询父级信息 - parent = this.getById(sysOrganization.getParentid()); - queryWrapper.eq("parentid", sysOrganization.getParentid()); - } else { - //默认 填写父级id为0 - sysOrganization.setParentid("0"); - queryWrapper.eq("parentid", "0"); - } - List max = this.listObjs(queryWrapper); - //判断查询是否存在 存在转换成 int 类型并给 codeMax 替换值 - if (!max.isEmpty() && max.getFirst() != null) { - String maxValue = max.getFirst().toString(); - if (maxValue.length() >= 2) { - codeMax = Integer.parseInt(maxValue.substring(maxValue.length() - 2)); - } - } - //2位数字编号 - DecimalFormat df = new DecimalFormat("00"); - //编号 - String code = df.format(codeMax + 1); - //查询到父级不为空 重新赋值 父级编号+新的序号 - if (parent != null) { - code = parent.getOrgcode() + df.format(codeMax + 1); - } - //判断是否是否填写 有效 否则默认为 1 - if (StrUtil.isEmpty(sysOrganization.getIsvaild())) { - sysOrganization.setIsvaild("1"); - } - //填写 编号 - sysOrganization.setOrgcode(code); - //填写 当前用户名称 - sysOrganization.setLastmodifier(currentUser.getUsername()); - //填写 当前日期 - sysOrganization.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - return this.save(sysOrganization); - } - - /*********************************** - * 用途说明:根据企业ID查询组织详情 - * 参数说明 - * id 企业id - * 返回值说明: 系统组织框架对象 - ***********************************/ - @Override - public List getOrganizationById(String id, - String orgName) { - - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); - SysUser userInfo = userService.getUserInfo(); - if (userInfo.getUsertype() != 0) { - List roleByUserId = - sysRoleMapper.getRoleByUserId(userInfo.getId()); - List ids = new ArrayList<>(); - // 循环当前角色 - for (SysRole sysRole : roleByUserId) { - // 获取角色的组织Id - String orgscope = sysRole.getOrgscope(); - if (StrUtil.isBlank(orgscope)) { - continue; - } - // 拆分组织Id - String[] split = orgscope.split(","); - List stringList = Arrays.asList(split); - ids.addAll(stringList); - } - if (ObjectUtil.isNotEmpty(ids)) { - queryWrapper.in(SysOrganization::getId, ids); - } - - } - if (StrUtil.isNotBlank(orgName)) { - queryWrapper.like(SysOrganization::getOrgname, orgName); - } - queryWrapper.eq(SysOrganization::getParentid, id).orderByDesc(SysOrganization::getOrgcode); - return this.list(queryWrapper); - } - - /*********************************** - * 用途说明:获取组织范围树结构 - * 参数说明 - *parentid 上级id - * params 名称(根据名称查询二级) - * 返回值说明: 组织树集合 - ***********************************/ - @Override - public List> getOrgScopeTree(String roleId) { - LambdaQueryWrapper queryWrapper = - new LambdaQueryWrapper<>(); - queryWrapper.eq(SysOrganization::getIsvaild, '1'); - queryWrapper.orderByAsc(SysOrganization::getOrgcode); - List> listMaps = this.listMaps(queryWrapper); - // 获取当前角色 - SysRole sysRole = sysRoleMapper.selectById(roleId); - String orgscope = sysRole.getOrgscope(); - List ids = new ArrayList<>(); - if (StrUtil.isNotBlank(orgscope)) { - String[] split = orgscope.split(","); - ids = Arrays.asList(split); - } - - for (Map map : listMaps) { - String id = (String) map.get("id"); - if (ids.contains(id)) { - map.put("checkinfo", true); - } else { - map.put("checkinfo", false); - } - map.put("bool", true); - } - // 生成组织树 - List> listMap = buildTrees(listMaps); - return listMap; - } - - /********************************** - * 用途说明: 修改角色组织范围 - * 参数说明 roleId 角色id - * 参数说明 orgscope 组织id集合 - * 返回值说明: boolean 是否修改成功 - ***********************************/ - @Override - public boolean updateOrgScopeByRoleId(String roleId, String orgscope) { - SysRole sysRole = new SysRole(); - sysRole.setId(roleId); - sysRole.setOrgscope(orgscope); - int i = sysRoleMapper.updateById(sysRole); - if (i > 0) { - return true; - } else { - return false; - } - - } - - /********************************** - * 用途说明: 生成组织范围树 - * 参数说明 sysMenus - * 返回值说明: java.util.List> - ***********************************/ - public List> buildTrees(List> sysMenus) { - List> resultMenuList = new ArrayList<>(); - // 获取父节点 - for (Map sysMenu : sysMenus) { - if ("0".equals(sysMenu.get("parentid"))) { - resultMenuList.add(sysMenu); - } - } - // 寻找子节点 - for (Map sysMenu : resultMenuList) { - sysMenu.put("checkinfo", true); - List> children = new ArrayList<>(); - List array = new ArrayList<>(); - for (Map menu : sysMenus) { - String id = (String) sysMenu.get("id"); - String parentid = (String) menu.get("parentid"); - if (id.equals(parentid)) { - // 如果存在一个子节点没有被选中,父节点则不是全选状态 - if (!(boolean) menu.get("checkinfo")) { - sysMenu.put("checkinfo", false); - } else { - // 将处于选中状态的子节点加入到数组中 - array.add((String) menu.get("orgname")); - } - children.add(menu); - } - } - // 所有子节点加入父节点 - sysMenu.put("children", children); - sysMenu.put("array", array); - } - return resultMenuList; - } - - /** - * 组织集合递归生成树状菜单(Map) - * - * @param sysOrgList 组织集合 - * @return - */ - public List> buildTree(List> sysOrgList) { - List> resultOrgList = new ArrayList<>(); - for (Map sysOrg : sysOrgList) { - List> childrenList = new ArrayList<>(); - List array = new ArrayList<>(); - for (Map org : sysOrgList) { - if (org.get("parentid").equals(sysOrg.get("id"))) { - if (!(boolean) org.get("checkinfo")) { - sysOrg.put("checkinfo", false); - } - array.add((String) org.get("orgname")); - childrenList.add(org); - } - } - if ("0".equals(sysOrg.get("parentid"))) { - if (childrenList.size() > 0) { - sysOrg.put("children", childrenList); - } - resultOrgList.add(sysOrg); - } - sysOrg.put("array", array); - } - return resultOrgList; - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/SysRoleServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/SysRoleServiceImpl.java deleted file mode 100644 index f06dbd8..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/SysRoleServiceImpl.java +++ /dev/null @@ -1,174 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import cn.hutool.core.util.IdUtil; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.SysRole; -import com.yfd.platform.system.mapper.SysRoleMapper; -import com.yfd.platform.system.service.ISysRoleService; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import jakarta.annotation.Resource; -import java.sql.Timestamp; -import java.text.DecimalFormat; -import java.util.List; -import java.util.Map; - -/** - *

- * 系统角色 服务实现类 - *

- * - * @author zhengsl - * @since 2021-12-15 - */ -@Service -@Transactional -public class SysRoleServiceImpl extends ServiceImpl implements ISysRoleService { - - @Resource - private SysRoleMapper roleMapper; - - @Resource - private UserServiceImpl currentuser; - - /*********************************** - * 用途说明:新增角色 - * 参数说明 - * sysRole 新增角色信息 - * 返回值说明: 是否新增成功 - ***********************************/ - @Override - public boolean addRole(SysRole sysRole) { - //生成用户编号 - int codeMax = 0; - DecimalFormat df = new DecimalFormat("000");//四位数字编号 - QueryWrapper queryWrapper = new QueryWrapper<>(); - List max = this.listObjs(queryWrapper.select("MAX(rolecode) " + - "rolecode"));// 查询最大的编号 - // 存在转换成 int 类型并给 codeMax 替换值 - if (!max.isEmpty() && max.getFirst() != null) { - try { - codeMax = Integer.parseInt(max.getFirst().toString()); - } catch (NumberFormatException e) { - // 如果转换失败,保持默认值 0 - e.printStackTrace(); - } - } - // 存在转换成int类型并给codeMax替换值 - String code = df.format(codeMax + 1); // 最大编号累加 - - sysRole.setRolecode(code); //添加角色编号 - if (StringUtils.isEmpty(sysRole.getIsvaild())) { - sysRole.setIsvaild("1"); //判断是否填写有效性 默认为 1 是 - } - sysRole.setLastmodifier(currentuser.getUsername()); //添加最近修改者 - sysRole.setLastmodifydate(new Timestamp(System.currentTimeMillis())); //添加最近修改时间 - return this.save(sysRole); - } - - /*********************************** - * 用途说明:删除角色用户(admin除外) - * 参数说明 - * id 系统角色用户对照表id - * 返回值说明: 是否新增成功 - ***********************************/ - @Override - public boolean deleteRoleUsers(String roleid, String urserids) { - boolean ok = true; - //得到单个用户id - String[] temp = urserids.split(","); - for (String userid : temp) { - //根据角色id、用户id删除 (登录账号admin除外) - ok = ok && roleMapper.deleteRoleUsers(roleid, userid); - - } - return ok; - } - - /*********************************** - * 用途说明:根据id删除角色 //待修改 - * 参数说明 - *id 角色id - * 返回值说明: 是否删除成功 - ***********************************/ - @Override - public void deleteById(String id) { - String[] ids = id.split(","); - for (String roleId : ids) { - //根据id删除 角色 - boolean isOk = this.removeById(roleId); - if (!isOk) { - continue; - } - roleMapper.deleteRoleMenus(roleId); - roleMapper.deleteRoleUser(roleId); - } - } - /* 原逻辑 - @Override - public boolean deleteById(String id) { - //根据角色id查询 所关联的用户 - List> isRoleUsersByroleid = - roleMapper.isRoleUsersByroleid(id); - //判断是否关联用户 - if (isRoleUsersByroleid.size() > 0) { - return false; - } - //根据id删除 角色 - boolean isOk = this.removeById(id); - if (isOk) { - return true; - } - return false; - }*/ - - /*********************************** - * 用途说明:查询已分配的用户 - * 参数说明 - *orgid 所属组织 - *username 用户名称 - *status 状态 - *level 角色级别 - * rolename 角色名称 - * isvaild 角色是否有效 - * 返回值说明: 系统用户角色数据集合 - ***********************************/ - @Override - public List listRoleUsers(String orgid, String username, - String status, String level, - String rolename, String isvaild) { - return roleMapper.listRoleUsers(orgid, username, status, level, - rolename, isvaild); - } - - /*********************************** - * 用途说明:角色分配权限 - * 参数说明 - * id 角色id - * menuIds 权限id字符串 - * 返回值说明: 是否分配成功 - ***********************************/ - @Override - @Transactional(rollbackFor = Exception.class) - public boolean setMenuById(String id, String menuIds) { - // 删除角色所对应的权限 - roleMapper.deleteRoleMenus(id); - // 重新赋予权限 - String[] ids = menuIds.split(","); - for (String menuId : ids) { - String uuid = IdUtil.fastSimpleUUID(); - roleMapper.addRoleMenu(uuid, id, menuId); - } - return true; - } - - @Override - public List selectRoleList(String rolename) { - return roleMapper.selectRoleList(rolename); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java deleted file mode 100644 index dc28501..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserDetailsServiceImpl.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import cn.hutool.core.util.ObjectUtil; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.yfd.platform.datasource.DataSource; -import com.yfd.platform.system.domain.LoginUser; -import com.yfd.platform.system.domain.SysUser; -import com.yfd.platform.system.mapper.SysMenuMapper; -import com.yfd.platform.system.service.IUserService; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; - -import jakarta.annotation.Resource; -import java.util.List; - -/** - *

- * 用户服务实现类 继承UserDetailsService 实现接口 - *

- * - * @author zhengsl - * @since 2021-10-27 - */ -@Service -public class UserDetailsServiceImpl implements UserDetailsService { - - @Resource - private IUserService userService; - - @Resource - private SysMenuMapper sysMenuMapper; - - @Override - @DataSource(name = "master") - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - //根据用户名称查询用户信息 - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("username", username); - SysUser user = userService.getOne(queryWrapper); - if (ObjectUtil.isEmpty(user)) { - throw new RuntimeException("用户账号不存在!"); - } - //Todo 根据用户查询权限信息 添加到LoginUser中 - List permissions = - sysMenuMapper.selectPermsByUserId(user.getId()); - - //封装成UserDetails对象返回 - return new LoginUser(user,permissions); - } -} diff --git a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java b/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java deleted file mode 100644 index 7e483f1..0000000 --- a/backend/src/main/java/com/yfd/platform/system/service/impl/UserServiceImpl.java +++ /dev/null @@ -1,579 +0,0 @@ -package com.yfd.platform.system.service.impl; - -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import com.yfd.platform.config.FileProperties; -import com.yfd.platform.config.ResponseResult; -import com.yfd.platform.system.domain.LoginUser; -import com.yfd.platform.system.domain.SysOrganization; -import com.yfd.platform.system.domain.SysRole; -import com.yfd.platform.system.domain.SysUser; -import com.yfd.platform.system.mapper.SysOrganizationMapper; -import com.yfd.platform.system.mapper.SysRoleMapper; -import com.yfd.platform.system.mapper.SysUserMapper; -import com.yfd.platform.system.service.IUserService; -import com.yfd.platform.utils.FileUtil; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import com.yfd.platform.config.FileSpaceProperties; -import jakarta.annotation.Resource; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.multipart.MultipartFile; - -import jakarta.annotation.Resource; -import jakarta.validation.constraints.NotBlank; -import java.io.File; -import java.sql.Timestamp; -import java.util.*; -import java.util.stream.Collectors; - -/** - *

- * 用户服务实现类 - *

- * - * @author zhengsl - * @since 2021-10-27 - */ -@Service -@RequiredArgsConstructor -public class UserServiceImpl extends ServiceImpl implements IUserService { - - @Resource - private SysUserMapper sysUserMapper; - - @Resource - private SysRoleMapper sysRoleMapper; - - @Resource - private PasswordEncoder passwordEncoder; - /** - * 文件空间配置 - */ - @Resource - private FileSpaceProperties fileSpaceProperties; - - /********************************** - * 用途说明:获取当前用户账号及名称 - * 参数说明 - * 返回值说明: 系统管理员[admin] - ***********************************/ - @Override - public String getUsername() { - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - String acountname = - loginuser.getUser().getNickname(); - return acountname; - //return "admin"; - } - - @Override - public Map getNameInfo() { - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - String nickname = loginuser.getUser().getNickname(); - String username = loginuser.getUser().getUsername(); - Map map = new HashMap<>(); - map.put("nickname", nickname); - map.put("username", username); - return map; - } - - @Override - public SysUser getUserInfo() { - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - return loginuser.getUser(); - } - - @Override - public ResponseResult getLoginUserInfo() { - UsernamePasswordAuthenticationToken authentication = - (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication(); - LoginUser loginuser = (LoginUser) authentication.getPrincipal(); - SysUser user = loginuser.getUser(); - //根据用户ID获取组织 - Map userInfo = - sysUserMapper.getOrganizationByid(user.getId()); - - // 使用 MyBatis 方式查询用户角色(Oracle 兼容) - List roles = sysRoleMapper.getRoleByUserId(user.getId()); - List collect = - roles.stream().map(SysRole::getRolename).collect(Collectors.toList()); - ResponseResult responseResult = new ResponseResult(); - responseResult.put("userInfo", userInfo); - responseResult.put("roles", collect); - responseResult.put("permissions", loginuser.getPermissions()); - return responseResult; - } - - /*********************************** - * 用途说明:新增用户 - * 参数说明 - *sysUser 新增用户对象 - * id 创建者id - * roleId 角色id - * 返回值说明: 提示字符串 - ************************************/ - @Override - public Map addUser(SysUser sysUser, String roleids) { - //返回信息 - Map result = new HashMap<>(); - sysUser.setId(IdUtil.fastSimpleUUID()); - //普通用户 - sysUser.setUsertype(1); - BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); - //设置缺省密码 - String cryptPassword = passwordEncoder.encode("123456"); - sysUser.setPassword(cryptPassword); - sysUser.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - sysUser.setLastmodifier(getUsername()); - //账号有效 - sysUser.setStatus(1); - //判断注册的登录账号是否存在 - if (isExistAccount(sysUser.getUsername())) { - //新增用户 - boolean ok = this.save(sysUser); - //新增用户分配权限 - if (StrUtil.isNotEmpty(roleids)) { - String[] roles = roleids.split(","); - for (String roleid : roles) { - //系统生成id - String id = IdUtil.fastSimpleUUID(); - //新增sys_role_users表数据 - ok = ok && sysUserMapper.addUserRoles(id, roleid, - sysUser.getId()); - } - } - //判断新增是否成功 消息提示 - if (ok) { - result.put("status", "sucess"); - result.put("msg", "新增用户成功!"); - - } else { - result.put("status", "error"); - result.put("msg", "新增用户失败!"); - } - } else { - result.put("status", "error"); - result.put("msg", "用户账号已存在,不能重复添加!"); - } - return result; - } - - /*********************************** - * 用途说明:查询系统用户 - * 参数说明 - *page 分页集合参数 - *orgid 所属组织 - *username 用户名称 - * mobile 手机号 - * status 状态 - * 返回值说明: 用户分页集合 - ************************************/ - @Override - public List list(String total, String size, String orgid, - String username, String mobile, String status) { - List list = sysUserMapper.list(total, size, orgid, username, - mobile, status); - for (Map map : list) { - List mapList = - sysUserMapper.getLevel(map.get("id").toString()); - String roleid = ""; - String level = ""; - String rolename = ""; - for (Map map1 : mapList) { - roleid += map1.get("id") + ","; - level += map1.get("level") + ","; - rolename += map1.get("rolename") + ","; - } - if (roleid.endsWith(",")) { - roleid = roleid.substring(0, roleid.length() - 1); - } - if (level.endsWith(",")) { - level = level.substring(0, level.length() - 1); - } - if (rolename.endsWith(",")) { - rolename = rolename.substring(0, rolename.length() - 1); - } - - map.put("roleid", roleid); - map.put("level", level); - map.put("rolename", rolename); - } - return list; //返回分页集合 - } - - /*********************************** - * 用途说明:根据ID修改用户 - * 参数说明 - *sysUser 用户对象 - *roleids 角色id - * 返回值说明: 是否更新成功 - ************************************/ - // ... existing code ... - - @Override - @Transactional(rollbackFor = Exception.class) - public Map updateById(SysUser sysUser, String roleids) { - Map result = new HashMap<>(); - - try { - // 设置修改信息 - String currentUsername = getUsername(); - Timestamp currentTime = new Timestamp(System.currentTimeMillis()); - sysUser.setLastmodifier(currentUsername); - sysUser.setLastmodifydate(currentTime); - - // 更新用户信息 - boolean ok = this.updateById(sysUser); - if (!ok) { - result.put("status", "error"); - result.put("msg", "用户信息修改失败!"); - return result; - } - - // 处理角色分配 - String userId = sysUser.getId(); - if (StrUtil.isNotEmpty(roleids)) { - handleUserRoles(userId, roleids); - } else { - // 清空所有角色 - sysUserMapper.delRoleUsersByUserid(userId); - } - - result.put("status", "sucess"); - result.put("msg", "用户信息修改成功!"); - - } catch (Exception e) { - log.error("更新用户信息失败", e); - result.put("status", "error"); - result.put("msg", "操作失败:" + e.getMessage()); - throw e; // 抛出异常,触发事务回滚 - } - - return result; - } - - /** - * 处理用户角色分配(增量更新) - * @param userId 用户 ID - * @param roleIds 角色 ID 字符串(逗号分隔) - */ - private void handleUserRoles(String userId, String roleIds) { - // 获取用户当前角色 - List currentRoles = sysUserMapper.getRoleid(userId); - Set currentRoleSet = new HashSet<>(currentRoles != null ? currentRoles : Collections.emptyList()); - - // 解析新角色列表 - String[] newRoles = roleIds.split(","); - Set newRoleSet = new HashSet<>(Arrays.asList(newRoles)); - - // 需要新增的角色(新角色 - 当前角色) - for (String roleId : newRoles) { - if (!currentRoleSet.contains(roleId)) { - String id = IdUtil.fastSimpleUUID(); - sysUserMapper.addUserRoles(id, roleId, userId); - } - } - - // 需要删除的角色(当前角色 - 新角色) - sysUserMapper.delInRoleUsersByUserid(userId, newRoles); - } - -// ... existing code ... - - - @Override - public Map getOneById(String id) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - Map map = this.getMap(queryWrapper.eq("id", id)); - List mapList = sysUserMapper.getLevel(id); - String roleid = ""; - String level = ""; - String rolename = ""; - for (Map map1 : mapList) { - roleid += map1.get("id") + ","; - level += map1.get("level") + ","; - rolename += map1.get("rolename") + ","; - } - if (roleid.endsWith(",")) { - roleid = roleid.substring(0, roleid.length() - 1); - } - if (level.endsWith(",")) { - level = level.substring(0, level.length() - 1); - } - if (rolename.endsWith(",")) { - rolename = rolename.substring(0, rolename.length() - 1); - } - - map.put("roleid", roleid); - map.put("level", level); - map.put("rolename", rolename); - return map; - } - - /*********************************** - * 用途说明:用户分配角色 - * 参数说明 - *listId 用户id与角色id - * 返回值说明: 判断是否添加成功 - ************************************/ - @Override - public boolean setUserRoles(String roleid, String userids) { - boolean isOk = true; - //拆分userid 数组 - String[] temp = userids.split(","); - //遍历userid - for (String userid : temp) { - //根据角色id与用户id查询 - List list = sysUserMapper.getRoleUsersByid(roleid, userid); - //判断是否用户已分配此权限 - if (list.size() == 0) { - //系统生成id - String id = IdUtil.fastSimpleUUID(); - //新增sys_role_users表数据 - isOk = isOk && sysUserMapper.addUserRoles(id, roleid, userid); - } - } - return isOk; - } - - /*********************************** - * 用途说明:根据id删除用户 - * 参数说明 - *id 用户id - * 返回值说明: 判断是否删除成功 - ************************************/ - @Override - public boolean deleteById(String id) { - //根据id查询 - SysUser sysUser = this.getById(id); - //账号头像存储地址 - String imgName = - fileSpaceProperties.getSystem() + File.separator + "user" + File.separator + sysUser.getAvatar(); - if ("admin".equals(sysUser.getUsername())) { - return false; - } else { - boolean isOk = this.removeById(id); - //判断是否删除成功 - if (isOk) { - //根据用户id 删除该用户角色关联 - sysUserMapper.delRoleUsersByUserid(id); - //判断是否存在 账号头像 存在删除 - if (StrUtil.isNotEmpty(sysUser.getAvatar())) { - FileUtil.del(imgName); - } - return false; - } else { - return false; - } - } - } - - /*********************************** - * 用途说明:重置用户密码(管理员) - * 参数说明 - *id 重置密码的 用户id - * 返回值说明: 判断是重置成功 - ************************************/ - @Override - public boolean resetPassword(String id) throws Exception { - boolean isOk = false; - //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id - String level = sysUserMapper.getMaxLevel(id); - //判断是否获取级别 - if (StrUtil.isNotEmpty(level)) { - //判断当前用户级别 管理员及以上权限 - if (Integer.parseInt(level) <= 2) { - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - //根据id 修改密码,密码修改时间,最近修改者,最近修改日期 将密码修改为 123456 - String cryptPassword = passwordEncoder.encode("123456"); - updateWrapper.eq("id", id).set("password", cryptPassword).set( - "pwdresettime", - new Timestamp(System.currentTimeMillis())).set( - "lastmodifydate", - new Timestamp(System.currentTimeMillis())).set( - "lastmodifier", getUsername()); - //是否修改成功 - isOk = this.update(updateWrapper); - } - } - return isOk; - } - - /*********************************** - * 用途说明:设置账号状态(管理员) - * 参数说明 - *id 用户id - * status 设置状态 - * 返回值说明: 判断是否设置成功 - ************************************/ - @Override - public boolean setStatus(String id, String status) { - boolean isOk = false; - //根据当前用户id 查询角色表的级别 currentUser.getUser() 获取当前用户id - String level = sysUserMapper.getMaxLevel(id); - //判断当前用户级别 管理员及以上权限 - if (Integer.parseInt(level) <= 2) { - UpdateWrapper updateWrapper = new UpdateWrapper<>(); - //根据id修改用户状态,最近修改人,最近修改时间 - updateWrapper.eq("id", id).set("status", status).set( - "lastmodifydate", - new Timestamp(System.currentTimeMillis())).set( - "lastmodifier", getUsername()); - //是否修改成功 - isOk = this.update(updateWrapper); - } - return isOk; - } - - /*********************************** - * 用途说明:上传用户头像 - * 参数说明 - * id 用户id - * img 账号头像 - * 返回值说明: 判断是否上传 - ***********************************/ - @Override - public boolean uploadAvatar(String id, MultipartFile img) { - //根据id查询 - SysUser sysUser = this.getById(id); - //账号头像存储地址 - String imgPath = fileSpaceProperties.getSystem() + "user"; - String avatar = sysUser.getAvatar(); - if (StrUtil.isNotBlank(avatar)) { - String imgName = imgPath + File.separator + avatar; - FileUtil.del(imgName); - } - //上传图片 并获取图片名称 (图片格式修改成png) - String imgName = FileUtil.upload(img, imgPath, - IdUtil.fastSimpleUUID() + "." + FileUtil.getExtensionName(img.getOriginalFilename())).getName(); - //修改 账户头像 - sysUser.setAvatar(imgName); - //修改 最近修改者 - sysUser.setLastmodifier(getUsername()); - //修改 最近修改日期 - sysUser.setLastmodifydate(new Timestamp(System.currentTimeMillis())); - //更新用户表 - boolean isOk = this.updateById(sysUser); - return isOk; - } - - /*********************************** - * 用途说明:新增系统角色用户对照表 对用户分配角色(单个) - * 参数说明 - * id 生成的id - * roleid 角色id - * userid 用户id - * 返回值说明: - ************************************/ - @Override - public boolean addUserRoles(String roleid, String userid) { - boolean isOk = true; - //根据角色id与用户id查询 - List list = sysUserMapper.getRoleUsersByid(roleid, userid); - //判断是否用户已分配此权限 - if (list.size() == 0) { - //系统生成id - String id = IdUtil.fastSimpleUUID(); - //新增sys_role_users表数据 - isOk = sysUserMapper.addUserRoles(id, roleid, userid); - } - return isOk; - } - - /* @Override - public Page queryUsers(String orgid, - String username, Page page) { - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - // 分页查询中的条件查询 - if (StrUtil.isNotBlank(username)) { - queryWrapper.like(SysUser::getUsername, username); - } - queryWrapper.eq(SysUser::getOrgid, orgid); - return sysUserMapper.selectPage(page, queryWrapper); - }*/ - - @Override - public Page queryUsers(String orgid, - String username, - Page page) { - Page mapPage = sysUserMapper.queryUsers(orgid, - username, page); - ;mapPage.getRecords().forEach(record -> { - String id = record.getId(); - List sysRoles = sysRoleMapper.getRoleByUserId(id); - record.setRoles(sysRoles); - }); - return mapPage; - } - - /*********************************** - * 用途说明:根据ID批量删除用户 - * 参数说明 - *ids 用户id集合 - * 返回值说明: 判断是否删除成功 - ************************************/ - @Override - public boolean deleteUserByIds(String id) { - String[] splitId = id.split(","); - List ids = Arrays.asList(splitId); - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); - queryWrapper.in(SysUser::getId, ids); - List sysUsers = sysUserMapper.selectList(queryWrapper); - List names = - sysUsers.stream().map(SysUser::getUsername).collect(Collectors.toList()); - if (names.contains("admin")) { - return false; - } else { - int result = sysUserMapper.deleteBatchIds(ids); - if (result <= 0) { - return false; - } - // 根据ID删除用户与角色的关联信息 - sysUserMapper.delRoleUsersByUserIds(ids); - List avatars = - sysUsers.stream().map(SysUser::getAvatar).collect(Collectors.toList()); - if (avatars.size() > 0) { - for (String avatar : avatars) { - //账号头像存储地址 - String imgName = - fileSpaceProperties.getSystem() + File.separator + "user" + File.separator + avatar; - FileUtil.del(imgName); - } - } - return true; - } - } - - /*********************************** - * 用途说明:比较登录名称是否有重复 - * 参数说明 - * account 登录名称 - * 返回值说明: 重复返回 false 否则返回 true - ************************************/ - private boolean isExistAccount(String username) { - QueryWrapper queryWrapper = new QueryWrapper<>(); - if (this.list(queryWrapper.eq("username", username)).size() > 0) { - //判断 查询登录账号 结果集是否为null 重复返回 false 否则返回 tree - return false; - } else { - return true; - } - } -} diff --git a/backend/src/main/java/com/yfd/platform/task/TaskMessage.java b/backend/src/main/java/com/yfd/platform/task/TaskMessage.java deleted file mode 100644 index 4a43d15..0000000 --- a/backend/src/main/java/com/yfd/platform/task/TaskMessage.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.yfd.platform.task; - -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.yfd.platform.component.ServerSendEventServer; -import com.yfd.platform.config.MessageConfig; -import com.yfd.platform.config.WebConfig; -import com.yfd.platform.system.domain.Message; -import com.yfd.platform.system.service.IMessageService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import jakarta.annotation.Resource; -import java.sql.Timestamp; -import java.util.List; - -/** - * @author TangWei - * @Date: 2023/3/22 15:39 - * @Description: - */ -@Component -public class TaskMessage { - - @Resource - private IMessageService messageService; - - /********************************** - * 用途说明: 定时监控消息是否过期 - * 参数说明 - * 返回值说明: void - ***********************************/ - public void examineMessage() { - List list = - messageService.list(new LambdaQueryWrapper().eq(Message::getStatus, "1")); - for (Message message : list) { - Timestamp createtime = message.getCreatetime(); - Timestamp timestamp = new Timestamp(System.currentTimeMillis()); - long create = createtime.getTime(); - long now = timestamp.getTime(); - Integer validperiod = message.getValidperiod(); - long v = validperiod * 60 * 60 * 1000; - if ((now - create) > v) { - message.setStatus("9"); - message.setReadtime(timestamp); - messageService.updateById(message); - } - - } - } - - /*public void sendMessage() { - String loginToken = webConfig.loginuserCache().get("loginToken"); - long count = - messageService.count(new LambdaQueryWrapper().eq(Message::getStatus, "1")); - ServerSendEventServer.sendMessage(loginToken, count + ""); - }*/ -} diff --git a/backend/src/main/java/com/yfd/platform/utils/CallBack.java b/backend/src/main/java/com/yfd/platform/utils/CallBack.java deleted file mode 100644 index 5f13d70..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/CallBack.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2019-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.yfd.platform.utils; - -/** - * @author: liaojinlong - * @date: 2020/6/9 17:02 - * @since: 1.0 - * @see {@link SpringContextHolder} - * 针对某些初始化方法,在SpringContextHolder 初始化前时,
- * 可提交一个 提交回调任务。
- * 在SpringContextHolder 初始化后,进行回调使用 - */ - -public interface CallBack { - /** - * 回调执行方法 - */ - void executor(); - - /** - * 本回调任务名称 - * @return / - */ - default String getCallBackName() { - return Thread.currentThread().getId() + ":" + this.getClass().getName(); - } -} - diff --git a/backend/src/main/java/com/yfd/platform/utils/CodeGenerator.java b/backend/src/main/java/com/yfd/platform/utils/CodeGenerator.java deleted file mode 100644 index 1c65429..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/CodeGenerator.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.yfd.platform.utils; - -import com.baomidou.mybatisplus.generator.FastAutoGenerator; -import com.baomidou.mybatisplus.generator.config.OutputFile; -import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; -import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; - -import java.util.HashMap; -import java.util.Map; -import java.util.Scanner; - -// 演示例子,执行 main 方法控制台输入模块表名回车自动生成对应项目目录中 -public class CodeGenerator { - - public static String scanner(String tip) { - Scanner scanner = new Scanner(System.in); - StringBuilder help = new StringBuilder(); - help.append("请输入" + tip + ":"); - System.out.println(help.toString()); - if (scanner.hasNext()) { - String ipt = scanner.next(); - if (ipt != null && !ipt.trim().isEmpty()) { - return ipt; - } - } - throw new RuntimeException("请输入正确的" + tip + "!"); - } - - public static void main(String[] args) { - String projectPath = System.getProperty("user.dir"); - String module = scanner("模块名称"); - - Map pathInfo = new HashMap<>(); - pathInfo.put(OutputFile.entity, projectPath + "/src/main/java/com/yfd/platform/" + module + "/domain"); - pathInfo.put(OutputFile.mapper, projectPath + "/src/main/java/com/yfd/platform/" + module + "/mapper"); - pathInfo.put(OutputFile.controller, projectPath + "/src/main/java/com/yfd/platform/" + module + "/controller"); - pathInfo.put(OutputFile.serviceImpl, projectPath + "/src/main/java/com/yfd/platform/" + module + "/service/impl"); - pathInfo.put(OutputFile.service, projectPath + "/src/main/java/com/yfd/platform/" + module + "/service"); - pathInfo.put(OutputFile.xml, projectPath + "/src/main/resources/mapper/" + module); - - FastAutoGenerator.create( - "jdbc:mysql://43.143.220.7:3306/frameworkdb2023?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&autoReconnect=true&failOverReadOnly=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai", - "root", - "zhengg7QkXa { - builder.author("TangWei") - .disableOpenDir() - .outputDir(projectPath + "/src/main/java"); - }) - .packageConfig(builder -> { - builder.parent("com.yfd.platform") - .moduleName(module) - .pathInfo(pathInfo); - }) - .strategyConfig(builder -> { - builder.addInclude(scanner("表名,多个英文逗号分割").split(",")) - .entityBuilder() - .enableLombok() - .naming(NamingStrategy.underline_to_camel) - .columnNaming(NamingStrategy.underline_to_camel) - .controllerBuilder() - .enableRestStyle() - .mapperBuilder() - .formatMapperFileName("%sMapper") - .serviceBuilder() - .formatServiceFileName("%sService") - .formatServiceImplFileName("%sServiceImpl") - .controllerBuilder() - .formatFileName("%sController"); - }) - .templateEngine(new FreemarkerTemplateEngine()) - .execute(); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/utils/EncryptConfigUtil.java b/backend/src/main/java/com/yfd/platform/utils/EncryptConfigUtil.java deleted file mode 100644 index 4df5527..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/EncryptConfigUtil.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.yfd.platform.utils; - -import org.jasypt.encryption.pbe.PooledPBEStringEncryptor; -import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig; -import org.jasypt.util.text.BasicTextEncryptor; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; - -public class EncryptConfigUtil { - - public static void main(String[] args) { - -// String salt = "rca20230101"; -// String password = "123456"; -// -// BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); -// //加密所需的salt -// textEncryptor.setPassword(salt); -// //要加密的数据(数据库的用户名或密码) -// String encrypt = textEncryptor.encrypt(password); -// System.out.println("password:"+encrypt); - - - BCryptPasswordEncoder passwordEncoder=new BCryptPasswordEncoder(); - String cryptPassword=passwordEncoder.encode("dl_2023");//设置缺省密码 - - } - -} \ No newline at end of file diff --git a/backend/src/main/java/com/yfd/platform/utils/EncryptUtils.java b/backend/src/main/java/com/yfd/platform/utils/EncryptUtils.java deleted file mode 100644 index 2ae2b26..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/EncryptUtils.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.utils; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.DESKeySpec; -import javax.crypto.spec.IvParameterSpec; -import java.nio.charset.StandardCharsets; - -/** - * 加密 - * @author - * @date 2018-11-23 - */ - -public class EncryptUtils { - - private static final String STR_PARAM = "Passw0rd"; - - private static Cipher cipher; - - private static final IvParameterSpec IV = new IvParameterSpec(STR_PARAM.getBytes(StandardCharsets.UTF_8)); - - private static DESKeySpec getDesKeySpec(String source) throws Exception { - if (source == null || source.length() == 0){ - return null; - } - cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); - String strKey = "Passw0rd"; - return new DESKeySpec(strKey.getBytes(StandardCharsets.UTF_8)); - } - - /** - * 对称加密 - */ - public static String desEncrypt(String source) throws Exception { - DESKeySpec desKeySpec = getDesKeySpec(source); - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); - SecretKey secretKey = keyFactory.generateSecret(desKeySpec); - cipher.init(Cipher.ENCRYPT_MODE, secretKey, IV); - return byte2hex( - cipher.doFinal(source.getBytes(StandardCharsets.UTF_8))).toUpperCase(); - } - - /** - * 对称解密 - */ - public static String desDecrypt(String source) throws Exception { - byte[] src = hex2byte(source.getBytes(StandardCharsets.UTF_8)); - DESKeySpec desKeySpec = getDesKeySpec(source); - SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); - SecretKey secretKey = keyFactory.generateSecret(desKeySpec); - cipher.init(Cipher.DECRYPT_MODE, secretKey, IV); - byte[] retByte = cipher.doFinal(src); - return new String(retByte); - } - - private static String byte2hex(byte[] inStr) { - String stmp; - StringBuilder out = new StringBuilder(inStr.length * 2); - for (byte b : inStr) { - stmp = Integer.toHexString(b & 0xFF); - if (stmp.length() == 1) { - // 如果是0至F的单位字符串,则添加0 - out.append("0").append(stmp); - } else { - out.append(stmp); - } - } - return out.toString(); - } - - private static byte[] hex2byte(byte[] b) { - int size = 2; - if ((b.length % size) != 0){ - throw new IllegalArgumentException("长度不是偶数"); - } - byte[] b2 = new byte[b.length / 2]; - for (int n = 0; n < b.length; n += size) { - String item = new String(b, n, 2); - b2[n / 2] = (byte) Integer.parseInt(item, 16); - } - return b2; - } -} diff --git a/backend/src/main/java/com/yfd/platform/utils/ExecutionJob.java b/backend/src/main/java/com/yfd/platform/utils/ExecutionJob.java deleted file mode 100644 index c4a2fcf..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/ExecutionJob.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.utils; - -import com.yfd.platform.config.MessageConfig; -import com.yfd.platform.config.thread.ThreadPoolExecutorUtil; -import com.yfd.platform.system.domain.Message; -import com.yfd.platform.system.domain.QuartzJob; -import com.yfd.platform.system.service.IMessageService; -import com.yfd.platform.system.service.IQuartzJobService; -import org.quartz.JobExecutionContext; -import org.springframework.scheduling.annotation.Async; -import org.springframework.scheduling.quartz.QuartzJobBean; -import org.springframework.stereotype.Component; - -import jakarta.annotation.Resource; -import java.sql.Timestamp; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadPoolExecutor; - -/** - * 参考人人开源,https://gitee.com/renrenio/renren-security - * - * @author / - * @date 2019-01-07 - */ -@Async -@SuppressWarnings({"unchecked", "all"}) -public class ExecutionJob extends QuartzJobBean { - - /** - * 该处仅供参考 - */ - private final static ThreadPoolExecutor EXECUTOR = - ThreadPoolExecutorUtil.getPoll(); - - @Resource - private IMessageService messageService; - - @Resource - private MessageConfig messageConfig; - - @Override - public void executeInternal(JobExecutionContext context) { - QuartzJob quartzJob = - (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY); - // 获取spring bean - IQuartzJobService quartzJobService = - SpringContextHolder.getBean(IQuartzJobService.class); - String uuid = quartzJob.getId(); - long startTime = System.currentTimeMillis(); - String jobName = quartzJob.getJobName(); - try { - // 执行任务 - System.out.println( - "--------------------------------------------------------------"); - System.out.println("任务开始执行,任务名称:" + jobName); - QuartzRunnable task = new QuartzRunnable(quartzJob.getJobClass(), - quartzJob.getJobMethod(), - quartzJob.getJobParams()); - Future future = EXECUTOR.submit(task); - future.get(); - long times = System.currentTimeMillis() - startTime; - Message message = new Message(); - message.setCreatetime(new Timestamp(System.currentTimeMillis())); - message.setType("1"); - message.setTitle(quartzJob.getJobName()); - message.setContent(quartzJob.getDescription()); - message.setSenderName("定时器"); - message.setReceiverCodes(quartzJob.getOrderno().toString()); - message.setReceiverNames(""); - message.setStatus("1"); - message.setValidperiod(24); - messageConfig.addMessage(message); - // 任务状态 - System.out.println("任务执行完毕,任务名称:" + jobName + ", " + - "执行时间:" + times + "毫秒"); - System.out.println( - "--------------------------------------------------------------"); - } catch (Exception e) { - System.out.println("任务执行失败,任务名称:" + jobName); - System.out.println( - "--------------------------------------------------------------"); - quartzJob.setStatus("0"); - //更新状态 - quartzJobService.updateById(quartzJob); - } - } - -} diff --git a/backend/src/main/java/com/yfd/platform/utils/FileUtil.java b/backend/src/main/java/com/yfd/platform/utils/FileUtil.java deleted file mode 100644 index 6940aee..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/FileUtil.java +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.utils; - -import cn.hutool.core.date.DateUtil; -import cn.hutool.core.io.IoUtil; -import cn.hutool.core.util.IdUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.poi.excel.BigExcelWriter; -import cn.hutool.poi.excel.ExcelUtil; -import com.yfd.platform.exception.BadRequestException; -import org.apache.commons.lang3.StringUtils; -import org.apache.poi.util.IOUtils; -import org.apache.poi.xssf.streaming.SXSSFSheet; -import org.apache.tomcat.util.http.fileupload.FileUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.multipart.MultipartFile; - -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import java.io.*; -import java.net.URLDecoder; -import java.security.MessageDigest; -import java.text.DecimalFormat; -import java.text.SimpleDateFormat; -import java.util.*; - -/** - * File工具类,扩展 hutool 工具包 - * - * @author - * @date 2018-12-27 - */ -public class FileUtil extends cn.hutool.core.io.FileUtil { - - private static final Logger log = LoggerFactory.getLogger(FileUtil.class); - - /** - * 系统临时目录 - *
- * windows 包含路径分割符,但Linux 不包含, - * 在windows \\==\ 前提下, - * 为安全起见 同意拼装 路径分割符, - *
-     *       java.io.tmpdir
-     *       windows : C:\Users/xxx\AppData\Local\Temp\
-     *       linux: /temp
-     * 
- */ - public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator; - /** - * 定义GB的计算常量 - */ - private static final int GB = 1024 * 1024 * 1024; - /** - * 定义MB的计算常量 - */ - private static final int MB = 1024 * 1024; - /** - * 定义KB的计算常量 - */ - private static final int KB = 1024; - - /** - * 格式化小数 - */ - private static final DecimalFormat DF = new DecimalFormat("0.00"); - - public static final String IMAGE = "image"; - public static final String TXT = "document"; - public static final String MUSIC = "music"; - public static final String VIDEO = "video"; - public static final String OTHER = "other"; - - - /** - * MultipartFile转File - */ - public static File toFile(MultipartFile multipartFile) { - // 获取文件名 - String fileName = multipartFile.getOriginalFilename(); - // 获取文件后缀 - String prefix = "." + getExtensionName(fileName); - File file = null; - try { - // 用uuid作为文件名,防止生成的临时文件重复 - file = File.createTempFile(IdUtil.simpleUUID(), prefix); - // MultipartFile to File - multipartFile.transferTo(file); - } catch (IOException e) { - log.error(e.getMessage(), e); - } - return file; - } - - /** - * 获取文件扩展名,不带 . - */ - public static String getExtensionName(String filename) { - if ((filename != null) && (filename.length() > 0)) { - int dot = filename.lastIndexOf('.'); - if ((dot > -1) && (dot < (filename.length() - 1))) { - return filename.substring(dot + 1); - } - } - return filename; - } - - /** - * Java文件操作 获取不带扩展名的文件名 - */ - public static String getFileNameNoEx(String filename) { - if ((filename != null) && (filename.length() > 0)) { - int dot = filename.lastIndexOf('.'); - if ((dot > -1) && (dot < (filename.length()))) { - return filename.substring(0, dot); - } - } - return filename; - } - - /** - * 文件大小转换 - */ - public static String getSize(long size) { - String resultSize; - if (size / GB >= 1) { - //如果当前Byte的值大于等于1GB - resultSize = DF.format(size / (float) GB) + "GB "; - } else if (size / MB >= 1) { - //如果当前Byte的值大于等于1MB - resultSize = DF.format(size / (float) MB) + "MB "; - } else if (size / KB >= 1) { - //如果当前Byte的值大于等于1KB - resultSize = DF.format(size / (float) KB) + "KB "; - } else { - resultSize = size + "B "; - } - return resultSize; - } - - /** - * inputStream 转 File - */ - static File inputStreamToFile(InputStream ins, String name) throws Exception { - File file = new File(SYS_TEM_DIR + name); - if (file.exists()) { - return file; - } - OutputStream os = new FileOutputStream(file); - int bytesRead; - int len = 8192; - byte[] buffer = new byte[len]; - while ((bytesRead = ins.read(buffer, 0, len)) != -1) { - os.write(buffer, 0, bytesRead); - } - os.close(); - ins.close(); - return file; - } - - /** - * 将文件名解析成文件的上传路径 - */ - public static File upload(MultipartFile file, String filePath) { - Date date = new Date(); - SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS"); - String name = getFileNameNoEx(file.getOriginalFilename()); - String suffix = getExtensionName(file.getOriginalFilename()); - String nowStr = "-" + format.format(date); - try { - String fileName = name + "." + suffix; - String path = filePath +File.separator + fileName; - // getCanonicalFile 可解析正确各种路径 - File dest = new File(path).getCanonicalFile(); - // 检测是否存在目录 - if (!dest.getParentFile().exists()) { - if (!dest.getParentFile().mkdirs()) { - System.out.println("was not successful."); - } - } - // 文件写入 - file.transferTo(dest); - return dest; - } catch (Exception e) { - log.error(e.getMessage(), e); - } - return null; - } - - /** - * 将文件名解析成文件的上传路径 - * file 上传的文件 - * filePath 存储路径 - * tofilename 保存文件名称 - - */ - public static File upload(MultipartFile file, String filePath,String tofilename) { - try { - String filename = filePath + File.separator + tofilename; - File dest = new File(filename).getCanonicalFile(); - // 检测是否存在目录 - if (!dest.getParentFile().exists()) { - if (!dest.getParentFile().mkdirs()) { - } - } - // 文件写入 - file.transferTo(dest); - return dest; - } catch (Exception e) { - log.error(e.getMessage(), e); - } - return null; - } - - - /** - * 导出excel - */ - public static void downloadExcel(List> list, HttpServletResponse response) throws IOException { - String tempPath = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx"; - String filename = "record"+cn.hutool.core.date.DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss"); - File file = new File(tempPath); - BigExcelWriter writer = ExcelUtil.getBigWriter(file); - // 一次性写出内容,使用默认样式,强制输出标题 - writer.write(list, true); - SXSSFSheet sheet = (SXSSFSheet)writer.getSheet(); - //上面需要强转SXSSFSheet 不然没有trackAllColumnsForAutoSizing方法 - sheet.trackAllColumnsForAutoSizing(); - //列宽自适应 - writer.autoSizeColumnAll(); - //response为HttpServletResponse对象 - response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8"); - //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码 - response.setHeader("Content-Disposition", "attachment;filename="+filename+".xlsx"); - ServletOutputStream out = response.getOutputStream(); - // 终止后删除临时文件 - file.deleteOnExit(); - writer.flush(out, true); - //此处记得关闭输出Servlet流 - IoUtil.close(out); - } - - public static String getFileType(String type) { - String documents = "txt doc pdf ppt pps xlsx xls docx"; - String music = "mp3 wav wma mpa ram ra aac aif m4a"; - String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg"; - String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg"; - if (image.contains(type)) { - return IMAGE; - } else if (documents.contains(type)) { - return TXT; - } else if (music.contains(type)) { - return MUSIC; - } else if (video.contains(type)) { - return VIDEO; - } else { - return OTHER; - } - } - - public static void checkSize(long maxSize, long size) { - // 1M - int len = 1024 * 1024; - if (size > (maxSize * len)) { - throw new BadRequestException("文件超出规定大小"); - } - } - - /** - * 判断两个文件是否相同 - */ - public static boolean check(File file1, File file2) { - String img1Md5 = getMd5(file1); - String img2Md5 = getMd5(file2); - return img1Md5.equals(img2Md5); - } - - /** - * 判断两个文件是否相同 - */ - public static boolean check(String file1Md5, String file2Md5) { - return file1Md5.equals(file2Md5); - } - - private static byte[] getByte(File file) { - // 得到文件长度 - byte[] b = new byte[(int) file.length()]; - try { - InputStream in = new FileInputStream(file); - try { - System.out.println(in.read(b)); - } catch (IOException e) { - log.error(e.getMessage(), e); - } - } catch (FileNotFoundException e) { - log.error(e.getMessage(), e); - return null; - } - return b; - } - - private static String getMd5(byte[] bytes) { - // 16进制字符 - char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; - try { - MessageDigest mdTemp = MessageDigest.getInstance("MD5"); - mdTemp.update(bytes); - byte[] md = mdTemp.digest(); - int j = md.length; - char[] str = new char[j * 2]; - int k = 0; - // 移位 输出字符串 - for (byte byte0 : md) { - str[k++] = hexDigits[byte0 >>> 4 & 0xf]; - str[k++] = hexDigits[byte0 & 0xf]; - } - return new String(str); - } catch (Exception e) { - log.error(e.getMessage(), e); - } - return null; - } - - /** - * 下载文件 - * - * @param request / - * @param response / - * @param file / - */ - public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) { - response.setCharacterEncoding(request.getCharacterEncoding()); - response.setContentType("application/octet-stream"); - FileInputStream fis = null; - try { - fis = new FileInputStream(file); - response.setHeader("Content-Disposition", "attachment; filename=" + file.getName()); - IOUtils.copy(fis, response.getOutputStream()); - response.flushBuffer(); - } catch (Exception e) { - log.error(e.getMessage(), e); - } finally { - if (fis != null) { - try { - fis.close(); - if (deleteOnExit) { - file.deleteOnExit(); - } - } catch (IOException e) { - log.error(e.getMessage(), e); - } - } - } - } - /** - * 预览PDF文件 - * - * @param filepath / - * @param response / - */ - public static void viewPDF(String filepath, HttpServletResponse response) throws IOException { - File file=new File(filepath); - String originFileName=file.getName(); //中文编码 - response.setCharacterEncoding("UTF-8"); - String showName= StrUtil.isNotBlank(originFileName)?originFileName:file.getName(); - showName= URLDecoder.decode(showName,"UTF-8"); - response.setHeader("Content-Disposition","inline;fileName="+new String(showName.getBytes(), "ISO8859-1")+";fileName*=UTF-8''"+ new String(showName.getBytes(), "ISO8859-1")); - FileInputStream fis = new FileInputStream(file); - response.setHeader("content-type", "application/pdf"); - response.setContentType("application/pdf; charset=utf-8"); - IOUtils.copy(fis, response.getOutputStream()); - fis.close(); - } - - public static String getMd5(File file) { - return getMd5(getByte(file)); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/utils/MpGenerator.java b/backend/src/main/java/com/yfd/platform/utils/MpGenerator.java deleted file mode 100644 index e3aec6e..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/MpGenerator.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.yfd.platform.utils; - -import com.baomidou.mybatisplus.generator.FastAutoGenerator; -import com.baomidou.mybatisplus.generator.config.OutputFile; -import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; -import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine; -import org.springframework.util.StringUtils; - -import java.util.HashMap; -import java.util.Map; -import java.util.Scanner; - -public class MpGenerator { - /** - * 读取控制台内容 - */ - public static String scanner(String tip) { - Scanner scanner = new Scanner(System.in); - StringBuilder help = new StringBuilder(); - help.append("请输入" + tip + ":"); - System.out.println(help.toString()); - if (scanner.hasNext()) { - String ipt = scanner.next(); - if (StringUtils.hasText(ipt)) { - return ipt; - } - } - throw new RuntimeException("请输入正确的" + tip + "!"); - } - - public static void main(String[] args) { - String projectPath = System.getProperty("user.dir"); - String url = PropertiesUtils.getPropertyField("spring.datasource.url"); - String username = PropertiesUtils.getPropertyField("spring.datasource.username"); - String password = PropertiesUtils.getPropertyField("spring.datasource.password"); - - String moduleName = scanner("模块名"); - String modulePath = moduleName.replace(".", "/"); - - Map pathInfo = new HashMap<>(); - pathInfo.put(OutputFile.entity, projectPath + "/src/main/java/com/yfd/platform/modules/domain" + modulePath + "/entity"); - pathInfo.put(OutputFile.mapper, projectPath + "/src/main/java/com/yfd/platform/modules/domain/" + modulePath + "/dao"); - pathInfo.put(OutputFile.controller, projectPath + "/src/main/java/com/yfd/platform/modules/domain" + modulePath + "/controller"); - pathInfo.put(OutputFile.service, projectPath + "/src/main/java/com/yfd/platform/modules/domain" + modulePath + "/service"); - pathInfo.put(OutputFile.serviceImpl, projectPath + "/src/main/java/com/yfd/platform/modules/domain" + modulePath + "/service/impl"); - pathInfo.put(OutputFile.xml, projectPath + "/src/main/resources/mapper/" + modulePath); - - FastAutoGenerator.create(url, username, password) - .globalConfig(builder -> { - builder.author("fwh") - .disableOpenDir() - .outputDir(projectPath + "/src/main/java"); - }) - .packageConfig(builder -> { - builder.parent(PropertiesUtils.getPropertyField("project.package.name")) - .moduleName(moduleName) - .pathInfo(pathInfo); - }) - .strategyConfig(builder -> { - builder.addInclude(scanner("表名,多个英文逗号分割").split(",")) - .entityBuilder() - .enableLombok() - .naming(NamingStrategy.underline_to_camel) - .columnNaming(NamingStrategy.underline_to_camel) - .controllerBuilder() - .enableRestStyle() - .mapperBuilder() - .formatMapperFileName("%sDao") - .serviceBuilder() - .formatServiceFileName("%sService") - .formatServiceImplFileName("%sServiceImpl") - .controllerBuilder() - .formatFileName("%sController"); - }) - .templateEngine(new FreemarkerTemplateEngine()) - .execute(); - } -} - diff --git a/backend/src/main/java/com/yfd/platform/utils/ObjectConverterUtil.java b/backend/src/main/java/com/yfd/platform/utils/ObjectConverterUtil.java deleted file mode 100644 index da72785..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/ObjectConverterUtil.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.yfd.platform.utils; - -import java.lang.reflect.Field; -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.*; -import java.util.stream.Collectors; - -public class ObjectConverterUtil { - - // 日期时间格式 - private static final DateTimeFormatter DATE_TIME_FORMATTER = - DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); - - /** - * 将 List 中的大写字段名转换为与实体类一致的小写格式 - * 适用于 Oracle 数据库查询结果转换 - * 时间类型字段会转换为字符串格式 - * - * @param entityClass 实体类 Class 对象 - * @param sourceList 源数据列表(字段名为大写) - * @return 转换后的列表(字段名与实体类一致) - */ - public static List> convertMapFieldsToEntityFormat( - Class entityClass, - List> sourceList) { - - if (sourceList == null || sourceList.isEmpty()) { - return sourceList; - } - - // 获取实体类的所有字段及类型 - Map fieldMap = new HashMap<>(); - for (Field field : entityClass.getDeclaredFields()) { - fieldMap.put(field.getName(), field); - } - - // 转换每个 Map - return sourceList.stream().map(sourceMap -> { - Map targetMap = new HashMap<>(); - - for (Map.Entry entry : sourceMap.entrySet()) { - String dbColumnName = entry.getKey(); // 数据库列名(大写) - Object value = entry.getValue(); - - // 将大写列名转为小写 - String lowerCaseName = dbColumnName.toLowerCase(); - - // 如果实体类中有对应的字段 - if (fieldMap.containsKey(lowerCaseName)) { - Field field = fieldMap.get(lowerCaseName); - String fieldType = field.getType().getSimpleName(); - - // 处理时间类型,转换为字符串 - if ("Timestamp".equals(fieldType) || "Date".equals(fieldType) || - "LocalDateTime".equals(fieldType)) { - targetMap.put(lowerCaseName, formatDateTimeValue(value)); - } else { - targetMap.put(lowerCaseName, value); - } - } else { - // 如果实体类中没有对应字段,保留原列名(转小写) - targetMap.put(lowerCaseName, value); - } - } - - return targetMap; - }).collect(Collectors.toList()); - } - - /** - * 通用方法:将单个 Map 的大写字段转换为实体类格式 - * 时间类型字段会转换为字符串格式 - * - * @param entityClass 实体类 Class 对象 - * @param sourceMap 源 Map(字段名为大写) - * @return 转换后的 Map(字段名与实体类一致) - */ - public static Map convertSingleMapFieldsToEntityFormat( - Class entityClass, - Map sourceMap) { - - if (sourceMap == null) { - return sourceMap; - } - - // 获取实体类的所有字段及类型 - Map fieldMap = new HashMap<>(); - for (Field field : entityClass.getDeclaredFields()) { - fieldMap.put(field.getName(), field); - } - - Map targetMap = new HashMap<>(); - - for (Map.Entry entry : sourceMap.entrySet()) { - String dbColumnName = entry.getKey(); - Object value = entry.getValue(); - - // 将大写列名转为小写 - String lowerCaseName = dbColumnName.toLowerCase(); - - // 验证字段是否存在于实体类中 - if (fieldMap.containsKey(lowerCaseName)) { - Field field = fieldMap.get(lowerCaseName); - String fieldType = field.getType().getSimpleName(); - - // 处理时间类型,转换为字符串 - if ("Timestamp".equals(fieldType) || "Date".equals(fieldType) || - "LocalDateTime".equals(fieldType)) { - targetMap.put(lowerCaseName, formatDateTimeValue(value)); - } else { - targetMap.put(lowerCaseName, value); - } - } - } - - return targetMap; - } - - /** - * 格式化时间类型值为字符串 - * - * @param value 时间值(可能是 Timestamp、Date 或 LocalDateTime) - * @return 格式化后的字符串,如果为 null 则返回 null - */ - private static String formatDateTimeValue(Object value) { - if (value == null) { - return null; - } - - if (value instanceof Timestamp) { - LocalDateTime localDateTime = ((Timestamp) value).toLocalDateTime(); - return localDateTime.format(DATE_TIME_FORMATTER); - } else if (value instanceof java.util.Date) { - // 包括 java.sql.Date 和 java.util.Date - LocalDateTime localDateTime = ((java.util.Date) value).toInstant() - .atZone(java.time.ZoneId.systemDefault()) - .toLocalDateTime(); - return localDateTime.format(DATE_TIME_FORMATTER); - } else if (value instanceof LocalDateTime) { - return ((LocalDateTime) value).format(DATE_TIME_FORMATTER); - } else { - // 其他类型直接转字符串 - return value.toString(); - } - } - -} diff --git a/backend/src/main/java/com/yfd/platform/utils/PropertiesUtils.java b/backend/src/main/java/com/yfd/platform/utils/PropertiesUtils.java deleted file mode 100644 index 93c7cfd..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/PropertiesUtils.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.yfd.platform.utils; - -import org.springframework.core.io.ClassPathResource; - -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.Properties; -/****************************** - * 用途说明: - * 作者姓名: pcj - * 创建时间: 2022/9/20 14:31 - ******************************/ -public class PropertiesUtils { - public final static String RESOURCE_PATH = "application.properties"; - - public final static Properties properties = new Properties(); - - public static String getPropertyField(String parameter) { - //对应resources目录下的资源路径 - ClassPathResource resource = new ClassPathResource(RESOURCE_PATH); - try { - properties.load(new InputStreamReader(resource.getInputStream(), "gbk")); - } catch (IOException e) { - throw new RuntimeException(e); - } - return properties.getProperty(parameter); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/utils/QuartzManage.java b/backend/src/main/java/com/yfd/platform/utils/QuartzManage.java deleted file mode 100644 index 3ff265c..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/QuartzManage.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.utils; - -import com.yfd.platform.system.domain.QuartzJob; -import lombok.extern.slf4j.Slf4j; -import org.quartz.*; -import org.quartz.impl.triggers.CronTriggerImpl; -import org.springframework.stereotype.Component; - -import jakarta.annotation.Resource; -import java.util.Date; - -import static org.quartz.TriggerBuilder.newTrigger; - -/** - * @author - * @date 2019-01-07 - */ -@Slf4j -@Component -public class QuartzManage { - - private static final String JOB_NAME = "TASK_"; - - @Resource(name = "scheduler") - private Scheduler scheduler; - - public void addJob(QuartzJob quartzJob) { - try { - // 构建job信息 - JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class). - withIdentity(JOB_NAME + quartzJob.getId()).build(); - - //通过触发器名和cron 表达式创建 Trigger - Trigger cronTrigger = newTrigger() - .withIdentity(JOB_NAME + quartzJob.getId()) - .startNow() - .withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getJobCron())) - .build(); - - cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob); - - //重置启动时间 - ((CronTriggerImpl) cronTrigger).setStartTime(new Date()); - - //执行定时任务 - scheduler.scheduleJob(jobDetail, cronTrigger); - - // 暂停任务 - if ("0".equals(quartzJob.getStatus())) { - pauseJob(quartzJob); - } - } catch (Exception e) { - log.error("创建定时任务失败", e); - throw new RuntimeException("创建定时任务失败"); - } - } - - /** - * 更新job cron表达式 - * - * @param quartzJob / - */ - public void updateJobCron(QuartzJob quartzJob) { - try { - TriggerKey triggerKey = - TriggerKey.triggerKey(JOB_NAME + quartzJob.getId()); - CronTrigger trigger = - (CronTrigger) scheduler.getTrigger(triggerKey); - // 如果不存在则创建一个定时任务 - if (trigger == null) { - addJob(quartzJob); - trigger = (CronTrigger) scheduler.getTrigger(triggerKey); - } - CronScheduleBuilder scheduleBuilder = - CronScheduleBuilder.cronSchedule(quartzJob.getJobCron()); - trigger = - trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); - //重置启动时间 - ((CronTriggerImpl) trigger).setStartTime(new Date()); - trigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob); - - scheduler.rescheduleJob(triggerKey, trigger); - // 暂停任务 - if ("0".equals(quartzJob.getStatus())) { - pauseJob(quartzJob); - } - } catch (Exception e) { - log.error("更新定时任务失败", e); - throw new RuntimeException("更新定时任务失败"); - } - - } - - /** - * 删除一个job - * - * @param quartzJob / - */ - public void deleteJob(QuartzJob quartzJob) { - try { - JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); - scheduler.pauseJob(jobKey); - scheduler.deleteJob(jobKey); - } catch (Exception e) { - log.error("删除定时任务失败", e); - throw new RuntimeException("删除定时任务失败"); - } - } - - /** - * 恢复一个job - * - * @param quartzJob / - */ - public void resumeJob(QuartzJob quartzJob) { - try { - TriggerKey triggerKey = - TriggerKey.triggerKey(JOB_NAME + quartzJob.getId()); - CronTrigger trigger = - (CronTrigger) scheduler.getTrigger(triggerKey); - // 如果不存在则创建一个定时任务 - if (trigger == null) { - addJob(quartzJob); - } - JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); - scheduler.resumeJob(jobKey); - } catch (Exception e) { - log.error("恢复定时任务失败", e); - throw new RuntimeException("恢复定时任务失败"); - } - } - - /** - * 立即执行job - * - * @param quartzJob / - */ - public void runJobNow(QuartzJob quartzJob) { - try { - TriggerKey triggerKey = - TriggerKey.triggerKey(JOB_NAME + quartzJob.getId()); - CronTrigger trigger = - (CronTrigger) scheduler.getTrigger(triggerKey); - // 如果不存在则创建一个定时任务 - if (trigger == null) { - addJob(quartzJob); - } - JobDataMap dataMap = new JobDataMap(); - dataMap.put(QuartzJob.JOB_KEY, quartzJob); - JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); - scheduler.triggerJob(jobKey, dataMap); - } catch (Exception e) { - log.error("定时任务执行失败", e); - throw new RuntimeException("定时任务执行失败"); - } - } - - /** - * 暂停一个job - * - * @param quartzJob / - */ - public void pauseJob(QuartzJob quartzJob) { - try { - JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId()); - scheduler.pauseJob(jobKey); - } catch (Exception e) { - log.error("定时任务暂停失败", e); - throw new RuntimeException("定时任务暂停失败"); - } - } -} diff --git a/backend/src/main/java/com/yfd/platform/utils/QuartzRunnable.java b/backend/src/main/java/com/yfd/platform/utils/QuartzRunnable.java deleted file mode 100644 index b1da541..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/QuartzRunnable.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.utils; - -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.util.ReflectionUtils; - -import java.lang.reflect.Method; -import java.util.concurrent.Callable; - -/** - * 执行定时任务 - * @author / - */ -@Slf4j -public class QuartzRunnable implements Callable { - - private final Object target; - private final Method method; - private final String params; - - QuartzRunnable(String beanName, String methodName, String params) - throws NoSuchMethodException, SecurityException { - this.target = SpringContextHolder.getBean(beanName); - this.params = params; - - if (StringUtils.isNotBlank(params)) { - this.method = target.getClass().getDeclaredMethod(methodName, String.class); - } else { - this.method = target.getClass().getDeclaredMethod(methodName); - } - } - - @Override - public Object call() throws Exception { - ReflectionUtils.makeAccessible(method); - if (StringUtils.isNotBlank(params)) { - method.invoke(target, params); - } else { - method.invoke(target); - } - return null; - } -} diff --git a/backend/src/main/java/com/yfd/platform/utils/RequestHolder.java b/backend/src/main/java/com/yfd/platform/utils/RequestHolder.java deleted file mode 100644 index 3dbfa55..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/RequestHolder.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.utils; - -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import jakarta.servlet.http.HttpServletRequest; -import java.util.Objects; - -/** - * 获取 HttpServletRequest - * @author - * @date 2018-11-24 - */ -public class RequestHolder { - - public static HttpServletRequest getHttpServletRequest() { - return ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest(); - } -} diff --git a/backend/src/main/java/com/yfd/platform/utils/RsaUtils.java b/backend/src/main/java/com/yfd/platform/utils/RsaUtils.java deleted file mode 100644 index 5c3e6c7..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/RsaUtils.java +++ /dev/null @@ -1,190 +0,0 @@ -package com.yfd.platform.utils; - -import org.apache.commons.codec.binary.Base64; - -import javax.crypto.Cipher; -import java.security.*; -import java.security.interfaces.RSAPrivateKey; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; - -/** - * @author https://www.cnblogs.com/nihaorz/p/10690643.html - * @description Rsa 工具类,公钥私钥生成,加解密 - * @date 2020-05-18 - **/ -public class RsaUtils { - - private static final String SRC = "123456"; - - public static void main(String[] args) throws Exception { - System.out.println("\n"); -// RsaKeyPair keyPair = generateKeyPair(); - String publicKey = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANL378k3RiZHWx5AfJqdH9xRNBmD9wGD2iRe41HdTNF8RUhNnHit5NpMNtGL0NPTSSpPjjI1kJfVorRvaQerUgkCAwEAAQ=="; - String privateKey = "MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8\n" + - "mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9p\n" + - "B6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue\n" + - "/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZ\n" + - "UBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6\n" + - "vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha\n" + - "4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3\n" + - "tTbklZkD2A=="; - RsaKeyPair keyPair =new RsaKeyPair(publicKey, privateKey); - System.out.println("私钥:" + keyPair.getPrivateKey()); - System.out.println("\n"); - test1(keyPair); - System.out.println("\n"); -// test2(keyPair); - System.out.println("\n"); - } - - /** - * 公钥加密私钥解密 - */ - private static void test1(RsaKeyPair keyPair) throws Exception { - System.out.println("***************** 公钥加密私钥解密开始 *****************"); - String text1 = encryptByPublicKey(keyPair.getPublicKey(), RsaUtils.SRC); - String text2 = decryptByPrivateKey(keyPair.getPrivateKey(), text1); - System.out.println("加密前:" + RsaUtils.SRC); - System.out.println("加密后:" + text1); - System.out.println("解密后:" + text2); - if (RsaUtils.SRC.equals(text2)) { - System.out.println("解密字符串和原始字符串一致,解密成功"); - } else { - System.out.println("解密字符串和原始字符串不一致,解密失败"); - } - System.out.println("***************** 公钥加密私钥解密结束 *****************"); - } - - /** - * 私钥加密公钥解密 - * @throws Exception / - */ - private static void test2(RsaKeyPair keyPair) throws Exception { - System.out.println("***************** 私钥加密公钥解密开始 *****************"); - String text1 = encryptByPrivateKey(keyPair.getPrivateKey(), RsaUtils.SRC); - String text2 = decryptByPublicKey(keyPair.getPublicKey(), text1); - System.out.println("加密前:" + RsaUtils.SRC); - System.out.println("加密后:" + text1); - System.out.println("解密后:" + text2); - if (RsaUtils.SRC.equals(text2)) { - System.out.println("解密字符串和原始字符串一致,解密成功"); - } else { - System.out.println("解密字符串和原始字符串不一致,解密失败"); - } - System.out.println("***************** 私钥加密公钥解密结束 *****************"); - } - - /** - * 公钥解密 - * - * @param publicKeyText 公钥 - * @param text 待解密的信息 - * @return / - * @throws Exception / - */ - public static String decryptByPublicKey(String publicKeyText, String text) throws Exception { - X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText)); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.DECRYPT_MODE, publicKey); - byte[] result = cipher.doFinal(Base64.decodeBase64(text)); - return new String(result); - } - - /** - * 私钥加密 - * - * @param privateKeyText 私钥 - * @param text 待加密的信息 - * @return / - * @throws Exception / - */ - public static String encryptByPrivateKey(String privateKeyText, String text) throws Exception { - PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText)); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, privateKey); - byte[] result = cipher.doFinal(text.getBytes()); - return Base64.encodeBase64String(result); - } - - /** - * 私钥解密 - * - * @param privateKeyText 私钥 - * @param text 待解密的文本 - * @return / - * @throws Exception / - */ - public static String decryptByPrivateKey(String privateKeyText, String text) throws Exception { - PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKeyText)); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5); - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.DECRYPT_MODE, privateKey); - byte[] result = cipher.doFinal(Base64.decodeBase64(text)); - return new String(result); - } - - /** - * 公钥加密 - * - * @param publicKeyText 公钥 - * @param text 待加密的文本 - * @return / - */ - public static String encryptByPublicKey(String publicKeyText, String text) throws Exception { - X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKeyText)); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec2); - Cipher cipher = Cipher.getInstance("RSA"); - cipher.init(Cipher.ENCRYPT_MODE, publicKey); - byte[] result = cipher.doFinal(text.getBytes()); - return Base64.encodeBase64String(result); - } - - /** - * 构建RSA密钥对 - * - * @return / - * @throws NoSuchAlgorithmException / - */ - public static RsaKeyPair generateKeyPair() throws NoSuchAlgorithmException { - KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); - keyPairGenerator.initialize(1024); - KeyPair keyPair = keyPairGenerator.generateKeyPair(); - RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); - RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); - String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded()); - String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded()); - return new RsaKeyPair(publicKeyString, privateKeyString); - } - - - /** - * RSA密钥对对象 - */ - public static class RsaKeyPair { - - private final String publicKey; - private final String privateKey; - - public RsaKeyPair(String publicKey, String privateKey) { - this.publicKey = publicKey; - this.privateKey = privateKey; - } - - public String getPublicKey() { - return publicKey; - } - - public String getPrivateKey() { - return privateKey; - } - - } -} diff --git a/backend/src/main/java/com/yfd/platform/utils/SecurityUtils.java b/backend/src/main/java/com/yfd/platform/utils/SecurityUtils.java deleted file mode 100644 index 9df23cd..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/SecurityUtils.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.utils; - -import cn.hutool.json.JSONArray; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import com.yfd.platform.exception.BadRequestException; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.HttpStatus; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; - -import java.util.List; - -/** - * 获取当前登录的用户 - * @author - * @date 2019-01-17 - */ -@Slf4j -public class SecurityUtils { - - /** - * 获取当前登录的用户 - * @return UserDetails - */ - public static UserDetails getCurrentUser() { - UserDetailsService userDetailsService = SpringContextHolder.getBean(UserDetailsService.class); - return userDetailsService.loadUserByUsername(getCurrentUsername()); - } - - /** - * 获取系统用户名称 - * - * @return 系统用户名称 - */ - public static String getCurrentUsername() { - final Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null) { - throw new BadRequestException(HttpStatus.UNAUTHORIZED, "当前登录状态过期"); - } - if (authentication.getPrincipal() instanceof UserDetails) { - UserDetails userDetails = (UserDetails) authentication.getPrincipal(); - return userDetails.getUsername(); - } - throw new BadRequestException(HttpStatus.UNAUTHORIZED, "找不到当前登录的信息"); - } - - /** - * 获取系统用户ID - * @return 系统用户ID - */ - public static Long getCurrentUserId() { - UserDetails userDetails = getCurrentUser(); - return new JSONObject(new JSONObject(userDetails).get("user")).get("id", Long.class); - } - - /** - * 获取当前用户的数据权限 - * @return / - */ - public static List getCurrentUserDataScope(){ - UserDetails userDetails = getCurrentUser(); - JSONArray array = JSONUtil.parseArray(new JSONObject(userDetails).get("dataScopes")); - return JSONUtil.toList(array,Long.class); - } - -} diff --git a/backend/src/main/java/com/yfd/platform/utils/SpringContextHolder.java b/backend/src/main/java/com/yfd/platform/utils/SpringContextHolder.java deleted file mode 100644 index b85c770..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/SpringContextHolder.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.utils; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.core.env.Environment; - -import java.util.ArrayList; -import java.util.List; -/** - * @author Jie - * @date 2019-01-07 - */ -@Slf4j -public class SpringContextHolder implements ApplicationContextAware, DisposableBean { - - private static ApplicationContext applicationContext = null; - private static final List CALL_BACKS = new ArrayList<>(); - private static boolean addCallback = true; - - /** - * 针对 某些初始化方法,在SpringContextHolder 未初始化时 提交回调方法。 - * 在SpringContextHolder 初始化后,进行回调使用 - * - * @param callBack 回调函数 - */ - public synchronized static void addCallBacks(CallBack callBack) { - if (addCallback) { - SpringContextHolder.CALL_BACKS.add(callBack); - } else { - log.warn("CallBack:{} 已无法添加!立即执行", callBack.getCallBackName()); - callBack.executor(); - } - } - - /** - * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. - */ - @SuppressWarnings("unchecked") - public static T getBean(String name) { - assertContextInjected(); - return (T) applicationContext.getBean(name); - } - - /** - * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. - */ - public static T getBean(Class requiredType) { - assertContextInjected(); - return applicationContext.getBean(requiredType); - } - - /** - * 获取SpringBoot 配置信息 - * - * @param property 属性key - * @param defaultValue 默认值 - * @param requiredType 返回类型 - * @return / - */ - public static T getProperties(String property, T defaultValue, Class requiredType) { - T result = defaultValue; - try { - result = getBean(Environment.class).getProperty(property, requiredType); - } catch (Exception ignored) {} - return result; - } - - /** - * 获取SpringBoot 配置信息 - * - * @param property 属性key - * @return / - */ - public static String getProperties(String property) { - return getProperties(property, null, String.class); - } - - /** - * 获取SpringBoot 配置信息 - * - * @param property 属性key - * @param requiredType 返回类型 - * @return / - */ - public static T getProperties(String property, Class requiredType) { - return getProperties(property, null, requiredType); - } - - /** - * 检查ApplicationContext不为空. - */ - private static void assertContextInjected() { - if (applicationContext == null) { - throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" + - ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder."); - } - } - - /** - * 清除SpringContextHolder中的ApplicationContext为Null. - */ - private static void clearHolder() { - log.debug("清除SpringContextHolder中的ApplicationContext:" - + applicationContext); - applicationContext = null; - } - - @Override - public void destroy() { - SpringContextHolder.clearHolder(); - } - - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - if (SpringContextHolder.applicationContext != null) { - log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext); - } - SpringContextHolder.applicationContext = applicationContext; - if (addCallback) { - for (CallBack callBack : SpringContextHolder.CALL_BACKS) { - callBack.executor(); - } - CALL_BACKS.clear(); - } - SpringContextHolder.addCallback = false; - } -} diff --git a/backend/src/main/java/com/yfd/platform/utils/StringUtils.java b/backend/src/main/java/com/yfd/platform/utils/StringUtils.java deleted file mode 100644 index b2a9be7..0000000 --- a/backend/src/main/java/com/yfd/platform/utils/StringUtils.java +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Copyright 2019-2020 Zheng Jie - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.yfd.platform.utils; - - -import cn.hutool.http.HttpUtil; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; -import com.yfd.platform.constant.Constant; -import lombok.SneakyThrows; -import org.lionsoul.ip2region.DataBlock; -import org.lionsoul.ip2region.DbConfig; -import org.lionsoul.ip2region.DbSearcher; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import eu.bitwalker.useragentutils.Browser; -import eu.bitwalker.useragentutils.UserAgent; -import jakarta.servlet.http.HttpServletRequest; -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.net.UnknownHostException; -import java.util.Calendar; -import java.util.Date; -import java.util.Enumeration; - -/** - * @author - * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类 - */ -public class StringUtils extends org.apache.commons.lang3.StringUtils { - - private static final Logger log = LoggerFactory.getLogger(StringUtils.class); - private static boolean ipLocal = false; - private static File file ; - private static DbConfig config; - private static final char SEPARATOR = '_'; - private static final String UNKNOWN = "unknown"; - - static { - SpringContextHolder.addCallBacks(() -> { - StringUtils.ipLocal = SpringContextHolder.getProperties("ip.local-parsing", false, Boolean.class); - if (ipLocal) { - /* - * 此文件为独享 ,不必关闭 - */ - String path = "ip2region/ip2region.db"; - String name = "ip2region.db"; - try { - config = new DbConfig(); - file = FileUtil.inputStreamToFile(new ClassPathResource(path).getInputStream(), name); - } catch (Exception e) { - log.error(e.getMessage(), e); - } - } - }); - } - - /** - * 驼峰命名法工具 - * - * @return toCamelCase(" hello_world ") == "helloWorld" - * toCapitalizeCamelCase("hello_world") == "HelloWorld" - * toUnderScoreCase("helloWorld") = "hello_world" - */ - public static String toCamelCase(String s) { - if (s == null) { - return null; - } - - s = s.toLowerCase(); - - StringBuilder sb = new StringBuilder(s.length()); - boolean upperCase = false; - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - - if (c == SEPARATOR) { - upperCase = true; - } else if (upperCase) { - sb.append(Character.toUpperCase(c)); - upperCase = false; - } else { - sb.append(c); - } - } - - return sb.toString(); - } - - /** - * 驼峰命名法工具 - * - * @return toCamelCase(" hello_world ") == "helloWorld" - * toCapitalizeCamelCase("hello_world") == "HelloWorld" - * toUnderScoreCase("helloWorld") = "hello_world" - */ - public static String toCapitalizeCamelCase(String s) { - if (s == null) { - return null; - } - s = toCamelCase(s); - return s.substring(0, 1).toUpperCase() + s.substring(1); - } - - /** - * 驼峰命名法工具 - * - * @return toCamelCase(" hello_world ") == "helloWorld" - * toCapitalizeCamelCase("hello_world") == "HelloWorld" - * toUnderScoreCase("helloWorld") = "hello_world" - */ - static String toUnderScoreCase(String s) { - if (s == null) { - return null; - } - - StringBuilder sb = new StringBuilder(); - boolean upperCase = false; - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - - boolean nextUpperCase = true; - - if (i < (s.length() - 1)) { - nextUpperCase = Character.isUpperCase(s.charAt(i + 1)); - } - - if ((i > 0) && Character.isUpperCase(c)) { - if (!upperCase || !nextUpperCase) { - sb.append(SEPARATOR); - } - upperCase = true; - } else { - upperCase = false; - } - - sb.append(Character.toLowerCase(c)); - } - - return sb.toString(); - } - - /** - * 获取ip地址 - */ - public static String getIp(HttpServletRequest request) { - String ip = request.getHeader("x-forwarded-for"); - if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { - ip = request.getHeader("Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { - ip = request.getHeader("WL-Proxy-Client-IP"); - } - if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) { - ip = request.getRemoteAddr(); - } - String comma = ","; - String localhost = "127.0.0.1"; - if (ip.contains(comma)) { - ip = ip.split(",")[0]; - } - if (localhost.equals(ip)) { - // 获取本机真正的ip地址 - try { - ip = InetAddress.getLocalHost().getHostAddress(); - } catch (UnknownHostException e) { - log.error(e.getMessage(), e); - } - } - return ip; - } - - /** - * 根据ip获取详细地址 - */ - @SneakyThrows - public static String getCityInfo(String ip) { - if (ipLocal) { - return getLocalCityInfo(ip); - } else { - return getHttpCityInfo(ip); - } - } - - /** - * 根据ip获取详细地址 - */ - public static String getHttpCityInfo(String ip) { - String host = "202.108.22.5"; - //超时应该在3钞以上 - int timeOut = 3000; - boolean status = false; - try { - status = InetAddress.getByName(host).isReachable(timeOut); - } catch (IOException e) { - e.printStackTrace(); - } - String api =""; - if (status){ - api = HttpUtil.get(String.format(Constant.Url.IP_URL, ip)); - }else { - api = "{\"ip\":\"127.0.0.1\",\"pro\":\"\",\"proCode\":\"999999\",\"city\":\"\",\"cityCode\":\"0\",\"region\":\"\",\"regionCode\":\"0\",\"addr\":\" 局域网\",\"regionNames\":\"\",\"err\":\"noprovince\"}"; - } - JSONObject object = JSONUtil.parseObj(api); - return object.get("addr", String.class); - } - - - /** - * 根据ip获取详细地址 - */ - public static String getLocalCityInfo(String ip) { - try { - DataBlock dataBlock = new DbSearcher(config, file.getPath()) - .binarySearch(ip); - String region = dataBlock.getRegion(); - String address = region.replace("0|", ""); - char symbol = '|'; - if (address.charAt(address.length() - 1) == symbol) { - address = address.substring(0, address.length() - 1); - } - return address.equals(Constant.REGION) ? "内网IP" : address; - } catch (Exception e) { - log.error(e.getMessage(), e); - } - return ""; - } - - public static String getBrowser(HttpServletRequest request) { - UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent")); - Browser browser = userAgent.getBrowser(); - return browser.getName(); - } - - /** - * 获得当天是周几 - */ - public static String getWeekDay() { - String[] weekDays = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; - Calendar cal = Calendar.getInstance(); - cal.setTime(new Date()); - - int w = cal.get(Calendar.DAY_OF_WEEK) - 1; - if (w < 0) { - w = 0; - } - return weekDays[w]; - } - - /** - * 获取当前机器的IP - * - * @return / - */ - public static String getLocalIp() { - try { - InetAddress candidateAddress = null; - // 遍历所有的网络接口 - for (Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); interfaces.hasMoreElements();) { - NetworkInterface anInterface = interfaces.nextElement(); - // 在所有的接口下再遍历IP - for (Enumeration inetAddresses = anInterface.getInetAddresses(); inetAddresses.hasMoreElements();) { - InetAddress inetAddr = inetAddresses.nextElement(); - // 排除loopback类型地址 - if (!inetAddr.isLoopbackAddress()) { - if (inetAddr.isSiteLocalAddress()) { - // 如果是site-local地址,就是它了 - return inetAddr.getHostAddress(); - } else if (candidateAddress == null) { - // site-local类型的地址未被发现,先记录候选地址 - candidateAddress = inetAddr; - } - } - } - } - if (candidateAddress != null) { - return candidateAddress.getHostAddress(); - } - // 如果没有发现 non-loopback地址.只能用最次选的方案 - InetAddress jdkSuppliedAddress = InetAddress.getLocalHost(); - if (jdkSuppliedAddress == null) { - return ""; - } - return jdkSuppliedAddress.getHostAddress(); - } catch (Exception e) { - return ""; - } - } -} diff --git a/backend/src/main/resources/application-dev.yml b/backend/src/main/resources/application-dev.yml deleted file mode 100644 index 37c1cdd..0000000 --- a/backend/src/main/resources/application-dev.yml +++ /dev/null @@ -1,94 +0,0 @@ -server: - port: 8093 - -spring: - #应用名称 - application: - name: Project-plateform - datasource: - type: com.alibaba.druid.pool.DruidDataSource - druid: - master: - driverClassName: dm.jdbc.driver.DmDriver - url: "${DB_MASTER_URL:jdbc:dm://localhost:5236/WPPDB}" - username: "${DB_MASTER_USERNAME:WPPDB}" - password: "${DB_MASTER_PASSWORD:}" - slave: - driverClassName: dm.jdbc.driver.DmDriver - url: "${DB_SLAVE_URL:jdbc:dm://localhost:5236/WPPDB}" - username: "${DB_SLAVE_USERNAME:WPPDB}" - password: "${DB_SLAVE_PASSWORD:}" - - mvc: - pathmatch: - matching-strategy: ant_path_matcher - servlet: - multipart: - max-file-size: 30MB - max-request-size: 100MB - -logging: - file: - name: logs/projectname.log - level: - com.genersoft.iot: debug - com.genersoft.iot.vmp.storager.dao: info - com.genersoft.iot.vmp.gb28181: info - -# 在线文档: swagger-ui(生产环境建议关闭) -swagger-ui: - enabled: true - - -# 登录相关配置 -login: - # 登录缓存 - cache-enable: true - # 是否限制单用户登录 - single-login: false - # 验证码 - login-code: - # 验证码类型配置 查看 LoginProperties 类 - code-type: arithmetic - -# 启动自动数据库初始化(仅 dev/server): -app: - init: - enabled: false - schema: classpath:db-init/sql/min-schema.sql - # data 文件可选;为避免复杂 dump 解析问题,先不导入 - # data: - marker-table: sys_user - marker-version: v1.0.0 - # 登录图形验证码有效时间/分钟 - expiration: 2 - # 验证码高度 - width: 111 - # 验证码宽度 - heigth: 36 - # 内容长度 - length: 2 - # 字体名称,为空则使用默认字体 - font-name: - # 字体大小 - font-size: 25 - -# IP 本地解析 -ip: - local-parsing: true - - -file-space: #项目文档空间 - files: D:\demoproject\files\ #单独上传的文件附件 - system: D:\demoproject\system\ #单独上传的文件 - -task: - pool: - # 核心线程池大小 - core-pool-size: 10 - # 最大线程数 - max-pool-size: 30 - # 活跃时间 - keep-alive-seconds: 60 - # 队列容量 - queue-capacity: 50 diff --git a/backend/src/main/resources/application-devtw.yml b/backend/src/main/resources/application-devtw.yml deleted file mode 100644 index f59a149..0000000 --- a/backend/src/main/resources/application-devtw.yml +++ /dev/null @@ -1,94 +0,0 @@ -server: - port: 8093 - -spring: - #应用名称 - application: - name: Project-plateform - datasource: - type: com.alibaba.druid.pool.DruidDataSource - druid: - master: - driverClassName: oracle.jdbc.OracleDriver - url: "${DB_MASTER_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" - username: "${DB_MASTER_USERNAME:QGC}" - password: "${DB_MASTER_PASSWORD:ar6Yr7Vxo5}" - slave: - driverClassName: oracle.jdbc.OracleDriver - url: "${DB_SLAVE_URL:jdbc:oracle:thin:@172.16.21.134:1521/SDLYZ}" - username: "${DB_SLAVE_USERNAME:QGC}" - password: "${DB_SLAVE_PASSWORD:ar6Yr7Vxo5}" - - mvc: - pathmatch: - matching-strategy: ant_path_matcher - servlet: - multipart: - max-file-size: 30MB - max-request-size: 100MB - -logging: - file: - name: logs/projectname.log - level: - com.genersoft.iot: debug - com.genersoft.iot.vmp.storager.dao: info - com.genersoft.iot.vmp.gb28181: info - -# 在线文档: swagger-ui(生产环境建议关闭) -swagger-ui: - enabled: true - - -# 登录相关配置 -login: - # 登录缓存 - cache-enable: true - # 是否限制单用户登录 - single-login: false - # 验证码 - login-code: - # 验证码类型配置 查看 LoginProperties 类 - code-type: arithmetic - -# 启动自动数据库初始化(仅 dev/server): -app: - init: - enabled: false - schema: classpath:db-init/sql/min-schema.sql - # data 文件可选;为避免复杂 dump 解析问题,先不导入 - # data: - marker-table: sys_user - marker-version: v1.0.0 - # 登录图形验证码有效时间/分钟 - expiration: 2 - # 验证码高度 - width: 111 - # 验证码宽度 - heigth: 36 - # 内容长度 - length: 2 - # 字体名称,为空则使用默认字体 - font-name: - # 字体大小 - font-size: 25 - -# IP 本地解析 -ip: - local-parsing: true - - -file-space: #项目文档空间 - files: D:\demoproject\files\ #单独上传的文件附件 - system: D:\demoproject\system\ #单独上传的文件 - -task: - pool: - # 核心线程池大小 - core-pool-size: 10 - # 最大线程数 - max-pool-size: 30 - # 活跃时间 - keep-alive-seconds: 60 - # 队列容量 - queue-capacity: 50 diff --git a/backend/src/main/resources/application-framework.yml b/backend/src/main/resources/application-framework.yml deleted file mode 100644 index 9baea68..0000000 --- a/backend/src/main/resources/application-framework.yml +++ /dev/null @@ -1,30 +0,0 @@ -jasypt: - encryptor: - password: ${JASYPT_PASSWORD:} - -# 密码加密传输,前端公钥加密,后端私钥解密(共性配置) -rsa: - private_key: ${RSA_PRIVATE_KEY:} - -# Actuator & Micrometer 默认配置(共性) -management: - endpoints: - web: - exposure: - include: health,info,metrics,prometheus,env,beans,threaddump,loggers,configprops - endpoint: - health: - show-details: always - metrics: - tags: - application: ${spring.application.name:platform} - - -# Springdoc 默认配置(共性) -springdoc: - api-docs: - enabled: true - swagger-ui: - enabled: true - path: /swagger-ui.html - packages-to-scan: com.yfd.platform diff --git a/backend/src/main/resources/application-server.yml b/backend/src/main/resources/application-server.yml deleted file mode 100644 index b4e0057..0000000 --- a/backend/src/main/resources/application-server.yml +++ /dev/null @@ -1,52 +0,0 @@ -server: - port: 8090 - -spring: - #应用名称 - application: - name: Project-plateform - datasource: - type: com.alibaba.druid.pool.DruidDataSource - druid: - master: - driverClassName: com.mysql.cj.jdbc.Driver - url: "${DB_MASTER_URL:jdbc:mysql://43.138.168.68:3306/frameworkdb2025?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true}" - username: "${DB_MASTER_USERNAME:root}" - password: "${DB_MASTER_PASSWORD:}" - - mvc: - pathmatch: - matching-strategy: ant_path_matcher - servlet: - multipart: - max-file-size: 30MB - max-request-size: 100MB - -logging: - file: - name: logs/projectname.log - - level: - com.genersoft.iot: debug - com.genersoft.iot.vmp.storager.dao: info - com.genersoft.iot.vmp.gb28181: info - -# 在线文档: swagger-ui(生产环境建议关闭) -swagger-ui: - enabled: false - -file-space: #项目文档空间 - files: D:\demoproject\files\ #单独上传的文件附件 - useravatar: D:\demoproject\useravatar\ #用户头像 - system: D:\demoproject\system\ #系统文档根目录,用于头像等静态资源 - -# 启动自动数据库初始化(仅 dev/server): -app: - init: - enabled: true - schema: classpath:db-init/sql/min-schema.sql - # data 文件可选;为避免复杂 dump 解析问题,先不导入 - # data: - marker-table: sys_user - marker-version: v1.0.0 - diff --git a/backend/src/main/resources/application.yml b/backend/src/main/resources/application.yml deleted file mode 100644 index 8f42778..0000000 --- a/backend/src/main/resources/application.yml +++ /dev/null @@ -1,34 +0,0 @@ -spring: - profiles: - active: devtw - -jasypt: - encryptor: - password: ${JASYPT_PASSWORD:} - -#密码加密传输,前端公钥加密,后端私钥解密 -rsa: - private_key: ${RSA_PRIVATE_KEY:MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A==} - -# Actuator & Micrometer 默认配置 -management: - endpoints: - web: - exposure: - include: health,info,metrics,prometheus,env,beans,threaddump,loggers,configprops - endpoint: - health: - show-details: always - metrics: - tags: - application: ${spring.application.name:platform} - - -# Springdoc 默认配置 -springdoc: - api-docs: - enabled: true - swagger-ui: - enabled: true - path: /swagger-ui.html - packages-to-scan: com.yfd.platform diff --git a/backend/src/main/resources/banner.txt b/backend/src/main/resources/banner.txt deleted file mode 100644 index 47e51d1..0000000 --- a/backend/src/main/resources/banner.txt +++ /dev/null @@ -1,8 +0,0 @@ - __ ____ ____ .___________. _______ ______ __ __ - | | \ \ / / | || ____| / || | | | - | | \ \/ / `---| |----`| |__ | ,----'| |__| | - .--. | | \_ _/ | | | __| | | | __ | - | `--' | | | | | | |____ | `----.| | | | - \______/ |__| |__| |_______| \______||__| |__| - - diff --git a/backend/src/main/resources/ip2region/ip2region.db b/backend/src/main/resources/ip2region/ip2region.db deleted file mode 100644 index e69de29..0000000 diff --git a/backend/src/main/resources/log4jdbc.log4j2.properties b/backend/src/main/resources/log4jdbc.log4j2.properties deleted file mode 100644 index 302525f..0000000 --- a/backend/src/main/resources/log4jdbc.log4j2.properties +++ /dev/null @@ -1,4 +0,0 @@ -# If you use SLF4J. First, you need to tell log4jdbc-log4j2 that you want to use the SLF4J logger -log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator -log4jdbc.auto.load.popular.drivers=false -log4jdbc.drivers=com.mysql.cj.jdbc.Driver \ No newline at end of file diff --git a/backend/src/main/resources/logback-spring.xml b/backend/src/main/resources/logback-spring.xml deleted file mode 100644 index 31a0ed8..0000000 --- a/backend/src/main/resources/logback-spring.xml +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - UTF-8 - ${LOG_PATTERN} - - - - - - ${LOG_PATH}/${LOG_FILE}.log - - UTF-8 - ${LOG_PATTERN} - - - ${LOG_PATH}/${LOG_FILE}.%d{yyyy-MM-dd}.log - 30 - - - - - - - - - - - - - \ No newline at end of file diff --git a/backend/src/main/resources/logback.xml b/backend/src/main/resources/logback.xml deleted file mode 100644 index c949c89..0000000 --- a/backend/src/main/resources/logback.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - yfAdmin - - - - - - - ${log.pattern} - ${log.charset} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/backend/src/main/resources/mapper/system/DictionaryMapper.xml b/backend/src/main/resources/mapper/system/DictionaryMapper.xml deleted file mode 100644 index 16edd1e..0000000 --- a/backend/src/main/resources/mapper/system/DictionaryMapper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/backend/src/main/resources/mapper/system/MessageMapper.xml b/backend/src/main/resources/mapper/system/MessageMapper.xml deleted file mode 100644 index 96cbcfc..0000000 --- a/backend/src/main/resources/mapper/system/MessageMapper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/backend/src/main/resources/mapper/system/Model3dMapper.xml b/backend/src/main/resources/mapper/system/Model3dMapper.xml deleted file mode 100644 index d935f68..0000000 --- a/backend/src/main/resources/mapper/system/Model3dMapper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/backend/src/main/resources/mapper/system/QuartzJobMapper.xml b/backend/src/main/resources/mapper/system/QuartzJobMapper.xml deleted file mode 100644 index b523b0a..0000000 --- a/backend/src/main/resources/mapper/system/QuartzJobMapper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/backend/src/main/resources/mapper/system/SysConfigMapper.xml b/backend/src/main/resources/mapper/system/SysConfigMapper.xml deleted file mode 100644 index cf22aa4..0000000 --- a/backend/src/main/resources/mapper/system/SysConfigMapper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/backend/src/main/resources/mapper/system/SysDictionaryItemsMapper.xml b/backend/src/main/resources/mapper/system/SysDictionaryItemsMapper.xml deleted file mode 100644 index 1bf0942..0000000 --- a/backend/src/main/resources/mapper/system/SysDictionaryItemsMapper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/backend/src/main/resources/mapper/system/SysDictionaryMapper.xml b/backend/src/main/resources/mapper/system/SysDictionaryMapper.xml deleted file mode 100644 index 6963e40..0000000 --- a/backend/src/main/resources/mapper/system/SysDictionaryMapper.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - diff --git a/backend/src/main/resources/mapper/system/SysLogMapper.xml b/backend/src/main/resources/mapper/system/SysLogMapper.xml deleted file mode 100644 index 1046de9..0000000 --- a/backend/src/main/resources/mapper/system/SysLogMapper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/backend/src/main/resources/mapper/system/SysMenuMapper.xml b/backend/src/main/resources/mapper/system/SysMenuMapper.xml deleted file mode 100644 index 85869c7..0000000 --- a/backend/src/main/resources/mapper/system/SysMenuMapper.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - update sys_menu set orderno=orderno+1 where parentid=#{parentid} and orderno < #{Orderno} and orderno >= #{upOrderno} - - - - - update sys_menu SET orderno=orderno-1 where parentid=#{parentid} and orderno > #{Orderno} and orderno <= #{downOrderno} - - - - - - - - - - diff --git a/backend/src/main/resources/mapper/system/SysMessageMapper.xml b/backend/src/main/resources/mapper/system/SysMessageMapper.xml deleted file mode 100644 index cda7c6f..0000000 --- a/backend/src/main/resources/mapper/system/SysMessageMapper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/backend/src/main/resources/mapper/system/SysOrganizationMapper.xml b/backend/src/main/resources/mapper/system/SysOrganizationMapper.xml deleted file mode 100644 index 053c5ae..0000000 --- a/backend/src/main/resources/mapper/system/SysOrganizationMapper.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - diff --git a/backend/src/main/resources/mapper/system/SysQuartzJobMapper.xml b/backend/src/main/resources/mapper/system/SysQuartzJobMapper.xml deleted file mode 100644 index 268cb3d..0000000 --- a/backend/src/main/resources/mapper/system/SysQuartzJobMapper.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/backend/src/main/resources/mapper/system/SysRoleMapper.xml b/backend/src/main/resources/mapper/system/SysRoleMapper.xml deleted file mode 100644 index c2c0d97..0000000 --- a/backend/src/main/resources/mapper/system/SysRoleMapper.xml +++ /dev/null @@ -1,150 +0,0 @@ - - - - - INSERT INTO sys_role_menu - - - id, - - - roleid, - - - menuid - - - - - #{id}, - - - #{roleid}, - - - #{menuid} - - - - - - - - - - - - - - - - - - - - - - - - - delete from sys_role_users where userid !=(select u.id from sys_user u where u.account="admin") and roleid=#{roleid} and userid=#{urserid} - - - - - DELETE FROM sys_role_menu WHERE roleid= #{id} - - - - - DELETE FROM sys_role_users WHERE roleid= #{id} - - diff --git a/backend/src/main/resources/mapper/system/SysUserMapper.xml b/backend/src/main/resources/mapper/system/SysUserMapper.xml deleted file mode 100644 index dfc56f0..0000000 --- a/backend/src/main/resources/mapper/system/SysUserMapper.xml +++ /dev/null @@ -1,116 +0,0 @@ - - - - - - - - - - - insert into sys_role_users values (#{id},#{roleid},#{userid}) - - - - - - - - - - - - - - - - - - delete from sys_role_users where userid=#{userid} - - - - delete from sys_role_users - where - userid=#{userid} - and roleid not in - - #{roleids} - - - - DELETE FROM sys_role_users WHERE userid IN - - #{id} - - - - diff --git a/backend/src/main/resources/quartz.properties b/backend/src/main/resources/quartz.properties deleted file mode 100644 index 03d3988..0000000 --- a/backend/src/main/resources/quartz.properties +++ /dev/null @@ -1,21 +0,0 @@ -######################################## -# Quartz 默认配置示例(RAMJobStore) -######################################## - -org.quartz.scheduler.instanceName = PlatformScheduler -org.quartz.scheduler.instanceId = AUTO - -# 线程池配置 -org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool -org.quartz.threadPool.threadCount = 10 -org.quartz.threadPool.threadPriority = 5 - -# 使用内存存储(如需持久化请改为 JobStoreTX 并配置数据源) -org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore - -# Misfire 阈值 -org.quartz.jobStore.misfireThreshold = 60000 - -# 插件(可选):关闭时清理 -org.quartz.plugin.shutdownHook.class = org.quartz.plugins.management.ShutdownHookPlugin -org.quartz.plugin.shutdownHook.cleanShutdown = true \ No newline at end of file diff --git a/backend/src/main/resources/static/assets/401-099a3a32.js b/backend/src/main/resources/static/assets/401-099a3a32.js deleted file mode 100644 index 314a602..0000000 --- a/backend/src/main/resources/static/assets/401-099a3a32.js +++ /dev/null @@ -1 +0,0 @@ -import{d as k,a9 as v,aa as x,c as V,g as o,w as s,a as i,Q as C,e as l,I as y,o as R,j as a,i as e,U as z,_ as B}from"./index-b25f0d08.js";const G={class:"errPage-container"},N={class:"list-unstyled"},U={class:"link-type"},j=["src"],I=["src"],P={name:"Page401"},h=k({...P,setup(E){const u=v({errGif:new URL("/assets/401-a61ddb94.gif",self.location).href,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}),{errGif:p,ewizardClap:_,dialogVisible:n}=x(u),f=y();function m(){f.back()}return(L,t)=>{const c=l("el-button"),b=l("router-link"),r=l("el-col"),g=l("el-row"),w=l("el-dialog");return R(),V("div",G,[o(c,{icon:"el-icon-arrow-left",class:"pan-back-btn",onClick:m},{default:s(()=>[...t[2]||(t[2]=[a(" 返回 ",-1)])]),_:1}),o(g,null,{default:s(()=>[o(r,{span:12},{default:s(()=>[t[6]||(t[6]=e("h1",{class:"text-jumbo text-ginormous"},"Oops!",-1)),t[7]||(t[7]=a(" gif来源",-1)),t[8]||(t[8]=e("a",{href:"https://zh.airbnb.com/",target:"_blank"},"airbnb",-1)),t[9]||(t[9]=a(" 页面 ",-1)),t[10]||(t[10]=e("h2",null,"你没有权限去该页面",-1)),t[11]||(t[11]=e("h6",null,"如有不满请联系你领导",-1)),e("ul",N,[t[4]||(t[4]=e("li",null,"或者你可以去:",-1)),e("li",U,[o(b,{to:"/dashboard"},{default:s(()=>[...t[3]||(t[3]=[a(" 回首页 ",-1)])]),_:1})]),t[5]||(t[5]=e("li",{class:"link-type"},[e("a",{href:"https://www.taobao.com/"},"随便看看")],-1)),e("li",null,[e("a",{href:"#",onClick:t[0]||(t[0]=z(d=>n.value=!0,["prevent"]))},"点我看图")])])]),_:1}),o(r,{span:12},{default:s(()=>[e("img",{src:i(p),width:"313",height:"428",alt:"Girl has dropped her ice cream."},null,8,j)]),_:1})]),_:1}),o(w,{modelValue:i(n),"onUpdate:modelValue":t[1]||(t[1]=d=>C(n)?n.value=d:null),title:"随便看"},{default:s(()=>[e("img",{src:i(_),class:"pan-img"},null,8,I)]),_:1},8,["modelValue"])])}}});const O=B(h,[["__scopeId","data-v-f88583c8"]]);export{O as default}; diff --git a/backend/src/main/resources/static/assets/401-485a4475.js b/backend/src/main/resources/static/assets/401-485a4475.js deleted file mode 100644 index 390a98a..0000000 --- a/backend/src/main/resources/static/assets/401-485a4475.js +++ /dev/null @@ -1 +0,0 @@ -import{d as v,aa as x,ab as V,c as C,f as t,w as o,a as i,S as y,i as a,M as I,o as R,j as _,h as e,W as S,J as z,K as B,_ as G}from"./index-5c62e6c4.js";const s=l=>(z("data-v-25007613"),l=l(),B(),l),N={class:"errPage-container"},j=s(()=>e("h1",{class:"text-jumbo text-ginormous"},"Oops!",-1)),M=s(()=>e("a",{href:"https://zh.airbnb.com/",target:"_blank"},"airbnb",-1)),P=s(()=>e("h2",null,"你没有权限去该页面",-1)),U=s(()=>e("h6",null,"如有不满请联系你领导",-1)),E={class:"list-unstyled"},J=s(()=>e("li",null,"或者你可以去:",-1)),K={class:"link-type"},L=s(()=>e("li",{class:"link-type"},[e("a",{href:"https://www.taobao.com/"},"随便看看")],-1)),O=["src"],T=["src"],W={name:"Page401"},$=v({...W,setup(l){const u=x({errGif:new URL("/assets/401-a61ddb94.gif",self.location).href,ewizardClap:"https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646",dialogVisible:!1}),{errGif:p,ewizardClap:f,dialogVisible:n}=V(u),h=I();function m(){h.back()}return(q,c)=>{const b=a("el-button"),g=a("router-link"),r=a("el-col"),w=a("el-row"),k=a("el-dialog");return R(),C("div",N,[t(b,{icon:"el-icon-arrow-left",class:"pan-back-btn",onClick:m},{default:o(()=>[_(" 返回 ")]),_:1}),t(w,null,{default:o(()=>[t(r,{span:12},{default:o(()=>[j,_(" gif来源"),M,_(" 页面 "),P,U,e("ul",E,[J,e("li",K,[t(g,{to:"/dashboard"},{default:o(()=>[_(" 回首页 ")]),_:1})]),L,e("li",null,[e("a",{href:"#",onClick:c[0]||(c[0]=S(d=>n.value=!0,["prevent"]))},"点我看图")])])]),_:1}),t(r,{span:12},{default:o(()=>[e("img",{src:i(p),width:"313",height:"428",alt:"Girl has dropped her ice cream."},null,8,O)]),_:1})]),_:1}),t(k,{modelValue:i(n),"onUpdate:modelValue":c[1]||(c[1]=d=>y(n)?n.value=d:null),title:"随便看"},{default:o(()=>[e("img",{src:i(f),class:"pan-img"},null,8,T)]),_:1},8,["modelValue"])])}}});const D=G($,[["__scopeId","data-v-25007613"]]);export{D as default}; diff --git a/backend/src/main/resources/static/assets/401-a61ddb94.gif b/backend/src/main/resources/static/assets/401-a61ddb94.gif deleted file mode 100644 index cd6e0d9433421b3f29d0ec0c40f755e354728000..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164227 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⋘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 GY5fOuZZib{ diff --git a/backend/src/main/resources/static/assets/401-fffd1e4b.css b/backend/src/main/resources/static/assets/401-fffd1e4b.css deleted file mode 100644 index 6a09eaa..0000000 --- a/backend/src/main/resources/static/assets/401-fffd1e4b.css +++ /dev/null @@ -1 +0,0 @@ -.errPage-container[data-v-f88583c8]{width:800px;max-width:100%;margin:100px auto}.errPage-container .pan-back-btn[data-v-f88583c8]{background:#008489;color:#fff;border:none!important}.errPage-container .pan-gif[data-v-f88583c8]{margin:0 auto;display:block}.errPage-container .pan-img[data-v-f88583c8]{display:block;margin:0 auto;width:100%}.errPage-container .text-jumbo[data-v-f88583c8]{font-size:60px;font-weight:700;color:#484848}.errPage-container .list-unstyled[data-v-f88583c8]{font-size:14px}.errPage-container .list-unstyled li[data-v-f88583c8]{padding-bottom:5px}.errPage-container .list-unstyled a[data-v-f88583c8]{color:#008489;text-decoration:none}.errPage-container .list-unstyled a[data-v-f88583c8]:hover{text-decoration:underline} diff --git a/backend/src/main/resources/static/assets/404-51ac6f86.css b/backend/src/main/resources/static/assets/404-51ac6f86.css deleted file mode 100644 index 52dce10..0000000 --- a/backend/src/main/resources/static/assets/404-51ac6f86.css +++ /dev/null @@ -1 +0,0 @@ -.wscn-http404-container[data-v-578ebab8]{transform:translate(-50%,-50%);position:absolute;top:40%;left:50%}.wscn-http404[data-v-578ebab8]{position:relative;width:1200px;padding:0 50px;overflow:hidden}.wscn-http404 .pic-404[data-v-578ebab8]{position:relative;float:left;width:600px;overflow:hidden}.wscn-http404 .pic-404__parent[data-v-578ebab8]{width:100%}.wscn-http404 .pic-404__child[data-v-578ebab8]{position:absolute}.wscn-http404 .pic-404__child.left[data-v-578ebab8]{width:80px;top:17px;left:220px;opacity:0;animation-name:cloudLeft-578ebab8;animation-duration:2s;animation-timing-function:linear;animation-fill-mode:forwards;animation-delay:1s}.wscn-http404 .pic-404__child.mid[data-v-578ebab8]{width:46px;top:10px;left:420px;opacity:0;animation-name:cloudMid-578ebab8;animation-duration:2s;animation-timing-function:linear;animation-fill-mode:forwards;animation-delay:1.2s}.wscn-http404 .pic-404__child.right[data-v-578ebab8]{width:62px;top:100px;left:500px;opacity:0;animation-name:cloudRight-578ebab8;animation-duration:2s;animation-timing-function:linear;animation-fill-mode:forwards;animation-delay:1s}@keyframes cloudLeft-578ebab8{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@keyframes cloudMid-578ebab8{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@keyframes cloudRight-578ebab8{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}.wscn-http404 .bullshit[data-v-578ebab8]{position:relative;float:left;width:300px;padding:30px 0;overflow:hidden}.wscn-http404 .bullshit__oops[data-v-578ebab8]{font-size:32px;font-weight:700;line-height:40px;color:#1482f0;opacity:0;margin-bottom:20px;animation-name:slideUp-578ebab8;animation-duration:.5s;animation-fill-mode:forwards}.wscn-http404 .bullshit__headline[data-v-578ebab8]{font-size:20px;line-height:24px;color:#222;font-weight:700;opacity:0;margin-bottom:10px;animation-name:slideUp-578ebab8;animation-duration:.5s;animation-delay:.1s;animation-fill-mode:forwards}.wscn-http404 .bullshit__info[data-v-578ebab8]{font-size:13px;line-height:21px;color:gray;opacity:0;margin-bottom:30px;animation-name:slideUp-578ebab8;animation-duration:.5s;animation-delay:.2s;animation-fill-mode:forwards}.wscn-http404 .bullshit__return-home[data-v-578ebab8]{display:block;float:left;width:110px;height:36px;background:#1482f0;border-radius:100px;text-align:center;color:#fff;opacity:0;font-size:14px;line-height:36px;cursor:pointer;animation-name:slideUp-578ebab8;animation-duration:.5s;animation-delay:.3s;animation-fill-mode:forwards}@keyframes slideUp-578ebab8{0%{transform:translateY(60px);opacity:0}to{transform:translateY(0);opacity:1}} diff --git a/backend/src/main/resources/static/assets/404-538aa4d7.png b/backend/src/main/resources/static/assets/404-538aa4d7.png deleted file mode 100644 index 3d8e2305cc973ad2121403aee4bf08728f76c461..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98071 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 diff --git a/backend/src/main/resources/static/assets/404-6dcbdda2.js b/backend/src/main/resources/static/assets/404-6dcbdda2.js deleted file mode 100644 index 7deafbf..0000000 --- a/backend/src/main/resources/static/assets/404-6dcbdda2.js +++ /dev/null @@ -1 +0,0 @@ -import{d as l,c as i,i as s,af as o,j as c,t as r,o as n,_}from"./index-b25f0d08.js";const d="/assets/404-538aa4d7.png",e="/assets/404_cloud-98e7ac66.png",p={class:"wscn-http404-container"},b={name:"Page404"},u=l({...b,setup(h){function a(){return"The webmaster said that you can not enter this page..."}return(m,t)=>(n(),i("div",p,[s("div",{class:"wscn-http404"},[t[4]||(t[4]=o('
404404404404
',1)),s("div",{class:"bullshit"},[t[0]||(t[0]=s("div",{class:"bullshit__oops"},"OOPS!",-1)),t[1]||(t[1]=s("div",{class:"bullshit__info"},[c(" All rights reserved "),s("a",{style:{color:"#20a0ff"},href:"https://wallstreetcn.com",target:"_blank"},"wallstreetcn")],-1)),s("div",{class:"bullshit__headline"},r(a)),t[2]||(t[2]=s("div",{class:"bullshit__info"}," Please check that the URL you entered is correct, or click the button below to return to the homepage. ",-1)),t[3]||(t[3]=s("a",{href:"",class:"bullshit__return-home"},"Back to home",-1))])])]))}});const f=_(u,[["__scopeId","data-v-578ebab8"]]);export{f as default}; diff --git a/backend/src/main/resources/static/assets/404-ae343fa7.js b/backend/src/main/resources/static/assets/404-ae343fa7.js deleted file mode 100644 index 51a23cb..0000000 --- a/backend/src/main/resources/static/assets/404-ae343fa7.js +++ /dev/null @@ -1 +0,0 @@ -import{d as o,c as _,h as t,t as i,ag as l,J as n,K as d,j as r,o as h,_ as p}from"./index-5c62e6c4.js";const f="/assets/404-538aa4d7.png",a="/assets/404_cloud-98e7ac66.png",e=s=>(n("data-v-ec8f1f5a"),s=s(),d(),s),u={class:"wscn-http404-container"},m=l('
404404404404
',1),v=e(()=>t("div",{class:"bullshit__oops"},"OOPS!",-1)),g=e(()=>t("div",{class:"bullshit__info"},[r(" All rights reserved "),t("a",{style:{color:"#20a0ff"},href:"https://wallstreetcn.com",target:"_blank"},"wallstreetcn")],-1)),b=e(()=>t("div",{class:"bullshit__info"}," Please check that the URL you entered is correct, or click the button below to return to the homepage. ",-1)),w=e(()=>t("a",{href:"",class:"bullshit__return-home"},"Back to home",-1)),k={name:"Page404"},y=o({...k,setup(s){function c(){return"The webmaster said that you can not enter this page..."}return(S,x)=>(h(),_("div",u,[t("div",{class:"wscn-http404"},[m,t("div",{class:"bullshit"},[v,g,t("div",{class:"bullshit__headline"},i(c)),b,w])])]))}});const I=p(y,[["__scopeId","data-v-ec8f1f5a"]]);export{I as default}; diff --git a/backend/src/main/resources/static/assets/404_cloud-98e7ac66.png b/backend/src/main/resources/static/assets/404_cloud-98e7ac66.png deleted file mode 100644 index c6281d09013e0a2c5f8e699a0a6038d9480291e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4766 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 diff --git a/backend/src/main/resources/static/assets/BarChart-a4765ae3.js b/backend/src/main/resources/static/assets/BarChart-a4765ae3.js deleted file mode 100644 index 95b45f0..0000000 --- a/backend/src/main/resources/static/assets/BarChart-a4765ae3.js +++ /dev/null @@ -1 +0,0 @@ -import{r as c,i as f,L as a}from"./resize-9f0962b6.js";import{d as m,I as y,aq as u,ar as x,k as h,a4 as p,o as g,c as b,X as S,p as v}from"./index-5c62e6c4.js";const w=["id"],L=m({__name:"BarChart",props:{id:{type:String,default:"barChart"},className:{type:String,default:""},width:{type:String,default:"200px",required:!0},height:{type:String,default:"200px",required:!0}},setup(e){const o=e,{mounted:i,chart:r,beforeDestroy:n,activated:l,deactivated:s}=c();function d(){const t=f(document.getElementById(o.id));t.setOption({title:{show:!0,text:"业绩总览",x:"center",padding:15,textStyle:{fontSize:18,fontStyle:"normal",fontWeight:"bold",color:"#337ecc"}},grid:{left:"2%",right:"2%",bottom:"10%",containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"cross",crossStyle:{color:"#999"}}},legend:{x:"center",y:"bottom",data:["收入","毛利润","收入增长率","利润增长率"]},xAxis:[{type:"category",data:["浙江","北京","上海","广东","深圳"],axisPointer:{type:"shadow"}}],yAxis:[{type:"value",min:0,max:1e4,interval:2e3,axisLabel:{formatter:"{value} "}},{type:"value",min:0,max:100,interval:20,axisLabel:{formatter:"{value}%"}}],series:[{name:"收入",type:"bar",data:[7e3,7100,7200,7300,7400],barWidth:20,itemStyle:{color:new a(0,0,0,1,[{offset:0,color:"#83bff6"},{offset:.5,color:"#188df0"},{offset:1,color:"#188df0"}])}},{name:"毛利润",type:"bar",data:[8e3,8200,8400,8600,8800],barWidth:20,itemStyle:{color:new a(0,0,0,1,[{offset:0,color:"#25d73c"},{offset:.5,color:"#1bc23d"},{offset:1,color:"#179e61"}])}},{name:"收入增长率",type:"line",yAxisIndex:1,data:[60,65,70,75,80],itemStyle:{color:"#67C23A"}},{name:"利润增长率",type:"line",yAxisIndex:1,data:[70,75,80,85,90],itemStyle:{color:"#409EFF"}}]}),r.value=t}return y(()=>{n()}),u(()=>{l()}),x(()=>{s()}),h(()=>{i(),p(()=>{d()})}),(t,C)=>(g(),b("div",{id:e.id,class:S(e.className),style:v({height:e.height,width:e.width})},null,14,w))}});export{L as default}; diff --git a/backend/src/main/resources/static/assets/BarChart-efd5cbe1.js b/backend/src/main/resources/static/assets/BarChart-efd5cbe1.js deleted file mode 100644 index 87b1a1e..0000000 --- a/backend/src/main/resources/static/assets/BarChart-efd5cbe1.js +++ /dev/null @@ -1 +0,0 @@ -import{r as c,i as f,L as a}from"./resize-24879ea2.js";import{d as m,K as y,ap as u,aq as x,k as h,a3 as p,o as g,c as b,V as S,q as v}from"./index-b25f0d08.js";const w=["id"],L=m({__name:"BarChart",props:{id:{type:String,default:"barChart"},className:{type:String,default:""},width:{type:String,default:"200px",required:!0},height:{type:String,default:"200px",required:!0}},setup(e){const o=e,{mounted:i,chart:r,beforeDestroy:n,activated:l,deactivated:s}=c();function d(){const t=f(document.getElementById(o.id));t.setOption({title:{show:!0,text:"业绩总览",x:"center",padding:15,textStyle:{fontSize:18,fontStyle:"normal",fontWeight:"bold",color:"#337ecc"}},grid:{left:"2%",right:"2%",bottom:"10%",containLabel:!0},tooltip:{trigger:"axis",axisPointer:{type:"cross",crossStyle:{color:"#999"}}},legend:{x:"center",y:"bottom",data:["收入","毛利润","收入增长率","利润增长率"]},xAxis:[{type:"category",data:["浙江","北京","上海","广东","深圳"],axisPointer:{type:"shadow"}}],yAxis:[{type:"value",min:0,max:1e4,interval:2e3,axisLabel:{formatter:"{value} "}},{type:"value",min:0,max:100,interval:20,axisLabel:{formatter:"{value}%"}}],series:[{name:"收入",type:"bar",data:[7e3,7100,7200,7300,7400],barWidth:20,itemStyle:{color:new a(0,0,0,1,[{offset:0,color:"#83bff6"},{offset:.5,color:"#188df0"},{offset:1,color:"#188df0"}])}},{name:"毛利润",type:"bar",data:[8e3,8200,8400,8600,8800],barWidth:20,itemStyle:{color:new a(0,0,0,1,[{offset:0,color:"#25d73c"},{offset:.5,color:"#1bc23d"},{offset:1,color:"#179e61"}])}},{name:"收入增长率",type:"line",yAxisIndex:1,data:[60,65,70,75,80],itemStyle:{color:"#67C23A"}},{name:"利润增长率",type:"line",yAxisIndex:1,data:[70,75,80,85,90],itemStyle:{color:"#409EFF"}}]}),r.value=t}return y(()=>{n()}),u(()=>{l()}),x(()=>{s()}),h(()=>{i(),p(()=>{d()})}),(t,C)=>(g(),b("div",{id:e.id,class:S(e.className),style:v({height:e.height,width:e.width})},null,14,w))}});export{L as default}; diff --git a/backend/src/main/resources/static/assets/FunnelChart-79f3d5f7.js b/backend/src/main/resources/static/assets/FunnelChart-79f3d5f7.js deleted file mode 100644 index 0a2fd3d..0000000 --- a/backend/src/main/resources/static/assets/FunnelChart-79f3d5f7.js +++ /dev/null @@ -1 +0,0 @@ -import{r as s,i as u}from"./resize-24879ea2.js";import{d as c,K as m,ap as h,aq as f,k as p,a3 as y,o as g,c as S,V as b,q as v}from"./index-b25f0d08.js";const w=["id"],q=c({__name:"FunnelChart",props:{id:{type:String,default:"funnelChart"},className:{type:String,default:""},width:{type:String,default:"200px",required:!0},height:{type:String,default:"200px",required:!0}},setup(e){const n=e,{mounted:a,chart:i,beforeDestroy:o,activated:l,deactivated:r}=s();function d(){const t=u(document.getElementById(n.id));t.setOption({title:{show:!0,text:"订单线索转化漏斗图",x:"center",padding:15,textStyle:{fontSize:18,fontStyle:"normal",fontWeight:"bold",color:"#337ecc"}},grid:{left:"2%",right:"2%",bottom:"10%",containLabel:!0},legend:{x:"center",y:"bottom",data:["Show","Click","Visit","Inquiry","Order"]},series:[{name:"Funnel",type:"funnel",left:"20%",top:60,bottom:60,width:"60%",sort:"descending",gap:2,label:{show:!0,position:"inside"},labelLine:{length:10,lineStyle:{width:1,type:"solid"}},itemStyle:{borderColor:"#fff",borderWidth:1},emphasis:{label:{fontSize:20}},data:[{value:60,name:"Visit"},{value:40,name:"Inquiry"},{value:20,name:"Order"},{value:80,name:"Click"},{value:100,name:"Show"}]}]}),i.value=t}return m(()=>{o()}),h(()=>{l()}),f(()=>{r()}),p(()=>{a(),y(()=>{d()})}),(t,x)=>(g(),S("div",{id:e.id,class:b(e.className),style:v({height:e.height,width:e.width})},null,14,w))}});export{q as default}; diff --git a/backend/src/main/resources/static/assets/FunnelChart-8e41d306.js b/backend/src/main/resources/static/assets/FunnelChart-8e41d306.js deleted file mode 100644 index b4f80e1..0000000 --- a/backend/src/main/resources/static/assets/FunnelChart-8e41d306.js +++ /dev/null @@ -1 +0,0 @@ -import{r as s,i as u}from"./resize-9f0962b6.js";import{d as c,I as m,aq as h,ar as f,k as p,a4 as y,o as g,c as S,X as b,p as v}from"./index-5c62e6c4.js";const w=["id"],q=c({__name:"FunnelChart",props:{id:{type:String,default:"funnelChart"},className:{type:String,default:""},width:{type:String,default:"200px",required:!0},height:{type:String,default:"200px",required:!0}},setup(e){const n=e,{mounted:a,chart:i,beforeDestroy:o,activated:l,deactivated:r}=s();function d(){const t=u(document.getElementById(n.id));t.setOption({title:{show:!0,text:"订单线索转化漏斗图",x:"center",padding:15,textStyle:{fontSize:18,fontStyle:"normal",fontWeight:"bold",color:"#337ecc"}},grid:{left:"2%",right:"2%",bottom:"10%",containLabel:!0},legend:{x:"center",y:"bottom",data:["Show","Click","Visit","Inquiry","Order"]},series:[{name:"Funnel",type:"funnel",left:"20%",top:60,bottom:60,width:"60%",sort:"descending",gap:2,label:{show:!0,position:"inside"},labelLine:{length:10,lineStyle:{width:1,type:"solid"}},itemStyle:{borderColor:"#fff",borderWidth:1},emphasis:{label:{fontSize:20}},data:[{value:60,name:"Visit"},{value:40,name:"Inquiry"},{value:20,name:"Order"},{value:80,name:"Click"},{value:100,name:"Show"}]}]}),i.value=t}return m(()=>{o()}),h(()=>{l()}),f(()=>{r()}),p(()=>{a(),y(()=>{d()})}),(t,x)=>(g(),S("div",{id:e.id,class:b(e.className),style:v({height:e.height,width:e.width})},null,14,w))}});export{q as default}; diff --git a/backend/src/main/resources/static/assets/PieChart-bffd7bcc.js b/backend/src/main/resources/static/assets/PieChart-bffd7bcc.js deleted file mode 100644 index 06edc6a..0000000 --- a/backend/src/main/resources/static/assets/PieChart-bffd7bcc.js +++ /dev/null @@ -1 +0,0 @@ -import{r as c,i as u}from"./resize-24879ea2.js";import{d as m,K as h,ap as f,aq as p,k as g,a3 as y,o as C,c as v,V as x,q as S}from"./index-b25f0d08.js";const b=["id"],z=m({__name:"PieChart",props:{id:{type:String,default:"pieChart"},className:{type:String,default:""},width:{type:String,default:"200px",required:!0},height:{type:String,default:"200px",required:!0}},setup(e){const i=e,{mounted:n,chart:o,beforeDestroy:r,activated:s,deactivated:d}=c();function l(){const t=u(document.getElementById(i.id));t.setOption({title:{show:!0,text:"产品分类总览",x:"center",padding:15,textStyle:{fontSize:18,fontStyle:"normal",fontWeight:"bold",color:"#337ecc"}},grid:{left:"2%",right:"2%",bottom:"10%",containLabel:!0},legend:{top:"bottom"},series:[{name:"Nightingale Chart",type:"pie",radius:[50,130],center:["50%","50%"],roseType:"area",itemStyle:{borderRadius:1,color:function(a){return["#409EFF","#67C23A","#E6A23C","#F56C6C"][a.dataIndex]}},data:[{value:26,name:"家用电器"},{value:27,name:"户外运动"},{value:24,name:"汽车用品"},{value:23,name:"手机数码"}]}]}),o.value=t}return h(()=>{r()}),f(()=>{s()}),p(()=>{d()}),g(()=>{n(),y(()=>{l()})}),(t,a)=>(C(),v("div",{id:e.id,class:x(e.className),style:S({height:e.height,width:e.width})},null,14,b))}});export{z as default}; diff --git a/backend/src/main/resources/static/assets/PieChart-f0d9d351.js b/backend/src/main/resources/static/assets/PieChart-f0d9d351.js deleted file mode 100644 index 8f6ea0a..0000000 --- a/backend/src/main/resources/static/assets/PieChart-f0d9d351.js +++ /dev/null @@ -1 +0,0 @@ -import{r as c,i as u}from"./resize-9f0962b6.js";import{d as m,I as h,aq as f,ar as p,k as g,a4 as y,o as C,c as v,X as x,p as S}from"./index-5c62e6c4.js";const b=["id"],B=m({__name:"PieChart",props:{id:{type:String,default:"pieChart"},className:{type:String,default:""},width:{type:String,default:"200px",required:!0},height:{type:String,default:"200px",required:!0}},setup(e){const i=e,{mounted:n,chart:o,beforeDestroy:r,activated:s,deactivated:d}=c();function l(){const t=u(document.getElementById(i.id));t.setOption({title:{show:!0,text:"产品分类总览",x:"center",padding:15,textStyle:{fontSize:18,fontStyle:"normal",fontWeight:"bold",color:"#337ecc"}},grid:{left:"2%",right:"2%",bottom:"10%",containLabel:!0},legend:{top:"bottom"},series:[{name:"Nightingale Chart",type:"pie",radius:[50,130],center:["50%","50%"],roseType:"area",itemStyle:{borderRadius:1,color:function(a){return["#409EFF","#67C23A","#E6A23C","#F56C6C"][a.dataIndex]}},data:[{value:26,name:"家用电器"},{value:27,name:"户外运动"},{value:24,name:"汽车用品"},{value:23,name:"手机数码"}]}]}),o.value=t}return h(()=>{r()}),f(()=>{s()}),p(()=>{d()}),g(()=>{n(),y(()=>{l()})}),(t,a)=>(C(),v("div",{id:e.id,class:x(e.className),style:S({height:e.height,width:e.width})},null,14,b))}});export{B as default}; diff --git a/backend/src/main/resources/static/assets/RadarChart-94b1112a.js b/backend/src/main/resources/static/assets/RadarChart-94b1112a.js deleted file mode 100644 index 3a44423..0000000 --- a/backend/src/main/resources/static/assets/RadarChart-94b1112a.js +++ /dev/null @@ -1 +0,0 @@ -import{r as l,i as m}from"./resize-9f0962b6.js";import{d as u,I as h,aq as f,ar as g,k as p,a4 as y,o as v,c as x,X as C,p as S}from"./index-5c62e6c4.js";const b=["id"],z=u({__name:"RadarChart",props:{id:{type:String,default:"radarChart"},className:{type:String,default:""},width:{type:String,default:"200px",required:!0},height:{type:String,default:"200px",required:!0}},setup(e){const n=e,{mounted:r,chart:i,beforeDestroy:o,activated:d,deactivated:s}=l();function c(){const t=m(document.getElementById(n.id));t.setOption({title:{show:!0,text:"订单状态统计",x:"center",padding:15,textStyle:{fontSize:18,fontStyle:"normal",fontWeight:"bold",color:"#337ecc"}},grid:{left:"2%",right:"2%",bottom:"10%",containLabel:!0},legend:{x:"center",y:"bottom",data:["预定数量","下单数量","发货数量"]},radar:{radius:"60%",indicator:[{name:"家用电器"},{name:"服装箱包"},{name:"运动户外"},{name:"手机数码"},{name:"汽车用品"},{name:"家具厨具"}]},series:[{name:"Budget vs spending",type:"radar",itemStyle:{borderRadius:6,color:function(a){return["#409EFF","#67C23A","#E6A23C","#F56C6C"][a.dataIndex]}},data:[{value:[400,400,400,400,400,400],name:"预定数量"},{value:[300,300,300,300,300,300],name:"下单数量"},{value:[200,200,200,200,200,200],name:"发货数量"}]}]}),i.value=t}return h(()=>{o()}),f(()=>{d()}),g(()=>{s()}),p(()=>{r(),y(()=>{c()})}),(t,a)=>(v(),x("div",{id:e.id,class:C(e.className),style:S({height:e.height,width:e.width})},null,14,b))}});export{z as default}; diff --git a/backend/src/main/resources/static/assets/RadarChart-e43ec971.js b/backend/src/main/resources/static/assets/RadarChart-e43ec971.js deleted file mode 100644 index 5f5722d..0000000 --- a/backend/src/main/resources/static/assets/RadarChart-e43ec971.js +++ /dev/null @@ -1 +0,0 @@ -import{r as l,i as m}from"./resize-24879ea2.js";import{d as u,K as h,ap as f,aq as g,k as p,a3 as y,o as v,c as x,V as C,q as S}from"./index-b25f0d08.js";const b=["id"],w=u({__name:"RadarChart",props:{id:{type:String,default:"radarChart"},className:{type:String,default:""},width:{type:String,default:"200px",required:!0},height:{type:String,default:"200px",required:!0}},setup(e){const n=e,{mounted:r,chart:i,beforeDestroy:o,activated:d,deactivated:s}=l();function c(){const t=m(document.getElementById(n.id));t.setOption({title:{show:!0,text:"订单状态统计",x:"center",padding:15,textStyle:{fontSize:18,fontStyle:"normal",fontWeight:"bold",color:"#337ecc"}},grid:{left:"2%",right:"2%",bottom:"10%",containLabel:!0},legend:{x:"center",y:"bottom",data:["预定数量","下单数量","发货数量"]},radar:{radius:"60%",indicator:[{name:"家用电器"},{name:"服装箱包"},{name:"运动户外"},{name:"手机数码"},{name:"汽车用品"},{name:"家具厨具"}]},series:[{name:"Budget vs spending",type:"radar",itemStyle:{borderRadius:6,color:function(a){return["#409EFF","#67C23A","#E6A23C","#F56C6C"][a.dataIndex]}},data:[{value:[400,400,400,400,400,400],name:"预定数量"},{value:[300,300,300,300,300,300],name:"下单数量"},{value:[200,200,200,200,200,200],name:"发货数量"}]}]}),i.value=t}return h(()=>{o()}),f(()=>{d()}),g(()=>{s()}),p(()=>{r(),y(()=>{c()})}),(t,a)=>(v(),x("div",{id:e.id,class:C(e.className),style:S({height:e.height,width:e.width})},null,14,b))}});export{w as default}; diff --git a/backend/src/main/resources/static/assets/editor-501cf061.css b/backend/src/main/resources/static/assets/editor-501cf061.css deleted file mode 100644 index 50ac020..0000000 --- a/backend/src/main/resources/static/assets/editor-501cf061.css +++ /dev/null @@ -1 +0,0 @@ -:root,:host{--w-e-textarea-bg-color: #fff;--w-e-textarea-color: #333;--w-e-textarea-border-color: #ccc;--w-e-textarea-slight-border-color: #e8e8e8;--w-e-textarea-slight-color: #d4d4d4;--w-e-textarea-slight-bg-color: #f5f2f0;--w-e-textarea-selected-border-color: #B4D5FF;--w-e-textarea-handler-bg-color: #4290f7;--w-e-toolbar-color: #595959;--w-e-toolbar-bg-color: #fff;--w-e-toolbar-active-color: #333;--w-e-toolbar-active-bg-color: #f1f1f1;--w-e-toolbar-disabled-color: #999;--w-e-toolbar-border-color: #e8e8e8;--w-e-modal-button-bg-color: #fafafa;--w-e-modal-button-border-color: #d9d9d9}.w-e-text-container *,.w-e-toolbar *{box-sizing:border-box;margin:0;outline:none;padding:0}.w-e-text-container blockquote,.w-e-text-container li,.w-e-text-container p,.w-e-text-container td,.w-e-text-container th,.w-e-toolbar *{line-height:1.5}.w-e-text-container{background-color:var(--w-e-textarea-bg-color);color:var(--w-e-textarea-color);height:100%;position:relative}.w-e-text-container .w-e-scroll{-webkit-overflow-scrolling:touch;height:100%}.w-e-text-container [data-slate-editor]{word-wrap:break-word;border-top:1px solid transparent;min-height:100%;outline:0;padding:0 10px;white-space:pre-wrap}.w-e-text-container [data-slate-editor] p{margin:15px 0}.w-e-text-container [data-slate-editor] h1,.w-e-text-container [data-slate-editor] h2,.w-e-text-container [data-slate-editor] h3,.w-e-text-container [data-slate-editor] h4,.w-e-text-container [data-slate-editor] h5{margin:20px 0}.w-e-text-container [data-slate-editor] img{cursor:default;display:inline!important;max-width:100%;min-height:20px;min-width:20px}.w-e-text-container [data-slate-editor] span{text-indent:0}.w-e-text-container [data-slate-editor] [data-selected=true]{box-shadow:0 0 0 2px var(--w-e-textarea-selected-border-color)}.w-e-text-placeholder{font-style:italic;left:10px;top:17px;width:90%}.w-e-max-length-info,.w-e-text-placeholder{color:var(--w-e-textarea-slight-color);pointer-events:none;position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none}.w-e-max-length-info{bottom:.5em;right:1em}.w-e-bar{background-color:var(--w-e-toolbar-bg-color);color:var(--w-e-toolbar-color);font-size:14px;padding:0 5px}.w-e-bar svg{fill:var(--w-e-toolbar-color);height:14px;width:14px}.w-e-bar-show{display:flex}.w-e-bar-hidden{display:none}.w-e-hover-bar{border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 5px #0000001f;position:absolute}.w-e-toolbar{flex-wrap:wrap;position:relative}.w-e-bar-divider{background-color:var(--w-e-toolbar-border-color);display:inline-flex;height:40px;margin:0 5px;width:1px}.w-e-bar-item{display:flex;height:40px;padding:4px;position:relative;text-align:center}.w-e-bar-item,.w-e-bar-item button{align-items:center;justify-content:center}.w-e-bar-item button{background:transparent;border:none;color:var(--w-e-toolbar-color);cursor:pointer;display:inline-flex;height:32px;overflow:hidden;padding:0 8px;white-space:nowrap}.w-e-bar-item button:hover{background-color:var(--w-e-toolbar-active-bg-color);color:var(--w-e-toolbar-active-color)}.w-e-bar-item button .title{margin-left:5px}.w-e-bar-item .active{background-color:var(--w-e-toolbar-active-bg-color);color:var(--w-e-toolbar-active-color)}.w-e-bar-item .disabled{color:var(--w-e-toolbar-disabled-color);cursor:not-allowed}.w-e-bar-item .disabled svg{fill:var(--w-e-toolbar-disabled-color)}.w-e-bar-item .disabled:hover{background-color:var(--w-e-toolbar-bg-color);color:var(--w-e-toolbar-disabled-color)}.w-e-bar-item .disabled:hover svg{fill:var(--w-e-toolbar-disabled-color)}.w-e-menu-tooltip-v5:before{background-color:var(--w-e-toolbar-active-color);border-radius:5px;color:var(--w-e-toolbar-bg-color);content:attr(data-tooltip);font-size:.75em;opacity:0;padding:5px 10px;position:absolute;text-align:center;top:40px;transition:opacity .6s;visibility:hidden;white-space:pre;z-index:1}.w-e-menu-tooltip-v5:after{border:5px solid transparent;border-bottom:5px solid var(--w-e-toolbar-active-color);content:"";opacity:0;position:absolute;top:30px;transition:opacity .6s;visibility:hidden}.w-e-menu-tooltip-v5:hover:after,.w-e-menu-tooltip-v5:hover:before{opacity:1;visibility:visible}.w-e-menu-tooltip-v5.tooltip-right:before{left:100%;top:10px}.w-e-menu-tooltip-v5.tooltip-right:after{border-bottom-color:transparent;border-left-color:transparent;border-right-color:var(--w-e-toolbar-active-color);border-top-color:transparent;left:100%;margin-left:-10px;top:16px}.w-e-bar-item-group .w-e-bar-item-menus-container{background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 10px #0000001f;display:none;left:0;margin-top:40px;position:absolute;top:0;z-index:1}.w-e-bar-item-group:hover .w-e-bar-item-menus-container{display:block}.w-e-select-list{background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 10px #0000001f;left:0;margin-top:40px;max-height:350px;min-width:100px;overflow-y:auto;position:absolute;top:0;z-index:1}.w-e-select-list ul{line-height:1;list-style:none}.w-e-select-list ul .selected{background-color:var(--w-e-toolbar-active-bg-color)}.w-e-select-list ul li{cursor:pointer;padding:7px 0 7px 25px;position:relative;text-align:left;white-space:nowrap}.w-e-select-list ul li:hover{background-color:var(--w-e-toolbar-active-bg-color)}.w-e-select-list ul li svg{left:0;margin-left:5px;margin-top:-7px;position:absolute;top:50%}.w-e-bar-bottom .w-e-select-list{bottom:0;margin-bottom:40px;margin-top:0;top:inherit}.w-e-drop-panel{background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 10px #0000001f;margin-top:40px;min-width:200px;padding:10px;position:absolute;top:0;z-index:1}.w-e-bar-bottom .w-e-drop-panel{bottom:0;margin-bottom:40px;margin-top:0;top:inherit}.w-e-modal{background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;box-shadow:0 2px 10px #0000001f;color:var(--w-e-toolbar-color);font-size:14px;min-height:40px;min-width:100px;padding:20px 15px 0;position:absolute;text-align:left;z-index:1}.w-e-modal .btn-close{cursor:pointer;line-height:1;padding:5px;position:absolute;right:8px;top:7px}.w-e-modal .btn-close svg{fill:var(--w-e-toolbar-color);height:10px;width:10px}.w-e-modal .babel-container{display:block;margin-bottom:15px}.w-e-modal .babel-container span{display:block;margin-bottom:10px}.w-e-modal .button-container{margin-bottom:15px}.w-e-modal button{background-color:var(--w-e-modal-button-bg-color);border:1px solid var(--w-e-modal-button-border-color);border-radius:4px;color:var(--w-e-toolbar-color);cursor:pointer;font-weight:400;height:32px;padding:4.5px 15px;text-align:center;touch-action:manipulation;transition:all .3s cubic-bezier(.645,.045,.355,1);-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.w-e-modal input[type=number],.w-e-modal input[type=text],.w-e-modal textarea{font-feature-settings:"tnum";background-color:var(--w-e-toolbar-bg-color);border:1px solid var(--w-e-modal-button-border-color);border-radius:4px;color:var(--w-e-toolbar-color);font-variant:tabular-nums;padding:4.5px 11px;transition:all .3s;width:100%}.w-e-modal textarea{min-height:60px}body .w-e-modal,body .w-e-modal *{box-sizing:border-box}.w-e-progress-bar{background-color:var(--w-e-textarea-handler-bg-color);height:1px;position:absolute;transition:width .3s;width:0}.w-e-full-screen-container{bottom:0!important;display:flex!important;flex-direction:column!important;height:100%!important;left:0!important;margin:0!important;padding:0!important;position:fixed;right:0!important;top:0!important;width:100%!important}.w-e-full-screen-container [data-w-e-textarea=true]{flex:1!important}.w-e-text-container [data-slate-editor] code{background-color:var(--w-e-textarea-slight-bg-color);border-radius:3px;font-family:monospace;padding:3px}.w-e-panel-content-color{list-style:none;text-align:left;width:230px}.w-e-panel-content-color li{border:1px solid var(--w-e-toolbar-bg-color);border-radius:3px;cursor:pointer;display:inline-block;padding:2px}.w-e-panel-content-color li:hover{border-color:var(--w-e-toolbar-color)}.w-e-panel-content-color li .color-block{border:1px solid var(--w-e-toolbar-border-color);border-radius:3px;height:17px;width:17px}.w-e-panel-content-color .active{border-color:var(--w-e-toolbar-color)}.w-e-panel-content-color .clear{line-height:1.5;margin-bottom:5px;width:100%}.w-e-panel-content-color .clear svg{height:16px;margin-bottom:-4px;width:16px}.w-e-text-container [data-slate-editor] blockquote{background-color:var(--w-e-textarea-slight-bg-color);border-left:8px solid var(--w-e-textarea-selected-border-color);display:block;font-size:100%;line-height:1.5;margin:10px 0;padding:10px}.w-e-panel-content-emotion{font-size:20px;list-style:none;text-align:left;width:300px}.w-e-panel-content-emotion li{border-radius:3px;cursor:pointer;display:inline-block;padding:0 5px}.w-e-panel-content-emotion li:hover{background-color:var(--w-e-textarea-slight-bg-color)}.w-e-textarea-divider{border-radius:3px;margin:20px auto;padding:20px}.w-e-textarea-divider hr{background-color:var(--w-e-textarea-border-color);border:0;display:block;height:1px}.w-e-text-container [data-slate-editor] pre>code{background-color:var(--w-e-textarea-slight-bg-color);border:1px solid var(--w-e-textarea-slight-border-color);border-radius:4px;display:block;font-size:14px;padding:10px;text-indent:0}.w-e-text-container [data-slate-editor] .w-e-image-container{display:inline-block;margin:0 3px}.w-e-text-container [data-slate-editor] .w-e-image-container:hover{box-shadow:0 0 0 2px var(--w-e-textarea-selected-border-color)}.w-e-text-container [data-slate-editor] .w-e-selected-image-container{overflow:hidden;position:relative}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .w-e-image-dragger{background-color:var(--w-e-textarea-handler-bg-color);height:7px;position:absolute;width:7px}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .left-top{cursor:nwse-resize;left:0;top:0}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .right-top{cursor:nesw-resize;right:0;top:0}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .left-bottom{bottom:0;cursor:nesw-resize;left:0}.w-e-text-container [data-slate-editor] .w-e-selected-image-container .right-bottom{bottom:0;cursor:nwse-resize;right:0}.w-e-text-container [data-slate-editor] .w-e-selected-image-container:hover,.w-e-text-container [contenteditable=false] .w-e-image-container:hover{box-shadow:none}.w-e-text-container [data-slate-editor] .table-container{border:1px dashed var(--w-e-textarea-border-color);border-radius:5px;margin-top:10px;overflow-x:auto;padding:10px;width:100%}.w-e-text-container [data-slate-editor] table{border-collapse:collapse}.w-e-text-container [data-slate-editor] table td,.w-e-text-container [data-slate-editor] table th{border:1px solid var(--w-e-textarea-border-color);line-height:1.5;min-width:30px;padding:3px 5px;text-align:left}.w-e-text-container [data-slate-editor] table th{background-color:var(--w-e-textarea-slight-bg-color);font-weight:700;text-align:center}.w-e-panel-content-table{background-color:var(--w-e-toolbar-bg-color)}.w-e-panel-content-table table{border-collapse:collapse}.w-e-panel-content-table td{border:1px solid var(--w-e-toolbar-border-color);cursor:pointer;height:15px;padding:3px 5px;width:20px}.w-e-panel-content-table td.active{background-color:var(--w-e-toolbar-active-bg-color)}.w-e-textarea-video-container{background-image:linear-gradient(45deg,#eee 25%,transparent 0,transparent 75%,#eee 0,#eee),linear-gradient(45deg,#eee 25%,#fff 0,#fff 75%,#eee 0,#eee);background-position:0 0,10px 10px;background-size:20px 20px;border:1px dashed var(--w-e-textarea-border-color);border-radius:5px;margin:10px auto 0;padding:10px 0;text-align:center}.w-e-text-container [data-slate-editor] pre>code{word-wrap:normal;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;-webkit-hyphens:none;hyphens:none;line-height:1.5;margin:.5em 0;overflow:auto;padding:1em;-moz-tab-size:4;-o-tab-size:4;tab-size:4;text-align:left;text-shadow:0 1px #fff;white-space:pre;word-break:normal;word-spacing:normal}.w-e-text-container [data-slate-editor] pre>code .token.cdata,.w-e-text-container [data-slate-editor] pre>code .token.comment,.w-e-text-container [data-slate-editor] pre>code .token.doctype,.w-e-text-container [data-slate-editor] pre>code .token.prolog{color:#708090}.w-e-text-container [data-slate-editor] pre>code .token.punctuation{color:#999}.w-e-text-container [data-slate-editor] pre>code .token.namespace{opacity:.7}.w-e-text-container [data-slate-editor] pre>code .token.boolean,.w-e-text-container [data-slate-editor] pre>code .token.constant,.w-e-text-container [data-slate-editor] pre>code .token.deleted,.w-e-text-container [data-slate-editor] pre>code .token.number,.w-e-text-container [data-slate-editor] pre>code .token.property,.w-e-text-container [data-slate-editor] pre>code .token.symbol,.w-e-text-container [data-slate-editor] pre>code .token.tag{color:#905}.w-e-text-container [data-slate-editor] pre>code .token.attr-name,.w-e-text-container [data-slate-editor] pre>code .token.builtin,.w-e-text-container [data-slate-editor] pre>code .token.char,.w-e-text-container [data-slate-editor] pre>code .token.inserted,.w-e-text-container [data-slate-editor] pre>code .token.selector,.w-e-text-container [data-slate-editor] pre>code .token.string{color:#690}.w-e-text-container [data-slate-editor] pre>code .language-css .token.string,.w-e-text-container [data-slate-editor] pre>code .style .token.string,.w-e-text-container [data-slate-editor] pre>code .token.entity,.w-e-text-container [data-slate-editor] pre>code .token.operator,.w-e-text-container [data-slate-editor] pre>code .token.url{color:#9a6e3a}.w-e-text-container [data-slate-editor] pre>code .token.atrule,.w-e-text-container [data-slate-editor] pre>code .token.attr-value,.w-e-text-container [data-slate-editor] pre>code .token.keyword{color:#07a}.w-e-text-container [data-slate-editor] pre>code .token.class-name,.w-e-text-container [data-slate-editor] pre>code .token.function{color:#dd4a68}.w-e-text-container [data-slate-editor] pre>code .token.important,.w-e-text-container [data-slate-editor] pre>code .token.regex,.w-e-text-container [data-slate-editor] pre>code .token.variable{color:#e90}.w-e-text-container [data-slate-editor] pre>code .token.bold,.w-e-text-container [data-slate-editor] pre>code .token.important{font-weight:700}.w-e-text-container [data-slate-editor] pre>code .token.italic{font-style:italic}.w-e-text-container [data-slate-editor] pre>code .token.entity{cursor:help} diff --git a/backend/src/main/resources/static/assets/editor-b13c93a6.js b/backend/src/main/resources/static/assets/editor-b13c93a6.js deleted file mode 100644 index 65ea8e0..0000000 --- a/backend/src/main/resources/static/assets/editor-b13c93a6.js +++ /dev/null @@ -1,186 +0,0 @@ -import{d as N1,r as Eg,al as lP,k as u$,a2 as s$,o as I1,c as L1,a8 as l$,am as c$,a9 as cP,aa as fP,K as f$,g as Dg,a as $r,Q as d$,ad as yx,w as p$}from"./index-b25f0d08.js";import{u as h$}from"./index-5282e30f.js";var se=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function g$(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}function us(t){var e={exports:{}};return t(e,e.exports),e.exports}var yi,$0,Fh=function(t){return t&&t.Math==Math&&t},kt=Fh(typeof globalThis=="object"&&globalThis)||Fh(typeof window=="object"&&window)||Fh(typeof self=="object"&&self)||Fh(typeof se=="object"&&se)||function(){return this}()||Function("return this")(),r5=Function.prototype,bx=r5.apply,v$=r5.bind,wx=r5.call,dP=typeof Reflect=="object"&&Reflect.apply||(v$?wx.bind(bx):function(){return wx.apply(bx,arguments)}),pP=Function.prototype,w4=pP.bind,E4=pP.call,m$=w4&&w4.bind(E4),ge=w4?function(t){return t&&m$(E4,t)}:function(t){return t&&function(){return E4.apply(t,arguments)}},sn=function(t){return typeof t=="function"},Gn=function(t){try{return!!t()}catch{return!0}},Hn=!Gn(function(){return Object.defineProperty({},1,{get:function(){return 7}})[1]!=7}),kc=Function.prototype.call,zn=kc.bind?kc.bind(kc):function(){return kc.apply(kc,arguments)},Ex={}.propertyIsEnumerable,Dx=Object.getOwnPropertyDescriptor,y$=Dx&&!Ex.call({1:2},1)?function(t){var e=Dx(this,t);return!!e&&e.enumerable}:Ex,o5={f:y$},Xr=function(t,e){return{enumerable:!(1&t),configurable:!(2&t),writable:!(4&t),value:e}},b$=ge({}.toString),w$=ge("".slice),Du=function(t){return w$(b$(t),8,-1)},qm=kt.Object,E$=ge("".split),hP=Gn(function(){return!qm("z").propertyIsEnumerable(0)})?function(t){return Du(t)=="String"?E$(t,""):qm(t)}:qm,D$=kt.TypeError,i5=function(t){if(t==null)throw D$("Can't call method on "+t);return t},jo=function(t){return hP(i5(t))},tr=function(t){return typeof t=="object"?t!==null:sn(t)},Qn={},Cx=function(t){return sn(t)?t:void 0},oc=function(t,e){return arguments.length<2?Cx(Qn[t])||Cx(kt[t]):Qn[t]&&Qn[t][e]||kt[t]&&kt[t][e]},Td=ge({}.isPrototypeOf),Km=oc("navigator","userAgent")||"",xx=kt.process,Sx=kt.Deno,Ax=xx&&xx.versions||Sx&&Sx.version,Ox=Ax&&Ax.v8;Ox&&($0=(yi=Ox.split("."))[0]>0&&yi[0]<4?1:+(yi[0]+yi[1])),!$0&&Km&&(!(yi=Km.match(/Edge\/(\d+)/))||yi[1]>=74)&&(yi=Km.match(/Chrome\/(\d+)/))&&($0=+yi[1]);var _h,Cg=$0,ho=!!Object.getOwnPropertySymbols&&!Gn(function(){var t=Symbol();return!String(t)||!(Object(t)instanceof Symbol)||!Symbol.sham&&Cg&&Cg<41}),a5=ho&&!Symbol.sham&&typeof Symbol.iterator=="symbol",C$=kt.Object,hl=a5?function(t){return typeof t=="symbol"}:function(t){var e=oc("Symbol");return sn(e)&&Td(e.prototype,C$(t))},x$=kt.String,D4=function(t){try{return x$(t)}catch{return"Object"}},S$=kt.TypeError,u5=function(t){if(sn(t))return t;throw S$(D4(t)+" is not a function")},xg=function(t,e){var n=t[e];return n==null?void 0:u5(n)},A$=kt.TypeError,O$=Object.defineProperty,ea=kt["__core-js_shared__"]||function(t,e){try{O$(kt,t,{value:e,configurable:!0,writable:!0})}catch{kt[t]=e}return e}("__core-js_shared__",{}),ss=us(function(t){(t.exports=function(e,n){return ea[e]||(ea[e]=n!==void 0?n:{})})("versions",[]).push({version:"3.19.3",mode:"pure",copyright:"© 2021 Denis Pushkarev (zloirock.ru)"})}),k$=kt.Object,Fp=function(t){return k$(i5(t))},B$=ge({}.hasOwnProperty),Vt=Object.hasOwn||function(t,e){return B$(Fp(t),e)},F$=0,_$=Math.random(),T$=ge(1 .toString),Sg=function(t){return"Symbol("+(t===void 0?"":t)+")_"+T$(++F$+_$,36)},Bc=ss("wks"),Cu=kt.Symbol,kx=Cu&&Cu.for,P$=a5?Cu:Cu&&Cu.withoutSetter||Sg,Bn=function(t){if(!Vt(Bc,t)||!ho&&typeof Bc[t]!="string"){var e="Symbol."+t;ho&&Vt(Cu,t)?Bc[t]=Cu[t]:Bc[t]=a5&&kx?kx(e):P$(e)}return Bc[t]},j$=kt.TypeError,N$=Bn("toPrimitive"),I$=function(t,e){if(!tr(t)||hl(t))return t;var n,r=xg(t,N$);if(r){if(e===void 0&&(e="default"),n=zn(r,t,e),!tr(n)||hl(n))return n;throw j$("Can't convert object to primitive value")}return e===void 0&&(e="number"),function(o,i){var a,u;if(i==="string"&&sn(a=o.toString)&&!tr(u=zn(a,o))||sn(a=o.valueOf)&&!tr(u=zn(a,o))||i!=="string"&&sn(a=o.toString)&&!tr(u=zn(a,o)))return u;throw A$("Can't convert object to primitive value")}(t,e)},ic=function(t){var e=I$(t,"string");return hl(e)?e:e+""},C4=kt.document,L$=tr(C4)&&tr(C4.createElement),gP=function(t){return L$?C4.createElement(t):{}},vP=!Hn&&!Gn(function(){return Object.defineProperty(gP("div"),"a",{get:function(){return 7}}).a!=7}),Bx=Object.getOwnPropertyDescriptor,R$=Hn?Bx:function(t,e){if(t=jo(t),e=ic(e),vP)try{return Bx(t,e)}catch{}if(Vt(t,e))return Xr(!zn(o5.f,t,e),t[e])},R1={f:R$},M$=/#|\.prototype\./,_p=function(t,e){var n=$$[z$(t)];return n==V$||n!=H$&&(sn(e)?Gn(e):!!e)},z$=_p.normalize=function(t){return String(t).replace(M$,".").toLowerCase()},$$=_p.data={},H$=_p.NATIVE="N",V$=_p.POLYFILL="P",U$=_p,Fx=ge(ge.bind),s5=function(t,e){return u5(t),e===void 0?t:Fx?Fx(t,e):function(){return t.apply(e,arguments)}},W$=kt.String,G$=kt.TypeError,ar=function(t){if(tr(t))return t;throw G$(W$(t)+" is not an object")},q$=kt.TypeError,_x=Object.defineProperty,K$=Hn?_x:function(t,e,n){if(ar(t),e=ic(e),ar(n),vP)try{return _x(t,e,n)}catch{}if("get"in n||"set"in n)throw q$("Accessors not supported");return"value"in n&&(t[e]=n.value),t},Na={f:K$},Tn=Hn?function(t,e,n){return Na.f(t,e,Xr(1,n))}:function(t,e,n){return t[e]=n,t},Y$=R1.f,X$=function(t){var e=function(n,r,o){if(this instanceof e){switch(arguments.length){case 0:return new t;case 1:return new t(n);case 2:return new t(n,r)}return new t(n,r,o)}return dP(t,this,arguments)};return e.prototype=t.prototype,e},Ko=function(t,e){var n,r,o,i,a,u,s,l,c=t.target,f=t.global,p=t.stat,d=t.proto,v=f?kt:p?kt[c]:(kt[c]||{}).prototype,g=f?Qn:Qn[c]||Tn(Qn,c,{})[c],m=g.prototype;for(o in e)n=!U$(f?o:c+(p?".":"#")+o,t.forced)&&v&&Vt(v,o),a=g[o],n&&(u=t.noTargetGet?(l=Y$(v,o))&&l.value:v[o]),i=n&&u?u:e[o],n&&typeof a==typeof i||(s=t.bind&&n?s5(i,kt):t.wrap&&n?X$(i):d&&sn(i)?ge(i):i,(t.sham||i&&i.sham||a&&a.sham)&&Tn(s,"sham",!0),Tn(g,o,s),d&&(Vt(Qn,r=c+"Prototype")||Tn(Qn,r,{}),Tn(Qn[r],o,i),t.real&&m&&!m[o]&&Tn(m,o,i)))},Tx=ss("keys"),M1=function(t){return Tx[t]||(Tx[t]=Sg(t))},Z$=!Gn(function(){function t(){}return t.prototype.constructor=null,Object.getPrototypeOf(new t)!==t.prototype}),Px=M1("IE_PROTO"),x4=kt.Object,J$=x4.prototype,Ag=Z$?x4.getPrototypeOf:function(t){var e=Fp(t);if(Vt(e,Px))return e[Px];var n=e.constructor;return sn(n)&&e instanceof n?n.prototype:e instanceof x4?J$:null},Q$=kt.String,tH=kt.TypeError,Og=Object.setPrototypeOf||("__proto__"in{}?function(){var t,e=!1,n={};try{(t=ge(Object.getOwnPropertyDescriptor(Object.prototype,"__proto__").set))(n,[]),e=n instanceof Array}catch{}return function(r,o){return ar(r),function(i){if(typeof i=="object"||sn(i))return i;throw tH("Can't set "+Q$(i)+" as a prototype")}(o),e?t(r,o):r.__proto__=o,r}}():void 0),eH=Math.ceil,nH=Math.floor,l5=function(t){var e=+t;return e!=e||e===0?0:(e>0?nH:eH)(e)},rH=Math.max,oH=Math.min,S4=function(t,e){var n=l5(t);return n<0?rH(n+e,0):oH(n,e)},iH=Math.min,Tp=function(t){return(e=t.length)>0?iH(l5(e),9007199254740991):0;var e},jx=function(t){return function(e,n,r){var o,i=jo(e),a=Tp(i),u=S4(r,a);if(t&&n!=n){for(;a>u;)if((o=i[u++])!=o)return!0}else for(;a>u;u++)if((t||u in i)&&i[u]===n)return t||u||0;return!t&&-1}},aH={includes:jx(!0),indexOf:jx(!1)},Pp={},uH=aH.indexOf,Nx=ge([].push),mP=function(t,e){var n,r=jo(t),o=0,i=[];for(n in r)!Vt(Pp,n)&&Vt(r,n)&&Nx(i,n);for(;e.length>o;)Vt(r,n=e[o++])&&(~uH(i,n)||Nx(i,n));return i},kg=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],sH=kg.concat("length","prototype"),lH=Object.getOwnPropertyNames||function(t){return mP(t,sH)},c5={f:lH},H0={f:Object.getOwnPropertySymbols},cH=ge([].concat),fH=oc("Reflect","ownKeys")||function(t){var e=c5.f(ar(t)),n=H0.f;return n?cH(e,n(t)):e},f5=Object.keys||function(t){return mP(t,kg)},dH=Hn?Object.defineProperties:function(t,e){ar(t);for(var n,r=jo(e),o=f5(e),i=o.length,a=0;i>a;)Na.f(t,n=o[a++],r[n]);return t},pH=oc("document","documentElement"),yP=M1("IE_PROTO"),Ym=function(){},bP=function(t){return" - - - -
- - - diff --git a/backend/src/test/java/com/yfd/platform/PlatformApplicationTests.java b/backend/src/test/java/com/yfd/platform/PlatformApplicationTests.java deleted file mode 100644 index c04ccc4..0000000 --- a/backend/src/test/java/com/yfd/platform/PlatformApplicationTests.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.yfd.platform; - -import cn.hutool.jwt.JWTUtil; -import org.junit.jupiter.api.Test; - -import java.sql.Timestamp; -import java.text.DecimalFormat; -import java.util.HashMap; -import java.util.Map; - -class PlatformApplicationTests { - - @Test - void contextLoads() { - Timestamp timestamp = new Timestamp(System.currentTimeMillis()); - Timestamp timestamp1 = new Timestamp(System.currentTimeMillis()); - long time = timestamp.getTime(); - long time1 = timestamp1.getTime(); - System.out.println(time1 - time); - String path = System.getProperty("user.dir"); - System.out.println(path); - int max = 101; - DecimalFormat df = new DecimalFormat("0000"); - String code = df.format(max + 1); - int i = Integer.parseInt("0030"); - System.out.println(i); - } - - @Test - void myTest() throws InterruptedException { - Map map = new HashMap() { - private static final long serialVersionUID = 1L; - - { - put("userid", Integer.parseInt("123232323")); - put("expire_time", System.currentTimeMillis() + 5 * 1000); - } - }; - String token = JWTUtil.createToken(map, "1234".getBytes()); - System.out.println(token); - Thread.sleep(10 * 1000); - - //解析token - boolean isok = JWTUtil.verify(token, "1234".getBytes()); - String userid = ""; - - } - -} diff --git a/backend/src/test/java/com/yfd/platform/TestGuaVA.java b/backend/src/test/java/com/yfd/platform/TestGuaVA.java deleted file mode 100644 index 870023e..0000000 --- a/backend/src/test/java/com/yfd/platform/TestGuaVA.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.yfd.platform; - -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -public class TestGuaVA { - private Cache cache = CacheBuilder.newBuilder().maximumSize(2).expireAfterWrite(10, TimeUnit.MINUTES).build(); - - public Object getCache(K keyValue, final String ThreadName) { - Object value = null; - try { - System.out.println("ThreadName getCache==============" + ThreadName); - value = cache.get(keyValue, new Callable() { - @SuppressWarnings("unchecked") - public V call() { - System.out.println("ThreadName 执行业务数据并返回处理结果的数据(访问数据库等)==============" + ThreadName); - return (V) "dataValue"; - } - }); - } catch (ExecutionException e) { - e.printStackTrace(); - } - return value; - } - - public static void main(String[] args) { - final TestGuaVA TestGuaVA=new TestGuaVA(); - - - Thread t1=new Thread(new Runnable() { - @Override - public void run() { - System.out.println("T1======start========"); - Object value=TestGuaVA.getCache("key","T1"); - System.out.println("T1 value=============="+value); - System.out.println("T1======end========"); - - } - }); - - Thread t2=new Thread(new Runnable() { - @Override - public void run() { - System.out.println("T2======start========"); - Object value=TestGuaVA.getCache("key","T2"); - System.out.println("T2 value=============="+value); - System.out.println("T2======end========"); - - } - }); - - Thread t3=new Thread(new Runnable() { - @Override - public void run() { - System.out.println("T3======start========"); - Object value=TestGuaVA.getCache("key","T3"); - System.out.println("T3 value=============="+value); - System.out.println("T3======end========"); - - } - }); - - t1.start(); - t2.start(); - t3.start(); - } - -} -