From 3d3450847870940e8a8b830bbf3c759d6b1c6b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=9Czhuoda?= Date: Sat, 16 Nov 2019 18:17:31 +0800 Subject: [PATCH] v1.0.0 --- front/.babelrc | 5 + front/.editorconfig | 9 + front/.env.development | 4 + front/.env.prod | 5 + front/.env.sit | 3 + front/.eslintignore | 0 front/.eslintrc.js | 34 + front/.gitignore | 28 + front/.postcssrc.js | 5 + front/.travis.yml | 5 + front/LICENSE | 21 + front/README.md | 13 + front/cypress.json | 3 + front/doc/notice.txt | 2 + front/package.json | 86 + front/public/favicon.ico | Bin 0 -> 16958 bytes front/public/index.html | 19 + front/src/App.vue | 31 + front/src/api/data-scope.js | 15 + front/src/api/department.js | 47 + front/src/api/email.js | 27 + front/src/api/employee.js | 43 + front/src/api/file.js | 28 + front/src/api/heart-beat.js | 7 + front/src/api/login.js | 19 + front/src/api/notice.js | 43 + front/src/api/online-user.js | 12 + front/src/api/position.js | 19 + front/src/api/privilege.js | 32 + front/src/api/role.js | 58 + front/src/api/smart-reload.js | 20 + front/src/api/system-config.js | 31 + front/src/api/task-manage.js | 35 + front/src/api/user-log.js | 28 + front/src/api/user.js | 20 + front/src/assets/icons/demo.css | 539 +++ front/src/assets/icons/demo_index.html | 722 ++++ .../font_1299963_2zqwx2axi0j/demo.css | 539 +++ .../font_1299963_2zqwx2axi0j/demo_index.html | 722 ++++ .../font_1299963_2zqwx2axi0j/iconfont.css | 113 + .../font_1299963_2zqwx2axi0j/iconfont.eot | Bin 0 -> 8812 bytes .../font_1299963_2zqwx2axi0j/iconfont.js | 1 + .../font_1299963_2zqwx2axi0j/iconfont.svg | 98 + .../font_1299963_2zqwx2axi0j/iconfont.ttf | Bin 0 -> 8644 bytes .../font_1299963_2zqwx2axi0j/iconfont.woff | Bin 0 -> 5436 bytes .../font_1299963_2zqwx2axi0j/iconfont.woff2 | Bin 0 -> 4584 bytes front/src/assets/icons/iconfont.css | 113 + front/src/assets/icons/iconfont.eot | Bin 0 -> 8812 bytes front/src/assets/icons/iconfont.js | 1 + front/src/assets/icons/iconfont.svg | 98 + front/src/assets/icons/iconfont.ttf | Bin 0 -> 8644 bytes front/src/assets/icons/iconfont.woff | Bin 0 -> 5436 bytes front/src/assets/icons/iconfont.woff2 | Bin 0 -> 4584 bytes front/src/assets/images/default_icon.png | Bin 0 -> 2364 bytes .../assets/images/error-page/error-401.svg | 1 + .../assets/images/error-page/error-404.svg | 1 + .../assets/images/error-page/error-500.svg | 1 + front/src/assets/images/icon-qr-qq-wechat.png | Bin 0 -> 43541 bytes .../assets/images/icon-social-bilibili.svg | 1 + .../src/assets/images/icon-social-juejin.svg | 1 + .../src/assets/images/icon-social-twitter.svg | 1 + front/src/assets/images/icon-social-zhihu.svg | 1 + front/src/assets/images/login-alipay.png | Bin 0 -> 1881 bytes front/src/assets/images/login-bg.jpg | Bin 0 -> 547587 bytes front/src/assets/images/login-logo.png | Bin 0 -> 4900 bytes front/src/assets/images/login-sina.png | Bin 0 -> 1851 bytes front/src/assets/images/login-taobao.png | Bin 0 -> 1898 bytes front/src/assets/images/login_desc_bg.png | Bin 0 -> 272693 bytes front/src/assets/images/login_logo.png | Bin 0 -> 3523 bytes front/src/assets/images/logo-min.png | Bin 0 -> 2079 bytes front/src/assets/images/logo.png | Bin 0 -> 3259 bytes front/src/assets/images/message.png | Bin 0 -> 1873 bytes front/src/assets/images/shadow.png | Bin 0 -> 224307 bytes .../images/slider/sub_slider_active.png | Bin 0 -> 3103 bytes .../images/slider/sub_slider_default.png | Bin 0 -> 3105 bytes front/src/assets/style/lib/animate.css | 3625 +++++++++++++++++ .../components/active-plate/active-plate.vue | 67 + front/src/components/charts/bar.vue | 73 + front/src/components/charts/index.js | 3 + front/src/components/charts/pie.vue | 85 + front/src/components/charts/theme.json | 490 +++ .../components/common-icon/common-icon.vue | 52 + front/src/components/common-icon/index.js | 2 + front/src/components/count-to/count-to.vue | 198 + front/src/components/count-to/index.js | 2 + front/src/components/count-to/index.less | 10 + front/src/components/editor/editor.vue | 77 + front/src/components/editor/index.js | 2 + front/src/components/icons/icons.vue | 38 + front/src/components/icons/index.js | 2 + .../main/components/a-back-top/index.js | 2 + .../main/components/a-back-top/index.vue | 130 + .../main/components/fullscreen/fullscreen.vue | 92 + .../main/components/fullscreen/index.js | 2 + .../custom-bread-crumb.less | 4 + .../custom-bread-crumb/custom-bread-crumb.vue | 44 + .../header-bar/custom-bread-crumb/index.js | 2 + .../components/header-bar/header-bar.less | 14 + .../main/components/header-bar/header-bar.vue | 39 + .../main/components/header-bar/index.js | 2 + .../header-bar/sider-trigger/index.js | 2 + .../sider-trigger/sider-trigger.less | 21 + .../sider-trigger/sider-trigger.vue | 35 + .../main/components/language/index.js | 2 + .../main/components/language/language.vue | 54 + .../main/components/notice/notice.vue | 371 ++ .../components/side-menu/collapsed-menu.vue | 84 + .../main/components/side-menu/index.js | 2 + .../main/components/side-menu/item-mixin.js | 30 + .../main/components/side-menu/mixin.js | 18 + .../components/side-menu/side-menu-item.vue | 35 + .../main/components/side-menu/side-menu.less | 39 + .../main/components/side-menu/side-menu.vue | 187 + .../main/components/tags-nav/index.js | 2 + .../main/components/tags-nav/tags-nav.less | 136 + .../main/components/tags-nav/tags-nav.vue | 256 ++ .../components/main/components/user/index.js | 2 + .../components/main/components/user/user.less | 25 + .../components/main/components/user/user.vue | 131 + front/src/components/main/index.js | 2 + front/src/components/main/main.less | 129 + front/src/components/main/main.vue | 443 ++ front/src/components/tables/edit.vue | 102 + front/src/components/tables/handle-btns.js | 70 + front/src/components/tables/index.js | 2 + front/src/components/tables/index.less | 17 + front/src/components/tables/tables.vue | 342 ++ front/src/config/index.js | 38 + front/src/constants/file.js | 24 + front/src/constants/index.js | 10 + front/src/constants/login.js | 13 + front/src/constants/notice.js | 13 + front/src/constants/privilege.js | 14 + front/src/directives/directives.js | 11 + front/src/directives/index.js | 31 + front/src/directives/module/clipboard.js | 30 + front/src/directives/module/draggable.js | 42 + front/src/directives/module/privilege.js | 23 + front/src/filters/index.js | 0 front/src/lib/cookie.js | 21 + front/src/lib/http.js | 91 + front/src/lib/local.js | 8 + front/src/lib/menu-func.js | 306 ++ front/src/lib/printPlugs.js | 133 + front/src/lib/render-dom.js | 10 + front/src/lib/table-action.js | 84 + front/src/lib/util.js | 499 +++ front/src/locale/index.js | 37 + front/src/locale/lang/en-US.js | 46 + front/src/locale/lang/zh-CN.js | 46 + front/src/locale/lang/zh-TW.js | 46 + front/src/main.js | 64 + front/src/main.less | 37 + front/src/plugins/error-store/index.js | 4 + front/src/plugins/index.js | 12 + front/src/router/before-close.js | 17 + front/src/router/index.js | 142 + front/src/router/module/api-doc.js | 25 + front/src/router/module/email.js | 40 + front/src/router/module/employee.js | 149 + front/src/router/module/error.js | 30 + front/src/router/module/file.js | 29 + front/src/router/module/heart-beat.js | 31 + front/src/router/module/home.js | 28 + front/src/router/module/keep-alive.js | 31 + front/src/router/module/monitor.js | 33 + front/src/router/module/notice.js | 43 + front/src/router/module/reload.js | 40 + front/src/router/module/system-setting.js | 62 + front/src/router/module/task.js | 63 + front/src/router/module/three-router.js | 62 + front/src/router/module/user-log.js | 42 + front/src/router/routers.js | 61 + front/src/store/index.js | 25 + front/src/store/module/app.js | 131 + front/src/store/module/notice.js | 19 + front/src/store/module/user.js | 122 + front/src/themes/ReadMe.md | 1 + front/src/themes/index.less | 302 ++ front/src/views/api-doc/swagger.vue | 33 + front/src/views/email/email-list.vue | 214 + front/src/views/email/send-mail.vue | 214 + .../department-employee-tree-item.vue | 124 + .../department-employee-tree.vue | 251 ++ .../views/employee/position/position-list.vue | 366 ++ .../employee-table-add/employee-table-add.vue | 527 +++ .../employee-table-detail.vue | 72 + .../employee-table/employee-table.vue | 569 +++ .../role-employee/role-employee-manage.vue | 831 ++++ .../role-data-scope/role-data-scope.vue | 144 + .../role/components/role-list/role-list.vue | 407 ++ .../role/components/role-tree/role-tree.vue | 403 ++ front/src/views/employee/role/role-manage.vue | 339 ++ front/src/views/error-page/401.vue | 19 + front/src/views/error-page/404.vue | 19 + front/src/views/error-page/500.vue | 19 + front/src/views/error-page/back-btn-group.vue | 40 + front/src/views/error-page/error-content.vue | 28 + front/src/views/error-page/error.less | 46 + front/src/views/file/file-list.vue | 279 ++ .../src/views/heart-beat/heart-beat-list.vue | 115 + front/src/views/home/components/card.vue | 43 + front/src/views/home/components/chart-bar.vue | 140 + .../views/home/components/chart-funnel.vue | 106 + .../src/views/home/components/chart-gauge.vue | 87 + .../src/views/home/components/chart-line.vue | 123 + front/src/views/home/components/chart-pie.vue | 110 + .../src/views/home/components/home-circle.vue | 41 + .../views/home/components/home-progress.vue | 59 + front/src/views/home/components/theme.json | 490 +++ front/src/views/home/home.vue | 144 + front/src/views/home/index.js | 2 + front/src/views/keep-alive/add-content.vue | 94 + front/src/views/keep-alive/content-list.vue | 80 + front/src/views/login/canvas.js | 289 ++ .../src/views/login/components/login-form.vue | 133 + front/src/views/login/login.less | 128 + front/src/views/login/login.vue | 52 + front/src/views/monitor/online-user.vue | 152 + front/src/views/monitor/sql.vue | 33 + front/src/views/notice/notice-list.vue | 397 ++ front/src/views/notice/person-notice.vue | 221 + .../reload/smart-reload/smart-reload-list.vue | 273 ++ .../system-config/system-config.vue | 397 ++ .../components/privilege-form.vue | 144 + .../system-privilege/system-privilege.vue | 318 ++ front/src/views/task/task-list.vue | 545 +++ front/src/views/user-log/user-login-log.vue | 181 + front/src/views/user-log/user-operate-log.vue | 252 ++ front/tests/e2e/.eslintrc | 12 + front/tests/e2e/plugins/index.js | 9 + front/tests/e2e/specs/test.js | 8 + front/tests/e2e/support/commands.js | 25 + front/tests/e2e/support/index.js | 20 + front/tests/unit/.eslintrc.js | 8 + front/tests/unit/HelloWorld.spec.js | 13 + front/vscode/settings.json | 43 + front/vue.config.js | 78 + java/smart-admin-api/doc/readme.txt | 17 + java/smart-admin-api/pom.xml | 386 ++ .../smartadmin/SmartAdminApplication.java | 28 + .../common/anno/ApiModelPropertyEnum.java | 35 + .../smartadmin/common/anno/DataScope.java | 34 + .../smartadmin/common/anno/NoNeedLogin.java | 22 + .../common/anno/NoValidPrivilege.java | 20 + .../smartadmin/common/anno/OperateLog.java | 20 + .../common/constant/CommentSortTypeEnum.java | 57 + .../smartadmin/common/constant/JudgeEnum.java | 52 + .../common/constant/ResponseCodeConst.java | 183 + .../smartadmin/common/domain/BaseEntity.java | 38 + .../smartadmin/common/domain/BaseEnum.java | 97 + .../common/domain/PageParamDTO.java | 35 + .../common/domain/PageResultDTO.java | 47 + .../smartadmin/common/domain/ResponseDTO.java | 128 + .../exception/SmartBusinessException.java | 33 + .../exception/SmartResponseCodeException.java | 24 + .../heartbeat/AbstractHeartBeatCommand.java | 90 + .../common/heartbeat/HeartBeatConfig.java | 29 + .../common/heartbeat/HeartBeatLogger.java | 20 + .../HeartBeatRecordCommendInterface.java | 17 + .../common/heartbeat/HeartBeatRecordDTO.java | 37 + .../heartbeat/HeatBeatRecordHelper.java | 45 + .../smartadmin/common/heartbeat/IpUtil.java | 81 + .../common/heartbeat/StringUtil.java | 60 + .../common/json/LongJsonDeserializer.java | 21 + .../common/json/LongJsonSerializer.java | 19 + .../common/kaptcha/KaptchaColor.java | 39 + .../common/kaptcha/KaptchaNoise.java | 44 + .../common/kaptcha/KaptchaWordRenderer.java | 75 + .../common/reload/SmartReloadManager.java | 134 + .../common/reload/SmartReloadScheduler.java | 87 + .../abstracts/AbstractSmartReloadCommand.java | 66 + .../AbstractSmartReloadCommand4Spring.java | 68 + .../common/reload/annotation/SmartReload.java | 18 + .../domain/AbstractSmartReloadObject.java | 31 + .../reload/domain/AnnotationReloadObject.java | 44 + .../reload/domain/InterfaceReloadObject.java | 37 + .../reload/domain/entity/ReloadItem.java | 55 + .../domain/entity/SmartReloadResult.java | 102 + .../SmartReloadCommandInterface.java | 38 + .../interfaces/SmartReloadThreadLogger.java | 12 + .../reload/interfaces/SmartReloadable.java | 18 + .../SmartSwaggerApiModelEnumPlugin.java | 91 + .../bigdecimal/BigDecimalValidator.java | 73 + .../validator/bigdecimal/CheckBigDecimal.java | 53 + .../bigdecimal/ComparisonSymbolEnum.java | 40 + .../common/validator/en/CheckEnum.java | 51 + .../common/validator/en/EnumValidator.java | 80 + .../config/SmartAdminWebAppConfig.java | 29 + .../config/SmartDruidDataSourceConfig.java | 170 + .../config/SmartHeartBeatConfig.java | 33 + .../smartadmin/config/SmartKaptchaConfig.java | 49 + .../config/SmartMybatisPlusConfig.java | 39 + .../smartadmin/config/SmartRedisConfig.java | 74 + .../smartadmin/config/SmartReloadConfig.java | 45 + .../config/SmartRestTemplateConfig.java | 109 + .../SmartSwaggerApiModelEnumConfig.java | 29 + .../SmartSwaggerDynamicGroupConfig.java | 217 + .../config/SmartWebSocketConfig.java | 25 + .../config/SystemEnvironmentCondition.java | 22 + .../smartadmin/constant/CommonConst.java | 51 + .../constant/SmartReloadTagConst.java | 16 + .../smartadmin/constant/SwaggerTagConst.java | 69 + .../constant/SystemEnvironmentEnum.java | 60 + .../handler/SmartGlobalExceptionHandler.java | 73 + .../handler/SmartOperateLogAspect.java | 167 + .../SmartAuthenticationInterceptor.java | 158 + .../listener/SmartAdminStartupRunner.java | 22 + .../constant/SqlOperateTypeEnum.java | 36 + .../module/codegenerator/dao/TableDao.java | 40 + .../domain/CodeGeneratorDTO.java | 51 + .../domain/CodeGeneratorQueryColumnDTO.java | 30 + .../module/codegenerator/domain/ColumnVO.java | 30 + .../codegenerator/domain/QueryFieldVO.java | 30 + .../service/CodeGeneratorComponent.java | 74 + .../service/CodeGeneratorService.java | 313 ++ .../module/datascope/DataScopeController.java | 57 + .../module/datascope/DataScopeRoleDao.java | 52 + .../module/datascope/MyBatisPlugin.java | 152 + .../datascope/constant/DataScopeTypeEnum.java | 47 + .../constant/DataScopeViewTypeEnum.java | 55 + .../constant/DataScopeWhereInTypeEnum.java | 37 + .../domain/dto/DataScopeAndViewTypeVO.java | 36 + .../domain/dto/DataScopeBatchSetDTO.java | 28 + .../domain/dto/DataScopeBatchSetRoleDTO.java | 30 + .../datascope/domain/dto/DataScopeDTO.java | 36 + .../domain/dto/DataScopeSelectVO.java | 24 + .../domain/dto/DataScopeSqlConfigDTO.java | 25 + .../domain/dto/DataScopeViewTypeVO.java | 28 + .../domain/entity/DataScopeRoleEntity.java | 33 + .../datascope/service/DataScopeService.java | 118 + .../service/DataScopeSqlConfigService.java | 121 + .../service/DataScopeViewService.java | 168 + .../department/DepartmentController.java | 99 + .../module/department/DepartmentDao.java | 48 + .../DepartmentResponseCodeConst.java | 39 + .../module/department/DepartmentService.java | 282 ++ .../department/DepartmentTreeService.java | 99 + .../domain/dto/DepartmentCreateDTO.java | 38 + .../domain/dto/DepartmentUpdateDTO.java | 25 + .../department/domain/dto/DepartmentVO.java | 58 + .../domain/entity/DepartmentEntity.java | 48 + .../module/email/EmailController.java | 80 + .../smartadmin/module/email/EmailDao.java | 47 + .../module/email/EmailSendStatusEnum.java | 37 + .../smartadmin/module/email/EmailService.java | 122 + .../email/domain/dto/EmailConfigDTO.java | 30 + .../module/email/domain/dto/EmailDTO.java | 44 + .../email/domain/dto/EmailQueryDTO.java | 35 + .../module/email/domain/dto/EmailVO.java | 45 + .../email/domain/entity/EmailEntity.java | 40 + .../module/employee/EmployeeController.java | 95 + .../module/employee/EmployeeDao.java | 129 + .../module/employee/EmployeeService.java | 342 ++ .../constant/EmployeeResponseCodeConst.java | 61 + .../employee/constant/EmployeeStatusEnum.java | 56 + .../module/employee/domain/bo/EmployeeBO.java | 73 + .../employee/domain/dto/EmployeeAddDTO.java | 63 + .../employee/domain/dto/EmployeeBaseDTO.java | 52 + .../dto/EmployeeBatchUpdateStatusDTO.java | 26 + .../employee/domain/dto/EmployeeDTO.java | 73 + .../domain/dto/EmployeeLoginFormDTO.java | 33 + .../employee/domain/dto/EmployeeQueryDTO.java | 39 + .../domain/dto/EmployeeQueryExportDTO.java | 42 + .../domain/dto/EmployeeUpdateDTO.java | 28 + .../domain/dto/EmployeeUpdatePwdDTO.java | 25 + .../domain/dto/EmployeeUpdateRolesDTO.java | 29 + .../domain/entity/EmployeeEntity.java | 91 + .../module/employee/domain/vo/EmployeeVO.java | 72 + .../module/file/FileController.java | 93 + .../smartadmin/module/file/FileDao.java | 72 + .../file/constant/FileModuleTypeEnum.java | 45 + .../file/constant/FileResponseCodeConst.java | 37 + .../file/constant/FileServiceNameConst.java | 24 + .../file/constant/FileServiceTypeEnum.java | 52 + .../module/file/domain/dto/FileAddDTO.java | 40 + .../module/file/domain/dto/FileDTO.java | 58 + .../module/file/domain/dto/FileQueryDTO.java | 33 + .../module/file/domain/dto/OSSConfig.java | 36 + .../module/file/domain/entity/FileEntity.java | 58 + .../module/file/domain/vo/FileVO.java | 58 + .../module/file/domain/vo/UploadVO.java | 27 + .../module/file/service/FileService.java | 197 + .../file/service/FileServiceAliYun.java | 182 + .../module/file/service/FileServiceLocal.java | 123 + .../file/service/FileServiceQiNiuYun.java | 175 + .../module/file/service/IFileService.java | 152 + .../module/heartbeat/HeartBeatController.java | 32 + .../module/heartbeat/HeartBeatRecordDao.java | 53 + .../heartbeat/HeartBeatRecordEntity.java | 42 + .../module/heartbeat/HeartBeatRecordVO.java | 36 + .../module/heartbeat/HeartBeatService.java | 91 + .../module/idgenerator/IdGeneratorDao.java | 37 + .../idgenerator/IdGeneratorManager.java | 66 + .../idgenerator/IdGeneratorService.java | 140 + .../idgenerator/constant/IdGeneratorEnum.java | 45 + .../constant/IdGeneratorRuleTypeEnum.java | 40 + .../idgenerator/domain/IdGeneratorEntity.java | 47 + .../domain/IdGeneratorLastNumberDTO.java | 38 + .../idgenerator/domain/IdGeneratorPOJO.java | 71 + .../domain/IdGeneratorRecordDTO.java | 22 + .../smartadmin/module/log/LogService.java | 75 + .../OrderOperateLogController.java | 44 + .../orderoperatelog/OrderOperateLogDao.java | 30 + .../OrderOperateLogService.java | 63 + .../OrderOperateLogDefaultEmpEnum.java | 37 + .../OrderOperateLogOperateTypeConst.java | 30 + .../OrderOperateLogOrderTypeEnum.java | 51 + .../domain/dto/OrderOperateLogSaveDTO.java | 79 + .../domain/dto/SupplierOrderOperateVO.java | 44 + .../domain/entity/OrderOperateLogEntity.java | 60 + .../domain/vo/OrderOperateLogVO.java | 69 + .../userloginlog/UserLoginLogController.java | 54 + .../log/userloginlog/UserLoginLogDao.java | 47 + .../log/userloginlog/UserLoginLogService.java | 82 + .../userloginlog/domain/UserLoginLogDTO.java | 53 + .../domain/UserLoginLogEntity.java | 60 + .../domain/UserLoginLogQueryDTO.java | 31 + .../UserOperateLogController.java | 50 + .../log/useroperatelog/UserOperateLogDao.java | 47 + .../useroperatelog/UserOperateLogService.java | 91 + .../domain/UserOperateLogDTO.java | 59 + .../domain/UserOperateLogEntity.java | 74 + .../domain/UserOperateLogQueryDTO.java | 34 + .../module/login/LoginController.java | 72 + .../module/login/LoginResponseCodeConst.java | 21 + .../smartadmin/module/login/LoginService.java | 210 + .../module/login/LoginTokenService.java | 118 + .../module/login/domain/KaptchaVO.java | 28 + .../module/login/domain/LoginCacheDTO.java | 28 + .../module/login/domain/LoginDetailVO.java | 70 + .../login/domain/LoginPrivilegeDTO.java | 35 + .../module/login/domain/RequestTokenBO.java | 26 + .../module/notice/NoticeController.java | 96 + .../module/notice/NoticeManage.java | 96 + .../module/notice/NoticeService.java | 234 ++ .../module/notice/dao/NoticeDao.java | 99 + .../notice/dao/NoticeReceiveRecordDao.java | 48 + .../notice/domain/dto/NoticeAddDTO.java | 28 + .../notice/domain/dto/NoticeDetailVO.java | 30 + .../notice/domain/dto/NoticeQueryDTO.java | 34 + .../notice/domain/dto/NoticeReadCountDTO.java | 26 + .../notice/domain/dto/NoticeReceiveDTO.java | 43 + .../domain/dto/NoticeReceiveQueryDTO.java | 25 + .../notice/domain/dto/NoticeUpdateDTO.java | 21 + .../module/notice/domain/dto/NoticeVO.java | 42 + .../notice/domain/entity/NoticeEntity.java | 45 + .../entity/NoticeReceiveRecordEntity.java | 33 + .../module/position/PositionController.java | 59 + .../module/position/PositionDao.java | 56 + .../position/PositionResponseCodeConst.java | 16 + .../module/position/PositionService.java | 124 + .../position/domain/dto/PositionAddDTO.java | 28 + .../position/domain/dto/PositionQueryDTO.java | 18 + .../domain/dto/PositionRelationAddDTO.java | 32 + .../domain/dto/PositionRelationQueryDTO.java | 20 + .../domain/dto/PositionRelationResultDTO.java | 40 + .../position/domain/dto/PositionResultVO.java | 41 + .../domain/dto/PositionUpdateDTO.java | 16 + .../domain/entity/PositionEntity.java | 26 + .../domain/entity/PositionRelationEntity.java | 26 + .../constant/PrivilegeResponseCodeConst.java | 24 + .../privilege/constant/PrivilegeTypeEnum.java | 49 + .../controller/PrivilegeController.java | 68 + .../module/privilege/dao/PrivilegeDao.java | 87 + .../domain/dto/PrivilegeFunctionDTO.java | 41 + .../domain/dto/PrivilegeFunctionVO.java | 41 + .../domain/dto/PrivilegeMenuDTO.java | 45 + .../domain/dto/PrivilegeMenuListVO.java | 37 + .../domain/dto/PrivilegeRequestUrlVO.java | 27 + .../domain/entity/PrivilegeEntity.java | 55 + .../service/PrivilegeEmployeeService.java | 196 + .../service/PrivilegeRequestUrlService.java | 117 + .../privilege/service/PrivilegeService.java | 217 + .../module/quartz/constant/QuartzConst.java | 17 + .../quartz/constant/TaskResultEnum.java | 47 + .../quartz/constant/TaskStatusEnum.java | 47 + .../quartz/controller/QuartzController.java | 81 + .../module/quartz/dao/QuartzTaskDao.java | 42 + .../module/quartz/dao/QuartzTaskLogDao.java | 35 + .../quartz/domain/dto/QuartzLogQueryDTO.java | 25 + .../quartz/domain/dto/QuartzQueryDTO.java | 16 + .../quartz/domain/dto/QuartzTaskDTO.java | 45 + .../quartz/domain/dto/QuartzTaskLogVO.java | 49 + .../quartz/domain/dto/QuartzTaskVO.java | 45 + .../domain/entity/QuartzTaskEntity.java | 49 + .../domain/entity/QuartzTaskLogEntity.java | 50 + .../module/quartz/service/QuartzTask.java | 78 + .../quartz/service/QuartzTaskLogService.java | 28 + .../quartz/service/QuartzTaskService.java | 316 ++ .../smartadmin/module/quartz/task/ITask.java | 16 + .../module/quartz/task/test/Example.java | 26 + .../module/role/basic/RoleController.java | 60 + .../smartadmin/module/role/basic/RoleDao.java | 26 + .../role/basic/RoleResponseCodeConst.java | 24 + .../module/role/basic/RoleService.java | 115 + .../role/basic/domain/dto/RoleAddDTO.java | 33 + .../role/basic/domain/dto/RoleBatchDTO.java | 30 + .../role/basic/domain/dto/RoleQueryDTO.java | 25 + .../role/basic/domain/dto/RoleSelectedVO.java | 21 + .../role/basic/domain/dto/RoleUpdateDTO.java | 24 + .../module/role/basic/domain/dto/RoleVO.java | 27 + .../role/basic/domain/entity/RoleEntity.java | 25 + .../roleemployee/RoleEmployeeController.java | 73 + .../role/roleemployee/RoleEmployeeDao.java | 80 + .../roleemployee/RoleEmployeeService.java | 133 + .../roleemployee/domain/RoleEmployeeDTO.java | 21 + .../domain/RoleEmployeeEntity.java | 24 + .../RolePrivilegeController.java | 45 + .../role/roleprivilege/RolePrivilegeDao.java | 58 + .../roleprivilege/RolePrivilegeService.java | 129 + .../domain/dto/RolePrivilegeDTO.java | 35 + .../domain/dto/RolePrivilegeSimpleDTO.java | 43 + .../domain/dto/RolePrivilegeTreeVO.java | 19 + .../domain/entity/RolePrivilegeEntity.java | 32 + .../smartreload/SmartReloadCommand.java | 52 + .../smartreload/SmartReloadController.java | 52 + .../smartreload/SmartReloadService.java | 103 + .../module/smartreload/dao/ReloadItemDao.java | 15 + .../smartreload/dao/ReloadResultDao.java | 23 + .../domain/dto/ReloadItemUpdateDTO.java | 29 + .../smartreload/domain/dto/ReloadItemVO.java | 46 + .../domain/dto/ReloadResultVO.java | 47 + .../domain/entity/ReloadItemEntity.java | 46 + .../domain/entity/ReloadResultEntity.java | 48 + .../systemconfig/SystemConfigController.java | 70 + .../module/systemconfig/SystemConfigDao.java | 62 + .../systemconfig/SystemConfigService.java | 250 ++ .../constant/SystemConfigDataType.java | 67 + .../constant/SystemConfigEnum.java | 65 + .../SystemConfigResponseCodeConst.java | 29 + .../domain/dto/SystemConfigAddDTO.java | 45 + .../domain/dto/SystemConfigDTO.java | 50 + .../domain/dto/SystemConfigQueryDTO.java | 29 + .../domain/dto/SystemConfigUpdateDTO.java | 25 + .../domain/dto/SystemConfigVO.java | 48 + .../domain/entity/SystemConfigEntity.java | 51 + .../module/websocket/MessageTypeEnum.java | 44 + .../module/websocket/WebSocketServer.java | 199 + .../websocket/domain/MessageCommonDTO.java | 29 + .../module/websocket/domain/MessageDTO.java | 41 + .../domain/WebSocketHeartBeatDTO.java | 23 + .../third/SmartApplicationContext.java | 80 + .../smartadmin/third/SmartRedisService.java | 622 +++ .../smartadmin/util/SmartBaseEnumUtil.java | 85 + .../smartadmin/util/SmartBeanUtil.java | 56 + .../smartadmin/util/SmartBigDecimalUtil.java | 303 ++ .../smartadmin/util/SmartDateUtil.java | 521 +++ .../smartadmin/util/SmartDigestUtil.java | 17 + .../smartadmin/util/SmartHttpUtil.java | 151 + .../smartadmin/util/SmartIPUtil.java | 159 + .../smartadmin/util/SmartPaginationUtil.java | 86 + .../smartadmin/util/SmartQuartzUtil.java | 43 + .../util/SmartRequestTokenUtil.java | 51 + .../smartadmin/util/SmartSendMailUtil.java | 243 ++ .../smartadmin/util/SmartStringUtil.java | 311 ++ .../smartadmin/util/SmartThreadFactory.java | 44 + .../util/SmartVerificationUtil.java | 95 + .../src/main/resources/banner.txt | 8 + .../main/resources/dev/application.properties | 122 + .../src/main/resources/dev/log4j2.xml | 97 + .../mapper/codegenerator/TableMapper.xml | 27 + .../mapper/datascope/DataScopeRoleMapper.xml | 36 + .../mapper/department/DepartmentMapper.xml | 54 + .../resources/mapper/email/EmailMapper.xml | 44 + .../mapper/employee/EmployeeMapper.xml | 183 + .../main/resources/mapper/file/FileMapper.xml | 100 + .../heartbeat/HeartBeatRecordMapper.xml | 41 + .../mapper/idgenerator/IdGeneratorMapper.xml | 48 + .../mapper/log/OrderOperateLogMapper.xml | 50 + .../mapper/log/UserLoginLogMapper.xml | 46 + .../mapper/log/UserOperateLogMapper.xml | 51 + .../resources/mapper/notice/NoticeMapper.xml | 155 + .../notice/NoticeReceiveRecordMapper.xml | 39 + .../mapper/position/PositionMapper.xml | 59 + .../mapper/privilege/PrivilegeMapper.xml | 111 + .../mapper/quartz/QuartzTaskLogMapper.xml | 38 + .../mapper/quartz/QuartzTaskMapper.xml | 36 + .../mapper/role/RoleEmployeeMapper.xml | 124 + .../main/resources/mapper/role/RoleMapper.xml | 27 + .../mapper/role/RolePrivilegeMapper.xml | 72 + .../mapper/smartreload/ReloadItemMapper.xml | 6 + .../mapper/smartreload/ReloadResultMapper.xml | 18 + .../systemconfig/SystemConfigMapper.xml | 98 + .../main/resources/pre/application.properties | 122 + .../src/main/resources/pre/log4j2.xml | 97 + .../resources/prod/application.properties | 122 + .../src/main/resources/prod/log4j2.xml | 97 + .../main/resources/sit/application.properties | 122 + .../src/main/resources/sit/log4j2.xml | 97 + .../main/resources/sql/quartz_mysql_2.3.0.sql | 179 + .../src/main/resources/sql/smart-admin.sql | 1497 +++++++ .../codegenerator/Controller.java.vm | 64 + .../templates/codegenerator/DTO.java.vm | 34 + .../templates/codegenerator/Dao.java.vm | 48 + .../templates/codegenerator/Dao.xml.vm | 77 + .../templates/codegenerator/Entity.java.vm | 35 + .../templates/codegenerator/QueryDTO.java.vm | 43 + .../templates/codegenerator/Service.java.vm | 95 + .../com/gangquan360/smartadmin/BaseTest.java | 29 + .../SmartAdminApplicationTests.java | 11 + .../CodeGeneratorServiceTest.java | 39 + java/smart-admin-parent/README.md | 1 + java/smart-admin-parent/pom.xml | 547 +++ 604 files changed, 51535 insertions(+) create mode 100644 front/.babelrc create mode 100644 front/.editorconfig create mode 100644 front/.env.development create mode 100644 front/.env.prod create mode 100644 front/.env.sit create mode 100644 front/.eslintignore create mode 100644 front/.eslintrc.js create mode 100644 front/.gitignore create mode 100644 front/.postcssrc.js create mode 100644 front/.travis.yml create mode 100644 front/LICENSE create mode 100644 front/README.md create mode 100644 front/cypress.json create mode 100644 front/doc/notice.txt create mode 100644 front/package.json create mode 100644 front/public/favicon.ico create mode 100644 front/public/index.html create mode 100644 front/src/App.vue create mode 100644 front/src/api/data-scope.js create mode 100644 front/src/api/department.js create mode 100644 front/src/api/email.js create mode 100644 front/src/api/employee.js create mode 100644 front/src/api/file.js create mode 100644 front/src/api/heart-beat.js create mode 100644 front/src/api/login.js create mode 100644 front/src/api/notice.js create mode 100644 front/src/api/online-user.js create mode 100644 front/src/api/position.js create mode 100644 front/src/api/privilege.js create mode 100644 front/src/api/role.js create mode 100644 front/src/api/smart-reload.js create mode 100644 front/src/api/system-config.js create mode 100644 front/src/api/task-manage.js create mode 100644 front/src/api/user-log.js create mode 100644 front/src/api/user.js create mode 100644 front/src/assets/icons/demo.css create mode 100644 front/src/assets/icons/demo_index.html create mode 100644 front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/demo.css create mode 100644 front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/demo_index.html create mode 100644 front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.css create mode 100644 front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.eot create mode 100644 front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.js create mode 100644 front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.svg create mode 100644 front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.ttf create mode 100644 front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.woff create mode 100644 front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.woff2 create mode 100644 front/src/assets/icons/iconfont.css create mode 100644 front/src/assets/icons/iconfont.eot create mode 100644 front/src/assets/icons/iconfont.js create mode 100644 front/src/assets/icons/iconfont.svg create mode 100644 front/src/assets/icons/iconfont.ttf create mode 100644 front/src/assets/icons/iconfont.woff create mode 100644 front/src/assets/icons/iconfont.woff2 create mode 100644 front/src/assets/images/default_icon.png create mode 100644 front/src/assets/images/error-page/error-401.svg create mode 100644 front/src/assets/images/error-page/error-404.svg create mode 100644 front/src/assets/images/error-page/error-500.svg create mode 100644 front/src/assets/images/icon-qr-qq-wechat.png create mode 100644 front/src/assets/images/icon-social-bilibili.svg create mode 100644 front/src/assets/images/icon-social-juejin.svg create mode 100644 front/src/assets/images/icon-social-twitter.svg create mode 100644 front/src/assets/images/icon-social-zhihu.svg create mode 100644 front/src/assets/images/login-alipay.png create mode 100644 front/src/assets/images/login-bg.jpg create mode 100644 front/src/assets/images/login-logo.png create mode 100644 front/src/assets/images/login-sina.png create mode 100644 front/src/assets/images/login-taobao.png create mode 100644 front/src/assets/images/login_desc_bg.png create mode 100644 front/src/assets/images/login_logo.png create mode 100644 front/src/assets/images/logo-min.png create mode 100644 front/src/assets/images/logo.png create mode 100644 front/src/assets/images/message.png create mode 100644 front/src/assets/images/shadow.png create mode 100644 front/src/assets/images/slider/sub_slider_active.png create mode 100644 front/src/assets/images/slider/sub_slider_default.png create mode 100644 front/src/assets/style/lib/animate.css create mode 100644 front/src/components/active-plate/active-plate.vue create mode 100644 front/src/components/charts/bar.vue create mode 100644 front/src/components/charts/index.js create mode 100644 front/src/components/charts/pie.vue create mode 100644 front/src/components/charts/theme.json create mode 100644 front/src/components/common-icon/common-icon.vue create mode 100644 front/src/components/common-icon/index.js create mode 100644 front/src/components/count-to/count-to.vue create mode 100644 front/src/components/count-to/index.js create mode 100644 front/src/components/count-to/index.less create mode 100644 front/src/components/editor/editor.vue create mode 100644 front/src/components/editor/index.js create mode 100644 front/src/components/icons/icons.vue create mode 100644 front/src/components/icons/index.js create mode 100644 front/src/components/main/components/a-back-top/index.js create mode 100644 front/src/components/main/components/a-back-top/index.vue create mode 100644 front/src/components/main/components/fullscreen/fullscreen.vue create mode 100644 front/src/components/main/components/fullscreen/index.js create mode 100644 front/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less create mode 100644 front/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue create mode 100644 front/src/components/main/components/header-bar/custom-bread-crumb/index.js create mode 100644 front/src/components/main/components/header-bar/header-bar.less create mode 100644 front/src/components/main/components/header-bar/header-bar.vue create mode 100644 front/src/components/main/components/header-bar/index.js create mode 100644 front/src/components/main/components/header-bar/sider-trigger/index.js create mode 100644 front/src/components/main/components/header-bar/sider-trigger/sider-trigger.less create mode 100644 front/src/components/main/components/header-bar/sider-trigger/sider-trigger.vue create mode 100644 front/src/components/main/components/language/index.js create mode 100644 front/src/components/main/components/language/language.vue create mode 100644 front/src/components/main/components/notice/notice.vue create mode 100644 front/src/components/main/components/side-menu/collapsed-menu.vue create mode 100644 front/src/components/main/components/side-menu/index.js create mode 100644 front/src/components/main/components/side-menu/item-mixin.js create mode 100644 front/src/components/main/components/side-menu/mixin.js create mode 100644 front/src/components/main/components/side-menu/side-menu-item.vue create mode 100644 front/src/components/main/components/side-menu/side-menu.less create mode 100644 front/src/components/main/components/side-menu/side-menu.vue create mode 100644 front/src/components/main/components/tags-nav/index.js create mode 100644 front/src/components/main/components/tags-nav/tags-nav.less create mode 100644 front/src/components/main/components/tags-nav/tags-nav.vue create mode 100644 front/src/components/main/components/user/index.js create mode 100644 front/src/components/main/components/user/user.less create mode 100644 front/src/components/main/components/user/user.vue create mode 100644 front/src/components/main/index.js create mode 100644 front/src/components/main/main.less create mode 100644 front/src/components/main/main.vue create mode 100644 front/src/components/tables/edit.vue create mode 100644 front/src/components/tables/handle-btns.js create mode 100644 front/src/components/tables/index.js create mode 100644 front/src/components/tables/index.less create mode 100644 front/src/components/tables/tables.vue create mode 100644 front/src/config/index.js create mode 100644 front/src/constants/file.js create mode 100644 front/src/constants/index.js create mode 100644 front/src/constants/login.js create mode 100644 front/src/constants/notice.js create mode 100644 front/src/constants/privilege.js create mode 100644 front/src/directives/directives.js create mode 100644 front/src/directives/index.js create mode 100644 front/src/directives/module/clipboard.js create mode 100644 front/src/directives/module/draggable.js create mode 100644 front/src/directives/module/privilege.js create mode 100644 front/src/filters/index.js create mode 100644 front/src/lib/cookie.js create mode 100644 front/src/lib/http.js create mode 100644 front/src/lib/local.js create mode 100644 front/src/lib/menu-func.js create mode 100644 front/src/lib/printPlugs.js create mode 100644 front/src/lib/render-dom.js create mode 100644 front/src/lib/table-action.js create mode 100644 front/src/lib/util.js create mode 100644 front/src/locale/index.js create mode 100644 front/src/locale/lang/en-US.js create mode 100644 front/src/locale/lang/zh-CN.js create mode 100644 front/src/locale/lang/zh-TW.js create mode 100644 front/src/main.js create mode 100644 front/src/main.less create mode 100644 front/src/plugins/error-store/index.js create mode 100644 front/src/plugins/index.js create mode 100644 front/src/router/before-close.js create mode 100644 front/src/router/index.js create mode 100644 front/src/router/module/api-doc.js create mode 100644 front/src/router/module/email.js create mode 100644 front/src/router/module/employee.js create mode 100644 front/src/router/module/error.js create mode 100644 front/src/router/module/file.js create mode 100644 front/src/router/module/heart-beat.js create mode 100644 front/src/router/module/home.js create mode 100644 front/src/router/module/keep-alive.js create mode 100644 front/src/router/module/monitor.js create mode 100644 front/src/router/module/notice.js create mode 100644 front/src/router/module/reload.js create mode 100644 front/src/router/module/system-setting.js create mode 100644 front/src/router/module/task.js create mode 100644 front/src/router/module/three-router.js create mode 100644 front/src/router/module/user-log.js create mode 100644 front/src/router/routers.js create mode 100644 front/src/store/index.js create mode 100644 front/src/store/module/app.js create mode 100644 front/src/store/module/notice.js create mode 100644 front/src/store/module/user.js create mode 100644 front/src/themes/ReadMe.md create mode 100644 front/src/themes/index.less create mode 100644 front/src/views/api-doc/swagger.vue create mode 100644 front/src/views/email/email-list.vue create mode 100644 front/src/views/email/send-mail.vue create mode 100644 front/src/views/employee/components/department-employee-tree-item/department-employee-tree-item.vue create mode 100644 front/src/views/employee/components/department-employee-tree/department-employee-tree.vue create mode 100644 front/src/views/employee/position/position-list.vue create mode 100644 front/src/views/employee/role-employee/components/employee-table-add/employee-table-add.vue create mode 100644 front/src/views/employee/role-employee/components/employee-table-detail/employee-table-detail.vue create mode 100644 front/src/views/employee/role-employee/components/employee-table/employee-table.vue create mode 100644 front/src/views/employee/role-employee/role-employee-manage.vue create mode 100644 front/src/views/employee/role/components/role-data-scope/role-data-scope.vue create mode 100644 front/src/views/employee/role/components/role-list/role-list.vue create mode 100644 front/src/views/employee/role/components/role-tree/role-tree.vue create mode 100644 front/src/views/employee/role/role-manage.vue create mode 100644 front/src/views/error-page/401.vue create mode 100644 front/src/views/error-page/404.vue create mode 100644 front/src/views/error-page/500.vue create mode 100644 front/src/views/error-page/back-btn-group.vue create mode 100644 front/src/views/error-page/error-content.vue create mode 100644 front/src/views/error-page/error.less create mode 100644 front/src/views/file/file-list.vue create mode 100644 front/src/views/heart-beat/heart-beat-list.vue create mode 100644 front/src/views/home/components/card.vue create mode 100644 front/src/views/home/components/chart-bar.vue create mode 100644 front/src/views/home/components/chart-funnel.vue create mode 100644 front/src/views/home/components/chart-gauge.vue create mode 100644 front/src/views/home/components/chart-line.vue create mode 100644 front/src/views/home/components/chart-pie.vue create mode 100644 front/src/views/home/components/home-circle.vue create mode 100644 front/src/views/home/components/home-progress.vue create mode 100644 front/src/views/home/components/theme.json create mode 100644 front/src/views/home/home.vue create mode 100644 front/src/views/home/index.js create mode 100644 front/src/views/keep-alive/add-content.vue create mode 100644 front/src/views/keep-alive/content-list.vue create mode 100644 front/src/views/login/canvas.js create mode 100644 front/src/views/login/components/login-form.vue create mode 100644 front/src/views/login/login.less create mode 100644 front/src/views/login/login.vue create mode 100644 front/src/views/monitor/online-user.vue create mode 100644 front/src/views/monitor/sql.vue create mode 100644 front/src/views/notice/notice-list.vue create mode 100644 front/src/views/notice/person-notice.vue create mode 100644 front/src/views/reload/smart-reload/smart-reload-list.vue create mode 100644 front/src/views/system-setting/system-config/system-config.vue create mode 100644 front/src/views/system-setting/system-privilege/components/privilege-form.vue create mode 100644 front/src/views/system-setting/system-privilege/system-privilege.vue create mode 100644 front/src/views/task/task-list.vue create mode 100644 front/src/views/user-log/user-login-log.vue create mode 100644 front/src/views/user-log/user-operate-log.vue create mode 100644 front/tests/e2e/.eslintrc create mode 100644 front/tests/e2e/plugins/index.js create mode 100644 front/tests/e2e/specs/test.js create mode 100644 front/tests/e2e/support/commands.js create mode 100644 front/tests/e2e/support/index.js create mode 100644 front/tests/unit/.eslintrc.js create mode 100644 front/tests/unit/HelloWorld.spec.js create mode 100644 front/vscode/settings.json create mode 100644 front/vue.config.js create mode 100644 java/smart-admin-api/doc/readme.txt create mode 100644 java/smart-admin-api/pom.xml create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/SmartAdminApplication.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/ApiModelPropertyEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/DataScope.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/NoNeedLogin.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/NoValidPrivilege.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/OperateLog.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/CommentSortTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/JudgeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/ResponseCodeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/BaseEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/BaseEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/PageParamDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/PageResultDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/ResponseDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/exception/SmartBusinessException.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/exception/SmartResponseCodeException.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/AbstractHeartBeatCommand.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatLogger.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatRecordCommendInterface.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatRecordDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeatBeatRecordHelper.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/IpUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/StringUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/json/LongJsonDeserializer.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/json/LongJsonSerializer.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaColor.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaNoise.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaWordRenderer.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/SmartReloadManager.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/SmartReloadScheduler.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/abstracts/AbstractSmartReloadCommand.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/abstracts/AbstractSmartReloadCommand4Spring.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/annotation/SmartReload.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/AbstractSmartReloadObject.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/AnnotationReloadObject.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/InterfaceReloadObject.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/entity/ReloadItem.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/entity/SmartReloadResult.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadCommandInterface.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadThreadLogger.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadable.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/swagger/SmartSwaggerApiModelEnumPlugin.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/BigDecimalValidator.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/CheckBigDecimal.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/ComparisonSymbolEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/en/CheckEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/en/EnumValidator.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartAdminWebAppConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartDruidDataSourceConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartHeartBeatConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartKaptchaConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartMybatisPlusConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartRedisConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartReloadConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartRestTemplateConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartSwaggerApiModelEnumConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartSwaggerDynamicGroupConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartWebSocketConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SystemEnvironmentCondition.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/CommonConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SmartReloadTagConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SwaggerTagConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SystemEnvironmentEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/handler/SmartGlobalExceptionHandler.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/handler/SmartOperateLogAspect.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/interceptor/SmartAuthenticationInterceptor.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/listener/SmartAdminStartupRunner.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/constant/SqlOperateTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/dao/TableDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/CodeGeneratorDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/CodeGeneratorQueryColumnDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/ColumnVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/QueryFieldVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/service/CodeGeneratorComponent.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/service/CodeGeneratorService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/DataScopeController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/DataScopeRoleDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/MyBatisPlugin.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeViewTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeWhereInTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeAndViewTypeVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeBatchSetDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeBatchSetRoleDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeSelectVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeSqlConfigDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeViewTypeVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/entity/DataScopeRoleEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeSqlConfigService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeViewService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentResponseCodeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentTreeService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentCreateDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentUpdateDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/entity/DepartmentEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailSendStatusEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailConfigDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/entity/EmailEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/constant/EmployeeResponseCodeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/constant/EmployeeStatusEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/bo/EmployeeBO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeAddDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeBaseDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeBatchUpdateStatusDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeLoginFormDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeQueryExportDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdateDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdatePwdDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdateRolesDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/entity/EmployeeEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/vo/EmployeeVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/FileController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/FileDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileModuleTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileResponseCodeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileServiceNameConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileServiceTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileAddDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/OSSConfig.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/entity/FileEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/vo/FileVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/vo/UploadVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceAliYun.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceLocal.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceQiNiuYun.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/IFileService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorManager.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/constant/IdGeneratorEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/constant/IdGeneratorRuleTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorLastNumberDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorPOJO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorRecordDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/LogService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogDefaultEmpEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogOperateTypeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogOrderTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/dto/OrderOperateLogSaveDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/dto/SupplierOrderOperateVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/entity/OrderOperateLogEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/vo/OrderOperateLogVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginResponseCodeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginTokenService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/KaptchaVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginCacheDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginDetailVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginPrivilegeDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/RequestTokenBO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeManage.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/dao/NoticeDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/dao/NoticeReceiveRecordDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeAddDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeDetailVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReadCountDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReceiveDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReceiveQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeUpdateDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/entity/NoticeEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/entity/NoticeReceiveRecordEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionResponseCodeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionAddDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationAddDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationResultDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionResultVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionUpdateDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/entity/PositionEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/entity/PositionRelationEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/constant/PrivilegeResponseCodeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/constant/PrivilegeTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/controller/PrivilegeController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/dao/PrivilegeDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeFunctionDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeFunctionVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeMenuDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeMenuListVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeRequestUrlVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/entity/PrivilegeEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeEmployeeService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeRequestUrlService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/QuartzConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/TaskResultEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/TaskStatusEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/controller/QuartzController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/dao/QuartzTaskDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/dao/QuartzTaskLogDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzLogQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskLogVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/entity/QuartzTaskEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/entity/QuartzTaskLogEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTask.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTaskLogService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTaskService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/task/ITask.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/task/test/Example.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleResponseCodeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleAddDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleBatchDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleSelectedVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleUpdateDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/entity/RoleEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/domain/RoleEmployeeDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/domain/RoleEmployeeEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeSimpleDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeTreeVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/entity/RolePrivilegeEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadCommand.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/dao/ReloadItemDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/dao/ReloadResultDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadItemUpdateDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadItemVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadResultVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/entity/ReloadItemEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/entity/ReloadResultEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigController.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigDao.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigDataType.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigResponseCodeConst.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigAddDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigQueryDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigUpdateDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigVO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/entity/SystemConfigEntity.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/MessageTypeEnum.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/WebSocketServer.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/MessageCommonDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/MessageDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/WebSocketHeartBeatDTO.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/third/SmartApplicationContext.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/third/SmartRedisService.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBaseEnumUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBeanUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBigDecimalUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartDateUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartDigestUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartHttpUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartIPUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartPaginationUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartQuartzUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartRequestTokenUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartSendMailUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartStringUtil.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartThreadFactory.java create mode 100644 java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartVerificationUtil.java create mode 100644 java/smart-admin-api/src/main/resources/banner.txt create mode 100644 java/smart-admin-api/src/main/resources/dev/application.properties create mode 100644 java/smart-admin-api/src/main/resources/dev/log4j2.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/codegenerator/TableMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/datascope/DataScopeRoleMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/department/DepartmentMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/email/EmailMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/employee/EmployeeMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/file/FileMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/heartbeat/HeartBeatRecordMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/idgenerator/IdGeneratorMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/log/OrderOperateLogMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/log/UserLoginLogMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/log/UserOperateLogMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/notice/NoticeMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/notice/NoticeReceiveRecordMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/position/PositionMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/privilege/PrivilegeMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/quartz/QuartzTaskLogMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/quartz/QuartzTaskMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/role/RoleEmployeeMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/role/RoleMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/role/RolePrivilegeMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/smartreload/ReloadItemMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/smartreload/ReloadResultMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/mapper/systemconfig/SystemConfigMapper.xml create mode 100644 java/smart-admin-api/src/main/resources/pre/application.properties create mode 100644 java/smart-admin-api/src/main/resources/pre/log4j2.xml create mode 100644 java/smart-admin-api/src/main/resources/prod/application.properties create mode 100644 java/smart-admin-api/src/main/resources/prod/log4j2.xml create mode 100644 java/smart-admin-api/src/main/resources/sit/application.properties create mode 100644 java/smart-admin-api/src/main/resources/sit/log4j2.xml create mode 100644 java/smart-admin-api/src/main/resources/sql/quartz_mysql_2.3.0.sql create mode 100644 java/smart-admin-api/src/main/resources/sql/smart-admin.sql create mode 100644 java/smart-admin-api/src/main/resources/templates/codegenerator/Controller.java.vm create mode 100644 java/smart-admin-api/src/main/resources/templates/codegenerator/DTO.java.vm create mode 100644 java/smart-admin-api/src/main/resources/templates/codegenerator/Dao.java.vm create mode 100644 java/smart-admin-api/src/main/resources/templates/codegenerator/Dao.xml.vm create mode 100644 java/smart-admin-api/src/main/resources/templates/codegenerator/Entity.java.vm create mode 100644 java/smart-admin-api/src/main/resources/templates/codegenerator/QueryDTO.java.vm create mode 100644 java/smart-admin-api/src/main/resources/templates/codegenerator/Service.java.vm create mode 100644 java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/BaseTest.java create mode 100644 java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/SmartAdminApplicationTests.java create mode 100644 java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/module/codegenerator/CodeGeneratorServiceTest.java create mode 100644 java/smart-admin-parent/README.md create mode 100644 java/smart-admin-parent/pom.xml diff --git a/front/.babelrc b/front/.babelrc new file mode 100644 index 00000000..2a818842 --- /dev/null +++ b/front/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "@vue/app" + ] +} diff --git a/front/.editorconfig b/front/.editorconfig new file mode 100644 index 00000000..9d08a1a8 --- /dev/null +++ b/front/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/front/.env.development b/front/.env.development new file mode 100644 index 00000000..7c1979f5 --- /dev/null +++ b/front/.env.development @@ -0,0 +1,4 @@ +NODE_ENV=development +VUE_APP_TYPE=dev +VUE_APP_URL=http://172.16.0.145:10086/smart-admin-api/ +VUE_APP_SOCKET_URL=ws://172.16.0.145:10086/smart-admin-api/ diff --git a/front/.env.prod b/front/.env.prod new file mode 100644 index 00000000..522eeaaa --- /dev/null +++ b/front/.env.prod @@ -0,0 +1,5 @@ +NODE_ENV=production +VUE_APP_TYPE=prod +VUE_APP_URL=http://preview.smartadmin.1024lab.net/smart-admin-api/ +VUE_APP_SOCKET_URL=ws://preview.smartadmin.1024lab.net/smart-admin-api/ + diff --git a/front/.env.sit b/front/.env.sit new file mode 100644 index 00000000..ac2ac140 --- /dev/null +++ b/front/.env.sit @@ -0,0 +1,3 @@ +NODE_ENV=production +VUE_APP_TYPE=sit +VUE_APP_URL=http://172.16.0.145:10086/smart-admin-api/ diff --git a/front/.eslintignore b/front/.eslintignore new file mode 100644 index 00000000..e69de29b diff --git a/front/.eslintrc.js b/front/.eslintrc.js new file mode 100644 index 00000000..28180441 --- /dev/null +++ b/front/.eslintrc.js @@ -0,0 +1,34 @@ +module.exports = { + root: true, + "extends": [ + "plugin:vue/essential", + "@vue/standard" + ], + rules: { + "generator-star-spacing": "off", //生成器函数*的前后空格 + // allow debugger during development + "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off", + "vue/no-parsing-error": [2, { + "x-invalid-end-tag": false + }], + "no-const-assign": 2, //禁止修改const声明的变量 + "no-unused-vars": [0, { //禁止声明变量后却不使用 + // 允许声明未使用变量 + "vars": "all", + // 参数不检查 + "args": "none" + }], + "quotes": [2, "single"], //单引号 + "singleQuote": true, + "indent": 2, //缩进量 + "no-var": 2, //禁用var,用let和const代替 + "camelcase": 2, //强制驼峰法命名 + "eqeqeq": 1, //要求使用 === 和 !== 代替 == 和 != 操作符 + "no-eq-null": 2, //禁止对null使用==或!=运算符 + "no-sequences": 0, //禁用逗号操作符 + "semi": [2, "always"] //强制分号 + }, + parserOptions: { + parser: "babel-eslint" + } +} diff --git a/front/.gitignore b/front/.gitignore new file mode 100644 index 00000000..17032d3d --- /dev/null +++ b/front/.gitignore @@ -0,0 +1,28 @@ +.DS_Store +node_modules +/dist + +package-lock.json + +/tests/e2e/videos/ +/tests/e2e/screenshots/ + +# local env files +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw* + +build/env.js diff --git a/front/.postcssrc.js b/front/.postcssrc.js new file mode 100644 index 00000000..961986e2 --- /dev/null +++ b/front/.postcssrc.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + autoprefixer: {} + } +} diff --git a/front/.travis.yml b/front/.travis.yml new file mode 100644 index 00000000..07c971f8 --- /dev/null +++ b/front/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: stable +script: npm run lint +notifications: + email: false diff --git a/front/LICENSE b/front/LICENSE new file mode 100644 index 00000000..7ec88ac0 --- /dev/null +++ b/front/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 iView + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/front/README.md b/front/README.md new file mode 100644 index 00000000..fe637c03 --- /dev/null +++ b/front/README.md @@ -0,0 +1,13 @@ +### 启动讲解 + +###### 配置vscode +将 /vscode/settings.json文件配置到vscode中 + +###### 启动 +1 安装依赖: + +`npm install` + +2 运行本地环境 + +`npm run local` \ No newline at end of file diff --git a/front/cypress.json b/front/cypress.json new file mode 100644 index 00000000..470c7201 --- /dev/null +++ b/front/cypress.json @@ -0,0 +1,3 @@ +{ + "pluginsFile": "tests/e2e/plugins/index.js" +} diff --git a/front/doc/notice.txt b/front/doc/notice.txt new file mode 100644 index 00000000..8184781f --- /dev/null +++ b/front/doc/notice.txt @@ -0,0 +1,2 @@ +1 login-form.vue 去掉登录帐号提示 +2 login-form.vue 修改默认登录绑定帐号 \ No newline at end of file diff --git a/front/package.json b/front/package.json new file mode 100644 index 00000000..037f4779 --- /dev/null +++ b/front/package.json @@ -0,0 +1,86 @@ +{ + "name": "smart-admin", + "version": "1.0.0", + "author": "1024创新实验室<1024lab@sina.com>", + "private": false, + "scripts": { + "dev": "vue-cli-service serve --open", + "local": "vue-cli-service serve --open --mode local", + "build": "vue-cli-service build", + "lint": "vue-cli-service lint", + "test:unit": "vue-cli-service test:unit", + "test:e2e": "vue-cli-service test:e2e", + "development": "vue-cli-service build --mode development", + "sit": "vue-cli-service build --mode sit", + "prod": "vue-cli-service build --mode prod" + }, + "dependencies": { + "@antv/g2": "^3.5.8-beta.1", + "axios": "^0.18.0", + "clipboard": "^2.0.0", + "codemirror": "^5.38.0", + "countup": "^1.8.2", + "cropperjs": "^1.2.2", + "dayjs": "^1.7.7", + "decimal.js": "^10.1.1", + "echarts": "^4.0.4", + "gq-plus": "^2.1.5", + "html2canvas": "^1.0.0-alpha.12", + "jquery": "^2.2.3", + "js-cookie": "^2.2.0", + "lodash": "^4.17.15", + "mavon-editor": "^2.7.5", + "simplemde": "^1.11.2", + "sortablejs": "^1.7.0", + "tree-table-vue": "^1.1.0", + "v-org-tree": "^1.0.6", + "view-design": "^4.0.2", + "vue": "^2.5.10", + "vue-data-loading": "^0.2.4", + "vue-enum": "", + "vue-i18n": "^7.8.0", + "vue-infinite-loading": "^2.4.4", + "vue-json-viewer": "^2.2.0", + "vue-json-views": "^0.1.1", + "vue-router": "^3.1.3", + "vue-slick": "^1.1.15", + "vuedraggable": "^2.16.0", + "vuex": "^3.0.1", + "wangeditor": "^3.1.1", + "xlsx": "^0.13.3" + }, + "devDependencies": { + "@vue/cli-plugin-babel": "^3.0.1", + "@vue/cli-plugin-eslint": "^3.0.1", + "@vue/cli-plugin-unit-mocha": "^3.0.1", + "@vue/cli-service": "^3.0.1", + "@vue/eslint-config-standard": "^3.0.0-beta.10", + "@vue/test-utils": "^1.0.0-beta.10", + "chai": "^4.1.2", + "compression-webpack-plugin": "^3.0.0", + "eslint-plugin-cypress": "^2.0.1", + "less": "^2.7.3", + "less-loader": "^4.0.5", + "lint-staged": "^6.0.0", + "uglifyjs-webpack-plugin": "^1.2.4", + "vue-template-compiler": "^2.5.13" + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 8" + ], + "gitHooks": { + "pre-commit": "lint-staged" + }, + "lint-staged": { + "*.js": [ + "vue-cli-service lint", + "git add" + ], + "*.vue": [ + "vue-cli-service lint", + "git add" + ] + } +} diff --git a/front/public/favicon.ico b/front/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5e59671b6e407a6a4ca45ce51e31ffa086ff3cad GIT binary patch literal 16958 zcmeI4Yitx%6oBtia8Wen{Zvb}C|HTnA3kD8D=})+D4M81}3b@15D*_6JF)pR>aCO-45(BLM4$R8SE_rLi(FJFKARX#%W-pP?R_;2a!= zH82%Q!FR2ZO9V#3GWZGV;5;0M1F#C-f;%A+=GL3)N7o5%gAp)#$HqS6PR=cDZNJ;<*ZQ^O)kAV4=3>ybJ3rHQ(}@pmT0)$zmROz8kA&S|viIubp7}bY z)&tU*Ke={?DIjY;BX5`PZkrF$Gfwl1%cjL&&4L@e`L*oV&$-!=`N2-^&x@e1Pb{fN z?i+`o#fQ)KDvosrWBpoB%p2hlwB+pB{z8v6Nyh5>i`bsk%pBy#og4c6gN-rQQ?rNa z+TC$aVK)Ifm|`{Su0YO#3t;r^(jQ^F41(t1dSWKQor~U#6X{J0l5 z+p2omVrl(pd_QgRtLu>UBF{k?F$}uz(OKt|SRLU{(DB`JKDIh$nq<6R{l6RXaE>e< z^oJ#mJEq?Ln6aI0@zKj#nGSNEgXTf*G1fUH&OA$ATd+&3TkkX8ul|26IX#2jlTd4k zr)$@8FXIO3m=<{-`V*FT-g#NhxNcrQ#CYD4Pr^G^?=#-7es5g8pSq`D+YOdjV(Qwp zl z8Z7l!Vr%R*V*8!{F+MS0u=x}{e&rofzRg?!Q|)fue#YG4=Z|A0V0<1yUz_-(WY6}^ zz1==j+gqzsv0t_MCaz!o^3E^U7}I>q+Puc*SL^XF*Q6TA$jzf`WWNHg)V3BW@0JHa za*}6;y4v|ezW!lTp9`jQ&zv;XyZN z;)wo1u+=a6Q}6~9g4GW()|d<&TfZ-cBsxh4#QY}SLGqk6{6w@vx} z@gTeii^2B3m$KVd)zje}P2L%5;5~jp)GlLQ25p}v z$wi*wvw3cG&(n5nMnT5fw#9Mlv1?8JI)7OgQxE}dXO!er z3e#W>9ENis&&qNy*as^?zB3LC@)dL(A8k>;v5uhFm%{O|{_y0 zg)E3+Fc2BXKp~SDAR`SJh!i(SoJW%+fO8HZ(N06gB#o3LEfS8aj + + + + + + + + + + +
+ + + + diff --git a/front/src/App.vue b/front/src/App.vue new file mode 100644 index 00000000..0d189502 --- /dev/null +++ b/front/src/App.vue @@ -0,0 +1,31 @@ + + + + + + diff --git a/front/src/api/data-scope.js b/front/src/api/data-scope.js new file mode 100644 index 00000000..14799315 --- /dev/null +++ b/front/src/api/data-scope.js @@ -0,0 +1,15 @@ +import { postAxios, getAxios } from '@/lib/http'; +export const dataScopeApi = { + // 批量设置某角色数据范围 + updateDataScope: data => { + return postAxios('/dataScope/batchSet', data); + }, + // 数据权限列表 + getDataScopeList: () => { + return getAxios('/dataScope/list'); + }, + // 获取某角色所设置的数据范围 + getDataScopeByRoleId: roleId => { + return getAxios('/dataScope/listByRole/' + roleId); + } +}; diff --git a/front/src/api/department.js b/front/src/api/department.js new file mode 100644 index 00000000..2e4ebfa0 --- /dev/null +++ b/front/src/api/department.js @@ -0,0 +1,47 @@ +import { postAxios, getAxios } from '@/lib/http'; +export const departmentApi = { + // 加载所有的部门子部门 + getLoadDepartment: () => { + return getAxios('/department/list'); + }, + // 查询部门及员工列表 + getDepartmentEmployeeList: () => { + return getAxios('/department/listEmployee'); + }, + // 添加部门 + addDepartment: (data) => { + return postAxios('/department/add', data); + }, + // 编辑部门 + updateDepartment: (data) => { + return postAxios('/department/update', data); + }, + // 删除部门 + deleteDepartment: (data) => { + return postAxios('/department/delete/' + data); + }, + // 根据id获取部门信息 + getDepartmentById: (data) => { + return getAxios('/department/query/' + data); + }, + // 查询部门列表 + getDepartmentAll: () => { + return getAxios('/department/listAll'); + }, + // 根据部门名称获取员工列表 + getListEmployeeByDepartmentName: (departmentName) => { + return getAxios('/department/listEmployeeByDepartmentName?departmentName=' + departmentName); + }, + // 上下移动 + upOrDown: (departmentId, swapId) => { + return getAxios('/department/upOrDown/' + departmentId + '/' + swapId); + }, + // 升级 + upGrade: (departmentId) => { + return getAxios('/department/upgrade/' + departmentId); + }, + // 降级 + downGrade: (departmentId, preId) => { + return getAxios('/department/downgrade/' + departmentId + '/' + preId); + } +}; diff --git a/front/src/api/email.js b/front/src/api/email.js new file mode 100644 index 00000000..cb541021 --- /dev/null +++ b/front/src/api/email.js @@ -0,0 +1,27 @@ +import { postAxios, getAxios } from '@/lib/http'; +export const emailApi = { + // 新增邮件 + addEmail: (data) => { + return postAxios('/email/add', data); + }, + // 分页查询邮件 + getEmail: (data) => { + return postAxios('/email/page/query', data); + }, + // 删除邮件 + deleteEmail: (id) => { + return getAxios('/email/delete/' + id); + }, + // 查看邮件详情 + getEmailDetails: (id) => { + return getAxios('/email/detail/' + id); + }, + // 发送邮件 + sendEmail: (id) => { + return getAxios('/email/send/' + id); + }, + // 更新编辑邮件 + updateEmail: (data) => { + return postAxios('/email/update', data); + } +}; diff --git a/front/src/api/employee.js b/front/src/api/employee.js new file mode 100644 index 00000000..7f1d8001 --- /dev/null +++ b/front/src/api/employee.js @@ -0,0 +1,43 @@ +import { postAxios, getAxios } from '@/lib/http'; +export const employeeApi = { + // 员工管理查询 + getEmployeeList: (data) => { + return postAxios('/employee/query', data); + }, + // 添加员工 + addEmployee: (data) => { + return postAxios('/employee/add', data); + }, + // 更新员工信息 + updateEmployee: (data) => { + return postAxios('/employee/update', data); + }, + // 禁用启用单个员工 + updateStatus: (employeeId, status) => { + return getAxios('/employee/updateStatus/' + employeeId + '/' + status); + }, + // 批量禁用 + updateStatusBatch: (data) => { + return postAxios('/employee/batchUpdateStatus', data); + }, + // 单个员工角色授权 + updateRoles: (data) => { + return postAxios('/employee/updateRoles', data); + }, + // 修改密码 + updatePwd: (data) => { + return postAxios('/employee/updatePwd', data); + }, + // 重置密码 + resetPassword: (employeeId) => { + return getAxios('/employee/resetPasswd/' + employeeId); + }, + // 通过部门id获取当前部门的人员&没有部门的人 + getListEmployeeByDeptId: (departmentId) => { + return getAxios('/employee/listEmployeeByDeptId/' + departmentId); + }, + // 删除员工 + deleteEmployee: (employeeId) => { + return postAxios('/employee/delete/' + employeeId); + } +}; diff --git a/front/src/api/file.js b/front/src/api/file.js new file mode 100644 index 00000000..91bcc147 --- /dev/null +++ b/front/src/api/file.js @@ -0,0 +1,28 @@ +import { postAxios, getAxios } from '@/lib/http'; +import config from '@/config'; +const baseUrl = config.baseUrl.apiUrl; +export const fileApi = { + // 系统文件查询 + queryFileList: data => { + return postAxios('/api/file/query', data); + }, + // 系统文件下载通过接口 + downLoadFile: id => { + return getAxios('/api/file/downLoad?id=' + id); + }, + // 文件上传 + fileUpload: (type, data) => { + // return postAxios('/api/file/localUpload/' + type, data); + return this.fileUploadUrl; + }, + // 文件保存 + addFile: data => { + return postAxios('/api/file/save', data); + }, + // 上传路径:本地 + fileUploadLocalUrl: baseUrl + '/api/file/localUpload/', + // 上传路径:阿里OSS + fileUploadAliUrl: baseUrl + '/api/file/aliYunUpload/', + // 上传路径:七牛 + fileUploadQiNiuUrl: baseUrl + '/api/file/qiNiuUpload/' +}; diff --git a/front/src/api/heart-beat.js b/front/src/api/heart-beat.js new file mode 100644 index 00000000..c5ec2486 --- /dev/null +++ b/front/src/api/heart-beat.js @@ -0,0 +1,7 @@ +import { postAxios, getAxios } from '@/lib/http'; +export const heartBeatApi = { + // 分页查询所有岗位 + queryHeartBeatRecord: data => { + return postAxios('/heartBeat/query', data); + } +}; diff --git a/front/src/api/login.js b/front/src/api/login.js new file mode 100644 index 00000000..83338d56 --- /dev/null +++ b/front/src/api/login.js @@ -0,0 +1,19 @@ +import { postAxios, getAxios } from '@/lib/http'; +export const loginApi = { + // 登录 + login: data => { + return postAxios('/session/login', data); + }, + // 根据token获取session + getSession: () => { + return getAxios('/session/get'); + }, + // 登出 + logout: (token) => { + return getAxios(`/session/logOut?x-access-token=${token}`); + }, + // 获取验证码 + getVerificationCode: () => { + return getAxios('/session/verificationCode'); + } +}; diff --git a/front/src/api/notice.js b/front/src/api/notice.js new file mode 100644 index 00000000..fad6ad83 --- /dev/null +++ b/front/src/api/notice.js @@ -0,0 +1,43 @@ +// 任务调度API +import { + postAxios, + getAxios +} from '@/lib/http'; +export const noticeApi = { + // 查询消息列表 + getNoticeList: (data) => { + return postAxios('/notice/page/query', data); + }, + // 未读消息列表 + getNoticeUnreadList: (data) => { + return postAxios('/notice/unread/page/query', data); + }, + // 查询个人消息列表 + getPersonNoticeList: (data) => { + return postAxios('/notice/receive/page/query', data); + }, + // 添加消息 + addNotice: (data) => { + return postAxios('/notice/add', data); + }, + // 标记已读 + addNoticeRecord: (id) => { + return getAxios(`/notice/read/${id}`); + }, + // 修改消息 + updateNotice: (data) => { + return postAxios('/notice/update', data); + }, + // 删除消息 + deleteNotice: (id) => { + return getAxios(`/notice/delete/${id}`); + }, + // 获取通知详情 + getNoticeDetail: (id) => { + return getAxios(`/notice/detail/${id}`); + }, + // 发送消息 + sendNotice: (id) => { + return getAxios(`/notice/send/${id}`); + } +}; diff --git a/front/src/api/online-user.js b/front/src/api/online-user.js new file mode 100644 index 00000000..b7847b9b --- /dev/null +++ b/front/src/api/online-user.js @@ -0,0 +1,12 @@ +// 任务调度API +import { + postAxios, + getAxios +} from '@/lib/http'; +export const onlineUserApi = { + // 查询在线员工列表 + getOnlineUserList: (data) => { + return postAxios('/userOnLine/query', data); + } + +}; diff --git a/front/src/api/position.js b/front/src/api/position.js new file mode 100644 index 00000000..3756c457 --- /dev/null +++ b/front/src/api/position.js @@ -0,0 +1,19 @@ +import { postAxios, getAxios } from '@/lib/http'; +export const positionApi = { + // 分页查询所有岗位 + getPositionListPage: data => { + return postAxios('/position/getListPage', data); + }, + // 更新岗位 + updatePosition: data => { + return postAxios('/position/update', data); + }, + // 添加岗位 + addPosition: data => { + return postAxios('/position/add', data); + }, + // 根据ID删除岗位 + deletePosition: id => { + return getAxios('/position/remove/' + id); + } +}; diff --git a/front/src/api/privilege.js b/front/src/api/privilege.js new file mode 100644 index 00000000..3c7a09dd --- /dev/null +++ b/front/src/api/privilege.js @@ -0,0 +1,32 @@ +import { postAxios, getAxios } from '@/lib/http'; + +export const privilegeApi = { + // 获取所有请求路径 + getAllUrl: data => { + return getAxios('/privilege/getAllUrl'); + }, + // 获取全部菜单列表 + getMenuList: data => { + return postAxios('/privilege/menu/queryAll'); + }, + // 菜单批量保存 + addBatchSaveMenu: data => { + return postAxios('/privilege/menu/batchSaveMenu', data); + }, + // 查询菜单功能点 + queryPrivilegeFunctionList: menuKey => { + return postAxios('/privilege/function/query/' + menuKey); + }, + // 保存更新功能点 + addOrUpdate: data => { + return postAxios('/privilege/function/saveOrUpdate', data); + }, + // 更新角色权限 + getRolePower: data => { + return postAxios('/privilege/updateRolePrivilege', data); + }, + // 获取角色可选的功能权限 + getListPrivilegeByRoleId: id => { + return getAxios('/privilege/listPrivilegeByRoleId/' + id); + } +}; diff --git a/front/src/api/role.js b/front/src/api/role.js new file mode 100644 index 00000000..be5f338a --- /dev/null +++ b/front/src/api/role.js @@ -0,0 +1,58 @@ +import { postAxios, getAxios } from '@/lib/http'; +export const roleApi = { + // 添加角色 + addRole: (remark, roleName) => { + const data = { + remark: remark, + roleName: roleName + }; + return postAxios('/role/add', data); + }, + // 删除角色 + deleteRole: id => { + return getAxios('/role/delete/' + id); + }, + // 修改角色 + updateRole: (id, remark, roleName) => { + const data = { + id: id, + remark: remark, + roleName: roleName + }; + return postAxios('/role/update', data); + }, + // 获取角色数据 + getRoleDetail: id => { + return getAxios('/role/get/' + id); + }, + // 加载角色列表 + getAllRole: () => { + return getAxios('role/getAll'); + }, + // 根据角色名字获取对应成员列表 + getListEmployee: data => { + return postAxios('/role/listEmployee', data); + }, + // 根据角色id获取角色成员-员工列表 + getAllListEmployee: id => { + return getAxios('/role/listAllEmployee/' + id); + }, + // 从角色成员列表中移除员工 + deleteEmployeeRole: param => { + return getAxios('/role/removeEmployee?employeeId=' + param.employeeId + '&roleId=' + param.roleId); + }, + // 从角色成员列表中批量移除员工 + deleteEmployeeList: data => { + return postAxios('/role/removeEmployeeList', data); + }, + + // 添加角色成员方法 + addEmployeeListRole: data => { + return postAxios('/role/addEmployeeList', data); + }, + // 通过员工id获取所有角色以及员工具有的角色 + getRoles: id => { + return getAxios('/role/getRoles/' + id); + }, + +}; diff --git a/front/src/api/smart-reload.js b/front/src/api/smart-reload.js new file mode 100644 index 00000000..8ee701ed --- /dev/null +++ b/front/src/api/smart-reload.js @@ -0,0 +1,20 @@ +// smartReloadAPI +import { + postAxios, + getAxios +} from '@/lib/http'; +export const smartReloadApi = { + // 查询所有 + getSmartReloadList: () => { + return getAxios('/smartReload/all'); + }, + // 更新单条数据 + updateSmartReloadData: (data) => { + return postAxios('/smartReload/update', data); + }, + // 获取执行结果 + getSmartReloadResult: (tag) => { + return getAxios(`/smartReload/result/${tag}`); + } + +}; diff --git a/front/src/api/system-config.js b/front/src/api/system-config.js new file mode 100644 index 00000000..392dd942 --- /dev/null +++ b/front/src/api/system-config.js @@ -0,0 +1,31 @@ +// 系统参数API +import { + postAxios, + getAxios +} from '@/lib/http'; +export const systemConfigApi = { + // 查询系统参数列表 + getSystemConfigList: (data) => { + return postAxios('/systemConfig/getListPage', data); + }, + // 添加系统参数 + addSystemConfig: (data) => { + return postAxios('/systemConfig/add', data); + }, + // 更新单条系统参数 + updateSystemConfig: (data) => { + return postAxios('/systemConfig/update', data); + }, + // 通过key获取对应的信息 + getConfigListByKey: (key) => { + return getAxios(`/systemConfig/selectByKey?configKey=${key}`); + }, + // 根据分组查询所有系统配置 + getListByGroup: (group) => { + return getAxios(`/systemConfig/getListByGroup?group=${group}`); + }, + // 获取系统版本信息 + getCodeVersion: () => { + return getAxios('/codeVersion'); + } +}; diff --git a/front/src/api/task-manage.js b/front/src/api/task-manage.js new file mode 100644 index 00000000..49eec6cf --- /dev/null +++ b/front/src/api/task-manage.js @@ -0,0 +1,35 @@ +// 任务调度API +import { + postAxios, + getAxios +} from '@/lib/http'; +export const taskApi = { + // 查询任务列表 + getTaskList: (data) => { + return postAxios('/quartz/task/query', data); + }, + // 添加或更新任务 + addOrUpdateTask: (data) => { + return postAxios('/quartz/task/saveOrUpdate', data); + }, + // 查询任务日志 + getTaskLog: (data) => { + return postAxios('/quartz/task/queryLog', data); + }, + // 暂停任务 + updateTaskPause: (taskId) => { + return getAxios(`/quartz/task/pause/${taskId}`); + }, + // 运行任务 + updateTaskRun: (taskId) => { + return getAxios(`/quartz/task/run/${taskId}`); + }, + // 恢复任务 + updateTaskResume: (taskId) => { + return getAxios(`/quartz/task/resume/${taskId}`); + }, + // 删除任务 + deleteTasks: (taskId) => { + return getAxios(`/quartz/task/delete/${taskId}`); + } +}; diff --git a/front/src/api/user-log.js b/front/src/api/user-log.js new file mode 100644 index 00000000..eb3a3ad9 --- /dev/null +++ b/front/src/api/user-log.js @@ -0,0 +1,28 @@ +// 用户日志API +import { + postAxios, + getAxios +} from '@/lib/http.js'; +export const userLogApi = { + // 查询用户操作日志 + getUserOperateLogPage: (data) => { + return postAxios('/userOperateLog/page/query', data); + }, + // 用户操作日志详情 + detailUserOperateLog: (data) => { + return getAxios('/userOperateLog/detail/' + data); + }, + // 删除用户操作日志 + deleteUserOperateLog: (data) => { + return getAxios('/userOperateLog/delete/' + data); + }, + // 查询用户登录日志 + getUserLoginLogPage: (data) => { + return postAxios('/userLoginLog/page/query', data); + }, + // 删除用户登录日志 + deleteUserLoginLog: (data) => { + return getAxios('/userLoginLog/delete/' + data); + } + +}; diff --git a/front/src/api/user.js b/front/src/api/user.js new file mode 100644 index 00000000..8ac0a2a1 --- /dev/null +++ b/front/src/api/user.js @@ -0,0 +1,20 @@ +import { postAxios, getAxios } from '@/lib/http'; + +export const login = ({ userName, password }) => { + const data = { + userName, + password + }; + return postAxios('login', data); +}; + +export const getUserInfo = (token) => { + let params = { + token + }; + return getAxios('get_info', params); +}; + +export const logout = (token) => { + return postAxios('logout', {}); +}; diff --git a/front/src/assets/icons/demo.css b/front/src/assets/icons/demo.css new file mode 100644 index 00000000..a67054a0 --- /dev/null +++ b/front/src/assets/icons/demo.css @@ -0,0 +1,539 @@ +/* Logo 字体 */ +@font-face { + font-family: "iconfont logo"; + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); +} + +.logo { + font-family: "iconfont logo"; + font-size: 160px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* tabs */ +.nav-tabs { + position: relative; +} + +.nav-tabs .nav-more { + position: absolute; + right: 0; + bottom: 0; + height: 42px; + line-height: 42px; + color: #666; +} + +#tabs { + border-bottom: 1px solid #eee; +} + +#tabs li { + cursor: pointer; + width: 100px; + height: 40px; + line-height: 40px; + text-align: center; + font-size: 16px; + border-bottom: 2px solid transparent; + position: relative; + z-index: 1; + margin-bottom: -1px; + color: #666; +} + + +#tabs .active { + border-bottom-color: #f00; + color: #222; +} + +.tab-container .content { + display: none; +} + +/* 页面布局 */ +.main { + padding: 30px 100px; + width: 960px; + margin: 0 auto; +} + +.main .logo { + color: #333; + text-align: left; + margin-bottom: 30px; + line-height: 1; + height: 110px; + margin-top: -50px; + overflow: hidden; + *zoom: 1; +} + +.main .logo a { + font-size: 160px; + color: #333; +} + +.helps { + margin-top: 40px; +} + +.helps pre { + padding: 20px; + margin: 10px 0; + border: solid 1px #e7e1cd; + background-color: #fffdef; + overflow: auto; +} + +.icon_lists { + width: 100% !important; + overflow: hidden; + *zoom: 1; +} + +.icon_lists li { + width: 100px; + margin-bottom: 10px; + margin-right: 20px; + text-align: center; + list-style: none !important; + cursor: default; +} + +.icon_lists li .code-name { + line-height: 1.2; +} + +.icon_lists .icon { + display: block; + height: 100px; + line-height: 100px; + font-size: 42px; + margin: 10px auto; + color: #333; + -webkit-transition: font-size 0.25s linear, width 0.25s linear; + -moz-transition: font-size 0.25s linear, width 0.25s linear; + transition: font-size 0.25s linear, width 0.25s linear; +} + +.icon_lists .icon:hover { + font-size: 100px; +} + +.icon_lists .svg-icon { + /* 通过设置 font-size 来改变图标大小 */ + width: 1em; + /* 图标和文字相邻时,垂直对齐 */ + vertical-align: -0.15em; + /* 通过设置 color 来改变 SVG 的颜色/fill */ + fill: currentColor; + /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 + normalize.css 中也包含这行 */ + overflow: hidden; +} + +.icon_lists li .name, +.icon_lists li .code-name { + color: #666; +} + +/* markdown 样式 */ +.markdown { + color: #666; + font-size: 14px; + line-height: 1.8; +} + +.highlight { + line-height: 1.5; +} + +.markdown img { + vertical-align: middle; + max-width: 100%; +} + +.markdown h1 { + color: #404040; + font-weight: 500; + line-height: 40px; + margin-bottom: 24px; +} + +.markdown h2, +.markdown h3, +.markdown h4, +.markdown h5, +.markdown h6 { + color: #404040; + margin: 1.6em 0 0.6em 0; + font-weight: 500; + clear: both; +} + +.markdown h1 { + font-size: 28px; +} + +.markdown h2 { + font-size: 22px; +} + +.markdown h3 { + font-size: 16px; +} + +.markdown h4 { + font-size: 14px; +} + +.markdown h5 { + font-size: 12px; +} + +.markdown h6 { + font-size: 12px; +} + +.markdown hr { + height: 1px; + border: 0; + background: #e9e9e9; + margin: 16px 0; + clear: both; +} + +.markdown p { + margin: 1em 0; +} + +.markdown>p, +.markdown>blockquote, +.markdown>.highlight, +.markdown>ol, +.markdown>ul { + width: 80%; +} + +.markdown ul>li { + list-style: circle; +} + +.markdown>ul li, +.markdown blockquote ul>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown>ul li p, +.markdown>ol li p { + margin: 0.6em 0; +} + +.markdown ol>li { + list-style: decimal; +} + +.markdown>ol li, +.markdown blockquote ol>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown code { + margin: 0 3px; + padding: 0 5px; + background: #eee; + border-radius: 3px; +} + +.markdown strong, +.markdown b { + font-weight: 600; +} + +.markdown>table { + border-collapse: collapse; + border-spacing: 0px; + empty-cells: show; + border: 1px solid #e9e9e9; + width: 95%; + margin-bottom: 24px; +} + +.markdown>table th { + white-space: nowrap; + color: #333; + font-weight: 600; +} + +.markdown>table th, +.markdown>table td { + border: 1px solid #e9e9e9; + padding: 8px 16px; + text-align: left; +} + +.markdown>table th { + background: #F7F7F7; +} + +.markdown blockquote { + font-size: 90%; + color: #999; + border-left: 4px solid #e9e9e9; + padding-left: 0.8em; + margin: 1em 0; +} + +.markdown blockquote p { + margin: 0; +} + +.markdown .anchor { + opacity: 0; + transition: opacity 0.3s ease; + margin-left: 8px; +} + +.markdown .waiting { + color: #ccc; +} + +.markdown h1:hover .anchor, +.markdown h2:hover .anchor, +.markdown h3:hover .anchor, +.markdown h4:hover .anchor, +.markdown h5:hover .anchor, +.markdown h6:hover .anchor { + opacity: 1; + display: inline-block; +} + +.markdown>br, +.markdown>p>br { + clear: both; +} + + +.hljs { + display: block; + background: white; + padding: 0.5em; + color: #333333; + overflow-x: auto; +} + +.hljs-comment, +.hljs-meta { + color: #969896; +} + +.hljs-string, +.hljs-variable, +.hljs-template-variable, +.hljs-strong, +.hljs-emphasis, +.hljs-quote { + color: #df5000; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-type { + color: #a71d5d; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute { + color: #0086b3; +} + +.hljs-section, +.hljs-name { + color: #63a35c; +} + +.hljs-tag { + color: #333333; +} + +.hljs-title, +.hljs-attr, +.hljs-selector-id, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #795da3; +} + +.hljs-addition { + color: #55a532; + background-color: #eaffea; +} + +.hljs-deletion { + color: #bd2c00; + background-color: #ffecec; +} + +.hljs-link { + text-decoration: underline; +} + +/* 代码高亮 */ +/* PrismJS 1.15.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre)>code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre)>code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} diff --git a/front/src/assets/icons/demo_index.html b/front/src/assets/icons/demo_index.html new file mode 100644 index 00000000..2c777b68 --- /dev/null +++ b/front/src/assets/icons/demo_index.html @@ -0,0 +1,722 @@ + + + + + IconFont Demo + + + + + + + + + + + +
+

+ +
+
+
    + +
  • + +
    多级菜单
    +
    &#xe608;
    +
  • + +
  • + +
    导航展开
    +
    &#xe609;
    +
  • + +
  • + +
    导航折叠
    +
    &#xe60a;
    +
  • + +
  • + +
    向上箭头
    +
    &#xe60b;
    +
  • + +
  • + +
    向左箭头
    +
    &#xe60c;
    +
  • + +
  • + +
    向右箭头
    +
    &#xe60d;
    +
  • + +
  • + +
    关闭按钮
    +
    &#xe60e;
    +
  • + +
  • + +
    数据上传
    +
    &#xe60f;
    +
  • + +
  • + +
    系统监控
    +
    &#xe610;
    +
  • + +
  • + +
    邮件管理
    +
    &#xe611;
    +
  • + +
  • + +
    小屏
    +
    &#xe612;
    +
  • + +
  • + +
    人员管理
    +
    &#xe613;
    +
  • + +
  • + +
    向下拉
    +
    &#xe614;
    +
  • + +
  • + +
    excel导入导出
    +
    &#xe615;
    +
  • + +
  • + +
    向下箭头
    +
    &#xe616;
    +
  • + +
  • + +
    首页
    +
    &#xe617;
    +
  • + +
  • + +
    系统设置
    +
    &#xe618;
    +
  • + +
  • + +
    消息
    +
    &#xe619;
    +
  • + +
  • + +
    全屏
    +
    &#xe61a;
    +
  • + +
  • + +
    组件
    +
    &#xe61b;
    +
  • + +
  • + +
    news
    +
    &#xe61e;
    +
  • + +
  • + +
    定时任务
    +
    &#xe622;
    +
  • + +
  • + +
    动态加载
    +
    &#xe623;
    +
  • + +
  • + +
    接口文档
    +
    &#xe624;
    +
  • + +
+
+

Unicode 引用

+
+ +

Unicode 是字体在网页端最原始的应用方式,特点是:

+
    +
  • 兼容性最好,支持 IE6+,及所有现代浏览器。
  • +
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • +
  • 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
  • +
+
+

注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式

+
+

Unicode 使用步骤如下:

+

第一步:拷贝项目下面生成的 @font-face

+
@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.eot');
+  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
+      url('iconfont.woff2') format('woff2'),
+      url('iconfont.woff') format('woff'),
+      url('iconfont.ttf') format('truetype'),
+      url('iconfont.svg#iconfont') format('svg');
+}
+
+

第二步:定义使用 iconfont 的样式

+
.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+

第三步:挑选相应图标并获取字体编码,应用于页面

+
+<span class="iconfont">&#x33;</span>
+
+
+

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    + 多级菜单 +
    +
    .iconduojicaidan +
    +
  • + +
  • + +
    + 导航展开 +
    +
    .icondaohangzhankai +
    +
  • + +
  • + +
    + 导航折叠 +
    +
    .icondaohangzhedie +
    +
  • + +
  • + +
    + 向上箭头 +
    +
    .iconxiangshangjiantou +
    +
  • + +
  • + +
    + 向左箭头 +
    +
    .iconxiangzuojiantou +
    +
  • + +
  • + +
    + 向右箭头 +
    +
    .iconxiangyoujiantou +
    +
  • + +
  • + +
    + 关闭按钮 +
    +
    .iconguanbianniu +
    +
  • + +
  • + +
    + 数据上传 +
    +
    .iconshujushangchuan +
    +
  • + +
  • + +
    + 系统监控 +
    +
    .iconxitongjiankong +
    +
  • + +
  • + +
    + 邮件管理 +
    +
    .iconyoujianguanli +
    +
  • + +
  • + +
    + 小屏 +
    +
    .iconxiaoping +
    +
  • + +
  • + +
    + 人员管理 +
    +
    .iconrenyuanguanli +
    +
  • + +
  • + +
    + 向下拉 +
    +
    .iconxiangxiala +
    +
  • + +
  • + +
    + excel导入导出 +
    +
    .iconexceldaorudaochu +
    +
  • + +
  • + +
    + 向下箭头 +
    +
    .iconxiangxiajiantou +
    +
  • + +
  • + +
    + 首页 +
    +
    .iconshouye +
    +
  • + +
  • + +
    + 系统设置 +
    +
    .iconxitongshezhi +
    +
  • + +
  • + +
    + 消息 +
    +
    .iconxiaoxi +
    +
  • + +
  • + +
    + 全屏 +
    +
    .iconquanping +
    +
  • + +
  • + +
    + 组件 +
    +
    .iconzujian +
    +
  • + +
  • + +
    + news +
    +
    .iconnews +
    +
  • + +
  • + +
    + 定时任务 +
    +
    .icondingshirenwu +
    +
  • + +
  • + +
    + 动态加载 +
    +
    .icondongtaijiazai +
    +
  • + +
  • + +
    + 接口文档 +
    +
    .iconjiekouwendang +
    +
  • + +
+
+

font-class 引用

+
+ +

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

+

与 Unicode 使用方式相比,具有如下特点:

+
    +
  • 兼容性良好,支持 IE8+,及所有现代浏览器。
  • +
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • +
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • +
  • 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 fontclass 代码:

+
<link rel="stylesheet" href="./iconfont.css">
+
+

第二步:挑选相应图标并获取类名,应用于页面:

+
<span class="iconfont iconxxx"></span>
+
+
+

" + iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    多级菜单
    +
    #iconduojicaidan
    +
  • + +
  • + +
    导航展开
    +
    #icondaohangzhankai
    +
  • + +
  • + +
    导航折叠
    +
    #icondaohangzhedie
    +
  • + +
  • + +
    向上箭头
    +
    #iconxiangshangjiantou
    +
  • + +
  • + +
    向左箭头
    +
    #iconxiangzuojiantou
    +
  • + +
  • + +
    向右箭头
    +
    #iconxiangyoujiantou
    +
  • + +
  • + +
    关闭按钮
    +
    #iconguanbianniu
    +
  • + +
  • + +
    数据上传
    +
    #iconshujushangchuan
    +
  • + +
  • + +
    系统监控
    +
    #iconxitongjiankong
    +
  • + +
  • + +
    邮件管理
    +
    #iconyoujianguanli
    +
  • + +
  • + +
    小屏
    +
    #iconxiaoping
    +
  • + +
  • + +
    人员管理
    +
    #iconrenyuanguanli
    +
  • + +
  • + +
    向下拉
    +
    #iconxiangxiala
    +
  • + +
  • + +
    excel导入导出
    +
    #iconexceldaorudaochu
    +
  • + +
  • + +
    向下箭头
    +
    #iconxiangxiajiantou
    +
  • + +
  • + +
    首页
    +
    #iconshouye
    +
  • + +
  • + +
    系统设置
    +
    #iconxitongshezhi
    +
  • + +
  • + +
    消息
    +
    #iconxiaoxi
    +
  • + +
  • + +
    全屏
    +
    #iconquanping
    +
  • + +
  • + +
    组件
    +
    #iconzujian
    +
  • + +
  • + +
    news
    +
    #iconnews
    +
  • + +
  • + +
    定时任务
    +
    #icondingshirenwu
    +
  • + +
  • + +
    动态加载
    +
    #icondongtaijiazai
    +
  • + +
  • + +
    接口文档
    +
    #iconjiekouwendang
    +
  • + +
+
+

Symbol 引用

+
+ +

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 + 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

+
    +
  • 支持多色图标了,不再受单色限制。
  • +
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • +
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • +
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 symbol 代码:

+
<script src="./iconfont.js"></script>
+
+

第二步:加入通用 CSS 代码(引入一次就行):

+
<style>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
+
+

第三步:挑选相应图标并获取类名,应用于页面:

+
<svg class="icon" aria-hidden="true">
+  <use xlink:href="#icon-xxx"></use>
+</svg>
+
+
+
+ +
+
+ + + diff --git a/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/demo.css b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/demo.css new file mode 100644 index 00000000..a67054a0 --- /dev/null +++ b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/demo.css @@ -0,0 +1,539 @@ +/* Logo 字体 */ +@font-face { + font-family: "iconfont logo"; + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834'); + src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'), + url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg'); +} + +.logo { + font-family: "iconfont logo"; + font-size: 160px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* tabs */ +.nav-tabs { + position: relative; +} + +.nav-tabs .nav-more { + position: absolute; + right: 0; + bottom: 0; + height: 42px; + line-height: 42px; + color: #666; +} + +#tabs { + border-bottom: 1px solid #eee; +} + +#tabs li { + cursor: pointer; + width: 100px; + height: 40px; + line-height: 40px; + text-align: center; + font-size: 16px; + border-bottom: 2px solid transparent; + position: relative; + z-index: 1; + margin-bottom: -1px; + color: #666; +} + + +#tabs .active { + border-bottom-color: #f00; + color: #222; +} + +.tab-container .content { + display: none; +} + +/* 页面布局 */ +.main { + padding: 30px 100px; + width: 960px; + margin: 0 auto; +} + +.main .logo { + color: #333; + text-align: left; + margin-bottom: 30px; + line-height: 1; + height: 110px; + margin-top: -50px; + overflow: hidden; + *zoom: 1; +} + +.main .logo a { + font-size: 160px; + color: #333; +} + +.helps { + margin-top: 40px; +} + +.helps pre { + padding: 20px; + margin: 10px 0; + border: solid 1px #e7e1cd; + background-color: #fffdef; + overflow: auto; +} + +.icon_lists { + width: 100% !important; + overflow: hidden; + *zoom: 1; +} + +.icon_lists li { + width: 100px; + margin-bottom: 10px; + margin-right: 20px; + text-align: center; + list-style: none !important; + cursor: default; +} + +.icon_lists li .code-name { + line-height: 1.2; +} + +.icon_lists .icon { + display: block; + height: 100px; + line-height: 100px; + font-size: 42px; + margin: 10px auto; + color: #333; + -webkit-transition: font-size 0.25s linear, width 0.25s linear; + -moz-transition: font-size 0.25s linear, width 0.25s linear; + transition: font-size 0.25s linear, width 0.25s linear; +} + +.icon_lists .icon:hover { + font-size: 100px; +} + +.icon_lists .svg-icon { + /* 通过设置 font-size 来改变图标大小 */ + width: 1em; + /* 图标和文字相邻时,垂直对齐 */ + vertical-align: -0.15em; + /* 通过设置 color 来改变 SVG 的颜色/fill */ + fill: currentColor; + /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示 + normalize.css 中也包含这行 */ + overflow: hidden; +} + +.icon_lists li .name, +.icon_lists li .code-name { + color: #666; +} + +/* markdown 样式 */ +.markdown { + color: #666; + font-size: 14px; + line-height: 1.8; +} + +.highlight { + line-height: 1.5; +} + +.markdown img { + vertical-align: middle; + max-width: 100%; +} + +.markdown h1 { + color: #404040; + font-weight: 500; + line-height: 40px; + margin-bottom: 24px; +} + +.markdown h2, +.markdown h3, +.markdown h4, +.markdown h5, +.markdown h6 { + color: #404040; + margin: 1.6em 0 0.6em 0; + font-weight: 500; + clear: both; +} + +.markdown h1 { + font-size: 28px; +} + +.markdown h2 { + font-size: 22px; +} + +.markdown h3 { + font-size: 16px; +} + +.markdown h4 { + font-size: 14px; +} + +.markdown h5 { + font-size: 12px; +} + +.markdown h6 { + font-size: 12px; +} + +.markdown hr { + height: 1px; + border: 0; + background: #e9e9e9; + margin: 16px 0; + clear: both; +} + +.markdown p { + margin: 1em 0; +} + +.markdown>p, +.markdown>blockquote, +.markdown>.highlight, +.markdown>ol, +.markdown>ul { + width: 80%; +} + +.markdown ul>li { + list-style: circle; +} + +.markdown>ul li, +.markdown blockquote ul>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown>ul li p, +.markdown>ol li p { + margin: 0.6em 0; +} + +.markdown ol>li { + list-style: decimal; +} + +.markdown>ol li, +.markdown blockquote ol>li { + margin-left: 20px; + padding-left: 4px; +} + +.markdown code { + margin: 0 3px; + padding: 0 5px; + background: #eee; + border-radius: 3px; +} + +.markdown strong, +.markdown b { + font-weight: 600; +} + +.markdown>table { + border-collapse: collapse; + border-spacing: 0px; + empty-cells: show; + border: 1px solid #e9e9e9; + width: 95%; + margin-bottom: 24px; +} + +.markdown>table th { + white-space: nowrap; + color: #333; + font-weight: 600; +} + +.markdown>table th, +.markdown>table td { + border: 1px solid #e9e9e9; + padding: 8px 16px; + text-align: left; +} + +.markdown>table th { + background: #F7F7F7; +} + +.markdown blockquote { + font-size: 90%; + color: #999; + border-left: 4px solid #e9e9e9; + padding-left: 0.8em; + margin: 1em 0; +} + +.markdown blockquote p { + margin: 0; +} + +.markdown .anchor { + opacity: 0; + transition: opacity 0.3s ease; + margin-left: 8px; +} + +.markdown .waiting { + color: #ccc; +} + +.markdown h1:hover .anchor, +.markdown h2:hover .anchor, +.markdown h3:hover .anchor, +.markdown h4:hover .anchor, +.markdown h5:hover .anchor, +.markdown h6:hover .anchor { + opacity: 1; + display: inline-block; +} + +.markdown>br, +.markdown>p>br { + clear: both; +} + + +.hljs { + display: block; + background: white; + padding: 0.5em; + color: #333333; + overflow-x: auto; +} + +.hljs-comment, +.hljs-meta { + color: #969896; +} + +.hljs-string, +.hljs-variable, +.hljs-template-variable, +.hljs-strong, +.hljs-emphasis, +.hljs-quote { + color: #df5000; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-type { + color: #a71d5d; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute { + color: #0086b3; +} + +.hljs-section, +.hljs-name { + color: #63a35c; +} + +.hljs-tag { + color: #333333; +} + +.hljs-title, +.hljs-attr, +.hljs-selector-id, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #795da3; +} + +.hljs-addition { + color: #55a532; + background-color: #eaffea; +} + +.hljs-deletion { + color: #bd2c00; + background-color: #ffecec; +} + +.hljs-link { + text-decoration: underline; +} + +/* 代码高亮 */ +/* PrismJS 1.15.0 +https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre)>code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre)>code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} diff --git a/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/demo_index.html b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/demo_index.html new file mode 100644 index 00000000..2c777b68 --- /dev/null +++ b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/demo_index.html @@ -0,0 +1,722 @@ + + + + + IconFont Demo + + + + + + + + + + + +
+

+ +
+
+
    + +
  • + +
    多级菜单
    +
    &#xe608;
    +
  • + +
  • + +
    导航展开
    +
    &#xe609;
    +
  • + +
  • + +
    导航折叠
    +
    &#xe60a;
    +
  • + +
  • + +
    向上箭头
    +
    &#xe60b;
    +
  • + +
  • + +
    向左箭头
    +
    &#xe60c;
    +
  • + +
  • + +
    向右箭头
    +
    &#xe60d;
    +
  • + +
  • + +
    关闭按钮
    +
    &#xe60e;
    +
  • + +
  • + +
    数据上传
    +
    &#xe60f;
    +
  • + +
  • + +
    系统监控
    +
    &#xe610;
    +
  • + +
  • + +
    邮件管理
    +
    &#xe611;
    +
  • + +
  • + +
    小屏
    +
    &#xe612;
    +
  • + +
  • + +
    人员管理
    +
    &#xe613;
    +
  • + +
  • + +
    向下拉
    +
    &#xe614;
    +
  • + +
  • + +
    excel导入导出
    +
    &#xe615;
    +
  • + +
  • + +
    向下箭头
    +
    &#xe616;
    +
  • + +
  • + +
    首页
    +
    &#xe617;
    +
  • + +
  • + +
    系统设置
    +
    &#xe618;
    +
  • + +
  • + +
    消息
    +
    &#xe619;
    +
  • + +
  • + +
    全屏
    +
    &#xe61a;
    +
  • + +
  • + +
    组件
    +
    &#xe61b;
    +
  • + +
  • + +
    news
    +
    &#xe61e;
    +
  • + +
  • + +
    定时任务
    +
    &#xe622;
    +
  • + +
  • + +
    动态加载
    +
    &#xe623;
    +
  • + +
  • + +
    接口文档
    +
    &#xe624;
    +
  • + +
+
+

Unicode 引用

+
+ +

Unicode 是字体在网页端最原始的应用方式,特点是:

+
    +
  • 兼容性最好,支持 IE6+,及所有现代浏览器。
  • +
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • +
  • 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
  • +
+
+

注意:新版 iconfont 支持多色图标,这些多色图标在 Unicode 模式下将不能使用,如果有需求建议使用symbol 的引用方式

+
+

Unicode 使用步骤如下:

+

第一步:拷贝项目下面生成的 @font-face

+
@font-face {
+  font-family: 'iconfont';
+  src: url('iconfont.eot');
+  src: url('iconfont.eot?#iefix') format('embedded-opentype'),
+      url('iconfont.woff2') format('woff2'),
+      url('iconfont.woff') format('woff'),
+      url('iconfont.ttf') format('truetype'),
+      url('iconfont.svg#iconfont') format('svg');
+}
+
+

第二步:定义使用 iconfont 的样式

+
.iconfont {
+  font-family: "iconfont" !important;
+  font-size: 16px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+

第三步:挑选相应图标并获取字体编码,应用于页面

+
+<span class="iconfont">&#x33;</span>
+
+
+

"iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    + 多级菜单 +
    +
    .iconduojicaidan +
    +
  • + +
  • + +
    + 导航展开 +
    +
    .icondaohangzhankai +
    +
  • + +
  • + +
    + 导航折叠 +
    +
    .icondaohangzhedie +
    +
  • + +
  • + +
    + 向上箭头 +
    +
    .iconxiangshangjiantou +
    +
  • + +
  • + +
    + 向左箭头 +
    +
    .iconxiangzuojiantou +
    +
  • + +
  • + +
    + 向右箭头 +
    +
    .iconxiangyoujiantou +
    +
  • + +
  • + +
    + 关闭按钮 +
    +
    .iconguanbianniu +
    +
  • + +
  • + +
    + 数据上传 +
    +
    .iconshujushangchuan +
    +
  • + +
  • + +
    + 系统监控 +
    +
    .iconxitongjiankong +
    +
  • + +
  • + +
    + 邮件管理 +
    +
    .iconyoujianguanli +
    +
  • + +
  • + +
    + 小屏 +
    +
    .iconxiaoping +
    +
  • + +
  • + +
    + 人员管理 +
    +
    .iconrenyuanguanli +
    +
  • + +
  • + +
    + 向下拉 +
    +
    .iconxiangxiala +
    +
  • + +
  • + +
    + excel导入导出 +
    +
    .iconexceldaorudaochu +
    +
  • + +
  • + +
    + 向下箭头 +
    +
    .iconxiangxiajiantou +
    +
  • + +
  • + +
    + 首页 +
    +
    .iconshouye +
    +
  • + +
  • + +
    + 系统设置 +
    +
    .iconxitongshezhi +
    +
  • + +
  • + +
    + 消息 +
    +
    .iconxiaoxi +
    +
  • + +
  • + +
    + 全屏 +
    +
    .iconquanping +
    +
  • + +
  • + +
    + 组件 +
    +
    .iconzujian +
    +
  • + +
  • + +
    + news +
    +
    .iconnews +
    +
  • + +
  • + +
    + 定时任务 +
    +
    .icondingshirenwu +
    +
  • + +
  • + +
    + 动态加载 +
    +
    .icondongtaijiazai +
    +
  • + +
  • + +
    + 接口文档 +
    +
    .iconjiekouwendang +
    +
  • + +
+
+

font-class 引用

+
+ +

font-class 是 Unicode 使用方式的一种变种,主要是解决 Unicode 书写不直观,语意不明确的问题。

+

与 Unicode 使用方式相比,具有如下特点:

+
    +
  • 兼容性良好,支持 IE8+,及所有现代浏览器。
  • +
  • 相比于 Unicode 语意明确,书写更直观。可以很容易分辨这个 icon 是什么。
  • +
  • 因为使用 class 来定义图标,所以当要替换图标时,只需要修改 class 里面的 Unicode 引用。
  • +
  • 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 fontclass 代码:

+
<link rel="stylesheet" href="./iconfont.css">
+
+

第二步:挑选相应图标并获取类名,应用于页面:

+
<span class="iconfont iconxxx"></span>
+
+
+

" + iconfont" 是你项目下的 font-family。可以通过编辑项目查看,默认是 "iconfont"。

+
+
+
+
+
    + +
  • + +
    多级菜单
    +
    #iconduojicaidan
    +
  • + +
  • + +
    导航展开
    +
    #icondaohangzhankai
    +
  • + +
  • + +
    导航折叠
    +
    #icondaohangzhedie
    +
  • + +
  • + +
    向上箭头
    +
    #iconxiangshangjiantou
    +
  • + +
  • + +
    向左箭头
    +
    #iconxiangzuojiantou
    +
  • + +
  • + +
    向右箭头
    +
    #iconxiangyoujiantou
    +
  • + +
  • + +
    关闭按钮
    +
    #iconguanbianniu
    +
  • + +
  • + +
    数据上传
    +
    #iconshujushangchuan
    +
  • + +
  • + +
    系统监控
    +
    #iconxitongjiankong
    +
  • + +
  • + +
    邮件管理
    +
    #iconyoujianguanli
    +
  • + +
  • + +
    小屏
    +
    #iconxiaoping
    +
  • + +
  • + +
    人员管理
    +
    #iconrenyuanguanli
    +
  • + +
  • + +
    向下拉
    +
    #iconxiangxiala
    +
  • + +
  • + +
    excel导入导出
    +
    #iconexceldaorudaochu
    +
  • + +
  • + +
    向下箭头
    +
    #iconxiangxiajiantou
    +
  • + +
  • + +
    首页
    +
    #iconshouye
    +
  • + +
  • + +
    系统设置
    +
    #iconxitongshezhi
    +
  • + +
  • + +
    消息
    +
    #iconxiaoxi
    +
  • + +
  • + +
    全屏
    +
    #iconquanping
    +
  • + +
  • + +
    组件
    +
    #iconzujian
    +
  • + +
  • + +
    news
    +
    #iconnews
    +
  • + +
  • + +
    定时任务
    +
    #icondingshirenwu
    +
  • + +
  • + +
    动态加载
    +
    #icondongtaijiazai
    +
  • + +
  • + +
    接口文档
    +
    #iconjiekouwendang
    +
  • + +
+
+

Symbol 引用

+
+ +

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 + 这种用法其实是做了一个 SVG 的集合,与另外两种相比具有如下特点:

+
    +
  • 支持多色图标了,不再受单色限制。
  • +
  • 通过一些技巧,支持像字体那样,通过 font-size, color 来调整样式。
  • +
  • 兼容性较差,支持 IE9+,及现代浏览器。
  • +
  • 浏览器渲染 SVG 的性能一般,还不如 png。
  • +
+

使用步骤如下:

+

第一步:引入项目下面生成的 symbol 代码:

+
<script src="./iconfont.js"></script>
+
+

第二步:加入通用 CSS 代码(引入一次就行):

+
<style>
+.icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+</style>
+
+

第三步:挑选相应图标并获取类名,应用于页面:

+
<svg class="icon" aria-hidden="true">
+  <use xlink:href="#icon-xxx"></use>
+</svg>
+
+
+
+ +
+
+ + + diff --git a/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.css b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.css new file mode 100644 index 00000000..8c269496 --- /dev/null +++ b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.css @@ -0,0 +1,113 @@ +@font-face {font-family: "iconfont"; + src: url('iconfont.eot?t=1567826173562'); /* IE9 */ + src: url('iconfont.eot?t=1567826173562#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), + url('iconfont.woff?t=1567826173562') format('woff'), + url('iconfont.ttf?t=1567826173562') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ + url('iconfont.svg?t=1567826173562#iconfont') format('svg'); /* iOS 4.1- */ +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.iconduojicaidan:before { + content: "\e608"; +} + +.icondaohangzhankai:before { + content: "\e609"; +} + +.icondaohangzhedie:before { + content: "\e60a"; +} + +.iconxiangshangjiantou:before { + content: "\e60b"; +} + +.iconxiangzuojiantou:before { + content: "\e60c"; +} + +.iconxiangyoujiantou:before { + content: "\e60d"; +} + +.iconguanbianniu:before { + content: "\e60e"; +} + +.iconshujushangchuan:before { + content: "\e60f"; +} + +.iconxitongjiankong:before { + content: "\e610"; +} + +.iconyoujianguanli:before { + content: "\e611"; +} + +.iconxiaoping:before { + content: "\e612"; +} + +.iconrenyuanguanli:before { + content: "\e613"; +} + +.iconxiangxiala:before { + content: "\e614"; +} + +.iconexceldaorudaochu:before { + content: "\e615"; +} + +.iconxiangxiajiantou:before { + content: "\e616"; +} + +.iconshouye:before { + content: "\e617"; +} + +.iconxitongshezhi:before { + content: "\e618"; +} + +.iconxiaoxi:before { + content: "\e619"; +} + +.iconquanping:before { + content: "\e61a"; +} + +.iconzujian:before { + content: "\e61b"; +} + +.iconnews:before { + content: "\e61e"; +} + +.icondingshirenwu:before { + content: "\e622"; +} + +.icondongtaijiazai:before { + content: "\e623"; +} + +.iconjiekouwendang:before { + content: "\e624"; +} + diff --git a/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.eot b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..cf0b3fbdf621e7a70585e35f454f7db627ef94f6 GIT binary patch literal 8812 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 literal 0 HcmV?d00001 diff --git a/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.js b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.js new file mode 100644 index 00000000..6a3315a1 --- /dev/null +++ b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.js @@ -0,0 +1 @@ +!function(e){var c,t='',h=(c=document.getElementsByTagName("script"))[c.length-1].getAttribute("data-injectcss");if(h&&!e.__iconfont__svg__cssinject__){e.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}!function(c){if(document.addEventListener)if(~["complete","loaded","interactive"].indexOf(document.readyState))setTimeout(c,0);else{var h=function(){document.removeEventListener("DOMContentLoaded",h,!1),c()};document.addEventListener("DOMContentLoaded",h,!1)}else document.attachEvent&&(a=c,o=e.document,l=!1,(i=function(){try{o.documentElement.doScroll("left")}catch(c){return void setTimeout(i,50)}t()})(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,t())});function t(){l||(l=!0,a())}var a,o,l,i}(function(){var c,h;(c=document.createElement("div")).innerHTML=t,t=null,(h=c.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",function(c,h){h.firstChild?function(c,h){h.parentNode.insertBefore(c,h)}(c,h.firstChild):h.appendChild(c)}(h,document.body))})}(window); \ No newline at end of file diff --git a/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.svg b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.svg new file mode 100644 index 00000000..a349f5e2 --- /dev/null +++ b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.svg @@ -0,0 +1,98 @@ + + + + + +Created by iconfont + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.ttf b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..69587d9ec84c49f0f13af71459b52433868ec15d GIT binary patch literal 8644 zcmd^EdvKgrb-(9+&;6eJ?Nide_1Kjxd1Y&*U0br{muv+{Y)E2*!H$t-NtRFjJs3Fw>^Ap%9+kPKQUJjfa^|cHQ6ozLo8G zGVLFo{>ARz*SYted+#~t{_eSV88OC8c7aK3&E!41xBgZ0$zL)?>pz=`(4G-Rt zK=~ZXd!~;~9e-i!%2yfVsOMjuJNm$^a?pO9F=Y*7Z67;4Gj%BOrmz1NZGVJNJq&{O zqV!SZzl6|z_}J2!L&$*N^N0=|U7ViU{Oifb7?WQ?dHC4Wnd3CTny7C>IlnMVn?GQfyL93D1-4H{b8rFC&)kgKeF~^OBX^xX;BL6a z%%JTHk8Ej(WA?XX~9J=YNEB%J_-m^wI!AT(RIgCMN6jvXfgbiwLw z5TF%S4+lZ)k-8TIq49bo2+$d;M}q+Ev3e{B&?BqIg8+@PIuJ$#=$6%!L4cN7U93SM zf#BU91ZbYsJAwckfHegH*1+o7AiyqIy)y`~5LWLB0&IoVyMrLC#{V2)KcoBTee@Ll zgb(m9OZQ37$QzW8Do?4i>IXDk->hE>g+p~?kC`yPV(s*IFO$B&zl>E!S(>e4Rkn?> zXe=>Q9WHjNnwO;@7nfFY6|xkU3S|=6p+rng##GHOR#3b<)0e@I=+&t- zO{sX}Z{n#`oR7v+Yi?#!Al)qShvK4pCf2-$%&JT#-nt%U}1Y>;hYZ@`MiNlYpkcSuaJghlx2NQ+Ll)Ct<{^|j$@ zjuJ7K)Z)lajLfh51I8PK6l+Qcxs{scUj)_7Vvur6%(hh^G1-H0_neDgoHwz)xE-`> zxItq}+AdSh63wI)3wmdJxCV9IHF!Po|0xS0z~Dw_TTi z_ePe6{@0FJEAaRF%hHpQ4Ag96J?tQSmT~N{48_#WVyRXIT)?(~BAX}au)OYIya zNTr0Wi64wrAWx~Y%trt))lD2GTph~t97k0m9&>n?L$O2!5645ZREU0XcJ_nO*X<|%&bL{vYvsqv?U6`VwM#YcsP^of9P824uHKD~(Ow?Q ziw677a@zmnkY$Db$*?TrXW*mH`5b$6F@l~5>vQy$=?6J~a5}QQ>%Q|mjN#h{H*}^) z5(AFjJ^GfolN#Du?AFa%Zz|onVXz&O4D<8%?OJZh=sVKqv1i*@H=ARJp}j;>tSu(i z4;4Zd#o?M*b}bNyzf`FUbO}xRg`7HzgCgli22!fjs+B~J&}U3U0JW%}^=5coZFJ{vw34xOH|t#s3AE7lH3uW^36HWLSW#aBTUI=fN_(q$0KhWLE%{ zAmPf;CQ3pIIK@ijm1(lAckKDLqF&F;bZ6l{W8)jy*8u?;qng6ZKb^3{ox78@oBB$9wZ z*brktBSG+Yje>1dDnk9iDF%zc)*9LGW>j=zA&y*w6)Wt&VU^ zj5ElazYm7bMv|hzWxvO%Rt;K<30!uw!Zi}QyDrYFwXBy7!}7n$e$0LY-9dFR*srkv zSeE0&u8s^Bg`OaX8g}|7p~f;v*a65uoen8UO^wGA$wX2W-4aPHfRHYr44MvdfiYF= zf)U`3*k0(^)#-46O&Rd-K)wJIY>iG8h$J{=v3bx=02Jl|XJBZYi?IZ~DrPW9MPCDA zK2@BY_?5aaM=?;bqzxr2XdQ>H)UM7Fb}QNgz_5qK@B*;>olReQ%URyv>$*pOkB2j* zIJIe>r#1gAmXZGSorTQSgk9<<>D=D!`-%2%_hXm@@zvd2A*p*cA+n0GWVbD6i32&i z2_Gq!bR3e3nwg6xd*Wd&Y$T#qRCXfrsG-TkGf~-aCI90ZQapvOvS!p|O-9qCWwfcX zgNAYq5yt^8g~DhoD?DuQM2bk!L+?{$vZGwmWGfnEiEFYQDXrC%o{mtcl}c;*x&4*B zg^)UMWjS8Tx{edJ((&`3bGR1?74}y4pKHFGi=}Zto{B0VyJuJldv-{z6g?wm$BB}5 zSk)bnxv7UWM^4&ZQB)}*kEpGt*sg9X8p&C`%~Dh?mI+&7+jG;B6^5g!sJfNZbDR`A zLKM~%op?@bvs6XHTEeF5M68r-xmc&7=vJHdFiBBIvLdoeJZh5@Rh)j>(BIypa2oAP z7Zo1d3#BXkl(-SVP=eDI8kWxYdFkfovb%E4$1`3ZKSh1n=AUIVbYHd?&I;}u*I$$# zmwJF#DRvjz&yKP4>_O~(52qMRy#}-r4jXlqw60pIlB`uU@&cUN2q$|iI6xBu*+x9E zFB}pFs=$6xFC1K;4nQCSvtFSJPzcIp60MT0vIfKSd%e*$=}F5Wa?R#lNDu5wcaBd? z_%R;?wXxT7TvIn)SU_3CjpuPd3W96$$4$5St&c;3u8G*SUOUU*+}tCW&|jKxw;mrE zIr1I^+S~91lPMAPm|_YBf5ZeYqsOO9huw)GfUh{C;djKL z7p)86R6;?ELzW}ZUa3oXpfxyP!CtS3bEqQR7a&50gsb9-$ahca6~mS3Z6O*@WMQhi zs_RDAY^1wmDas_qDMa^J;ZnN!*(6DFBDRHU{g*PC(R|0d``6RvctVya+5BXRH$zJE z)0T`r%^ybdbgB4yPMd}4{&~9(vLSt z()uCb9hp+5lH(zZ%QClho~vXfTb5N?wMCK~D^krBY7t4%Bz@h@=8|p!c|&xwhwcrH zqP-cdW((^gq}$QXWT7W-0kv#v>$-$xgd{H;>nJJ;DVp4qj^rYw8D?zVR@;sg3=@q_ zM>H;M>WG=Qw3hj+T3hs6zHMk|8~5WXpSt6YDelMrNNv4(JS1l~40kDHn%$ebLN>{r z>&G)jT%n#6IUTsQWm2*sNo~Da+>o*xM!ICOOhs<%%6A%;-#XnM?rkTsJ2IIRnIn-- z51)vVDo3m7Xt5CIQg^ziC(;{9_i!m*C`Q{yqUE$g(RkSN!d^sndXio>6)EN867Na( zbVp0kbhpGs(+)IEDdNore!x8JtpHD;57t%|x6+ufIB|gb4nCmKS7uF|v(;!|j1~Sy zT0H^xZubdJRyvYQMEJYBM8eD1oGCirjo&k6$r1y#*HGIu0&$)H3&ktoC| zbSZTI+#^}FF|&3H(U!HaeY^o-E}w@_B3|RVvE$bRrKiN*g|Nwiw0IQR$cF)_Vm<&~ z-!bvT>j&I3Px4QF;gO?}@CSyguwWmVfxtW_;5()k&|55|Qw2#l9l(A{eg<%taOL+4 z)Z=ACYy7ch7#csK8E^fJz&J-#T7b@Vx3r{hzN*fW){8KHxxU5jN&ESC5mES0uhG9{VZO< zy2PGE3xD|)ajhHY8?igbIovJmPJxB!5`%k`3#96^5g;mjqgtg}g9|23L!3>JlFNN{ zqZbY?bOD@K#o1Tt!ic`}#qY`VO18qW-oI^E3^i&FZYJ71Xon-Z<}{uGGP(|jd*fvK z`ZBuZS*fJ`q=T!Prplc2zD#8YDRM~uhU0PFkfITkY5TC}K~|o_kJ}O539Ey`J!
w^-dZn^ z3s*qrn|3l~Sz1U|&2;ZDEER)=9US)di$HsD+%`Nk0ar`bu88Z_uQW%O5*)4;6)FYz zcoJ{tih*;|#w7KS9EnsW{5$tQNJpjBu-!GR#wNx81dutfx&$F6gH5I3AtNF18fFN! z&~OPpf$$K7GaLo%RvhYqj0K27BTz;TekR?&hiF~zsv11ZJ;!K5QLM=2*uHc7B99nh zQ*F*=2Qzj@+DWg^jm7>svc7p`J*N5I{Rch>A9CQOt5YA!+I{F;>(eAD`=P0;r}Y>d zxZ% z@#F{ZNjwh{9vp_pIUX9s3xhx#^h5VDX*V`A*j9WC5B4-2wmh#r3~8k-X|JM z`2nJVJb%bf8~19asqu$IysFV<*HC+Od!GeLJ>``1K*% zj@tIxF{Gg}JVo%c6t+(ZyEx?!b|c@|O9KUdwjhQrG%ghea6L8j#wFb#r2H(>#~d?c zxULa0o#tSE?9O|G0q?zYEKf_gWwgfK|JSy$->`!SgGa@~n2`TV(xZ}h@ zi#>%)?d?+TRE3nqM)qA*A!Xm&gp`F=q}$2@FNGF_qa?Hdixq$i`3fK?mT(si^eZ}R zT`TX?(yqqA0&YU93;a<(ZEW$y{HTca#@%AA{IepyC4Y5yeihNGe2^@|BQc^a=$9b1^d^wQ#ZA9&1cW+QAazkMcs?%H8+Z!6aDprT0nCyKBzhYtpnoZkLLUE zTndXjsGFuv|K3dISMfFs@`Z?F{nYM!b_o{vs9@pqnFd>*x3l{-XfQau>bw|u^~j57 zZvVv>v5r!Z=a68gm6t&8Zsld<@n5E3g8zR^yfFlM74%K5yutc`kpbPrnSTP_2+6Q= z{0s7)R-W+B&F5Nqj(>Nqw(=6_&$aS0@;_+h75qc<%T``xVUk*TgYBVcD{rzQ%^TZJ z%uFrK9LgVjAU{97xG=l8uw<-c?w*-jK00+`rMQyrnK^NCesLkcw!CJAG&!>{b7FShj*kuwih%^ZJiT}fe{XHWvS;Ar zEFnI`@^E$@Ks?W;*&XE2ka$miK{zwQY5Orv!fk4vK0 zaW;y-f(CD_Xr+DGU+FPnC-8OrkN7X~wLa~5DUnDf1?RIyI=p^^OtJ{C1h@r-2@jSO zr5MF2foH}xYNrln9$H>JGCw^ve`spKIW)C+cxqwpETa3T=ItBBnM3n4-kEt+ofP#) zkXu?@c74iO(f^k61B=V8vN^XrwQvx13-inF$-~P>mi^w-he3AE%r7klobE?zw|a>l zN9T1gUOYYz@`;&+2S5tQhCd#nqf_CTGt)CiF~1Ybh`=$J3+h^9t0xaHE-)}N`oFmw8(bqIu$hvzZi>1F#6rnEFQ4_;>>h9mPc_b)D= Mo>_p1<{6R9021Zi4kvHG_ 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 literal 0 HcmV?d00001 diff --git a/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.woff2 b/front/src/assets/icons/download (4)/font_1299963_2zqwx2axi0j/iconfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..89c0d09e7ac28fa8a86980e9905e1c02ee7ebfc4 GIT binary patch literal 4584 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 SWT0jUIY|qZd}3}i0ssK8jJret literal 0 HcmV?d00001 diff --git a/front/src/assets/icons/iconfont.css b/front/src/assets/icons/iconfont.css new file mode 100644 index 00000000..8c269496 --- /dev/null +++ b/front/src/assets/icons/iconfont.css @@ -0,0 +1,113 @@ +@font-face {font-family: "iconfont"; + src: url('iconfont.eot?t=1567826173562'); /* IE9 */ + src: url('iconfont.eot?t=1567826173562#iefix') format('embedded-opentype'), /* IE6-IE8 */ + url('data:application/x-font-woff2;charset=utf-8;base64,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') format('woff2'), + url('iconfont.woff?t=1567826173562') format('woff'), + url('iconfont.ttf?t=1567826173562') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+ */ + url('iconfont.svg?t=1567826173562#iconfont') format('svg'); /* iOS 4.1- */ +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.iconduojicaidan:before { + content: "\e608"; +} + +.icondaohangzhankai:before { + content: "\e609"; +} + +.icondaohangzhedie:before { + content: "\e60a"; +} + +.iconxiangshangjiantou:before { + content: "\e60b"; +} + +.iconxiangzuojiantou:before { + content: "\e60c"; +} + +.iconxiangyoujiantou:before { + content: "\e60d"; +} + +.iconguanbianniu:before { + content: "\e60e"; +} + +.iconshujushangchuan:before { + content: "\e60f"; +} + +.iconxitongjiankong:before { + content: "\e610"; +} + +.iconyoujianguanli:before { + content: "\e611"; +} + +.iconxiaoping:before { + content: "\e612"; +} + +.iconrenyuanguanli:before { + content: "\e613"; +} + +.iconxiangxiala:before { + content: "\e614"; +} + +.iconexceldaorudaochu:before { + content: "\e615"; +} + +.iconxiangxiajiantou:before { + content: "\e616"; +} + +.iconshouye:before { + content: "\e617"; +} + +.iconxitongshezhi:before { + content: "\e618"; +} + +.iconxiaoxi:before { + content: "\e619"; +} + +.iconquanping:before { + content: "\e61a"; +} + +.iconzujian:before { + content: "\e61b"; +} + +.iconnews:before { + content: "\e61e"; +} + +.icondingshirenwu:before { + content: "\e622"; +} + +.icondongtaijiazai:before { + content: "\e623"; +} + +.iconjiekouwendang:before { + content: "\e624"; +} + diff --git a/front/src/assets/icons/iconfont.eot b/front/src/assets/icons/iconfont.eot new file mode 100644 index 0000000000000000000000000000000000000000..cf0b3fbdf621e7a70585e35f454f7db627ef94f6 GIT binary patch literal 8812 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 literal 0 HcmV?d00001 diff --git a/front/src/assets/icons/iconfont.js b/front/src/assets/icons/iconfont.js new file mode 100644 index 00000000..6a3315a1 --- /dev/null +++ b/front/src/assets/icons/iconfont.js @@ -0,0 +1 @@ +!function(e){var c,t='',h=(c=document.getElementsByTagName("script"))[c.length-1].getAttribute("data-injectcss");if(h&&!e.__iconfont__svg__cssinject__){e.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}!function(c){if(document.addEventListener)if(~["complete","loaded","interactive"].indexOf(document.readyState))setTimeout(c,0);else{var h=function(){document.removeEventListener("DOMContentLoaded",h,!1),c()};document.addEventListener("DOMContentLoaded",h,!1)}else document.attachEvent&&(a=c,o=e.document,l=!1,(i=function(){try{o.documentElement.doScroll("left")}catch(c){return void setTimeout(i,50)}t()})(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,t())});function t(){l||(l=!0,a())}var a,o,l,i}(function(){var c,h;(c=document.createElement("div")).innerHTML=t,t=null,(h=c.getElementsByTagName("svg")[0])&&(h.setAttribute("aria-hidden","true"),h.style.position="absolute",h.style.width=0,h.style.height=0,h.style.overflow="hidden",function(c,h){h.firstChild?function(c,h){h.parentNode.insertBefore(c,h)}(c,h.firstChild):h.appendChild(c)}(h,document.body))})}(window); \ No newline at end of file diff --git a/front/src/assets/icons/iconfont.svg b/front/src/assets/icons/iconfont.svg new file mode 100644 index 00000000..a349f5e2 --- /dev/null +++ b/front/src/assets/icons/iconfont.svg @@ -0,0 +1,98 @@ + + + + + +Created by iconfont + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/front/src/assets/icons/iconfont.ttf b/front/src/assets/icons/iconfont.ttf new file mode 100644 index 0000000000000000000000000000000000000000..69587d9ec84c49f0f13af71459b52433868ec15d GIT binary patch literal 8644 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
w^-dZn^ z3s*qrn|3l~Sz1U|&2;ZDEER)=9US)di$HsD+%`Nk0ar`bu88Z_uQW%O5*)4;6)FYz zcoJ{tih*;|#w7KS9EnsW{5$tQNJpjBu-!GR#wNx81dutfx&$F6gH5I3AtNF18fFN! z&~OPpf$$K7GaLo%RvhYqj0K27BTz;TekR?&hiF~zsv11ZJ;!K5QLM=2*uHc7B99nh zQ*F*=2Qzj@+DWg^jm7>svc7p`J*N5I{Rch>A9CQOt5YA!+I{F;>(eAD`=P0;r}Y>d zxZ% z@#F{ZNjwh{9vp_pIUX9s3xhx#^h5VDX*V`A*j9WC5B4-2wmh#r3~8k-X|JM z`2nJVJb%bf8~19asqu$IysFV<*HC+Od!GeLJ>``1K*% zj@tIxF{Gg}JVo%c6t+(ZyEx?!b|c@|O9KUdwjhQrG%ghea6L8j#wFb#r2H(>#~d?c zxULa0o#tSE?9O|G0q?zYEKf_gWwgfK|JSy$->`!SgGa@~n2`TV(xZ}h@ zi#>%)?d?+TRE3nqM)qA*A!Xm&gp`F=q}$2@FNGF_qa?Hdixq$i`3fK?mT(si^eZ}R zT`TX?(yqqA0&YU93;a<(ZEW$y{HTca#@%AA{IepyC4Y5yeihNGe2^@|BQc^a=$9b1^d^wQ#ZA9&1cW+QAazkMcs?%H8+Z!6aDprT0nCyKBzhYtpnoZkLLUE zTndXjsGFuv|K3dISMfFs@`Z?F{nYM!b_o{vs9@pqnFd>*x3l{-XfQau>bw|u^~j57 zZvVv>v5r!Z=a68gm6t&8Zsld<@n5E3g8zR^yfFlM74%K5yutc`kpbPrnSTP_2+6Q= z{0s7)R-W+B&F5Nqj(>Nqw(=6_&$aS0@;_+h75qc<%T``xVUk*TgYBVcD{rzQ%^TZJ z%uFrK9LgVjAU{97xG=l8uw<-c?w*-jK00+`rMQyrnK^NCesLkcw!CJAG&!>{b7FShj*kuwih%^ZJiT}fe{XHWvS;Ar zEFnI`@^E$@Ks?W;*&XE2ka$miK{zwQY5Orv!fk4vK0 zaW;y-f(CD_Xr+DGU+FPnC-8OrkN7X~wLa~5DUnDf1?RIyI=p^^OtJ{C1h@r-2@jSO zr5MF2foH}xYNrln9$H>JGCw^ve`spKIW)C+cxqwpETa3T=ItBBnM3n4-kEt+ofP#) zkXu?@c74iO(f^k61B=V8vN^XrwQvx13-inF$-~P>mi^w-he3AE%r7klobE?zw|a>l zN9T1gUOYYz@`;&+2S5tQhCd#nqf_CTGt)CiF~1Ybh`=$J3+h^9t0xaHE-)}N`oFmw8(bqIu$hvzZi>1F#6rnEFQ4_;>>h9mPc_b)D= Mo>_p1<{6R9021Zi4kvHG_ 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 literal 0 HcmV?d00001 diff --git a/front/src/assets/icons/iconfont.woff2 b/front/src/assets/icons/iconfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..89c0d09e7ac28fa8a86980e9905e1c02ee7ebfc4 GIT binary patch literal 4584 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 SWT0jUIY|qZd}3}i0ssK8jJret literal 0 HcmV?d00001 diff --git a/front/src/assets/images/default_icon.png b/front/src/assets/images/default_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1e0872fd462bc710a45851953108675002830fb2 GIT binary patch literal 2364 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 \ No newline at end of file diff --git a/front/src/assets/images/error-page/error-404.svg b/front/src/assets/images/error-page/error-404.svg new file mode 100644 index 00000000..77d97f71 --- /dev/null +++ b/front/src/assets/images/error-page/error-404.svg @@ -0,0 +1 @@ +drone_delivery \ No newline at end of file diff --git a/front/src/assets/images/error-page/error-500.svg b/front/src/assets/images/error-page/error-500.svg new file mode 100644 index 00000000..ef72fd32 --- /dev/null +++ b/front/src/assets/images/error-page/error-500.svg @@ -0,0 +1 @@ +co-working \ No newline at end of file diff --git a/front/src/assets/images/icon-qr-qq-wechat.png b/front/src/assets/images/icon-qr-qq-wechat.png new file mode 100644 index 0000000000000000000000000000000000000000..c5f6b18591f0025bc37fc2dae5c7bc85177c42ad GIT binary patch literal 43541 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 W(3(E^8d>n@;Zjjhm#>!n6!bq|VVLs( literal 0 HcmV?d00001 diff --git a/front/src/assets/images/icon-social-bilibili.svg b/front/src/assets/images/icon-social-bilibili.svg new file mode 100644 index 00000000..d655a329 --- /dev/null +++ b/front/src/assets/images/icon-social-bilibili.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/assets/images/icon-social-juejin.svg b/front/src/assets/images/icon-social-juejin.svg new file mode 100644 index 00000000..c0ad2aeb --- /dev/null +++ b/front/src/assets/images/icon-social-juejin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/assets/images/icon-social-twitter.svg b/front/src/assets/images/icon-social-twitter.svg new file mode 100644 index 00000000..cef3ec09 --- /dev/null +++ b/front/src/assets/images/icon-social-twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/assets/images/icon-social-zhihu.svg b/front/src/assets/images/icon-social-zhihu.svg new file mode 100644 index 00000000..3a82ca82 --- /dev/null +++ b/front/src/assets/images/icon-social-zhihu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/front/src/assets/images/login-alipay.png b/front/src/assets/images/login-alipay.png new file mode 100644 index 0000000000000000000000000000000000000000..7d9f0306411646da46ca036af00fda790a3f2e04 GIT binary patch literal 1881 zcmah~3sBQ`81D&+FRmSShx37<3Zl}cZ)l`2Xp2;=houvIa2k>TU1<`NlokhbDB}hq zj(K+6yrF>NR1gN644ncxb?SUf#0NS>CqqR=IZ^Pr6b0R#+;U0&kNke$_x-=$_g!*h z=FjmQJz+G5!|~KdX^reS-t~+e!M@w<>RxvEh|$F}u|yJMhbfE`juMF&ptr)wm=S}~ z^cBaj5Dv$!(`<@o;tlg4gs_TW7e?f;k}R9U2?=wMFk-o?EGz5hK3XxKXNaPA2NF|aeWpb4&5Ri%`!Js%8l*ohg-3(!?eVbigDi5s6(#>Ib68Ada+Asr}AT1jJG? zD~2;Piiq11*4=_HZix&f}1Kx{502Ds>3u5w7O ztEOFAL0XJ5r(tL$MOcA;Js|VYvB-wB_lAoO9gBQOF31K0x+?UYiXGTu+rTv)>_2uf z*ufaiwk^f>=cG2zf7rHn*K5N~j@F8Wvn`in_@Qa2dg?K!Wyzi;QND-IOySk=yS*XX zt)+{l=&kcR&^u0FP0H=Fewvp$Ao?L!94yam`YmnCH-2IK+1#@%!~TrWhFK@N!%J7!*4Fmmb+uVl3deZGiT2}ZJ4~&k2cX>gowl&QcX7DeCrsF5qv^6u<$di1!;Y>v-{rP!=~DORz|&)IA54+wLH@j)fIM8e z2`k?EqNr~1^oe@s2Cp0LUL)6v-MF_R4oO~leEqx3x9Zbu{kNwK+nZY!?a9t=aVHhS zGJ@;;|496?cMY9jzn3=Cm|rGTx>Xm=9vSPbu5W5g$bCB3JMR*2M*XkP6Y)$cW9}#J=&dl_z5gbhbrsjj6wK^wT++n&d zXjjYjFEH+H29ics2NeQ=fq^kq!%pl;{E#U^coq$tz5YFhR39%!XAF&W%S{o03^>a=@^35$V0jIjJB$iA&=sa1J65=C60ygUO74+WSU3O@D z!Ll(scb53A>1*|NcPet=YTLfQ$|F{vx;=ycpoXpwEdJn9kZ!?vB+e$5KC4J5YmDPN z)?fX2n=y+%?bdY#x!zPV?7Q;eaGr(9DfEy#ALbwMUA27l50c3~%7$2OA@=2>nR>5U z_sZq@v7YstFP24(*eEZ&RubpY)L4?XE`jVUtOe#ZZ`;-}rK7bca7|jZI`wSUQ2}yw zTyHt|^W@S$r_J4FypKfsmy@-|N*wwA?(+*Jr;{BX7KFR*^5N2GpQri;q3LB2$GU(w mv8MFgjFT(C$93)NIc^+tZ^1ph@s-5&v(xM5Yj;O1U;QsNJ;NIS literal 0 HcmV?d00001 diff --git a/front/src/assets/images/login-bg.jpg b/front/src/assets/images/login-bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..04c27b4f2c492241b7865a392088329c277a59ee GIT binary patch literal 547587 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 p7WA>N`#QUh?Mu08+iN+ZX!f zn{V}J=~@%6F080A)hgD=`gAKi0uMuRZdTme+^%95Z;G6D=yk2O_HAwFw{5SyQ%uxR^Y8$Z`ap#y<1e*^tW19+#6x~cHN_` z>YC-){{XfA*5gu*y<3WYjUiA29E)r74L9!7I&j18I~(`uKZd#`cVx4sTkPU**XR#W z`n}N}s{Qo+!|I!3LF#sh%S#i|j<;y`?br7<$I&RU*EY6#Huuu6Z#I75uKSvn`b%8X zUg_b^W14C(w+_3ze&ua6!_h_@=ky(=)9>$WU#Q&Nt#4POd2@&3^z`(t<<|cIx^MD9 zVX^vevi2d`T_NbbYg%=#_MXhSywbXHN!4yFt@R35x;?F>Z9hxUG&+KtDOwg#pcv0k zG?X)PwY|BM<(+%qr(WGorsnTe*DCD9?QQla5#JMz%`$$7{l08QeXn&VRM;P58@od5 ze#zE$j-7qhZmVt~v)tVb-1eV=S|eQ`F+)ss^)De&Z&2H>+3%dzWM&~c8^+mkGFo-e%>|F(4L8HTAPlq zSlz#M%X*Y`**@hf5yoe;xbJ-@-QRE>X20oQ+RHkfzAm<2xwvJa_@b?rgX;J zSG~Eq7WFT5dUfgP{;0UUtWCvAb*?g(qp%}~s;=BS?e0}ZA^s=bIBqrLq1)*?jlPp< zersx}Qd(&)&NIit6tySy@6nI89hvqc(yCRqhL5#32UhmxyS45*k<>j(%I1v?V#{Ck z^?hqi)2rNEvb~*--qP)TDs>vn^r(PcmaRZ4eD?2B_S1&dUk^-4^PX+yw%@nMvR@4} zs}uIWt`YlL()|}%y8X7~rFp68nq~H%XRc7vFPW%P)F|C*T73`Q)z$w1admh5X4_D_ z%TCoPmVybB17nA8s#e2k_x*_F={c|bTDYuCamwTCJzJ-{t3uy5JG!ocs%g5tu7$2q z(yyy&`jxJr?K@JhWlHt-cTTgfa?4AqR`nTE({sg8NW+KJbk(}qtG5(eU2aRRiSXg{ z@jdT*@7=Z2y%6iWmh93Mo%?+&OtYrz&1Z0GISc9O+8&(7y0z`qSt>NPlYGx8g#8~u z&~<)k)c#MQqrT$HdRDdLYj#z5<>4d5^Di*ze7mRo*HdVnE3K^iD!b2ycb4wlT|wLy zI=13tZD`olbxpan?e5!grfs8HqyGN-uv&Vy>A1I_tU;x0&{;$%FF&XGUzGH|QPbMH z4Q};TU&P&rc3;t|;Z>vJ`1T)@`M;WP`M*%FcgwV&ySFYY#XEM{@X{WKwRCG{3U95s zF2kxhYg^a{tD5IjV_8z@<_9%eU=|9Po+}<7%wA&^{HDr!kfJC=Z({ey!?$f*N%s`0j2pD6pXvES!ZZ{!nDcv#aks?o?bWD! z4dX1K2`E5m;072BP)7^Y<|LBwFx;q;9C;HtL>dx=1jI-nl!>3ZD%T=&DAjuAIUUC+ za2b^*jcR6bIAa{VB(pA27nc-tih1r_+l%*wWszueDQ1&DazFQ>E(uCbB{L$S>F#f< zw@PBGk8g+5z}^&O(xAB&fVkClL;|H}zGcQ{JRQ!l?pfKlCvuw=qTq8c ztSN_4rsZj9Ym0o+Y_fuU#7=5shW1v=nKfs@NyXjX(zCa(bzZY5QMaJ`ij|)1qJ_OC zlTxKel*-1m5^+HpYHH>_pGXTWCG=c)b{`sTPORD3(dz#IS@rEw-)D5UZ0~D!TI&~- zbsLI0g|+<+FGahgG-&szF%P8;FZZ`QlW3$kkewl;dez5g3X?1^lZ%(W1-7fymOxHA> z6J_aomBlLdms;EO8*965!>-fQ^Rk_#sTT~hrRIHCdR}KVpdXuceM0kIrrk{|@cMgU zb2zi@ZA8pW*9}DQgZekf`X4a)W65je-EHgfue$dvm*G}vE=_Ril=eq?-2U8pdsju< zyNh<;QKw3d@~LH}={EIf(n`C3Zt71eyA7mulNPNj8=2 zlZC-A!n}01f%%Wk-Fg8z7A(b-)XqX0Se9GzZB=IrW zhTG!V@Xpm$jtlAfPRpg}#JP@loXBNyBncnoB^5j4p0!G+9J^|I1)iE18jTo$g)*S! zC0Rka(F`TtcAI-pa>`N&xTMAih*Bh^qlprobUE4hIjxt5=R6GP}*=UX0sWsY;!$OLAkq-gdaXsW1!Z@#)NaU$fz>$X@W4bvLPeYA& zoTVl@M=H%!B&0$l%C~ixxx_`5$y~wsJ(XeT~3>?nI}*2+6$^8;xwcxWv>X zY%!>-?2%0wm=}VoAYMm~5lp_$CfERA0Pc=Fvv5*E3k61v6dTSm*_O(hmHgp?4GF`u z;}8{>%$y8K#DTbl7)uor?1;1iB1Ftj1N4fY07(U?ym>`VK+^*>=axh9hzFRKk%=k8 zfFPV987$%nia>xbFyW5@8IMtz?Gj9UV#u5b;}sQXObR?81{9xUSd5Igh6F^p#afkW zV~T7b0stTf00Lg*SQAiF%=_RVSjq(m0Dv3-2^qnWs`fWS^9_rMZD$#L%fF;fHVBzFvcaPRSUQ19|u-&lu8{2_{17)4bb*n7FeFrs8+w4OcuKCw#OTbzh0ndVeUCQv_&0&hi@7%m<& zh-WFo)KDNm2;w|t?aC-00prDD4g!E20X$DBC)Oz;5b!tw{8#XeCdmk_pa3$Gov0#D z62ci(K!}`sVq!8<5CsnKNY=U#n4lm8sD)GC0;vE&!U4$OLA4P~yCX73GYEN1kqMqL z1jx#c&g^~oh>X>0xQRI_=i~e$8^RotYP?hPfX|?0r|I_JP*BKPXRPy zqu&*1R>na>oMbyWz{tQrf&f4iPDh?2wg8L^fl?4+O02tt002aYnZT^R5mMv8gG7>& zPy~>`tkq*v#HvvVdt{Ea%z>(DH#DTGWCEoTUc^Ud0^ZrNjUn@n3wn_eGw-IdK5?7=j5c2zz{Z@`{@(aO4Y`0!)B| z1U@iwz2Zp)sWtFV#&U|Bf=Y3XY7(6V?3^Qt$)_=cT&*mE10xYdnURTnqji{u2_Zz{ zJN6p1JqAil#v5-^5UQX*!9RpRoH-~7&*3Td;~dq9!Mio7jGy%&PprA87}Gf0kRT$0 zyy8ORlG;C1Ng{EU2aF>jcJLAu3ono35v2rrh@wvqd}L^1EbRz+50G3UnpW+T6RDM7 zFawSUz#&-6TuEmyxWrls%+n_RqMRZuIC>RB%7kHkJWR~Y)ls}8ib;*Nj1C4TwLk>{ z1c?ce&0{Lgx*SQhp{(j|Ss^n{1j_<&pLA(7NXe*Jgmaj8hbeI}xg)ZO;$W*yNOA&_ zo+UzXGUFidw422{`JM!mcZqGGYmE2!te}k*)@l>5)800YgJld9jxS=Nqb#;A^}E0|lS@ zLX0yRtm3I!k_-eDP=VkfA-S=XijHxqOHu4GIoPzgwo@gdVD}_#Y0MvCfz4~&0Rim< zc}$w*5>@5HwldtgBT`SMOF^37RQ*J9zyzFVaR!NmBlM{U6g&e) zCM1XeIHFAvJ^ug*H^9r#v`HZe!@6^nLnQGELYzV>`0zss0?0c#%qcvkJ76V{Y4be6 zMaqO82b2h7budElE>erZrL725p>Q zSR@WT#mBU^R4hQ}2>?mNJ*0x*5GX0z7P^>DH9Z?ntlbl8U29hfPNng=t4-vL!p7Ij zMno!HRAHz;;ZD+dqn_%EhtZvydz)PRU$FilKhLM#{;R3#r=xp!RjW?xa^F_9y=|S& zUqfo?Zg21ITtl7xJwsFsqS8V+x!Q@DeNCOUXsu>GoxYD)vcA=49Pickcc076d%xS; zQMI;nLn*vHS{hu|Q7mf`p$4mkPc~`b;sOarV!L+dZund~ygrY(;oRPPdw&X=zCHS{ zR;wPf1zkewy|pV>+*PYZwQ5~crIoMr?rKt_PNh(-6$x`_2^SWQNgS(dZF|wd{c0br zHg#R?WUG9s&-K4+$48;=-)y_i<6-q{Z|Y9Bea4TgGVg0|+h^QTWu4zlb?bVTJKBZ) z8q74SQLxj4Zzzhc^y$^MW1K*0j|1j@iFN*4xwiiR`I^PH+lgD1{2iLLT57QM;(LED z^_S@U!naTOHhi~~+||E&V~l4=l(6!jw{AbQozu7X9{SQcf4wYs&hpvYe|2>qT+nn| zEyQi#uy*;Qt7@9H=H$M!qh>BFtgGAq09DOpwR-mqr%ldqY|U;D z&wDN?>b9G6QGLN}^^NVWp=m(Xr$w~Q8ke+bicb~Es`{;KTU=A7?;~n}2QO3Q`;OP! ztlO5YEaDUQcxy2|+!GxynQg~1_iUTau6X)Bl6StYYke!*x<2cE+|{)G>8k76#;aP| zj)$#TYT>qem#M0Hd9m4^=o%|rwMi_(jPvt@A00lRawMYr)O1K>XlpOZSyJoFT(Qvk9&V=*KNJFrNn!#bcV9ig)<$8>UZ3CSbB@q zkF`r}rL6SPmV0lZ`}?O#=UTpgqpIyayF*F6yZ+Cm?W@ZcYS#>V zX}Z1B>eijPEa-HdR?V*Kvt_!~TeGUWqHyB5qMIyBl%iqw`2Ba6^>&D=<*erl6HXV0 z+ZvodUoJF$yM3y3>+T!vzUy%5TLhpZ=o2{)*rmwcNd;8r= zjavJ6Q{ApL>%7{&iyY^(J6%lE?9n=JTFvHVMv=tcS)D4 zT}{~Ee49J%=cOGr+Wl_pAKsqQqisRECwfq`*ETKgk4H>?uXx+-XIQCYqG?0vX5{Z5tczOran+g|Ta(seDduRhmu>9lnRX-4MO-%h4| zeL|xx*en}W=AAmtAo1?`jVVO0RUgq`t>9~Gq`uDQ$Jv$2-z&1rWhV4Jl->Qbbsnah z_Z9c4_Z?@xI=Q^Mxl3>Eu8DM)Rki;BY0%R2y9yQ-m6@k$8jh>EZLO}TS~lhP8K}@V z52r=dob04y;#+>I`*q}}FX3+~@Smp>Po&x2+*|!so4dAZu_`ss*i{SL-k1H$?#_b! zw`zK~+y4Mc`rW4OP14O{cv$N9d$jFs$4ZWuqt?+|aaR8TO{KOf?i;!k^W4@IXXizrg7^sY~|pTIcIOIezc{{{XhfP5$0`pZ0 j9xu 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 Fon}TpX09i97m*h7*dv1|%%2{CYZ>9ezC*_ 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

=z%Au|oxZ+3Nx4tps65@o9A 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

}ngG#A4Q5r8#O`f*3&>TJaB5%}!J10U|4?($) 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
}E@v|_G9?1zA4Z(GKO^K= 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 I=fBtg2Zx>A6#xJL literal 0 HcmV?d00001 diff --git a/front/src/assets/images/login-logo.png b/front/src/assets/images/login-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..61765e6dab63920b8e5a9962605860893332543c GIT binary patch literal 4900 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 bXeU50`OgRKIXU;Y|65_K9ME+ZK4<;~Y*11s literal 0 HcmV?d00001 diff --git a/front/src/assets/images/login-sina.png b/front/src/assets/images/login-sina.png new file mode 100644 index 0000000000000000000000000000000000000000..950619fd1b7c76b785dea3be1d775ffe950278c1 GIT binary patch literal 1851 zcmah~2~ZPf6pna+2#ORLpfk9J;4zZ>AlVWrBmp9XBgT?~Se9ggK#~oc1p-*DfH+Vs zDD^0eCly3Rk!meMOB0Jn83932#0r!mShN%iiU-mS0@@jw?(FV=?DxI*{`b8%n;RPJ zZ)@#hO&}0##Q{PoK028nt9kglE0sTr56+lKj;%vtu~Z0!2|h|B1_s0$C=QmwkTNal z8tg?N%pOq51u|nO28|A969``31|6hGgfSonj#Fv*#KD?6BA`<8iQ#Ms zO`;RP@v4Ay6keAeEK{T>DtJnw_Zq;<0OAHTFa`kzjasV*4SeE+T@as}x2Z&60)i#- ziEo0EOF{twg2Dis!XYc@EH>cDqtH1_7LVrvFlclxmByvgnPfT#WYItd1DL#sxHnW8 z3rdB4lfLj3pBRr}I*>|DO--ewGARfeN2T+4JSvSrWiZG%f~-%|VvvEX)w@ku5W;!| zs?uR9L<^WLLNQ1(#wX&DzBz(MH*Hp{pG*^;FscF4QRx(#`A8E$rD7VVOGecb&Xo!( ztcEqP7SrQc`ZN~Ll0-5Mf3I1MW*V)>r10Cby%(*QrRiX*6xJijr~(%`*3BH24ium; zgdwO5LDW+j4~<7KL?4gn0D-`qVIHtDT%}basrps#a9|;X!F;0mJDG;xOc|XH;vz7) zt7%-2MtcL5AWBti+Iyi~kU{?s6qjEKVbK4Al?pHxK{XJrfy!L5RGl_%!ka__inV$S z(kfuFkWa*qM^UMipr=wV5sH_eWzllw(vGE zPpA72Urcu}ti{_F#ruEFOr3J~G4IUp@&5aS5|q+Ex$mijq6dO~^g^ee?3C z@wKd>$l>Ni&6l&D9V|MS{w(_LqAnu>wFLGYJ9xb1W<;~ap1PWq9*0w6v#+;RabAl* zy4LeJqv7S4E3@t!<2ui;jMqIHBGfFGz?>WM{*;>hBvO3mz{rCnrHuW<5}SFR?&25y zIo-~FIuw0!PFn7DM)qry&N=gB#p!`vwo$ilk8K{`UT1%EV5E0!3|T$8KXah{uVD;j zJ6Km#+dF(&A6_5R&0e!s$NVnl>}avv<7rCeG8@;m$6B6{jn_yf;8ds8)xK?}{5_GG z9i(j0{&RK@vn$fa(Af-kK%G?ZI=I;BP^HoK5}}nfn&YupZ2HX3V*UEGoq65W?P`k` zuNXeQPM1&l6TSLS-kpw@d6qSRqM)gGqjoj^f z;+8eZety7mv3sFS>71{B%CPn-?9AG?LA7Ak*<7IKo|m_GpYxJv%cp^y21@_P#jeMJ zw|a)|#O3@}8&a^CMXv3=$0}Y9b5<;FaEK~7Zr%3R%Pbz| z$5H-3JC_~UJm=_2Q)6S?-b7B#g0ix*N2c;}6>0C04U|hppZn)`e835B-Lz(WA#-rs zKjf{7hxJF=UzAogYcGU`X^yWy8J+AAo*R>I$REmBwb5fZnIuQsN;aOk;`wdT><;&! znj&df-j%_M7Wcu!MG@KTer<}Yu;d0i!SMpAJ4YZNFN0qfmTtMdC35q88euy(GglLC Rzrp-F6N`d{r+uR{{{_^{#sUBU literal 0 HcmV?d00001 diff --git a/front/src/assets/images/login-taobao.png b/front/src/assets/images/login-taobao.png new file mode 100644 index 0000000000000000000000000000000000000000..ecaa608aecd8657619c9852b6f9818d6bb52d6fa GIT binary patch literal 1898 zcmah~2~ZPf6pn}zupkye8a%cE6_FkMCyIZBz;K@pO6X-8I329Cdh!$0%1HJ0YddqBBDYdcxCEY z#E(WB--oI-q(&Jo(c*eGWWlh_dV*rpXnym}1f)$tNFW|bL@_DzNnJe?Kw&9!iLa8Q zBxFbu8j@i^qBA1Y+Kd#f7-r7*2mH(u%77jrA;7HHVMd8r${eyQq2`utkO>Sy$P_8_ zT~Hcj6d=P52;j>Wu(VtsUqC2ka|L`KvDh2nakwIoBLca67FQtg;YfHqVEAHE-VAVp zL?sU%_C>9v%p{T|Bp_%qnb;;i8#g3^T(MXTa(Ez*$D$A{<4TN#%q-04K4L+R7_|nJ zAW<9xEEb`7JdKnxsYu@)K~IdD#f-ygq7nw0Ap+#GIhG?00b%VZjz}};hMdD%5YZue z1S5?UmOF~2vZPdw!arzMuOCGlNfq+%**=Iis#g*Ss6vc*nn6p6oZxN=i;&0+2t?ur zHIC~>G9HzLlejSnCjgnul3_96xdg>v++_56kAuh|5|J`3-&q{$=Bv3}2_*tw^f^Z) z;c(tTl{kzhto$I90tx>ErR0Yp68c{-td%6-20cV+fLbaRB(TIGZ%U;k6f=?#rbR;K zQYLjgHj2U$AzvU9Dg-_#^pK!q$HE)a-Y^#)I~M+!T#yO|v{dMO6+5y;wSi?i+JDqy zw1W|hYFh)uufXHNja(q<9yu@Yx75MAm zoS@47$|%v`+Gw}mSWCN!yV0WQZ`(k6mde{j_}DfAa{s7_@#*&Rii!uqC$?CzqYG4O zt#0owue*VTc*Hfm$ttN`)9Bc8$98L3X8aC~x61}(EyNzuL2DV8FNY_w?PDlDDIu*|xL*ZBd@j75lIBolW(M zpSiG)>BF$^H~X!pWm=h1Ry%okG<1W31BW(7)I5#b-1ThAQ6janwjg^}FT-ci_~wU= zw{II8CTh2@4xo)w5GP`EqUjEQ`ssI8EWJW^fWEz0xyjn@{*wH|ho`>@uMQBBnz+Ko zd-rC`tNuROUcSJ;!lq=-t`7ekS*H~~*nQ@n;cJ)1b;+(1A756A^VGekLl~&C>S{SA z%w#ovI+z4lm-WV!O+;m#Ktb% zQWh}vM`H=|?hp0LXUzq48)K$8^SbACJoF25ns9GR4I+ZQdCqQuo!2;X=!LmgzZ`57 ziJaBNx;f*(B)^%$ipsx|rZM^^hxR(Hh%C6}cyukJt17%dF6zyy2^|l1v~{jgPk#Q@ zwJ8s8u*p{wj8|mZ0E$7^S3GZa4Kk|Pi-g{Tt7w{-V=Sa^F>O3LkA1hyf zx@yISt2Sv_GctFsA8_rfj%{+WIoTDM@owI{C4JS#<2o zud^DI%W_Xe3NP4oY(3g@==faQc?7+0aQe2vyY1Nz>sj^It~6iu{=`W-yCasrU#KEN JejsQ?&OeO7%7_2} literal 0 HcmV?d00001 diff --git a/front/src/assets/images/login_desc_bg.png b/front/src/assets/images/login_desc_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..70d8d62f10871e3af7783c3c23b246f6e4ea24ca GIT binary patch literal 272693 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%0AK3FI^M%_lJo#)O{!vCfw1OP75wP6Wjy`Z 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 P00000NkvXXu0mjfFM&Ni literal 0 HcmV?d00001 diff --git a/front/src/assets/images/login_logo.png b/front/src/assets/images/login_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..2955b838b1f804fca7a4f66b2f1e653e199c6491 GIT binary patch literal 3523 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 literal 0 HcmV?d00001 diff --git a/front/src/assets/images/logo.png b/front/src/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f338302ee66b29782882ee1b18751e5816173e50 GIT binary patch literal 3259 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 LNkvXXu0mjfRjz|) literal 0 HcmV?d00001 diff --git a/front/src/assets/images/shadow.png b/front/src/assets/images/shadow.png new file mode 100644 index 0000000000000000000000000000000000000000..79cc097fd05bf5f241324a963c3d21cb62aee884 GIT binary patch literal 224307 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ð#!yPL3NxhH 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⋘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 z zPtE7GIia)yzpJ0;b52IL%bV@%P>naM&qa#P>GsO0)PR4iv38T+i;o)UsvJ5N{;$=Z zasxB34wDGOic1)Po0uScsesBsEQokg$KrPiYVhPH1y^`%aepZ$-4wgAOHU3AT8)yr zmEp5Ba#VSm{oHRG8n8(M@e8yqq>Aix*jH#6<-Sd|0QusKB3dsgX)YMgp@5nFv7_3+ zl-f4>1Y)Zr+R`iN3e%eI$>HtHj#Iwr5Q^CIvAl8_Nj#1e`cf|0{p;v3+8UU-fBnR1 zG63z=cpyRR$A2Bjb+Hdd0X%<9$<=MO2#(v+Z|4_Z*s+6-5GnPp`8yU4L`gZ};TZkB zwk*DmEW9raGLzs{mdBE#9Z{m!SrSJY8Z*XOU_Q-T)dll=jn_j{@Ye_w+!bw*fn5j@%I>>vD(Ne^>9VAL zr5>tB+W!aVUvYSTm$f0aX;9r)Vb^pY^>zL+b?@|bw9u|E;RNkJO9PbLFa^;) z^FaB)u%iWA)*)Uv+9;;=D;s(h7JfQ=!9!8LZKs}t<8Wg1o< z)TZ0Dq$Kx+bEcT_a~kfXvvpLo)*>12jVt%*PS1q^gQdBrWP~tlUcvkE?@66R_0_{f zV)yIh)c2roNgsJMVU&czX>B=DnIc_XU5s?sVqwQ^SAd?y<@%9+jHl@<*lp%K?OWBC zIyQdn)*4Xi>QZ@B@5E`kZ@PW{1aTdavs8AVkXCn9s-9TIk1ihA;T;VLp8!I?;9*5~q< zZeC^K#W{lpySbL(#k}4R7TuryVr+3Nnf)MFI$0{Ct(r}9F$*ew4Y|xn7DWWwDy28| z!*f9%m0V?w_EK4a1J=zE?i~fw*Ry1`AqBg-bkZWxX`AHR|7y$8)@ur8j^i=x8@Q~C zFhSs+ALW`k|Fku1RIbb_%<|<1i|Tp{(w@Z1q-7%Zq{Vg#IxA3^Sz~%6inr$m$pr|4 z*9KF2#-c&bVUXwvl%c^pfJ@-mM{)hVP0@lTK&9fU zme_r5_k60vmCW#Z>Zzvhd@O97ob7ZreFr$Zl@gcBp%YPA=XyWq+#Bb5k@=WFz1j%4 z8F;=v+~32wJ?dOt>K8^k(gpkk?fKU9`!a6%@fG1c zSx`G{oeNw|x1zertm;J$fa=*S>ZdKy2`lm&S1zmdq78|hEGtmOM@OtKo)a!zuoU&@ zG3Li$KloBXugo^u>qSPEk6n={Thv+3>zlrUi!r|GYZTA`llO$3&gy4^*+i5orNfFv ztd-I|C7{;cpC?Gb17?Uee9$Wx*zt=W4O;+-IU!E~*qJt_N~+rTZ}ncGe4lK$W2UB-asklHd+&#U_! z#BpH`UGW8ozf0kkYlIJhOLaMJTE(Gb5mfKiU{Q)@JPALj{4w8=*d>-2im_i!$T ztY5GtS6_&Yt-ZSgvmzmhseZ{WL)6;!20QQe8Oy@1Ldn3DJE+fBz=qozdqSL_8~#$v zIHjSP$J}eO)2Mv$32>E%@&C}N*^;W+_N47{II_)n+Tpw0ecti@1`AF-?=kn3Jgcd+ z36Ol5`059ZK@)Sc^sPnE5KJOsQ8w(`NedG-J->ag$~f;|fhVg_Ig%n5`>{xG53lc( zmkI*!Yj5*0U6TG1Uw%F>OZS_!EvmYaKZX0er!r6|ICL{5s&nT*h;rw>OG-BEnw_2W zl7TWeW%4~Vyp#`)vB!n9)^Odx;L1KQ1~>+~^>b9lyBwst@C+ zFn!Ph8kQQ9`Btt$zq`I(=!j=6ODPwcF@r1DhMKH(2-wJb5qQ-}!0D^PqL#?UF;s{t z#MVI-d&_;+?;1-L{nfz;U}%TwnPKqNf|E#RoA}H_JQDu;*QN?mE?8Lyl>Kxfb&t#y zxGJ&TyxRDf38K_@d<|HLB|u?oK{mhBY8yH#zz+!B+xX)g_f1p$*S+qQxOa=-Xec7U z65*`n*OzU(Oz+f30DCV&O4JB3O&}f8-Z0pr3~!}}J%=9>5@ji>OAZ8p4G0Hy2D8IpnfeoIn=E-yuaS$yldC*OV%cBTeDy>G1*qT#ZiO zxVF1I*?NBb)60%D?GYDvi<&9P{fe>sR`&8<0i4mu3q#zM+ruqz8@|~0){yR;;(Xco zZby@S@1FD%dK;yXYKs^@Zn8h#%;aPs3I0jF-EHG>e-tVB@%o$^b3WRrFA({inZ2H} z))Z;jXgDlL@^HrJwi}7out=>+?Ea)Ug-P21VE7g!fza@m&!n-FsSkxM1>z+TQY z;x-9l4AmO^Y6ZEGaK=tn)Os8t?hJ&j$C7cJQks>IZWK4#8y7#j)x_bWEn;Tcm~bIB zfs%JuENtp~@Sz{89Layjoc=S!_Pu)3jJxGg=3IMZytQ?a8${{PrfF)WV|gujBN1M_ zKzb$7aKKp~8_b@W>ntn;0Mkbi_ZMbZM@W$lR@k~!6(aiKleQo=kNEHg4>3A+;lvD@ z2lqt9)}RYdhxG&vkzFsmJSBubNbLs5A*P<>mtZjD-nB#Vo4GF=hh1SN4SwVaNT)`u zSHn?fF}NaJ^KN8X1JJ$`5fNvWByYL&4-^zn`@K&%18~)A+Hn!PcC2HtZ5Io{C)DDb z`W)Y}b@fzjFd#N_G0&7IGOR!_&!+UM#LJvb!2%?z$ft5}L>y%uY#IgO2DwZjAy1PO zt1%mP^W;mGYwVuI;uc9-Q(qRYsG_kDv)Wue#NnBV%X)T$g907Gn!OfyDfG55 zQE2q!`*5O@Kd7)Uch05J?q9+^bnfJzbFW{1G^FH1;d@6^T|}GRk}dcc_dMP8d@YBq z-tQNb%>hFB(-8pOicnfj@q0*9$J4KjDDuUJ1EoCQ_O1L@_iZe@FSfm2}BiK-33 zC!YUG#v~_jFdn>i{QdxykbGfpD zj`7dFeOmrWDo5lmtxgnMo!fqCUH3?w__U2RKv{uCd6QtpelT0m2f7olG?LMopW3)I zZWDEMR2ib#w>4%y9ZMt#N4keaa81YV$@WO0&Ack(F|u?O(c@A zJ3GVc!;=q-C4<5NjGN*ft|M_AjzC(!j~+gb-)Oz<>qaJN-p_pkOTD@rT0dunST)!S%{m9LUUCmwDqD1IZ@*HtBAa8&hu^5ZHnM?x1qz{?RAzp z3sz@Z=iRh{+Yc6YbiAr|Ew3WXqaj*SX-q+9yZ5yCY+tD6&*P(%y>s<8xCC~DFP)H2 z@2)@B7jab|=#$*zy%XirAS7`gzTq;%I_axpiHX&gmH2)+y&pF0vsw<8Ll5`jLYdBsg};QR3>~|3XY>C@m~gAWTybKN z{el;kiO3jHx)mna&AJf0su?NCGbbd9Z{v=nNVN7?;7zN-(ETZPp=5Xc+DaBxM1fy9 z;rmEnx^u+h=;Qg^j?=%aB!A_&ZxfvY=>;rIM(akT*ZpBz<5V#R-{DxjKvpOy9ggdh z(MOu^tVb2&Y~nvcqPOdkk*JpS+u0Y8^X&`6g)T&Tu+D_(8AYu~O+JBOVR`iL_JCias@nfSQ|gD%>1mfbQj=N)GAw#4#hvK)wD^UR>JkP(R4X>1HaWd)zkve$o!z_;bfCYF0 zBMHl!3o*J%*EvnG%nq*~MIcUs4nr={+%1%7Xr`U zPo8sp1h{uC9T$g;OK=7f;W%No%XNn{9*zTUK2O7F3F&i~R{`Uw+w$o8ovz@3v2)C8 zdT}ONVSGb}Fhi4d2anPZnWAZ|O_Fe|DdmUsM{H@Nny5Af#R>4VB zIhKFEc3$4y1-k`K-DynfWj5m!?kIoZa@rlc4q_uah%dO5sfEmy!3(9T3WTq$d|Pngi?BEEnXvzRXU8pzE(!M~o`x=BHn(El_8B z1aVIS8Z$j;cII7&e`Tv;nqr#!WC0F9J4FvPwPuFSxtw6?KN(R!u(6cYTl;c zblBu$SaZGCHl77}7%(9W20tah?%8G15wW2Qx?JhH^H<>L?b#uObMt@Hc=C((-bi*eeK#u(dsi8&0`o!kdj#kQ4M;SuMMz0)UB+acXbk^k^eRyvs zqyW zx{GY~Vv{NQ(xo4f54D`WU*&{xiFgn7N3-qZEB*_wUtVTsVaF=Yk(inzp{;x1hD{QP zXE?#A0-tl`Z0QsvRbb#+)P|@$vMes?axPxYCyKua-1O=lb-i5p3%vg6dZ*04Ty5bj zW_cZ|yq)m7d%U$V@?~AZ_{!tv0?m#+RIg$M-4amq@SoPlY-GG$J@*SuPu%57 zaj1$OK_r{;jM3@3;1Fp07oZD9&=Xl{H4E83_2A1ghy>vo1MiU1J7P@H(Nk*G8RFgO zO?An}<9&6pxuL{8c*zTuA-9<0`s3-N(QZr7IvnpbhOkm`pGi@q76eBwRDf1(z@vs4 zGGYMnnB+mPkkM*yXNXPv#MaZTxoG_8qH2}J|9#Pt%nv(^!z8Qi)DK4=mVm%Br~ZpYJUn8Em; z&dsssMl@S-6a`T|8_ezkFwscuTnfO=UZ_1xE+Zh%Xg7g>&uPg?!6YRrd&~}dQN*XM z0Qco?#qam!MIPYut=I!?uA*tBcy~Dy@)5kVj5w=fdimP7-iTNkc=QKzcXR6Kmw1X2 zLukA+sVY*^=ow=}a54-5#hSCrZd=>W;)_jEIK&PukF=ZZ8YUC}$nL2ILN|tbuNMRQ zG>rz*XA%xjD#!-S^Ukq+FPCS<&w&W-fxa)5#+XAEVVM~leEhO-TU6Z{|JL(<>0k1G z877$S_kOf;WHZrW50ZJblOm+;hc(zVwM=D9pQk!jYUZ+lbdv3Gr;Urg(vM8MlD4`$ z+e5ru)=|?K9i_2U(l{I3|ITZgdsb+-$X;s#_MWUTVFPgtzyP{7mjDzGTo4; z@@KRTv3za&!yy>0mXBK^%v;=*k2)?HBwd!)hN>YotO!S}7eNQ(8_m{}S4DKndvl$N ziddSB=ia|A*5)NX;-kz}W~}c<3iOBdoXSV^cpD{={k&EQxZygqk|D^(*DbgwN?Y9*b3U$oDhlHcP zOGoZX0hF7BXn0 z$yyJriJ0sccyt)WLwDv#CKRHfeiaeVNUgAHz)!p%NYbBVseZVF^sZi#y@%)w>(*K5 z%QDssk4L?=ZQ-OGM>p>S>gALFD5T^z3`&fDmig(arKYnx^_wmHq2oino@1}X`{HSP zPhl=5Yg3AGGcSh0nu&MaNvop0Pd$NlG)J$Oli~B5$LlV;hA_gRUiRY>iF#zH7i4jY zPZ}8{A){sHhkeDCZWK?ay0e+a&t7`e|(kr*37a3 zVQ(I+A=IZk9e8=b6o~gTW1+D>JuvOyEAf9m*^p(~fY^}pe8!4~rS)8eYbfhkKT$ED zS8;EvBPG`0N1vPk971M;kGKLxRI99%abp+7=jWLJt({}cL1PkJ9Ya03?rBr-rP?hJ z=dS8tI+;I*6sZc~ZnUOW3Y6}%k-q<)25gkWcB&SRh!(|j@kc8iDtRLFt|q)5*Lo%O zg-iiwfa2#Usy}`(E5|zUxE3uf0~Gde)8OsK?Fq2dVE_E8MZ#k9U%S> zMud3W{_ZsihyE+F|80=47PF`IoU{ZJX7O^8l;lS~aA9-N8~fX4G0=ln!YTJA<7|2R z-fF}7p|?kh2ZH zsd>pY(NrH-Qw0HFO*ExisBo1S_TH2nDb*&y$W98&R{h5u{so zWRwT)@KzUD;wuM`sskE2=`v`wZYr5DY6S*9*_+!Z#GW&?{rO}uUJ%|r;uL4@Gn&GCAQP{XIKuLTfssIC{FmsemChAtzE@JqO2RN9>Df;MgPFv924F5rN|60K z|KWj#YaItkz~ld?EGDj8RPmiM6h2SEDJ0t~Qtu(lytD#DzgZQojETu$pz){922zz; zA)dMRCeLL-PtVh*36G@Xt`{MYY-eMY1^ZR9?C0S4=;l-XZR^VU*euiCrg$divEyAG zVnp?@8C%2z5y3gvvXlNC;*4&3E8+mFuVpQzCLhDss2$3eD<$4$o)`86XZ~E{RJm_Z z2>(KSGXo-*)dtiojq}L{XdvN+qDO#f`C8C+Gyv#o=x#XXkKD_mm?@uLrdkQmoi@SW z=kC#YJdewJJg&lXWDpH(AH(iJ3BwF2=*XgZ`M5W+VN1*+Ul6dzh1R$&Lh+f=RMbyP z;gAWo4}upknIsQzxH&SyqEhcof2(j>@zx&;Axo{8He&~Z&ne{dr)f@v9`6Q$&TbTp z2Xv478Q`?bHFS*%o@-S?h?d0TDDVRucz6CM_bWH4stX+v46RQ2mDQ#!~!K6hhU z6X~kt`_})mm=-`>**1A$zNq{cnevU%nxJ`)vAHVI$cB zTyrey`mrxz>FeqU)MuqW=2Yp3r;*w6tpZd|iT+sYo{RFq-YB3ea22pz5&@5@e&_}Z zFgB;Lmq~ZqCt2%+y>V#IVkl+Xx41GM%)EW72R~Hfze?5@L{%DzrOF2~%1!HhL~VI% z7ZN06mKnk=aJ|2(xVM|s;FpbEMr`|r&AzJXYe@eU#Us_JVe%hdJBGO8z-RWo&cRbv>iu&FFwqpjUPE|O*}dApl4>ZRtS*NgpDPyn2GQGn zde~yzFk27oep+f@{)wH&spdd~4@(kbC+<1AWcmKqnO1_rBzdcgu*uk?A#;Ug4?6-2 z>Fad>f^bs%>a})bzNO1fty{!NQ|1h~4N1hf)WXyhy=r(^s+5T`3NFf8aotxH zF4zq#gf8?cvw z>YOF8j!%|nHs|y>zAWQxVvQ-h2eKdOinVbuaJ%bj`H$As^OR3Zs$$F1|M&|cf2AC> zhZnSdS6~JtWR=7VKNQ1e^nN4+4lJ6P6Fz^x5|7wyWE6Sd9zxDZ;}NfOU0CR0RvpXn zNN;3{W8fQq(*Lx4wfR4G$3H^8YS24V{X<(ipm!IfKep8|?2sbu_*EiQ%03*=tNYo+ zmQVWbQCAyJcEf7oID6IFV`up71Zfu68xs&P9?Rss6M;xZRMkeTI7`j(Dha#1nbKr0 ziwTgRulilCL9X60zx=wsDnoSY?jpN=vW=t$48y?Fp@FiGE`^HJIkX<`00^y5!2!-q zbjJRJO3wZ&_h}dx1m`S6i7pzSaxI7*!To8jStq))SqnTtMD@YFc~#RNDx50_+yyz*tgw?ar*Z!(|ly@jcJ z6@mD}ZJB=@fMWT+Sol6D|E}F-vPlS67uMcVHt03*U=vVqs)~`QZ9;3FD;(!j4|0zW zmJ2S1pM<{^%fn_GaZ;i`{YEXm+t|O7qcO{&!VA6kAY{aa-*lhpD)jH(cy3=7FxMq% zptj3JrO%^7VQxLrA3}iMoZ6%em=36Sb5g9D(vs83dYotX^U=~F)kv!zum0mEpx9)r!IgMMOq`5n#BA zaaSOf1jo zkY9R89lNH& zDa_#EsB?QlTZij@|2($F-+s9CK&tdf$Gz#g-l7slu*44&^iPqYF8OOAMxE0nps129 zla#Tp3=E-eNOVFm91f<(&58oGQC;G1dpFNqNIy`!h;n}Ixw8ImUd+m z8-#F^*%fdc?m4UkFYhN-%bUjKQM7eO1soid`dqVl_F2EU-F_1&uOnbUkuN_$;+wf! zo7h?8$J^}e1G?90>xx(&Vjnuv&isv}G1CFoqEN|ZUk(n1dJCVk4Gp9yxQU|v>Cn_e z63_FUvc@Neo>VUV8|V1aBSXzdf^m}m!Oys+67_&7yKHg%FVBc0P0`avvn^r$XZWAU zK0gih>O@+tb15Lb)-PwFXi*mfPi2a|hN)^CjqWuPT;AV+O1w>#*=WlHy8@^Nm;W6~ z|2b@Mt4YL>ba@?VlWEW!Ye!8 zk-kDw@>x(Qf1|Vm*@&1t*&rPG1+5qgkcMf7_0Kje{Vs&YOACheR465S@Nmg;l%HxC z*hDvGw9I+sl@^yCAc(|K1JcmTZc#0HIEf$y^g9qQ?BLW@E_{-Y$AY53mvny;O8|N1z;rjxIs5TvWn z^}2^YGx6Ho7264&CYb@@;%HE$R-`M2xWj*ugDx6ReTCHuWw34$JMcm5aX~-pXW&hS zhV^x9eIm72MESBzZ2Xsr#!>DPCq2RTfVi)lDkYha7v&4rtcnr+zW8agfax4<_YkaQ zQLH@*X#qv(Pc?eMRD!d6^xN2Bar@-zSaynb7GWpNP1OW0U(MWju~@8>5ks6Pq;VB9 zmeMM2Yu=(iJNjA8xxGb>%#q4mw>TkEL!fnFc2@9O^`3h+``DJ>iAeAj&6p$n{n=c9 zhE#LzcC{y&aDmCHdhWrc%bv5rHeppZb80ikQ@wnpCx$&nlydD#GW_oPTnlSi>iMhZ z^?w)sTESUD08PGUK=6WnC%q4j6iQ06k=Gh5tQBm^W>V&xMM20WfnKeQgm^ zFYo!W(}O&4+b}#GH7m{YFTOP?r@g3CYo(IT|L1Coh|(?YfZ?3NHM@3@vhPFZQ@S~f z3}32YO-n_~5`e++*A}sg=jQomRyzW&@0MlJMQZp9qKV#G-4lDOCq7YAtoj-Bkbe5= zjP`EdaobK(+z62l?LY#r(LYUTPd@`0Cj>@!|Q@ z)tZDmMjh?@gWw0wmHA>thL_{aGj0|Jd{#ckaOe$me#D{3#{Z%H1yX(C{rJ}!w|lJT z$nQ9#dPG3R$2w%mIans2#Y9P#07oK=*kxC|VX0p-bmoUb&tX}j!vqLr2vNW|nx_tFiK4uI;j;b__J)WF-wN znsAGO))8vat(I%_8`WfM7NH*KK~m@h;WQIBjGqhieG4f-XYBVlMjP6y^U zhz23{pEJ+L*keCu+_%%C6_xRoU-@^1bAfo>T^s+sgg8B>?vAKslWW*eI0*C|IeS_* zi2YzW>v{9+ONjL1h)mH^kaAxRAt(pz-`rjV5_e<(Z!% zBSG&g&6_37MA>D9CVzbcT+YCaQ)J9r!uCrpI9=o%dOz`%bW@f^N6zSbNXAqgP%g6oX$p9Y96LX z7Ufc=>MC2MG$S3M=$Dm`(-cN{wR>XV&$;B{UbSes)#@3FtniF$orHD;MTuWf zFDR8{C~S}|!}lND=d6)`U)iLZ%5crEQ!Oc4JW&e9#%4>>wEX{H^imt){M_9sW-_=g zV%h|eA8~x}yN@=mY$;ym*mh2k%_<-cOKu)*im*-xdUsF7sPUWyRAEqo4A-uO(NfrX_fg!HMJQz#s zOgdYVUg%X9p0#HBdm#xk#F=_wC{AzYTii;=&Oq+bx&-TOY%N=#$SiNb8-hpf=GnXp zrrwwa>C*LH6{xSz6>iHwESO~tcX!122@^bOz=5obK zkge(70&D^{_7nB|XkX44E}Mp9NHD$TFs%?Xcd6tgvk<*%tF?kQ^@)8#9D#rqAij4U zd{KCza$+d$OkU600q8G&j~l}l@yy&(<3ARM5}#ohRa+pAK$9%RiuA-Rg{UDN7HZ)7 zQ8?R`TJQ>s&}M%8paZS z=1I4>h=rm&Pp-_7pCdpc`TeK+LN=@nvV8ragmrk?)V8`wB$Krh7oz?MYXUYs?viXJbYb zX*c^$iUx@=>H4JNsMr#GY=~>*q6McRkxIL3w7aDr{4Wq$-hZC9KeZe2fn$P?c#`>HpPo3b6AEphZE0xNXT- zF$#?z%djxus!u_o}T4iuDdRyeW>z`e%nvn9q3+TuCCRImeau?WFkzkh?kU z!hP&K$HYRAFzGK9H$;?@abXDcQoH(t8|zziJK2K}5UCw<#R0$UJn`d+L{@2?AK~ct z(XSrlY9EEr0kCjWp=4-6w%m&%o#1-4!AH*M@^>C-MS=fPv#;;CEjFhs!6`CY5w$$R zNvs0s3uOeEm7u=l@(MIWrxAgD3p0BnK5G?(GPLVa)+(IjUIhtxX~YQ(Mj)nWN9kqe zQOzDjC*#J36C_Y8d+gvBY9%udrVk`EBo_;;{wEn{civOlNKLkEIa>_A0ib_C2z7UF zR+&*7&AG4(Jk<@824>W>0MLve-JC;`|b~56^ zP;!L0))g^g#EY`?rdqBrySu*FqA>e;I8A~<9ESMEa>#lkoh@+d{mmCzFKaaY6`?r* zNJWiI7&UTbT?wam)C@L|X*YiYBt0tsdC;rCWmK6`3~|VWlBW#BxT&O->KpbP1KUAt zsYHh#&71Gqb2e~QVi~H=W8IL}30H))N##AIQq3aV2z2;J14|*6CfA8`tcYw$t=8J>74*r@3$a0O7=Vx(6z%t3zzIxwv(U<6J3Qjc}FynDGF+eh##R&Yuo z#%#qguTi_=!|&!>>O8cifhcRgRwo7f&DnS^X(^F6G?!P3eqoln+_PyzAzMzC@UPBC zHDQxz84U*F^Y3t6%}~4V^G4X?7+zm{2rZ2msX-*lN(fVNX~~TkrI+|J;3qYF91d9o zN^LXcBEN=4#^p>h?uHVEpenDRfz44-!|~yM#M_J1p&ODB&6FpuG4(b>I50VERW!Qn zkGpp|%}!RPpkT;fcjh2LO5Rw(=HkgE{52aNZuhvAdzaiD*DI40uqn0>gec^m0Y_H8 zF*)24kll^iB3o`ABfduE@lXy!r9Nx6|0KD=n z<&f#iTN=goC@mTAvAPVr)r1-KFZ&Ow0iKB4XgD#SgEU43wy0Zz0m=)wJD$OFdGj?s znFSe|qjva`p#>d-$10eHJT~0mtWCTXATw~|TKOP#^=;u#SExV{9ggenF$P*aUrdyW z05W(i0qM$+Ltvt=O^gySsiM0BAgIgALX9WkmT|PY!0>$WW$m>AsfNQ-x*!21i1Gqd z!R7xd=Hx+?0e;ihd-#}9wNh&#!<|{ zpG4Ap{j)DRMX}zqw!{ey9WIB9N93EdSpl>3!Tp2T4@d_SQ$bZUE)5sg@ z%Grqc$($+gq`TEhC1%kW7bOB?@~BNCnh#XXTGO;FBe{Bp3qev~gK%ue6*4%uh78V9 z)G0Eu>d9_h34vRvdhlbbeQR6GPuUmda9O6-BLPh9?>*S<4B5-=;V02|pU-&!dit@c z;%PhUcOL1+#uN198~k_)MSC*O)uEK}hnhp!9j22JoQ?D^($@%3Lhp1&BphQq<)ckz zodB8x<)Kf55~&TW8T2-P?}AIrR-gY>jm8%TSoxHfs0!>WWUK|@p6-JcW;5khgWkwK zVwRe7+h5gP-v41LGxi;BG{n61`=2CCEQv>dQHc)wCtJ+9G$6|-(rZQ~`-+vOp&j>! zrj^iCW->`3s<2m)k{VLLGKNK%8n$J_eL_7pc9Y$?;8H=&Aez)}iV9WIZz5J?E%5gc-+>s7H1XM)B!0skea=j?c#Ro|5ZF5#a-<MM%1;e^%6-GZ*rAEb5kwx^xaQr3GCMd&V^_P*kc0VZ8LBD*l3XG% zLJiH;N<8-3Hv?Q`VL`Ir5Jp9?!N3k!pXS!Ir_pC!lE@Z0eqC?*KDx6kt+72){)|J zXYH|EPZV zxHH(ki~CvU7I)Q%O1=0Cpg;N_c0pZGs<%SVyCOjIH3LUFFJXu}GN|RzrTc?&28xv> zwMY;sv7)9_9|SUpG%uEtkZH$YN=R)Sy}lV3i!_bm^VWdNE3YZfV56<^o9%%3cQLZi z6WqU7?dl%-YnU2_ROf5chjMuL;;C0Mqx%%!pyGr5JjjX+8}~kxouraR4{|Q7?!W_Yr>3&uOfrr$ACe0h-0o(Sq~i{UEcHe*SVb! zZa0qR`q8h1%=DYO9zx{^QT>9;0m$7SzuOriiqO3sP6JKbniPwR0n#64C{!IS^^~Qq ziGw6Cpk^XPo;3*so1)at+$slCYZ7XVAJk-wk&q^V9^YLs+QboZ+u&MwA~a?{MElnm zb!5`-BmL}YBZ;Gnh?@k02kwsTX>X2;$j#VuGD>Ac8EuI9W0stUek0c67*(bl(yXu_Qo-U^o}=hx-%Icuo(bqtHkWdnUOKoRQ3PK^i< zpY>%b-gEUB%j4TT{{E$x!RYiO>3|zZ;knB#^f&4>;1V5??~OQlZ|O)mCty z2fqdk2(7+=SAJFbC*`!}$L5NMqVwO!v;1%m(~QU)+cHx_hHMJ^GA_tgK@A5B%J-aO=8VCM{z4vg6X+$q>$kY%@R>t0U|#xU zSoM#9%%61aeI?e=-UHte>f&QTEYAfI%=z|Bt?Hhc{Sn>DB^AWZOm%5GmhRd=Zyisk zD;0anCXd0-!Z7+>FV`nWYB@jU1D^hGtxi9_(K|-Kh~)!_r8Ak-=d$z5<}0V8|Fh*+ z;?3uW>>DpdqxYxg=>#Rgs*5(4113C}oTu3W*lDBJW45F3WZu&LenKZ@C7o&Z|6+EX zm!Y)NcP9%~kstgvo^?uQZb>dqFyA&$j&{iW%@FtQkGuR&2Lyc)cD;<+9U9af+W&=S z4kBm;q1pW-|Cvl)mqj0u`bMU4=8a~hx8~oaw&{U$JaFx0x_)I{_ceIPuroycvtO7V2$WT(K{=!N% z3&Z^;KD{HH&+G6S8-S|XUcz_Jx%p!Oi!>AL=LW-Q%Xsq zp)gf3rVCFU6m|nMyZ0&fN@6+I6ELo1Obf2a#z_2LJbh;75sR2iH%UyzJixKW>bqNi z@!OqG5O4xaXLIUU%Q|Z7i^pXyAJCBeaVJ!uj_9TxXTidoGKrxO2WGgs=EbWItlR9v ztrg~o?=1CRbg-P`ocQjH8OifuGad7>jSHnRF9-I1t&!#S z&qF;Di{zj|4c8dR2EGkdvaI*#Rtfx4G%+XS!9A*ilP1Yp!iXIDV&rF=>HvqT0ad1R z+%s#CzBl&aV zW$C;!Uq>3OYWpoZttk4~hmRM_y~ouD~6gP?pK z=f{@JxvzDko|}I$+AsX2Se@C{I@*w8yPj<>8o4Fk@+NaHTL2!>S6L)bxh+S){eOTM zq?VBn#ObJ*6JuoG&_9!{4ZnUauF|hlB3$FrXQ6V%)y70^6(rb%VXP-HtP#YWNM0aW zjY~{GHkcS9oewCZ5Q5U!@belXRrhRodlyhGVGaiz!HbT8{Eu4)*L7y{(6- zu);4-pg>5J;U0z3kl{k&&$Lz6%Jv%PPrJ#Y5dn)V80<@mWGy~)>>NC);Vx8;iM_0p zn5?At-pOYW%hm) zBBB}&4aJ}!**&5XF4)m8C@qEZOt@*9(gZ07%;o}^yv=6zJ`|c1(PEcYot;L&8tAp` zmHhY-(em^x5dxWEak|QYPsiD(f2BX=g?THtMm@gtK*i6hTi%V!q6$fxDy7HS;@;k5 z(g2K=3|G=+P>%0Gv|_V)7d^3tB?EE*3gO6`B@i(~-O#Ob%f49x0TLgv zm!FRnSOeQQ4|9;nwDJq5nGQJsuZd3^H*+<@G9Lae>=g|iqXQ)rh_Fr=(UkeUbxdFX zSNcRFO6#tSewb>LHviZOdWvwxoOKgNn{vE#)2|h*(4y8K+mGK*Acig1`JK1BY^;aA zkQE^igvJ+U1?`@mQEp(eH8UNhtsz_e1wG}GrZYvjsdX_@;|WgRL;n`$RxgB0Mg8$f zBjO-$G_Nx5cH32zqm1Gd(bYisxY1?@Lq122?DbGAKOC^zrB(8#xABvDt;K0#ZXq3( zu3f(RYCUXR)beEw^%yz#P3iqM1Ge8E=-CzEjso)VcxK6RrQ>l>0-U21b}cNd+X%c| z`W}OYo=-s=Dh>Jqp7*{^JAXM8fd8eyg56dRh}%as<~=$>9izVzG;U!TM;&MORJ$b_ z<5{r=^lWrQz^!>gZekN-+>_;#A95XYsCAA&lE0{rhmzk0jN|%nAr60=25oGbfYaOomc0>6~4T3&8F*U|7PV#on zrw71VLEHG{%9V(er!Mn2^P?F_+4dICq0RYmj;0DbJmG+SY~u(Y5C8-%Eu-ao5@q;M%Y>+cS;-_7xR`~t|~J0IVA_e7BO>w8?LERpGqgLn+1X9 ziYcfDUX#(smljmC7VRP~xU|i|!addACjK$yeTOz7IOh1&Pz3I3+w`-5qh ziH<~4|9`R)^d1-B+IrN`Mbu#AdH;S~S(7SMeRfHzNZn83-MB`d*IdsnRX!IJ=XEayyxj;AV>qW)w+ zJS?-l#zOdY)}Vxw3I)Q-%mUB0Q>1gFaW}qdr*R%#_Fp zye-0{vL|v(lxP5;reI>IGI)>xS~>_QL;GisQiE3uzxi69=M-TJn%ddU5lzXUj0y>I zIjUkiRi!UWC|@IsA!)*KRX}myQShHauksgQK>?vVZV>*b-vjK9SKM@d2C50bwtfgf z0HB$l%gCF&yJ*|guqQUWH>h6NpHC$oBQWEON=;(I-yh8mxFLpv1FNumiZXUw| zrr6KTPG}|NQ!X)^$F|k(dhXbBd_BMpT}J>AKng&i6v-kx$|767{l8C(9Xrn9Py*Lg zqxsE%Ywn`LG(bfwb^=jX*#bFrPqRaeL|;%M>mqjzgq6ZoaMA~NLDf!#HYDoutb|W> zsR6R^V^2FUpR)k9e6a}6XCUht>hL3y)ym5wXjc=4=D zbd1xaE}}U3Y=g_@u2lU8s zk$tCo%??8f5z@YKsE=^%XvY(!xT2vrCxKG=xo5kR=r|%*fl8FA4V-y+=S(BSFraX3 z-sdh>BL$g(z`9(4e5P3vE#NRztxws+K}XBcwcqPGtB{o#HrxKtE;&VxGt#8+9wu9$ zDu|7OfGU$t>1LV`_qaUmH|HZ{g%ZhCmA&z z_}&r?1?gaz21qsPg0GuC1MP2jT;>5)h?psZts3sZLVg*AcEzd zS~+%HX(Ya0b)8iZE3m7mcugw!bpO)rrx^W4-zo)7cHUD3A`j2(2WBmmI?hjHxYZd;z!y^=^wK*L_;0x}AgiC`$VbyJ=u z+v}|cFbzI!viExv|2@l}eA_&p&X-2b-~?FNUIGj+X{!95HJQ#({J^IR47jI5Ot(%n z45%S=QsG~hle%qNq{FHU4Uieag#=h7j(jn_qjU)TmXQU6%hCU(j;1*+sX>*v35>314 z4(S~KO-PQymx_4slrggMUg8|XL#8u5hi7=UBZ_^^ljuvAbeRn>C4uUGK4e1DML`ff z3T^}Rp`gytH3s;q_<{dj?3=F+IRK3Jgy0ZP{Tx2&5g?T#&_*_)ato?Dck*Kw-MFfV z!}na?I!q7ol;C;t^kPd_ z)|8@wHESKzHJ`Gysp@pAuylwSMS;A<_hV7=FCF9V>!N!x2hAfbQB-X@|DvJEx^=N7 zB8Aof@4xCgtC(gY)}0cp!bfqalkb_))|6Fkc;B~(py9;VY&%2>5q={$bzPd$MO7F{ zqoH!kVPb&yxr@5f7I&BPWSt4`r4$$ESt+ag&mu-2%#WA*Pm6nwPClO_lPPjKFJlBG z6^oElvkj^E<~cgyIrjLthU?AhLW2FxbZnl&``thg%SqCNd3k`pElDjnz1Y4mW!sdV z+pp+y+r>d@*^784OiZShq7bgCqBuKyK|?wctS-H-nRM|>LCL-rJMcTmZ>ve z|F%CvmHF7m9@L+q+R*)eC!qdb>#@fk(eLHwrhP90$UphXkA070UG%$d-hA__u%H8f zv7O}anI7=>^Xv}(MQrpfbd5v!m$c zFE5z7gXt|E-ilJM0v>eowq*yhc-(KE9LS)B4j=Y?bf^JCYMq;Iq3*ccNSs6p2n6Wp z^{1+byTpCfz(f=c-t!JTtHhfTew2I;;Fpx{G?^BFwe+yQgL*^PI$s2$bo-i%7j-6W zLn)9*w@)3Pga(L|*CumB1oa5M43xwdXZb9Q(R5Xan6JF`iU}Vux zx0go0=quGiK{=+_#!{SdXi9j6?{88>re?i@eC`2YHHFW){q!@1CIZ_MKv%`+;Lh$2 z(0FZp-W558D-G6#)25&A$%WabbX;GTx;ey56CiQY?6Ge5QE`eyv)Z~vlhD=D+0%q1 zac%h7ck4|^LQS4mSr5|8lXu|I;^L4nB#)iMmDjmLi-15ihf|Xp&V!0t`?5E6`z25{ zSzh2-!e7#op#qWN&}MnGTYT=oHHl>x?xT~aQN1{)p@(3b2@i#T2nVD?=@)yNC?F}w z;Hg8wL7>{jwcmdq6dG(;>G-d~9p`)Lmak2Ba~eD$q~P>-blcb$-z!~HF8@vL!Q;P( z^Oq2(XVZmrjj}ZuQdejqwBHYM52|v(VcLT@HgnIQFX^5@))Ki9>@5{|n~RGdNPxb4 zo1m2czI3wR&*J+(`cVV*S6{s)O3S4a{Z4T!&5#R-{%(ukjYABbcX9#vnRg0I-@Pv2 zp6|QRTQ~-O{ty4~>GbJOKPKu8mXo~Rg?4i}M*bT$T0G2JoCNBDyAwAigw_=UWa?1*73pp4cX95umSZ@w@CRK8UW9)O6oOlaeJOop5Obn&>21 zMN73!qgW4Fbf(g`5E)qDS7c*4N-)g6q1t1O-t% z$*Qra%MbrNtLr}Rr^OnE6dm&J2Cw!y1uE&Ya#jI!;!ZM;;({a0rTA2@R_D-SMs?dq zbJGEfOlX(_NpB&;9G`!8w7viBw{Fof9e;QBS6dcpqGJuiP?be0s>X1c7>IRLgLmH? zo&^P{y?rl=&Ln?)QgA1^p=eSey3=aI*45Ju&hHx3GtNt0Lh!s@^a=J@SD~V5LQ^4` zSBF<^!zB!=*gszGNOlS0{vL|cS}7peQ+6Z5M)9QkLHQ9RCU22CET^UYTCdg&$f6au zAJKoH4$YdRpfM3mZmxE)qR=Ytz?XUnhU*RtW>Po}a*egC`e0Z*+4X}tGqv;5#Cr$QBZ`swGt?Q7UIz8_EY&wS?N0@U~4 ze?wrLf3x@+AeX;?Cuj#eUw-HJTG%=Quz8*DB?bjR(~+lhe&N6axPSCVKboF-<^@?z z(q)I+&UE0?iN7pB_&X;80DNdNyavCY|2FMrv`z57PY=+3tYaPP0|WQI*}_mADV$^w zUIMTHGbKE}X9t4=&Xwc{*PO1W!hUi%e>fCKVy$jE%Ru)O>%r41Kn8$7kO~M+vbP)U z>8^kmK-K6FA>pwd_?(+Kv8%#A9cV6#$Dx`B%(1VFL9lEdySlVEM%48j+~m<+S#?Tt zGIODbFPkPOK9%r5mq$D_oN8ZfJk;US%WEB)45Cvyj+<>9CEf#E!@;F1S>r<(hZMx9 zHjH;Sv$)u)_7RLwmm)_Kciv}#4~itjmI4`r1BArPsUft@rW2`y-otNNQJGnGcU7S1 znt9@I#F?DP5-_6Pqx&d2P!DQMvwM(j8B2&^0U_1i-CP^!1bkmNJ)~=5FsV=i3_+z* zZ=57axdQcY@F~_fWV@e87)XIu*GNwtorDP`1S?4#X4+)1-0iO}Zg(VvI_$@j1x*!% zirJ4&UDZAWlGHkwR_WJReg)JTDKk?EpR2;3SBeulGqa*fzR@(_yxvzLqKvCw&1J`%d zBtfEWCQY?jggg3vOZbDsQHO@5$yAkym84irf;5fjqN513Ucw6Uq#|)uGHTXjPMzrPU^E@GEQ)e;xJON+ zaQq=is_8Su#DBS9R@;TA1v8XG+68 zP-0Rh2bw{`+B~|55bXz>PyWX-k4?m&m3_tey@W@hZCNdvE!*tkWp!GX&I|jW<7AI+ z?-c9);4FadI|25^Yu(`6pAB@O=}6<~f?eXJ%Y6Z_0CK=Fz#TiuOJ^E@4A8xFv7x?P zfIZ*;PB8zS!2RAU3d?uvwzJ@?SD7qS{f?8|jEcTa*b~Qnq0fBslONUlx^Ubt?->y* zV%T@O*<8PV5=f^gxqjX6oA0}vmt!64SjYN6z}*VOB)heyPPwDbBcf4YNmLL~&IeOQ zB5_JV^5w_P2&VG#Hws7UT7&7nD_;tm#kwxD__fz&?oE+9tnMip8^a;m)H zvpBTd{_t(fEP*VYIg$(o&Sbw_^qhCZdnA@A9Ni zA%xou9K(r19ZP+-uTE{u23-ZJ2LKM$E*K=<@EZe;-e{5A-2zSQ_Jdy}G zNdPE+e_3*bW}%%Vamavac<{;8qk7^!R`a>lfxY>C%~GmObj-NI0c zB&J_DG3gw1(XH~1r~&Vs&3b9@Dq_L>dnN#)oR~l2tOB_~RVA;Y>5$8h_S>Q&tuHQ` zr5jlcZY#$JZDw*H6X0IdEq0JB5}UfsOttzPSqmxXZ9>@q=pvel_qAz7Sz3cp=dfnm zIZ@(`Ij$>!_Dkr}J3Zdv&Ewa80m^^Yx&U#! z)h{B`KWia?goO(Id zOM2?Dj&-bKePH0O2h61dJp}Qu*=VahhEQTXNk_VNVzwq7L+uqYkGaTJb6t}$w zSlR6TT>u{IW{&6%=;gOu!%0Jlib>sDe4j}T#h1D7z`EqKX#-i+h3xs%e2owj9cK=Y zb$MN>s2+7oh&vxh7iCq+Gz%g2@W*4b+}WQu6D-wf7p8y zsOz$_zH{$=hWmk43{ZL<>b^o{IOLv-j@v|NWo)e(%d5`mJ6I+nkM`RrS5Y zJ@=e_?)g8@^B-2|Kkg=~GfmfU&bI&5^;K70>5`ht$Z-UVyByacc+LX(#r<(5v5vzL zpMFuOMV}I#Mt~El&+4!u4PrEDX?93-@~(TafTlK{L4PtOd3D%S^qn)0aM{(YPlKqmpUq3@7B!dETvyP&)bYfx95vZ_f*QNB{VzoN4~&; zP%gq#$8c?d+B4(wBENp)JZ* z3c|?&c#o5PwXsILvVkFi3|k4}4X(%6gtZ8?kBo2i1VAW3)yNVqP8P)BV3!Ss-Jx=_ z=GYD3)G5X7MF4JCcxcn%uTEFRhZ<3zg?{IMB=}+~Un8IO6~jQvoeb%p5iZxJuk9XPfP3rKc1xUk0KCU5U1WtA`z0$|)gNMW2mxa3c}$Cs9>4 zd-4+>Lx&N3Z-LPfs*eQKqpz6&+!+4yi(OTi#K;{|TokIQ*qT%> zHPyKc+@A>1Ght;etbHS}r&m0ecscITAvRaC7rO!T_VeQT(c7%HuG8IR>J?E^(XS-|@q_qYon_I>%czo!l4LmqM;z`g#6OD;fsvT!`D z6L?ogUc%Ks3uwRCE&o8>b}i9!6!7$(&NU~&?fd#2`k51GzxZBH;ZowcpF*YHSCOz= zLGEi``}*?(_d_xzCWq6(V4rf?wc&rP?p(9b6K5FNyXoPSY^kk>qufN$wh0i`H2`SF zaih#<1j%$!QmV)QYYKOfpv<%rpEtr!piqcB8;&&s@58Z&=XP^3fVJBgJm3{d&Y&(X zc6;GF-_6@+%ny&+>5l?0eRUX44c~Nd?YDu5{9MZrpFQbB27r*QMcsK5Qqj zs*@^iKMKKW4u3c2U!Yh*L4n#8o5t#{u>h@HTG|F2&bHSO<~t*5}L?Z3|k0CzSXp=&9?X+h%5eOaYy*61JD$-!FG`U-OOeFsE^w1LI5|XVg{m?#HBd($;F!YpQerJ}u@^rK ztHT5UJ#<-{z42QPVJd~e0)2tED1a+LH3_^q-r&IWM+Ih8hn_@IPmFlq_}>exI;bii z9lRxaiwZZ1EH(A1;TtcC7GQEaUrbF1&D@TAwf{Q9Bl)S%E=Wl;U2E7pE-rEf9HkK% zD9qv)%muIsn@o;5Deez}K{>XEJ){fRfda&1F9C#uEgDsL z%a#>Z&I)K2m~YLNuc3>^%}AYbo!EjF!)`~i)64{5`Db!*&O@rv!|zTY)t#|!=YN!S zqJqJ64Y~`S8U-YlnTGvPjM(SY9fLjQl@%~V@o}^()ex4YnLo}zkk}a!Zs;}G2ib)i z#fQ4+Z45n##m`I>3$qA2?dVq>D_WjW(?6ZY$>Li+dT@!NLV~UX*j9I6$L*7eXTB$7 znLSo&>|+X?HJofFPZAUkr}NqEGW3^q351?fNl#sNf%4NjrHDTG!S}iZf-eHs_t%L& z(NqN9MMwESpk2ozN{b4J_s4&K&-I?g!U?pW5?tSx|NF)FaFOGG_5B=zFaN$Aa6W{N z{J!?JuYLV_R!*Pw>|)oA)luCNbgu3=cWmA4lP!?Z&w0cH-qEA1+VDd@1N_k;)dUE(7b3iB zYJxy?orcpJ+a5?~d@bNB4|R3=Pv_2E;O_S-T7-mqIIyJPi5tl295WQq;dIH-iTE<@0f6`$sJO4bvt8xcTPoVAng?Xyu19cX7pm}dg7QPKwdlrP^Z2- z_~=wu36QMSKGrGOq*6r?+6Pf&;A)sQLZ}xByorenG$zI^3D59+oY6wij+b^JJFT^g zD%D-Q>4$yl@k`tahEC_5b0)h#VXDEjnobap+)gF~!tqEqT?J4*QK+!}31PDQ_qT$C zii~12j%6^&Wyo{pA_u{&ill6jH2iUz@-qc25^srYp+4EZQz^6!KlgzSG7}+$)wWv2 zor$2TZr3GimZ9D-eHbT$ZD=daz*4^F6f8p&-AhcPIeB0X4(xibI__X_xfU&9|F6!J$Vd@47d9Bv-+J1QNnFT^f2p01j1Jp z2lL7$S*ITNoM?0oKr_XyQvd+Bi$&v5+(bcvS~MgKUF6`?qv+P8EfPx!Nzn`!pC64zgKyN<4b0xH712*!F#tu+FEK#FgBilZZu{u;6^KR*$9mnWq+3^OT zGR_78DFT%g@B>}EI~mhcdqBQKcx8Kd$_HD3vUP)N**U5k$pbux-JCjf)dhet<>+EU zuT$O3g_hIpaW8ig?7aGkI+UPS;JuygSw7OKPjs3K^pO$YX~oNPu8MbD9bvxDJ7mY!$tza18t;N7Z!8$m30N@40SDZd<%s!A733XfVOJc_A2zKcX z%waZY*Lx$OGdVO%gp`74SYp|cNcvU&)q};q>TpuyDaEp$z^)sOLk){R{qAW+_fSw0 z&gZ`65*y0q5EGNtU1q(G_JJlMgF>Gq@S|61E;3Uf+=CK8TtK}RJHDv%Dvbg7nqyzl zY2ZLOm1r`=3p$o2G*hPL$Y(3p25)z0L;-SDS1Dj>R^eu0BY{|{ox9I8 zO`3SK69Q74`YCu0qyn2RG*MtN71Gbksiv6vLAC)kh6_#VtLh-1+OE*K&5=G!En1wo zOM!=@OQwUY0s`B|$(D-Nart3-3 z3Vg@L(!oMw3Ln&{kq!p4J*IlfbjUM19rlxUyquqwIg*Yi#NUHN&COhP?n7O~GrJyD z?ipJ!QUJsA8_u1qRAkGh(@C?^Qw(T5G!0Q+0d9D_qI$1Q! zM`$&b?(YH+8O0YC;KIbXf+N+TQm0+rH-N@!`$+(QI7|qL;3gq%sDO9&Xu2~#x3!;~ zG)SN)l*S2@&1BT=ciUUyq|Z7p%&z`(i~v+C&{puP|84iW|{GRBhWHe1a$0m=## zn_>qKIg-o{trA55;Goyic{vFOMRh<$R}t5eOnSsi4-s8QH`=gGgg;&EhEjvdV=6>5 zAGsTpq-ly!BvX@yvjQ+ur&`@l(MGVwn{0b21Os3>I|8QJPZB7qWh#mSHCc0Uu{xDf zt}z02=R#rpxMzE{H&d(d_Sa#pCcqb^>1Oumq{RTtzin5&%5%s>&iq;^v$xL_EwmS#%C5DB0HvsiF8+hCH|I@vOu|8CvLI4Gskt+W{obJx zTvNLfOX;d_z@XyplHG+I&6i&3{x^5ziB~tjdmVffcv2VZ3*?$Y0;mLa>a0q1tdYK~ z4Asdc(Y2ZbJO-E&t*4rIuaw8S+8z?Yra&&BQI>k6xza;WRs>$u>DS~#)FMqNG)c*} zUnC)N1J-hVDW`6)f^w#Q9tyOID=izn;wcTa!fNqxUuLZI^gbjcRrMnfnv-oW(_sQs z;s4*=&1APp8z7-%i|#t-(^h{u9US;X$dCE-nUI`;5YiL>7{IN!t!t-3N+3^;MPq21 zqlhbHHw|bNblt|OIlNYa;bt0E0uxpjCDMqrk*=)*ntE|EsN8yRfDaxAV(#1mJtyz! z(46GM=w#hy8i_^B)&x*=2NelcObTJ8?k8DNmeHY10-QSMM+YpGNDUoZLx(_@xmirA zI}VP$ib`#**@9hD)f{>zzz(%cMPt@EUhMkAgu>!n`?OmqD;kO>Piv02R_$LjDalg} z(PF~JlEAg4Ih0G+HOVJ^g6e|cblWeQ1W}ZnKz;Szpsv>6m)X;s8uct4b-Pe;qL?;h zH|>{W2z0k|wY^7*sT!-ygyT7-?rvFd|mdo&$mke|1@ z^a$rh(+vb9ME?QYx^Nij>ghY|exeTX8nN>T(eyr-iinhKD0R2hm75$z@4TNJt~nVl zDZ7#PqO6@7F79p%`Ud{-tLZ`D1zih7sU_$a4&VxxNKZPXM^NDw>9ANQs<2qd zxn&Oscq*VuB3;=pA~qCFyiuMc(|H?H69Hp{jU?Xi{@vN|T{WEvBo8#-Vej z@F|U`#dALa*{lTLLd7}i_*Imlp>QEd16gz_R<(OP{E zE2}^Wr2@Pin%GQ1*oL_0^?J~;j$1LJa$tgM-0xY-h1& zrH(6n)QB!Y;aCO=W7(LhK$FNikC7Z(V{d5-DhWD8Q$V(pi$B}S5|gqXnGZF@_-b0H zQ$L1vY&JCz%THb3YN4|xmOaIkq~!g{v#)*aYhU}iwvIdfxKjrU_l%0=U3QMl_Pmxw zTX56y*|ysRo#RnG&La;dQaE|&huCef-C>FDBsPyJ9OMRb=hb=aF$O=05V6*i+skCY zqo5bj8WiqA@XfK?VPkYRdJv6Aoj^pM-JbJfyr#PPgJ}a45&B<*>#RIvCv#w{!IE4{ z6kL-Ddr5eot6NG3d8q(B9^w=dj&Mh52L(hJ#N&Fn_%%ds0+FJPC_D;`dSXlLA~eWnZcGQO)5}|&y9iD%%16U2u<+{Z-6HO zM`$hbBTshS2}!Sog~#s6&eZLosP6Pqt?%u#ZT`>@n|IFs18F%a7hn7)j`B>xE7X{2 zvhWmoPGN$uPWITA-az6-1s}QDYC)}RAPI;XE5#Di6D$)O)CU5^=t3vcK(LNnDR>cf zOT(a|A^AL)*;bwc(wh2+3yw?DbfmDME3e6c!iUmqiH0l(yT#FkF0FF}Jo{=cN(3~6 zyRMVYwBVF)5L)C4g~q^|lZ}siq_mFi{wAh8cH%it5Uw$8l6_^kDp3G63sCWffm$}= z(!+E>*#s5{Y;f_CnzX?5q$O(1KYLWI zE~~nbnS{aZp}L-2R}vjTglTl$gKxUd*yzC{Z#n$WWBfmwGb_+Wr&~@CU|RdJpAuU2 zAn*Akiga?J9=P&h9|;*!$j=HzW0g4einz7a&N1D*{-QtW5AHd(1SJRw+C_I4I2&|X&09G4qI#&i51)HxCzx^IgQMHuD1sKB?;+A^ z1++ojIlAHc9)osh6;~Q`jkI{e!0DR}-qmgH6mrpUrG4$m5`t8^wNp%z?6{(94zQoj z5X!3CD+@`IfWys46sUd(9+n0LlZ#c{VzMV307347(bTEp6krNW?Ma0-O{3kBw)Za% zHI3dmK(nY`noJxjr&`k$O$tsB-OcC1wHE(-Xr^8XmW%0uxO?=}2MbgzBCRo5NtxAq zXz=L8xjzZf(T<3ZuHtZezXTGMIEO0Gp)#5JBq|)mq(ZSGEQ~@!pEINqSJQs5^t8a! z_K7ECK9Pp1d;HRRW92lsEM*8?Fpi5)3YR67d2+o@s2}u3Kkj;+COd1 z2(itL2~qBt&Qn)$&Cvv=xt>TTzx`=tqEWC7U7f^>KmCzr2iCfCaPC#?tiHE#!LmhE zICt$G_kHbaU;EnEHFn&`w$Slf)#a64-|EhGRhL%4N%V_8yK5u>v|e>fG4x;T5Fx?h z!5m*6z$yUF!ev3=TwK~?2-P+aRM!c@i=a(84CaC(I;_wM^7i1z7kdb>DxSE)h`I%T zc)W|pkWKXvaKaNDK5;@shX2g*0ykB34beVGqj9W!K2ZapT^#7-gG!dcE*XGLSq^3r zA=jfV?68v)9iq8sCrVD)00GXL-IjXJR&NeNS|%3;xyRgpq~qD)E|1V$-EKH4J1EJw^uwOUb`Pp`q@_mn#PL4-Kocz}%hRxO-$g0nFi77&w45SqJB#@!EC*%yZlos|Cx5IVU>lc^!g=WN~3rv85u1^FEq_q4U2wVb}JI2JsvR z;@$>;mzzx&z}xl&!r-tIbw+H2{$SUc&qbIT>EvWFwDbvC)2U=0JNJ#isLn$Qi$n=% zlLerDk(=$^w|$-uE0ZKL3dY6n7pJM>OaycrS8&dO zc7|2zR18W}v7BB7S^ zpzEOhmHmEFu>+5}@=C}h3V1u8+kL`&Z4@og^~RB@-netz_qDHm?Q37x+;ImpxFf1g zTBBQS4s$=+UXbTt8{we~fQ`k%KMBQza|IwObQX8p)tMTjBicj6scvYSC;nR?YZ&a7 zQo4g*#Cz52s}rVVRdqi>tI0H-g5}>ate)+6-a_!2>yeJN=nq2+KD!c9s{?rC;SN7s zplPajtPi8P^$0b^A166-0o>;nl=$YZpd4-RDwqFzX#kI5nCbF$J>WH+I7|i(i(NkG z0>iPM4ZH?VEz}Jj#HE+(4AdSc(BeUl^<0igMx;STuuCh^5m$kQMPW0ohSMjvov?V^ zuBAkhP)Fb}4}|cjgNRSOs67(Y!j3w#B_+UH9m$1h0pUwJU+RDpzNGUeuyGcm$kiU? zIwn~_3NY*Zt2>W|VLrDxlxxU3c{+ichiF-Ja8L2^*#hFhskei9NOWyiQC|WOi7Elr z2)w4GN>j5sKK#)g&bAaiPuc~9cm5QCs@y_wn=R~=W&^s2uGb80Dq$x%IvfdK%Y<_Z zPAb|TOrnNlNB9y&7bW@(T2IK;D2wD&2SJN=FI_(M4pfnBD$IC()#1 z(6v%Wx`YorItGJsb-0UpHQRMo2iW%&Ro5x;v#1c9sBQDnNxY{5jug}$dliATJlvPq z^BEy{leHyNqk$qrMdAo>KH867zaP5Ph+~mu+$)8l1>TbjN&)cgj~P}L<>G*({SnEd z*e!~zBbpQTJtK+0P4;sGJt#@yROfmFbv%pI zanysqhv#^M7-1f4vhYg@lj5rOuy%kZ(NFXY(IiGF0P2>m>f`}Xmhc1b=CKR(KucJd z2KYf*Z38LDAYq|W48^Z)243oFt2>&pEL`n&GYVXYI$|deIf4jKkD^E@ps9wx2xIzz zpr|Z|l;V!LfSAsPe)j-m1d8iOS}WRI6-d%Zs5?D{8;W@CDlnRX z6r6Qk2vL=qIsXLm0N@IRiaFTf_brjG9C_gUuh<6;;U~}aP)C-asg(|Pit`O)X|UrB z`$H6=;*ckGb7jeB4Mj7UWy5Qdm7&!*5!7~%vMq&5f(7Hqo_8^Fgny0xf+^AxKJ7iM zAqS{yygfpn3a(BniqN$Lg$;d(=q!5woKsJs#;nxWg}tXe=nlQ!;+Z?{(hr~!QSO2S z-U|h(+?7OCDBic#B5YlZRnt7t?Nm{*Et|!t=ucPc6ZD=?xYn?iP2Rhs3$J|i ze!xv|JuDf+Ics10+Sk7JwXbXGxTgc%QuwCHsh|=O)(uD( z(HGjmNv7Sv5PAaM%oe6v~7|nsatXtGQ7{0U!Xgx+Bhm zSaI$={0`h9ZQw}=8yTMix;{^9UK z@sa^L74wO~G3kfls$YCEaHm7p26Oa-awMk`br&U+6$lpB{+u=3nLDRrC@Hn*S;>HKf!c||Nbxe(IiNCMYt+7llL z(veISDU&oTDpd{V85M`s!e|2Fn(1#9fv~j~_|+h+75D#Ozj?X(i0;-cB9>zfjRCpB zAncaz!S|0qyZzWBj7mj~_9TUW@{~?Rgr)`4R+!)s>Hsx;ul75EWDF*me$-L#s3a>Bg(0UJRK15H@#IG=q|l?x?C0J-Rz8 zz=@egvv^V6XLzUhd)rL{9#4p2>u7)~;0Wjx5YwoC8lh7ZCj54yfigs4<2SI1V~&%? zV%yBY?^hgJI;_OPPZsYkrUdlK)`6T2bv6Nn=H=Ge;X*?`gZn%zp&`(0LLfL47>sWPuU@b^I93fkr?_|qA0c!nhk^4|FZ=EnE5-f+fCKYOjib+i!;K7SBp>FUR zt~SKI&QP=jB-bJKjXL~tP?`=DB>>jsFde{NGB;Wp0u_R%8cfq2gwMf37eLH}Gj+P; z*r3W6T&KW709=E5bI~MQQxJOyNTGOWGF0rBj(D=Sa|#fEe5n*K!nKtt1TkhVvQ^+( zaKcnbiM%dMjt1V%-Tb2N`{?vg+h&^P=5se$WV_ubO<#L@;DvE%>9SG(Sp5^XH0xFi(^I|pQ^blSa(?BF1l_2&I99=!p z#ry7d?-=udLqr8s+q=9+m=k>5$zIs$;4mGHrvichiJc6>YQm)A(l3n4m+=aCd%m z0%frspSb5tOH??i0D=ErnTkXr*0$%umNJK^RK*YOMg~`z;$~s93fSrz%29+A-fYJn zy%vH}bzY^nP!j3rprJ&*K=_U85a$7*G}Ml%(CHqbIaI(amp1zv+w^ns{tzV#TgM#T zWZRe4!?K++O*|K0Yst|aAi z&4oZQpiwj_i9x&V2^+Mif+$-^QWP89Tr^SIHW@U00o21pS6JB%V|9^%s8jTkWhV3r z-N0y?i^8ll)get*(`LbkX$TpeVE*(L2ms9;vmkdEaoZ7JUm37dWom`3Xs1wQa-iwdtOCDN+%o}`dsA3t=Iyjr4D#i3E zm3R{3YLcNzVIPM5$+NG0?Q38Ax<=rxZV+7W;4Z_NZss%(e(;a#EJIgtS6m}@b;%3< z)3cKSv3Q#i`IQ=u4gwf?=KIBe?%Tt7z&}qs_5<_{Fzj)5sFQ@TN=a<#yt~*ipfCqq zfLz>EI>d0IEe;d-QD+ycwq(ET^=J@FM^nd@&6(8{p{35?mC+w5Zy z|9RB$rz;7|^PBJ>K@LWjB|2NyWe;^nJTN+;RLk=@4Xh)l7mPcvEp!0G7y zLO_k6>Cq1Vvd%;wI4q~;Fg@)`2{Y4OPiHe!1q?+5o)CU|qN7w_!n;&(i6)|>7*;!! zXVbv+-iFm)=x9k5o}{vDa%Z<;jp(97;@-yA$rMQ(Wp@$9tYUOpDMHm|J5;PQrz08< zqzZVTZ~t|)`;5HWD|~CyL9jGrGSmU7D#Ubtl@8kI>{=)bUH;H~E)kD<(}}*aQu(

Vgn8s3BxJttwP!+0+JWPIHiMQ2?i?r?ll#HSd3D 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 F{{SzO*Q5Xd literal 0 HcmV?d00001 diff --git a/front/src/assets/images/slider/sub_slider_default.png b/front/src/assets/images/slider/sub_slider_default.png new file mode 100644 index 0000000000000000000000000000000000000000..67a4f2794e26b2e082f282b6209dd3208365cfca GIT binary patch literal 3105 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 MHZZ?drRNg&AN+^vQ~&?~ literal 0 HcmV?d00001 diff --git a/front/src/assets/style/lib/animate.css b/front/src/assets/style/lib/animate.css new file mode 100644 index 00000000..6c72f594 --- /dev/null +++ b/front/src/assets/style/lib/animate.css @@ -0,0 +1,3625 @@ +@charset "UTF-8"; + +/*! + * animate.css -https://daneden.github.io/animate.css/ + * Version - 3.7.2 + * Licensed under the MIT license - http://opensource.org/licenses/MIT + * + * Copyright (c) 2019 Daniel Eden + */ + +@-webkit-keyframes bounce { + from, + 20%, + 53%, + 80%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 40%, + 43% { + -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + -webkit-transform: translate3d(0, -30px, 0); + transform: translate3d(0, -30px, 0); + } + + 70% { + -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + -webkit-transform: translate3d(0, -15px, 0); + transform: translate3d(0, -15px, 0); + } + + 90% { + -webkit-transform: translate3d(0, -4px, 0); + transform: translate3d(0, -4px, 0); + } +} + +@keyframes bounce { + from, + 20%, + 53%, + 80%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 40%, + 43% { + -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + -webkit-transform: translate3d(0, -30px, 0); + transform: translate3d(0, -30px, 0); + } + + 70% { + -webkit-animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + animation-timing-function: cubic-bezier(0.755, 0.05, 0.855, 0.06); + -webkit-transform: translate3d(0, -15px, 0); + transform: translate3d(0, -15px, 0); + } + + 90% { + -webkit-transform: translate3d(0, -4px, 0); + transform: translate3d(0, -4px, 0); + } +} + +.bounce { + -webkit-animation-name: bounce; + animation-name: bounce; + -webkit-transform-origin: center bottom; + transform-origin: center bottom; +} + +@-webkit-keyframes flash { + from, + 50%, + to { + opacity: 1; + } + + 25%, + 75% { + opacity: 0; + } +} + +@keyframes flash { + from, + 50%, + to { + opacity: 1; + } + + 25%, + 75% { + opacity: 0; + } +} + +.flash { + -webkit-animation-name: flash; + animation-name: flash; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes pulse { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 50% { + -webkit-transform: scale3d(1.05, 1.05, 1.05); + transform: scale3d(1.05, 1.05, 1.05); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes pulse { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 50% { + -webkit-transform: scale3d(1.05, 1.05, 1.05); + transform: scale3d(1.05, 1.05, 1.05); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.pulse { + -webkit-animation-name: pulse; + animation-name: pulse; +} + +@-webkit-keyframes rubberBand { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 30% { + -webkit-transform: scale3d(1.25, 0.75, 1); + transform: scale3d(1.25, 0.75, 1); + } + + 40% { + -webkit-transform: scale3d(0.75, 1.25, 1); + transform: scale3d(0.75, 1.25, 1); + } + + 50% { + -webkit-transform: scale3d(1.15, 0.85, 1); + transform: scale3d(1.15, 0.85, 1); + } + + 65% { + -webkit-transform: scale3d(0.95, 1.05, 1); + transform: scale3d(0.95, 1.05, 1); + } + + 75% { + -webkit-transform: scale3d(1.05, 0.95, 1); + transform: scale3d(1.05, 0.95, 1); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes rubberBand { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 30% { + -webkit-transform: scale3d(1.25, 0.75, 1); + transform: scale3d(1.25, 0.75, 1); + } + + 40% { + -webkit-transform: scale3d(0.75, 1.25, 1); + transform: scale3d(0.75, 1.25, 1); + } + + 50% { + -webkit-transform: scale3d(1.15, 0.85, 1); + transform: scale3d(1.15, 0.85, 1); + } + + 65% { + -webkit-transform: scale3d(0.95, 1.05, 1); + transform: scale3d(0.95, 1.05, 1); + } + + 75% { + -webkit-transform: scale3d(1.05, 0.95, 1); + transform: scale3d(1.05, 0.95, 1); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.rubberBand { + -webkit-animation-name: rubberBand; + animation-name: rubberBand; +} + +@-webkit-keyframes shake { + from, + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 10%, + 30%, + 50%, + 70%, + 90% { + -webkit-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + } + + 20%, + 40%, + 60%, + 80% { + -webkit-transform: translate3d(10px, 0, 0); + transform: translate3d(10px, 0, 0); + } +} + +@keyframes shake { + from, + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 10%, + 30%, + 50%, + 70%, + 90% { + -webkit-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + } + + 20%, + 40%, + 60%, + 80% { + -webkit-transform: translate3d(10px, 0, 0); + transform: translate3d(10px, 0, 0); + } +} + +.shake { + -webkit-animation-name: shake; + animation-name: shake; +} + +@-webkit-keyframes headShake { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 6.5% { + -webkit-transform: translateX(-6px) rotateY(-9deg); + transform: translateX(-6px) rotateY(-9deg); + } + + 18.5% { + -webkit-transform: translateX(5px) rotateY(7deg); + transform: translateX(5px) rotateY(7deg); + } + + 31.5% { + -webkit-transform: translateX(-3px) rotateY(-5deg); + transform: translateX(-3px) rotateY(-5deg); + } + + 43.5% { + -webkit-transform: translateX(2px) rotateY(3deg); + transform: translateX(2px) rotateY(3deg); + } + + 50% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +@keyframes headShake { + 0% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + + 6.5% { + -webkit-transform: translateX(-6px) rotateY(-9deg); + transform: translateX(-6px) rotateY(-9deg); + } + + 18.5% { + -webkit-transform: translateX(5px) rotateY(7deg); + transform: translateX(5px) rotateY(7deg); + } + + 31.5% { + -webkit-transform: translateX(-3px) rotateY(-5deg); + transform: translateX(-3px) rotateY(-5deg); + } + + 43.5% { + -webkit-transform: translateX(2px) rotateY(3deg); + transform: translateX(2px) rotateY(3deg); + } + + 50% { + -webkit-transform: translateX(0); + transform: translateX(0); + } +} + +.headShake { + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-name: headShake; + animation-name: headShake; +} + +@-webkit-keyframes swing { + 20% { + -webkit-transform: rotate3d(0, 0, 1, 15deg); + transform: rotate3d(0, 0, 1, 15deg); + } + + 40% { + -webkit-transform: rotate3d(0, 0, 1, -10deg); + transform: rotate3d(0, 0, 1, -10deg); + } + + 60% { + -webkit-transform: rotate3d(0, 0, 1, 5deg); + transform: rotate3d(0, 0, 1, 5deg); + } + + 80% { + -webkit-transform: rotate3d(0, 0, 1, -5deg); + transform: rotate3d(0, 0, 1, -5deg); + } + + to { + -webkit-transform: rotate3d(0, 0, 1, 0deg); + transform: rotate3d(0, 0, 1, 0deg); + } +} + +@keyframes swing { + 20% { + -webkit-transform: rotate3d(0, 0, 1, 15deg); + transform: rotate3d(0, 0, 1, 15deg); + } + + 40% { + -webkit-transform: rotate3d(0, 0, 1, -10deg); + transform: rotate3d(0, 0, 1, -10deg); + } + + 60% { + -webkit-transform: rotate3d(0, 0, 1, 5deg); + transform: rotate3d(0, 0, 1, 5deg); + } + + 80% { + -webkit-transform: rotate3d(0, 0, 1, -5deg); + transform: rotate3d(0, 0, 1, -5deg); + } + + to { + -webkit-transform: rotate3d(0, 0, 1, 0deg); + transform: rotate3d(0, 0, 1, 0deg); + } +} + +.swing { + -webkit-transform-origin: top center; + transform-origin: top center; + -webkit-animation-name: swing; + animation-name: swing; +} + +@-webkit-keyframes tada { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 30%, + 50%, + 70%, + 90% { + -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 40%, + 60%, + 80% { + -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes tada { + from { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } + + 10%, + 20% { + -webkit-transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + transform: scale3d(0.9, 0.9, 0.9) rotate3d(0, 0, 1, -3deg); + } + + 30%, + 50%, + 70%, + 90% { + -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg); + } + + 40%, + 60%, + 80% { + -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg); + } + + to { + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.tada { + -webkit-animation-name: tada; + animation-name: tada; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes wobble { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 15% { + -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); + transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); + } + + 30% { + -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); + transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); + } + + 45% { + -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); + transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); + } + + 60% { + -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); + transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); + } + + 75% { + -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); + transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes wobble { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 15% { + -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); + transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg); + } + + 30% { + -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); + transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg); + } + + 45% { + -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); + transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg); + } + + 60% { + -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); + transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg); + } + + 75% { + -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); + transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.wobble { + -webkit-animation-name: wobble; + animation-name: wobble; +} + +@-webkit-keyframes jello { + from, + 11.1%, + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 22.2% { + -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); + transform: skewX(-12.5deg) skewY(-12.5deg); + } + + 33.3% { + -webkit-transform: skewX(6.25deg) skewY(6.25deg); + transform: skewX(6.25deg) skewY(6.25deg); + } + + 44.4% { + -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); + transform: skewX(-3.125deg) skewY(-3.125deg); + } + + 55.5% { + -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); + transform: skewX(1.5625deg) skewY(1.5625deg); + } + + 66.6% { + -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); + transform: skewX(-0.78125deg) skewY(-0.78125deg); + } + + 77.7% { + -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); + transform: skewX(0.390625deg) skewY(0.390625deg); + } + + 88.8% { + -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); + transform: skewX(-0.1953125deg) skewY(-0.1953125deg); + } +} + +@keyframes jello { + from, + 11.1%, + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + 22.2% { + -webkit-transform: skewX(-12.5deg) skewY(-12.5deg); + transform: skewX(-12.5deg) skewY(-12.5deg); + } + + 33.3% { + -webkit-transform: skewX(6.25deg) skewY(6.25deg); + transform: skewX(6.25deg) skewY(6.25deg); + } + + 44.4% { + -webkit-transform: skewX(-3.125deg) skewY(-3.125deg); + transform: skewX(-3.125deg) skewY(-3.125deg); + } + + 55.5% { + -webkit-transform: skewX(1.5625deg) skewY(1.5625deg); + transform: skewX(1.5625deg) skewY(1.5625deg); + } + + 66.6% { + -webkit-transform: skewX(-0.78125deg) skewY(-0.78125deg); + transform: skewX(-0.78125deg) skewY(-0.78125deg); + } + + 77.7% { + -webkit-transform: skewX(0.390625deg) skewY(0.390625deg); + transform: skewX(0.390625deg) skewY(0.390625deg); + } + + 88.8% { + -webkit-transform: skewX(-0.1953125deg) skewY(-0.1953125deg); + transform: skewX(-0.1953125deg) skewY(-0.1953125deg); + } +} + +.jello { + -webkit-animation-name: jello; + animation-name: jello; + -webkit-transform-origin: center; + transform-origin: center; +} + +@-webkit-keyframes heartBeat { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 14% { + -webkit-transform: scale(1.3); + transform: scale(1.3); + } + + 28% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 42% { + -webkit-transform: scale(1.3); + transform: scale(1.3); + } + + 70% { + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes heartBeat { + 0% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 14% { + -webkit-transform: scale(1.3); + transform: scale(1.3); + } + + 28% { + -webkit-transform: scale(1); + transform: scale(1); + } + + 42% { + -webkit-transform: scale(1.3); + transform: scale(1.3); + } + + 70% { + -webkit-transform: scale(1); + transform: scale(1); + } +} + +.heartBeat { + -webkit-animation-name: heartBeat; + animation-name: heartBeat; + -webkit-animation-duration: 1.3s; + animation-duration: 1.3s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; +} + +@-webkit-keyframes bounceIn { + from, + 20%, + 40%, + 60%, + 80%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + 20% { + -webkit-transform: scale3d(1.1, 1.1, 1.1); + transform: scale3d(1.1, 1.1, 1.1); + } + + 40% { + -webkit-transform: scale3d(0.9, 0.9, 0.9); + transform: scale3d(0.9, 0.9, 0.9); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(1.03, 1.03, 1.03); + transform: scale3d(1.03, 1.03, 1.03); + } + + 80% { + -webkit-transform: scale3d(0.97, 0.97, 0.97); + transform: scale3d(0.97, 0.97, 0.97); + } + + to { + opacity: 1; + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +@keyframes bounceIn { + from, + 20%, + 40%, + 60%, + 80%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + 20% { + -webkit-transform: scale3d(1.1, 1.1, 1.1); + transform: scale3d(1.1, 1.1, 1.1); + } + + 40% { + -webkit-transform: scale3d(0.9, 0.9, 0.9); + transform: scale3d(0.9, 0.9, 0.9); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(1.03, 1.03, 1.03); + transform: scale3d(1.03, 1.03, 1.03); + } + + 80% { + -webkit-transform: scale3d(0.97, 0.97, 0.97); + transform: scale3d(0.97, 0.97, 0.97); + } + + to { + opacity: 1; + -webkit-transform: scale3d(1, 1, 1); + transform: scale3d(1, 1, 1); + } +} + +.bounceIn { + -webkit-animation-duration: 0.75s; + animation-duration: 0.75s; + -webkit-animation-name: bounceIn; + animation-name: bounceIn; +} + +@-webkit-keyframes bounceInDown { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: translate3d(0, -3000px, 0); + transform: translate3d(0, -3000px, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(0, 25px, 0); + transform: translate3d(0, 25px, 0); + } + + 75% { + -webkit-transform: translate3d(0, -10px, 0); + transform: translate3d(0, -10px, 0); + } + + 90% { + -webkit-transform: translate3d(0, 5px, 0); + transform: translate3d(0, 5px, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes bounceInDown { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: translate3d(0, -3000px, 0); + transform: translate3d(0, -3000px, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(0, 25px, 0); + transform: translate3d(0, 25px, 0); + } + + 75% { + -webkit-transform: translate3d(0, -10px, 0); + transform: translate3d(0, -10px, 0); + } + + 90% { + -webkit-transform: translate3d(0, 5px, 0); + transform: translate3d(0, 5px, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.bounceInDown { + -webkit-animation-name: bounceInDown; + animation-name: bounceInDown; +} + +@-webkit-keyframes bounceInLeft { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: translate3d(-3000px, 0, 0); + transform: translate3d(-3000px, 0, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(25px, 0, 0); + transform: translate3d(25px, 0, 0); + } + + 75% { + -webkit-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + } + + 90% { + -webkit-transform: translate3d(5px, 0, 0); + transform: translate3d(5px, 0, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes bounceInLeft { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + 0% { + opacity: 0; + -webkit-transform: translate3d(-3000px, 0, 0); + transform: translate3d(-3000px, 0, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(25px, 0, 0); + transform: translate3d(25px, 0, 0); + } + + 75% { + -webkit-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + } + + 90% { + -webkit-transform: translate3d(5px, 0, 0); + transform: translate3d(5px, 0, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.bounceInLeft { + -webkit-animation-name: bounceInLeft; + animation-name: bounceInLeft; +} + +@-webkit-keyframes bounceInRight { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + from { + opacity: 0; + -webkit-transform: translate3d(3000px, 0, 0); + transform: translate3d(3000px, 0, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(-25px, 0, 0); + transform: translate3d(-25px, 0, 0); + } + + 75% { + -webkit-transform: translate3d(10px, 0, 0); + transform: translate3d(10px, 0, 0); + } + + 90% { + -webkit-transform: translate3d(-5px, 0, 0); + transform: translate3d(-5px, 0, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes bounceInRight { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + from { + opacity: 0; + -webkit-transform: translate3d(3000px, 0, 0); + transform: translate3d(3000px, 0, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(-25px, 0, 0); + transform: translate3d(-25px, 0, 0); + } + + 75% { + -webkit-transform: translate3d(10px, 0, 0); + transform: translate3d(10px, 0, 0); + } + + 90% { + -webkit-transform: translate3d(-5px, 0, 0); + transform: translate3d(-5px, 0, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.bounceInRight { + -webkit-animation-name: bounceInRight; + animation-name: bounceInRight; +} + +@-webkit-keyframes bounceInUp { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + from { + opacity: 0; + -webkit-transform: translate3d(0, 3000px, 0); + transform: translate3d(0, 3000px, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + + 75% { + -webkit-transform: translate3d(0, 10px, 0); + transform: translate3d(0, 10px, 0); + } + + 90% { + -webkit-transform: translate3d(0, -5px, 0); + transform: translate3d(0, -5px, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes bounceInUp { + from, + 60%, + 75%, + 90%, + to { + -webkit-animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1); + } + + from { + opacity: 0; + -webkit-transform: translate3d(0, 3000px, 0); + transform: translate3d(0, 3000px, 0); + } + + 60% { + opacity: 1; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + + 75% { + -webkit-transform: translate3d(0, 10px, 0); + transform: translate3d(0, 10px, 0); + } + + 90% { + -webkit-transform: translate3d(0, -5px, 0); + transform: translate3d(0, -5px, 0); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.bounceInUp { + -webkit-animation-name: bounceInUp; + animation-name: bounceInUp; +} + +@-webkit-keyframes bounceOut { + 20% { + -webkit-transform: scale3d(0.9, 0.9, 0.9); + transform: scale3d(0.9, 0.9, 0.9); + } + + 50%, + 55% { + opacity: 1; + -webkit-transform: scale3d(1.1, 1.1, 1.1); + transform: scale3d(1.1, 1.1, 1.1); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } +} + +@keyframes bounceOut { + 20% { + -webkit-transform: scale3d(0.9, 0.9, 0.9); + transform: scale3d(0.9, 0.9, 0.9); + } + + 50%, + 55% { + opacity: 1; + -webkit-transform: scale3d(1.1, 1.1, 1.1); + transform: scale3d(1.1, 1.1, 1.1); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } +} + +.bounceOut { + -webkit-animation-duration: 0.75s; + animation-duration: 0.75s; + -webkit-animation-name: bounceOut; + animation-name: bounceOut; +} + +@-webkit-keyframes bounceOutDown { + 20% { + -webkit-transform: translate3d(0, 10px, 0); + transform: translate3d(0, 10px, 0); + } + + 40%, + 45% { + opacity: 1; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } +} + +@keyframes bounceOutDown { + 20% { + -webkit-transform: translate3d(0, 10px, 0); + transform: translate3d(0, 10px, 0); + } + + 40%, + 45% { + opacity: 1; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } +} + +.bounceOutDown { + -webkit-animation-name: bounceOutDown; + animation-name: bounceOutDown; +} + +@-webkit-keyframes bounceOutLeft { + 20% { + opacity: 1; + -webkit-transform: translate3d(20px, 0, 0); + transform: translate3d(20px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } +} + +@keyframes bounceOutLeft { + 20% { + opacity: 1; + -webkit-transform: translate3d(20px, 0, 0); + transform: translate3d(20px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } +} + +.bounceOutLeft { + -webkit-animation-name: bounceOutLeft; + animation-name: bounceOutLeft; +} + +@-webkit-keyframes bounceOutRight { + 20% { + opacity: 1; + -webkit-transform: translate3d(-20px, 0, 0); + transform: translate3d(-20px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } +} + +@keyframes bounceOutRight { + 20% { + opacity: 1; + -webkit-transform: translate3d(-20px, 0, 0); + transform: translate3d(-20px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } +} + +.bounceOutRight { + -webkit-animation-name: bounceOutRight; + animation-name: bounceOutRight; +} + +@-webkit-keyframes bounceOutUp { + 20% { + -webkit-transform: translate3d(0, -10px, 0); + transform: translate3d(0, -10px, 0); + } + + 40%, + 45% { + opacity: 1; + -webkit-transform: translate3d(0, 20px, 0); + transform: translate3d(0, 20px, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } +} + +@keyframes bounceOutUp { + 20% { + -webkit-transform: translate3d(0, -10px, 0); + transform: translate3d(0, -10px, 0); + } + + 40%, + 45% { + opacity: 1; + -webkit-transform: translate3d(0, 20px, 0); + transform: translate3d(0, 20px, 0); + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } +} + +.bounceOutUp { + -webkit-animation-name: bounceOutUp; + animation-name: bounceOutUp; +} + +@-webkit-keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +.fadeIn { + -webkit-animation-name: fadeIn; + animation-name: fadeIn; +} + +@-webkit-keyframes fadeInDown { + from { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInDown { + from { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInDown { + -webkit-animation-name: fadeInDown; + animation-name: fadeInDown; +} + +@-webkit-keyframes fadeInDownBig { + from { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInDownBig { + from { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInDownBig { + -webkit-animation-name: fadeInDownBig; + animation-name: fadeInDownBig; +} + +@-webkit-keyframes fadeInLeft { + from { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInLeft { + from { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInLeft { + -webkit-animation-name: fadeInLeft; + animation-name: fadeInLeft; +} + +@-webkit-keyframes fadeInLeftBig { + from { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInLeftBig { + from { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInLeftBig { + -webkit-animation-name: fadeInLeftBig; + animation-name: fadeInLeftBig; +} + +@-webkit-keyframes fadeInRight { + from { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInRight { + from { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInRight { + -webkit-animation-name: fadeInRight; + animation-name: fadeInRight; +} + +@-webkit-keyframes fadeInRightBig { + from { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInRightBig { + from { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInRightBig { + -webkit-animation-name: fadeInRightBig; + animation-name: fadeInRightBig; +} + +@-webkit-keyframes fadeInUp { + from { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInUp { + -webkit-animation-name: fadeInUp; + animation-name: fadeInUp; +} + +@-webkit-keyframes fadeInUpBig { + from { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fadeInUpBig { + from { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.fadeInUpBig { + -webkit-animation-name: fadeInUpBig; + animation-name: fadeInUpBig; +} + +@-webkit-keyframes fadeOut { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + +@keyframes fadeOut { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + +.fadeOut { + -webkit-animation-name: fadeOut; + animation-name: fadeOut; +} + +@-webkit-keyframes fadeOutDown { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +@keyframes fadeOutDown { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +.fadeOutDown { + -webkit-animation-name: fadeOutDown; + animation-name: fadeOutDown; +} + +@-webkit-keyframes fadeOutDownBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } +} + +@keyframes fadeOutDownBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, 2000px, 0); + transform: translate3d(0, 2000px, 0); + } +} + +.fadeOutDownBig { + -webkit-animation-name: fadeOutDownBig; + animation-name: fadeOutDownBig; +} + +@-webkit-keyframes fadeOutLeft { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes fadeOutLeft { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +.fadeOutLeft { + -webkit-animation-name: fadeOutLeft; + animation-name: fadeOutLeft; +} + +@-webkit-keyframes fadeOutLeftBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } +} + +@keyframes fadeOutLeftBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(-2000px, 0, 0); + transform: translate3d(-2000px, 0, 0); + } +} + +.fadeOutLeftBig { + -webkit-animation-name: fadeOutLeftBig; + animation-name: fadeOutLeftBig; +} + +@-webkit-keyframes fadeOutRight { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +@keyframes fadeOutRight { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +.fadeOutRight { + -webkit-animation-name: fadeOutRight; + animation-name: fadeOutRight; +} + +@-webkit-keyframes fadeOutRightBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } +} + +@keyframes fadeOutRightBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(2000px, 0, 0); + transform: translate3d(2000px, 0, 0); + } +} + +.fadeOutRightBig { + -webkit-animation-name: fadeOutRightBig; + animation-name: fadeOutRightBig; +} + +@-webkit-keyframes fadeOutUp { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +@keyframes fadeOutUp { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +.fadeOutUp { + -webkit-animation-name: fadeOutUp; + animation-name: fadeOutUp; +} + +@-webkit-keyframes fadeOutUpBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } +} + +@keyframes fadeOutUpBig { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(0, -2000px, 0); + transform: translate3d(0, -2000px, 0); + } +} + +.fadeOutUpBig { + -webkit-animation-name: fadeOutUpBig; + animation-name: fadeOutUpBig; +} + +@-webkit-keyframes flip { + from { + -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) + rotate3d(0, 1, 0, -360deg); + transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 40% { + -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) + rotate3d(0, 1, 0, -190deg); + transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) + rotate3d(0, 1, 0, -190deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 50% { + -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) + rotate3d(0, 1, 0, -170deg); + transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) + rotate3d(0, 1, 0, -170deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 80% { + -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) + rotate3d(0, 1, 0, 0deg); + transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) + rotate3d(0, 1, 0, 0deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + to { + -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) + rotate3d(0, 1, 0, 0deg); + transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } +} + +@keyframes flip { + from { + -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) + rotate3d(0, 1, 0, -360deg); + transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, -360deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 40% { + -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) + rotate3d(0, 1, 0, -190deg); + transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) + rotate3d(0, 1, 0, -190deg); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } + + 50% { + -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) + rotate3d(0, 1, 0, -170deg); + transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 150px) + rotate3d(0, 1, 0, -170deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 80% { + -webkit-transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) + rotate3d(0, 1, 0, 0deg); + transform: perspective(400px) scale3d(0.95, 0.95, 0.95) translate3d(0, 0, 0) + rotate3d(0, 1, 0, 0deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + to { + -webkit-transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) + rotate3d(0, 1, 0, 0deg); + transform: perspective(400px) scale3d(1, 1, 1) translate3d(0, 0, 0) rotate3d(0, 1, 0, 0deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } +} + +.animated.flip { + -webkit-backface-visibility: visible; + backface-visibility: visible; + -webkit-animation-name: flip; + animation-name: flip; +} + +@-webkit-keyframes flipInX { + from { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 60% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); + transform: perspective(400px) rotate3d(1, 0, 0, 10deg); + opacity: 1; + } + + 80% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); + transform: perspective(400px) rotate3d(1, 0, 0, -5deg); + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } +} + +@keyframes flipInX { + from { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 60% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg); + transform: perspective(400px) rotate3d(1, 0, 0, 10deg); + opacity: 1; + } + + 80% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg); + transform: perspective(400px) rotate3d(1, 0, 0, -5deg); + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } +} + +.flipInX { + -webkit-backface-visibility: visible !important; + backface-visibility: visible !important; + -webkit-animation-name: flipInX; + animation-name: flipInX; +} + +@-webkit-keyframes flipInY { + from { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); + transform: perspective(400px) rotate3d(0, 1, 0, -20deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 60% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); + transform: perspective(400px) rotate3d(0, 1, 0, 10deg); + opacity: 1; + } + + 80% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); + transform: perspective(400px) rotate3d(0, 1, 0, -5deg); + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } +} + +@keyframes flipInY { + from { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + opacity: 0; + } + + 40% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg); + transform: perspective(400px) rotate3d(0, 1, 0, -20deg); + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; + } + + 60% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg); + transform: perspective(400px) rotate3d(0, 1, 0, 10deg); + opacity: 1; + } + + 80% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg); + transform: perspective(400px) rotate3d(0, 1, 0, -5deg); + } + + to { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } +} + +.flipInY { + -webkit-backface-visibility: visible !important; + backface-visibility: visible !important; + -webkit-animation-name: flipInY; + animation-name: flipInY; +} + +@-webkit-keyframes flipOutX { + from { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } + + 30% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + opacity: 1; + } + + to { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + opacity: 0; + } +} + +@keyframes flipOutX { + from { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } + + 30% { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + transform: perspective(400px) rotate3d(1, 0, 0, -20deg); + opacity: 1; + } + + to { + -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + transform: perspective(400px) rotate3d(1, 0, 0, 90deg); + opacity: 0; + } +} + +.flipOutX { + -webkit-animation-duration: 0.75s; + animation-duration: 0.75s; + -webkit-animation-name: flipOutX; + animation-name: flipOutX; + -webkit-backface-visibility: visible !important; + backface-visibility: visible !important; +} + +@-webkit-keyframes flipOutY { + from { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } + + 30% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); + transform: perspective(400px) rotate3d(0, 1, 0, -15deg); + opacity: 1; + } + + to { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + opacity: 0; + } +} + +@keyframes flipOutY { + from { + -webkit-transform: perspective(400px); + transform: perspective(400px); + } + + 30% { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg); + transform: perspective(400px) rotate3d(0, 1, 0, -15deg); + opacity: 1; + } + + to { + -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + transform: perspective(400px) rotate3d(0, 1, 0, 90deg); + opacity: 0; + } +} + +.flipOutY { + -webkit-animation-duration: 0.75s; + animation-duration: 0.75s; + -webkit-backface-visibility: visible !important; + backface-visibility: visible !important; + -webkit-animation-name: flipOutY; + animation-name: flipOutY; +} + +@-webkit-keyframes lightSpeedIn { + from { + -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); + transform: translate3d(100%, 0, 0) skewX(-30deg); + opacity: 0; + } + + 60% { + -webkit-transform: skewX(20deg); + transform: skewX(20deg); + opacity: 1; + } + + 80% { + -webkit-transform: skewX(-5deg); + transform: skewX(-5deg); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes lightSpeedIn { + from { + -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg); + transform: translate3d(100%, 0, 0) skewX(-30deg); + opacity: 0; + } + + 60% { + -webkit-transform: skewX(20deg); + transform: skewX(20deg); + opacity: 1; + } + + 80% { + -webkit-transform: skewX(-5deg); + transform: skewX(-5deg); + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.lightSpeedIn { + -webkit-animation-name: lightSpeedIn; + animation-name: lightSpeedIn; + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; +} + +@-webkit-keyframes lightSpeedOut { + from { + opacity: 1; + } + + to { + -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); + transform: translate3d(100%, 0, 0) skewX(30deg); + opacity: 0; + } +} + +@keyframes lightSpeedOut { + from { + opacity: 1; + } + + to { + -webkit-transform: translate3d(100%, 0, 0) skewX(30deg); + transform: translate3d(100%, 0, 0) skewX(30deg); + opacity: 0; + } +} + +.lightSpeedOut { + -webkit-animation-name: lightSpeedOut; + animation-name: lightSpeedOut; + -webkit-animation-timing-function: ease-in; + animation-timing-function: ease-in; +} + +@-webkit-keyframes rotateIn { + from { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: rotate3d(0, 0, 1, -200deg); + transform: rotate3d(0, 0, 1, -200deg); + opacity: 0; + } + + to { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateIn { + from { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: rotate3d(0, 0, 1, -200deg); + transform: rotate3d(0, 0, 1, -200deg); + opacity: 0; + } + + to { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateIn { + -webkit-animation-name: rotateIn; + animation-name: rotateIn; +} + +@-webkit-keyframes rotateInDownLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateInDownLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateInDownLeft { + -webkit-animation-name: rotateInDownLeft; + animation-name: rotateInDownLeft; +} + +@-webkit-keyframes rotateInDownRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateInDownRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateInDownRight { + -webkit-animation-name: rotateInDownRight; + animation-name: rotateInDownRight; +} + +@-webkit-keyframes rotateInUpLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateInUpLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateInUpLeft { + -webkit-animation-name: rotateInUpLeft; + animation-name: rotateInUpLeft; +} + +@-webkit-keyframes rotateInUpRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, -90deg); + transform: rotate3d(0, 0, 1, -90deg); + opacity: 0; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +@keyframes rotateInUpRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, -90deg); + transform: rotate3d(0, 0, 1, -90deg); + opacity: 0; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + opacity: 1; + } +} + +.rotateInUpRight { + -webkit-animation-name: rotateInUpRight; + animation-name: rotateInUpRight; +} + +@-webkit-keyframes rotateOut { + from { + -webkit-transform-origin: center; + transform-origin: center; + opacity: 1; + } + + to { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: rotate3d(0, 0, 1, 200deg); + transform: rotate3d(0, 0, 1, 200deg); + opacity: 0; + } +} + +@keyframes rotateOut { + from { + -webkit-transform-origin: center; + transform-origin: center; + opacity: 1; + } + + to { + -webkit-transform-origin: center; + transform-origin: center; + -webkit-transform: rotate3d(0, 0, 1, 200deg); + transform: rotate3d(0, 0, 1, 200deg); + opacity: 0; + } +} + +.rotateOut { + -webkit-animation-name: rotateOut; + animation-name: rotateOut; +} + +@-webkit-keyframes rotateOutDownLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } +} + +@keyframes rotateOutDownLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, 45deg); + transform: rotate3d(0, 0, 1, 45deg); + opacity: 0; + } +} + +.rotateOutDownLeft { + -webkit-animation-name: rotateOutDownLeft; + animation-name: rotateOutDownLeft; +} + +@-webkit-keyframes rotateOutDownRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } +} + +@keyframes rotateOutDownRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } +} + +.rotateOutDownRight { + -webkit-animation-name: rotateOutDownRight; + animation-name: rotateOutDownRight; +} + +@-webkit-keyframes rotateOutUpLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } +} + +@keyframes rotateOutUpLeft { + from { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: left bottom; + transform-origin: left bottom; + -webkit-transform: rotate3d(0, 0, 1, -45deg); + transform: rotate3d(0, 0, 1, -45deg); + opacity: 0; + } +} + +.rotateOutUpLeft { + -webkit-animation-name: rotateOutUpLeft; + animation-name: rotateOutUpLeft; +} + +@-webkit-keyframes rotateOutUpRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, 90deg); + transform: rotate3d(0, 0, 1, 90deg); + opacity: 0; + } +} + +@keyframes rotateOutUpRight { + from { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + opacity: 1; + } + + to { + -webkit-transform-origin: right bottom; + transform-origin: right bottom; + -webkit-transform: rotate3d(0, 0, 1, 90deg); + transform: rotate3d(0, 0, 1, 90deg); + opacity: 0; + } +} + +.rotateOutUpRight { + -webkit-animation-name: rotateOutUpRight; + animation-name: rotateOutUpRight; +} + +@-webkit-keyframes hinge { + 0% { + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 20%, + 60% { + -webkit-transform: rotate3d(0, 0, 1, 80deg); + transform: rotate3d(0, 0, 1, 80deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 40%, + 80% { + -webkit-transform: rotate3d(0, 0, 1, 60deg); + transform: rotate3d(0, 0, 1, 60deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + opacity: 1; + } + + to { + -webkit-transform: translate3d(0, 700px, 0); + transform: translate3d(0, 700px, 0); + opacity: 0; + } +} + +@keyframes hinge { + 0% { + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 20%, + 60% { + -webkit-transform: rotate3d(0, 0, 1, 80deg); + transform: rotate3d(0, 0, 1, 80deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + + 40%, + 80% { + -webkit-transform: rotate3d(0, 0, 1, 60deg); + transform: rotate3d(0, 0, 1, 60deg); + -webkit-transform-origin: top left; + transform-origin: top left; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + opacity: 1; + } + + to { + -webkit-transform: translate3d(0, 700px, 0); + transform: translate3d(0, 700px, 0); + opacity: 0; + } +} + +.hinge { + -webkit-animation-duration: 2s; + animation-duration: 2s; + -webkit-animation-name: hinge; + animation-name: hinge; +} + +@-webkit-keyframes jackInTheBox { + from { + opacity: 0; + -webkit-transform: scale(0.1) rotate(30deg); + transform: scale(0.1) rotate(30deg); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + } + + 50% { + -webkit-transform: rotate(-10deg); + transform: rotate(-10deg); + } + + 70% { + -webkit-transform: rotate(3deg); + transform: rotate(3deg); + } + + to { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +@keyframes jackInTheBox { + from { + opacity: 0; + -webkit-transform: scale(0.1) rotate(30deg); + transform: scale(0.1) rotate(30deg); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + } + + 50% { + -webkit-transform: rotate(-10deg); + transform: rotate(-10deg); + } + + 70% { + -webkit-transform: rotate(3deg); + transform: rotate(3deg); + } + + to { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} + +.jackInTheBox { + -webkit-animation-name: jackInTheBox; + animation-name: jackInTheBox; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes rollIn { + from { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); + transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes rollIn { + from { + opacity: 0; + -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); + transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg); + } + + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.rollIn { + -webkit-animation-name: rollIn; + animation-name: rollIn; +} + +/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */ + +@-webkit-keyframes rollOut { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); + transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); + } +} + +@keyframes rollOut { + from { + opacity: 1; + } + + to { + opacity: 0; + -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); + transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg); + } +} + +.rollOut { + -webkit-animation-name: rollOut; + animation-name: rollOut; +} + +@-webkit-keyframes zoomIn { + from { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + 50% { + opacity: 1; + } +} + +@keyframes zoomIn { + from { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + 50% { + opacity: 1; + } +} + +.zoomIn { + -webkit-animation-name: zoomIn; + animation-name: zoomIn; +} + +@-webkit-keyframes zoomInDown { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomInDown { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -1000px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomInDown { + -webkit-animation-name: zoomInDown; + animation-name: zoomInDown; +} + +@-webkit-keyframes zoomInLeft { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomInLeft { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(-1000px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(10px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomInLeft { + -webkit-animation-name: zoomInLeft; + animation-name: zoomInLeft; +} + +@-webkit-keyframes zoomInRight { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomInRight { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(1000px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(-10px, 0, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomInRight { + -webkit-animation-name: zoomInRight; + animation-name: zoomInRight; +} + +@-webkit-keyframes zoomInUp { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomInUp { + from { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 1000px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + 60% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomInUp { + -webkit-animation-name: zoomInUp; + animation-name: zoomInUp; +} + +@-webkit-keyframes zoomOut { + from { + opacity: 1; + } + + 50% { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + to { + opacity: 0; + } +} + +@keyframes zoomOut { + from { + opacity: 1; + } + + 50% { + opacity: 0; + -webkit-transform: scale3d(0.3, 0.3, 0.3); + transform: scale3d(0.3, 0.3, 0.3); + } + + to { + opacity: 0; + } +} + +.zoomOut { + -webkit-animation-name: zoomOut; + animation-name: zoomOut; +} + +@-webkit-keyframes zoomOutDown { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomOutDown { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, -60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, 2000px, 0); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomOutDown { + -webkit-animation-name: zoomOutDown; + animation-name: zoomOutDown; +} + +@-webkit-keyframes zoomOutLeft { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0); + transform: scale(0.1) translate3d(-2000px, 0, 0); + -webkit-transform-origin: left center; + transform-origin: left center; + } +} + +@keyframes zoomOutLeft { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(42px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: scale(0.1) translate3d(-2000px, 0, 0); + transform: scale(0.1) translate3d(-2000px, 0, 0); + -webkit-transform-origin: left center; + transform-origin: left center; + } +} + +.zoomOutLeft { + -webkit-animation-name: zoomOutLeft; + animation-name: zoomOutLeft; +} + +@-webkit-keyframes zoomOutRight { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: scale(0.1) translate3d(2000px, 0, 0); + transform: scale(0.1) translate3d(2000px, 0, 0); + -webkit-transform-origin: right center; + transform-origin: right center; + } +} + +@keyframes zoomOutRight { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(-42px, 0, 0); + } + + to { + opacity: 0; + -webkit-transform: scale(0.1) translate3d(2000px, 0, 0); + transform: scale(0.1) translate3d(2000px, 0, 0); + -webkit-transform-origin: right center; + transform-origin: right center; + } +} + +.zoomOutRight { + -webkit-animation-name: zoomOutRight; + animation-name: zoomOutRight; +} + +@-webkit-keyframes zoomOutUp { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +@keyframes zoomOutUp { + 40% { + opacity: 1; + -webkit-transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + transform: scale3d(0.475, 0.475, 0.475) translate3d(0, 60px, 0); + -webkit-animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + animation-timing-function: cubic-bezier(0.55, 0.055, 0.675, 0.19); + } + + to { + opacity: 0; + -webkit-transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); + transform: scale3d(0.1, 0.1, 0.1) translate3d(0, -2000px, 0); + -webkit-transform-origin: center bottom; + transform-origin: center bottom; + -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + animation-timing-function: cubic-bezier(0.175, 0.885, 0.32, 1); + } +} + +.zoomOutUp { + -webkit-animation-name: zoomOutUp; + animation-name: zoomOutUp; +} + +@-webkit-keyframes slideInDown { + from { + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes slideInDown { + from { + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.slideInDown { + -webkit-animation-name: slideInDown; + animation-name: slideInDown; +} + +@-webkit-keyframes slideInLeft { + from { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes slideInLeft { + from { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.slideInLeft { + -webkit-animation-name: slideInLeft; + animation-name: slideInLeft; +} + +@-webkit-keyframes slideInRight { + from { + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes slideInRight { + from { + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.slideInRight { + -webkit-animation-name: slideInRight; + animation-name: slideInRight; +} + +@-webkit-keyframes slideInUp { + from { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes slideInUp { + from { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + visibility: visible; + } + + to { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.slideInUp { + -webkit-animation-name: slideInUp; + animation-name: slideInUp; +} + +@-webkit-keyframes slideOutDown { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +@keyframes slideOutDown { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); + } +} + +.slideOutDown { + -webkit-animation-name: slideOutDown; + animation-name: slideOutDown; +} + +@-webkit-keyframes slideOutLeft { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes slideOutLeft { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +.slideOutLeft { + -webkit-animation-name: slideOutLeft; + animation-name: slideOutLeft; +} + +@-webkit-keyframes slideOutRight { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +@keyframes slideOutRight { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + } +} + +.slideOutRight { + -webkit-animation-name: slideOutRight; + animation-name: slideOutRight; +} + +@-webkit-keyframes slideOutUp { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +@keyframes slideOutUp { + from { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + + to { + visibility: hidden; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + } +} + +.slideOutUp { + -webkit-animation-name: slideOutUp; + animation-name: slideOutUp; +} + +.animated { + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} + +.animated.infinite { + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; +} + +.animated.delay-1s { + -webkit-animation-delay: 1s; + animation-delay: 1s; +} + +.animated.delay-2s { + -webkit-animation-delay: 2s; + animation-delay: 2s; +} + +.animated.delay-3s { + -webkit-animation-delay: 3s; + animation-delay: 3s; +} + +.animated.delay-4s { + -webkit-animation-delay: 4s; + animation-delay: 4s; +} + +.animated.delay-5s { + -webkit-animation-delay: 5s; + animation-delay: 5s; +} + +.animated.fast { + -webkit-animation-duration: 800ms; + animation-duration: 800ms; +} + +.animated.faster { + -webkit-animation-duration: 500ms; + animation-duration: 500ms; +} + +.animated.slow { + -webkit-animation-duration: 2s; + animation-duration: 2s; +} + +.animated.slower { + -webkit-animation-duration: 3s; + animation-duration: 3s; +} + +@media (print), (prefers-reduced-motion: reduce) { + .animated { + -webkit-animation-duration: 1ms !important; + animation-duration: 1ms !important; + -webkit-transition-duration: 1ms !important; + transition-duration: 1ms !important; + -webkit-animation-iteration-count: 1 !important; + animation-iteration-count: 1 !important; + } +} \ No newline at end of file diff --git a/front/src/components/active-plate/active-plate.vue b/front/src/components/active-plate/active-plate.vue new file mode 100644 index 00000000..237e2e05 --- /dev/null +++ b/front/src/components/active-plate/active-plate.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/front/src/components/charts/bar.vue b/front/src/components/charts/bar.vue new file mode 100644 index 00000000..49dcd500 --- /dev/null +++ b/front/src/components/charts/bar.vue @@ -0,0 +1,73 @@ + + + diff --git a/front/src/components/charts/index.js b/front/src/components/charts/index.js new file mode 100644 index 00000000..cd86f348 --- /dev/null +++ b/front/src/components/charts/index.js @@ -0,0 +1,3 @@ +import ChartPie from './pie.vue'; +import ChartBar from './bar.vue'; +export { ChartPie, ChartBar }; diff --git a/front/src/components/charts/pie.vue b/front/src/components/charts/pie.vue new file mode 100644 index 00000000..4c4ffc7d --- /dev/null +++ b/front/src/components/charts/pie.vue @@ -0,0 +1,85 @@ + + + diff --git a/front/src/components/charts/theme.json b/front/src/components/charts/theme.json new file mode 100644 index 00000000..909b518a --- /dev/null +++ b/front/src/components/charts/theme.json @@ -0,0 +1,490 @@ +{ + "color": [ + "#2d8cf0", + "#19be6b", + "#ff9900", + "#E46CBB", + "#9A66E4", + "#ed3f14" + ], + "backgroundColor": "rgba(0,0,0,0)", + "textStyle": {}, + "title": { + "textStyle": { + "color": "#516b91" + }, + "subtextStyle": { + "color": "#93b7e3" + } + }, + "line": { + "itemStyle": { + "normal": { + "borderWidth": "2" + } + }, + "lineStyle": { + "normal": { + "width": "2" + } + }, + "symbolSize": "6", + "symbol": "emptyCircle", + "smooth": true + }, + "radar": { + "itemStyle": { + "normal": { + "borderWidth": "2" + } + }, + "lineStyle": { + "normal": { + "width": "2" + } + }, + "symbolSize": "6", + "symbol": "emptyCircle", + "smooth": true + }, + "bar": { + "itemStyle": { + "normal": { + "barBorderWidth": 0, + "barBorderColor": "#ccc" + }, + "emphasis": { + "barBorderWidth": 0, + "barBorderColor": "#ccc" + } + } + }, + "pie": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "scatter": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "boxplot": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "parallel": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "sankey": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "funnel": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "gauge": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "candlestick": { + "itemStyle": { + "normal": { + "color": "#edafda", + "color0": "transparent", + "borderColor": "#d680bc", + "borderColor0": "#8fd3e8", + "borderWidth": "2" + } + } + }, + "graph": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + } + }, + "lineStyle": { + "normal": { + "width": 1, + "color": "#aaa" + } + }, + "symbolSize": "6", + "symbol": "emptyCircle", + "smooth": true, + "color": [ + "#2d8cf0", + "#19be6b", + "#f5ae4a", + "#9189d5", + "#56cae2", + "#cbb0e3" + ], + "label": { + "normal": { + "textStyle": { + "color": "#eee" + } + } + } + }, + "map": { + "itemStyle": { + "normal": { + "areaColor": "#f3f3f3", + "borderColor": "#516b91", + "borderWidth": 0.5 + }, + "emphasis": { + "areaColor": "rgba(165,231,240,1)", + "borderColor": "#516b91", + "borderWidth": 1 + } + }, + "label": { + "normal": { + "textStyle": { + "color": "#000" + } + }, + "emphasis": { + "textStyle": { + "color": "rgb(81,107,145)" + } + } + } + }, + "geo": { + "itemStyle": { + "normal": { + "areaColor": "#f3f3f3", + "borderColor": "#516b91", + "borderWidth": 0.5 + }, + "emphasis": { + "areaColor": "rgba(165,231,240,1)", + "borderColor": "#516b91", + "borderWidth": 1 + } + }, + "label": { + "normal": { + "textStyle": { + "color": "#000" + } + }, + "emphasis": { + "textStyle": { + "color": "rgb(81,107,145)" + } + } + } + }, + "categoryAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "valueAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "logAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "timeAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "toolbox": { + "iconStyle": { + "normal": { + "borderColor": "#999" + }, + "emphasis": { + "borderColor": "#666" + } + } + }, + "legend": { + "textStyle": { + "color": "#999999" + } + }, + "tooltip": { + "axisPointer": { + "lineStyle": { + "color": "#ccc", + "width": 1 + }, + "crossStyle": { + "color": "#ccc", + "width": 1 + } + } + }, + "timeline": { + "lineStyle": { + "color": "#8fd3e8", + "width": 1 + }, + "itemStyle": { + "normal": { + "color": "#8fd3e8", + "borderWidth": 1 + }, + "emphasis": { + "color": "#8fd3e8" + } + }, + "controlStyle": { + "normal": { + "color": "#8fd3e8", + "borderColor": "#8fd3e8", + "borderWidth": 0.5 + }, + "emphasis": { + "color": "#8fd3e8", + "borderColor": "#8fd3e8", + "borderWidth": 0.5 + } + }, + "checkpointStyle": { + "color": "#8fd3e8", + "borderColor": "rgba(138,124,168,0.37)" + }, + "label": { + "normal": { + "textStyle": { + "color": "#8fd3e8" + } + }, + "emphasis": { + "textStyle": { + "color": "#8fd3e8" + } + } + } + }, + "visualMap": { + "color": [ + "#516b91", + "#59c4e6", + "#a5e7f0" + ] + }, + "dataZoom": { + "backgroundColor": "rgba(0,0,0,0)", + "dataBackgroundColor": "rgba(255,255,255,0.3)", + "fillerColor": "rgba(167,183,204,0.4)", + "handleColor": "#a7b7cc", + "handleSize": "100%", + "textStyle": { + "color": "#333" + } + }, + "markPoint": { + "label": { + "normal": { + "textStyle": { + "color": "#eee" + } + }, + "emphasis": { + "textStyle": { + "color": "#eee" + } + } + } + } +} \ No newline at end of file diff --git a/front/src/components/common-icon/common-icon.vue b/front/src/components/common-icon/common-icon.vue new file mode 100644 index 00000000..03cbc0e8 --- /dev/null +++ b/front/src/components/common-icon/common-icon.vue @@ -0,0 +1,52 @@ + + + + + diff --git a/front/src/components/common-icon/index.js b/front/src/components/common-icon/index.js new file mode 100644 index 00000000..ca1bd334 --- /dev/null +++ b/front/src/components/common-icon/index.js @@ -0,0 +1,2 @@ +import CommonIcon from './common-icon.vue'; +export default CommonIcon; diff --git a/front/src/components/count-to/count-to.vue b/front/src/components/count-to/count-to.vue new file mode 100644 index 00000000..4c8f274e --- /dev/null +++ b/front/src/components/count-to/count-to.vue @@ -0,0 +1,198 @@ + + + diff --git a/front/src/components/count-to/index.js b/front/src/components/count-to/index.js new file mode 100644 index 00000000..52c7fb88 --- /dev/null +++ b/front/src/components/count-to/index.js @@ -0,0 +1,2 @@ +import countTo from './count-to.vue'; +export default countTo; diff --git a/front/src/components/count-to/index.less b/front/src/components/count-to/index.less new file mode 100644 index 00000000..e17d7c60 --- /dev/null +++ b/front/src/components/count-to/index.less @@ -0,0 +1,10 @@ +@prefix: ~"count-to"; + +.@{prefix}-wrapper{ + .content-outer{ + display: inline-block; + .@{prefix}-unit-text{ + font-style: normal; + } + } +} diff --git a/front/src/components/editor/editor.vue b/front/src/components/editor/editor.vue new file mode 100644 index 00000000..da3123dc --- /dev/null +++ b/front/src/components/editor/editor.vue @@ -0,0 +1,77 @@ + + + + + diff --git a/front/src/components/editor/index.js b/front/src/components/editor/index.js new file mode 100644 index 00000000..58c0cd58 --- /dev/null +++ b/front/src/components/editor/index.js @@ -0,0 +1,2 @@ +import Editor from './editor.vue'; +export default Editor; diff --git a/front/src/components/icons/icons.vue b/front/src/components/icons/icons.vue new file mode 100644 index 00000000..08112f96 --- /dev/null +++ b/front/src/components/icons/icons.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/front/src/components/icons/index.js b/front/src/components/icons/index.js new file mode 100644 index 00000000..9bce89b3 --- /dev/null +++ b/front/src/components/icons/index.js @@ -0,0 +1,2 @@ +import Icons from './icons.vue'; +export default Icons; diff --git a/front/src/components/main/components/a-back-top/index.js b/front/src/components/main/components/a-back-top/index.js new file mode 100644 index 00000000..7c87382d --- /dev/null +++ b/front/src/components/main/components/a-back-top/index.js @@ -0,0 +1,2 @@ +import ABackTop from './index.vue'; +export default ABackTop; diff --git a/front/src/components/main/components/a-back-top/index.vue b/front/src/components/main/components/a-back-top/index.vue new file mode 100644 index 00000000..e13c5621 --- /dev/null +++ b/front/src/components/main/components/a-back-top/index.vue @@ -0,0 +1,130 @@ + + diff --git a/front/src/components/main/components/fullscreen/fullscreen.vue b/front/src/components/main/components/fullscreen/fullscreen.vue new file mode 100644 index 00000000..b5fb231c --- /dev/null +++ b/front/src/components/main/components/fullscreen/fullscreen.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/front/src/components/main/components/fullscreen/index.js b/front/src/components/main/components/fullscreen/index.js new file mode 100644 index 00000000..45c287e9 --- /dev/null +++ b/front/src/components/main/components/fullscreen/index.js @@ -0,0 +1,2 @@ +import Fullscreen from './fullscreen.vue'; +export default Fullscreen; diff --git a/front/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less b/front/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less new file mode 100644 index 00000000..1ace1eb8 --- /dev/null +++ b/front/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.less @@ -0,0 +1,4 @@ +.custom-bread-crumb{ + display: inline-block; + vertical-align: top; +} diff --git a/front/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue b/front/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue new file mode 100644 index 00000000..63bd2281 --- /dev/null +++ b/front/src/components/main/components/header-bar/custom-bread-crumb/custom-bread-crumb.vue @@ -0,0 +1,44 @@ + + diff --git a/front/src/components/main/components/header-bar/custom-bread-crumb/index.js b/front/src/components/main/components/header-bar/custom-bread-crumb/index.js new file mode 100644 index 00000000..a360517d --- /dev/null +++ b/front/src/components/main/components/header-bar/custom-bread-crumb/index.js @@ -0,0 +1,2 @@ +import customBreadCrumb from './custom-bread-crumb.vue'; +export default customBreadCrumb; diff --git a/front/src/components/main/components/header-bar/header-bar.less b/front/src/components/main/components/header-bar/header-bar.less new file mode 100644 index 00000000..17077577 --- /dev/null +++ b/front/src/components/main/components/header-bar/header-bar.less @@ -0,0 +1,14 @@ +.header-bar{ + width: 100%; + height: 100%; + position: relative; + .custom-content-con{ + float: right; + height: auto; + padding-right: 20px; + // line-height: 64px; + & > *{ + float: right; + } + } +} diff --git a/front/src/components/main/components/header-bar/header-bar.vue b/front/src/components/main/components/header-bar/header-bar.vue new file mode 100644 index 00000000..1b9d41f5 --- /dev/null +++ b/front/src/components/main/components/header-bar/header-bar.vue @@ -0,0 +1,39 @@ + + diff --git a/front/src/components/main/components/header-bar/index.js b/front/src/components/main/components/header-bar/index.js new file mode 100644 index 00000000..7559bb43 --- /dev/null +++ b/front/src/components/main/components/header-bar/index.js @@ -0,0 +1,2 @@ +import HeaderBar from './header-bar'; +export default HeaderBar; diff --git a/front/src/components/main/components/header-bar/sider-trigger/index.js b/front/src/components/main/components/header-bar/sider-trigger/index.js new file mode 100644 index 00000000..e474a26d --- /dev/null +++ b/front/src/components/main/components/header-bar/sider-trigger/index.js @@ -0,0 +1,2 @@ +import siderTrigger from './sider-trigger.vue'; +export default siderTrigger; diff --git a/front/src/components/main/components/header-bar/sider-trigger/sider-trigger.less b/front/src/components/main/components/header-bar/sider-trigger/sider-trigger.less new file mode 100644 index 00000000..bb852980 --- /dev/null +++ b/front/src/components/main/components/header-bar/sider-trigger/sider-trigger.less @@ -0,0 +1,21 @@ +.trans{ + transition: transform .2s ease; +} +@size: 40px; +.sider-trigger-a{ + padding: 6px; + width: @size; + height: @size; + display: inline-block; + text-align: center; + color: #5c6b77; + margin-top: 10px; + i{ + .trans; + vertical-align: top; + } + &.collapsed i{ + transform: rotateZ(180deg); + .trans; + } +} diff --git a/front/src/components/main/components/header-bar/sider-trigger/sider-trigger.vue b/front/src/components/main/components/header-bar/sider-trigger/sider-trigger.vue new file mode 100644 index 00000000..71971884 --- /dev/null +++ b/front/src/components/main/components/header-bar/sider-trigger/sider-trigger.vue @@ -0,0 +1,35 @@ + + + diff --git a/front/src/components/main/components/language/index.js b/front/src/components/main/components/language/index.js new file mode 100644 index 00000000..74d5e61b --- /dev/null +++ b/front/src/components/main/components/language/index.js @@ -0,0 +1,2 @@ +import Language from './language.vue'; +export default Language; diff --git a/front/src/components/main/components/language/language.vue b/front/src/components/main/components/language/language.vue new file mode 100644 index 00000000..29a8cbb0 --- /dev/null +++ b/front/src/components/main/components/language/language.vue @@ -0,0 +1,54 @@ + + + diff --git a/front/src/components/main/components/notice/notice.vue b/front/src/components/main/components/notice/notice.vue new file mode 100644 index 00000000..337d09ae --- /dev/null +++ b/front/src/components/main/components/notice/notice.vue @@ -0,0 +1,371 @@ + + + + + diff --git a/front/src/components/main/components/side-menu/collapsed-menu.vue b/front/src/components/main/components/side-menu/collapsed-menu.vue new file mode 100644 index 00000000..6011e12b --- /dev/null +++ b/front/src/components/main/components/side-menu/collapsed-menu.vue @@ -0,0 +1,84 @@ + + diff --git a/front/src/components/main/components/side-menu/index.js b/front/src/components/main/components/side-menu/index.js new file mode 100644 index 00000000..4a51d599 --- /dev/null +++ b/front/src/components/main/components/side-menu/index.js @@ -0,0 +1,2 @@ +import SideMenu from './side-menu.vue'; +export default SideMenu; diff --git a/front/src/components/main/components/side-menu/item-mixin.js b/front/src/components/main/components/side-menu/item-mixin.js new file mode 100644 index 00000000..921342fe --- /dev/null +++ b/front/src/components/main/components/side-menu/item-mixin.js @@ -0,0 +1,30 @@ +export default { + props: { + // 父文件 + parentItem: { + type: Object, + default: () => { } + }, + // 主题 + theme: { + type: String, + require: false + }, + // 图标尺寸 + iconSize: { + type: Number, + require: false + } + }, + computed: { + parentName () { + return this.parentItem.name; + }, + children () { + return this.parentItem.children; + }, + textColor () { + return this.theme === 'dark' ? '#fff' : '#495060'; + } + } +}; diff --git a/front/src/components/main/components/side-menu/mixin.js b/front/src/components/main/components/side-menu/mixin.js new file mode 100644 index 00000000..5650c5ee --- /dev/null +++ b/front/src/components/main/components/side-menu/mixin.js @@ -0,0 +1,18 @@ +import CommonIcon from '_c/common-icon'; +import { showTitle } from '@/lib/menu-func'; +export default { + components: { + CommonIcon + }, + methods: { + showTitle (item) { + return showTitle(item, this); + }, + showChildren (item) { + return item.children && (item.children.length > 1 || (item.meta && item.meta.showAlways)); + }, + getNameOrHref (item, children0) { + return item.href ? `isTurnByHref_${item.href}` : (children0 ? item.children[0].name : item.name); + } + } +}; diff --git a/front/src/components/main/components/side-menu/side-menu-item.vue b/front/src/components/main/components/side-menu/side-menu-item.vue new file mode 100644 index 00000000..d236b7a5 --- /dev/null +++ b/front/src/components/main/components/side-menu/side-menu-item.vue @@ -0,0 +1,35 @@ + + diff --git a/front/src/components/main/components/side-menu/side-menu.less b/front/src/components/main/components/side-menu/side-menu.less new file mode 100644 index 00000000..e50fae79 --- /dev/null +++ b/front/src/components/main/components/side-menu/side-menu.less @@ -0,0 +1,39 @@ +.side-menu-wrapper{ + user-select: none; + .menu-collapsed{ + padding-top: 10px; + + .ivu-dropdown{ + .ivu-dropdown-rel a{ + width: 100%; + } + } + .ivu-tooltip{ + width: 100%; + .ivu-tooltip-rel{ + width: 100%; + } + .ivu-tooltip-popper .ivu-tooltip-content{ + .ivu-tooltip-arrow{ + border-right-color: #fff; + } + .ivu-tooltip-inner{ + background: #fff; + color: #495060; + } + } + } + + + } + a.drop-menu-a{ + display: inline-block; + padding: 6px 15px; + width: 100%; + text-align: center; + color: #495060; + } +} +.menu-title{ + padding-left: 6px; +} diff --git a/front/src/components/main/components/side-menu/side-menu.vue b/front/src/components/main/components/side-menu/side-menu.vue new file mode 100644 index 00000000..6bae34c6 --- /dev/null +++ b/front/src/components/main/components/side-menu/side-menu.vue @@ -0,0 +1,187 @@ + + + diff --git a/front/src/components/main/components/tags-nav/index.js b/front/src/components/main/components/tags-nav/index.js new file mode 100644 index 00000000..56d2f1c2 --- /dev/null +++ b/front/src/components/main/components/tags-nav/index.js @@ -0,0 +1,2 @@ +import TagsNav from './tags-nav.vue'; +export default TagsNav; diff --git a/front/src/components/main/components/tags-nav/tags-nav.less b/front/src/components/main/components/tags-nav/tags-nav.less new file mode 100644 index 00000000..ddb05134 --- /dev/null +++ b/front/src/components/main/components/tags-nav/tags-nav.less @@ -0,0 +1,136 @@ +.no-select{ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.size{ + height: 100%; +} +.tags-nav{ + position: relative; + margin:0 auto; + // border-top: 1px solid #F0F0F0; + // border-bottom: 1px solid #F0F0F0; + background: #f4f6f8; + padding:0 20px; + + .no-select; + .size; + .close-con{ + position: absolute; + right: 0; + top: 5px; + height: 30px; + width: 42px; + background: #f3f5f7; + text-align: center; + z-index: 10; + margin-top:5px; + + border-top: 1px solid #F5F7FC; + border-bottom: 1px solid #F5F7FC; + i{ + color:#666666; + } + button{ + margin-top:3px; + + } + } + .btn-con{ + margin-top:10px; + position: absolute; + top: 0px; + height: 30px; + line-height: 30px; + // padding:0 10px; + background: #f3f5f7; + z-index: 10; + + button{ + position: relative; + top:-1px; + line-height: 14px; + text-align: center; + color:#666666; + + } + &.left-btn{ + left: 0px; + border: 1px solid #F5F7FC; + } + &.right-btn{ + right: 42px; + border: 1px solid #F5F7FC; + } + } + .scroll-outer{ + position: absolute; + left: 52px; + right: 61px; + top: 0; + bottom: 0; + padding:10px 0; + .scroll-body{ + display: inline-block; + position: absolute; + box-shadow: border-box; + overflow: visible; + white-space: nowrap; + transition: left .3s ease; + .ivu-tag{ + height:34px; + margin:0; + } + .ivu-tag{ + // min-width:10px; + height:30px; + line-height: 30px; + border-radius: 3px; + padding:0 10px; + background: #fff!important; + border:none; + text-align: center; + color:#1C2B36; + font-size: 14px; + margin:0 5px; + span{ + color:#1C2B36!important; + padding:0 5px; + } + i{ + color:#1C2B36!important; + font-size: 4px; + } + } + .ivu-tag-primary{ + transition: background .2s ease; + background: #2D8CF0!important; + span,i{ + color:#fff!important; + } + } + } + } + .contextmenu { + position: absolute; + margin: 0; + padding: 5px 0; + background: #fff; + z-index: 1000; + list-style-type: none; + border-radius: 3px; + box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .1); + li { + margin: 0; + padding: 5px 15px; + cursor: pointer; + &:hover { + background: #eee; + } + } + } +} diff --git a/front/src/components/main/components/tags-nav/tags-nav.vue b/front/src/components/main/components/tags-nav/tags-nav.vue new file mode 100644 index 00000000..00909fa0 --- /dev/null +++ b/front/src/components/main/components/tags-nav/tags-nav.vue @@ -0,0 +1,256 @@ + + + + + diff --git a/front/src/components/main/components/user/index.js b/front/src/components/main/components/user/index.js new file mode 100644 index 00000000..54d7ca0b --- /dev/null +++ b/front/src/components/main/components/user/index.js @@ -0,0 +1,2 @@ +import User from './user.vue'; +export default User; diff --git a/front/src/components/main/components/user/user.less b/front/src/components/main/components/user/user.less new file mode 100644 index 00000000..9c5eeba7 --- /dev/null +++ b/front/src/components/main/components/user/user.less @@ -0,0 +1,25 @@ +.user-avatar-dropdown{ + padding-left:20px; + color:#909ca4; + .dropdown-arrows{ + margin:0 10px; + } + .head{ + position: relative; + top:-2px; + } +} +.user{ + + &-avatar-dropdown{ + cursor: pointer; + display: inline-block; + // height: 64px; + vertical-align: middle; + // line-height: 64px; + .ivu-badge-dot{ + top: 16px; + } + } + +} diff --git a/front/src/components/main/components/user/user.vue b/front/src/components/main/components/user/user.vue new file mode 100644 index 00000000..d7f0324a --- /dev/null +++ b/front/src/components/main/components/user/user.vue @@ -0,0 +1,131 @@ + + + + diff --git a/front/src/components/main/index.js b/front/src/components/main/index.js new file mode 100644 index 00000000..87be9ddf --- /dev/null +++ b/front/src/components/main/index.js @@ -0,0 +1,2 @@ +import Main from './main.vue'; +export default Main; diff --git a/front/src/components/main/main.less b/front/src/components/main/main.less new file mode 100644 index 00000000..7a6d4c83 --- /dev/null +++ b/front/src/components/main/main.less @@ -0,0 +1,129 @@ +//滚动条样式 +.scrollbar(@width: 2px){ + &::-webkit-scrollbar { width: @width; height: 8px; } + &::-webkit-scrollbar-thumb { border-radius: 5px; -webkit-box-shadow: inset 0 0 5px rgb(185, 185, 185); background: #c7c5c8; } + &::-webkit-scrollbar-track { border-radius: 0; background: #ddd; } +} +.no-scrollbar{ + &::-webkit-scrollbar {display:none} +} +.main{ + .scrollbar, + .ivu-table-overflowX, + .content-wrapper, + .w-e-text{ + .scrollbar; + } + iframe body{ + .scrollbar; + } + .logo-con{ + padding: 19px 0 15px 20px; + &.collapsed{ + padding: 19px 0 15px; + text-align: center; + } + } + .menu-dropdown{ + margin-left: 200px; + } + .search-bar{ + padding:0 20px; + margin-bottom: 20px; + &.collapsed{ + padding:0 12px; + i{ + width: 40px; + + } + } + input{ + width: 100%; + height:36px; + background: #152a3a; + color:#44505c; + font-size: 14px; + outline: none; + + &::placeholder{ + color:#44505c; + } + &:focus{ + border:none; + outline: none; + background: #fff; + } + border:none; + } + i{ + line-height: 36px; + color:#44505c; + } + } + .header-con{ + background: #fff; + padding: 0 10px; + width: 100%; + } + .main-layout-con{ + height: 100%; + overflow: hidden; + } + .main-content-con{ + height: ~"calc(100% - 60px)"; + overflow: hidden; + } + .tag-nav-wrapper{ + padding: 0; + height:50px; + // background:#F0F0F0; + } + .content-wrapper{ + padding: 0 18px 18px; + height: ~"calc(100% - 80px)"; + overflow: auto; + } + .left-sider{ + .ivu-layout-sider-children{ + overflow-y: scroll; + margin-right: -18px; + } + } +} +.ivu-menu-light.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu):after{ + right: inherit; left: 0; +} +.ivu-menu-item > i{ + margin-right: 12px !important; +} +.ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i { + margin-right: 8px !important; +} +.collased-menu-dropdown{ + width: 100%; + margin: 0; + line-height: normal; + padding: 7px 0 6px 16px; + clear: both; + font-size: 12px !important; + white-space: nowrap; + list-style: none; + cursor: pointer; + transition: background 0.2s ease-in-out; + &:hover{ + background: rgba(100, 100, 100, 0.1); + } + & * { + color: #515a6e; + } + .ivu-menu-item > i{ + margin-right: 12px !important; + } + .ivu-menu-submenu > .ivu-menu > .ivu-menu-item > i { + margin-right: 8px !important; + } +} + +.ivu-select-dropdown.ivu-dropdown-transfer{ + max-height: 400px; +} diff --git a/front/src/components/main/main.vue b/front/src/components/main/main.vue new file mode 100644 index 00000000..5004c1b1 --- /dev/null +++ b/front/src/components/main/main.vue @@ -0,0 +1,443 @@ + + + diff --git a/front/src/components/tables/edit.vue b/front/src/components/tables/edit.vue new file mode 100644 index 00000000..55c142ac --- /dev/null +++ b/front/src/components/tables/edit.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/front/src/components/tables/handle-btns.js b/front/src/components/tables/handle-btns.js new file mode 100644 index 00000000..7254b3e1 --- /dev/null +++ b/front/src/components/tables/handle-btns.js @@ -0,0 +1,70 @@ +// 验证 +const validate = { + operation: (params) => { + if (params.operation === 0) { + return false; + } + return true; + }, + audit: (params) => { + if (params.audit === 0) { + return false; + } + return true; + } +}; +const btns = { + // 删除:需要判定 + delete: (h, params, vm) => { + let disabledFlag = false; + return h('Tooltip', { + props: { + content: '删除', + placement: 'top', + transfer: true + } + }, [h('Button', { + props: { + type: 'error', + size: 'small', + icon: 'md-trash', + disabled: disabledFlag + }, + style: { + marginRight: '5px' + }, + on: { + click: () => { + vm.$emit('on-delete', params); + } + } + })]); + }, + edit: (h, params, vm) => { + let disabledFlag = false; + return h('Tooltip', { + props: { + content: '编辑', + placement: 'top', + transfer: true + } + }, [h('Button', { + props: { + type: 'primary', + size: 'small', + icon: 'md-trash', + disabled: disabledFlag + }, + style: { + marginRight: '5px' + }, + on: { + click: () => { + vm.$emit('on-edit', params); + } + } + })]); + } +}; + +export default btns; diff --git a/front/src/components/tables/index.js b/front/src/components/tables/index.js new file mode 100644 index 00000000..899190c0 --- /dev/null +++ b/front/src/components/tables/index.js @@ -0,0 +1,2 @@ +import Tables from './tables.vue'; +export default Tables; diff --git a/front/src/components/tables/index.less b/front/src/components/tables/index.less new file mode 100644 index 00000000..3c352e11 --- /dev/null +++ b/front/src/components/tables/index.less @@ -0,0 +1,17 @@ +.search-con{ + padding: 10px 0; + .search{ + &-col{ + display: inline-block; + width: 200px; + } + &-input{ + display: inline-block; + width: 200px; + margin-left: 2px; + } + &-btn{ + margin-left: 2px; + } + } +} diff --git a/front/src/components/tables/tables.vue b/front/src/components/tables/tables.vue new file mode 100644 index 00000000..0c2329b4 --- /dev/null +++ b/front/src/components/tables/tables.vue @@ -0,0 +1,342 @@ + + + diff --git a/front/src/config/index.js b/front/src/config/index.js new file mode 100644 index 00000000..a80b6815 --- /dev/null +++ b/front/src/config/index.js @@ -0,0 +1,38 @@ +console.log('api url : ', process.env.VUE_APP_URL); +console.log('websocket url : ', process.env.VUE_APP_SOCKET_URL); +export default { + /** + * @description 配置显示在浏览器标签的title + */ + title: 'Smart-Admin', + /** + * @description token在Cookie中存储的天数,默认1天 + */ + cookieExpires: 3, + /** + * @description 是否使用国际化,默认为false + * 如果不使用,则需要在路由中给需要在菜单中展示的路由设置meta: {title: 'xxx'} + * 用来在菜单中显示文字 + */ + useI18n: false, + /** + * @description api请求基础路径 + */ + baseUrl: { + apiUrl: process.env.VUE_APP_URL, + webSocketUrl: process.env.VUE_APP_SOCKET_URL + }, + /** + * @description 默认打开的首页的路由name值,默认为home + */ + homeName: 'Home', + /** + * @description 需要加载的插件 + */ + plugin: { + 'error-store': { + showInHeader: true, // 设为false后不会在顶部显示错误日志徽标 + developmentOff: true // 设为true后在开发环境不会收集错误信息,方便开发中排查错误 + } + } +}; diff --git a/front/src/constants/file.js b/front/src/constants/file.js new file mode 100644 index 00000000..6a205f55 --- /dev/null +++ b/front/src/constants/file.js @@ -0,0 +1,24 @@ +export const FILE_TYPE = { + LOCAL: { + value: 1, + desc: '本地文件服务' + }, + ALI_OSS: { + value: 2, + desc: '阿里OSS文件服务' + }, + QI_NIU_OSS: { + value: 3, + desc: '七牛文件服务' + } +}; +export const SERVICE_TYPE = { + BACK_USER: { + value: '1', + desc: '用户后台' + } +}; +export default { + FILE_TYPE, + SERVICE_TYPE +}; diff --git a/front/src/constants/index.js b/front/src/constants/index.js new file mode 100644 index 00000000..55101226 --- /dev/null +++ b/front/src/constants/index.js @@ -0,0 +1,10 @@ +import notice from './notice.js'; +import login from './login.js'; +import file from './file.js'; +import privilege from './privilege'; +export default { + ...notice, + ...login, + ...file, + ...privilege +}; diff --git a/front/src/constants/login.js b/front/src/constants/login.js new file mode 100644 index 00000000..fb28973b --- /dev/null +++ b/front/src/constants/login.js @@ -0,0 +1,13 @@ +export const PRIVILEGE_TYPE = { + MENU: { + value: 1, + desc: '是' + }, + POINTS: { + value: 2, + desc: '否' + } +}; +export default { + PRIVILEGE_TYPE +}; diff --git a/front/src/constants/notice.js b/front/src/constants/notice.js new file mode 100644 index 00000000..0d5315fa --- /dev/null +++ b/front/src/constants/notice.js @@ -0,0 +1,13 @@ +export const NOTICE_STATUS = { + YES: { + value: 1, + desc: '是' + }, + NO: { + value: 0, + desc: '否' + } +}; +export default { + NOTICE_STATUS +}; diff --git a/front/src/constants/privilege.js b/front/src/constants/privilege.js new file mode 100644 index 00000000..885e86d6 --- /dev/null +++ b/front/src/constants/privilege.js @@ -0,0 +1,14 @@ +export const PRIVILEGE_TYPE_ENUM = { + MENU: { + value: 1, + desc: '菜单' + }, + POINTS: { + value: 2, + desc: '功能点' + } +}; + +export default { + PRIVILEGE_TYPE_ENUM +}; diff --git a/front/src/directives/directives.js b/front/src/directives/directives.js new file mode 100644 index 00000000..701eec5d --- /dev/null +++ b/front/src/directives/directives.js @@ -0,0 +1,11 @@ +import draggable from './module/draggable'; +import clipboard from './module/clipboard'; +import privilege from './module/privilege'; + +const directives = { + draggable, + clipboard, + privilege +}; + +export default directives; diff --git a/front/src/directives/index.js b/front/src/directives/index.js new file mode 100644 index 00000000..dcc9ffb3 --- /dev/null +++ b/front/src/directives/index.js @@ -0,0 +1,31 @@ +import directive from './directives'; + +const importDirective = Vue => { + /** + * 拖拽指令 v-draggable="options" + * options = { + * trigger: /这里传入作为拖拽触发器的CSS选择器/, + * body: /这里传入需要移动容器的CSS选择器/, + * recover: /拖动结束之后是否恢复到原来的位置/ + * } + */ + Vue.directive('draggable', directive.draggable); + /** + * clipboard指令 v-draggable="options" + * options = { + * value: /在输入框中使用v-model绑定的值/, + * success: /复制成功后的回调/, + * error: /复制失败后的回调/ + * } + */ + Vue.directive('clipboard', directive.clipboard); + /** + * privilege指令 v-privilege="options" + * options = { + * value: /当前按钮的唯一权限识别/, + * } + */ + Vue.directive('privilege', directive.privilege); +}; + +export default importDirective; diff --git a/front/src/directives/module/clipboard.js b/front/src/directives/module/clipboard.js new file mode 100644 index 00000000..0684eb61 --- /dev/null +++ b/front/src/directives/module/clipboard.js @@ -0,0 +1,30 @@ +import Clipboard from 'clipboard'; +export default { + bind: (el, binding) => { + const clipboard = new Clipboard(el, { + text: () => binding.value.value + }); + el.__success_callback__ = binding.value.success; + el.__error_callback__ = binding.value.error; + clipboard.on('success', e => { + const callback = el.__success_callback__; + callback && callback(e); + }); + clipboard.on('error', e => { + const callback = el.__error_callback__; + callback && callback(e); + }); + el.__clipboard__ = clipboard; + }, + update: (el, binding) => { + el.__clipboard__.text = () => binding.value.value; + el.__success_callback__ = binding.value.success; + el.__error_callback__ = binding.value.error; + }, + unbind: (el, binding) => { + delete el.__success_callback__; + delete el.__error_callback__; + el.__clipboard__.destroy(); + delete el.__clipboard__; + } +}; diff --git a/front/src/directives/module/draggable.js b/front/src/directives/module/draggable.js new file mode 100644 index 00000000..8bf798b3 --- /dev/null +++ b/front/src/directives/module/draggable.js @@ -0,0 +1,42 @@ +import { on } from '@/lib/util'; +export default { + inserted: (el, binding, vnode) => { + let triggerDom = document.querySelector(binding.value.trigger); + triggerDom.style.cursor = 'move'; + let bodyDom = document.querySelector(binding.value.body); + let pageX = 0; + let pageY = 0; + let transformX = 0; + let transformY = 0; + let canMove = false; + const handleMousedown = e => { + let transform = /\(.*\)/.exec(bodyDom.style.transform); + if (transform) { + transform = transform[0].slice(1, transform[0].length - 1); + let splitxy = transform.split('px, '); + transformX = parseFloat(splitxy[0]); + transformY = parseFloat(splitxy[1].split('px')[0]); + } + pageX = e.pageX; + pageY = e.pageY; + canMove = true; + }; + const handleMousemove = e => { + let xOffset = e.pageX - pageX + transformX; + let yOffset = e.pageY - pageY + transformY; + if (canMove) + {bodyDom.style.transform = `translate(${xOffset}px, ${yOffset}px)`;} + }; + const handleMouseup = e => { + canMove = false; + }; + on(triggerDom, 'mousedown', handleMousedown); + on(document, 'mousemove', handleMousemove); + on(document, 'mouseup', handleMouseup); + }, + update: (el, binding, vnode) => { + if (!binding.value.recover) return; + let bodyDom = document.querySelector(binding.value.body); + bodyDom.style.transform = ''; + } +}; diff --git a/front/src/directives/module/privilege.js b/front/src/directives/module/privilege.js new file mode 100644 index 00000000..ecfaf7e1 --- /dev/null +++ b/front/src/directives/module/privilege.js @@ -0,0 +1,23 @@ +// 页面内按钮过滤 +import store from '@/store/index'; +export default { + inserted: function (el, binding, vnode) { + // 获取当前路由name + // 如果页面为同一模块下的子页面则取最上级权限 + let routeName = vnode.context.$route.meta.group + ? vnode.context.$route.meta.group + : vnode.context.$route.name; + // 超级管理员 + if (store.state.user.userLoginInfo.isSuperMan) { + return true; + } + // 获取功能点权限 + let functionList = store.state.user.privilegeFunctionPointsMap.get(routeName); + // 有权限 + if (functionList && functionList.includes(binding.value)) { + + } else { + el.parentNode.removeChild(el); + } + } +}; diff --git a/front/src/filters/index.js b/front/src/filters/index.js new file mode 100644 index 00000000..e69de29b diff --git a/front/src/lib/cookie.js b/front/src/lib/cookie.js new file mode 100644 index 00000000..83386119 --- /dev/null +++ b/front/src/lib/cookie.js @@ -0,0 +1,21 @@ +import Cookies from 'js-cookie'; +import config from '@/config'; +const { cookieExpires } = config; +export const TOKEN_KEY = 'token'; + +export default { + setToken: token => { + Cookies.set(TOKEN_KEY, token, { + // token在Cookie中存储的天数,默认1天 + expires: cookieExpires || 7 + }); + }, + getToken: () => { + const token = Cookies.get(TOKEN_KEY); + if (token) return token; + else return null; + }, + clearToken: () => { + Cookies.remove(TOKEN_KEY); + } +}; diff --git a/front/src/lib/http.js b/front/src/lib/http.js new file mode 100644 index 00000000..12a7b39d --- /dev/null +++ b/front/src/lib/http.js @@ -0,0 +1,91 @@ +import Axios from 'axios'; +import config from '@/config'; +import { Message, Spin } from 'iview'; +import cookie from '@/lib/cookie'; +// 之所以封装这个axios,是因为在一些请求中,无法上传信息,很尴尬,估计原因是继承的有问题,无法携带headers +export const baseUrl = config.baseUrl.apiUrl; +export const socketBaseUrl = config.baseUrl.webSocketUrl; + +let axios = Axios.create({ + baseURL: baseUrl, + timeout: 30000, + headers: { + 'Content-Type': 'application/json; charset=utf-8' + } +}); +// 添加请求拦截器 + +// download url +const downloadUrl = url => { + let iframe = document.createElement('iframe'); + iframe.style.display = 'none'; + iframe.src = url; + iframe.onload = function () { + document.body.removeChild(iframe); + }; + document.body.appendChild(iframe); +}; + +axios.interceptors.request.use( + function (config) { + // 在发送请求之前做些什么 + if (cookie.getToken()) { + config.headers['x-access-token'] = cookie.getToken(); + } + return config; + }, + function (error) { + // 对请求错误做些什么 + Spin.hide(); + return Promise.reject(error); + } +); +// 添加响应拦截器 +axios.interceptors.response.use( + res => { + // 处理请求是下载的接口 + if ( + res.headers && + (res.headers['content-type'] === 'application/x-msdownload' || + res.headers['content-type'] === + 'application/octet-stream;charset=utf-8') + ) { + downloadUrl(res.request.responseURL); + res.data = ''; + res.headers['content-type'] = 'text/json'; + return res; + } + let { data } = res; + if (data.code !== 1) { + if (data.code === 1001) { + cookie.clearToken(); + localStorage.clear(); + window.location.href = window.location.pathname + '#/login'; + Message.error('未登录,或登录失效,请登录'); + } else if (data.code === 502) { + window.location.href = window.location.pathname + '#/500'; + } else { + Message.error(data.msg); + } + Spin.hide(); + return Promise.reject(res); + } + return data; + }, + error => { + Spin.hide(); + Message.error('服务内部错误'); + console.log('1111', error); + // 对响应错误做点什么 + return Promise.reject(error); + } +); + +export const postAxios = (url, data) => { + return axios.post(url, data); +}; +export const getAxios = (url, data) => { + return axios.get(url, { + params: data + }); +}; diff --git a/front/src/lib/local.js b/front/src/lib/local.js new file mode 100644 index 00000000..c19d7e3d --- /dev/null +++ b/front/src/lib/local.js @@ -0,0 +1,8 @@ +export const localSave = (key, value) => { + localStorage.setItem(key, value); +}; + +export const localRead = key => { + return localStorage.getItem(key) || ''; +}; + diff --git a/front/src/lib/menu-func.js b/front/src/lib/menu-func.js new file mode 100644 index 00000000..70a94ff9 --- /dev/null +++ b/front/src/lib/menu-func.js @@ -0,0 +1,306 @@ +import { forEach, hasOneOf, objEqual } from '@/lib/util'; +import config from '@/config'; +import { localRead, localSave } from '@/lib/local'; +const { title, useI18n } = config; +export const hasChild = item => { + return item.children && item.children.length !== 0; +}; +const showThisMenuEle = (item, access) => { + if (item.meta && item.meta.access && item.meta.access.length) { + if (hasOneOf(item.meta.access, access)) return true; + else return false; + } else return true; +}; +/** + * @param {Array} list 通过路由列表得到菜单列表 + * @returns {Array} + */ +export const getMenuByRouter = (list, access) => { + let res = []; + forEach(list, item => { + if (!item.meta || (item.meta && !item.meta.hideInMenu)) { + let obj = { + icon: (item.meta && item.meta.icon) || '', + name: item.name, + meta: item.meta + }; + if ( + (hasChild(item) || (item.meta && item.meta.showAlways)) && + showThisMenuEle(item, access) + ) { + obj.children = getMenuByRouter(item.children, access); + } + if (item.meta && item.meta.href) obj.href = item.meta.href; + if (showThisMenuEle(item, access)) res.push(obj); + } + }); + return res; +}; +/** + * 通过权限过滤菜单 + * @param {Object} map 权限对象 + * @param {Array} menuList 菜单列表 + * @returns {Array} + */ +export const getShowMenu = (map = {}, menuList, access = false) => { + // 判断是否为超级管理员 + if (access) { + return menuList; + } + // 返回的菜单列表 + let result = []; + for (let menuItem of menuList) { + let routerObj = JSON.parse(JSON.stringify(menuItem)); + if ( + map.hasOwnProperty(menuItem.name) && + (menuItem.name !== 'home' && menuItem.name !== '_home') + ) { + // 判断该菜单权限下是否为数组,若为数组,则为功能点权限否则为子菜单 + if (getType(map[routerObj.name]) === 'array') { + let funcPrivilege = localRead('funcPrivilegeInfo') + ? JSON.parse(localRead('funcPrivilegeInfo')) + : {}; + localSave( + 'funcPrivilegeInfo', + JSON.stringify({ + ...funcPrivilege, + [routerObj.name]: map[routerObj.name] + }) + ); + } else if ( + getType(map[routerObj.name]) !== 'array' && + !routerObj.children + ) { + // 判断是否为二级菜单,若是则需要多枚举一层赋值 + let funcPrivilege = localRead('funcPrivilegeInfo') + ? JSON.parse(localRead('funcPrivilegeInfo')) + : {}; + localSave( + 'funcPrivilegeInfo', + JSON.stringify({ + ...funcPrivilege, + [routerObj.name]: map[routerObj.name][routerObj.name] + }) + ); + } else if ( + getType(map[routerObj.name]) !== 'array' && + routerObj.children + ) { + // 循环子菜单权限 + routerObj.children = getShowMenu( + map[routerObj.name], + routerObj.children + ); + } + result.push(routerObj); + } + } + return result; +}; +// 获取数据类型 +export const getType = obj => { + return {}.toString + .call(obj) + .match(/\s([a-zA-Z]+)/)[1] + .toLowerCase(); +}; + +/** + * @description 本地存储和获取标签导航列表 + */ +export const setTagNavListInLocalStorage = list => { + localStorage.tagNaveList = JSON.stringify(list); +}; +/** + * @returns {Array} 其中的每个元素只包含路由原信息中的name, path, meta三项 + */ +export const getTagNavListFromLocalStorage = () => { + const list = localStorage.tagNaveList; + return list ? JSON.parse(list) : []; +}; +export const getBreadCrumbList = (route, homeRoute) => { + let homeItem = { + ...homeRoute, + icon: homeRoute.meta.icon + }; + let routeMatched = route.matched; + if (routeMatched.some(item => item.name === homeRoute.name)) { + return [homeItem]; + } + let res = routeMatched + .filter(item => { + return item.meta === undefined || !item.meta.hideInBread; + }) + .map(item => { + let meta = { + ...item.meta + }; + if (meta.title && typeof meta.title === 'function') { + meta.__titleIsFunction__ = true; + meta.title = meta.title(route); + } + let obj = { + icon: (item.meta && item.meta.icon) || '', + name: item.name, + meta: meta + }; + return obj; + }); + res = res.filter(item => { + return !item.meta.hideInMenu; + }); + return [...res]; +}; +/** + * @param {Array} routers 路由列表数组 + * @description 用于找到路由列表中name为home的对象 + */ +export const getHomeRoute = (routers, homeName = 'Home') => { + let i = -1; + let len = routers.length; + let homeRoute = {}; + while (++i < len) { + let item = routers[i]; + if (item.children && item.children.length) { + let res = getHomeRoute(item.children, homeName); + if (res.name) return res; + } else { + if (item.name === homeName) homeRoute = item; + } + } + return homeRoute; +}; +/** + * @param {Array} list 标签列表 + * @param {String} name 当前关闭的标签的name + */ +export const getNextRoute = (list, route) => { + let res = {}; + if (list.length === 2) { + res = getHomeRoute(list); + } else { + const index = list.findIndex(item => routeEqual(item, route)); + if (index === list.length - 1) res = list[list.length - 2]; + else res = list[index + 1]; + } + return res; +}; + +/** + * 判断打开的标签列表里是否已存在这个新添加的路由对象 + */ +export const routeHasExist = (tagNavList, routeItem) => { + let len = tagNavList.length; + let res = false; + doCustomTimes(len, index => { + if (routeEqual(tagNavList[index], routeItem)) res = true; + }); + return res; +}; +/** + * @param {*} list 现有标签导航列表 + * @param {*} newRoute 新添加的路由原信息对象 + * @description 如果该newRoute已经存在则不再添加 + */ +export const getNewTagList = (list, newRoute) => { + const { name, path, meta, query } = newRoute; + let newList = [...list]; + let index = newList.findIndex(item => item.name === name); + if (index >= 0) { + newList[index] = { name, path, meta, query }; + } else newList.push({ name, path, meta, query }); + return newList; +}; +export const routeEqual = (route1, route2) => { + return route1.name === route2.name; +}; +export const getRouteTitleHandled = route => { + let router = { + ...route + }; + let meta = { + ...route.meta + }; + let title = ''; + if (meta.title) { + if (typeof meta.title === 'function') { + meta.__titleIsFunction__ = true; + title = meta.title(router); + } else title = meta.title; + } + meta.title = title; + router.meta = meta; + return router; +}; +/** + * @param {Number} times 回调函数需要执行的次数 + * @param {Function} callback 回调函数 + */ +export const doCustomTimes = (times, callback) => { + let i = -1; + while (++i < times) { + callback(i); + } +}; +export const showTitle = (item, vm) => { + let { title, __titleIsFunction__ } = item.meta; + if (!title) return; + if (useI18n) { + if (title.includes('{{') && title.includes('}}') && useI18n) { + title = title.replace(/({{[\s\S]+?}})/, (m, str) => + str.replace(/{{([\s\S]*)}}/, (m, _) => vm.$t(_.trim())) + ); + } else if (__titleIsFunction__) title = item.meta.title; + else title = vm.$t(item.name); + } else title = (item.meta && item.meta.title) || item.name; + return title; +}; +/** + * @description 根据当前跳转的路由设置显示在浏览器标签的title + * @param {Object} routeItem 路由对象 + * @param {Object} vm Vue实例 + */ +export const setTitle = (routeItem, vm) => { + const handledRoute = getRouteTitleHandled(routeItem); + const pageTitle = showTitle(handledRoute, vm); + const resTitle = pageTitle ? `${pageTitle} - ${title}` : title; + window.document.title = resTitle; +}; + +export const findNodeUpper = (ele, tag) => { + if (ele.parentNode) { + if (ele.parentNode.tagName === tag.toUpperCase()) { + return ele.parentNode; + } else { + return findNodeUpper(ele.parentNode, tag); + } + } +}; + +export const findNodeUpperByClasses = (ele, classes) => { + let parentNode = ele.parentNode; + if (parentNode) { + let classList = parentNode.classList; + if ( + classList && + classes.every(className => classList.contains(className)) + ) { + return parentNode; + } else { + return findNodeUpperByClasses(parentNode, classes); + } + } +}; + +export const findNodeDownward = (ele, tag) => { + const tagName = tag.toUpperCase(); + if (ele.childNodes.length) { + let i = -1; + let len = ele.childNodes.length; + while (++i < len) { + let child = ele.childNodes[i]; + if (child.tagName === tagName) return child; + else return findNodeDownward(child, tag); + } + } +}; diff --git a/front/src/lib/printPlugs.js b/front/src/lib/printPlugs.js new file mode 100644 index 00000000..9c4295dd --- /dev/null +++ b/front/src/lib/printPlugs.js @@ -0,0 +1,133 @@ +// 打印类属性、方法定义 +/* eslint-disable */ +//第二个参数表明是否要关闭当前窗口 +const Print = function(dom, close, options) { + if (!(this instanceof Print)) return new Print(dom, close, options); + + this.options = this.extend( + { + noPrint: '.no-print' + }, + options + ); + + if (typeof dom === 'string') { + this.dom = document.querySelector(dom); + } else { + this.dom = dom; + } + + this.init(close); +}; +Print.prototype = { + init: function(close) { + var content = this.getStyle() + this.getHtml(); + this.writeIframe(content, close); + }, + extend: function(obj, obj2) { + for (var k in obj2) { + obj[k] = obj2[k]; + } + return obj; + }, + + getStyle: function() { + var str = '', + styles = document.querySelectorAll('style,link'); + for (var i = 0; i < styles.length; i++) { + str += styles[i].outerHTML; + } + str += + ''; + + return str; + }, + + getHtml: function() { + var inputs = document.querySelectorAll('input'); + var textareas = document.querySelectorAll('textarea'); + var selects = document.querySelectorAll('select'); + + for (var k in inputs) { + if (inputs[k].type == 'checkbox' || inputs[k].type == 'radio') { + if (inputs[k].checked == true) { + inputs[k].setAttribute('checked', 'checked'); + } else { + inputs[k].removeAttribute('checked'); + } + } else if (inputs[k].type == 'text') { + inputs[k].setAttribute('value', inputs[k].value); + } + } + + for (var k2 in textareas) { + if (textareas[k2].type == 'textarea') { + textareas[k2].innerHTML = textareas[k2].value; + } + } + + for (var k3 in selects) { + if (selects[k3].type == 'select-one') { + var child = selects[k3].children; + for (var i in child) { + if (child[i].tagName == 'OPTION') { + if (child[i].selected == true) { + child[i].setAttribute('selected', 'selected'); + } else { + child[i].removeAttribute('selected'); + } + } + } + } + } + return this.dom.outerHTML; + }, + + writeIframe: function(content, close) { + var w, + doc, + iframe = document.createElement('iframe'), + f = document.body.appendChild(iframe); + iframe.id = 'myIframe'; + iframe.style = 'position:absolute;'; + + w = f.contentWindow || f.contentDocument; + doc = f.contentDocument || f.contentWindow.document; + doc.open(); + doc.write(content); + doc.close(); + this.toPrint(w, close); + setTimeout(function() { + document.body.removeChild(iframe); + }, 500); + }, + + toPrint: function(frameWindow, close) { + try { + setTimeout(function() { + frameWindow.focus(); + try { + if (!frameWindow.document.execCommand('print', false, null)) { + frameWindow.print(); + } + } catch (e) { + frameWindow.print(); + } + frameWindow.close(); + if (close) { + window.close(); + } + }, 500); + } catch (err) { + console.log('err', err); + } + } +}; +const MyPlugin = {}; +MyPlugin.install = function(Vue, options) { + // 4. 添加实例方法 + Vue.prototype.$print = Print; +}; +export default MyPlugin; diff --git a/front/src/lib/render-dom.js b/front/src/lib/render-dom.js new file mode 100644 index 00000000..1cad207e --- /dev/null +++ b/front/src/lib/render-dom.js @@ -0,0 +1,10 @@ +export default { + name: 'RenderDom', + functional: true, + props: { + render: Function + }, + render: (h, ctx) => { + return ctx.props.render(h); + } +}; diff --git a/front/src/lib/table-action.js b/front/src/lib/table-action.js new file mode 100644 index 00000000..f9a541fc --- /dev/null +++ b/front/src/lib/table-action.js @@ -0,0 +1,84 @@ +// 处理table操作按钮 +const tableAction = (h, array) => { + let btnArray = []; + let btnMore = []; + array.map((item, index) => { + if (index < 2) { + let btn = h( + 'a', + { + props: { + type: !index ? 'primary' : 'info', + size: 'small', + to: item.to ? item.to : '', + target: item.target ? item.target : '_self', + ghost: true + }, + style: { + marginLeft: '5px' + }, + directives: item.directives, + on: { + click: item.action + } + }, + item.title + ); + btnArray.push(btn); + } else { + btnMore.push( + h( + 'DropdownItem', + { + nativeOn: { + click: item.action + } + }, + item.title + ) + ); + } + }); + let dropdown = h( + 'Dropdown', + { + props: { + transfer: true + } + }, + [ + h( + 'a', + { + props: { + type: 'default', + size: 'small' + }, + style: { + marginLeft: '5px' + } + }, + [ + h('span', '更多'), + h('Icon', { + props: { + type: 'ios-arrow-down' + } + }) + ] + ), + h( + 'DropdownMenu', + { + slot: 'list' + }, + btnMore + ) + ] + ); + if (array.length > 2) { + btnArray.push(dropdown); + } + return btnArray; +}; +export default tableAction; diff --git a/front/src/lib/util.js b/front/src/lib/util.js new file mode 100644 index 00000000..9e254c5d --- /dev/null +++ b/front/src/lib/util.js @@ -0,0 +1,499 @@ +/** + * @param {String} url + * @description 从URL中解析参数 + */ +export const getParams = url => { + const keyValueArr = url.split('?')[1].split('&'); + let paramObj = {}; + keyValueArr.forEach(item => { + const keyValue = item.split('='); + paramObj[keyValue[0]] = keyValue[1]; + }); + return paramObj; +}; + +/** + * @param {Any} obj + * @description 获取数据类型 + */ +export const getType = obj => { + return {}.toString + .call(obj) + .match(/\s([a-zA-Z]+)/)[1] + .toLowerCase(); +}; +// 日期格式 +export const dateFormat = { + YMD: 'YMD', + YMDHM: 'YMDHM', + YMDHMS: 'YMDHMS' +}; +export const forEach = (arr, fn) => { + if (!arr.length || !fn) return; + let i = -1; + let len = arr.length; + while (++i < len) { + let item = arr[i]; + fn(item, i, arr); + } +}; + +/** + * @param {Array} arr1 + * @param {Array} arr2 + * @description 得到两个数组的交集, 两个数组的元素为数值或字符串 + */ +export const getIntersection = (arr1, arr2) => { + let len = Math.min(arr1.length, arr2.length); + let i = -1; + let res = []; + while (++i < len) { + const item = arr2[i]; + if (arr1.indexOf(item) > -1) res.push(item); + } + return res; +}; + +/** + * @param {Array} arr1 + * @param {Array} arr2 + * @description 得到两个数组的并集, 两个数组的元素为数值或字符串 + */ +export const getUnion = (arr1, arr2) => { + return Array.from(new Set([...arr1, ...arr2])); +}; + +/** + * @param {Array} target 目标数组 + * @param {Array} arr 需要查询的数组 + * @description 判断要查询的数组是否至少有一个元素包含在目标数组中 + */ +export const hasOneOf = (targetarr, arr) => { + return targetarr.some(_ => arr.indexOf(_) > -1); +}; + +/** + * @param {String|Number} value 要验证的字符串或数值 + * @param {*} validList 用来验证的列表 + */ +export function oneOf (value, validList) { + for (let i = 0; i < validList.length; i++) { + if (value === validList[i]) { + return true; + } + } + return false; +} + +/** + * @param {Number} timeStamp 判断时间戳格式是否是毫秒 + * @returns {Boolean} + */ +const isMillisecond = timeStamp => { + const timeStr = String(timeStamp); + return timeStr.length > 10; +}; + +/** + * @param {Number} timeStamp 传入的时间戳 + * @param {Number} currentTime 当前时间时间戳 + * @returns {Boolean} 传入的时间戳是否早于当前时间戳 + */ +const isEarly = (timeStamp, currentTime) => { + return timeStamp < currentTime; +}; + +/** + * @param {Number} num 数值 + * @returns {String} 处理后的字符串 + * @description 如果传入的数值小于10,即位数只有1位,则在前面补充0 + */ +const getHandledValue = num => { + return num < 10 ? '0' + num : num; +}; + +/** + * @param {Number} timeStamp 传入的时间戳 + * @param {Number} startType 要返回的时间字符串的格式类型,传入'year'则返回年开头的完整时间 + */ +const getDate = (timeStamp, startType) => { + const d = new Date(timeStamp * 1000); + const year = d.getFullYear(); + const month = getHandledValue(d.getMonth() + 1); + const date = getHandledValue(d.getDate()); + const hours = getHandledValue(d.getHours()); + const minutes = getHandledValue(d.getMinutes()); + const second = getHandledValue(d.getSeconds()); + let resStr = ''; + if (startType === 'year') + {resStr = + year + + '-' + + month + + '-' + + date + + ' ' + + hours + + ':' + + minutes + + ':' + + second;} + else resStr = month + '-' + date + ' ' + hours + ':' + minutes; + return resStr; +}; + +/** + * @param {String|Number} timeStamp 时间戳 + * @returns {String} 相对时间字符串 + */ +export const getRelativeTime = timeStamp => { + // 判断当前传入的时间戳是秒格式还是毫秒 + const IS_MILLISECOND = isMillisecond(timeStamp); + // 如果是毫秒格式则转为秒格式 + if (IS_MILLISECOND) Math.floor((timeStamp /= 1000)); + // 传入的时间戳可以是数值或字符串类型,这里统一转为数值类型 + timeStamp = Number(timeStamp); + // 获取当前时间时间戳 + const currentTime = Math.floor(Date.parse(new Date()) / 1000); + // 判断传入时间戳是否早于当前时间戳 + const IS_EARLY = isEarly(timeStamp, currentTime); + // 获取两个时间戳差值 + let diff = currentTime - timeStamp; + // 如果IS_EARLY为false则差值取反 + if (!IS_EARLY) diff = -diff; + let resStr = ''; + const dirStr = IS_EARLY ? '前' : '后'; + // 少于等于59秒 + if (diff <= 59) resStr = diff + '秒' + dirStr; + // 多于59秒,少于等于59分钟59秒 + else if (diff > 59 && diff <= 3599) + {resStr = Math.floor(diff / 60) + '分钟' + dirStr;} + // 多于59分钟59秒,少于等于23小时59分钟59秒 + else if (diff > 3599 && diff <= 86399) + {resStr = Math.floor(diff / 3600) + '小时' + dirStr;} + // 多于23小时59分钟59秒,少于等于29天59分钟59秒 + else if (diff > 86399 && diff <= 2623859) + {resStr = Math.floor(diff / 86400) + '天' + dirStr;} + // 多于29天59分钟59秒,少于364天23小时59分钟59秒,且传入的时间戳早于当前 + else if (diff > 2623859 && diff <= 31567859 && IS_EARLY) + {resStr = getDate(timeStamp);} + else resStr = getDate(timeStamp, 'year'); + return resStr; +}; + +/** + * @returns {String} 当前浏览器名称 + */ +export const getExplorer = () => { + const ua = window.navigator.userAgent; + const isExplorer = exp => { + return ua.indexOf(exp) > -1; + }; + if (isExplorer('MSIE')) return 'IE'; + else if (isExplorer('Firefox')) return 'Firefox'; + else if (isExplorer('Chrome')) return 'Chrome'; + else if (isExplorer('Opera')) return 'Opera'; + else if (isExplorer('Safari')) return 'Safari'; +}; + +/** + * @description 绑定事件 on(element, event, handler) + */ +export const on = (function () { + if (document.addEventListener) { + return function (element, event, handler) { + if (element && event && handler) { + element.addEventListener(event, handler, false); + } + }; + } else { + return function (element, event, handler) { + if (element && event && handler) { + element.attachEvent('on' + event, handler); + } + }; + } +})(); + +/** + * @description 解绑事件 off(element, event, handler) + */ +export const off = (function () { + if (document.removeEventListener) { + return function (element, event, handler) { + if (element && event) { + element.removeEventListener(event, handler, false); + } + }; + } else { + return function (element, event, handler) { + if (element && event) { + element.detachEvent('on' + event, handler); + } + }; + } +})(); + +/** + * 判断一个对象是否存在key,如果传入第二个参数key,则是判断这个obj对象是否存在key这个属性 + * 如果没有传入key这个参数,则判断obj对象是否有键值对 + */ +export const hasKey = (obj, key) => { + if (key) return key in obj; + else { + let keysArr = Object.keys(obj); + return keysArr.length; + } +}; + +/** + * @param {*} obj1 对象 + * @param {*} obj2 对象 + * @description 判断两个对象是否相等,这两个对象的值只能是数字或字符串 + */ +export const objEqual = (obj1, obj2) => { + const keysArr1 = Object.keys(obj1); + const keysArr2 = Object.keys(obj2); + if (keysArr1.length !== keysArr2.length) return false; + else if (keysArr1.length === 0 && keysArr2.length === 0) return true; + /* eslint-disable-next-line */ else + {return !keysArr1.some(key => obj1[key] != obj2[key]);} +}; + +// 相关工具类 +export const utils = { + /** + * @description table实现反选 + * @param {Object} vm Vue实例 + * @param {Array} tableSelectDate 选中的数据 + * @param {Array} allData 所有数据 + * @param {Array} key 数据中的唯一值 + */ + reverseSelect (vm, tableSelectDate, allData, key) { + let copyMess = JSON.parse(JSON.stringify(tableSelectDate)); + // 流程:先全部选中->再部分选中 + vm.handleSelectAll(false); + // 选中的idList + let idList = copyMess.map(item => item[key]); + console.log(idList); + for (let item of allData) { + if (idList.every(id => id !== item.id)) { + vm.$set(item, '_checked', true); + tableSelectDate.push(item); + } else { + vm.$set(item, '_checked', false); + } + } + }, + // 校验字符串是否相同 合同使用 + contrastString (originStr, changeStr) { + let origin = originStr + .replace(/\s*/g, '') + .replace(/"/g, '\'') + .replace(/ /g, '') + .replace(/disabled=\/'\/'/g, 'disabled'); + let change = changeStr + .replace(/\s*/g, '') + .replace(/"/g, '\'') + .replace(/ /g, '') + .replace(/disabled=\/'\/'/g, 'disabled'); + return origin === change; + }, + // 获取当前日期getDateStr(0)、前几天getDateStr(-10)、后几天getDateStr(20) + getDateStr (AddDayCount, format) { + let date = new Date(); + // 获取AddDayCount天后的日期 + date.setDate(date.getDate() + AddDayCount); + return this.getDate(date, format); + }, + getDate (date, format) { + let year = date.getFullYear(); + // day获取当前几号,不足10补0 + let day = date.getDate() > 9 ? date.getDate() : '0' + date.getDate(); + // month获取当前月份的日期,不足10补0 + let month = + date.getMonth() + 1 > 9 + ? date.getMonth() + 1 + : '0' + (date.getMonth() + 1); + // h获取当前小时,不足10补0 + let h = date.getHours() > 9 ? date.getHours() : '0' + date.getHours(); + // s获取当前分钟,不足10补0 + let m = date.getMinutes() > 9 ? date.getMinutes() : '0' + date.getMinutes(); + // s获取当前秒数,不足10补0 + let s = date.getSeconds() > 9 ? date.getSeconds() : '0' + date.getSeconds(); + let resultDate = ''; + if (format === dateFormat.YMD) { + resultDate = year + '-' + month + '-' + day; + } + if (format === dateFormat.YMDHM) { + resultDate = year + '-' + month + '-' + day + ' ' + h + ':' + m; + } + if (format === dateFormat.YMDHMS) { + resultDate = year + '-' + month + '-' + day + ' ' + h + ':' + m + ':' + s; + } + return resultDate; + }, + // 获取周一和周日日期,返回两种格式时间 + getDateWeek () { + let now = new Date(); + let nowTime = now.getTime(); + let day = now.getDay(); + let oneDayLong = 1000 * 60 * 60 * 24; + let MondayTime = nowTime - (day - 1) * oneDayLong; + let SundayTime = nowTime + (7 - day) * oneDayLong; + let monday = new Date(MondayTime); + let sunday = new Date(SundayTime); + return { + // first: this.getDateAll(monday), + // last: this.getDateAll(sunday), + firstDate: monday, + lastDate: sunday + }; + }, + // 获取月初与月末日期,返回两种时间格式 + getDateMonth () { + let dateFirter = new Date(); + let dateLast = new Date(); + dateFirter.setDate(1); + + let currentMonth = dateLast.getMonth(); + let nextMonth = ++currentMonth; + let nextMonthFirstDay = new Date(dateLast.getFullYear(), nextMonth, 1); + let oneDay = 1000 * 60 * 60 * 24; + dateLast = new Date(nextMonthFirstDay - oneDay); + + return { + // first: this.getDateAll(dateFirter), + // last: this.getDateAll(dateLast), + firstDate: dateFirter, + lastDate: dateLast + }; + }, + // 计算天数 + getDayBetweenDate (date) { + date = this.getDate(new Date(date), 'YMD'); + let startTime = Date.parse(new Date(date)); // IE支持“yyyy/MM/dd”格式 + let endTime = Date.parse(this.getDate(new Date(), 'YMD')); + let day = parseInt((endTime - startTime) / (1000 * 60 * 60 * 24)); + return day; + }, + getDateIntervalYear (firstDate, secondDate) { + if (!firstDate || !secondDate) { + return 0; + } + let first = new Date(firstDate); + let second = new Date(secondDate); + let firstYear = first.getFullYear(); + let secondYear = second.getFullYear(); + let intervalYear = secondYear - firstYear; + return intervalYear < 0 ? 0 : intervalYear; + }, + getDateIntervalYearFixed2 (firstDate, secondDate) { + if (!firstDate || !secondDate) { + return 0; + } + // 格式化时间 + let startDate = new Date(this.getDate(new Date(firstDate), 'YMD')); + let endDate = new Date(this.getDate(new Date(secondDate), 'YMD')); + // 得到毫秒值 + let startTime = Date.parse(startDate); + let endTime = Date.parse(endDate); + // 得到差了多少天 + let day = parseInt((endTime - startTime) / (1000 * 60 * 60 * 24)); + if (day <= 0) { + return 0; + } + // 得到差的多少年 保留两位小数 + let resultYear = parseFloat((day / (30 * 12)).toFixed(2)); + return resultYear; + }, + // 数字转化为中文大写 + // 代码如下所示: + convertCurrency (money) { + // 汉字的数字 + let cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']; + // 基本单位 + let cnIntRadice = ['', '拾', '佰', '仟']; + // 对应整数部分扩展单位 + let cnIntUnits = ['', '万', '亿', '兆']; + // 对应小数部分单位 + let cnDecUnits = ['角', '分', '毫', '厘']; + // 整数金额时后面跟的字符 + let cnInteger = '整'; + // 整型完以后的单位 + let cnIntLast = '元'; + // 最大处理的数字 + let maxNum = 999999999999999.9999; + // 金额整数部分 + let integerNum; + // 金额小数部分 + let decimalNum; + // 输出的中文金额字符串 + let chineseStr = ''; + // 分离金额后用的数组,预定义 + let parts; + if (money === '') { + return ''; + } + money = parseFloat(money); + if (money >= maxNum) { + // 超出最大处理数字 + return ''; + } + if (money === 0) { + chineseStr = cnNums[0] + cnIntLast + cnInteger; + return chineseStr; + } + // 转换为字符串 + money = money.toString(); + if (money.indexOf('.') === -1) { + integerNum = money; + decimalNum = ''; + } else { + parts = money.split('.'); + integerNum = parts[0]; + decimalNum = parts[1].substr(0, 4); + } + // 获取整型部分转换 + if (parseInt(integerNum, 10) > 0) { + let zeroCount = 0; + let IntLen = integerNum.length; + for (let i = 0; i < IntLen; i++) { + let n = integerNum.substr(i, 1); + let p = IntLen - i - 1; + let q = p / 4; + let m = p % 4; + if (n === '0') { + zeroCount++; + } else { + if (zeroCount > 0) { + chineseStr += cnNums[0]; + } + // 归零 + zeroCount = 0; + chineseStr += cnNums[parseInt(n)] + cnIntRadice[m]; + } + if (m === 0 && zeroCount < 4) { + chineseStr += cnIntUnits[q]; + } + } + chineseStr += cnIntLast; + } + // 小数部分 + if (decimalNum !== '') { + let decLen = decimalNum.length; + for (let i = 0; i < decLen; i++) { + let n = decimalNum.substr(i, 1); + if (n !== '0') { + chineseStr += cnNums[Number(n)] + cnDecUnits[i]; + } + } + } + if (chineseStr === '') { + chineseStr += cnNums[0] + cnIntLast + cnInteger; + } else if (decimalNum === '') { + chineseStr += cnInteger; + } + return chineseStr; + } +}; diff --git a/front/src/locale/index.js b/front/src/locale/index.js new file mode 100644 index 00000000..e9dd62c3 --- /dev/null +++ b/front/src/locale/index.js @@ -0,0 +1,37 @@ +import Vue from 'vue'; +import VueI18n from 'vue-i18n'; +import { localRead } from '@/lib/local'; +import customZhCn from './lang/zh-CN'; +import customZhTw from './lang/zh-TW'; +import customEnUs from './lang/en-US'; +import zhCnLocale from 'iview/src/locale/lang/zh-CN'; +import enUsLocale from 'iview/src/locale/lang/en-US'; +import zhTwLocale from 'iview/src/locale/lang/zh-TW'; + +Vue.use(VueI18n); + +// 自动根据浏览器系统语言设置语言 +const navLang = navigator.language; +const localLang = (navLang === 'zh-CN' || navLang === 'en-US') ? navLang : false; +let lang = localLang || localRead('local') || 'zh-CN'; + +Vue.config.lang = lang; + +// vue-i18n 6.x+写法 +Vue.locale = () => { }; +const messages = { + 'zh-CN': Object.assign(zhCnLocale, customZhCn), + 'zh-TW': Object.assign(zhTwLocale, customZhTw), + 'en-US': Object.assign(enUsLocale, customEnUs) +}; +const i18n = new VueI18n({ + locale: lang, + messages +}); + +export default i18n; + +// vue-i18n 5.x写法 +// Vue.locale('zh-CN', Object.assign(zhCnLocale, customZhCn)) +// Vue.locale('en-US', Object.assign(zhTwLocale, customZhTw)) +// Vue.locale('zh-TW', Object.assign(enUsLocale, customEnUs)) diff --git a/front/src/locale/lang/en-US.js b/front/src/locale/lang/en-US.js new file mode 100644 index 00000000..dc20d8f6 --- /dev/null +++ b/front/src/locale/lang/en-US.js @@ -0,0 +1,46 @@ +export default { + home: 'Home', + login: 'Login', + components: 'Components', + count_to_page: 'Count-to', + tables_page: 'Table', + split_pane_page: 'Split-pane', + markdown_page: 'Markdown-editor', + editor_page: 'Rich-Text-Editor', + icons_page: 'Custom-icon', + img_cropper_page: 'Image-editor', + update: 'Update', + doc: 'Document', + join_page: 'QQ Group', + update_table_page: 'Update .CSV', + update_paste_page: 'Paste Table Data', + multilevel: 'multilevel', + directive_page: 'Directive', + level_1: 'Level-1', + level_2: 'Level-2', + level_2_1: 'Level-2-1', + level_2_3: 'Level-2-3', + level_2_2: 'Level-2-2', + level_2_2_1: 'Level-2-2-1', + level_2_2_2: 'Level-2-2-2', + excel: 'Excel', + 'upload-excel': 'Upload Excel', + 'export-excel': 'Export Excel', + tools_methods_page: 'Tools Methods', + drag_list_page: 'Drag-list', + i18n_page: 'Internationalization', + modalTitle: 'Modal Title', + content: 'This is the modal box content.', + buttonText: 'Show Modal', + 'i18n-tip': 'Note: Only this page is multi-language, other pages do not add language content to the multi-language package.', + error_store_page: 'Error Collection', + error_logger_page: 'Error Logger', + query: 'Query', + params: 'Params', + cropper_page: 'Cropper', + message_page: 'Message Center', + tree_table_page: 'Tree Table', + org_tree_page: 'Org Tree', + drag_drawer_page: 'Draggable Drawer', + tree_select_page: 'Tree Selector' +} diff --git a/front/src/locale/lang/zh-CN.js b/front/src/locale/lang/zh-CN.js new file mode 100644 index 00000000..9e402562 --- /dev/null +++ b/front/src/locale/lang/zh-CN.js @@ -0,0 +1,46 @@ +export default { + home: '首页', + login: '登录', + components: '组件', + count_to_page: '数字渐变', + tables_page: '多功能表格', + split_pane_page: '分割窗口', + markdown_page: 'Markdown编辑器', + editor_page: '富文本编辑器', + icons_page: '自定义图标', + img_cropper_page: '图片编辑器', + update: '上传数据', + join_page: 'QQ群', + doc: '文档', + update_table_page: '上传CSV文件', + update_paste_page: '粘贴表格数据', + multilevel: '多级菜单', + directive_page: '指令', + level_1: 'Level-1', + level_2: 'Level-2', + level_2_1: 'Level-2-1', + level_2_3: 'Level-2-3', + level_2_2: 'Level-2-2', + level_2_2_1: 'Level-2-2-1', + level_2_2_2: 'Level-2-2-2', + excel: 'Excel', + 'upload-excel': '上传excel', + 'export-excel': '导出excel', + tools_methods_page: '工具函数', + drag_list_page: '拖拽列表', + i18n_page: '多语言', + modalTitle: '模态框题目', + content: '这是模态框内容', + buttonText: '显示模态框', + 'i18n-tip': '注:仅此页做了多语言,其他页面没有在多语言包中添加语言内容', + error_store_page: '错误收集', + error_logger_page: '错误日志', + query: '带参路由', + params: '动态路由', + cropper_page: '图片裁剪', + message_page: '消息中心', + tree_table_page: '树状表格', + org_tree_page: '组织结构树', + drag_drawer_page: '可拖动抽屉', + tree_select_page: '树状下拉选择器' +} diff --git a/front/src/locale/lang/zh-TW.js b/front/src/locale/lang/zh-TW.js new file mode 100644 index 00000000..ce51c428 --- /dev/null +++ b/front/src/locale/lang/zh-TW.js @@ -0,0 +1,46 @@ +export default { + home: '首頁', + login: '登錄', + components: '组件', + count_to_page: '数字渐变', + tables_page: '多功能表格', + split_pane_page: '分割窗口', + markdown_page: 'Markdown編輯器', + editor_page: '富文本編輯器', + icons_page: '自定義圖標', + img_cropper_page: '圖片編輯器', + update: '上傳數據', + join_page: 'QQ群', + doc: '文檔', + update_table_page: '上傳CSV文件', + update_paste_page: '粘貼表格數據', + multilevel: '多级菜单', + directive_page: '指令', + level_1: 'Level-1', + level_2: 'Level-2', + level_2_1: 'Level-2-1', + level_2_3: 'Level-2-3', + level_2_2: 'Level-2-2', + level_2_2_1: 'Level-2-2-1', + level_2_2_2: 'Level-2-2-2', + excel: 'Excel', + 'upload-excel': '上傳excel', + 'export-excel': '導出excel', + tools_methods_page: '工具函數', + drag_list_page: '拖拽列表', + i18n_page: '多語言', + modalTitle: '模態框題目', + content: '這是模態框內容', + buttonText: '顯示模態框', + 'i18n-tip': '注:僅此頁做了多語言,其他頁面沒有在多語言包中添加語言內容', + error_store_page: '錯誤收集', + error_logger_page: '錯誤日誌', + query: '帶參路由', + params: '動態路由', + cropper_page: '圖片裁剪', + message_page: '消息中心', + tree_table_page: '樹狀表格', + org_tree_page: '組織結構樹', + drag_drawer_page: '可拖動抽屜', + tree_select_page: '樹狀下拉選擇器' +} diff --git a/front/src/main.js b/front/src/main.js new file mode 100644 index 00000000..7a1e8807 --- /dev/null +++ b/front/src/main.js @@ -0,0 +1,64 @@ +// The Vue build version to load with the `import` command +// (runtime-only or standalone) has been set in webpack.base.conf with an alias. +import Vue from 'vue'; +import App from './App'; +import router from './router'; +import store from './store'; +import iView from 'iview'; +import i18n from '@/locale'; +import config from '@/config'; +import importDirective from '@/directives'; +import JsonViewer from 'vue-json-viewer'; +import _ from 'lodash'; +// import { directive as clickOutside } from 'v-click-outside-x'; +import * as vClickOutside from 'v-click-outside-x'; +import installPlugin from '@/plugins'; +import './themes/index.less'; +import '@/assets/icons/iconfont.css'; +import 'slick-carousel/slick/slick.css'; +import { Decimal } from 'decimal.js'; +// 枚举管理 +import Enum from 'vue-enum'; +import enumInfo from '@/constants'; +// 处理table操作按钮 +import tableAction from './lib/table-action'; +Vue.prototype.$tableAction = tableAction; +Vue.use(Enum, { enumInfo }); +Vue.use(iView, { + i18n: (key, value) => i18n.t(key, value) +}); +Vue.use(JsonViewer); +Vue.use(vClickOutside); +Number.prototype.toFixed = function (length) { + let x = new Decimal(this); + return x.toFixed(length); +}; + +/** + * @description 注册admin内置插件 + */ +installPlugin(Vue); +/** + * @description 生产环境关掉提示 + */ +Vue.config.productionTip = false; +/** + * @description 全局注册应用配置 + */ +Vue.prototype.$config = config; +/** + * 注册指令 + */ +importDirective(Vue); +// Vue.directive('clickOutside', clickOutside); + +window._ = _; + +/* eslint-disable no-new */ +new Vue({ + el: '#app', + router, + i18n, + store, + render: h => h(App) +}); diff --git a/front/src/main.less b/front/src/main.less new file mode 100644 index 00000000..72a1a030 --- /dev/null +++ b/front/src/main.less @@ -0,0 +1,37 @@ +.warp-card { + margin-top: 10px; + &:first-child { + margin-top: 0; + } + .action-show { + .ivu-btn { + margin: 0 3px; + } + } + .action-hide { + .ivu-btn { + margin: 0 3px; + span { + //display: none; + } + } + } + .add-form { + padding-top: 15px; + } +} +.areaSelect .areaBox .areaArrow.active { + border-color: #689df6 !important; +} + +.areaSelect .areaBox .areaInput:hover, .areaSelect .areaBox .areaInput:focus { + border-color: #689df6 !important; +} + +.areaSelect .areaBox .areaModal ul li.active[data-v-16a01167] { + background: #fff !important; + color: #689df6 !important; +} +.main{ + .side-menu-wrapper .ivu-menu-dark .ivu-menu .ivu-menu-submenu-has-parent-submenu{ padding-left: 41px; } +} diff --git a/front/src/plugins/error-store/index.js b/front/src/plugins/error-store/index.js new file mode 100644 index 00000000..c8b35b8f --- /dev/null +++ b/front/src/plugins/error-store/index.js @@ -0,0 +1,4 @@ +import store from '@/store'; +export default { + install(Vue, options) {} +}; diff --git a/front/src/plugins/index.js b/front/src/plugins/index.js new file mode 100644 index 00000000..1a1c1870 --- /dev/null +++ b/front/src/plugins/index.js @@ -0,0 +1,12 @@ +import config from '@/config'; +const { plugin } = config; + +export default Vue => { + for (let name in plugin) { + const value = plugin[name]; + Vue.use( + require(`./${name}`).default, + typeof value === 'object' ? value : undefined + ); + } +}; diff --git a/front/src/router/before-close.js b/front/src/router/before-close.js new file mode 100644 index 00000000..01ba93d7 --- /dev/null +++ b/front/src/router/before-close.js @@ -0,0 +1,17 @@ +import { Modal } from 'iview'; + +const beforeClose = { + before_close_normal: resolve => { + Modal.confirm({ + title: '确定要关闭这一页吗', + onOk: () => { + resolve(true); + }, + onCancel: () => { + resolve(false); + } + }); + } +}; + +export default beforeClose; diff --git a/front/src/router/index.js b/front/src/router/index.js new file mode 100644 index 00000000..aeaba49c --- /dev/null +++ b/front/src/router/index.js @@ -0,0 +1,142 @@ +import Vue from 'vue'; +import Router from 'vue-router'; +import { routers } from './routers'; +import store from '@/store'; +import iView from 'iview'; +import cookie from '@/lib/cookie'; +import { localRead } from '@/lib/local'; +import { setTitle } from '@/lib/menu-func'; + +Vue.use(Router); +const router = new Router({ + routes: routers + // mode: 'history' +}); +const LOGIN_PAGE_NAME = 'login'; + +// 防止用户刷新丢失登录信息 +if ( + Object.keys(store.state.user.userLoginInfo).length === 0 && + localRead('userLoginInfo') +) { + store.commit('setUserLoginInfo', JSON.parse(localRead('userLoginInfo'))); +} +// 解决路由跳转相同的地址报错 +const originalPush = Router.prototype.push; +Router.prototype.push = function (location) { + try { + return originalPush.call(this, location).catch(err => err); + } catch (error) { + // TODO zhuoda sentry + console.error(error); + } +}; + +// 关于当前页面 +Router.prototype.closeCurrentPage = function () { + let current = this.history.current; + store.commit('closeTag', current); + store.commit('deleteKeepAliveIncludes', current.name); +}; + +// 关闭当前页面然后跳转到指定页面 +Router.prototype.closeCurrentPageAndPush = function (pushParam) { + let current = this.history.current; + store.commit('closeTagNotPushNextRoute', current); + store.commit('deleteKeepAliveIncludes', current.name); + this.push(pushParam); +}; +let storeSelf = store; +router.beforeEach((to, from, next) => { + console.log(to); + iView.LoadingBar.start(); + const token = cookie.getToken(); + if (!token && to.name !== LOGIN_PAGE_NAME) { + // 未登录且要跳转的页面不是登录页 + next({ + name: LOGIN_PAGE_NAME // 跳转到登录页 + }); + } else if (!token && to.name === LOGIN_PAGE_NAME) { + // 未登陆且要跳转的页面是登录页 + next(); // 跳转 + } else if (token && to.name === LOGIN_PAGE_NAME) { + // 已登录且要跳转的页面是登录页 + next({ + name: 'home' // 跳转到home页 + }); + } else { + // 特殊页面直接放行 + if (to.meta.access) { + next(); + return; + } + + // 去掉/之后第一个字母 + let key = to.path.substr(1, 1); + let pathArray = storeSelf.state.user.privilegeRouterPathMap.get(key); + if (!(pathArray && pathArray.indexOf(to.path) >= 0)) { + next({ + name: 'Error401' + }); + } else { + next(); + } + } +}); + +router.afterEach(to => { + setTitle(to, router.app); + iView.LoadingBar.finish(); + window.scrollTo(0, 0); +}); + +let tempCheckObj = { + checkRouterNameMap: new Map(), + checkRouterPathMap: new Map() +}; + +function recursionRouter (routerArray) { + for (let routerItem of routerArray) { + if (!routerItem.name) { + console.error('没有配置router name', routerItem); + } else { + let existNameRouter = tempCheckObj.checkRouterNameMap.get( + routerItem.name + ); + if (typeof existNameRouter !== 'undefined') { + console.error('存在相同的router name', routerItem, existNameRouter); + } else { + tempCheckObj.checkRouterNameMap.set(routerItem.name, routerItem); + } + } + + if (!routerItem.path) { + console.error('没有配置router path', routerItem); + } else { + // path必须以 / 开头 + if (routerItem.path !== '*' && routerItem.path.indexOf('/') !== 0) { + console.error('path 没有以/开头 ', routerItem); + } + + let existPathRouter = tempCheckObj.checkRouterPathMap.get( + routerItem.path + ); + if (typeof existPathRouter !== 'undefined') { + console.error('存在相同的router path', routerItem, existPathRouter); + } else { + tempCheckObj.checkRouterPathMap.set(routerItem.path, routerItem); + } + } + + if (routerItem.children) { + recursionRouter(routerItem.children); + } + } +} + +recursionRouter(routers); + +delete tempCheckObj.checkRouterNameMap; +delete tempCheckObj.checkRouterPathMap; + +export default router; diff --git a/front/src/router/module/api-doc.js b/front/src/router/module/api-doc.js new file mode 100644 index 00000000..5c611a81 --- /dev/null +++ b/front/src/router/module/api-doc.js @@ -0,0 +1,25 @@ +import Main from '@/components/main'; +// 接口文档 +export const apiDoc = [ + { + path: '/api-doc', + component: Main, + name: 'ApiDoc', + meta: { + title: '接口文档', + icon: 'icon iconfont iconjiekouwendang' + }, + + children: [ + { + path: '/api-doc/swagger', + name: 'Swagger', + meta: { + title: 'Swagger接口文档', + icon: 'icon iconfont iconjiekouwendang' + }, + component: () => import('@/views/api-doc/swagger.vue') + } + ] + } +]; diff --git a/front/src/router/module/email.js b/front/src/router/module/email.js new file mode 100644 index 00000000..9fb26781 --- /dev/null +++ b/front/src/router/module/email.js @@ -0,0 +1,40 @@ +import Main from '@/components/main'; +// 基础设置 +export const emailSetting = [ + { + path: '/email', + name: 'Email', + component: Main, + meta: { + title: '邮件管理', + icon: 'icon iconfont iconyoujianguanli' + }, + children: [ + // 发送email + { + path: '/email/email-list', + name: 'EmailList', + meta: { + title: '邮件管理', + childrenPoints: [ + { title: '查询', name: 'email-query' }, + { title: '新增', name: 'email-add' }, + { title: '编辑', name: 'email-update' }, + { title: '删除', name: 'email-delete' } + ] + }, + component: () => import('@/views/email/email-list.vue') + }, + // 发送email + { + path: '/email/send-mail', + name: 'SendMail', + meta: { + title: '发送邮件', + childrenPoints: [{ title: '发送', name: 'email-send' }] + }, + component: () => import('@/views/email/send-mail.vue') + } + ] + } +]; diff --git a/front/src/router/module/employee.js b/front/src/router/module/employee.js new file mode 100644 index 00000000..5c735b6a --- /dev/null +++ b/front/src/router/module/employee.js @@ -0,0 +1,149 @@ +import Main from '@/components/main'; +// 基础设置 +export const employee = [ + { + path: '/employee', + component: Main, + name: 'Employee', + meta: { + title: '人员管理', + icon: 'icon iconfont iconrenyuanguanli' + }, + children: [ + // 角色管理页面路由 + { + path: '/employee/role', + name: 'RoleManage', + meta: { + title: '角色管理', + childrenPoints: [ + { + title: '添加角色', + name: 'add-role' + }, + { + title: '删除角色', + name: 'delete-role' + }, + { + title: '编辑角色', + name: 'update-role' + }, + { + title: '修改角色权限', + name: 'update-role-privilege' + }, + { + title: '添加成员', + name: 'add-employee-role' + }, + { + title: '移除成员', + name: 'delete-employee-role' + }, + { + title: '批量移除', + name: 'delete-employee-role-batch' + }, + { + title: '查询成员', + name: 'search-employee-list' + }, + { + title: '查询数据范围', + name: 'query-data-scope' + }, + { + title: '更新数据范围', + name: 'update-data-scope' + } + ] + }, + component: () => import('@/views/employee/role/role-manage.vue') + }, + // 岗位管理页面路由 新 + { + path: '/employee/position', + name: 'PositionList', + meta: { + title: '岗位管理', + childrenPoints: [ + { + title: '查询', + name: 'search-position' + }, + { + title: '添加', + name: 'add-position' + }, + { + title: '修改', + name: 'update-position' + }, + { + title: '删除', + name: 'delete-position' + } + ] + }, + component: () => import('@/views/employee/position/position-list.vue') + }, + // 人员管理页面路由 + { + path: '/employee/role-employee-manage', + name: 'RoleEmployeeManage', + meta: { + title: '员工管理', + childrenPoints: [ + { + title: '添加部门', + name: 'add-department' + }, + { + title: '编辑部门', + name: 'update-department' + }, + { + title: '删除部门', + name: 'delete-department' + }, + { + title: '查询', + name: 'search-department' + }, + { + title: '添加成员', + name: 'add-employee' + }, + { + title: '编辑成员', + name: 'update-employee' + }, + { + title: '禁用', + name: 'disabled-employee' + }, + { + title: '批量操作', + name: 'disabled-employee-batch' + }, + { + title: '员工角色编辑', + name: 'update-employee-role' + }, + { + title: '删除员工', + name: 'delete-employee' + }, + { + title: '重置密码', + name: 'reset-employee-password' + } + ] + }, + component: () => + import('@/views/employee/role-employee/role-employee-manage.vue') + } + ] + } +]; diff --git a/front/src/router/module/error.js b/front/src/router/module/error.js new file mode 100644 index 00000000..3c890ce3 --- /dev/null +++ b/front/src/router/module/error.js @@ -0,0 +1,30 @@ +// 错误页 +export const error = [ + { + path: '/401', + name: 'Error401', + meta: { + hideInMenu: true, + access: true + }, + component: () => import('@/views/error-page/401.vue') + }, + { + path: '/500', + name: 'Error500', + meta: { + hideInMenu: true, + access: true + }, + component: () => import('@/views/error-page/500.vue') + }, + { + path: '*', + name: 'http://localhost:8080/#employee/role-employee-manage', + meta: { + hideInMenu: true, + access: true + }, + component: () => import('@/views/error-page/404.vue') + } +]; diff --git a/front/src/router/module/file.js b/front/src/router/module/file.js new file mode 100644 index 00000000..ac77299a --- /dev/null +++ b/front/src/router/module/file.js @@ -0,0 +1,29 @@ +import Main from '@/components/main'; +// 文件服务 +export const file = [ + { + path: '/file', + name: 'File', + component: Main, + meta: { + title: '文件服务', + icon: 'ios-cloud-upload' + }, + children: [ + { + path: '/file/file-list', + name: 'FileList', + meta: { + title: '文件列表', + icon: 'ios-cloud-upload', + childrenPoints: [ + { title: '查询', name: 'file-filePage-query' }, + { title: '上传', name: 'file-filePage-upload' }, + { title: '下载', name: 'file-filePage-download' } + ] + }, + component: () => import('@/views/file/file-list.vue') + } + ] + } +]; diff --git a/front/src/router/module/heart-beat.js b/front/src/router/module/heart-beat.js new file mode 100644 index 00000000..99dfbb9e --- /dev/null +++ b/front/src/router/module/heart-beat.js @@ -0,0 +1,31 @@ +import Main from '@/components/main'; +// 心跳服务 +export const heartBeat = [ + { + path: '/heart-beat', + name: 'HeartBeat', + component: Main, + meta: { + title: '心跳服务', + icon: 'icon iconfont icondingshirenwu' + }, + + children: [ + { + path: '/heart-beat/heart-beat-list', + name: 'HeartBeatList', + meta: { + title: '心跳服务', + icon: 'icon iconfont icondingshirenwu', + childrenPoints: [ + { + title: '查询任务', + name: 'heart-beat-query' + } + ] + }, + component: () => import('@/views/heart-beat/heart-beat-list.vue') + } + ] + } +]; diff --git a/front/src/router/module/home.js b/front/src/router/module/home.js new file mode 100644 index 00000000..e843b3b6 --- /dev/null +++ b/front/src/router/module/home.js @@ -0,0 +1,28 @@ +import Main from '@/components/main'; +// 首页 +export const home = [ + { + path: '/', + name: '_home', + redirect: '/home', + component: Main, + meta: { + noKeepAlive: true, + hideInMenu: true, + access: true, + icon: 'icon iconfont iconxitongshezhi' + }, + children: [ + { + path: '/home', + name: 'Home', + meta: { + title: '首页', + access: true, + noKeepAlive: true + }, + component: () => import('@/views/home') + } + ] + } +]; diff --git a/front/src/router/module/keep-alive.js b/front/src/router/module/keep-alive.js new file mode 100644 index 00000000..38ef2173 --- /dev/null +++ b/front/src/router/module/keep-alive.js @@ -0,0 +1,31 @@ +import Main from '@/components/main'; +// 接口文档 +export const keepAlive = [ + { + path: '/keep-alive', + name: 'KeepAlive', + component: Main, + meta: { + title: 'KeepAlive', + icon: 'icon iconfont iconxitongshezhi' + }, + children: [ + { + path: '/keep-alive/content-list', + name: 'KeepAliveContentList', + meta: { + title: 'KeepAlive列表' + }, + component: () => import('@/views/keep-alive/content-list.vue') + }, + { + path: '/keep-alive/add-content', + name: 'KeepAliveAddContent', + meta: { + title: 'KeepAlive表单' + }, + component: () => import('@/views/keep-alive/add-content.vue') + } + ] + } +]; diff --git a/front/src/router/module/monitor.js b/front/src/router/module/monitor.js new file mode 100644 index 00000000..c072f4fd --- /dev/null +++ b/front/src/router/module/monitor.js @@ -0,0 +1,33 @@ +import Main from '@/components/main'; +// 系统监控 +export const monitor = [ + { + path: '/monitor', + component: Main, + name: 'Monitor', + meta: { + title: '系统监控', + icon: 'icon iconfont iconxitongjiankong' + }, + children: [ + { + path: '/monitor/online-user', + name: 'OnlineUser', + meta: { + title: '在线人数', + childrenPoints: [{ title: '查询', name: 'online-user-search' }] + }, + component: () => import('@/views/monitor/online-user.vue') + }, + // SQL监控 + { + path: '/monitor/sql', + name: 'Sql', + meta: { + title: 'SQL监控' + }, + component: () => import('@/views/monitor/sql.vue') + } + ] + } +]; diff --git a/front/src/router/module/notice.js b/front/src/router/module/notice.js new file mode 100644 index 00000000..ea4c6f4c --- /dev/null +++ b/front/src/router/module/notice.js @@ -0,0 +1,43 @@ +import Main from '@/components/main'; +// 消息管理 +export const notice = [ + { + path: '/notice', + name: 'Notice', + component: Main, + meta: { + title: '消息管理', + icon: 'icon iconfont iconnews' + }, + children: [ + { + path: '/notice/notice-list', + name: 'NoticeList', + meta: { + title: '通知管理', + childrenPoints: [ + { title: '查询', name: 'notice-query' }, + { title: '添加', name: 'notice-add' }, + { title: '修改', name: 'notice-edit' }, + { title: '删除', name: 'notice-delete' }, + { title: '详情', name: 'notice-detail' }, + { title: '发送', name: 'notice-send' } + ] + }, + component: () => import('@/views/notice/notice-list.vue') + }, + { + path: '/notice/person-notice', + name: 'PersonNotice', + meta: { + title: '个人消息', + childrenPoints: [ + { title: '查询', name: 'person-notice-query' }, + { title: '详情', name: 'person-notice-detail' } + ] + }, + component: () => import('@/views/notice/person-notice.vue') + } + ] + } +]; diff --git a/front/src/router/module/reload.js b/front/src/router/module/reload.js new file mode 100644 index 00000000..958bd2d7 --- /dev/null +++ b/front/src/router/module/reload.js @@ -0,0 +1,40 @@ +import Main from '@/components/main'; +// 动态加载 +export const reload = [ + { + path: '/reload', + name: 'Reload', + component: Main, + meta: { + title: '动态加载', + icon: 'icon iconfont icondongtaijiazai' + }, + + children: [ + { + path: '/reload/smart-reload-list', + name: 'SmartReloadList', + meta: { + title: 'SmartReload', + icon: 'icon iconfont icondongtaijiazai', + childrenPoints: [ + { + title: '查询', + name: 'smart-reload-search' + }, + { + title: '执行reload', + name: 'smart-reload-update' + }, + { + title: '查看执行结果', + name: 'smart-reload-result' + } + ] + }, + component: () => + import('@/views/reload/smart-reload/smart-reload-list.vue') + } + ] + } +]; diff --git a/front/src/router/module/system-setting.js b/front/src/router/module/system-setting.js new file mode 100644 index 00000000..e85884f8 --- /dev/null +++ b/front/src/router/module/system-setting.js @@ -0,0 +1,62 @@ +import Main from '@/components/main'; +// 基础设置 +export const systemSetting = [ + { + path: '/system-setting', + name: 'SystemSetting', + component: Main, + meta: { + title: '系统设置', + icon: 'icon iconfont iconxitongshezhi' + }, + + children: [ + { + path: '/system-setting/system-config', + name: 'SystemConfig', + meta: { + title: '系统参数', + childrenPoints: [ + { + title: '查询系统参数', + name: 'system-params-search' + }, + { + title: '添加系统参数', + name: 'system-params-add' + }, + { + title: '修改系统参数', + name: 'system-config-update' + }, + { + title: '搜索系统参数', + name: 'system-config-search' + } + ] + }, + component: () => + import('@/views/system-setting/system-config/system-config.vue') + }, + { + path: '/system-setting/system-privilege', + name: 'SystemPrivilege', + meta: { + title: '菜单管理', + childrenPoints: [ + { + title: '编辑', + name: 'privilege-main-update' + }, + { + title: '查询', + name: 'privilege-main-search' + } + ] + }, + component: () => + import('@/views/system-setting/system-privilege/system-privilege.vue') + } + ] + } +]; diff --git a/front/src/router/module/task.js b/front/src/router/module/task.js new file mode 100644 index 00000000..7779e2ae --- /dev/null +++ b/front/src/router/module/task.js @@ -0,0 +1,63 @@ +import Main from '@/components/main'; +// 任务调度 +export const task = [ + { + path: '/task', + name: 'Task', + component: Main, + meta: { + title: '定时任务', + icon: 'icon iconfont icondingshirenwu' + }, + + children: [ + { + path: '/system-setting/task-list', + name: 'TaskList', + meta: { + title: '任务管理', + icon: 'icon iconfont icondingshirenwu', + childrenPoints: [ + { + title: '查询任务', + name: 'task-search' + }, + { + title: '刷新任务', + name: 'task-refresh' + }, + { + title: '添加任务', + name: 'task-add' + }, + { + title: '编辑任务', + name: 'task-update' + }, + { + title: '暂停任务', + name: 'task-pause' + }, + { + title: '恢复任务', + name: 'task-resume' + }, + { + title: '立即运行任务', + name: 'task-run' + }, + { + title: '查看任务日志', + name: 'task-query-log' + }, + { + title: '删除任务', + name: 'task-delete' + } + ] + }, + component: () => import('@/views/task/task-list.vue') + } + ] + } +]; diff --git a/front/src/router/module/three-router.js b/front/src/router/module/three-router.js new file mode 100644 index 00000000..b1a9a409 --- /dev/null +++ b/front/src/router/module/three-router.js @@ -0,0 +1,62 @@ +import Main from '@/components/main'; +// 三级路由演示 +export const threeRouter = [ + { + path: '/three-router', + name: 'ThreeRouter', + component: Main, + meta: { + title: '三级路由', + icon: 'icon iconfont iconzujian' + }, + children: [ + // 最大支持到三级菜单 + { + path: '/three-router/level-two', + name: 'LevelTwo', + meta: { + title: '三级菜单' + }, + component: () => import('@/views/home'), + children: [ + { + path: '/three-router/level-two/level-three1', + name: 'RoleOneTwo', + meta: { + title: '三级A', + childrenPoints: [ + { title: '添加', name: 'roleOneTwo-add' }, + { title: '删除', name: 'roleOneTwo-delete' } + ] + }, + component: () => import('@/views/home') + }, + { + path: '/three-router/level-two/level-three2', + name: 'RoleTwoTwo', + meta: { + title: '三级B', + childrenPoints: [ + { title: '添加', name: 'roleTwoTwo-add' }, + { title: '删除', name: 'roleTwoTwo-delete' } + ] + }, + component: () => import('@/views/home') + } + ] + }, + { + path: '/three-router/level-two2', + name: 'RoleOneOne', + meta: { + title: '二级菜单', + childrenPoints: [ + { title: '添加', name: 'roleOneOne-add' }, + { title: '删除', name: 'roleOneOne-delete' } + ] + }, + component: () => import('@/views/home') + } + ] + } +]; diff --git a/front/src/router/module/user-log.js b/front/src/router/module/user-log.js new file mode 100644 index 00000000..15765ffb --- /dev/null +++ b/front/src/router/module/user-log.js @@ -0,0 +1,42 @@ +import Main from '@/components/main'; +// 用户日志 +export const userLog = [ + { + path: '/user-log', + name: 'UserLog', + component: Main, + meta: { + title: '用户日志', + icon: 'ios-paper-outline' + }, + children: [ + // 发送email + { + path: '/user-log/user-operate-log', + name: 'UserOperateLog', + meta: { + title: '用户操作日志', + childrenPoints: [ + { title: '查询', name: 'user-operate-log-search' }, + { title: '详情', name: 'user-operate-log-detail' }, + { title: '删除', name: 'user-operate-log-delete' } + ] + }, + component: () => import('@/views/user-log/user-operate-log.vue') + }, + // 人员管理页面路由 + { + path: '/user-log/user-login-log', + name: 'UserLoginLog', + meta: { + title: '用户登录日志', + childrenPoints: [ + { title: '查询', name: 'user-login-log-search' }, + { title: '删除', name: 'user-login-log-delete' } + ] + }, + component: () => import('@/views/user-log/user-login-log.vue') + } + ] + } +]; diff --git a/front/src/router/routers.js b/front/src/router/routers.js new file mode 100644 index 00000000..25492ecf --- /dev/null +++ b/front/src/router/routers.js @@ -0,0 +1,61 @@ +import { home } from './module/home'; +import { employee } from './module/employee'; +import { systemSetting } from './module/system-setting'; +import { notice } from './module/notice'; +import { emailSetting } from './module/email'; +import { monitor } from './module/monitor'; +import { userLog } from './module/user-log'; +import { error } from './module/error'; +import { task } from './module/task'; +import { reload } from './module/reload'; +import { apiDoc } from './module/api-doc'; +import { threeRouter } from './module/three-router'; +import { keepAlive } from './module/keep-alive'; +import { heartBeat } from './module/heart-beat'; +import { file } from './module/file'; + +/** + * + * iview-admin中meta除了原生参数外可配置的参数: + * meta: { + * title: { String|Number|Function } + * 显示在侧边栏、面包屑和标签栏的文字 + * 使用'{{ 多语言字段 }}'形式结合多语言使用,例子看多语言的路由配置; + * 可以传入一个回调函数,参数是当前路由对象,例子看动态路由和带参路由 + * hideInBread: (false) 设为true后此级路由将不会出现在面包屑中,示例看QQ群路由配置 + * hideInMenu: (false) 设为true后在左侧菜单不会显示该页面选项, + * group:{String} 同一功能模块下子页面的功能点权限继承菜单模块创建的路由权限 by lihaifan&lipeng + * noKeepAlive: (false) 设为true后页面在切换标签后不会缓存,如果需要缓存,无需设置这个字段,而且需要设置页面组件name属性和路由配置的name一致 + * access: (null) 可访问该页面的权限数组,当前路由设置的权限会影响子路由 + * } + */ +// 登录模块 +export const login = { + path: '/login', + name: 'login', + meta: { + hideInMenu: true, + title: 'Login - 登录' + }, + component: () => import('@/views/login/login.vue') +}; + +// 全部路由 +export const routers = [ + login, + ...home, + ...employee, + ...systemSetting, + ...notice, + ...emailSetting, + ...userLog, + ...monitor, + ...error, + ...task, + ...reload, + ...apiDoc, + ...threeRouter, + ...keepAlive, + ...heartBeat, + ...file +]; diff --git a/front/src/store/index.js b/front/src/store/index.js new file mode 100644 index 00000000..6883f539 --- /dev/null +++ b/front/src/store/index.js @@ -0,0 +1,25 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; + +import user from './module/user'; +import app from './module/app'; +import notice from './module/notice'; + +Vue.use(Vuex); + +export default new Vuex.Store({ + state: { + // + }, + mutations: { + // + }, + actions: { + // + }, + modules: { + user, + notice, + app + } +}); diff --git a/front/src/store/module/app.js b/front/src/store/module/app.js new file mode 100644 index 00000000..b7c028c3 --- /dev/null +++ b/front/src/store/module/app.js @@ -0,0 +1,131 @@ +import { + getBreadCrumbList, + setTagNavListInLocalStorage, + getMenuByRouter, + getTagNavListFromLocalStorage, + getHomeRoute, + getNextRoute, + routeHasExist, + routeEqual, + getRouteTitleHandled +} from '@/lib/menu-func'; +import { localSave, localRead } from '@/lib/local'; +import router from '@/router'; +import { routers } from '@/router/routers'; +import config from '@/config'; +const { homeName } = config; +// 关闭页面+tag +const closePage = (state, route) => { + const nextRoute = getNextRoute(state.tagNavList, route); + state.tagNavList = state.tagNavList.filter(item => { + return !routeEqual(item, route); + }); + router.push(nextRoute); +}; + +export default { + state: { + // 缓存路由 + keepAliveIncludes: [], + // 面包屑列表 + breadCrumbList: [], + // tag列表 + tagNavList: [], + // 首页路由 + homeRoute: {}, + // 本地缓存 + local: localRead('local'), + // 错误列表 + errorList: [], + hasReadErrorPage: false + }, + getters: { + // 左侧菜单 + menuList: (state, getters, rootState) => + getMenuByRouter(routers, rootState.user.access), + errorCount: state => state.errorList.length + }, + mutations: { + // 加入缓存 + pushKeepAliveIncludes (state, val) { + if (state.keepAliveIncludes.length < 30) { + let number = state.keepAliveIncludes.findIndex(e => e === val); + if (number === -1) { + state.keepAliveIncludes.push(val); + } + } + }, + // 删除缓存 + deleteKeepAliveIncludes (state, val) { + let number = state.keepAliveIncludes.findIndex(e => e === val); + if (number !== -1) { + state.keepAliveIncludes.splice(number, 1); + } + }, + // 清空缓存 + clearKeepAliveIncludes (state, val) { + state.keepAliveIncludes = [val]; + }, + // 关闭其他 + deleteOtherKeepAliveIncludes (state, val) { + state.keepAliveIncludes.forEach((item, index, arr) => { + if (item !== config.homeName && item !== val) { + arr.splice(index, 1); + } + }); + }, + // 设置其是否出现在面包屑中 + setBreadCrumb (state, route) { + state.breadCrumbList = getBreadCrumbList(route, state.homeRoute); + }, + // 初始化首页使用 + setHomeRoute (state, routes) { + state.homeRoute = getHomeRoute(routes, homeName); + }, + // 设置tag列表 + setTagNavList (state, list) { + let tagList = []; + if (list) { + tagList = [...list]; + } else tagList = getTagNavListFromLocalStorage() || []; + if (tagList[0] && tagList[0].name !== homeName) tagList.shift(); + let homeTagIndex = tagList.findIndex(item => item.name === homeName); + if (homeTagIndex > 0) { + let homeTag = tagList.splice(homeTagIndex, 1)[0]; + tagList.unshift(homeTag); + } + state.tagNavList = tagList; + setTagNavListInLocalStorage([...tagList]); + }, + // 关闭tag + closeTag (state, route) { + let tag = state.tagNavList.filter(item => routeEqual(item, route)); + route = tag[0] ? tag[0] : null; + if (!route) return; + closePage(state, route); + }, + // 关闭当前tag,且不进行跳转 + closeTagNotPushNextRoute (state, route) { + state.tagNavList = state.tagNavList.filter(item => { + return !routeEqual(item, route); + }); + }, + // 新增tag + addTag (state, { route, type = 'unshift' }) { + let router = getRouteTitleHandled(route); + if (!routeHasExist(state.tagNavList, router)) { + if (type === 'push') state.tagNavList.push(router); + else { + if (router.name === homeName) state.tagNavList.unshift(router); + else state.tagNavList.splice(1, 0, router); + } + setTagNavListInLocalStorage([...state.tagNavList]); + } + }, + // 保存本地信息 + setLocal (state, lang) { + localSave('local', lang); + state.local = lang; + } + } +}; diff --git a/front/src/store/module/notice.js b/front/src/store/module/notice.js new file mode 100644 index 00000000..3cff149e --- /dev/null +++ b/front/src/store/module/notice.js @@ -0,0 +1,19 @@ +import { noticeApi } from '@/api/notice'; +export default { + state: { + noticeList: [], + noticeNumber: 0 + }, + mutations: { + updateNotice(state, data) { + state.noticeList = [...state.noticeList, ...data]; + }, + updateNoticeNum(state, data) { + state.noticeNumber = data; + }, + restNotice(state) { + state.noticeList = []; + state.noticeNumber = 0; + } + } +}; diff --git a/front/src/store/module/user.js b/front/src/store/module/user.js new file mode 100644 index 00000000..eb2ca10a --- /dev/null +++ b/front/src/store/module/user.js @@ -0,0 +1,122 @@ +import cookie from '@/lib/cookie.js'; +import { loginApi } from '@/api/login'; +import { localSave, localRead } from '@/lib/local'; +import { getType } from '@/lib/util'; +import { PRIVILEGE_TYPE_ENUM } from '@/constants/privilege'; + +const localReadRouterPrivilege = () => { + let map = new Map(); + let userRouterPrivilegeString = localRead('userRouterPrivilege'); + if (userRouterPrivilegeString) { + let privilegeList = JSON.parse(userRouterPrivilegeString); + if (privilegeList) { + for (const path of privilegeList) { + let key = path.substr(1, 1); + let pathArray = map.get(key); + if (pathArray) { + pathArray.push(path); + } else { + pathArray = []; + pathArray.push(path); + map.set(key, pathArray); + } + } + } + } + return map; +}; + +export default { + state: { + token: cookie.getToken(), + // session信息 + userLoginInfo: {}, + isUpdatePrivilege: false, + // key为router name, value为 key的集合,用于v-privilege,页面功能点判断 + privilegeFunctionPointsMap: new Map(), + // 菜单key权限集合,用于左侧是否有菜单权限判断 + privilegeMenuKeyList: [], + /** + * key为 router path的首字母,value为集合 + * 这样做是为了提高查询效率,用于vue-router拦截判断path + */ + privilegeRouterPathMap: localReadRouterPrivilege() + + }, + mutations: { + // 设置token + setToken (state, token) { + state.token = token; + cookie.setToken(token); + }, + // 保存用户登录信息 + setUserLoginInfo (state, userLoginInfo) { + state.userLoginInfo = userLoginInfo; + localSave('userLoginInfo', JSON.stringify(userLoginInfo)); + }, + setUserPrivilege (state, privilegeList) { + state.isUpdatePrivilege = true; + let routerPathArray = []; + for (const privilege of privilegeList) { + // 是菜单权限 + if (privilege.type === PRIVILEGE_TYPE_ENUM.MENU.value) { + state.privilegeMenuKeyList.push(privilege.key); + if (privilege.url) { + routerPathArray.push(privilege.url); + // 去掉/之后第一个字母 + let key = privilege.url.substr(1, 1); + let pathArray = state.privilegeRouterPathMap.get(key); + if (pathArray) { + pathArray.push(privilege.url); + } else { + pathArray = []; + pathArray.push(privilege.url); + state.privilegeRouterPathMap.set(key, pathArray); + } + } + } + // 如果是功能点 + if (privilege.type === PRIVILEGE_TYPE_ENUM.POINTS.value) { + if (privilege.parentKey) { + let pointArray = state.privilegeFunctionPointsMap.get(privilege.parentKey); + if (pointArray) { + pointArray.push(privilege.key); + } else { + pointArray = []; + pointArray.push(privilege.key); + state.privilegeFunctionPointsMap.set(privilege.parentKey, pointArray); + } + } + } + } + localSave('userRouterPrivilege', JSON.stringify(routerPathArray)); + } + }, + getters: { + // 用户功能点权限 + userFuncPrivilegeInfo: () => localRead('funcPrivilegeInfo'), + // 用户菜单权限 + userMenuPrivilege: state => state.userLoginInfo.privilegeList + }, + actions: { + // 登录 + handleLogin ({ commit }, params) { + params.loginName = params.loginName.trim(); + return new Promise((resolve, reject) => { + loginApi + .login(params) + .then(res => { + localStorage.clear(); + const data = res.data; + commit('setToken', data.xaccessToken); + // 保存用户登录 + commit('setUserLoginInfo', data); + resolve(); + }) + .catch(err => { + reject(err); + }); + }); + } + } +}; diff --git a/front/src/themes/ReadMe.md b/front/src/themes/ReadMe.md new file mode 100644 index 00000000..57ab76e4 --- /dev/null +++ b/front/src/themes/ReadMe.md @@ -0,0 +1 @@ +这是配置主题及颜色的 diff --git a/front/src/themes/index.less b/front/src/themes/index.less new file mode 100644 index 00000000..2a2286f0 --- /dev/null +++ b/front/src/themes/index.less @@ -0,0 +1,302 @@ +@import '~iview/src/styles/index.less'; +/************** + 导航栏 +**************/ +// 导航栏背景 +@menu-dark-title: #001529; +@menu-dark-active-bg: #000c17; +@layout-sider-background: #001529; +@primary-color: #2d8cf0; +@blue: #2d8cf0; +@blueA100: #2e3c5a; +@blueA200: #e7f3ff; +@blueA300: #f0f7fd; +@blueA400: #001529; +@garyA100: #f5f5f5; +@garyA200: #666; +@garyA300: #999; +@tableColor: #eee; +@black: #444; + +.side-menu-wrapper { + // 一级菜单 高亮颜色 + .ivu-menu-dark.ivu-menu-vertical .ivu-menu-item-active:not(.ivu-menu-submenu), + .ivu-menu-dark.ivu-menu-vertical .ivu-menu-submenu-title-active:not(.ivu-menu-submenu){ + color: #fff; + } + .ivu-menu-dark { + .ivu-menu { + .ivu-menu-submenu { + margin-bottom: 0; + } + + .ivu-menu-submenu-title { + padding: 10px 24px !important; + } + + .ivu-menu-submenu-has-parent-submenu { + padding-left: 51px; + } + + // 二级菜单 + .ivu-menu-item, + .ivu-menu-submenu-has-parent-submenu { + padding: 9px 0 9px 65px !important; + background: url('../assets/images/slider/sub_slider_default.png') 30px 0 + no-repeat !important; + + &:hover { + background: url('../assets/images/slider/sub_slider_default.png') 30px + 0 no-repeat !important; + } + + &.ivu-menu-item-active { + background: url('../assets/images/slider/sub_slider_active.png') 30px + 0 no-repeat !important; + border-right: 5px @primary-color solid; + + &:hover { + background: url('../assets/images/slider/sub_slider_active.png') + 30px 0 no-repeat !important; + border-right: 5px @primary-color solid; + } + } + } + .ivu-menu-submenu-has-parent-submenu { + padding-left: 41px !important; + .ivu-menu-submenu-title { + padding: 0 24px !important; + } + &.ivu-menu-child-item-active { + background: url('../assets/images/slider/sub_slider_active.png') 30px + 0 no-repeat !important; + border-right: 0; + } + .ivu-menu { + padding-top: 10px; + } + .ivu-menu-item, + .ivu-menu-item-active:hover { + background: none !important; + padding-left: 52px !important; + } + } + } + } +} + +// 导航栏 +.menu-collapsed { + text-align: center; + padding-top: 0 !important; +} + +// 左侧导航收缩 +.ivu-layout-sider-collapsed { + .ivu-dropdown { + text-align: center; + line-height: 38px; + margin: 0px auto; + color: #515a6e; + + &:hover { + color: @primary-color; + } + } + .ivu-tooltip { + line-height: 38px; + } +} +// 收缩导航栏鼠标经过下拉 +.menu-dropdown { + width: 160px; + left: 65px !important; + background: #001529; + border-radius: 3px; + color: #fff; + .ivu-dropdown-item { + color: #fff; + height: 40px; + line-height: 40px; + padding: 0 20px; + box-sizing: border-box; + .menu-title { + // padding:5px 0; + } + &:hover { + background: none; + border-right: 4px @primary-color solid; + } + } +} +/************** + header +**************/ +@layout-header-height: 52px; + +//面包屑 +.ivu-breadcrumb { + color: #515a6e; +} + +.ivu-breadcrumb-item-separator { + color: #515a6e; +} + + +/************** + table +**************/ +@table-thead-bg: #F7F7F9; +@border-color-split: #F7F7F9; +// @border-color-base: #F7F7F9; + +.ivu-table { + height: auto; + + table { + border-spacing: 0; + width: 100%; + tr { + &.ivu-table-row-hover { + tr, td { + animation: tableHover 0.5s; + } + } + th, td { + border: 1px @tableColor solid; + border-left: 0; + border-top: 0; + text-align: center; + &.ivu-table-column-left { + text-align: left; + } + &:nth-child(1) { + border-left: 0; + } + .ivu-table-cell { + padding: 0 8px; + } + .table-line { + background: @tableColor; + height: 1px; + margin: 8px -18px; + } + } + th { + color: @garyA200; + background: @garyA100; + height: 42px; + font-size: 14px; + color: #808080; + text-align: left; + } + td { + font-weight: normal; + padding: 2px 0; + height: 32px; + text-align: left; + font-size: 12px; + border-bottom: 1px solid #F7F7F9; + .ivu-table-cell-with-expand{ + height: 32px; + line-height: 32px; + } + } + } + } +} + +.ivu-table-body { + &::-webkit-scrollbar { + width: 10px; + height: 10px; + } +} + +.ivu-card-extra { + position: absolute; + right: 8px; + top: 8px; +} + +.ivu-card-head { + background: #fafafa; + border-radius: 4px 4px 0 0; + padding: 12px 16px; + font-size: 14px; + font-weight: bold; + .ivu-icon { + color: #666; + } +} + +.ivu-select-dropdown { + z-index: 10000; + &::-webkit-scrollbar { + width: 10px; + height: 10px; + } +} + +.ivu-dropdown-transfer, +.ivu-select-dropdown-transfer { + position: fixed; +} + +.ivu-table-fixed-body { + overflow: inherit; +} +.ivu-card{ + box-shadow: none !important; +} +// 表单类 +.ivu-btn{ + &:focus{ + box-shadow: none; + } +} +.ivu-form-item{ + margin-bottom: 15px; +} +.ivu-spin-fix{ + background-color: rgba(255, 255, 255, 0.3); +} + +// 重写4.0 table样式 +.ivu-table-wrapper{ + border: 1px solid #dcdee2; + border-bottom: 0; + border-right: 0; + .ivu-table{ + &:after{ + content: ""; + position: absolute; + background-color: #dcdee2; + width: 1px; + height: 100%; + top: 0; + right: 0; + z-index: 3; + } + } +} +// 重写字体大小 +.ivu-select, +.ivu-select-single .ivu-select-selection .ivu-select-placeholder, +.ivu-select-single .ivu-select-selection .ivu-select-selected-value, +.ivu-select-input, +.ivu-input, +textarea.ivu-input, +.ivu-btn, +.ivu-checkbox-wrapper, +.ivu-form .ivu-form-item-label{ + font-size: 12px; +} +.ivu-btn-large{ + font-size: 14px; +} +.ivu-select-item, +.ivu-dropdown-item{ + font-size: 12px !important; +} \ No newline at end of file diff --git a/front/src/views/api-doc/swagger.vue b/front/src/views/api-doc/swagger.vue new file mode 100644 index 00000000..c05f5e73 --- /dev/null +++ b/front/src/views/api-doc/swagger.vue @@ -0,0 +1,33 @@ + + + diff --git a/front/src/views/email/email-list.vue b/front/src/views/email/email-list.vue new file mode 100644 index 00000000..357998a8 --- /dev/null +++ b/front/src/views/email/email-list.vue @@ -0,0 +1,214 @@ + + + diff --git a/front/src/views/email/send-mail.vue b/front/src/views/email/send-mail.vue new file mode 100644 index 00000000..ae4bb47e --- /dev/null +++ b/front/src/views/email/send-mail.vue @@ -0,0 +1,214 @@ + + + + diff --git a/front/src/views/employee/components/department-employee-tree-item/department-employee-tree-item.vue b/front/src/views/employee/components/department-employee-tree-item/department-employee-tree-item.vue new file mode 100644 index 00000000..8f64b4d5 --- /dev/null +++ b/front/src/views/employee/components/department-employee-tree-item/department-employee-tree-item.vue @@ -0,0 +1,124 @@ + + + + diff --git a/front/src/views/employee/components/department-employee-tree/department-employee-tree.vue b/front/src/views/employee/components/department-employee-tree/department-employee-tree.vue new file mode 100644 index 00000000..d3367d81 --- /dev/null +++ b/front/src/views/employee/components/department-employee-tree/department-employee-tree.vue @@ -0,0 +1,251 @@ + + + + diff --git a/front/src/views/employee/position/position-list.vue b/front/src/views/employee/position/position-list.vue new file mode 100644 index 00000000..98870609 --- /dev/null +++ b/front/src/views/employee/position/position-list.vue @@ -0,0 +1,366 @@ + + + + diff --git a/front/src/views/employee/role-employee/components/employee-table-add/employee-table-add.vue b/front/src/views/employee/role-employee/components/employee-table-add/employee-table-add.vue new file mode 100644 index 00000000..e93daec4 --- /dev/null +++ b/front/src/views/employee/role-employee/components/employee-table-add/employee-table-add.vue @@ -0,0 +1,527 @@ + + + diff --git a/front/src/views/employee/role-employee/components/employee-table-detail/employee-table-detail.vue b/front/src/views/employee/role-employee/components/employee-table-detail/employee-table-detail.vue new file mode 100644 index 00000000..a2cc214d --- /dev/null +++ b/front/src/views/employee/role-employee/components/employee-table-detail/employee-table-detail.vue @@ -0,0 +1,72 @@ + + + diff --git a/front/src/views/employee/role-employee/components/employee-table/employee-table.vue b/front/src/views/employee/role-employee/components/employee-table/employee-table.vue new file mode 100644 index 00000000..fc2ef709 --- /dev/null +++ b/front/src/views/employee/role-employee/components/employee-table/employee-table.vue @@ -0,0 +1,569 @@ + + + diff --git a/front/src/views/employee/role-employee/role-employee-manage.vue b/front/src/views/employee/role-employee/role-employee-manage.vue new file mode 100644 index 00000000..034407a7 --- /dev/null +++ b/front/src/views/employee/role-employee/role-employee-manage.vue @@ -0,0 +1,831 @@ + + + + diff --git a/front/src/views/employee/role/components/role-data-scope/role-data-scope.vue b/front/src/views/employee/role/components/role-data-scope/role-data-scope.vue new file mode 100644 index 00000000..0413ce76 --- /dev/null +++ b/front/src/views/employee/role/components/role-data-scope/role-data-scope.vue @@ -0,0 +1,144 @@ + + + + diff --git a/front/src/views/employee/role/components/role-list/role-list.vue b/front/src/views/employee/role/components/role-list/role-list.vue new file mode 100644 index 00000000..bfef12f5 --- /dev/null +++ b/front/src/views/employee/role/components/role-list/role-list.vue @@ -0,0 +1,407 @@ + + + + diff --git a/front/src/views/employee/role/components/role-tree/role-tree.vue b/front/src/views/employee/role/components/role-tree/role-tree.vue new file mode 100644 index 00000000..9721599d --- /dev/null +++ b/front/src/views/employee/role/components/role-tree/role-tree.vue @@ -0,0 +1,403 @@ + + + + diff --git a/front/src/views/employee/role/role-manage.vue b/front/src/views/employee/role/role-manage.vue new file mode 100644 index 00000000..9765f362 --- /dev/null +++ b/front/src/views/employee/role/role-manage.vue @@ -0,0 +1,339 @@ + + + diff --git a/front/src/views/error-page/401.vue b/front/src/views/error-page/401.vue new file mode 100644 index 00000000..70b3c366 --- /dev/null +++ b/front/src/views/error-page/401.vue @@ -0,0 +1,19 @@ + + + diff --git a/front/src/views/error-page/404.vue b/front/src/views/error-page/404.vue new file mode 100644 index 00000000..291406f6 --- /dev/null +++ b/front/src/views/error-page/404.vue @@ -0,0 +1,19 @@ + + + diff --git a/front/src/views/error-page/500.vue b/front/src/views/error-page/500.vue new file mode 100644 index 00000000..e2a6c249 --- /dev/null +++ b/front/src/views/error-page/500.vue @@ -0,0 +1,19 @@ + + + diff --git a/front/src/views/error-page/back-btn-group.vue b/front/src/views/error-page/back-btn-group.vue new file mode 100644 index 00000000..7966849b --- /dev/null +++ b/front/src/views/error-page/back-btn-group.vue @@ -0,0 +1,40 @@ + + + diff --git a/front/src/views/error-page/error-content.vue b/front/src/views/error-page/error-content.vue new file mode 100644 index 00000000..d81d965e --- /dev/null +++ b/front/src/views/error-page/error-content.vue @@ -0,0 +1,28 @@ + + + diff --git a/front/src/views/error-page/error.less b/front/src/views/error-page/error.less new file mode 100644 index 00000000..63802459 --- /dev/null +++ b/front/src/views/error-page/error.less @@ -0,0 +1,46 @@ +.error-page{ + width: 100%; + height: 100%; + position: relative; + background: #f8f8f9; + .content-con{ + width: 700px; + height: 600px; + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -60%); + img{ + display: block; + width: 100%; + height: 100%; + } + .text-con{ + position: absolute; + left: 0px; + top: 0px; + h4{ + position: absolute; + left: 0px; + top: 0px; + font-size: 80px; + font-weight: 700; + color: #348EED; + } + h5{ + position: absolute; + width: 700px; + left: 0px; + top: 100px; + font-size: 20px; + font-weight: 700; + color: #67647D; + } + } + .back-btn-group{ + position: absolute; + right: 0px; + bottom: 20px; + } + } +} diff --git a/front/src/views/file/file-list.vue b/front/src/views/file/file-list.vue new file mode 100644 index 00000000..9f79d984 --- /dev/null +++ b/front/src/views/file/file-list.vue @@ -0,0 +1,279 @@ + + + diff --git a/front/src/views/heart-beat/heart-beat-list.vue b/front/src/views/heart-beat/heart-beat-list.vue new file mode 100644 index 00000000..1637378e --- /dev/null +++ b/front/src/views/heart-beat/heart-beat-list.vue @@ -0,0 +1,115 @@ + + diff --git a/front/src/views/home/components/card.vue b/front/src/views/home/components/card.vue new file mode 100644 index 00000000..763eabf4 --- /dev/null +++ b/front/src/views/home/components/card.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/front/src/views/home/components/chart-bar.vue b/front/src/views/home/components/chart-bar.vue new file mode 100644 index 00000000..8130be3c --- /dev/null +++ b/front/src/views/home/components/chart-bar.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/front/src/views/home/components/chart-funnel.vue b/front/src/views/home/components/chart-funnel.vue new file mode 100644 index 00000000..dd076399 --- /dev/null +++ b/front/src/views/home/components/chart-funnel.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/front/src/views/home/components/chart-gauge.vue b/front/src/views/home/components/chart-gauge.vue new file mode 100644 index 00000000..99750aa7 --- /dev/null +++ b/front/src/views/home/components/chart-gauge.vue @@ -0,0 +1,87 @@ + + + + + diff --git a/front/src/views/home/components/chart-line.vue b/front/src/views/home/components/chart-line.vue new file mode 100644 index 00000000..d7aeed44 --- /dev/null +++ b/front/src/views/home/components/chart-line.vue @@ -0,0 +1,123 @@ + + + + + diff --git a/front/src/views/home/components/chart-pie.vue b/front/src/views/home/components/chart-pie.vue new file mode 100644 index 00000000..01037399 --- /dev/null +++ b/front/src/views/home/components/chart-pie.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/front/src/views/home/components/home-circle.vue b/front/src/views/home/components/home-circle.vue new file mode 100644 index 00000000..903ec4e2 --- /dev/null +++ b/front/src/views/home/components/home-circle.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/front/src/views/home/components/home-progress.vue b/front/src/views/home/components/home-progress.vue new file mode 100644 index 00000000..dc9682a7 --- /dev/null +++ b/front/src/views/home/components/home-progress.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/front/src/views/home/components/theme.json b/front/src/views/home/components/theme.json new file mode 100644 index 00000000..909b518a --- /dev/null +++ b/front/src/views/home/components/theme.json @@ -0,0 +1,490 @@ +{ + "color": [ + "#2d8cf0", + "#19be6b", + "#ff9900", + "#E46CBB", + "#9A66E4", + "#ed3f14" + ], + "backgroundColor": "rgba(0,0,0,0)", + "textStyle": {}, + "title": { + "textStyle": { + "color": "#516b91" + }, + "subtextStyle": { + "color": "#93b7e3" + } + }, + "line": { + "itemStyle": { + "normal": { + "borderWidth": "2" + } + }, + "lineStyle": { + "normal": { + "width": "2" + } + }, + "symbolSize": "6", + "symbol": "emptyCircle", + "smooth": true + }, + "radar": { + "itemStyle": { + "normal": { + "borderWidth": "2" + } + }, + "lineStyle": { + "normal": { + "width": "2" + } + }, + "symbolSize": "6", + "symbol": "emptyCircle", + "smooth": true + }, + "bar": { + "itemStyle": { + "normal": { + "barBorderWidth": 0, + "barBorderColor": "#ccc" + }, + "emphasis": { + "barBorderWidth": 0, + "barBorderColor": "#ccc" + } + } + }, + "pie": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "scatter": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "boxplot": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "parallel": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "sankey": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "funnel": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "gauge": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + }, + "emphasis": { + "borderWidth": 0, + "borderColor": "#ccc" + } + } + }, + "candlestick": { + "itemStyle": { + "normal": { + "color": "#edafda", + "color0": "transparent", + "borderColor": "#d680bc", + "borderColor0": "#8fd3e8", + "borderWidth": "2" + } + } + }, + "graph": { + "itemStyle": { + "normal": { + "borderWidth": 0, + "borderColor": "#ccc" + } + }, + "lineStyle": { + "normal": { + "width": 1, + "color": "#aaa" + } + }, + "symbolSize": "6", + "symbol": "emptyCircle", + "smooth": true, + "color": [ + "#2d8cf0", + "#19be6b", + "#f5ae4a", + "#9189d5", + "#56cae2", + "#cbb0e3" + ], + "label": { + "normal": { + "textStyle": { + "color": "#eee" + } + } + } + }, + "map": { + "itemStyle": { + "normal": { + "areaColor": "#f3f3f3", + "borderColor": "#516b91", + "borderWidth": 0.5 + }, + "emphasis": { + "areaColor": "rgba(165,231,240,1)", + "borderColor": "#516b91", + "borderWidth": 1 + } + }, + "label": { + "normal": { + "textStyle": { + "color": "#000" + } + }, + "emphasis": { + "textStyle": { + "color": "rgb(81,107,145)" + } + } + } + }, + "geo": { + "itemStyle": { + "normal": { + "areaColor": "#f3f3f3", + "borderColor": "#516b91", + "borderWidth": 0.5 + }, + "emphasis": { + "areaColor": "rgba(165,231,240,1)", + "borderColor": "#516b91", + "borderWidth": 1 + } + }, + "label": { + "normal": { + "textStyle": { + "color": "#000" + } + }, + "emphasis": { + "textStyle": { + "color": "rgb(81,107,145)" + } + } + } + }, + "categoryAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "valueAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "logAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "timeAxis": { + "axisLine": { + "show": true, + "lineStyle": { + "color": "#cccccc" + } + }, + "axisTick": { + "show": false, + "lineStyle": { + "color": "#333" + } + }, + "axisLabel": { + "show": true, + "textStyle": { + "color": "#999999" + } + }, + "splitLine": { + "show": true, + "lineStyle": { + "color": [ + "#eeeeee" + ] + } + }, + "splitArea": { + "show": false, + "areaStyle": { + "color": [ + "rgba(250,250,250,0.05)", + "rgba(200,200,200,0.02)" + ] + } + } + }, + "toolbox": { + "iconStyle": { + "normal": { + "borderColor": "#999" + }, + "emphasis": { + "borderColor": "#666" + } + } + }, + "legend": { + "textStyle": { + "color": "#999999" + } + }, + "tooltip": { + "axisPointer": { + "lineStyle": { + "color": "#ccc", + "width": 1 + }, + "crossStyle": { + "color": "#ccc", + "width": 1 + } + } + }, + "timeline": { + "lineStyle": { + "color": "#8fd3e8", + "width": 1 + }, + "itemStyle": { + "normal": { + "color": "#8fd3e8", + "borderWidth": 1 + }, + "emphasis": { + "color": "#8fd3e8" + } + }, + "controlStyle": { + "normal": { + "color": "#8fd3e8", + "borderColor": "#8fd3e8", + "borderWidth": 0.5 + }, + "emphasis": { + "color": "#8fd3e8", + "borderColor": "#8fd3e8", + "borderWidth": 0.5 + } + }, + "checkpointStyle": { + "color": "#8fd3e8", + "borderColor": "rgba(138,124,168,0.37)" + }, + "label": { + "normal": { + "textStyle": { + "color": "#8fd3e8" + } + }, + "emphasis": { + "textStyle": { + "color": "#8fd3e8" + } + } + } + }, + "visualMap": { + "color": [ + "#516b91", + "#59c4e6", + "#a5e7f0" + ] + }, + "dataZoom": { + "backgroundColor": "rgba(0,0,0,0)", + "dataBackgroundColor": "rgba(255,255,255,0.3)", + "fillerColor": "rgba(167,183,204,0.4)", + "handleColor": "#a7b7cc", + "handleSize": "100%", + "textStyle": { + "color": "#333" + } + }, + "markPoint": { + "label": { + "normal": { + "textStyle": { + "color": "#eee" + } + }, + "emphasis": { + "textStyle": { + "color": "#eee" + } + } + } + } +} \ No newline at end of file diff --git a/front/src/views/home/home.vue b/front/src/views/home/home.vue new file mode 100644 index 00000000..6992ab69 --- /dev/null +++ b/front/src/views/home/home.vue @@ -0,0 +1,144 @@ + + + + + diff --git a/front/src/views/home/index.js b/front/src/views/home/index.js new file mode 100644 index 00000000..5f66ed9d --- /dev/null +++ b/front/src/views/home/index.js @@ -0,0 +1,2 @@ +import home from './home.vue'; +export default home; diff --git a/front/src/views/keep-alive/add-content.vue b/front/src/views/keep-alive/add-content.vue new file mode 100644 index 00000000..0c2290dd --- /dev/null +++ b/front/src/views/keep-alive/add-content.vue @@ -0,0 +1,94 @@ + + + + diff --git a/front/src/views/keep-alive/content-list.vue b/front/src/views/keep-alive/content-list.vue new file mode 100644 index 00000000..11b34887 --- /dev/null +++ b/front/src/views/keep-alive/content-list.vue @@ -0,0 +1,80 @@ + + + + diff --git a/front/src/views/login/canvas.js b/front/src/views/login/canvas.js new file mode 100644 index 00000000..37976ad7 --- /dev/null +++ b/front/src/views/login/canvas.js @@ -0,0 +1,289 @@ +// 离子波浪 +export const lonWave = () => { + var starlings = function (n, r, t, o, e, u, i, f) { + var a = f.onSetup + void 0 === a && (a = null) + var v = f.onRepeat + void 0 === v && (v = null) + var c = f.modifier + void 0 === c && (c = null) + var l = f.perspective + void 0 === l && (l = 1) + var d = f.pixelRatio + void 0 === d && (d = 1) + var m = f.triangles + void 0 === m && (m = !1) + var s + var p + var y = r.length + var w = function (n, r) { + let t = s.createShader(n) + return s.shaderSource(t, r), s.compileShader(t), t + } + var b = function () { + for (var n = 0; n < o.length; n += 1) { + for (var r = s.createBuffer(), e = o[n], u = e.data(0, 0).length, i = new Float32Array(t * y * u), f = 0; f < t; f += 1) { + for (var a = e.data(f, t), v = f * y * u, l = 0; l < y; l += 1) { + for (var d = 0; d < u; d += 1) { + c !== null && e.name === c.attribute ? i[v] = c.value(i[v], a, d, l) : i[v] = a[d] + v += 1 + } + } + } + s.bindBuffer(s.ARRAY_BUFFER, r) + s.bufferData(s.ARRAY_BUFFER, i, s.STATIC_DRAW) + var m = s.getAttribLocation(p, o[n].name) + s.enableVertexAttribArray(m) + s.vertexAttribPointer(m, u, s.FLOAT, !1, !1, 0, 0) + } + } + var A = function () { + e.push({ + name: 'uMVP', + type: 'mat4' + }) + for (var n = 0; n < e.length; n += 1) { + var r = s.getUniformLocation(p, e[n].name) + e[n].location = r + } + } + var F = { + float: function (n, r) { + return s.uniform1f(n, r) + }, + vec2: function (n, r) { + return s.uniform2fv(n, r) + }, + vec3: function (n, r) { + return s.uniform3fv(n, r) + }, + vec4: function (n, r) { + return s.uniform4fv(n, r) + }, + mat2: function (n, r) { + return s.uniformMatrix2fv(n, !1, r) + }, + mat3: function (n, r) { + return s.uniformMatrix3fv(n, !1, r) + }, + mat4: function (n, r) { + return s.uniformMatrix4fv(n, !1, r) + } + } + var g = function () { + s.clear(16640) + s.useProgram(p) + v !== null && v(s, p, e) + for (var n = 0; n < e.length; n += 1) F[e[n].type](e[n].location, e[n].value) + s.drawArrays(m ? s.TRIANGLES : s.POINTS, 0, y * t) + requestAnimationFrame(g) + } + var h = function () { + n.width = n.clientWidth * d + n.height = n.clientHeight * d + var r = s.drawingBufferWidth + var t = s.drawingBufferHeight + s.viewport(0, 0, r, t) + e[e.length - 1].value = [l / (r / t), 0, 0, 0, 0, l, 0, 0, 0, 0, -1, -1, 0, 0, 1, 1] + } + s = n.getContext('webgl') + p = s.createProgram() + s.attachShader(p, w(s.VERTEX_SHADER, u)) + s.attachShader(p, w(s.FRAGMENT_SHADER, i)) + s.linkProgram(p) + A() + h() + b() + a !== null && a(s) + g() + window.addEventListener('resize', h, !1) + } + + // Do you like rainbow waves? + var rainbow = false + + // Need more performance? + var HD = true + + var canvas = document.getElementById('canvas') + var background = document.querySelector('.background') + var bar = document.querySelector('.progress') + var initialize = function initialize (vertices) { + var pixelRatio = HD ? window.devicePixelRatio : 1 + var rows = HD ? 90 : 90 + var multiplier = rows * rows + var duration = 0.4 + var geometry = [{ + x: 0, + y: 0, + z: 0 + }] + var pointSize = (HD ? 6 : 2).toFixed(1) + + var step = 0.004 + var size = 5 + var attributes = [{ + name: 'aPositionStart', + data: function data (i, total) { + return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -1, (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1] + } + }, + { + name: 'aControlPointOne', + data: function data (i) { + return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -0.5 + getRandom(0.2), (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1] + } + }, + { + name: 'aControlPointTwo', + data: function data (i) { + return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -0.5 + getRandom(0.2), (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1] + } + }, + { + name: 'aPositionEnd', + data: function data (i) { + return [size - (i % rows / rows + 0.5 / rows) * (size * 2), -1, (size - (Math.floor(i / rows) / rows + 0.5 / rows) * size * 2) * -1] + } + }, + { + name: 'aOffset', + data: function data (i) { + return [i * ((1 - duration) / (multiplier - 1))] + } + }, + { + name: 'aColor', + data: function data (i, total) { + return getHSL(rainbow ? i / total * 1.0 : 0.5 + i / total * 0.4, 0.5, 0.5) + } + }] + + var uniforms = [{ + name: 'uProgress', + type: 'float', + value: 0.8 + }] + + var vertexShader = '\n attribute vec3 aPositionStart;\n attribute vec3 aControlPointOne;\n attribute vec3 aControlPointTwo;\n attribute vec3 aPositionEnd;\n attribute float aOffset;\n attribute vec3 aColor;\n\n uniform float uProgress;\n uniform mat4 uMVP;\n\n varying vec3 vColor;\n\n vec3 bezier4(vec3 a, vec3 b, vec3 c, vec3 d, float t) {\n return mix(mix(mix(a, b, t), mix(b, c, t), t), mix(mix(b, c, t), mix(c, d, t), t), t);\n }\n\n float easeInOutQuint(float t){\n return t < 0.5 ? 16.0 * t * t * t * t * t : 1.0 + 16.0 * (--t) * t * t * t * t;\n }\n\n void main () {\n float tProgress = easeInOutQuint(min(1.0, max(0.0, (uProgress - aOffset)) / ' + duration + '));\n vec3 newPosition = bezier4(aPositionStart, aControlPointOne, aControlPointTwo, aPositionEnd, tProgress);\n gl_PointSize = ' + pointSize + ' + ((newPosition.y + 1.0) * 80.0);\n gl_Position = uMVP * vec4(newPosition, 1.0);\n vColor = aColor;\n }\n' + + var fragmentShader = '\n precision mediump float;\n\n varying vec3 vColor;\n\n void main() {\n vec2 pc = 2.0 * gl_PointCoord - 1.0;\n gl_FragColor = vec4(vColor, 1.0 - dot(pc, pc));\n }\n' + + var onSetup = function onSetup (gl) { + gl.blendFunc(gl.SRC_ALPHA, gl.ONE) + gl.enable(gl.BLEND) + } + + var onRepeat = function onRepeat () { + rotateY(uniforms[uniforms.length - 1].value, 0.002) + if (uniforms[0].value < 0) { + uniforms[0].value = 1 + } + uniforms[0].value -= step + } + + var options = { + onSetup: onSetup, + onRepeat: onRepeat, + pixelRatio: pixelRatio + } + + starlings(canvas, geometry, multiplier, attributes, uniforms, vertexShader, fragmentShader, options) + } + + var getRandom = function getRandom (value) { + return Math.random() * value - value / 2 + } + + var rotateY = function rotateY (matrix, angle) { + var sin = Math.sin(angle) + var cos = Math.cos(angle) + var clone = JSON.parse(JSON.stringify(matrix)) + + matrix[0] = clone[0] * cos - clone[8] * sin + matrix[1] = clone[1] * cos - clone[9] * sin + matrix[2] = clone[2] * cos - clone[10] * sin + matrix[3] = clone[3] * cos - clone[11] * sin + matrix[8] = clone[0] * sin + clone[8] * cos + matrix[9] = clone[1] * sin + clone[9] * cos + matrix[10] = clone[2] * sin + clone[10] * cos + matrix[11] = clone[3] * sin + clone[11] * cos + } + + var h2r = function h2r (p, q, t) { + if (t < 0) t += 1 + if (t > 1) t -= 1 + if (t < 1 / 6) return p + (q - p) * 6 * t + if (t < 1 / 2) return q + if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t) + return p + } + + var getHSL = function getHSL (h, s, l) { + h = (h % 1 + 1) % 1 + s = Math.max(0, Math.min(1, s)) + l = Math.max(0, Math.min(1, l)) + if (s === 0) return [l, l, l] + var p = l <= 0.5 ? l * (1 + s) : l + s - l * s + var q = 2 * l - p + return [h2r(q, p, h + 1 / 3), h2r(q, p, h), h2r(q, p, h - 1 / 3)] + } + initialize() +} + +// 随机线条 +export const canvasParticle = (function () { + function getElementByTag (name) { return document.getElementsByTagName(name) } + function getELementById (id) { return document.getElementById(id) } + function canvasInit (canvasConfig) { + canvasConfig = canvasConfig || {} + var html = getElementByTag('html')[0] + var body = document.getElementById('canvasView') + var canvasObj = document.createElement('canvas') + var canvas = { element: canvasObj, points: [], config: { vx: canvasConfig.vx || 4, vy: canvasConfig.vy || 4, height: canvasConfig.height || 2, width: canvasConfig.width || 2, count: canvasConfig.count || 100, color: canvasConfig.color || '121, 162, 185', stroke: canvasConfig.stroke || '130,255,255', dist: canvasConfig.dist || 6000, e_dist: canvasConfig.e_dist || 20000, max_conn: 10 } }; if (canvas.element.getContext('2d')) { canvas.context = canvas.element.getContext('2d') } else { return null } + body.style.padding = '0'; body.style.margin = '0'; body.appendChild(canvas.element); canvas.element.style = 'position: fixed; top: 0; left: 0; z-index: -1;'; canvasSize(canvas.element); window.onresize = function () { canvasSize(canvas.element) } + body.onmousemove = function (e) { var event = e || window.event; canvas.mouse = { x: event.clientX, y: event.clientY } } + document.onmouseleave = function () { canvas.mouse = undefined } + setInterval(function () { drawPoint(canvas) }, 40) + } + function canvasSize (canvas) { + var width = document.getElementById('canvasView').style.width + var height = document.getElementById('canvasView').style.height + width = parseInt(width); height = parseInt(height) + canvas.width = width || window.innerWeight || document.documentElement.clientWidth || document.body.clientWidth; canvas.height = height || window.innerWeight || document.documentElement.clientHeight || document.body.clientHeight + } + function drawPoint (canvas) { + var context = canvas.context + var point + var dist + context.clearRect(0, 0, canvas.element.width, canvas.element.height); context.beginPath(); context.fillStyle = 'rgb(' + canvas.config.color + ')'; for (var i = 0, len = canvas.config.count; i < len; i++) { + if (canvas.points.length != canvas.config.count) { point = { x: Math.floor(Math.random() * canvas.element.width), y: Math.floor(Math.random() * canvas.element.height), vx: canvas.config.vx / 2 - Math.random() * canvas.config.vx, vy: canvas.config.vy / 2 - Math.random() * canvas.config.vy } } else { point = borderPoint(canvas.points[i], canvas) } + context.fillRect(point.x - canvas.config.width / 2, point.y - canvas.config.height / 2, canvas.config.width, canvas.config.height); canvas.points[i] = point + } + drawLine(context, canvas, canvas.mouse); context.closePath() + } + function borderPoint (point, canvas) { + var p = point; if (point.x <= 0 || point.x >= canvas.element.width) { p.vx = -p.vx; p.x += p.vx } else if (point.y <= 0 || point.y >= canvas.element.height) { p.vy = -p.vy; p.y += p.vy } else { p = { x: p.x + p.vx, y: p.y + p.vy, vx: p.vx, vy: p.vy } } + return p + } + function drawLine (context, canvas, mouse) { + let dist + context = context || canvas.context; for (var i = 0, len = canvas.config.count; i < len; i++) { + canvas.points[i].max_conn = 0; for (var j = 0; j < len; j++) { + if (i != j) { + dist = Math.round(canvas.points[i].x - canvas.points[j].x) * Math.round(canvas.points[i].x - canvas.points[j].x) + + Math.round(canvas.points[i].y - canvas.points[j].y) * Math.round(canvas.points[i].y - canvas.points[j].y); if (dist <= canvas.config.dist && canvas.points[i].max_conn < canvas.config.max_conn) { + canvas.points[i].max_conn++; context.lineWidth = 0.5 - dist / canvas.config.dist; context.strokeStyle = 'rgba(' + canvas.config.stroke + ',' + (1 - dist / canvas.config.dist) + ')' + context.beginPath(); context.moveTo(canvas.points[i].x, canvas.points[i].y); context.lineTo(canvas.points[j].x, canvas.points[j].y); context.stroke() + } + } + } + if (mouse) { + dist = Math.round(canvas.points[i].x - mouse.x) * Math.round(canvas.points[i].x - mouse.x) + + Math.round(canvas.points[i].y - mouse.y) * Math.round(canvas.points[i].y - mouse.y); if (dist > canvas.config.dist && dist <= canvas.config.e_dist) { canvas.points[i].x = canvas.points[i].x + (mouse.x - canvas.points[i].x) / 20; canvas.points[i].y = canvas.points[i].y + (mouse.y - canvas.points[i].y) / 20 } + if (dist <= canvas.config.e_dist) { context.lineWidth = 1; context.strokeStyle = 'rgba(' + canvas.config.stroke + ',' + (1 - dist / canvas.config.e_dist) + ')'; context.beginPath(); context.moveTo(canvas.points[i].x, canvas.points[i].y); context.lineTo(mouse.x, mouse.y); context.stroke() } + } + } + } + return canvasInit +})() diff --git a/front/src/views/login/components/login-form.vue b/front/src/views/login/components/login-form.vue new file mode 100644 index 00000000..558d4bc6 --- /dev/null +++ b/front/src/views/login/components/login-form.vue @@ -0,0 +1,133 @@ + + \ No newline at end of file diff --git a/front/src/views/login/login.less b/front/src/views/login/login.less new file mode 100644 index 00000000..d1d6fc2b --- /dev/null +++ b/front/src/views/login/login.less @@ -0,0 +1,128 @@ +.center { + text-align: center; +} + +.login { + font-family: Arial, "PingFang SC", "Microsoft YaHei"; + width: 100%; + height: 100%; + background: url(../../assets/images/login-bg.jpg) no-repeat fixed; + background-size: cover; + + .content { + width: 424px; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -56%) + } + .ivu-card { + background: rgba(255, 255, 255, 0.95); + border-radius: 10px; + box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.3); + } + .form-con { + margin: 32px 0; + width: 424px; + background: #fff; + padding: 32px 32px; + border-radius: 0 8px 8px 0; + .ivu-input { + border: 1px solid #E8E8EE; + border-radius: 4px; + font-size: 16px; + color: #525252; + padding: 0 20px; + &:focus { + border: 1px solid #0097F6; + box-shadow: none; + } + } + .ivu-form-item-error-tip { + height: 30px; + line-height: 30px; + padding: 0; + color: #f66; + top:90%; + } + .ivu-form-item { + margin-bottom: 22px; + } + .remember { + margin: -10px 0 10px; + } + .ivu-input, + .ivu-btn { + height: 48px; + } + .ivu-btn { + font-size: 16px; + } + .ivu-input-group-prepend { + padding: 4px 15px; + } + .code-input { + width: 172px; + } + .codeUrl { + height: 80%; + position: absolute; + z-index: 3; + top: 0; + bottom: 0; + margin: auto; + right: 24px; + border-radius: 0 4px 4px 0; + cursor: pointer; + } + } + .login-tip { + font-size: 10px; + text-align: center; + color: #c3c3c3; + } + .footerDesc { + font-family: "MicrosoftYaHei"; + color: #A6A6A8; + font-size: 14px; + } + .otherWay { + font-size: 14px; + font-family: "Microsoft YaHei"; + .inline { + display: inline-block; + } + .align { + vertical-align: middle; + } + .marginLeft { + margin-left: 20px; + float:right; + } + } + .remember { + font-size: 14px; + } +} +.draw { + position: fixed; + width: 1px; + z-index: 99999; + line-height: 1px; + pointer-events: none; +} + +@keyframes floatOne { + 0% { + opacity: 1; + } + + 50% { + opacity: 1; + } + + 100% { + opacity: 0; + transform: translate3D(0, -20px, 0) scale(5) rotate(45deg); + } +} \ No newline at end of file diff --git a/front/src/views/login/login.vue b/front/src/views/login/login.vue new file mode 100644 index 00000000..89e4fd19 --- /dev/null +++ b/front/src/views/login/login.vue @@ -0,0 +1,52 @@ + + + + diff --git a/front/src/views/monitor/online-user.vue b/front/src/views/monitor/online-user.vue new file mode 100644 index 00000000..b133c303 --- /dev/null +++ b/front/src/views/monitor/online-user.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/front/src/views/monitor/sql.vue b/front/src/views/monitor/sql.vue new file mode 100644 index 00000000..ced71bf8 --- /dev/null +++ b/front/src/views/monitor/sql.vue @@ -0,0 +1,33 @@ + + + diff --git a/front/src/views/notice/notice-list.vue b/front/src/views/notice/notice-list.vue new file mode 100644 index 00000000..933675e6 --- /dev/null +++ b/front/src/views/notice/notice-list.vue @@ -0,0 +1,397 @@ + + + + + diff --git a/front/src/views/notice/person-notice.vue b/front/src/views/notice/person-notice.vue new file mode 100644 index 00000000..cc2fec01 --- /dev/null +++ b/front/src/views/notice/person-notice.vue @@ -0,0 +1,221 @@ + + + + + diff --git a/front/src/views/reload/smart-reload/smart-reload-list.vue b/front/src/views/reload/smart-reload/smart-reload-list.vue new file mode 100644 index 00000000..b0027c4c --- /dev/null +++ b/front/src/views/reload/smart-reload/smart-reload-list.vue @@ -0,0 +1,273 @@ + + diff --git a/front/src/views/system-setting/system-config/system-config.vue b/front/src/views/system-setting/system-config/system-config.vue new file mode 100644 index 00000000..0fd884a4 --- /dev/null +++ b/front/src/views/system-setting/system-config/system-config.vue @@ -0,0 +1,397 @@ + + + diff --git a/front/src/views/system-setting/system-privilege/components/privilege-form.vue b/front/src/views/system-setting/system-privilege/components/privilege-form.vue new file mode 100644 index 00000000..6233c82f --- /dev/null +++ b/front/src/views/system-setting/system-privilege/components/privilege-form.vue @@ -0,0 +1,144 @@ + + + diff --git a/front/src/views/system-setting/system-privilege/system-privilege.vue b/front/src/views/system-setting/system-privilege/system-privilege.vue new file mode 100644 index 00000000..c6b33e4e --- /dev/null +++ b/front/src/views/system-setting/system-privilege/system-privilege.vue @@ -0,0 +1,318 @@ + + + diff --git a/front/src/views/task/task-list.vue b/front/src/views/task/task-list.vue new file mode 100644 index 00000000..26942927 --- /dev/null +++ b/front/src/views/task/task-list.vue @@ -0,0 +1,545 @@ + + + + + diff --git a/front/src/views/user-log/user-login-log.vue b/front/src/views/user-log/user-login-log.vue new file mode 100644 index 00000000..f326625c --- /dev/null +++ b/front/src/views/user-log/user-login-log.vue @@ -0,0 +1,181 @@ + + + diff --git a/front/src/views/user-log/user-operate-log.vue b/front/src/views/user-log/user-operate-log.vue new file mode 100644 index 00000000..db47df63 --- /dev/null +++ b/front/src/views/user-log/user-operate-log.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/front/tests/e2e/.eslintrc b/front/tests/e2e/.eslintrc new file mode 100644 index 00000000..02023fba --- /dev/null +++ b/front/tests/e2e/.eslintrc @@ -0,0 +1,12 @@ +{ + "plugins": [ + "cypress" + ], + "env": { + "mocha": true, + "cypress/globals": true + }, + "rules": { + "strict": "off" + } +} diff --git a/front/tests/e2e/plugins/index.js b/front/tests/e2e/plugins/index.js new file mode 100644 index 00000000..cfefc78b --- /dev/null +++ b/front/tests/e2e/plugins/index.js @@ -0,0 +1,9 @@ +// https://docs.cypress.io/guides/guides/plugins-guide.html + +module.exports = (on, config) => Object.assign({}, config, { + fixturesFolder: 'tests/e2e/fixtures', + integrationFolder: 'tests/e2e/specs', + screenshotsFolder: 'tests/e2e/screenshots', + videosFolder: 'tests/e2e/videos', + supportFile: 'tests/e2e/support/index.js' +}) diff --git a/front/tests/e2e/specs/test.js b/front/tests/e2e/specs/test.js new file mode 100644 index 00000000..41ad94a0 --- /dev/null +++ b/front/tests/e2e/specs/test.js @@ -0,0 +1,8 @@ +// https://docs.cypress.io/api/introduction/api.html + +describe('My First Test', () => { + it('Visits the app root url', () => { + cy.visit('/') + cy.contains('h1', 'Welcome to Your Vue.js App') + }) +}) diff --git a/front/tests/e2e/support/commands.js b/front/tests/e2e/support/commands.js new file mode 100644 index 00000000..c1f5a772 --- /dev/null +++ b/front/tests/e2e/support/commands.js @@ -0,0 +1,25 @@ +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This is will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) diff --git a/front/tests/e2e/support/index.js b/front/tests/e2e/support/index.js new file mode 100644 index 00000000..d68db96d --- /dev/null +++ b/front/tests/e2e/support/index.js @@ -0,0 +1,20 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// Import commands.js using ES2015 syntax: +import './commands' + +// Alternatively you can use CommonJS syntax: +// require('./commands') diff --git a/front/tests/unit/.eslintrc.js b/front/tests/unit/.eslintrc.js new file mode 100644 index 00000000..8038afe9 --- /dev/null +++ b/front/tests/unit/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + env: { + mocha: true + }, + rules: { + 'import/no-extraneous-dependencies': 'off' + } +} diff --git a/front/tests/unit/HelloWorld.spec.js b/front/tests/unit/HelloWorld.spec.js new file mode 100644 index 00000000..bb668bf4 --- /dev/null +++ b/front/tests/unit/HelloWorld.spec.js @@ -0,0 +1,13 @@ +import { expect } from 'chai' +import { shallow } from '@vue/test-utils' +import HelloWorld from '@/components/HelloWorld.vue' + +describe('HelloWorld.vue', () => { + it('renders props.msg when passed', () => { + const msg = 'new message' + const wrapper = shallow(HelloWorld, { + propsData: { msg } + }) + expect(wrapper.text()).to.include(msg) + }) +}) diff --git a/front/vscode/settings.json b/front/vscode/settings.json new file mode 100644 index 00000000..ab4bb79a --- /dev/null +++ b/front/vscode/settings.json @@ -0,0 +1,43 @@ +{ + "terminal.integrated.shell.windows": "C:\\WINDOWS\\System32\\cmd.exe", + "jetbrainsKeymap.promptV3Features": true, + "editor.multiCursorModifier": "ctrlCmd", + "editor.formatOnPaste": true, + "debug.allowBreakpointsEverywhere": true, + "files.autoSave": "afterDelay", + "workbench.colorTheme": "One Dark Pro", + "workbench.iconTheme": "vscode-icons", + "vetur.validation.template": false, + "[javascript]": { + "editor.defaultFormatter": "vscode.typescript-language-features" + }, + "[less]": { + "editor.defaultFormatter": "HookyQR.beautify" + }, + "javascript.format.insertSpaceBeforeFunctionParenthesis": true, + "eslint.autoFixOnSave": true, + "eslint.alwaysShowStatus": true, + "workbench.startupEditor": "newUntitledFile", + //"vetur.format.defaultFormatter.html": "js-beautify-html", + //"vetur.format.defaultFormatter.js": "vscode-typescript", //让vue中的js按编辑器自带的ts格式进行格式化 + "vetur.format.defaultFormatterOptions": { + // "js-beautify-html": { + // // force|force-aligned | force-expand-multiline + // "wrap_line_length": 100, + // "wrap_attributes": "auto", + // "end_with_newline": false + // //"wrap_attributes": "auto" + // }, + "prettyhtml": { + "printWidth": 100, + "singleQuote": false, + "wrapAttributes": false, + "sortAttributes": true + }, + "prettier": { + "semi": true, + "singleQuote": true + } + }, + "search.location": "panel", +} diff --git a/front/vue.config.js b/front/vue.config.js new file mode 100644 index 00000000..827c711d --- /dev/null +++ b/front/vue.config.js @@ -0,0 +1,78 @@ +const path = require('path'); +const resolve = dir => { + return path.join(__dirname, dir); +}; +const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); +const CompressionWebpackPlugin = require('compression-webpack-plugin'); +const productionGzipExtensions = ['js', 'css']; +// 项目部署基础 +// 默认情况下,我们假设你的应用将被部署在域的根目录下, +// 例如:https://www.my-app.com/ +// 默认:'/' +// 如果您的应用程序部署在子路径中,则需要在这指定子路径 +// 例如:https://www.foobar.com/my-app/ +// 需要将它改为'/my-app/' +// iview-admin线上演示打包路径: https://file.iviewui.com-dist/ +const publicPath = process.env.NODE_ENV === 'production' ? '/' : '/'; +const lintOnSave = process.env.NODE_ENV === 'production'; + +module.exports = { + // Project deployment base + // By default we assume your app will be deployed at the root of a domain, + // e.g. https://www.my-app.com/ + // If your app is deployed at a sub-path, you will need to specify that + // sub-path here. For example, if your app is deployed at + // https://www.foobar.com/my-app/ + // then change this to '/my-app/' + publicPath, + // tweak internal webpack configuration. + // see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md + // 如果你不需要使用eslint,把lintOnSave设为false即可 + lintOnSave, + chainWebpack: config => { + config.entry = { + main: ['babel-polyfill', './src/main'], + vendors: './src/vendors' + }; + config.module + .rule('iview') + .test(/iview.src.*?js$/) + .use('babel') + .loader('babel-loader') + .end(); + config.resolve.alias + .set('@', resolve('src')) // key,value自行定义,比如.set('@@', resolve('src/components')) + .set('_c', resolve('src/components')); + }, + // 设为false打包时不生成.map文件 + productionSourceMap: false, + // 这里写你调用接口的基础路径,来解决跨域,如果设置了代理,那你本地开发环境的axios的baseUrl要写为 '' ,即空字符串 + // devServer: { + // proxy: 'localhost:3000' + // } + configureWebpack: { + plugins: [ + // 开启gzip压缩 + new CompressionWebpackPlugin({ + algorithm: 'gzip', + test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'), + threshold: 10240, + minRatio: 0.8 + }) + ], + optimization: { + minimizer: [ + new UglifyJsPlugin({ + uglifyOptions: { + compress: { + warnings: true, + drop_console: true, // console + drop_debugger: true, + pure_funcs: ['console.log'] // 移除console + } + } + }) + ] + } + } +}; diff --git a/java/smart-admin-api/doc/readme.txt b/java/smart-admin-api/doc/readme.txt new file mode 100644 index 00000000..e5cd39c0 --- /dev/null +++ b/java/smart-admin-api/doc/readme.txt @@ -0,0 +1,17 @@ +1 更新密码 +com.gangquan360.smartadmin.module.employee.EmployeeController.updatePwd + +2 更新功能点 +PrivilegeController functionSaveOrUpdate和menuBatchSave + +3 超管默认账号 +sa/123456 + +4 执行脚本: +先执行:src/main/resources/sql/smart-admin.sql +再执行:src/main/resources/sql/quartz_mysql_2.3.0.sql + +5 除dev之外文件 + +6 刷新页面,获取权限是否走缓存 +com.gangquan360.smartadmin.module.login.LoginService.getSession \ No newline at end of file diff --git a/java/smart-admin-api/pom.xml b/java/smart-admin-api/pom.xml new file mode 100644 index 00000000..c40ad514 --- /dev/null +++ b/java/smart-admin-api/pom.xml @@ -0,0 +1,386 @@ + + + com.gangquan360 + smart-admin-parent + 1.0.0 + + + 4.0.0 + smart-admin-api + jar + + smart-admin-api + + + UTF-8 + UTF-8 + + + + + + velocity + + + commons-collections + commons-collections + + + org.apache.velocity + + + + org.springframework.boot + spring-boot-starter-log4j2 + + + + org.apache.logging.log4j + log4j-web + 2.10.0 + + + + org.springframework.boot + spring-boot-starter-actuator + + + logback-classic + ch.qos.logback + + + spring-boot-starter-logging + org.springframework.boot + + + + + + org.springframework.boot + spring-boot-starter-websocket + + + + org.projectlombok + lombok + provided + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.boot + spring-boot-starter + + + + + + com.microsoft.sqlserver + mssql-jdbc + + + + + com.alibaba + druid + + + + com.alibaba + fastjson + + + + org.springframework.boot + spring-boot-starter-jdbc + + + logback-classic + ch.qos.logback + + + spring-boot-starter + org.springframework.boot + + + + + + mysql + mysql-connector-java + + + + com.baomidou + mybatisplus-spring-boot-starter + + + spring-boot-starter-logging + org.springframework.boot + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-devtools + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.jsonwebtoken + jjwt + + + + org.springframework.boot + spring-boot-starter-mail + + + spring-boot-starter + org.springframework.boot + + + + + org.springframework.boot + spring-boot-starter-quartz + + + org.quartz-scheduler + quartz + + + org.quartz-scheduler + quartz-jobs + + + + org.apache.commons + commons-lang3 + + + + + io.springfox + springfox-swagger2 + + + + io.springfox + springfox-swagger-ui + + + + com.googlecode.concurrentlinkedhashmap + concurrentlinkedhashmap-lru + + + + org.springframework.boot + spring-boot-starter-aop + + + + org.apache.velocity + velocity-engine-core + test + + + + + redis.clients + jedis + + + + cn.afterturn + easypoi-base + + + javassist + org.javassist + + + + + + cn.afterturn + easypoi-web + + + + cn.afterturn + easypoi-annotation + + + + org.apache.poi + poi + + + + org.apache.poi + poi-ooxml-schemas + + + + org.apache.poi + poi-ooxml + + + + commons-beanutils + commons-beanutils + + + + com.thoughtworks.xstream + xstream + 1.4.10 + + + + org.springframework.boot + spring-boot-test + + + + + com.qiniu + qiniu-java-sdk + + + + + com.aliyun.oss + aliyun-sdk-oss + + + commons-lang + commons-lang + + + commons-logging + commons-logging + + + commons-collections + commons-collections + + + + + + com.baomidou + mybatis-plus + + + + eu.bitwalker + UserAgentUtils + + + + com.github.penggle + kaptcha + + + + com.squareup.okhttp3 + okhttp + + + + + + + + src/main/java + + **/*.* + + + + false + src/main/resources + + dev/* + sit/* + pre/* + prod/* + + + + src/main/resources/${profiles.active} + true + + *.properties + *.xml + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + + + + pl.project13.maven + git-commit-id-plugin + 2.2.4 + + + get-the-git-infos + + revision + + + + + ${project.basedir}/.git + git + false + true + ${project.build.outputDirectory}/git.properties + json + + false + false + -dirty + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/SmartAdminApplication.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/SmartAdminApplication.java new file mode 100644 index 00000000..2ef566e1 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/SmartAdminApplication.java @@ -0,0 +1,28 @@ +package com.gangquan360.smartadmin; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.EnableAspectJAutoProxy; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * [ admin 项目启动类 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@SpringBootApplication(scanBasePackages = {"com.gangquan360.smartadmin", "cn.afterturn.easypoi"}) +@EnableCaching +@EnableScheduling +@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true) +public class SmartAdminApplication { + + public static void main(String[] args) { + SpringApplication.run(SmartAdminApplication.class, args); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/ApiModelPropertyEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/ApiModelPropertyEnum.java new file mode 100644 index 00000000..39b2f92f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/ApiModelPropertyEnum.java @@ -0,0 +1,35 @@ +package com.gangquan360.smartadmin.common.anno; + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 枚举类字段属性的注解 + * + * @author listen + * @date 2019/05/16 15:18 + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +public @interface ApiModelPropertyEnum { + + /** + * 枚举类对象 + * + * @return + */ + Class value(); + + String example() default ""; + + boolean required() default true; + + String dataType() default ""; + + String enumDesc() default ""; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/DataScope.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/DataScope.java new file mode 100644 index 00000000..ec58da8c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/DataScope.java @@ -0,0 +1,34 @@ +package com.gangquan360.smartadmin.common.anno; + +import com.gangquan360.smartadmin.module.datascope.constant.DataScopeTypeEnum; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * [ 数据范围 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface DataScope { + + DataScopeTypeEnum dataScopeType() default DataScopeTypeEnum.DEFAULT; + + /** + * 第几个where 条件 从0开始 + * @return + */ + int whereIndex() default 0; + + String joinSql() default ""; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/NoNeedLogin.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/NoNeedLogin.java new file mode 100644 index 00000000..4bb314a8 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/NoNeedLogin.java @@ -0,0 +1,22 @@ +package com.gangquan360.smartadmin.common.anno; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * + * [ 不需要登陆 ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface NoNeedLogin { +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/NoValidPrivilege.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/NoValidPrivilege.java new file mode 100644 index 00000000..4ba657c3 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/NoValidPrivilege.java @@ -0,0 +1,20 @@ +package com.gangquan360.smartadmin.common.anno; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * + * [ 不需要权限验证 ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Retention(RetentionPolicy.RUNTIME) +public @interface NoValidPrivilege { + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/OperateLog.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/OperateLog.java new file mode 100644 index 00000000..c6762082 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/anno/OperateLog.java @@ -0,0 +1,20 @@ +package com.gangquan360.smartadmin.common.anno; + +import java.lang.annotation.*; + +/** + * [ 用户操作日志 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +public @interface OperateLog { + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/CommentSortTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/CommentSortTypeEnum.java new file mode 100644 index 00000000..da4d561c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/CommentSortTypeEnum.java @@ -0,0 +1,57 @@ +package com.gangquan360.smartadmin.common.constant; + + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +/** + * 全局排序枚举类 + * + * @author listen + * @date 2018/01/13 14:24 + */ +public enum CommentSortTypeEnum implements BaseEnum { + + /** + * 正序 ASC 1 + */ + ASC(1, "ASC"), + + /** + * 倒序 DESC 2 + */ + DESC(2, "DESC"); + + private Integer value; + + private String desc; + + /** + * 排序类型:1正序 | 2倒序 + */ + public static final String INFO = "排序类型:1正序 | 2倒序"; + + CommentSortTypeEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + /** + * 获取枚举类的值 + * + * @return Integer + */ + @Override + public Integer getValue() { + return value; + } + + /** + * 获取枚举类的说明 + * + * @return String + */ + @Override + public String getDesc() { + return desc; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/JudgeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/JudgeEnum.java new file mode 100644 index 00000000..dda791a5 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/JudgeEnum.java @@ -0,0 +1,52 @@ +package com.gangquan360.smartadmin.common.constant; + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +import java.util.Arrays; +import java.util.Optional; + +/** + * + * [ 是与否] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +public enum JudgeEnum implements BaseEnum { + + NO(0, "否"), + + YES(1, "是"); + + private Integer value; + private String desc; + + JudgeEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + @Override + public Integer getValue() { + return value; + } + @Override + public String getDesc() { + return desc; + } + + public static JudgeEnum valueOf(Integer status) { + JudgeEnum[] values = JudgeEnum.values(); + Optional first = Arrays.stream(values).filter(e -> e.getValue().equals(status)).findFirst(); + return !first.isPresent() ? null : first.get(); + } + + public static boolean isExist(Integer status) { + JudgeEnum judgeEnum = valueOf(status); + return judgeEnum != null; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/ResponseCodeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/ResponseCodeConst.java new file mode 100644 index 00000000..df0cef93 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/constant/ResponseCodeConst.java @@ -0,0 +1,183 @@ +package com.gangquan360.smartadmin.common.constant; + +import com.gangquan360.smartadmin.module.department.DepartmentResponseCodeConst; +import com.gangquan360.smartadmin.module.employee.constant.EmployeeResponseCodeConst; +import com.gangquan360.smartadmin.module.file.constant.FileResponseCodeConst; +import com.gangquan360.smartadmin.module.log.orderoperatelog.constant.OrderOperateLogOperateTypeConst; +import com.gangquan360.smartadmin.module.login.LoginResponseCodeConst; +import com.gangquan360.smartadmin.module.position.PositionResponseCodeConst; +import com.gangquan360.smartadmin.module.privilege.constant.PrivilegeResponseCodeConst; +import com.gangquan360.smartadmin.module.role.basic.RoleResponseCodeConst; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigResponseCodeConst; +import lombok.extern.slf4j.Slf4j; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * 每个业务,100个范围值就够了. + */ +@Slf4j +public class ResponseCodeConst { + + // 范围声明 + static { + // 系统功能,从0开始,step=1000 + ResponseCodeContainer.register(ResponseCodeConst.class, 0, 1000); + ResponseCodeContainer.register(LoginResponseCodeConst.class, 1001, 1999); + ResponseCodeContainer.register(DepartmentResponseCodeConst.class, 2001, 2999); + ResponseCodeContainer.register(EmployeeResponseCodeConst.class, 3001, 3999); + ResponseCodeContainer.register(FileResponseCodeConst.class, 4001, 4999); + ResponseCodeContainer.register(SystemConfigResponseCodeConst.class, 5001, 5999); + ResponseCodeContainer.register(RoleResponseCodeConst.class, 6001, 6999); + ResponseCodeContainer.register(PrivilegeResponseCodeConst.class, 7001, 7999); + ResponseCodeContainer.register(OrderOperateLogOperateTypeConst.class, 8001, 8999); + ResponseCodeContainer.register(PositionResponseCodeConst.class, 13000, 13999); + + } + + public static final ResponseCodeConst SUCCESS = new ResponseCodeConst(1, "success", true); + + public static final ResponseCodeConst COMMON_ERROR = new ResponseCodeConst(2, "我错了...."); + + public static final ResponseCodeConst ERROR_PARAM = new ResponseCodeConst(101, "参数异常!"); + + public static final ResponseCodeConst ERROR_PARAM_ANY = new ResponseCodeConst(102, "%s参数异常!"); + + public static final ResponseCodeConst SYSTEM_ERROR = new ResponseCodeConst(111, "系统错误"); + + public static final ResponseCodeConst DEVELOPMENT = new ResponseCodeConst(112, "此功能正在开发中"); + + public static final ResponseCodeConst NOT_EXISTS = new ResponseCodeConst(113, "数据不存在"); + + public static ResponseCodeConst REQUEST_METHOD_ERROR = new ResponseCodeConst(114, "请求方式错误"); + + public static ResponseCodeConst JSON_FORMAT_ERROR = new ResponseCodeConst(115, "JSON格式错误"); + + protected int code; + + protected String msg; + + protected boolean success; + + public ResponseCodeConst() { + } + + protected ResponseCodeConst(int code, String msg) { + super(); + this.code = code; + this.msg = msg; + ResponseCodeContainer.put(this); + } + + protected ResponseCodeConst(int code, String msg, boolean success) { + super(); + this.code = code; + this.msg = msg; + this.success = success; + ResponseCodeContainer.put(this); + } + + protected ResponseCodeConst(int code) { + super(); + this.code = code; + ResponseCodeContainer.put(this); + } + + public int getCode() { + return code; + } + + public void setCode(int code) { + this.code = code; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public static void init() { + log.info("ResponseCodeConst init...."); + } + + // =======================分割======================= + + /** + * 内部类,用于检测code范围 + * + * @author Anders + */ + @Slf4j + private static class ResponseCodeContainer { + + private static final Map RESPONSE_CODE_MAP = new HashMap<>(); + + private static final Map, int[]> RESPONSE_CODE_RANGE_MAP = new HashMap<>(); + + /** + * id的范围:[start, end]左闭右闭 + * + * @param clazz + * @param start + * @param end + */ + private static void register(Class clazz, int start, int end) { + if (start > end) { + throw new IllegalArgumentException(" start > end!"); + } + + if (RESPONSE_CODE_RANGE_MAP.containsKey(clazz)) { + throw new IllegalArgumentException(String.format(" Class:%s already exist!", clazz.getSimpleName())); + } + RESPONSE_CODE_RANGE_MAP.forEach((k, v) -> { + if ((start >= v[0] && start <= v[1]) || (end >= v[0] && end <= v[1])) { + throw new IllegalArgumentException(String.format(" Class:%s 's id range[%d,%d] has " + "intersection with " + "class:%s", clazz.getSimpleName(), start, end, + k.getSimpleName())); + } + }); + + RESPONSE_CODE_RANGE_MAP.put(clazz, new int[]{start, end}); + + // 提前初始化static变量,进行范围检测 + Field[] fields = clazz.getFields(); + if (fields.length != 0) { + try { + fields[0].get(clazz); + } catch (IllegalArgumentException | IllegalAccessException e) { + log.error("", e); + } + } + } + + public static void put(ResponseCodeConst codeConst) { + int[] idRange = RESPONSE_CODE_RANGE_MAP.get(codeConst.getClass()); + if (idRange == null) { + throw new IllegalArgumentException(String.format(" Class:%s has not been registered!", codeConst.getClass().getSimpleName())); + } + int code = codeConst.code; + if (code < idRange[0] || code > idRange[1]) { + throw new IllegalArgumentException(String.format(" Id(%d) out of range[%d,%d], " + "class:%s", code, idRange[0], idRange[1], codeConst.getClass().getSimpleName())); + } + if (RESPONSE_CODE_MAP.keySet().contains(code)) { + log.error(String.format(" Id(%d) out of range[%d,%d], " + "class:%s code is repeat!", code, idRange[0], idRange[1], codeConst.getClass().getSimpleName())); + System.exit(0); + } + RESPONSE_CODE_MAP.put(code, codeConst); + } + + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/BaseEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/BaseEntity.java new file mode 100644 index 00000000..507fb215 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/BaseEntity.java @@ -0,0 +1,38 @@ +package com.gangquan360.smartadmin.common.domain; + +import com.baomidou.mybatisplus.annotations.TableId; +import com.baomidou.mybatisplus.enums.IdType; +import lombok.Data; + +import java.util.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 上午 11:15 + * @since JDK1.8 + */ +@Data +public class BaseEntity { + + /** + * 主键id + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/BaseEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/BaseEnum.java new file mode 100644 index 00000000..7e194637 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/BaseEnum.java @@ -0,0 +1,97 @@ +package com.gangquan360.smartadmin.common.domain; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONAware; +import com.alibaba.fastjson.JSONObject; +import com.google.common.base.CaseFormat; +import lombok.Data; + +import java.util.LinkedHashMap; +import java.util.Objects; + +/** + * @author listen + * @date 2018-07-17 下午 3:52 + */ +public interface BaseEnum { + + /** + * 获取枚举类的值 + * + * @return Object + */ + Object getValue(); + + /** + * 获取枚举类的说明 + * + * @return String + */ + String getDesc(); + + /** + * 比较参数是否与枚举类的value相同 + * + * @param value + * @return boolean + */ + default boolean equalsValue(Object value) { + return Objects.equals(getValue(), value); + } + + /** + * 比较枚举类是否相同 + * + * @param baseEnum + * @return boolean + */ + default boolean equals(BaseEnum baseEnum) { + return Objects.equals(getValue(), baseEnum.getValue()) && Objects.equals(getDesc(), baseEnum.getDesc()); + } + + /** + * 返回枚举类的说明 + * + * @param clazz 枚举类类对象 + * @return + */ + static String getInfo(Class clazz) { + BaseEnum[] enums = clazz.getEnumConstants(); + LinkedHashMap json = new LinkedHashMap<>(enums.length); + for (BaseEnum e : enums) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("value", new DeletedQuotationAware(e.getValue())); + jsonObject.put("desc", new DeletedQuotationAware(e.getDesc())); + json.put(e.toString(), jsonObject); + } + + String enumJson = JSON.toJSONString(json, true); + enumJson = enumJson.replaceAll("\"", ""); + enumJson= enumJson.replaceAll("\t","  "); + enumJson = enumJson.replaceAll("\n","
"); + String prefix = "
export const
" + CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, clazz.getSimpleName() + " =
"); + return prefix + "" + enumJson + "
"; + } + + + @Data + class DeletedQuotationAware implements JSONAware { + + private String value; + + public DeletedQuotationAware(Object value) { + if(value == null){ + this.value = ""; + }else if (value instanceof String) { + this.value = "'" + value + "'"; + }else { + this.value = value.toString(); + } + } + + @Override + public String toJSONString() { + return value; + } + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/PageParamDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/PageParamDTO.java new file mode 100644 index 00000000..7d768fb2 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/PageParamDTO.java @@ -0,0 +1,35 @@ +package com.gangquan360.smartadmin.common.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.Max; +import javax.validation.constraints.NotNull; + +/** + * 分页基础参数 + * + * @author lihaifan + * @Date Created in 2017/10/28 16:19 + */ +@Data +public class PageParamDTO { + + @NotNull(message = "分页参数不能为空") + @ApiModelProperty(value = "页码(不能为空)", example = "1") + protected Integer pageNum; + + @NotNull(message = "每页数量不能为空") + @ApiModelProperty(value = "每页数量(不能为空)", example = "10") + @Max(value = 200, message = "每页最大为200") + protected Integer pageSize; + + @ApiModelProperty("排序规则:true正序 | false 倒序") + protected Boolean sort; + + @ApiModelProperty("排序字段") + protected String orderByField; + + @ApiModelProperty("是否查询总条数") + protected Boolean searchCount; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/PageResultDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/PageResultDTO.java new file mode 100644 index 00000000..94e3d803 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/PageResultDTO.java @@ -0,0 +1,47 @@ +package com.gangquan360.smartadmin.common.domain; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * Page返回对象 + * + * @Author lihaifan + * @Date Created in 2017/10/31 15:05 + */ +@Data +public class PageResultDTO { + + /** + * 当前页 + */ + @ApiModelProperty(value = "当前页") + private Integer pageNum; + + /** + * 每页的数量 + */ + @ApiModelProperty(value = "每页的数量") + private Integer pageSize; + + /** + * 总记录数 + */ + @ApiModelProperty(value = "总记录数") + private Long total; + + /** + * 总页数 + */ + @ApiModelProperty(value = "总页数") + private Integer pages; + + /** + * 结果集 + */ + @ApiModelProperty(value = "结果集") + private List list; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/ResponseDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/ResponseDTO.java new file mode 100644 index 00000000..df28466c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/domain/ResponseDTO.java @@ -0,0 +1,128 @@ +package com.gangquan360.smartadmin.common.domain; + + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + +/** + * 返回类 + * + * @param + * @author gangquan + */ +public class ResponseDTO { + + protected Integer code; + + protected String msg; + + protected Boolean success; + + protected T data; + + public ResponseDTO() { + } + + public ResponseDTO(ResponseCodeConst responseCodeConst, String msg) { + this.code = responseCodeConst.getCode(); + this.msg = msg; + this.success = responseCodeConst.isSuccess(); + } + + public ResponseDTO(ResponseCodeConst responseCodeConst, T data) { + super(); + this.code = responseCodeConst.getCode(); + this.msg = responseCodeConst.getMsg(); + this.data = data; + this.success = responseCodeConst.isSuccess(); + } + + public ResponseDTO(ResponseCodeConst responseCodeConst, T data, String msg) { + super(); + this.code = responseCodeConst.getCode(); + this.msg = msg; + this.data = data; + this.success = responseCodeConst.isSuccess(); + } + + private ResponseDTO(ResponseCodeConst responseCodeConst) { + this.code = responseCodeConst.getCode(); + this.msg = responseCodeConst.getMsg(); + this.success = responseCodeConst.isSuccess(); + } + + public ResponseDTO(ResponseDTO responseDTO) { + this.code = responseDTO.getCode(); + this.msg = responseDTO.getMsg(); + this.success = responseDTO.isSuccess(); + } + + public static ResponseDTO succ() { + return new ResponseDTO(ResponseCodeConst.SUCCESS); + } + + public static ResponseDTO succData(T data, String msg) { + return new ResponseDTO(ResponseCodeConst.SUCCESS, data, msg); + } + + public static ResponseDTO succData(T data) { + return new ResponseDTO(ResponseCodeConst.SUCCESS, data); + } + + public static ResponseDTO succMsg(String msg) { + return new ResponseDTO(ResponseCodeConst.SUCCESS, msg); + } + + + public static ResponseDTO wrap(ResponseCodeConst codeConst) { + return new ResponseDTO<>(codeConst); + } + + public static ResponseDTO wrap(ResponseCodeConst codeConst, T t) { + return new ResponseDTO(codeConst, t); + } + + public static ResponseDTO wrap(ResponseCodeConst codeConst, String msg) { + return new ResponseDTO(codeConst, msg); + } + + public String getMsg() { + return msg; + } + + public ResponseDTO setMsg(String msg) { + this.msg = msg; + return this; + } + + public int getCode() { + return code; + } + + public ResponseDTO setCode(Integer code) { + this.code = code; + return this; + } + + public T getData() { + return data; + } + + public ResponseDTO setData(T data) { + this.data = data; + return this; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + @Override + public String toString() { + return "ResponseDTO{" + "code=" + code + ", msg='" + msg + '\'' + ", success=" + success + ", data=" + data + + '}'; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/exception/SmartBusinessException.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/exception/SmartBusinessException.java new file mode 100644 index 00000000..2a35552b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/exception/SmartBusinessException.java @@ -0,0 +1,33 @@ +package com.gangquan360.smartadmin.common.exception; +/** + * + * [ 业务逻辑异常,全局异常拦截后统一返回ResponseCodeConst.SYSTEM_ERROR ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +public class SmartBusinessException extends RuntimeException { + + public SmartBusinessException() { + } + + public SmartBusinessException(String message) { + super(message); + } + + public SmartBusinessException(String message, Throwable cause) { + super(message, cause); + } + + public SmartBusinessException(Throwable cause) { + super(cause); + } + + public SmartBusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/exception/SmartResponseCodeException.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/exception/SmartResponseCodeException.java new file mode 100644 index 00000000..f0edc118 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/exception/SmartResponseCodeException.java @@ -0,0 +1,24 @@ +package com.gangquan360.smartadmin.common.exception; + +/** + * [ 全局异常拦截后保留ResponseCode码的异常] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/7 0007 下午 16:11 + * @since JDK1.8 + */ +public class SmartResponseCodeException extends RuntimeException{ + private Integer code; + + public SmartResponseCodeException(Integer code, String message) { + super(message); + this.code = code; + } + + public Integer getCode() { + return code; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/AbstractHeartBeatCommand.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/AbstractHeartBeatCommand.java new file mode 100644 index 00000000..d2a3412d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/AbstractHeartBeatCommand.java @@ -0,0 +1,90 @@ +package com.gangquan360.smartadmin.common.heartbeat; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.util.Date; +import java.util.List; +import java.util.concurrent.*; + + +/** +* @Description: 心跳服务 +* @Author: simajinqiang +* @Date: 2018/7/9 16:26 +*/ +public abstract class AbstractHeartBeatCommand implements HeartBeatRecordCommendInterface { + + + ScheduledExecutorService executorService; + + int threadNum = 1; + + /** + * 项目路径 + */ + private String projectPath; + /** + * 服务器ip(多网卡) + */ + private List serverIps; + /** + * 进程号 + */ + private Integer processNo; + /** + * 进程开启时间 + */ + private Date processStartTime; + + HeartBeatLogger logger; + + /** + * 初始化 + */ + public void init(HeartBeatConfig config, HeartBeatLogger logger){ + this.handlerHeartBeat(); + ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("AbstractHeartBeatCommand-%s").build(); + executorService = Executors.newScheduledThreadPool(threadNum, threadFactory); + executorService.scheduleWithFixedDelay(new DoHeartBeat(), config.getDelayHandlerTime(), config.getIntervalTime(), TimeUnit.MILLISECONDS); + } + + public void handlerHeartBeat(){ + try { + projectPath = HeatBeatRecordHelper.getProjectPath(); + serverIps = IpUtil.getLocalIPS(); + processNo = HeatBeatRecordHelper.getProcessID(); + processStartTime = HeatBeatRecordHelper.getStartTime(); + }catch (Throwable e){ + logger.error("get heart beat info error.", e); + } + } + + /** + * 销毁线程池 + */ + public void destroy(){ + if (executorService != null && !executorService.isShutdown()) { + executorService.shutdown(); + executorService = null; + } + } + + public class DoHeartBeat implements Runnable{ + + @Override + public void run() { + try { + HeartBeatRecordDTO heartBeatRecord = new HeartBeatRecordDTO(); + heartBeatRecord.setProjectPath(projectPath); + heartBeatRecord.setServerIp(StringUtil.join(serverIps,";")); + heartBeatRecord.setProcessNo(processNo); + heartBeatRecord.setProcessStartTime(processStartTime); + heartBeatRecord.setHeartBeatTime(new Date()); + handler(heartBeatRecord); + }catch (Throwable t){ + logger.error("handler heartbeat error.", t); + } + + } + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatConfig.java new file mode 100644 index 00000000..7e6f5f0a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatConfig.java @@ -0,0 +1,29 @@ +package com.gangquan360.smartadmin.common.heartbeat; + +import lombok.Builder; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/8 0008 下午 16:22 + * @since JDK1.8 + */ +@Data +@Builder +public class HeartBeatConfig { + + /** + * 延迟执行时间 + */ + private Long delayHandlerTime; + + /** + * 间隔执行时间 + */ + private Long intervalTime; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatLogger.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatLogger.java new file mode 100644 index 00000000..b624fe1e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatLogger.java @@ -0,0 +1,20 @@ +package com.gangquan360.smartadmin.common.heartbeat; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/8 0008 下午 16:23 + * @since JDK1.8 + */ +public interface HeartBeatLogger { + + void error(String string); + + void error(String string, Throwable e); + + void info(String string); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatRecordCommendInterface.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatRecordCommendInterface.java new file mode 100644 index 00000000..943836a9 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatRecordCommendInterface.java @@ -0,0 +1,17 @@ +package com.gangquan360.smartadmin.common.heartbeat; + + + +/** +* @Description: +* @Author: simajinqiang +* @Date: 2018/7/9 14:06 +*/ +public interface HeartBeatRecordCommendInterface { + /** + * 处理 + * @param heartBeatRecord + */ + void handler(HeartBeatRecordDTO heartBeatRecord); + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatRecordDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatRecordDTO.java new file mode 100644 index 00000000..83914968 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeartBeatRecordDTO.java @@ -0,0 +1,37 @@ +package com.gangquan360.smartadmin.common.heartbeat; + +import lombok.Data; + +import java.util.Date; + +/** +* @Description: 心跳记录日志 +* @Author: simajinqiang +* @Date: 2018/7/9 11:11 +*/ +@Data +public class HeartBeatRecordDTO { + + /** + * 项目名字 + */ + private String projectPath; + /** + * 服务器ip + */ + private String serverIp; + /** + * 进程号 + */ + private Integer processNo; + /** + * 进程开启时间 + */ + private Date processStartTime; + /** + * 心跳当前时间 + */ + private Date heartBeatTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeatBeatRecordHelper.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeatBeatRecordHelper.java new file mode 100644 index 00000000..41e4ed3d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/HeatBeatRecordHelper.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.common.heartbeat; + + +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.util.Date; + +/** +* @Description: 心跳工具类 +* @Author: simajinqiang +* @Date: 2018/7/9 11:48 +*/ +public class HeatBeatRecordHelper { + + /** + * 获取进程号 + * @return + */ + public static final Integer getProcessID() { + RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); + return Integer.valueOf(runtimeMXBean.getName().split("@")[0]) + .intValue(); + } + + /** + * 获取项目名称 + * @return + */ + public static final String getProjectPath(){ + return System.getProperty("user.dir"); + } + + /** + * 获取进程启动时间 + * @return + */ + public static final Date getStartTime(){ + RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean(); + return new Date(runtimeMXBean.getStartTime()); + } + + + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/IpUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/IpUtil.java new file mode 100644 index 00000000..d3359bdc --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/IpUtil.java @@ -0,0 +1,81 @@ +package com.gangquan360.smartadmin.common.heartbeat; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +/** +* @Description: ip工具类 +* @Author: sbq +* @CreateDate: 2019/8/8 10:33 +* @Version: 1.0 +*/ +public class IpUtil { + /** + * 获得服务器的IP地址 + */ + public static String getLocalIP() { + String sIP = ""; + InetAddress ip = null; + try { + boolean bFindIP = false; + Enumeration netInterfaces = (Enumeration) NetworkInterface + .getNetworkInterfaces(); + while (netInterfaces.hasMoreElements()) { + if (bFindIP) { + break; + } + NetworkInterface ni = (NetworkInterface) netInterfaces + .nextElement(); + Enumeration ips = ni.getInetAddresses(); + while (ips.hasMoreElements()) { + ip = (InetAddress) ips.nextElement(); + if (!ip.isLoopbackAddress() + && ip.getHostAddress().matches( + "(\\d{1,3}\\.){3}\\d{1,3}")) { + bFindIP = true; + break; + } + } + } + } catch (Exception e) { + } + if (null != ip) { + sIP = ip.getHostAddress(); + } + return sIP; + } + + /** + * @Description: 获得服务器的IP地址(多网卡) + * @Author: sbq + * @CreateDate: 2019/8/8 10:34 + * @Version: 1.0 + */ + public static List getLocalIPS() { + InetAddress ip = null; + List ipList = new ArrayList(); + try { + Enumeration netInterfaces = (Enumeration) NetworkInterface + .getNetworkInterfaces(); + while (netInterfaces.hasMoreElements()) { + NetworkInterface ni = (NetworkInterface) netInterfaces + .nextElement(); + Enumeration ips = ni.getInetAddresses(); + while (ips.hasMoreElements()) { + ip = (InetAddress) ips.nextElement(); + if (!ip.isLoopbackAddress() + && ip.getHostAddress().matches( + "(\\d{1,3}\\.){3}\\d{1,3}")) { + ipList.add(ip.getHostAddress()); + } + } + } + } catch (Exception e) { + } + return ipList; + } + +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/StringUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/StringUtil.java new file mode 100644 index 00000000..bcbffa59 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/heartbeat/StringUtil.java @@ -0,0 +1,60 @@ +package com.gangquan360.smartadmin.common.heartbeat; + +import java.util.Iterator; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/8 0008 下午 16:27 + * @since JDK1.8 + */ +public class StringUtil { + + + + public static String join(Iterable iterable, String separator) { + return iterable == null ? null : join(iterable.iterator(), separator); + } + + + public static String join(Iterator iterator, String separator) { + if (iterator == null) { + return null; + } else if (!iterator.hasNext()) { + return ""; + } else { + Object first = iterator.next(); + if (!iterator.hasNext()) { + String result = toString(first); + return result; + } else { + StringBuilder buf = new StringBuilder(256); + if (first != null) { + buf.append(first); + } + + while(iterator.hasNext()) { + if (separator != null) { + buf.append(separator); + } + + Object obj = iterator.next(); + if (obj != null) { + buf.append(obj); + } + } + + return buf.toString(); + } + } + } + + public static String toString(Object obj) { + return obj == null ? "" : obj.toString(); + } + +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/json/LongJsonDeserializer.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/json/LongJsonDeserializer.java new file mode 100644 index 00000000..50d809a5 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/json/LongJsonDeserializer.java @@ -0,0 +1,21 @@ +package com.gangquan360.smartadmin.common.json; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; + +import java.io.IOException; + +public class LongJsonDeserializer extends JsonDeserializer { + + @Override + public Long deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { + String value = jsonParser.getText(); + try { + return value == null ? null : Long.parseLong(value); + } catch (NumberFormatException e) { + return null; + } + } +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/json/LongJsonSerializer.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/json/LongJsonSerializer.java new file mode 100644 index 00000000..1682357b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/json/LongJsonSerializer.java @@ -0,0 +1,19 @@ +package com.gangquan360.smartadmin.common.json; + + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; + +public class LongJsonSerializer extends JsonSerializer { + @Override + public void serialize(Long value, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { + String text = (value == null ? null : String.valueOf(value)); + if (text != null) { + jsonGenerator.writeString(text); + } + } +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaColor.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaColor.java new file mode 100644 index 00000000..638ac106 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaColor.java @@ -0,0 +1,39 @@ +package com.gangquan360.smartadmin.common.kaptcha; + +import com.google.common.collect.Lists; + +import java.awt.*; +import java.util.List; +import java.util.Random; + +/** + * [ 验证码颜色 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/6 0006 上午 10:51 + * @since JDK1.8 + */ +public class KaptchaColor { + + public static Color getColor() { + + List colors = Lists.newArrayList(); + colors.add(new Color(0, 135, 255)); + colors.add(new Color(51, 153, 51)); + colors.add(new Color(255, 102, 102)); + colors.add(new Color(255, 153, 0)); + colors.add(new Color(153, 102, 0)); + colors.add(new Color(153, 102, 153)); + colors.add(new Color(51, 153, 153)); + colors.add(new Color(102, 102, 255)); + colors.add(new Color(0, 102, 204)); + colors.add(new Color(204, 51, 51)); + colors.add(new Color(128, 153, 65)); + Random random = new Random(); + int colorIndex = random.nextInt(10); + return colors.get(colorIndex); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaNoise.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaNoise.java new file mode 100644 index 00000000..3af2a7ad --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaNoise.java @@ -0,0 +1,44 @@ +package com.gangquan360.smartadmin.common.kaptcha; + +import com.google.code.kaptcha.NoiseProducer; +import com.google.code.kaptcha.util.Configurable; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.Random; + +/** + * [ 验证码加噪处理 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/6 0006 上午 10:47 + * @since JDK1.8 + */ +public class KaptchaNoise extends Configurable implements NoiseProducer { + public KaptchaNoise() { + } + + @Override + public void makeNoise(BufferedImage image, float factorOne, float factorTwo, float factorThree, float factorFour) { + + int width = image.getWidth(); + int height = image.getHeight(); + Graphics2D graph = (Graphics2D)image.getGraphics(); + graph.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)); + graph.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); + Random random = new Random(); + int noiseLineNum = random.nextInt(3); + if(noiseLineNum == 0){ + noiseLineNum = 1; + } + for (int i = 0; i < noiseLineNum; i++){ + graph.setColor(KaptchaColor.getColor()); + graph.drawLine(random.nextInt(width), random.nextInt(height), 10 + random.nextInt(20), 10 + random.nextInt(20)); + } + + graph.dispose(); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaWordRenderer.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaWordRenderer.java new file mode 100644 index 00000000..ef0269b1 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/kaptcha/KaptchaWordRenderer.java @@ -0,0 +1,75 @@ +package com.gangquan360.smartadmin.common.kaptcha; + +import com.google.code.kaptcha.util.Configurable; + +import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.image.BufferedImage; +import java.util.Random; + +/** + * [ 验证码字体生成 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/6 0006 上午 9:43 + * @since JDK1.8 + */ +public class KaptchaWordRenderer extends Configurable implements com.google.code.kaptcha.text.WordRenderer { + + public KaptchaWordRenderer() { + } + + @Override + public BufferedImage renderWord(String word, int width, int height) { + int fontSize = this.getConfig().getTextProducerFontSize(); + Font[] fonts = this.getConfig().getTextProducerFonts(fontSize); + int charSpace = this.getConfig().getTextProducerCharSpace(); + BufferedImage image = new BufferedImage(width, height, 2); + + Graphics2D g2D = image.createGraphics(); + g2D.setColor(Color.WHITE); + RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + hints.add(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY)); + g2D.setRenderingHints(hints); + g2D.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); + + FontRenderContext frc = g2D.getFontRenderContext(); + Random random = new Random(); + int startPosY = (height - fontSize) / 5 + fontSize; + char[] wordChars = word.toCharArray(); + Font[] chosenFonts = new Font[wordChars.length]; + int[] charWidths = new int[wordChars.length]; + int widthNeeded = 0; + + int startPosX; + for(startPosX = 0; startPosX < wordChars.length; ++startPosX) { + chosenFonts[startPosX] = fonts[random.nextInt(fonts.length)]; + char[] charToDraw = new char[]{wordChars[startPosX]}; + GlyphVector gv = chosenFonts[startPosX].createGlyphVector(frc, charToDraw); + charWidths[startPosX] = (int)gv.getVisualBounds().getWidth(); + if (startPosX > 0) { + widthNeeded += 2; + } + + widthNeeded += charWidths[startPosX]; + } + + startPosX = (width - widthNeeded) / 2; + + for(int i = 0; i < wordChars.length; ++i) { + g2D.setColor(KaptchaColor.getColor()); + g2D.setFont(chosenFonts[i].deriveFont(Font.PLAIN)); + char[] charToDraw = new char[]{wordChars[i]}; + g2D.drawChars(charToDraw, 0, charToDraw.length, startPosX, startPosY); + startPosX = startPosX + charWidths[i] + charSpace; + } + + return image; + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/SmartReloadManager.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/SmartReloadManager.java new file mode 100644 index 00000000..f6e7352e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/SmartReloadManager.java @@ -0,0 +1,134 @@ +package com.gangquan360.smartadmin.common.reload; + +import com.gangquan360.smartadmin.common.reload.annotation.SmartReload; +import com.gangquan360.smartadmin.common.reload.domain.AbstractSmartReloadObject; +import com.gangquan360.smartadmin.common.reload.domain.AnnotationReloadObject; +import com.gangquan360.smartadmin.common.reload.domain.InterfaceReloadObject; +import com.gangquan360.smartadmin.common.reload.domain.entity.ReloadItem; +import com.gangquan360.smartadmin.common.reload.domain.entity.SmartReloadResult; +import com.gangquan360.smartadmin.common.reload.interfaces.SmartReloadCommandInterface; +import com.gangquan360.smartadmin.common.reload.interfaces.SmartReloadThreadLogger; +import com.gangquan360.smartadmin.common.reload.interfaces.SmartReloadable; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; + +import static java.util.Objects.requireNonNull; + +/** + * SmartReloadManager 管理器 + *

+ * 可以在此类中添加 检测任务 以及注册 处理程序 + * + * @author zhuoda + */ +public class SmartReloadManager { + + private Map tagReloadObject; + + private SmartReloadScheduler reloadScheduler; + + private SmartReloadThreadLogger logger; + + public SmartReloadManager(SmartReloadThreadLogger logger, int threadCount) { + this.tagReloadObject = new ConcurrentHashMap<>(); + if (logger == null) { + throw new ExceptionInInitializerError("SmartReloadLoggerImp cannot be null"); + } + + if (threadCount < 1) { + throw new ExceptionInInitializerError("threadCount must be greater than 1"); + } + + this.logger = logger; + this.reloadScheduler = new SmartReloadScheduler(this.logger, threadCount); + } + + /** + * 默认创建单个线程 + * + * @param logger + */ + public SmartReloadManager(SmartReloadThreadLogger logger) { + this(logger, 1); + } + + /** + * 停止 + */ + public void shutdown() { + reloadScheduler.shutdown(); + } + + /** + * 添加任务 + * + * @param command SmartReloadCommand实现类 + * @param initialDelay 第一次执行前的延迟时间 + * @param delay 任务间隔时间 + * @param unit 延迟单位 TimeUnit 天、小时、分、秒等 + */ + public void addCommand(SmartReloadCommandInterface command, long initialDelay, long delay, TimeUnit unit) { + reloadScheduler.addCommand(command, initialDelay, delay, unit); + } + + /** + * 注册 实现接口的方式 + * + * @param tag + * @param reloadable + */ + public void register(String tag, SmartReloadable reloadable) { + requireNonNull(reloadable); + requireNonNull(tag); + if (tagReloadObject.containsKey(tag)) { + logger.error("<> register duplicated tag reload : " + tag + " , and it will be cover!"); + } + tagReloadObject.put(tag, new InterfaceReloadObject(reloadable)); + } + + /** + * 注册 要求此类必须包含使用了SmartReload注解的方法 + * + * @param reloadObject + */ + public void register(Object reloadObject) { + requireNonNull(reloadObject); + Method[] declaredMethods = reloadObject.getClass().getDeclaredMethods(); + if (declaredMethods != null) { + for (int i = 0; i < declaredMethods.length; i++) { + Method method = declaredMethods[i]; + SmartReload annotation = method.getAnnotation(SmartReload.class); + if (annotation != null) { + String reloadTag = annotation.value(); + this.register(reloadTag, new AnnotationReloadObject(reloadObject, method)); + } + } + } + } + + private void register(String tag, AbstractSmartReloadObject reloadObject) { + if (tagReloadObject.containsKey(tag)) { + logger.error("<> register duplicated tag reload : " + tag + " , and it will be cover!"); + } + tagReloadObject.put(tag, reloadObject); + } + + /** + * Reload 已注册的ReloadItem + * + * @param reloadItem + * @return SmartReloadResult + */ + public SmartReloadResult doReload(ReloadItem reloadItem) { + AbstractSmartReloadObject reloadObject = tagReloadObject.get(reloadItem.getTag()); + if (reloadObject != null) { + return reloadObject.reload(reloadItem); + } + // 返回注册结果 + return new SmartReloadResult(reloadItem.getTag(), reloadItem.getArgs(), reloadItem.getIdentification(), false, "No registered reload handler was found"); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/SmartReloadScheduler.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/SmartReloadScheduler.java new file mode 100644 index 00000000..d0dc0587 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/SmartReloadScheduler.java @@ -0,0 +1,87 @@ +package com.gangquan360.smartadmin.common.reload; + +import com.gangquan360.smartadmin.common.reload.interfaces.SmartReloadCommandInterface; +import com.gangquan360.smartadmin.common.reload.interfaces.SmartReloadThreadLogger; + +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Reload 调度器 + * + * @author zhuoda + */ +public class SmartReloadScheduler { + + private ScheduledThreadPoolExecutor executor; + + private SmartReloadThreadLogger logger; + + SmartReloadScheduler(SmartReloadThreadLogger logger, int threadCount) { + this.executor = new ScheduledThreadPoolExecutor(threadCount, new SmartReloadSchedulerThreadFactory()); + this.logger = logger; + } + + void shutdown() { + try { + executor.shutdown(); + } catch (Throwable e) { + logger.error("<> shutdown ", e); + } + } + + void addCommand(SmartReloadCommandInterface command, long initialDelay, long delay, TimeUnit unit) { + executor.scheduleWithFixedDelay(new ScheduleRunnable(command, this.logger), initialDelay, delay, unit); + } + + static class ScheduleRunnable implements Runnable { + + private SmartReloadCommandInterface command; + + private SmartReloadThreadLogger logger; + + public ScheduleRunnable(SmartReloadCommandInterface command, SmartReloadThreadLogger logger) { + this.command = command; + this.logger = logger; + } + + @Override + public void run() { + try { + command.doTask(); + } catch (Throwable e) { + logger.error("", e); + } + } + } + + static class SmartReloadSchedulerThreadFactory implements ThreadFactory { + + private static final AtomicInteger poolNumber = new AtomicInteger(1); + + private final ThreadGroup group; + + private final AtomicInteger threadNumber = new AtomicInteger(1); + + private final String namePrefix; + + SmartReloadSchedulerThreadFactory() { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); + namePrefix = "smartreload-" + poolNumber.getAndIncrement() + "-thread-"; + } + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, namePrefix + 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/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/abstracts/AbstractSmartReloadCommand.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/abstracts/AbstractSmartReloadCommand.java new file mode 100644 index 00000000..b5b90aac --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/abstracts/AbstractSmartReloadCommand.java @@ -0,0 +1,66 @@ +package com.gangquan360.smartadmin.common.reload.abstracts; + +import com.gangquan360.smartadmin.common.reload.SmartReloadManager; +import com.gangquan360.smartadmin.common.reload.domain.entity.ReloadItem; +import com.gangquan360.smartadmin.common.reload.interfaces.SmartReloadCommandInterface; + +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 检测是否 Reload 的类 + * + * @author zhuoda + */ +public abstract class AbstractSmartReloadCommand implements SmartReloadCommandInterface { + + /** + * 当前ReloadItem的存储器 + */ + private ConcurrentHashMap currentTags = null; + + /** + * Reload的执行类 + */ + private SmartReloadManager reloadManager; + + public AbstractSmartReloadCommand(SmartReloadManager reloadManager) { + this.reloadManager = reloadManager; + this.currentTags = new ConcurrentHashMap<>(); + // 初始获取ReloadItem数据 + List readTagStatesFromDb = readReloadItem(); + if (readTagStatesFromDb != null) { + for (ReloadItem reloadItem : readTagStatesFromDb) { + String tag = reloadItem.getTag(); + String tagChangeIdentifier = reloadItem.getIdentification(); + this.currentTags.put(tag, tagChangeIdentifier); + } + } + } + /** + * 任务: + * 读取数据库中 ReloadItem 数据 + * 校验是否发生变化 + * 执行重加载动作 + */ + @Override + public void doTask() { + // 获取数据库数据 + List readTagStatesFromDb = readReloadItem(); + String tag; + String tagIdentifier; + String preTagChangeIdentifier; + for (ReloadItem reloadItem : readTagStatesFromDb) { + tag = reloadItem.getTag(); + tagIdentifier = reloadItem.getIdentification(); + preTagChangeIdentifier = currentTags.get(tag); + // 数据不一致 + if (preTagChangeIdentifier == null || ! preTagChangeIdentifier.equals(tagIdentifier)) { + // 更新map数据 + currentTags.put(tag, tagIdentifier); + // 执行重新加载此项的动作 + handleReloadResult(this.reloadManager.doReload(reloadItem)); + } + } + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/abstracts/AbstractSmartReloadCommand4Spring.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/abstracts/AbstractSmartReloadCommand4Spring.java new file mode 100644 index 00000000..4b550591 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/abstracts/AbstractSmartReloadCommand4Spring.java @@ -0,0 +1,68 @@ +package com.gangquan360.smartadmin.common.reload.abstracts; + +import com.gangquan360.smartadmin.common.reload.SmartReloadManager; +import com.gangquan360.smartadmin.common.reload.domain.entity.ReloadItem; +import com.gangquan360.smartadmin.common.reload.interfaces.SmartReloadCommandInterface; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 检测是否 Reload 的类 + * + * @author zhuoda + */ +public abstract class AbstractSmartReloadCommand4Spring implements SmartReloadCommandInterface { + + /** + * 当前ReloadItem的存储器 + */ + protected ConcurrentHashMap currentTags = new ConcurrentHashMap<>(); + + /** + * Reload的执行类 + */ + @Autowired + protected SmartReloadManager reloadManager; + +// @PostConstruct + public void init() { + List readTagStatesFromDb = readReloadItem(); + if (readTagStatesFromDb != null) { + for (ReloadItem reloadItem : readTagStatesFromDb) { + String tag = reloadItem.getTag(); + String tagChangeIdentifier = reloadItem.getIdentification(); + this.currentTags.put(tag, tagChangeIdentifier); + } + } + } + + /** + * 任务: + * 读取数据库中 ReloadItem 数据 + * 校验是否发生变化 + * 执行重加载动作 + */ + @Override + public void doTask() { + // 获取数据库数据 + List readTagStatesFromDb = readReloadItem(); + String tag; + String tagIdentifier; + String preTagChangeIdentifier; + for (ReloadItem reloadItem : readTagStatesFromDb) { + tag = reloadItem.getTag(); + tagIdentifier = reloadItem.getIdentification(); + preTagChangeIdentifier = currentTags.get(tag); + // 数据不一致 + if (preTagChangeIdentifier == null || ! preTagChangeIdentifier.equals(tagIdentifier)) { + // 更新map数据 + currentTags.put(tag, tagIdentifier); + // 执行重新加载此项的动作 + handleReloadResult(this.reloadManager.doReload(reloadItem)); + } + } + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/annotation/SmartReload.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/annotation/SmartReload.java new file mode 100644 index 00000000..6176ae2d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/annotation/SmartReload.java @@ -0,0 +1,18 @@ +package com.gangquan360.smartadmin.common.reload.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 定义 SmartReload 注解 + * + * @author zhuoda + */ +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface SmartReload { + + String value(); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/AbstractSmartReloadObject.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/AbstractSmartReloadObject.java new file mode 100644 index 00000000..1f37569d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/AbstractSmartReloadObject.java @@ -0,0 +1,31 @@ +package com.gangquan360.smartadmin.common.reload.domain; + +import com.gangquan360.smartadmin.common.reload.domain.entity.ReloadItem; +import com.gangquan360.smartadmin.common.reload.domain.entity.SmartReloadResult; + +import java.io.PrintWriter; +import java.io.StringWriter; +/** + * AbstractSmartReloadObject 处理程序的抽象类 + * + * @author zhuoda + */ +public abstract class AbstractSmartReloadObject { + + protected String getStackTrace(Throwable e) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + e.printStackTrace(pw); + return sw.toString(); + } + + /** + * 通过reloadItem参数reload,获得结果 + * + * @param reloadItem + * @return boolean + * @author zhuokongming + * @date 2016年10月21日 下午2:09:44 + */ + public abstract SmartReloadResult reload(ReloadItem reloadItem); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/AnnotationReloadObject.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/AnnotationReloadObject.java new file mode 100644 index 00000000..21ea4dea --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/AnnotationReloadObject.java @@ -0,0 +1,44 @@ +package com.gangquan360.smartadmin.common.reload.domain; + +import com.gangquan360.smartadmin.common.reload.annotation.SmartReload; +import com.gangquan360.smartadmin.common.reload.domain.entity.ReloadItem; +import com.gangquan360.smartadmin.common.reload.domain.entity.SmartReloadResult; + +import java.lang.reflect.Method; + +/** + * Reload 处理程序的实现类 + * 用于包装以注解 SmartReload 实现的处理类 + * + * @author zhuoda + */ +public class AnnotationReloadObject extends AbstractSmartReloadObject { + + private Object reloadObject; + + private Method method; + + public AnnotationReloadObject(Object reloadObject, Method method) { + super(); + this.reloadObject = reloadObject; + this.method = method; + this.method.setAccessible(true); + } + + @Override + public SmartReloadResult reload(ReloadItem reloadItem) { + SmartReloadResult result = new SmartReloadResult(); + String tag = method.getAnnotation(SmartReload.class).value(); + result.setTag(tag); + result.setArgs(reloadItem.getArgs()); + result.setIdentification(reloadItem.getIdentification()); + try { + Object invoke = method.invoke(reloadObject, reloadItem.getArgs()); + result.setResult((Boolean) invoke); + } catch (Throwable e) { + result.setException(getStackTrace(e)); + } + return result; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/InterfaceReloadObject.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/InterfaceReloadObject.java new file mode 100644 index 00000000..409aba0f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/InterfaceReloadObject.java @@ -0,0 +1,37 @@ +package com.gangquan360.smartadmin.common.reload.domain; + +import com.gangquan360.smartadmin.common.reload.domain.entity.ReloadItem; +import com.gangquan360.smartadmin.common.reload.domain.entity.SmartReloadResult; +import com.gangquan360.smartadmin.common.reload.interfaces.SmartReloadable; + +/** + * Reload 处理程序的实现类 + * 用于处理以接口实现的处理类 + * + * @author zhuoda + */ +public class InterfaceReloadObject extends AbstractSmartReloadObject { + + private SmartReloadable object; + + public InterfaceReloadObject(SmartReloadable object) { + super(); + this.object = object; + } + + @Override + public SmartReloadResult reload(ReloadItem reloadItem) { + SmartReloadResult reloadResult = new SmartReloadResult(); + reloadResult.setArgs(reloadItem.getArgs()); + reloadResult.setIdentification(reloadItem.getIdentification()); + reloadResult.setTag(reloadItem.getTag()); + try { + boolean res = object.reload(reloadItem); + reloadResult.setResult(res); + } catch (Throwable e) { + reloadResult.setException(getStackTrace(e)); + } + return reloadResult; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/entity/ReloadItem.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/entity/ReloadItem.java new file mode 100644 index 00000000..a2e9a40d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/entity/ReloadItem.java @@ -0,0 +1,55 @@ +package com.gangquan360.smartadmin.common.reload.domain.entity; +/** + * ReloadItem 类 + * + * @author zhuoda + */ +public class ReloadItem { + + /** + * 项名称 + */ + private String tag; + + /** + * 参数 + */ + private String args; + + /** + * 标识 + */ + private String identification; + + public ReloadItem() { + + } + public ReloadItem(String tag, String identification, String args) { + this.tag = tag; + this.identification = identification; + this.args = args; + } + + public String getTag() { + return tag; + } + public void setTag(String tag) { + this.tag = tag; + } + public String getIdentification() { + return identification; + } + public void setIdentification(String identification) { + this.identification = identification; + } + public String getArgs() { + return args; + } + public void setArgs(String args) { + this.args = args; + } + @Override + public String toString() { + return "ReloadItem{" + "tag='" + tag + '\'' + ", identification='" + identification + '\'' + ", args='" + args + '\'' + '}'; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/entity/SmartReloadResult.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/entity/SmartReloadResult.java new file mode 100644 index 00000000..a22fba47 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/domain/entity/SmartReloadResult.java @@ -0,0 +1,102 @@ +package com.gangquan360.smartadmin.common.reload.domain.entity; +/** + * t_reload_result 表 实体类 + * + * @author zhuoda + */ +public class SmartReloadResult { + + /** + * 项名称 + */ + private String tag; + + /** + * 参数 + */ + private String args; + + /** + * 标识 + */ + private String identification; + + /** + * 处理结果 + */ + private boolean result; + + /** + * 异常说明 + */ + private String exception; + + public SmartReloadResult() { + } + + public SmartReloadResult(String tag, String args, boolean result, String exception) { + this.tag = tag; + this.args = args; + this.result = result; + this.exception = exception; + } + + public SmartReloadResult(String tag, String args, String identification, boolean result, String exception) { + this.tag = tag; + this.args = args; + this.identification = identification; + this.result = result; + this.exception = exception; + } + + public void setTag(String tag) { + this.tag = tag; + } + + public void setArgs(String args) { + this.args = args; + } + + public void setIdentification(String identification) { + this.identification = identification; + } + + public void setResult(boolean result) { + this.result = result; + } + + public void setException(String exception) { + this.exception = exception; + } + + public String getTag() { + return tag; + } + + public String getArgs() { + return args; + } + + public String getIdentification() { + return identification; + } + + public boolean isResult() { + return result; + } + + public String getException() { + return exception; + } + + @Override + public String toString() { + return "SmartReloadResult{" + + "tag='" + tag + '\'' + + ", args='" + args + '\'' + + ", identification='" + identification + '\'' + + ", result=" + result + + ", exception='" + exception + '\'' + + '}'; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadCommandInterface.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadCommandInterface.java new file mode 100644 index 00000000..6adbed3e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadCommandInterface.java @@ -0,0 +1,38 @@ +package com.gangquan360.smartadmin.common.reload.interfaces; + +import com.gangquan360.smartadmin.common.reload.domain.entity.ReloadItem; +import com.gangquan360.smartadmin.common.reload.domain.entity.SmartReloadResult; + +import java.util.List; + +/** + * 检测是否 Reload 的类 + * + * @author zhuoda + */ +public interface SmartReloadCommandInterface { + + /** + * 任务: + * 读取数据库中 ReloadItem 数据 + * 校验是否发生变化 + * 执行重加载动作 + */ + void doTask(); + + /** + * 该方法返回一个List:
+ * ReloadItem对象的tagIdentify为:该tag的 状态(状态其实就是个字符串,如果该字符串跟上次有变化则进行reload操作)
+ * ReloadItem对象的args为: reload操作需要的参数

+ * + * @return List + */ + List readReloadItem(); + + /** + * 处理Reload结果 + * + * @param reloadResult + */ + void handleReloadResult(SmartReloadResult reloadResult); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadThreadLogger.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadThreadLogger.java new file mode 100644 index 00000000..5db12541 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadThreadLogger.java @@ -0,0 +1,12 @@ +package com.gangquan360.smartadmin.common.reload.interfaces; + +/** + * SmartReloadThreadLogger 日志类 + */ +public interface SmartReloadThreadLogger { + + void error(String string); + + void error(String string, Throwable e); + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadable.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadable.java new file mode 100644 index 00000000..66122413 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/reload/interfaces/SmartReloadable.java @@ -0,0 +1,18 @@ +package com.gangquan360.smartadmin.common.reload.interfaces; + +import com.gangquan360.smartadmin.common.reload.domain.entity.ReloadItem; +/** + * reload 接口
+ * 需要reload的业务实现类 + */ +@FunctionalInterface +public interface SmartReloadable { + + /** + * reload + * + * @param reloadItem + * @return boolean + */ + boolean reload(ReloadItem reloadItem); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/swagger/SmartSwaggerApiModelEnumPlugin.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/swagger/SmartSwaggerApiModelEnumPlugin.java new file mode 100644 index 00000000..cc863c48 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/swagger/SmartSwaggerApiModelEnumPlugin.java @@ -0,0 +1,91 @@ +/* + * + * Copyright 2015 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.gangquan360.smartadmin.common.swagger; + +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.common.domain.BaseEnum; +import com.google.common.base.Function; +import com.google.common.base.Optional; +import org.apache.commons.lang3.StringUtils; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin; +import springfox.documentation.spi.schema.contexts.ModelPropertyContext; +import springfox.documentation.swagger.common.SwaggerPluginSupport; + +import java.lang.reflect.AnnotatedElement; + +import static springfox.documentation.schema.Annotations.findPropertyAnnotation; + +/** + * swagger 用于说明枚举类字段说明 + * SWAGGER_PLUGIN_ORDER+1 是将此配置放在原来的后面执行 + * + * @author listen + * @date 2019年5月16日 15:36:56 + */ +public class SmartSwaggerApiModelEnumPlugin implements ModelPropertyBuilderPlugin { + + @Override + public void apply(ModelPropertyContext context) { + Optional annotation = Optional.absent(); + + if (context.getAnnotatedElement().isPresent()) { + annotation = annotation.or(findApiModePropertyAnnotation(context.getAnnotatedElement().get())); + } + if (context.getBeanPropertyDefinition().isPresent()) { + annotation = annotation.or(findPropertyAnnotation(context.getBeanPropertyDefinition().get(), ApiModelPropertyEnum.class)); + } + + if (annotation.isPresent()) { + Class aClass = annotation.get().value(); + String enumInfo = BaseEnum.getInfo(aClass); + String enumDesc = annotation.get().enumDesc(); + context.getBuilder().required(annotation.transform(toIsRequired()).or(false)) + .description(enumDesc +":"+enumInfo) + .example(annotation.transform(toExample()).orNull()); + } + } + + @Override + public boolean supports(DocumentationType delimiter) { + return SwaggerPluginSupport.pluginDoesApply(delimiter); + } + + static Function toIsRequired() { + return annotation -> annotation.required(); + } + + public static Optional findApiModePropertyAnnotation(AnnotatedElement annotated) { + return Optional.fromNullable(AnnotationUtils.getAnnotation(annotated, ApiModelPropertyEnum.class)); + } + + static Function toExample() { + return annotation -> { + String example = annotation.example(); + if (StringUtils.isBlank(example)) { + return ""; + } + return example; + }; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/BigDecimalValidator.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/BigDecimalValidator.java new file mode 100644 index 00000000..ed0a91fb --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/BigDecimalValidator.java @@ -0,0 +1,73 @@ +package com.gangquan360.smartadmin.common.validator.bigdecimal; + +import com.gangquan360.smartadmin.util.SmartBigDecimalUtil; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.math.BigDecimal; + +/** + * BigDecimal 类校验器 + * + * @author listen + * @date 2018年3月20日 13:51:46 + */ +public class BigDecimalValidator implements ConstraintValidator { + + /** + * 获取定义的数值 + */ + private BigDecimal value; + + /** + * 获取比较符 + */ + private ComparisonSymbolEnum symbolEnum; + + /** + * 是否必须 + */ + private boolean required; + + @Override + public void initialize(CheckBigDecimal constraintAnnotation) { + // 初始化属性 + value = new BigDecimal(constraintAnnotation.value()); + symbolEnum = constraintAnnotation.symbolEnum(); + required = constraintAnnotation.required(); + } + + @Override + public boolean isValid(BigDecimal decimal, ConstraintValidatorContext constraintValidatorContext) { + + // 如果数值为空,校验是否必须 + if (null == decimal) { + return ! required; + } + + // 根据操作符,校验结果 + switch (symbolEnum) { + // 等于 + case EQUAL: + return SmartBigDecimalUtil.equals(decimal, value); + // 不等于 + case NOT_EQUAL: + return ! SmartBigDecimalUtil.equals(decimal, value); + // 小于 + case LESS_THAN: + return SmartBigDecimalUtil.isLessThan(decimal, value); + // 小于等于 + case LESS_THAN_OR_EQUAL: + return SmartBigDecimalUtil.isLessThan(decimal, value) || SmartBigDecimalUtil.equals(decimal, value); + // 大于 + case GREATER_THAN: + return SmartBigDecimalUtil.isGreaterThan(decimal, value); + // 大于等于 + case GREATER_THAN_OR_EQUAL: + return SmartBigDecimalUtil.isGreaterThan(decimal, value) || SmartBigDecimalUtil.equals(decimal, value); + default: + } + + return false; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/CheckBigDecimal.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/CheckBigDecimal.java new file mode 100644 index 00000000..a005fd8b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/CheckBigDecimal.java @@ -0,0 +1,53 @@ +package com.gangquan360.smartadmin.common.validator.bigdecimal; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义的属性校验注解 + * + * @author listen + * @date 2018年3月20日 13:53:33 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = BigDecimalValidator.class)// 自定义验证的处理类 +public @interface CheckBigDecimal { + + /** + * 与这个数值校验 + * + * @return + */ + String value(); + + /** + * 比较符 请使用 ComparisonSymbolEnum 枚举类 + * + * @return + */ + ComparisonSymbolEnum symbolEnum(); + + /** + * 默认的错误提示信息 + * + * @return String + */ + String message() default "非法的数值"; + + /** + * 是否必须 : 默认 true + * + * @return boolean + */ + boolean required() default true; + + //下面这两个属性必须添加 :不然会报错 + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/ComparisonSymbolEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/ComparisonSymbolEnum.java new file mode 100644 index 00000000..f25948cc --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/bigdecimal/ComparisonSymbolEnum.java @@ -0,0 +1,40 @@ +package com.gangquan360.smartadmin.common.validator.bigdecimal; + +/** + * 比较符枚举类 + * + * @author listen + * @date 2018/03/20 14:01 + */ +public enum ComparisonSymbolEnum { + + /** + * 等于 + */ + EQUAL, + + /** + * 不等于 + */ + NOT_EQUAL, + + /** + * 小于 + */ + LESS_THAN, + + /** + * 小于等于 + */ + LESS_THAN_OR_EQUAL, + + /** + * 大于 + */ + GREATER_THAN, + + /** + * 大于等于 + */ + GREATER_THAN_OR_EQUAL, +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/en/CheckEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/en/CheckEnum.java new file mode 100644 index 00000000..662dc7ed --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/en/CheckEnum.java @@ -0,0 +1,51 @@ +package com.gangquan360.smartadmin.common.validator.en; + + +import com.gangquan360.smartadmin.common.domain.BaseEnum; +import com.gangquan360.smartadmin.common.validator.en.EnumValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 自定义的属性校验注解 + * 为了方便与校验属性的值是否为合法的枚举值 + * + * @author listen + * @date 2017/11/11 15:31 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = EnumValidator.class)// 自定义验证的处理类 +public @interface CheckEnum { + + /** + * 默认的错误提示信息 + * + * @return String + */ + String message() default "非法的枚举值"; + + /** + * 枚举类对象 必须实现BaseEnum接口 + * + * @return + */ + Class enumClazz(); + + /** + * 是否必须 + * + * @return boolean + */ + boolean required() default false; + + //下面这两个属性必须添加 :不然会报错 + Class[] groups() default {}; + + Class[] payload() default {}; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/en/EnumValidator.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/en/EnumValidator.java new file mode 100644 index 00000000..8cb3004d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/common/validator/en/EnumValidator.java @@ -0,0 +1,80 @@ +package com.gangquan360.smartadmin.common.validator.en; + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.List; + +/** + * 枚举类校验器 + * + * @author listen + * @date 2017/11/11 15:34 + */ +public class EnumValidator implements ConstraintValidator { + + /** + * 枚举类的类对象 + */ + private Class enumClass; + + /** + * 是否必须 + */ + private boolean required; + + @Override + public void initialize(CheckEnum constraintAnnotation) { + // 获取注解传入的枚举类对象 + enumClass = constraintAnnotation.enumClazz(); + required = constraintAnnotation.required(); + } + + @Override + public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) { + // 判断是否必须 + if (null == value) { + return !required; + } + + if (value instanceof List) { + // 如果为 List 集合数据 + return this.checkList((List) value); + } + + // 校验是否为合法的枚举值 + return this.hasEnum(value); + } + + /** + * 校验集合类型 + * + * @param list + * @return + */ + private boolean checkList(List list) { + if (required && list.isEmpty()) { + // 必须的情况下 list 不能为空 + return false; + } + for (Object obj : list) { + boolean hasEnum = this.hasEnum(obj); + if (!hasEnum) { + return false; + } + } + return true; + } + + private boolean hasEnum(Object value) { + // 校验是否为合法的枚举值 + BaseEnum[] enums = enumClass.getEnumConstants(); + for (BaseEnum baseEnum : enums) { + if (baseEnum.getValue().equals(value)) { + return true; + } + } + return false; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartAdminWebAppConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartAdminWebAppConfig.java new file mode 100644 index 00000000..b4ee830f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartAdminWebAppConfig.java @@ -0,0 +1,29 @@ +package com.gangquan360.smartadmin.config; + +import com.gangquan360.smartadmin.interceptor.SmartAuthenticationInterceptor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.*; + +/** + * @Description + * @Author lihaifan + * @Date Created in 2017/10/24 13:48 + */ +@Configuration +public class SmartAdminWebAppConfig implements WebMvcConfigurer{ + @Autowired + private SmartAuthenticationInterceptor smartAuthenticationInterceptor; + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(smartAuthenticationInterceptor).addPathPatterns("/**"); + } + + + @Override + public void addViewControllers(ViewControllerRegistry registry) { + registry.addViewController("/druidMonitor").setViewName("redirect:/druid/index.html"); + registry.addViewController("/swaggerApi").setViewName("redirect:/swagger-ui.html"); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartDruidDataSourceConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartDruidDataSourceConfig.java new file mode 100644 index 00000000..b05932ab --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartDruidDataSourceConfig.java @@ -0,0 +1,170 @@ +package com.gangquan360.smartadmin.config; + +import com.alibaba.druid.filter.Filter; +import com.alibaba.druid.filter.stat.StatFilter; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.support.http.StatViewServlet; +import com.alibaba.druid.support.http.WebStatFilter; +import com.alibaba.druid.support.spring.stat.DruidStatInterceptor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.support.DefaultPointcutAdvisor; +import org.springframework.aop.support.JdkRegexpMethodPointcut; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.boot.web.servlet.ServletRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import javax.sql.DataSource; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * [ 数据源配置 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Slf4j +@Configuration +public class SmartDruidDataSourceConfig { + + @Value("${spring.datasource.driver-class-name}") + String driver; + + @Value("${spring.datasource.url}") + String url; + + @Value("${spring.datasource.username}") + String username; + + @Value("${spring.datasource.password}") + String password; + + @Value("${spring.datasource.initial-size}") + int initialSize; + + @Value("${spring.datasource.min-idle}") + int minIdle; + + @Value("${spring.datasource.max-active}") + int maxActive; + + @Value("${spring.datasource.max-wait}") + long maxWait; + + @Value("${spring.datasource.time-between-eviction-runs-millis}") + long timeBetweenEvictionRunsMillis; + + @Value("${spring.datasource.min-evictable-edle-time-millis}") + long minEvictableIdleTimeMillis; + + @Value("${spring.datasource.filters}") + String filters; + + @Value("${spring.datasource.druid.username}") + String druidUserName; + + @Value("${spring.datasource.druid.password}") + String druidPassword; + + @Value("${spring.datasource.druid.login.enabled}") + boolean druidLoginEnable; + + @Autowired + private StatFilter logSlowSql; + + @Autowired + private DruidStatInterceptor druidStatInterceptor; + + @Bean + @Primary + public DataSource druidDataSource() { + DruidDataSource druidDataSource = new DruidDataSource(); + druidDataSource.setDriverClassName(driver); + druidDataSource.setUrl(url); + druidDataSource.setUsername(username); + druidDataSource.setPassword(password); + druidDataSource.setInitialSize(initialSize); + druidDataSource.setMinIdle(minIdle); + druidDataSource.setMaxActive(maxActive); + druidDataSource.setMaxWait(maxWait); + druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis); + druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis); + try { + druidDataSource.setFilters(filters); + ArrayList arrayList = new ArrayList<>(); + arrayList.add(logSlowSql); + druidDataSource.setProxyFilters(arrayList); + druidDataSource.init(); + } catch (SQLException e) { + log.error("初始化数据源出错", e); + } + + return druidDataSource; + } + + @Bean + public ServletRegistrationBean druidServlet() { + ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(); + servletRegistrationBean.setServlet(new StatViewServlet()); + servletRegistrationBean.addUrlMappings("/druid/*"); + Map initParameters = new HashMap(); + //不设置用户名密码可以直接通过druid/index.html访问 + if (druidLoginEnable) { + initParameters.put("loginUsername", druidUserName); + initParameters.put("loginPassword", druidPassword); + } + initParameters.put("resetEnable", "false"); + servletRegistrationBean.setInitParameters(initParameters); + return servletRegistrationBean; + } + + @Bean + public FilterRegistrationBean filterRegistrationBean() { + FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); + filterRegistrationBean.setFilter(new WebStatFilter()); + filterRegistrationBean.addUrlPatterns("/*"); + filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); + return filterRegistrationBean; + } + + @Bean + public StatFilter logSlowSql() { + StatFilter statFilter = new StatFilter(); + statFilter.setMergeSql(true); + statFilter.setSlowSqlMillis(300); + statFilter.setLogSlowSql(true); + return statFilter; + } + + @Bean(name = "druid-stat-interceptor") + public DruidStatInterceptor druidStatInterceptor() { + DruidStatInterceptor dsInterceptor = new DruidStatInterceptor(); + return dsInterceptor; + } + + @Bean + public JdkRegexpMethodPointcut jdkRegexpMethodPointcut() { + JdkRegexpMethodPointcut jdkRegexpMethodPointcut = new JdkRegexpMethodPointcut(); + jdkRegexpMethodPointcut.setPatterns("com.gangquan360.smartadmin.module..*Service.*"); + return jdkRegexpMethodPointcut; + } + + @Bean + public DefaultPointcutAdvisor defaultPointcutAdvisor() { + DefaultPointcutAdvisor pointcutAdvisor = new DefaultPointcutAdvisor(); + pointcutAdvisor.setPointcut(jdkRegexpMethodPointcut()); + pointcutAdvisor.setAdvice(druidStatInterceptor); + return pointcutAdvisor; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartHeartBeatConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartHeartBeatConfig.java new file mode 100644 index 00000000..7e572a84 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartHeartBeatConfig.java @@ -0,0 +1,33 @@ +package com.gangquan360.smartadmin.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +@Configuration +public class SmartHeartBeatConfig { + + /** + * 延迟执行时间 + */ + @Value("${heart-beat.delayHandlerTime}") + private Long delayHandlerTime; + + /** + * 间隔执行时间 + */ + @Value("${heart-beat.intervalTime}") + private Long intervalTime; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartKaptchaConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartKaptchaConfig.java new file mode 100644 index 00000000..e29d98bf --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartKaptchaConfig.java @@ -0,0 +1,49 @@ +package com.gangquan360.smartadmin.config; + +import com.gangquan360.smartadmin.common.kaptcha.KaptchaNoise; +import com.gangquan360.smartadmin.common.kaptcha.KaptchaWordRenderer; +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + +/** + * [ 验证码配置 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/4 0004 上午 9:40 + * @since JDK1.8 + */ +@Configuration +public class SmartKaptchaConfig { + + @Bean + public DefaultKaptcha getDefaultKaptcha(){ + DefaultKaptcha defaultKaptcha=new DefaultKaptcha(); + Properties properties=new Properties(); + properties.setProperty("kaptcha.border", "no"); + properties.setProperty("kaptcha.border.color", "34,114,200"); + properties.setProperty("kaptcha.image.width", "125"); + properties.setProperty("kaptcha.image.height", "45"); + properties.setProperty("kaptcha.textproducer.char.string", "ABCDEFG23456789"); + properties.setProperty("kaptcha.textproducer.char.length", "5"); + properties.setProperty("kaptcha.textproducer.font.names", "Arial,Arial Narrow,Serif,Helvetica,Tahoma,Times New Roman,Verdana"); + properties.setProperty("kaptcha.textproducer.font.size", "38"); + + properties.setProperty("kaptcha.background.clear.from", "white"); + properties.setProperty("kaptcha.background.clear.to", "white"); + + properties.setProperty("kaptcha.word.impl",KaptchaWordRenderer.class.getName()); + properties.setProperty("kaptcha.noise.impl", KaptchaNoise.class.getName()); + + Config config=new Config(properties); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartMybatisPlusConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartMybatisPlusConfig.java new file mode 100644 index 00000000..5cdb86a1 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartMybatisPlusConfig.java @@ -0,0 +1,39 @@ +package com.gangquan360.smartadmin.config; + +import com.baomidou.mybatisplus.plugins.PaginationInterceptor; +import com.baomidou.mybatisplus.plugins.PerformanceInterceptor; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +/** + * description + * + * @author listen + * @date 2017/12/19 13:54 + */ +@EnableTransactionManagement +@Configuration +@MapperScan(basePackages = {"com.gangquan360.smartadmin.module.*"}) +public class SmartMybatisPlusConfig { + + /** + * 分页插件 + */ + @Bean + public PaginationInterceptor paginationInterceptor() { + return new PaginationInterceptor(); + } + + /** + * mybatis-plus SQL执行效率插件【生产环境可以关闭】 + */ + @Bean + @Conditional(SystemEnvironmentCondition.class) + public PerformanceInterceptor performanceInterceptor() { + return new PerformanceInterceptor(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartRedisConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartRedisConfig.java new file mode 100644 index 00000000..881d54ac --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartRedisConfig.java @@ -0,0 +1,74 @@ +package com.gangquan360.smartadmin.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.*; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * [ redis配置 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Configuration +public class SmartRedisConfig { + + @Autowired + private RedisConnectionFactory factory; + + @Bean + public RedisTemplate redisTemplate() { + Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); + ObjectMapper om = new ObjectMapper(); + om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); + jackson2JsonRedisSerializer.setObjectMapper(om); + RedisTemplate template = new RedisTemplate(); + template.setConnectionFactory(factory); + template.setKeySerializer(new StringRedisSerializer()); + template.setValueSerializer(jackson2JsonRedisSerializer); + template.setHashKeySerializer(jackson2JsonRedisSerializer); + template.setHashValueSerializer(jackson2JsonRedisSerializer); + template.setDefaultSerializer(new StringRedisSerializer()); + template.afterPropertiesSet(); + return template; + } + + @Bean + public HashOperations hashOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForHash(); + } + + @Bean + public ValueOperations valueOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForValue(); + } + + @Bean + public ListOperations listOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForList(); + } + + @Bean + public SetOperations setOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForSet(); + } + + @Bean + public ZSetOperations zSetOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForZSet(); + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartReloadConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartReloadConfig.java new file mode 100644 index 00000000..8b2f2ec8 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartReloadConfig.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.config; + +import com.gangquan360.smartadmin.common.reload.SmartReloadManager; +import com.gangquan360.smartadmin.common.reload.interfaces.SmartReloadThreadLogger; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/28 0028 下午 20:15 + * @since JDK1.8 + */ +@Slf4j +@Configuration +public class SmartReloadConfig { + + @Value("${smart-reload.thread-count}") + private Integer threadCount; + + @Bean + public SmartReloadManager initSmartReloadManager() { + /** + * 创建 Reload Manager 调度器 + */ + SmartReloadManager smartReloadManager = new SmartReloadManager(new SmartReloadThreadLogger() { + @Override + public void error(String string) { + log.error(string); + } + + @Override + public void error(String string, Throwable e) { + log.error(string, e); + } + }, threadCount); + return smartReloadManager; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartRestTemplateConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartRestTemplateConfig.java new file mode 100644 index 00000000..da3eac8c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartRestTemplateConfig.java @@ -0,0 +1,109 @@ +package com.gangquan360.smartadmin.config; + +import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; +import org.apache.http.client.HttpClient; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.config.Registry; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.conn.socket.ConnectionSocketFactory; +import org.apache.http.conn.socket.PlainConnectionSocketFactory; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; +import org.springframework.http.converter.FormHttpMessageConverter; +import org.springframework.http.converter.HttpMessageConverter; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.web.client.RestTemplate; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Configuration +public class SmartRestTemplateConfig { + + + @Value("${http.pool.max-total}") + private Integer maxTotal; + @Value("${http.pool.default-max-per-route}") + private Integer defaultMaxPerRoute; + @Value("${http.pool.socket-timeout}") + private Integer socketTimeout; + @Value("${http.pool.connect-timeout}") + private Integer connectTimeout; + @Value("${http.pool.connection-request-timeout}") + private Integer connectionRequestTimeout; + + + @Bean + public RestTemplate restTemplate(ClientHttpRequestFactory factory) { + return new RestTemplate(factory); + } + + @Bean + public ClientHttpRequestFactory httpRequestFactory() { + HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient()); + return factory; + } + + /** + * fastJsonRestTemplate + * + * @return + */ + @Bean(name = "fastJsonRestTemplate") + public RestTemplate fastJsonRestTemplate() { + RestTemplate restTemplate = new RestTemplate(httpRequestFactory()); + + HttpMessageConverter converter = new StringHttpMessageConverter(Charset.forName("UTF-8")); + + FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter(); + List fastMediaTypes = new ArrayList<>(); + fastMediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED); + fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); + fastConverter.setSupportedMediaTypes(fastMediaTypes); + List> converters = restTemplate.getMessageConverters(); + converters.add(1,converter); + converters.add(fastConverter); + return restTemplate; + } + + + @Bean + public HttpClient httpClient() { + Registry registry = RegistryBuilder.create() + .register("http", PlainConnectionSocketFactory.getSocketFactory()) + .register("https", SSLConnectionSocketFactory.getSocketFactory()) + .build(); + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); + connectionManager.setMaxTotal(maxTotal); + connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute); + + RequestConfig requestConfig = RequestConfig.custom() + .setSocketTimeout(socketTimeout) + .setConnectTimeout(connectTimeout) + .setConnectionRequestTimeout(connectionRequestTimeout) + .build(); + return HttpClientBuilder.create() + .setDefaultRequestConfig(requestConfig) + .setConnectionManager(connectionManager) + .build(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartSwaggerApiModelEnumConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartSwaggerApiModelEnumConfig.java new file mode 100644 index 00000000..93d9427c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartSwaggerApiModelEnumConfig.java @@ -0,0 +1,29 @@ +package com.gangquan360.smartadmin.config; + +import com.gangquan360.smartadmin.common.swagger.SmartSwaggerApiModelEnumPlugin; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.annotation.Order; +import springfox.documentation.swagger.common.SwaggerPluginSupport; + +/** + * [ 对于枚举类进行swagger注解,与前端的vue-enum相匹配 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/9 0009 上午 9:46 + * @since JDK1.8 + */ +@Configuration +@Profile({"dev", "sit", "pre", "prod"}) +public class SmartSwaggerApiModelEnumConfig { + + @Bean + @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1) + public SmartSwaggerApiModelEnumPlugin swaggerEnum(){ + return new SmartSwaggerApiModelEnumPlugin(); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartSwaggerDynamicGroupConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartSwaggerDynamicGroupConfig.java new file mode 100644 index 00000000..efe1eda8 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartSwaggerDynamicGroupConfig.java @@ -0,0 +1,217 @@ +package com.gangquan360.smartadmin.config; + +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.base.Predicates; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; +import org.springframework.core.env.Environment; +import org.springframework.web.bind.annotation.RestController; +import springfox.documentation.RequestHandler; +import springfox.documentation.builders.ApiInfoBuilder; +import springfox.documentation.builders.PathSelectors; +import springfox.documentation.builders.RequestHandlerSelectors; +import springfox.documentation.service.*; +import springfox.documentation.spi.DocumentationType; +import springfox.documentation.spi.service.contexts.SecurityContext; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +/** + * [ 根据SwaggerTagConst内部类动态生成Swagger group ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/7 0007 下午 19:20 + * @since JDK1.8 + */ +@Slf4j +@EnableSwagger2 +@Configuration +@Profile({"dev", "sit", "pre", "prod"}) +public class SmartSwaggerDynamicGroupConfig implements EnvironmentAware, BeanDefinitionRegistryPostProcessor { + + /** + * 分组名称 + */ + private String apiGroupName; + + /** + * 文档标题 + */ + private String title; + + /** + * 文档描述 + */ + private String description; + + /** + * api版本 + */ + private String version; + + /** + * service url + */ + private String serviceUrl; + + /** + * controller 包路径 + */ + private String packAge; + + private int groupIndex = 0; + + private String groupName = "default"; + + private List groupList = Lists.newArrayList(); + + private Map> groupMap = Maps.newHashMap(); + + @Override + public void setEnvironment(Environment environment) { + this.apiGroupName = environment.getProperty("swagger.apiGroupName"); + this.title = environment.getProperty("swagger.title"); + this.description = environment.getProperty("swagger.description"); + this.version = environment.getProperty("swagger.version"); + this.serviceUrl = environment.getProperty("swagger.serviceUrl"); + this.packAge = environment.getProperty("swagger.packAge"); + } + + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + this.groupBuild(); + for (Map.Entry> entry : groupMap.entrySet()) { + String group = entry.getKey(); + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(Docket.class, this :: baseDocket); + BeanDefinition beanDefinition = builder.getRawBeanDefinition(); + registry.registerBeanDefinition(group + "Api", beanDefinition); + } + } + + private void groupBuild() { + Class clazz = SwaggerTagConst.class; + Class[] innerClazz = clazz.getDeclaredClasses(); + for (Class cls : innerClazz) { + String group = cls.getSimpleName(); + List apiTags = Lists.newArrayList(); + Field[] fields = cls.getDeclaredFields(); + for (Field field : fields) { + boolean isFinal = Modifier.isFinal(field.getModifiers()); + if (isFinal) { + try { + apiTags.add(field.get(null).toString()); + } catch (Exception e) { + log.error("", e); + } + } + } + groupList.add(group); + groupMap.put(group, apiTags); + } + } + + private Docket baseDocket() { + // 请求类型过滤规则 + Predicate controllerPredicate = getControllerPredicate(); + // controller 包路径 + Predicate controllerPackage = RequestHandlerSelectors.basePackage(packAge); + return new Docket(DocumentationType.SWAGGER_2) + .groupName(groupName) + .forCodeGeneration(true) + .select() + .apis(controllerPackage) + .apis(controllerPredicate) + .paths(PathSelectors.any()) + .build() + .apiInfo(this.serviceApiInfo()) + .securitySchemes(securitySchemes()) + .securityContexts(securityContexts()); + } + + private List securitySchemes() { + List apiKeyList= new ArrayList<>(); + apiKeyList.add(new ApiKey("x-access-token", "x-access-token", "header")); + return apiKeyList; + } + + private List securityContexts() { + List securityContexts=new ArrayList<>(); + securityContexts.add( + SecurityContext.builder() + .securityReferences(defaultAuth()) + .forPaths(PathSelectors.any()) + .build()); + return securityContexts; + } + + List defaultAuth() { + AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); + AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; + authorizationScopes[0] = authorizationScope; + List securityReferences=new ArrayList<>(); + securityReferences.add(new SecurityReference("x-access-token", authorizationScopes)); + return securityReferences; + } + + private Predicate getControllerPredicate() { + groupName = groupList.get(groupIndex); + List apiTags = groupMap.get(groupName); + Predicate methodPredicate = (input) -> { + Api api = null; + Optional apiOptional = input.findControllerAnnotation(Api.class); + if (apiOptional.isPresent()) { + api = apiOptional.get(); + } + List tags = Arrays.asList(api.tags()); + if (api != null && apiTags.containsAll(tags)) { + return true; + } + return false; + }; + groupIndex++; + return Predicates.and(RequestHandlerSelectors.withClassAnnotation(RestController.class), methodPredicate); + } + + private ApiInfo serviceApiInfo() { + return new ApiInfoBuilder() + .title(title) + .description(description) + .version(version) + .license("Apache License Version 2.0") + .contact(new Contact("1024创新实验室", "http://www.1024lab.net", "")) + .termsOfServiceUrl(serviceUrl) + .build(); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { + + } + + + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartWebSocketConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartWebSocketConfig.java new file mode 100644 index 00000000..3087d2ec --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SmartWebSocketConfig.java @@ -0,0 +1,25 @@ +package com.gangquan360.smartadmin.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.socket.server.standard.ServerEndpointExporter; + +/** + * [ WebSocketConfig ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/10 0010 下午 16:07 + * @since JDK1.8 + */ +@Configuration +public class SmartWebSocketConfig { + + @Bean + public ServerEndpointExporter serverEndpointExporter() { + return new ServerEndpointExporter(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SystemEnvironmentCondition.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SystemEnvironmentCondition.java new file mode 100644 index 00000000..46755115 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/config/SystemEnvironmentCondition.java @@ -0,0 +1,22 @@ +package com.gangquan360.smartadmin.config; +import com.gangquan360.smartadmin.constant.SystemEnvironmentEnum; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Condition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.type.AnnotatedTypeMetadata; +/** + * 是否是正式环境 + * + * @author listen + * @date 2019/08/27 08:56 + */ +public class SystemEnvironmentCondition implements Condition { + + @Value("${spring.profiles.active}") + private String systemEnvironment; + + @Override + public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { + return ! SystemEnvironmentEnum.PROD.equalsValue(systemEnvironment); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/CommonConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/CommonConst.java new file mode 100644 index 00000000..1b482e0c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/CommonConst.java @@ -0,0 +1,51 @@ +package com.gangquan360.smartadmin.constant; + +import com.google.common.collect.ImmutableSet; +import org.apache.commons.collections4.CollectionUtils; + +import java.util.Set; + +/** + * + * [ 通用常量 ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +public class CommonConst { + + + public static final class Page { + public static final Integer SIZE = 10; + } + + public static final class Password { + public static final String DEFAULT = "123456"; + public static final String SALT_FORMAT = "smart_%s_admin"; + } + + public static final String IGNORE_H5_URL_MAPPING = "/h5/api"; + + public static final class CommonCollection { + public static final Set IGNORE_URL = ImmutableSet.of("/swagger", "Excel"); + + public static final Set IGNORE_URL_MAPPING = ImmutableSet.of(IGNORE_H5_URL_MAPPING); + + public static Boolean contain(Set ignores, String uri) { + if (CollectionUtils.isEmpty(ignores)) { + return false; + } + for (String ignoreUrl : ignores) { + if (uri.startsWith(ignoreUrl)) { + return true; + } + } + return false; + } + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SmartReloadTagConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SmartReloadTagConst.java new file mode 100644 index 00000000..f5ed6e68 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SmartReloadTagConst.java @@ -0,0 +1,16 @@ +package com.gangquan360.smartadmin.constant; +/** + * smart initDefines 项 常量 + * + * @author listen + * @date 2018/02/10 14:29 + */ +public class SmartReloadTagConst { + + /** + * 系统环境设置 DEMO + */ + public static final String SYSTEM_CONFIG = "system_config"; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SwaggerTagConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SwaggerTagConst.java new file mode 100644 index 00000000..6ce07b85 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SwaggerTagConst.java @@ -0,0 +1,69 @@ +package com.gangquan360.smartadmin.constant; + +/** + * [] + * + * @author yandanyang + * @version 1.0 + * @since JDK1.8 + */ +public class SwaggerTagConst { + + + public static class Admin { + public static final String MANAGER_SYSTEM_CONFIG = "管理端-系统配置"; + + public static final String MANAGER_USER = "管理端-用户"; + + public static final String MANAGER_USER_LOGIN = "管理端-用户登录"; + + public static final String MANAGER_DEPARTMENT = "管理端-部门"; + + public static final String MANAGER_ROLE = "管理端-角色"; + + public static final String MANAGER_ROLE_USER = "管理端-角色用户"; + + public static final String MANAGER_ROLE_PRIVILEGE = "管理端-角色权限"; + + public static final String MANAGER_SMART_RELOAD = "管理端-smart reload"; + + public static final String MANAGER_ORDER_OPERATE_LOG = "管理端-单据操作日志"; + + public static final String MANAGER_TASK_SCHEDULER = "管理端-任务调度"; + + public static final String MANAGER_USER_LOGIN_LOG = "管理端-用户登录日志"; + + public static final String MANAGER_USER_OPERATE_LOG = "管理端-用户操作日志"; + + public static final String MANAGER_DATA_SCOPE = "管理端-数据范围"; + + public static final String MANAGER_JOB = "管理端-岗位"; + + public static final String MANAGER_NOTICE = "管理端-系统通知"; + + public static final String MANAGER_FILE = "通用-文件服务"; + + public static final String MANAGER_PRIVILEGE = "通用-权限"; + + public static final String MANAGER_EMAIL = "通用-邮件发送"; + + public static final String MANAGER_HEART_BEAT = "通用-心跳服务"; + } + + /** + * 自定义分组2 + */ + public static class Group2 { + + + } + + /** + * 自定义分组2 + */ + public static class Group3 { + + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SystemEnvironmentEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SystemEnvironmentEnum.java new file mode 100644 index 00000000..07ba8b54 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/constant/SystemEnvironmentEnum.java @@ -0,0 +1,60 @@ +package com.gangquan360.smartadmin.constant; + +import com.gangquan360.smartadmin.common.domain.BaseEnum; +/** + * 系统环境枚举类 + * + * @author listen + * @date 2019年4月11日 17:34:59 + */ +public enum SystemEnvironmentEnum implements BaseEnum { + + /** + * dev + */ + DEV("dev", "开发环境"), + + /** + * sit + */ + SIT("sit", "测试环境"), + + /** + * pre + */ + PRE("pre", "预发布环境"), + + /** + * prod + */ + PROD("prod", "生产环境"); + + private String value; + + private String desc; + + SystemEnvironmentEnum(String value, String desc) { + this.value = value; + this.desc = desc; + } + /** + * 获取定义枚举value值 + * + * @return Integer + */ + @Override + public String getValue() { + return value; + } + + /** + * 获取枚举类的说明 + * + * @return String + */ + @Override + public String getDesc() { + return desc; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/handler/SmartGlobalExceptionHandler.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/handler/SmartGlobalExceptionHandler.java new file mode 100644 index 00000000..29f779a4 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/handler/SmartGlobalExceptionHandler.java @@ -0,0 +1,73 @@ +package com.gangquan360.smartadmin.handler; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.common.exception.SmartBusinessException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.TypeMismatchException; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.validation.FieldError; +import org.springframework.web.HttpRequestMethodNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * [ 全局异常拦截 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Slf4j +@ControllerAdvice +public class SmartGlobalExceptionHandler { + + /** + * 添加全局异常处理流程 + * + * @param e + * @return + * @throws Exception + */ + @ResponseBody + @ExceptionHandler(Exception.class) + public ResponseDTO exceptionHandler(Exception e) { + // http 请求方式错误 + if (e instanceof HttpRequestMethodNotSupportedException) { + return ResponseDTO.wrap(ResponseCodeConst.REQUEST_METHOD_ERROR); + } + + // 参数类型错误 + if (e instanceof TypeMismatchException) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM); + } + + // json 格式错误 + if (e instanceof HttpMessageNotReadableException) { + return ResponseDTO.wrap(ResponseCodeConst.JSON_FORMAT_ERROR); + } + + // 参数校验未通过 + if (e instanceof MethodArgumentNotValidException) { + List fieldErrors = ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors(); + List msgList = fieldErrors.stream().map(FieldError :: getDefaultMessage).collect(Collectors.toList()); + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, String.join(",", msgList)); + } + + if (e instanceof SmartBusinessException) { + return ResponseDTO.wrap(ResponseCodeConst.SYSTEM_ERROR); + } + + log.error("error:", e); + + return ResponseDTO.wrap(ResponseCodeConst.SYSTEM_ERROR); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/handler/SmartOperateLogAspect.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/handler/SmartOperateLogAspect.java new file mode 100644 index 00000000..dc2dccdc --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/handler/SmartOperateLogAspect.java @@ -0,0 +1,167 @@ +package com.gangquan360.smartadmin.handler; + +import com.alibaba.fastjson.JSON; +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import com.gangquan360.smartadmin.module.log.LogService; +import com.gangquan360.smartadmin.module.log.useroperatelog.domain.UserOperateLogEntity; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.util.SmartRequestTokenUtil; +import com.gangquan360.smartadmin.util.SmartStringUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.Signature; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.AfterThrowing; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.aspectj.lang.reflect.MethodSignature; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Method; +/** + * [ 操作日志记录处理,对所有OperateLog注解的Controller进行操作日志监控 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Slf4j +@Aspect +@Component +public class SmartOperateLogAspect { + + @Autowired + private LogService logService; + + @Pointcut("execution(* com.gangquan360.smartadmin.module..*Controller.*(..)))") + public void logPointCut() { + } + + @AfterReturning(pointcut = "logPointCut()") + public void doAfterReturning(JoinPoint joinPoint) { + handleLog(joinPoint, null); + } + + @AfterThrowing(value = "logPointCut()", throwing = "e") + public void doAfterThrowing(JoinPoint joinPoint, Exception e) { + handleLog(joinPoint, e); + } + + protected void handleLog(final JoinPoint joinPoint, final Exception e) { + try { + HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); + OperateLog operateLog = this.getAnnotationLog(joinPoint); + if (operateLog == null) { + return; + } + RequestTokenBO requestToken = SmartRequestTokenUtil.getRequestUser(); + if (requestToken == null) { + return; + } + // 设置方法名称 + String className = joinPoint.getTarget().getClass().getName(); + String methodName = joinPoint.getSignature().getName(); + String operateMethod = className + "." + methodName; + Object[] args = joinPoint.getArgs(); + StringBuilder sb = new StringBuilder(); + for (Object obj : args) { + sb.append(obj.getClass().getSimpleName()); + sb.append("["); + sb.append(JSON.toJSONString(obj)); + sb.append("]"); + } + String params = sb.toString(); + String failReason = null; + Integer result = JudgeEnum.YES.getValue(); + if (e != null) { + result = JudgeEnum.NO.getValue(); + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw, true); + e.printStackTrace(pw); + failReason = sw.toString(); + pw.flush(); + pw.close(); + sw.flush(); + sw.close(); + } + UserOperateLogEntity operateLogEntity = + UserOperateLogEntity.builder().userId(requestToken.getRequestUserId()).userName(requestToken.getEmployeeBO().getActualName()).url(request.getRequestURI()).method(operateMethod).param(params).failReason(failReason).result(result).build(); + ApiOperation apiOperation = this.getApiOperation(joinPoint); + if (apiOperation != null) { + operateLogEntity.setContent(apiOperation.value()); + } + Api api = this.getApi(joinPoint); + if (api != null) { + String[] tags = api.tags(); + operateLogEntity.setModule(SmartStringUtil.join(tags, ",")); + } + logService.addLog(operateLogEntity); + } catch (Exception exp) { + log.error("保存操作日志异常:{}", exp.getMessage()); + exp.printStackTrace(); + } + } + + private OperateLog getAnnotationLog(JoinPoint joinPoint) throws Exception { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + OperateLog classAnnotation = AnnotationUtils.findAnnotation(method.getDeclaringClass(), OperateLog.class); + + if (method != null) { + return classAnnotation; + } + return null; + } + + /** + * swagger API + * + * @param joinPoint + * @return + * @throws Exception + */ + private Api getApi(JoinPoint joinPoint) { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + Api classAnnotation = AnnotationUtils.findAnnotation(method.getDeclaringClass(), Api.class); + + if (method != null) { + return classAnnotation; + } + return null; + } + + /** + * swagger ApiOperation + * + * @param joinPoint + * @return + * @throws Exception + */ + private ApiOperation getApiOperation(JoinPoint joinPoint) { + Signature signature = joinPoint.getSignature(); + MethodSignature methodSignature = (MethodSignature) signature; + Method method = methodSignature.getMethod(); + + if (method != null) { + return method.getAnnotation(ApiOperation.class); + } + return null; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/interceptor/SmartAuthenticationInterceptor.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/interceptor/SmartAuthenticationInterceptor.java new file mode 100644 index 00000000..83879e54 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/interceptor/SmartAuthenticationInterceptor.java @@ -0,0 +1,158 @@ +package com.gangquan360.smartadmin.interceptor; + +import com.alibaba.fastjson.JSONObject; +import com.gangquan360.smartadmin.common.anno.NoNeedLogin; +import com.gangquan360.smartadmin.common.anno.NoValidPrivilege; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.CommonConst; +import com.gangquan360.smartadmin.module.login.LoginResponseCodeConst; +import com.gangquan360.smartadmin.module.login.LoginTokenService; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.module.privilege.service.PrivilegeEmployeeService; +import com.gangquan360.smartadmin.util.SmartRequestTokenUtil; +import com.gangquan360.smartadmin.util.SmartStringUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.List; + +/** + * [ 登录拦截器 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Component +public class SmartAuthenticationInterceptor extends HandlerInterceptorAdapter { + + private static final String TOKEN_NAME = "x-access-token"; + + @Value("${access-control-allow-origin}") + private String accessControlAllowOrigin; + + @Autowired + private LoginTokenService loginTokenService; + + @Autowired + private PrivilegeEmployeeService privilegeEmployeeService; + + /** + * 拦截服务器端响应处理ajax请求返回结果 + * + * @param request + * @param response + * @param handler + * @return + * @throws Exception + */ + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + //跨域设置 + this.crossDomainConfig(response); + boolean isHandlerMethod = handler instanceof HandlerMethod; + if (! isHandlerMethod) { + return true; + } + + //不需要登录的注解 + Boolean isNoNeedLogin = ((HandlerMethod) handler).getMethodAnnotation(NoNeedLogin.class) != null; + if (isNoNeedLogin) { + return true; + } + + //放行的Uri前缀 + String uri = request.getRequestURI(); + String contextPath = request.getContextPath(); + String target = uri.replaceFirst(contextPath, ""); + if (CommonConst.CommonCollection.contain(CommonConst.CommonCollection.IGNORE_URL, target)) { + return true; + } + + //需要做token校验, 消息头的token优先于请求query参数的token + String xHeaderToken = request.getHeader(TOKEN_NAME); + String xRequestToken = request.getParameter(TOKEN_NAME); + String xAccessToken = null != xHeaderToken ? xHeaderToken : xRequestToken; + if (null == xAccessToken) { + this.outputResult(response, LoginResponseCodeConst.LOGIN_ERROR); + return false; + } + + //根据token获取登录用户 + RequestTokenBO requestToken = loginTokenService.getEmployeeTokenInfo(xAccessToken); + if (null == requestToken) { + this.outputResult(response, LoginResponseCodeConst.LOGIN_ERROR); + return false; + } + + //判断接口权限 + String methodName = ((HandlerMethod) handler).getMethod().getName(); + String className = ((HandlerMethod) handler).getBeanType().getName(); + List list = SmartStringUtil.splitConvertToList(className, "\\."); + String controllerName = list.get(list.size() - 1); + Method m = ((HandlerMethod) handler).getMethod(); + Class cls = ((HandlerMethod) handler).getBeanType(); + boolean isClzAnnotation = cls.isAnnotationPresent(NoValidPrivilege.class); + boolean isMethodAnnotation = m.isAnnotationPresent(NoValidPrivilege.class); + NoValidPrivilege noValidPrivilege = null; + if (isClzAnnotation) { + noValidPrivilege = cls.getAnnotation(NoValidPrivilege.class); + } else if (isMethodAnnotation) { + noValidPrivilege = m.getAnnotation(NoValidPrivilege.class); + } + //不需验证权限 + if (noValidPrivilege != null) { + SmartRequestTokenUtil.setUser(request, requestToken); + return true; + } + //需要验证权限 + Boolean privilegeValidPass = privilegeEmployeeService.checkEmployeeHavePrivilege(requestToken, controllerName, methodName); + if (! privilegeValidPass) { + this.outputResult(response, LoginResponseCodeConst.NOT_HAVE_PRIVILEGES); + return false; + } + SmartRequestTokenUtil.setUser(request, requestToken); + return true; + } + + /** + * 配置跨域 + * + * @param response + */ + private void crossDomainConfig(HttpServletResponse response) { + response.setHeader("Access-Control-Allow-Origin", accessControlAllowOrigin); + response.setHeader("Access-Control-Allow-Credentials", "true"); + response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE, PATCH"); + response.setHeader("Access-Control-Expose-Headers", "*"); + response.setHeader("Access-Control-Allow-Headers", "Authentication,Origin, X-Requested-With, Content-Type, " + "Accept, x-access-token"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Expires ", "-1"); + } + + /** + * 错误输出 + * + * @param response + * @param responseCodeConst + * @throws IOException + */ + private void outputResult(HttpServletResponse response, LoginResponseCodeConst responseCodeConst) throws IOException { + ResponseDTO wrap = ResponseDTO.wrap(responseCodeConst); + String msg = JSONObject.toJSONString(wrap); + response.setContentType("application/json;charset=UTF-8"); + response.getWriter().write(msg); + response.flushBuffer(); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/listener/SmartAdminStartupRunner.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/listener/SmartAdminStartupRunner.java new file mode 100644 index 00000000..f19aa9b7 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/listener/SmartAdminStartupRunner.java @@ -0,0 +1,22 @@ +package com.gangquan360.smartadmin.listener; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +/** + * 应用启动以后检测code码 + * + * @author zhuo + * @version 1.0 + * @since JDK1.8 + */ + +@Component +public class SmartAdminStartupRunner implements CommandLineRunner { + + @Override + public void run(String... args) { + ResponseCodeConst.init(); + } +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/constant/SqlOperateTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/constant/SqlOperateTypeEnum.java new file mode 100644 index 00000000..49186aff --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/constant/SqlOperateTypeEnum.java @@ -0,0 +1,36 @@ +package com.gangquan360.smartadmin.module.codegenerator.constant; + + +/** + * [ gt,lt 目前只支持Date] + * + * @author yandanyang + * @version 1.0 + * @since JDK1.8 + */ +public enum SqlOperateTypeEnum{ + + + LIKE(1, "like"), + EQUALS(2, "equals"), + IN(3, "in"), + TIME_EQUALS(5, "time_equals"), + TIME_BETWEEN(6, "time_between"); + + private Integer type; + + private String name; + + SqlOperateTypeEnum(Integer type, String name) { + this.type = type; + this.name = name; + } + + public Integer getType() { + return type; + } + + public String getName() { + return name; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/dao/TableDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/dao/TableDao.java new file mode 100644 index 00000000..e772b0f3 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/dao/TableDao.java @@ -0,0 +1,40 @@ +package com.gangquan360.smartadmin.module.codegenerator.dao; + +import com.gangquan360.smartadmin.module.codegenerator.domain.ColumnVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/10 0010 下午 18:59 + * @since JDK1.8 + */ +@Mapper +@Component +public interface TableDao { + + + /** + * 查询表描述 + * @param tableName + * @return + */ + String selectTableDesc(@Param("tableName") String tableName); + + /** + * 查询表列信息 + * @param tableName + * @return + */ + List selectTableColumn(@Param("tableName") String tableName); + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/CodeGeneratorDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/CodeGeneratorDTO.java new file mode 100644 index 00000000..adff6c5f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/CodeGeneratorDTO.java @@ -0,0 +1,51 @@ +package com.gangquan360.smartadmin.module.codegenerator.domain; + +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/11 0011 上午 10:12 + * @since JDK1.8 + */ +@Data +@Builder +public class CodeGeneratorDTO { + + /** + * 需要生成代码的表名 + */ + private String tableName; + + /** + * 表前缀 + */ + private String tablePrefix; + + /** + * 基础包路径 + */ + private String basePackage; + + /** + * 公司 + */ + private String company; + + /** + * 作者 + */ + private String author; + + /** + * 需要构建查询方法的列 + */ + private List queryColumnList; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/CodeGeneratorQueryColumnDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/CodeGeneratorQueryColumnDTO.java new file mode 100644 index 00000000..d945c652 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/CodeGeneratorQueryColumnDTO.java @@ -0,0 +1,30 @@ +package com.gangquan360.smartadmin.module.codegenerator.domain; + +import com.gangquan360.smartadmin.module.codegenerator.constant.SqlOperateTypeEnum; +import lombok.Builder; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/11 0011 上午 10:13 + * @since JDK1.8 + */ +@Data +@Builder +public class CodeGeneratorQueryColumnDTO { + + /** + * 生成查询方法的查询列名 + */ + private String columnName; + + /** + * 此列的查询动作 + */ + private SqlOperateTypeEnum sqlOperate; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/ColumnVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/ColumnVO.java new file mode 100644 index 00000000..3d23b9d8 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/ColumnVO.java @@ -0,0 +1,30 @@ +package com.gangquan360.smartadmin.module.codegenerator.domain; + +import lombok.Builder; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/10 0010 下午 17:55 + * @since JDK1.8 + */ +@Data +@Builder +public class ColumnVO { + + private String columnName; + + private String columnType; + + private String columnDesc; + + private String fieldType; + + private String fieldName; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/QueryFieldVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/QueryFieldVO.java new file mode 100644 index 00000000..fc5c1036 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/domain/QueryFieldVO.java @@ -0,0 +1,30 @@ +package com.gangquan360.smartadmin.module.codegenerator.domain; + +import lombok.Builder; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/10 0010 下午 17:56 + * @since JDK1.8 + */ +@Data +@Builder +public class QueryFieldVO { + + private String fieldName; + + private String columnName; + + private String columnDesc; + + private String fieldType; + + private String sqlOperate; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/service/CodeGeneratorComponent.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/service/CodeGeneratorComponent.java new file mode 100644 index 00000000..724fb4be --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/service/CodeGeneratorComponent.java @@ -0,0 +1,74 @@ +package com.gangquan360.smartadmin.module.codegenerator.service; + +import com.google.common.collect.Lists; +import org.springframework.stereotype.Component; + +import java.io.File; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/11 0011 上午 8:33 + * @since JDK1.8 + */ +@Component +public class CodeGeneratorComponent { + + private static Map dataMap = new HashMap<>(16); + + static { + dataMap(); + } + + public static void dataMap(){ + dataMap.put("int","Integer"); + dataMap.put("tinyint","Integer"); + dataMap.put("smallint","Integer"); + dataMap.put("integer","Integer"); + dataMap.put("bigint","Long"); + dataMap.put("float","Float"); + dataMap.put("double","Double"); + dataMap.put("decimal","BigDecimal"); + + dataMap.put("char","String"); + dataMap.put("varchar","String"); + dataMap.put("tinytext","String"); + dataMap.put("text","String"); + dataMap.put("longtext","String"); + + dataMap.put("date","Date"); + dataMap.put("datetime","Date"); + dataMap.put("timestamp","Date"); + + } + + + public Map codeTemplates(String moduleClass, String basePackage, String modulePackage){ + String javaPackagePath = "src"+File.separator+"main" + File.separator + "java" + File.separator; + javaPackagePath = javaPackagePath + basePackage.replace(".", File.separator) + File.separator+"module"+File.separator + modulePackage + File.separator; + String xmlPackagePath = "src"+File.separator+"main" + File.separator + "resources" + File.separator +"mapper"+File.separator+ modulePackage + File.separator; + Map templateMap = new HashMap<>(7); + templateMap.put("templates/codegenerator/Controller.java.vm",javaPackagePath+"controller"+File.separator+moduleClass+"Controller.java"); + templateMap.put("templates/codegenerator/Dao.java.vm",javaPackagePath+"dao"+File.separator+moduleClass+"Dao.java"); + templateMap.put("templates/codegenerator/Dao.xml.vm",xmlPackagePath+moduleClass+"Mapper.xml"); + templateMap.put("templates/codegenerator/DTO.java.vm",javaPackagePath+"domain"+File.separator+"dto"+File.separator+moduleClass+"DTO.java"); + templateMap.put("templates/codegenerator/Entity.java.vm",javaPackagePath+"domain"+File.separator+"entity"+File.separator+moduleClass+"Entity.java"); + templateMap.put("templates/codegenerator/QueryDTO.java.vm",javaPackagePath+"domain"+File.separator+"dto"+File.separator+moduleClass+"QueryDTO.java"); + templateMap.put("templates/codegenerator/Service.java.vm",javaPackagePath+"service"+File.separator+moduleClass+"Service.java"); + return templateMap; + } + + public String getJavaType(String mysqlType ){ + String javaType = dataMap.get(mysqlType); + return javaType; + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/service/CodeGeneratorService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/service/CodeGeneratorService.java new file mode 100644 index 00000000..b1158d19 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/codegenerator/service/CodeGeneratorService.java @@ -0,0 +1,313 @@ +package com.gangquan360.smartadmin.module.codegenerator.service; + +import com.gangquan360.smartadmin.module.codegenerator.dao.TableDao; +import com.gangquan360.smartadmin.module.codegenerator.domain.CodeGeneratorDTO; +import com.gangquan360.smartadmin.module.codegenerator.domain.CodeGeneratorQueryColumnDTO; +import com.gangquan360.smartadmin.module.codegenerator.domain.ColumnVO; +import com.gangquan360.smartadmin.module.codegenerator.domain.QueryFieldVO; +import com.gangquan360.smartadmin.util.SmartDateUtil; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang.WordUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ResourceUtils; + +import java.io.File; +import java.io.FileWriter; +import java.util.*; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/11 0011 上午 9:36 + * @since JDK1.8 + */ +@Slf4j +@Service +public class CodeGeneratorService { + + @Autowired + private TableDao tableDao; + + @Autowired + private CodeGeneratorComponent codeGeneratorComponent; + + /** + * 大家注意了开始生成代码了 + * + * @param codeGenerator + * @throws Exception + */ + public void codeGenerator(CodeGeneratorDTO codeGenerator) throws Exception { + this.basicValid(codeGenerator); + String date = SmartDateUtil.formatYMDHMS(new Date()); + String tableDesc = this.getTableDesc(codeGenerator.getTableName()); + String author = codeGenerator.getAuthor(); + String basePackage = codeGenerator.getBasePackage(); + if (StringUtils.isEmpty(basePackage)) { + basePackage = "com.gangquan360.smartadmin"; + } + String moduleClass = this.tableName2Class(codeGenerator.getTableName(), codeGenerator.getTablePrefix()); + String moduleVar = this.tableName2Var(codeGenerator.getTableName(), codeGenerator.getTablePrefix()); + String modulePackage = this.tableName2Package(codeGenerator.getTableName(), codeGenerator.getTablePrefix()); + + List columnList = this.columnList(codeGenerator.getTableName()); + List queryFieldList = this.buildQueryField(codeGenerator, columnList); + Map codeTemplates = codeGeneratorComponent.codeTemplates(moduleClass, basePackage, modulePackage); + List queryImports = this.buildQueryImport(queryFieldList); + List dtoImports = this.buildDTOImport(columnList); + List entityImports = this.buildEntityImport(columnList); + Properties p = new Properties(); + p.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + p.put("directive.foreach.counter.name", "velocityCount"); + p.put("directive.foreach.counter.initial.value", "1"); + Velocity.init(p); + Map map = new HashMap<>(); + map.put("company", codeGenerator.getCompany()); + map.put("tableName", codeGenerator.getTableName()); + map.put("basePackage", basePackage); + map.put("modulePackage", modulePackage); + map.put("moduleClass", moduleClass); + map.put("tableDesc", tableDesc); + map.put("author", author); + map.put("date", date); + map.put("moduleVar", moduleVar); + map.put("columnList", columnList); + map.put("queryFieldList", queryFieldList); + map.put("queryImports", queryImports); + map.put("dtoImports", dtoImports); + map.put("entityImports", entityImports); + VelocityContext context = new VelocityContext(map); + this.codeGenerator(context, codeTemplates); + } + + private List buildQueryImport(List queryFieldList) { + List queryImports = Lists.newArrayList(); + if (CollectionUtils.isNotEmpty(queryFieldList)) { + queryFieldList.forEach(e -> { + importPackage(queryImports, e.getFieldType()); + if ("in".equals(e.getSqlOperate())) { + queryImports.add("import java.util.List;"); + } + }); + } + return queryImports; + } + + private List buildDTOImport(List columnList) { + List dtoImports = Lists.newArrayList(); + if (CollectionUtils.isNotEmpty(columnList)) { + columnList.forEach(e -> { + importPackage(dtoImports, e.getFieldType()); + }); + } + return dtoImports; + } + + private List buildEntityImport(List columnList) { + List entityImports = Lists.newArrayList(); + if (CollectionUtils.isNotEmpty(columnList)) { + columnList.forEach(e -> { + if (! e.getFieldName().equals("createTime") && ! e.getFieldName().equals("updateTime") && ! e.getFieldName().equals("id")) { + importPackage(entityImports, e.getFieldType()); + } + }); + } + return entityImports; + } + + private void importPackage(List imports, String fieldType) { + if ("Date".equals(fieldType) && ! imports.contains("import java.util.Date;")) { + imports.add("import java.util.Date;"); + } + if ("BigDecimal".equals(fieldType) && ! imports.contains("import java.math.BigDecimal;")) { + imports.add("import java.math.BigDecimal;"); + } + } + + /** + * 生成代码 + * + * @param context + * @param codeTemplates + */ + private void codeGenerator(VelocityContext context, Map codeTemplates) throws Exception { + String projectPath = ResourceUtils.getURL("classpath:").getPath(); + String targetDir = "target"; + int targetIndex = StringUtils.indexOf(projectPath, targetDir); + projectPath = projectPath.substring(0, targetIndex + targetDir.length() + 1); + projectPath = projectPath.replace("target/", "").replaceFirst("/", ""); + for (Entry entry : codeTemplates.entrySet()) { + String template = entry.getKey(); + String filePath = projectPath + entry.getValue(); + String fileName = filePath.substring(filePath.lastIndexOf(File.separator) + 1); + String fileDir = filePath.replace(fileName, ""); + File directory = new File(fileDir); + if (! directory.exists()) { + directory.mkdirs(); + } + FileWriter writer; + try { + writer = new FileWriter(filePath); + Template tpl = Velocity.getTemplate(template, "UTF-8"); + tpl.merge(context, writer); + writer.flush(); + writer.close(); + } catch (Exception e) { + log.error("", e); + } + } + } + + public static void main(String[] args) { + try { + int i = 1 / 0; + } catch (Exception e) { + log.error("", e); + } + } + + private void basicValid(CodeGeneratorDTO codeGenerator) throws Exception { + if (StringUtils.isEmpty(codeGenerator.getTableName())) { + throw new Exception("你没建表吗?"); + } + if (StringUtils.isEmpty(codeGenerator.getTablePrefix())) { + throw new Exception("你的表没前缀吗?"); + } + if (StringUtils.isEmpty(codeGenerator.getAuthor())) { + throw new Exception("输入下你的大名"); + } + } + + /** + * 构建查询集合 + * + * @param codeGenerator + * @param columnList + * @return + * @throws Exception + */ + private List buildQueryField(CodeGeneratorDTO codeGenerator, List columnList) throws Exception { + List queryFieldList = Lists.newArrayList(); + Map storageMap = columnList.stream().collect(Collectors.toMap(ColumnVO:: getColumnName, e -> e)); + List queryColumnList = codeGenerator.getQueryColumnList(); + if (CollectionUtils.isEmpty(queryColumnList)) { + return queryFieldList; + } + for (CodeGeneratorQueryColumnDTO queryColumn : queryColumnList) { + ColumnVO columnDTO = storageMap.get(queryColumn.getColumnName()); + if (columnDTO == null) { + String errorMsg = "sql列[" + queryColumn.getColumnName() + "]在表[" + codeGenerator.getTableName() + "]中不存在。"; + log.error(errorMsg); + throw new Exception(errorMsg); + } + QueryFieldVO queryField = + QueryFieldVO.builder().fieldName(columnDTO.getFieldName()).fieldType(columnDTO.getFieldType()).columnName(columnDTO.getColumnName()).columnDesc(columnDTO.getColumnDesc()).sqlOperate(queryColumn.getSqlOperate().getName()).build(); + queryFieldList.add(queryField); + } + return queryFieldList; + } + + /** + * 列数据 组合 + * + * @param tableName + * @return + * @throws Exception + */ + private List columnList(String tableName) throws Exception { + List list = tableDao.selectTableColumn(tableName); + for (ColumnVO column : list) { + String javaType = codeGeneratorComponent.getJavaType(column.getColumnType()); + if (StringUtils.isEmpty(javaType)) { + String errorMsg = "sql数据类型[" + column.getColumnType() + "]缺少对应的java类型。"; + log.error(errorMsg); + throw new Exception(errorMsg); + } + if ("Integer".equals(javaType) && column.getColumnName().contains("id")) { + column.setFieldType("Long"); + } else { + column.setFieldType(javaType); + } + column.setFieldName(this.columnName2Field(column.getColumnName())); + } + return list; + } + + /** + * 获取列注释为类描述 + * + * @param tableName + * @return + */ + private String getTableDesc(String tableName) { + return tableDao.selectTableDesc(tableName); + } + + /** + * 列名转字段名 + * + * @param columnName + * @return + */ + private String columnName2Field(String columnName) { + String transName = WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", ""); + return WordUtils.uncapitalize(transName); + } + + /** + * 表名转类名前缀 + * + * @param tableName + * @param tablePrefix + * @return + */ + private String tableName2Class(String tableName, String tablePrefix) { + if (StringUtils.isNotBlank(tablePrefix)) { + tableName = tableName.replaceFirst(tablePrefix, ""); + } + return WordUtils.capitalizeFully(tableName, new char[]{'_'}).replace("_", ""); + } + + /** + * 表名转包名 + * + * @param tableName + * @param tablePrefix + * @return + */ + private String tableName2Package(String tableName, String tablePrefix) { + if (StringUtils.isNotBlank(tablePrefix)) { + tableName = tableName.replaceFirst(tablePrefix, ""); + } + return tableName.replace("_", ""); + } + + /** + * 表名转 java变量前缀 + * + * @param tableName + * @param tablePrefix + * @return + */ + private String tableName2Var(String tableName, String tablePrefix) { + if (StringUtils.isNotBlank(tablePrefix)) { + tableName = tableName.replaceFirst(tablePrefix, ""); + } + String transName = WordUtils.capitalizeFully(tableName, new char[]{'_'}).replace("_", ""); + return WordUtils.uncapitalize(transName); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/DataScopeController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/DataScopeController.java new file mode 100644 index 00000000..91a31754 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/DataScopeController.java @@ -0,0 +1,57 @@ +package com.gangquan360.smartadmin.module.datascope; + +import com.gangquan360.smartadmin.common.anno.NoValidPrivilege; +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.datascope.domain.dto.*; +import com.gangquan360.smartadmin.module.datascope.service.DataScopeService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/27 0027 下午 15:12 + * @since JDK1.8 + */ +@Api(tags = {SwaggerTagConst.Admin.MANAGER_DATA_SCOPE}) +@OperateLog +@RestController +public class DataScopeController { + + @Autowired + private DataScopeService dataScopeService; + + @ApiOperation(value = "获取当前系统所配置的所有数据范围") + @GetMapping("/dataScope/list") + @NoValidPrivilege + public ResponseDTO> dataScopeList() { + return dataScopeService.dataScopeList(); + } + + @ApiOperation(value = "获取某角色所设置的数据范围") + @GetMapping("/dataScope/listByRole/{roleId}") + @NoValidPrivilege + public ResponseDTO> dataScopeListByRole(@PathVariable Long roleId) { + return dataScopeService.dataScopeListByRole(roleId); + } + + @ApiOperation(value = "批量设置某角色数据范围") + @PostMapping("/dataScope/batchSet") + @NoValidPrivilege + public ResponseDTO dataScopeBatchSet(@RequestBody @Valid DataScopeBatchSetRoleDTO batchSetRoleDTO) { + return dataScopeService.dataScopeBatchSet(batchSetRoleDTO); + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/DataScopeRoleDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/DataScopeRoleDao.java new file mode 100644 index 00000000..750571dd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/DataScopeRoleDao.java @@ -0,0 +1,52 @@ +package com.gangquan360.smartadmin.module.datascope; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.gangquan360.smartadmin.module.datascope.domain.entity.DataScopeRoleEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/27 0027 下午 14:41 + * @since JDK1.8 + */ +@Mapper +@Component +public interface DataScopeRoleDao extends BaseMapper { + + /** + * 获取某个角色的设置信息 + * @param roleId + * @return + */ + List listByRoleId(@Param("roleId") Long roleId); + + /** + * 获取某批角色的所有数据范围配置信息 + * @param roleIdList + * @return + */ + List listByRoleIdList(@Param("roleIdList") List roleIdList); + + /** + * 删除某个角色的设置信息 + * @param roleId + * @return + */ + void deleteByRoleId(@Param("roleId") Long roleId); + + + /** + * 批量添加设置信息 + * @param list + */ + void batchInsert(@Param("list")List list); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/MyBatisPlugin.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/MyBatisPlugin.java new file mode 100644 index 00000000..64625ce3 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/MyBatisPlugin.java @@ -0,0 +1,152 @@ +package com.gangquan360.smartadmin.module.datascope; + +import com.gangquan360.smartadmin.module.datascope.domain.dto.DataScopeSqlConfigDTO; +import com.gangquan360.smartadmin.module.datascope.service.DataScopeSqlConfigService; +import com.gangquan360.smartadmin.third.SmartApplicationContext; +import com.gangquan360.smartadmin.util.SmartStringUtil; +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.mapping.*; +import org.apache.ibatis.plugin.*; +import org.apache.ibatis.session.ResultHandler; +import org.apache.ibatis.session.RowBounds; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Properties; + +/** + * [ mybaits sql 拦截 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Intercepts({@Signature(type = org.apache.ibatis.executor.Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})}) +@Component +public class MyBatisPlugin implements Interceptor { + + @Override + public Object intercept(Invocation invocation) throws Throwable { + MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0]; + Object parameter = invocation.getArgs()[1]; + BoundSql boundSql = mappedStatement.getBoundSql(parameter); + String originalSql = boundSql.getSql().trim(); + String id = mappedStatement.getId(); + List methodStrList = SmartStringUtil.splitConvertToList(id, "\\."); + String path = methodStrList.get(methodStrList.size() - 2) + "." + methodStrList.get(methodStrList.size() - 1); + DataScopeSqlConfigService dataScopeSqlConfigService = this.dataScopeSqlConfigService(); + if (dataScopeSqlConfigService == null) { + return invocation.proceed(); + } + DataScopeSqlConfigDTO sqlConfigDTO = dataScopeSqlConfigService.getSqlConfig(path); + if (sqlConfigDTO != null) { + BoundSql newBoundSql = copyFromBoundSql(mappedStatement, boundSql, this.joinSql(originalSql, sqlConfigDTO)); + ParameterMap map = mappedStatement.getParameterMap(); + MappedStatement newMs = copyFromMappedStatement(mappedStatement, new BoundSqlSqlSource(newBoundSql), map); + invocation.getArgs()[0] = newMs; + } + + Object obj = invocation.proceed(); + return obj; + } + + private String joinSql(String sql, DataScopeSqlConfigDTO sqlConfigDTO) { + if (null == sqlConfigDTO) { + return sql; + } + String appendSql = this.dataScopeSqlConfigService().getJoinSql(sqlConfigDTO); + if (StringUtils.isEmpty(appendSql)) { + return sql; + } + Integer appendSqlWhereIndex = sqlConfigDTO.getWhereIndex(); + String where = "where"; + String order = "order by"; + String group = "group by"; + int whereIndex = StringUtils.ordinalIndexOf(sql.toLowerCase(), where, appendSqlWhereIndex + 1); + int orderIndex = sql.toLowerCase().indexOf(order); + int groupIndex = sql.toLowerCase().indexOf(group); + if (whereIndex > - 1) { + String subSql = sql.substring(0, whereIndex + where.length() + 1); + subSql = subSql + " " + appendSql + " AND " + sql.substring(whereIndex + where.length() + 1); + return subSql; + } + + if (groupIndex > - 1) { + String subSql = sql.substring(0, groupIndex); + subSql = subSql + " where " + appendSql + " " + sql.substring(groupIndex); + return subSql; + } + if (orderIndex > - 1) { + String subSql = sql.substring(0, orderIndex); + subSql = subSql + " where " + appendSql + " " + sql.substring(orderIndex); + return subSql; + } + sql += " where " + appendSql; + return sql; + } + + public DataScopeSqlConfigService dataScopeSqlConfigService() { + return (DataScopeSqlConfigService) SmartApplicationContext.getBean("dataScopeSqlConfigService"); + } + + public class BoundSqlSqlSource implements SqlSource { + + BoundSql boundSql; + + public BoundSqlSqlSource(BoundSql boundSql) { + this.boundSql = boundSql; + } + @Override + public BoundSql getBoundSql(Object parameterObject) { + return boundSql; + } + } + + /** + * 复制MappedStatement对象 + */ + private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource, ParameterMap parameterMap) { + + MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType()); + builder.resource(ms.getResource()); + builder.fetchSize(ms.getFetchSize()); + builder.statementType(ms.getStatementType()); + builder.keyGenerator(ms.getKeyGenerator()); + builder.timeout(ms.getTimeout()); + builder.parameterMap(parameterMap); + builder.resultMaps(ms.getResultMaps()); + builder.resultSetType(ms.getResultSetType()); + builder.cache(ms.getCache()); + builder.flushCacheRequired(ms.isFlushCacheRequired()); + builder.useCache(ms.isUseCache()); + return builder.build(); + } + + /** + * 复制BoundSql对象 + */ + private BoundSql copyFromBoundSql(MappedStatement ms, BoundSql boundSql, String sql) { + BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), sql, boundSql.getParameterMappings(), boundSql.getParameterObject()); + for (ParameterMapping mapping : boundSql.getParameterMappings()) { + String prop = mapping.getProperty(); + if (boundSql.hasAdditionalParameter(prop)) { + newBoundSql.setAdditionalParameter(prop, boundSql.getAdditionalParameter(prop)); + } + } + return newBoundSql; + } + + @Override + public Object plugin(Object arg0) { + return Plugin.wrap(arg0, this); + } + + @Override + public void setProperties(Properties arg0) { + + } + +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeTypeEnum.java new file mode 100644 index 00000000..8fba7ff8 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeTypeEnum.java @@ -0,0 +1,47 @@ +package com.gangquan360.smartadmin.module.datascope.constant; + + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/28 0028 下午 15:37 + * @since JDK1.8 + */ +public enum DataScopeTypeEnum { + + DEFAULT(0,0,"默认类型","数据范围样例"); + + private Integer type; + private Integer sort; + private String name; + private String desc; + + DataScopeTypeEnum(Integer type,Integer sort,String name,String desc) { + this.type = type; + this.sort = sort; + this.name = name; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public Integer getSort() { + return sort; + } + + public String getDesc() { + return desc; + } + + public String getName() { + return name; + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeViewTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeViewTypeEnum.java new file mode 100644 index 00000000..0ff89c04 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeViewTypeEnum.java @@ -0,0 +1,55 @@ +package com.gangquan360.smartadmin.module.datascope.constant; + + +import java.util.Arrays; +import java.util.Optional; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/28 0028 下午 15:37 + * @since JDK1.8 + */ +public enum DataScopeViewTypeEnum { + + ME(0,0,"本人"), + + DEPARTMENT(1,5,"本部门"), + + DEPARTMENT_AND_SUB(2,10,"本部门及下属子部门"), + + ALL(3,15,"全部"); + + private Integer type; + private Integer level; + private String name; + + DataScopeViewTypeEnum(Integer type,Integer level, String name) { + this.type = type; + this.level = level; + this.name = name; + } + + public Integer getType() { + return type; + } + + public Integer getLevel() { + return level; + } + + public String getName() { + return name; + } + + public static DataScopeViewTypeEnum valueOf(Integer type) { + DataScopeViewTypeEnum[] values = DataScopeViewTypeEnum.values(); + Optional first = Arrays.stream(values).filter(e -> e.getType().equals(type)).findFirst(); + return !first.isPresent() ? null : first.get(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeWhereInTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeWhereInTypeEnum.java new file mode 100644 index 00000000..8008c428 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/constant/DataScopeWhereInTypeEnum.java @@ -0,0 +1,37 @@ +package com.gangquan360.smartadmin.module.datascope.constant; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/8 0008 下午 16:00 + * @since JDK1.8 + */ +public enum DataScopeWhereInTypeEnum { + + EMPLOYEE(0,"以员工IN"), + + DEPARTMENT(1,"以部门IN"); + + private Integer type; + private String desc; + + DataScopeWhereInTypeEnum(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + + public String getDesc() { + return desc; + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeAndViewTypeVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeAndViewTypeVO.java new file mode 100644 index 00000000..1dd55a68 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeAndViewTypeVO.java @@ -0,0 +1,36 @@ +package com.gangquan360.smartadmin.module.datascope.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/27 0027 下午 16:37 + * @since JDK1.8 + */ +@Data +public class DataScopeAndViewTypeVO { + + @ApiModelProperty("数据范围类型") + private Integer dataScopeType; + + @ApiModelProperty("数据范围名称") + private String dataScopeTypeName; + + @ApiModelProperty("描述") + private String dataScopeTypeDesc; + + @ApiModelProperty("顺序") + private Integer dataScopeTypeSort; + + @ApiModelProperty("可见范围列表") + private List viewTypeList; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeBatchSetDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeBatchSetDTO.java new file mode 100644 index 00000000..3d361d91 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeBatchSetDTO.java @@ -0,0 +1,28 @@ +package com.gangquan360.smartadmin.module.datascope.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/27 0027 下午 16:51 + * @since JDK1.8 + */ +@Data +public class DataScopeBatchSetDTO { + + @ApiModelProperty("数据范围类型") + @NotNull(message = "数据范围类型不能为空") + private Integer dataScopeType; + + @ApiModelProperty("可见范围") + @NotNull(message = "可见范围不能为空") + private Integer viewType; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeBatchSetRoleDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeBatchSetRoleDTO.java new file mode 100644 index 00000000..7b64750d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeBatchSetRoleDTO.java @@ -0,0 +1,30 @@ +package com.gangquan360.smartadmin.module.datascope.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/27 0027 下午 16:47 + * @since JDK1.8 + */ +@Data +public class DataScopeBatchSetRoleDTO { + + @ApiModelProperty("角色id") + @NotNull(message = "角色id不能为空") + private Long roleId; + + @ApiModelProperty("设置信息") + @Valid + private List batchSetList; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeDTO.java new file mode 100644 index 00000000..11718988 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeDTO.java @@ -0,0 +1,36 @@ +package com.gangquan360.smartadmin.module.datascope.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/27 0027 下午 16:37 + * @since JDK1.8 + */ +@Data +@Builder +public class DataScopeDTO { + + @ApiModelProperty("数据范围类型") + private Integer dataScopeType; + + @ApiModelProperty("数据范围名称") + private String dataScopeTypeName; + + @ApiModelProperty("描述") + private String dataScopeTypeDesc; + + @ApiModelProperty("顺序") + private Integer dataScopeTypeSort; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeSelectVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeSelectVO.java new file mode 100644 index 00000000..3f0ddf8c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeSelectVO.java @@ -0,0 +1,24 @@ +package com.gangquan360.smartadmin.module.datascope.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/27 0027 下午 16:43 + * @since JDK1.8 + */ +@Data +public class DataScopeSelectVO { + + @ApiModelProperty("数据范围id") + private Integer dataScopeType; + + @ApiModelProperty("可见范围") + private Integer viewType; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeSqlConfigDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeSqlConfigDTO.java new file mode 100644 index 00000000..64f83755 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeSqlConfigDTO.java @@ -0,0 +1,25 @@ +package com.gangquan360.smartadmin.module.datascope.domain.dto; + +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/28 0028 下午 17:21 + * @since JDK1.8 + */ +@Data +public class DataScopeSqlConfigDTO { + + private Integer dataScopeType; + + private String joinSql; + + private Integer whereIndex; + + private Integer dataScopeWhereInType; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeViewTypeVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeViewTypeVO.java new file mode 100644 index 00000000..fd4acffa --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/dto/DataScopeViewTypeVO.java @@ -0,0 +1,28 @@ +package com.gangquan360.smartadmin.module.datascope.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Builder; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/28 0028 下午 15:41 + * @since JDK1.8 + */ +@Data +@Builder +public class DataScopeViewTypeVO { + + @ApiModelProperty("可见范围") + private Integer viewType; + @ApiModelProperty("可见范围名称") + private String viewTypeName; + + @ApiModelProperty("级别,用于表示范围大小") + private Integer viewTypeLevel; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/entity/DataScopeRoleEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/entity/DataScopeRoleEntity.java new file mode 100644 index 00000000..cb0de325 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/domain/entity/DataScopeRoleEntity.java @@ -0,0 +1,33 @@ +package com.gangquan360.smartadmin.module.datascope.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * [ 数据范围与角色关系 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/27 0027 下午 14:43 + * @since JDK1.8 + */ +@Data +@TableName("t_role_data_scope") +public class DataScopeRoleEntity extends BaseEntity{ + + /** + * 数据范围id + */ + private Integer dataScopeType; + /** + * 数据范围类型 + */ + private Integer viewType; + /** + * 角色id + */ + private Long roleId; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeService.java new file mode 100644 index 00000000..b2169b4d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeService.java @@ -0,0 +1,118 @@ +package com.gangquan360.smartadmin.module.datascope.service; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.datascope.DataScopeRoleDao; +import com.gangquan360.smartadmin.module.datascope.constant.DataScopeTypeEnum; +import com.gangquan360.smartadmin.module.datascope.constant.DataScopeViewTypeEnum; +import com.gangquan360.smartadmin.module.datascope.domain.dto.*; +import com.gangquan360.smartadmin.module.datascope.domain.entity.DataScopeRoleEntity; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.google.common.collect.Lists; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; + +import java.util.Comparator; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/27 0027 下午 14:52 + * @since JDK1.8 + */ +@Service +public class DataScopeService { + + @Autowired + private DataScopeRoleDao dataScopeRoleDao; + + /** + * 获取所有可以进行数据范围配置的信息 + * + * @return + */ + public ResponseDTO> dataScopeList() { + List dataScopeList = this.getDataScopeType(); + List dataScopeAndTypeList = SmartBeanUtil.copyList(dataScopeList, DataScopeAndViewTypeVO.class); + List typeList = this.getViewType(); + dataScopeAndTypeList.forEach(e -> { + e.setViewTypeList(typeList); + }); + return ResponseDTO.succData(dataScopeAndTypeList); + } + + /** + * 获取当前系统存在的数据可见范围 + * + * @return + */ + public List getViewType() { + List viewTypeList = Lists.newArrayList(); + DataScopeViewTypeEnum[] enums = DataScopeViewTypeEnum.class.getEnumConstants(); + DataScopeViewTypeVO dataScopeViewTypeDTO; + for (DataScopeViewTypeEnum viewTypeEnum : enums) { + dataScopeViewTypeDTO = DataScopeViewTypeVO.builder().viewType(viewTypeEnum.getType()).viewTypeLevel(viewTypeEnum.getLevel()).viewTypeName(viewTypeEnum.getName()).build(); + viewTypeList.add(dataScopeViewTypeDTO); + } + Comparator comparator = (h1, h2) -> h1.getViewTypeLevel().compareTo(h2.getViewTypeLevel()); + viewTypeList.sort(comparator); + return viewTypeList; + } + + public List getDataScopeType() { + List dataScopeTypeList = Lists.newArrayList(); + DataScopeTypeEnum[] enums = DataScopeTypeEnum.class.getEnumConstants(); + DataScopeDTO dataScopeDTO; + for (DataScopeTypeEnum typeEnum : enums) { + dataScopeDTO = + DataScopeDTO.builder().dataScopeType(typeEnum.getType()).dataScopeTypeDesc(typeEnum.getDesc()).dataScopeTypeName(typeEnum.getName()).dataScopeTypeSort(typeEnum.getSort()).build(); + dataScopeTypeList.add(dataScopeDTO); + } + Comparator comparator = (h1, h2) -> h1.getDataScopeTypeSort().compareTo(h2.getDataScopeTypeSort()); + dataScopeTypeList.sort(comparator); + return dataScopeTypeList; + } + + /** + * 获取某个角色的数据范围设置信息 + * + * @param roleId + * @return + */ + public ResponseDTO> dataScopeListByRole(Long roleId) { + + List dataScopeRoleEntityList = dataScopeRoleDao.listByRoleId(roleId); + if (CollectionUtils.isEmpty(dataScopeRoleEntityList)) { + return ResponseDTO.succData(Lists.newArrayList()); + } + List dataScopeSelects = SmartBeanUtil.copyList(dataScopeRoleEntityList, DataScopeSelectVO.class); + return ResponseDTO.succData(dataScopeSelects); + } + + /** + * 批量设置某个角色的数据范围设置信息 + * + * @param batchSetRoleDTO + * @return + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO dataScopeBatchSet(DataScopeBatchSetRoleDTO batchSetRoleDTO) { + List batchSetList = batchSetRoleDTO.getBatchSetList(); + if (CollectionUtils.isEmpty(batchSetList)) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "缺少配置信息"); + } + List dataScopeRoleEntityList = SmartBeanUtil.copyList(batchSetList, DataScopeRoleEntity.class); + dataScopeRoleEntityList.forEach(e -> e.setRoleId(batchSetRoleDTO.getRoleId())); + dataScopeRoleDao.deleteByRoleId(batchSetRoleDTO.getRoleId()); + dataScopeRoleDao.batchInsert(dataScopeRoleEntityList); + return ResponseDTO.succ(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeSqlConfigService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeSqlConfigService.java new file mode 100644 index 00000000..82d744dd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeSqlConfigService.java @@ -0,0 +1,121 @@ +package com.gangquan360.smartadmin.module.datascope.service; + +import com.gangquan360.smartadmin.common.anno.DataScope; +import com.gangquan360.smartadmin.module.datascope.constant.DataScopeWhereInTypeEnum; +import com.gangquan360.smartadmin.module.datascope.domain.dto.DataScopeSqlConfigDTO; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.util.SmartRequestTokenUtil; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.reflections.Reflections; +import org.reflections.scanners.MethodAnnotationsScanner; +import org.reflections.util.ClasspathHelper; +import org.reflections.util.ConfigurationBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/29 0029 上午 10:12 + * @since JDK1.8 + */ +@Service +public class DataScopeSqlConfigService { + + private ConcurrentHashMap dataScopeMethodMap = new ConcurrentHashMap<>(); + + @Autowired + private DataScopeViewService dataScopeViewService; + + @Value("${swagger.packAge}") + private String scanPackage; + + /** + * 注解joinsql 参数 + */ + private static final String EMPLOYEE_PARAM = "#employeeIds"; + + private static final String DEPARTMENT_PARAM = "#departmentIds"; + + @PostConstruct + private void initDataScopeMethodMap() { + this.refreshDataScopeMethodMap(); + } + + /** + * 刷新 所有添加数据范围注解的接口方法配置 + * + * @return + */ + private Map refreshDataScopeMethodMap() { + Reflections reflections = new Reflections(new ConfigurationBuilder().setUrls(ClasspathHelper.forPackage(scanPackage)).setScanners(new MethodAnnotationsScanner())); + Set methods = reflections.getMethodsAnnotatedWith(DataScope.class); + for (Method method : methods) { + DataScope dataScopeAnnotation = method.getAnnotation(DataScope.class); + if (dataScopeAnnotation != null) { + DataScopeSqlConfigDTO configDTO = new DataScopeSqlConfigDTO(); + configDTO.setDataScopeType(dataScopeAnnotation.dataScopeType().getType()); + configDTO.setJoinSql(dataScopeAnnotation.joinSql()); + configDTO.setWhereIndex(dataScopeAnnotation.whereIndex()); + dataScopeMethodMap.put(method.getDeclaringClass().getSimpleName() + "." + method.getName(), configDTO); + } + } + return dataScopeMethodMap; + } + + /** + * 根据调用的方法获取,此方法的配置信息 + * + * @param method + * @return + */ + public DataScopeSqlConfigDTO getSqlConfig(String method) { + DataScopeSqlConfigDTO sqlConfigDTO = this.dataScopeMethodMap.get(method); + return sqlConfigDTO; + } + + /** + * 组装需要拼接的sql + * + * @param sqlConfigDTO + * @return + */ + public String getJoinSql(DataScopeSqlConfigDTO sqlConfigDTO) { + Integer dataScopeType = sqlConfigDTO.getDataScopeType(); + String joinSql = sqlConfigDTO.getJoinSql(); + RequestTokenBO requestToken = SmartRequestTokenUtil.getThreadLocalUser(); + Long employeeId = requestToken.getRequestUserId(); + if (DataScopeWhereInTypeEnum.EMPLOYEE.getType().equals(sqlConfigDTO.getDataScopeWhereInType())) { + List canViewEmployeeIds = dataScopeViewService.getCanViewEmployeeId(dataScopeType, employeeId); + if (CollectionUtils.isEmpty(canViewEmployeeIds)) { + return ""; + } + String employeeIds = StringUtils.join(canViewEmployeeIds, ","); + String sql = joinSql.replaceAll(EMPLOYEE_PARAM, employeeIds); + return sql; + } + if (DataScopeWhereInTypeEnum.DEPARTMENT.getType().equals(sqlConfigDTO.getDataScopeWhereInType())) { + List canViewDepartmentIds = dataScopeViewService.getCanViewDepartmentId(dataScopeType, employeeId); + if (CollectionUtils.isEmpty(canViewDepartmentIds)) { + return ""; + } + String departmentIds = StringUtils.join(canViewDepartmentIds, ","); + String sql = joinSql.replaceAll(DEPARTMENT_PARAM, departmentIds); + return sql; + } + return ""; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeViewService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeViewService.java new file mode 100644 index 00000000..e2481284 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/datascope/service/DataScopeViewService.java @@ -0,0 +1,168 @@ +package com.gangquan360.smartadmin.module.datascope.service; + +import com.gangquan360.smartadmin.module.datascope.DataScopeRoleDao; +import com.gangquan360.smartadmin.module.datascope.constant.DataScopeViewTypeEnum; +import com.gangquan360.smartadmin.module.datascope.domain.entity.DataScopeRoleEntity; +import com.gangquan360.smartadmin.module.department.DepartmentTreeService; +import com.gangquan360.smartadmin.module.employee.EmployeeDao; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import com.gangquan360.smartadmin.module.employee.domain.entity.EmployeeEntity; +import com.gangquan360.smartadmin.module.employee.domain.vo.EmployeeVO; +import com.gangquan360.smartadmin.module.privilege.service.PrivilegeEmployeeService; +import com.gangquan360.smartadmin.module.role.roleemployee.RoleEmployeeDao; +import com.gangquan360.smartadmin.module.systemconfig.SystemConfigService; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigEnum; +import com.gangquan360.smartadmin.module.systemconfig.domain.dto.SystemConfigDTO; +import com.google.common.collect.Lists; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/28 0028 下午 15:56 + * @since JDK1.8 + */ +@Service +public class DataScopeViewService { + + @Autowired + private RoleEmployeeDao roleEmployeeDao; + + @Autowired + private DataScopeRoleDao dataScopeRoleDao; + + @Autowired + private DepartmentTreeService departmentTreeService; + + @Autowired + private EmployeeDao employeeDao; + + @Autowired + private PrivilegeEmployeeService privilegeEmployeeService; + + /** + * 获取某人可以查看的所有人员信息 + * + * @param dataScopeType + * @param employeeId + * @return + */ + public List getCanViewEmployeeId(Integer dataScopeType, Long employeeId) { + Integer viewType = this.getEmployeeDataScopeViewType(dataScopeType, employeeId); + if (DataScopeViewTypeEnum.ME.getType().equals(viewType)) { + return this.getMeEmployeeIdList(employeeId); + } + if (DataScopeViewTypeEnum.DEPARTMENT.getType().equals(viewType)) { + return this.getDepartmentEmployeeIdList(employeeId); + } + if (DataScopeViewTypeEnum.DEPARTMENT_AND_SUB.getType().equals(viewType)) { + return this.getDepartmentAndSubEmployeeIdList(employeeId); + } + return Lists.newArrayList(); + } + + public List getCanViewDepartmentId(Integer dataScopeType, Long employeeId) { + Integer viewType = this.getEmployeeDataScopeViewType(dataScopeType, employeeId); + if (DataScopeViewTypeEnum.ME.getType().equals(viewType)) { + return this.getMeDepartmentIdList(employeeId); + } + if (DataScopeViewTypeEnum.DEPARTMENT.getType().equals(viewType)) { + return this.getMeDepartmentIdList(employeeId); + } + if (DataScopeViewTypeEnum.DEPARTMENT_AND_SUB.getType().equals(viewType)) { + return this.getDepartmentAndSubIdList(employeeId); + } + return Lists.newArrayList(); + } + + private List getMeDepartmentIdList(Long employeeId) { + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + return Lists.newArrayList(employeeEntity.getDepartmentId()); + } + + private List getDepartmentAndSubIdList(Long employeeId) { + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + List allDepartmentIds = Lists.newArrayList(); + departmentTreeService.buildIdList(employeeEntity.getDepartmentId(), allDepartmentIds); + return allDepartmentIds; + } + + /** + * 根据员工id 获取各数据范围最大的可见范围 map + * + * @param employeeId + * @return + */ + private Integer getEmployeeDataScopeViewType(Integer dataScopeType, Long employeeId) { + if (employeeId == null) { + return DataScopeViewTypeEnum.ME.getType(); + } + + if (privilegeEmployeeService.isSuperman(employeeId)) { + return DataScopeViewTypeEnum.ALL.getType(); + } + List roleIdList = roleEmployeeDao.selectRoleIdByEmployeeId(employeeId); + //未设置角色 默认本人 + if (CollectionUtils.isEmpty(roleIdList)) { + return DataScopeViewTypeEnum.ME.getType(); + } + //未设置角色数据范围 默认本人 + List dataScopeRoleList = dataScopeRoleDao.listByRoleIdList(roleIdList); + if (CollectionUtils.isEmpty(dataScopeRoleList)) { + return DataScopeViewTypeEnum.ME.getType(); + } + Map> listMap = dataScopeRoleList.stream().collect(Collectors.groupingBy(DataScopeRoleEntity :: getDataScopeType)); + List viewLevelList = listMap.get(dataScopeType); + DataScopeRoleEntity maxLevel = viewLevelList.stream().max(Comparator.comparing(e -> DataScopeViewTypeEnum.valueOf(e.getViewType()).getLevel())).get(); + return maxLevel.getViewType(); + } + + /** + * 获取本人相关 可查看员工id + * + * @param employeeId + * @return + */ + private List getMeEmployeeIdList(Long employeeId) { + return Lists.newArrayList(employeeId); + } + /** + * 获取本部门相关 可查看员工id + * + * @param employeeId + * @return + */ + private List getDepartmentEmployeeIdList(Long employeeId) { + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + List employeeList = employeeDao.getEmployeeIdByDeptId(employeeEntity.getDepartmentId()); + List employeeIdList = employeeList.stream().map(e -> e.getId()).collect(Collectors.toList()); + return employeeIdList; + } + + /** + * 获取本部门及下属子部门相关 可查看员工id + * + * @param employeeId + * @return + */ + private List getDepartmentAndSubEmployeeIdList(Long employeeId) { + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + List allDepartmentIds = Lists.newArrayList(); + departmentTreeService.buildIdList(employeeEntity.getDepartmentId(), allDepartmentIds); + List employeeList = employeeDao.getEmployeeIdByDeptIds(allDepartmentIds); + List employeeIdList = employeeList.stream().map(e -> e.getId()).collect(Collectors.toList()); + return employeeIdList; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentController.java new file mode 100644 index 00000000..ffa65490 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentController.java @@ -0,0 +1,99 @@ +package com.gangquan360.smartadmin.module.department; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.department.domain.dto.DepartmentCreateDTO; +import com.gangquan360.smartadmin.module.department.domain.dto.DepartmentUpdateDTO; +import com.gangquan360.smartadmin.module.department.domain.dto.DepartmentVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * 部门管理路由器 + * + * @author listen + * @date 2017/12/19 14:29 + */ +@Api(tags = {SwaggerTagConst.Admin.MANAGER_DEPARTMENT}) +@OperateLog +@RestController +public class DepartmentController { + + @Autowired + private DepartmentService departmentService; + + @ApiOperation(value = "查询部门树形列表", notes = "查询部门列表") + @GetMapping("/department/list") + public ResponseDTO> listDepartment() { + return departmentService.listDepartment(); + } + + @ApiOperation(value = "查询部门及员工列表", notes = "查询部门及员工列表") + @GetMapping("/department/listEmployee") + public ResponseDTO> listDepartmentEmployee() { + return departmentService.listAllDepartmentEmployee(null); + } + + @ApiOperation(value = "根据部门名称查询部门及员工列表", notes = "根据部门名称查询部门及员工列表") + @GetMapping("/department/listEmployeeByDepartmentName") + public ResponseDTO> listDepartmentEmployee(String departmentName) { + return departmentService.listAllDepartmentEmployee(departmentName); + } + + @ApiOperation(value = "添加部门", notes = "添加部门") + @PostMapping("/department/add") + public ResponseDTO addDepartment(@Valid @RequestBody DepartmentCreateDTO departmentCreateDTO) { + return departmentService.addDepartment(departmentCreateDTO); + } + + @ApiOperation(value = "更新部门信息", notes = "更新部门信息") + @PostMapping("/department/update") + public ResponseDTO updateDepartment(@Valid @RequestBody DepartmentUpdateDTO departmentUpdateDTO) { + return departmentService.updateDepartment(departmentUpdateDTO); + } + + @ApiOperation(value = "删除部门", notes = "删除部门") + @PostMapping("/department/delete/{departmentId}") + public ResponseDTO delDepartment(@PathVariable("departmentId") Long departmentId) { + return departmentService.delDepartment(departmentId); + } + + @ApiOperation(value = "获取部门信息", notes = "获取部门") + @GetMapping("/department/query/{departmentId}") + public ResponseDTO getDepartment(@PathVariable("departmentId") Long departmentId) { + return departmentService.getDepartmentById(departmentId); + } + + @ApiOperation(value = "查询部门列表", notes = "查询部门列表") + @GetMapping("/department/listAll") + public ResponseDTO> listAll() { + return departmentService.listAll(); + } + + + @ApiOperation(value = "上下移动") + @GetMapping("/department/upOrDown/{departmentId}/{swapId}") + public ResponseDTO upOrDown(@PathVariable("departmentId") Long departmentId,@PathVariable("swapId") Long swapId) { + return departmentService.upOrDown(departmentId,swapId); + } + + @ApiOperation(value = "升级") + @GetMapping("/department/upgrade/{departmentId}") + public ResponseDTO upgrade(@PathVariable("departmentId") Long departmentId) { + return departmentService.upgrade(departmentId); + } + + @ApiOperation(value = "降级") + @GetMapping("/department/downgrade/{departmentId}/{preId}") + public ResponseDTO downgrade(@PathVariable("departmentId") Long departmentId,@PathVariable("preId") Long preId) { + return departmentService.downgrade(departmentId,preId); + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentDao.java new file mode 100644 index 00000000..5c3e3b65 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentDao.java @@ -0,0 +1,48 @@ +package com.gangquan360.smartadmin.module.department; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.gangquan360.smartadmin.module.department.domain.dto.DepartmentVO; +import com.gangquan360.smartadmin.module.department.domain.entity.DepartmentEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * t_department dao接口 + * + * @author listen + * @date 2017/12/19 10:58 + */ +@Component +@Mapper +public interface DepartmentDao extends BaseMapper { + + + /** + * 根据部门id,查询此部门子部门的数量 + * + * @param departmentId + * @return int 子部门的数量 + */ + Integer countSubDepartment(@Param("departmentId") Long departmentId); + + /** + * 获取全部部门列表 + * + * @return List + */ + List listAll(); + + /** + * 功能描述: 根据父部门id查询 + * + * @param + * @return + * @auther yandanyang + * @date 2018/8/25 0025 上午 9:46 + */ + List selectByParentId(@Param("departmentId") Long departmentId); + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentResponseCodeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentResponseCodeConst.java new file mode 100644 index 00000000..b84c2f5e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentResponseCodeConst.java @@ -0,0 +1,39 @@ +package com.gangquan360.smartadmin.module.department; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + +/** + * 部门返回信息常量类 + * 2001 - 2999 + * + * @author listen + * @date 2017/12/19 18:52 + */ +public class DepartmentResponseCodeConst extends ResponseCodeConst { + + /** + * 部门不存在 1001 + */ + public static final DepartmentResponseCodeConst DEPT_NOT_EXISTS = new DepartmentResponseCodeConst(2001, "部门不存在!"); + + /** + * 当前部门有子级部门 不能删除 10003 + */ + public static final DepartmentResponseCodeConst CANNOT_DEL_DEPARTMENT_WITH_CHILD = new + DepartmentResponseCodeConst(2002, "当前部门有子级部门,无法删除!"); + + /** + * 当前部门有员工 不能删除 10004 + */ + public static final DepartmentResponseCodeConst CANNOT_DEL_DEPARTMENT_WITH_EMPLOYEE = new + DepartmentResponseCodeConst(2003, "当前部门有员工,无法删除!"); + + /** + * + */ + public static final DepartmentResponseCodeConst PARENT_ID_ERROR = new DepartmentResponseCodeConst(2004, "上级部门id不能等于当前部门id"); + + public DepartmentResponseCodeConst(int code, String msg) { + super(code, msg); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentService.java new file mode 100644 index 00000000..aea9b092 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentService.java @@ -0,0 +1,282 @@ +package com.gangquan360.smartadmin.module.department; + +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.department.domain.dto.DepartmentCreateDTO; +import com.gangquan360.smartadmin.module.department.domain.dto.DepartmentUpdateDTO; +import com.gangquan360.smartadmin.module.department.domain.dto.DepartmentVO; +import com.gangquan360.smartadmin.module.department.domain.entity.DepartmentEntity; +import com.gangquan360.smartadmin.module.employee.EmployeeDao; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 部门管理业务类 + * + * @author listen + * @date 2017/12/19 14:25 + */ +@Service +public class DepartmentService { + + @Autowired + private DepartmentDao departmentDao; + + @Autowired + private EmployeeDao employeeDao; + + @Autowired + private DepartmentTreeService departmentTreeService; + + /** + * 获取部门树形结构 + * + * @return + */ + public ResponseDTO> listDepartment() { + List departmentVOList = departmentDao.listAll(); + List result = departmentTreeService.buildTree(departmentVOList); + return ResponseDTO.succData(result); + } + + /** + * 获取所有部门和员工信息 + * + * @param departmentName + * @return + */ + public ResponseDTO> listAllDepartmentEmployee(String departmentName) { + + // 获取全部部门列表 + List departmentVOList = departmentDao.listAll(); + if (StringUtils.isNotBlank(departmentName)) { + // 检索条件不为空的时候 过滤部门列表 + departmentVOList = filterDepartment(departmentVOList, departmentName); + } + + Map departmentMap = departmentVOList.stream().collect(Collectors.toMap(DepartmentVO :: getId, Function.identity())); + // 获取全部员工列表 + List employeeList = employeeDao.listAll(); + employeeList.forEach(employeeDTO -> { + + DepartmentVO departmentVO = departmentMap.get(employeeDTO.getDepartmentId()); + if (null == departmentVO) { + return; + } + List employeeDTOList = departmentVO.getEmployees(); + if (null == employeeDTOList) { + employeeDTOList = new ArrayList<>(); + } + employeeDTOList.add(employeeDTO); + departmentVO.setEmployees(employeeDTOList); + }); + List result = departmentTreeService.buildTree(departmentVOList); + return ResponseDTO.succData(result); + } + + /** + * 过滤部门名称,获取过滤后的结果 + * + * @author lidoudou + * @date 2019/4/28 20:17 + */ + private List filterDepartment(List departmentVOList, String departmentName) { + Map departmentMap = new HashMap<>(); + departmentVOList.forEach(item -> { + if (item.getName().indexOf(departmentName) < 0) { + return; + } + // 当前部门包含关键字 + departmentMap.put(item.getId(), item); + Long parentId = item.getParentId(); + if (null != parentId) { + List filterResult = new ArrayList<>(); + getParentDepartment(departmentVOList, parentId, filterResult); + for (DepartmentVO dto : filterResult) { + if (! departmentMap.containsKey(dto.getId())) { + departmentMap.put(dto.getId(), dto); + } + } + } + }); + return departmentMap.values().stream().collect(Collectors.toList()); + } + + private List getParentDepartment(List departmentVOList, Long parentId, List result) { + List deptList = departmentVOList.stream().filter(e -> e.getId().equals(parentId)).collect(Collectors.toList()); + for (DepartmentVO item : deptList) { + result.add(item); + if (item.getParentId() != 0 && item.getParentId() != null) { + result.addAll(getParentDepartment(departmentVOList, item.getParentId(), result)); + } + } + return result; + } + + /** + * 新增添加部门 + * + * @param departmentCreateDTO + * @return AjaxResult + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO addDepartment(DepartmentCreateDTO departmentCreateDTO) { + DepartmentEntity departmentEntity = SmartBeanUtil.copy(departmentCreateDTO, DepartmentEntity.class); + departmentEntity.setSort(0L); + departmentDao.insert(departmentEntity); + departmentEntity.setSort(departmentEntity.getId()); + departmentDao.updateById(departmentEntity); + return ResponseDTO.succ(); + } + + /** + * 更新部门信息 + * + * @param updateDTO + * @return AjaxResult + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO updateDepartment(DepartmentUpdateDTO updateDTO) { + if (updateDTO.getParentId() == null) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.PARENT_ID_ERROR); + } + DepartmentEntity entity = departmentDao.selectById(updateDTO.getId()); + if (entity == null) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS); + } + DepartmentEntity departmentEntity = SmartBeanUtil.copy(updateDTO, DepartmentEntity.class); + departmentEntity.setSort(entity.getSort()); + departmentDao.updateById(departmentEntity); + return ResponseDTO.succ(); + } + + /** + * 根据id删除部门 + * 1、需要判断当前部门是否有子部门,有子部门则不允许删除 + * 2、需要判断当前部门是否有员工,有员工则不能删除 + * + * @param departmentId + * @return AjaxResult + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delDepartment(Long departmentId) { + // 是否有子级部门 + int subDepartmentNum = departmentDao.countSubDepartment(departmentId); + if (subDepartmentNum > 0) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.CANNOT_DEL_DEPARTMENT_WITH_CHILD); + } + + // 是否有员工 + int employeeNum = employeeDao.countByDepartmentId(departmentId); + if (employeeNum > 0) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.CANNOT_DEL_DEPARTMENT_WITH_EMPLOYEE); + } + departmentDao.deleteById(departmentId); + return ResponseDTO.succ(); + } + + /** + * 根据id获取部门信息 + * + * @param departmentId + * @return AjaxResult + */ + public ResponseDTO getDepartmentById(Long departmentId) { + DepartmentEntity departmentEntity = departmentDao.selectById(departmentId); + if (departmentEntity == null) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.DEPT_NOT_EXISTS); + } + DepartmentVO departmentVO = SmartBeanUtil.copy(departmentEntity, DepartmentVO.class); + return ResponseDTO.succData(departmentVO); + } + + /** + * 获取所有部门 + * + * @return + */ + public ResponseDTO> listAll() { + List departmentVOList = departmentDao.listAll(); + return ResponseDTO.succData(departmentVOList); + } + + /** + * 上下移动 + * + * @param departmentId + * @param swapId + * @return + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO upOrDown(Long departmentId, Long swapId) { + DepartmentEntity departmentEntity = departmentDao.selectById(departmentId); + if (departmentEntity == null) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS); + } + DepartmentEntity swapEntity = departmentDao.selectById(swapId); + if (swapEntity == null) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS); + } + Long departmentSort = departmentEntity.getSort(); + departmentEntity.setSort(swapEntity.getSort()); + departmentDao.updateById(departmentEntity); + swapEntity.setSort(departmentSort); + departmentDao.updateById(swapEntity); + return ResponseDTO.succ(); + } + + /** + * 部门升级 + * + * @param departmentId + * @return + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO upgrade(Long departmentId) { + DepartmentEntity departmentEntity = departmentDao.selectById(departmentId); + if (departmentEntity == null) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS); + } + if (departmentEntity.getParentId() == null || departmentEntity.getParentId().equals(0)) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.ERROR_PARAM, "此部门已经是根节点无法移动"); + } + DepartmentEntity parentEntity = departmentDao.selectById(departmentEntity.getParentId()); + + departmentEntity.setParentId(parentEntity.getParentId()); + departmentDao.updateById(departmentEntity); + return ResponseDTO.succ(); + } + + /** + * 部门降级 + * + * @param departmentId + * @param preId + * @return + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO downgrade(Long departmentId, Long preId) { + DepartmentEntity departmentEntity = departmentDao.selectById(departmentId); + if (departmentEntity == null) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS); + } + DepartmentEntity preEntity = departmentDao.selectById(preId); + if (preEntity == null) { + return ResponseDTO.wrap(DepartmentResponseCodeConst.NOT_EXISTS); + } + departmentEntity.setParentId(preEntity.getId()); + departmentDao.updateById(departmentEntity); + return ResponseDTO.succ(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentTreeService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentTreeService.java new file mode 100644 index 00000000..034fcde9 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/DepartmentTreeService.java @@ -0,0 +1,99 @@ +package com.gangquan360.smartadmin.module.department; + +import com.gangquan360.smartadmin.module.department.domain.dto.DepartmentVO; +import com.google.common.collect.Lists; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/29 0029 下午 13:52 + * @since JDK1.8 + */ +@Service +public class DepartmentTreeService { + + @Autowired + private DepartmentDao departmentDao; + + /** + * 构建部门树结构 + * @param departmentVOList + * @return + */ + public List buildTree(List departmentVOList) { + if(CollectionUtils.isEmpty(departmentVOList)){ + return Lists.newArrayList(); + } + List list = departmentVOList.stream().filter(e -> e.getParentId() == null || e.getParentId() == 0).collect(Collectors.toList()); + if(CollectionUtils.isEmpty(list)){ + return Lists.newArrayList(); + } + this.buildTree(list,departmentVOList); + return list; + } + + private void buildTree(List nodeList,List departmentVOList){ + int nodeSize = nodeList.size(); + for(int i =0 ;i< nodeSize;i++){ + int preIndex = i-1; + int nextIndex = i+1; + DepartmentVO node = nodeList.get(i); + if(preIndex>-1){ + node.setPreId(nodeList.get(preIndex).getId()); + } + if(nextIndex departmentVOList) { + List children = getChildren(node, departmentVOList); + if (CollectionUtils.isNotEmpty(children)) { + node.setChildrenDepartment(children); + this.buildTree(children,departmentVOList); + } + } + + private List getChildren(DepartmentVO node, List departmentVOList) { + Long id = node.getId(); + return departmentVOList.stream().filter(e -> id.equals(e.getParentId())).collect(Collectors.toList()); + } + + + + /** + * 通过部门id,获取当前以及下属部门 + */ + public void buildIdList(Long deptId, List result) { + List departmentVOList = departmentDao.listAll(); + result.add(deptId); + if (null == deptId) { + result.addAll(departmentVOList.stream().map(DepartmentVO::getId).collect(Collectors.toList())); + return; + } + List children = getChildrenIdList(deptId, departmentVOList); + if (!children.isEmpty()) { + result.addAll(children.stream().map(DepartmentVO::getId).collect(Collectors.toList())); + for (DepartmentVO child : children) { + buildTree(child, departmentVOList); + } + } + } + + private List getChildrenIdList(Long deptId, List departmentVOList) { + return departmentVOList.stream().filter(e -> deptId.equals(e.getParentId())).collect(Collectors.toList()); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentCreateDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentCreateDTO.java new file mode 100644 index 00000000..58174a5b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentCreateDTO.java @@ -0,0 +1,38 @@ +package com.gangquan360.smartadmin.module.department.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotNull; + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +public class DepartmentCreateDTO { + + + @ApiModelProperty("部门名称") + @Length(min = 1, max = 50, message = "请输入正确的部门名称(1-50个字符)") + @NotNull(message = "请输入正确的部门名称(1-50个字符)") + private String name; + + @ApiModelProperty("部门简称") + private String shortName; + + @ApiModelProperty("部门负责人id") + private Long managerId; + + @ApiModelProperty("上级部门id (可选)") + private Long parentId; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentUpdateDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentUpdateDTO.java new file mode 100644 index 00000000..2f3278a4 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentUpdateDTO.java @@ -0,0 +1,25 @@ +package com.gangquan360.smartadmin.module.department.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Data +public class DepartmentUpdateDTO extends DepartmentCreateDTO { + + @ApiModelProperty("部门id") + @NotNull(message = "部门id不能为空") + private Long id; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentVO.java new file mode 100644 index 00000000..a76b3b73 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/dto/DepartmentVO.java @@ -0,0 +1,58 @@ +package com.gangquan360.smartadmin.module.department.domain.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +@Data +public class DepartmentVO { + + @ApiModelProperty("部门id") + private Long id; + + @ApiModelProperty("部门名称") + private String name; + + @ApiModelProperty("部门简称") + private String shortName; + + @ApiModelProperty("部门负责人姓名") + private String managerName; + + @ApiModelProperty("部门负责人id") + private Long managerId; + + @ApiModelProperty("子部门") + @JsonProperty("children") + private List childrenDepartment; + + @ApiModelProperty("父级部门id") + private Long parentId; + + @ApiModelProperty("同级上一个元素id") + private Long preId; + + @ApiModelProperty("同级下一个元素id") + private Long nextId; + + @ApiModelProperty("排序") + private Long sort; + + @ApiModelProperty("父级部门名称") + private String parentName; + + @ApiModelProperty("部门员工列表") + private List employees; + + @ApiModelProperty("上次更新时间") + private Date updateTime; + + @ApiModelProperty("创建时间") + private Date createTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/entity/DepartmentEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/entity/DepartmentEntity.java new file mode 100644 index 00000000..f24cd594 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/department/domain/entity/DepartmentEntity.java @@ -0,0 +1,48 @@ +package com.gangquan360.smartadmin.module.department.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +import java.io.Serializable; + +/** + * 部门实体类 + * t_department 数据表 + * + * @author listen + * @date 2017/12/19 10:45 + */ +@Data +@TableName(value = "t_department") +public class DepartmentEntity extends BaseEntity implements Serializable { + + private static final long serialVersionUID = -6787726615141147044L; + + /** + * 部门名称 + */ + private String name; + + /** + * 部门简称 + */ + private String shortName; + + /** + * 负责人员工 id + */ + private Long managerId; + + /** + * 部门父级id + */ + private Long parentId; + + /** + * 排序 + */ + private Long sort; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailController.java new file mode 100644 index 00000000..a04aff8d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailController.java @@ -0,0 +1,80 @@ +package com.gangquan360.smartadmin.module.email; + +import com.gangquan360.smartadmin.common.anno.NoValidPrivilege; +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.email.domain.dto.EmailDTO; +import com.gangquan360.smartadmin.module.email.domain.dto.EmailQueryDTO; +import com.gangquan360.smartadmin.module.email.domain.dto.EmailVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-05-13 17:10:16 + * @since JDK1.8 + */ +@RestController +@OperateLog +@Api(tags = {SwaggerTagConst.Admin.MANAGER_EMAIL}) +public class EmailController { + + @Autowired + private EmailService emailService; + + @ApiOperation(value = "分页查询",notes = "@author yandanyang") + @PostMapping("/email/page/query") + @NoValidPrivilege + public ResponseDTO> queryByPage(@RequestBody EmailQueryDTO queryDTO) { + return emailService.queryByPage(queryDTO); + } + + @ApiOperation(value = "添加",notes = "@author yandanyang") + @PostMapping("/email/add") + @NoValidPrivilege + public ResponseDTO add(@RequestBody @Valid EmailDTO addTO){ + return emailService.add(addTO); + } + + @ApiOperation(value="修改",notes = "@author yandanyang") + @PostMapping("/email/update") + @NoValidPrivilege + public ResponseDTO update(@RequestBody @Valid EmailDTO updateDTO){ + return emailService.update(updateDTO); + } + + + @ApiOperation(value="删除",notes = "@author yandanyang") + @GetMapping("/email/delete/{id}") + @NoValidPrivilege + public ResponseDTO delete(@PathVariable("id") Long id){ + return emailService.delete(id); + } + + + @ApiOperation(value="详情",notes = "@author yandanyang") + @GetMapping("/email/detail/{id}") + @NoValidPrivilege + public ResponseDTO detail(@PathVariable("id") Long id){ + return emailService.detail(id); + } + + + @ApiOperation(value="发送",notes = "@author yandanyang") + @GetMapping("/email/send/{id}") + @NoValidPrivilege + public ResponseDTO send(@PathVariable("id") Long id){ + return emailService.send(id); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailDao.java new file mode 100644 index 00000000..e7fd5e76 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailDao.java @@ -0,0 +1,47 @@ +package com.gangquan360.smartadmin.module.email; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.pagination.Pagination; +import com.gangquan360.smartadmin.module.email.domain.dto.EmailQueryDTO; +import com.gangquan360.smartadmin.module.email.domain.entity.EmailEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-05-13 17:10:16 + * @since JDK1.8 + */ +@Mapper +@Component +public interface EmailDao extends BaseMapper { + + /** + * 分页查询 + * @param queryDTO + * @return EmailEntity + */ + List queryByPage(Pagination page, @Param("queryDTO") EmailQueryDTO queryDTO); + + /** + * 根据id删除 + * @param id + * @return + */ + void deleteById(@Param("id") Long id); + + /** + * 批量删除 + * @param idList + * @return + */ + void deleteByIds(@Param("idList") List idList); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailSendStatusEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailSendStatusEnum.java new file mode 100644 index 00000000..ba8e6e85 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailSendStatusEnum.java @@ -0,0 +1,37 @@ +package com.gangquan360.smartadmin.module.email; + + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/28 0028 下午 15:37 + * @since JDK1.8 + */ +public enum EmailSendStatusEnum { + + NOT_SEND(0,"未发送"), + + SEND(1,"已发送"); + + private Integer type; + private String desc; + + EmailSendStatusEnum(Integer type, String desc) { + this.type = type; + this.desc = desc; + } + + public Integer getType() { + return type; + } + + public String getDesc() { + return desc; + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailService.java new file mode 100644 index 00000000..483490c1 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/EmailService.java @@ -0,0 +1,122 @@ +package com.gangquan360.smartadmin.module.email; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.email.domain.dto.EmailConfigDTO; +import com.gangquan360.smartadmin.module.email.domain.dto.EmailDTO; +import com.gangquan360.smartadmin.module.email.domain.dto.EmailQueryDTO; +import com.gangquan360.smartadmin.module.email.domain.dto.EmailVO; +import com.gangquan360.smartadmin.module.email.domain.entity.EmailEntity; +import com.gangquan360.smartadmin.module.systemconfig.SystemConfigService; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigEnum; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import com.gangquan360.smartadmin.util.SmartSendMailUtil; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-05-13 17:10:16 + * @since JDK1.8 + */ +@Service +public class EmailService { + + @Autowired + private EmailDao emailDao; + + @Autowired + private SystemConfigService systemConfigService; + + /** + * @author yandanyang + * @description 分页查询 + * @date 2019-05-13 17:10:16 + */ + public ResponseDTO> queryByPage(EmailQueryDTO queryDTO) { + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List entities = emailDao.queryByPage(page, queryDTO); + List dtoList = SmartBeanUtil.copyList(entities, EmailVO.class); + page.setRecords(dtoList); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * @author yandanyang + * @description 添加 + * @date 2019-05-13 17:10:16 + */ + public ResponseDTO add(EmailDTO addDTO) { + EmailEntity entity = SmartBeanUtil.copy(addDTO, EmailEntity.class); + emailDao.insert(entity); + return ResponseDTO.succData(entity.getId()); + } + + /** + * @author yandanyang + * @description 编辑 + * @date 2019-05-13 17:10:16 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(EmailDTO updateDTO) { + EmailEntity entity = SmartBeanUtil.copy(updateDTO, EmailEntity.class); + emailDao.updateById(entity); + return ResponseDTO.succData(entity.getId()); + } + + /** + * @author yandanyang + * @description 删除 + * @date 2019-05-13 17:10:16 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long id) { + emailDao.deleteById(id); + return ResponseDTO.succ(); + } + + /** + * @author yandanyang + * @description 根据ID查询 + * @date 2019-05-13 17:10:16 + */ + public ResponseDTO detail(Long id) { + EmailEntity entity = emailDao.selectById(id); + EmailVO dto = SmartBeanUtil.copy(entity, EmailVO.class); + return ResponseDTO.succData(dto); + } + + /** + * 发送某个已创建的邮件 + * + * @param id + * @return + */ + public ResponseDTO send(Long id) { + EmailEntity entity = emailDao.selectById(id); + EmailConfigDTO emailConfig = systemConfigService.selectByKey2Obj(SystemConfigEnum.Key.EMAIL_CONFIG.name(), EmailConfigDTO.class); + String toEmails = entity.getToEmails(); + if (StringUtils.isEmpty(toEmails)) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "收件人信息为空"); + } + String[] emails = toEmails.split(";"); + SmartSendMailUtil.sendMail(emailConfig.getUsername(), emailConfig.getPassword(), emailConfig.getUsername(), emails, "", emailConfig.getSmtpHost(), entity.getTitle(), entity.getContent()); + entity.setSendStatus(EmailSendStatusEnum.SEND.getType()); + emailDao.updateById(entity); + return ResponseDTO.succ(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailConfigDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailConfigDTO.java new file mode 100644 index 00000000..84974033 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailConfigDTO.java @@ -0,0 +1,30 @@ +package com.gangquan360.smartadmin.module.email.domain.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/13 0013 下午 16:52 + * @since JDK1.8 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EmailConfigDTO { + + private String smtpHost; + + private String username; + + private String password; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailDTO.java new file mode 100644 index 00000000..86b23076 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailDTO.java @@ -0,0 +1,44 @@ +package com.gangquan360.smartadmin.module.email.domain.dto; +import lombok.Data; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 12:27 + * @since JDK1.8 + */ +@Data +public class EmailDTO { + + @ApiModelProperty("主键") + private Long id; + + @ApiModelProperty("标题") + private String title; + + @ApiModelProperty("收件人") + private String toEmails; + + @ApiModelProperty("发送状态 0未发送 1已发送") + private Integer sendStatus; + + @ApiModelProperty("邮件内容") + private String content; + + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + @ApiModelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailQueryDTO.java new file mode 100644 index 00000000..4aea64bc --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailQueryDTO.java @@ -0,0 +1,35 @@ +package com.gangquan360.smartadmin.module.email.domain.dto; + +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-05-13 17:10:16 + * @since JDK1.8 + */ +@Data +public class EmailQueryDTO extends PageParamDTO { + + + @ApiModelProperty("开始日期") + private String startDate; + + @ApiModelProperty("结束日期") + private String endDate; + + + @ApiModelProperty("标题") + private String title; + + + @ApiModelProperty("发送状态 0未发送 1已发送") + private Integer sendStatus; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailVO.java new file mode 100644 index 00000000..29545058 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/dto/EmailVO.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.module.email.domain.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 12:27 + * @since JDK1.8 + */ +@Data +public class EmailVO { + + @ApiModelProperty("主键") + private Long id; + + @ApiModelProperty("标题") + private String title; + + @ApiModelProperty("收件人") + private String toEmails; + + @ApiModelProperty("发送状态 0未发送 1已发送") + private Integer sendStatus; + + @ApiModelProperty("邮件内容") + private String content; + + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + @ApiModelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/entity/EmailEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/entity/EmailEntity.java new file mode 100644 index 00000000..92951595 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/email/domain/entity/EmailEntity.java @@ -0,0 +1,40 @@ +package com.gangquan360.smartadmin.module.email.domain.entity; +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-05-13 17:10:16 + * @since JDK1.8 + */ +@Data +@TableName("t_email") +public class EmailEntity extends BaseEntity { + + /** + * 标题 + */ + private String title; + + /** + * 收件人 + */ + private String toEmails; + + /** + * 发送状态 0未发送 1已发送 + */ + private Integer sendStatus; + + /** + * 邮件内容 + */ + private String content; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeController.java new file mode 100644 index 00000000..18af9fd8 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeController.java @@ -0,0 +1,95 @@ +package com.gangquan360.smartadmin.module.employee; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.employee.domain.dto.*; +import com.gangquan360.smartadmin.module.employee.domain.vo.EmployeeVO; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.util.SmartRequestTokenUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * 员工管理 + * + * @author lidoudou + * @date 2017年12月19日上午11:34:52 + */ +@RestController +@Api(tags = {SwaggerTagConst.Admin.MANAGER_USER}) +@OperateLog +public class EmployeeController { + + @Autowired + private EmployeeService employeeService; + + @PostMapping("/employee/query") + @ApiOperation(value = "员工管理查询", notes = "员工管理查询 @author lidoudou") + public ResponseDTO> query(@RequestBody EmployeeQueryDTO query) { + return employeeService.selectEmployeeList(query); + } + + @ApiOperation(value = "添加员工", notes = "@author yandanyang") + @PostMapping("/employee/add") + public ResponseDTO addEmployee(@Valid @RequestBody EmployeeAddDTO emp) { + RequestTokenBO requestToken = SmartRequestTokenUtil.getRequestUser(); + return employeeService.addEmployee(emp, requestToken); + } + + @ApiOperation(value = "禁用单个员工", notes = "@author yandanyang") + @GetMapping("/employee/updateStatus/{employeeId}/{status}") + public ResponseDTO updateStatus(@PathVariable("employeeId") Long employeeId, @PathVariable("status") Integer status) { + return employeeService.updateStatus(employeeId, status); + } + + @ApiOperation(value = "批量禁用", notes = "@author yandanyang") + @PostMapping("/employee/batchUpdateStatus") + public ResponseDTO batchUpdateStatus(@Valid @RequestBody EmployeeBatchUpdateStatusDTO batchUpdateStatusDTO) { + return employeeService.batchUpdateStatus(batchUpdateStatusDTO); + } + + @ApiOperation(value = "更新员工信息", notes = "@author yandanyang") + @PostMapping("/employee/update") + public ResponseDTO updateEmployee(@Valid @RequestBody EmployeeUpdateDTO employeeUpdateDto) { + return employeeService.updateEmployee(employeeUpdateDto); + } + + @ApiOperation(value = "删除员工信息", notes = "@author yandanyang") + @PostMapping("/employee/delete/{employeeId}") + public ResponseDTO deleteEmployeeById(@PathVariable("employeeId") Long employeeId) { + return employeeService.deleteEmployeeById(employeeId); + } + + @ApiOperation(value = "单个员工角色授权", notes = "@author yandanyang") + @PostMapping("/employee/updateRoles") + public ResponseDTO updateRoles(@Valid @RequestBody EmployeeUpdateRolesDTO updateRolesDTO) { + return employeeService.updateRoles(updateRolesDTO); + } + + @ApiOperation(value = "修改密码", notes = "@author yandanyang") + @PostMapping("/employee/updatePwd") + public ResponseDTO updatePwd(@Valid @RequestBody EmployeeUpdatePwdDTO updatePwdDTO) { + RequestTokenBO requestToken = SmartRequestTokenUtil.getRequestUser(); + return employeeService.updatePwd(updatePwdDTO, requestToken); + } + + @ApiOperation(value = "通过部门id获取当前部门的人员&没有部门的人", notes = "@author yandanyang") + @GetMapping("/employee/listEmployeeByDeptId/{deptId}") + public ResponseDTO> listEmployeeByDeptId(@PathVariable Long deptId) { + return employeeService.getEmployeeByDeptId(deptId); + } + + @ApiOperation(value = "员工重置密码", notes = "@author lizongliang") + @GetMapping("/employee/resetPasswd/{employeeId}") + public ResponseDTO resetPasswd(@PathVariable("employeeId") Integer employeeId) { + return employeeService.resetPasswd(employeeId); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeDao.java new file mode 100644 index 00000000..7191f1b1 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeDao.java @@ -0,0 +1,129 @@ +package com.gangquan360.smartadmin.module.employee; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeQueryDTO; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeQueryExportDTO; +import com.gangquan360.smartadmin.module.employee.domain.entity.EmployeeEntity; +import com.gangquan360.smartadmin.module.employee.domain.vo.EmployeeVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; + +/** + * 员工dao接口 + * + * @author lidoudou + * @date 2017年12月19日下午1:36:30 + */ +@Mapper +@Component +public interface EmployeeDao extends BaseMapper { + /** + * 查询员工列表 + * + * @param page + * @param queryDTO + * @return + */ + List selectEmployeeList(Page page, @Param("queryDTO") EmployeeQueryDTO queryDTO); + + /** + * 不带分页查询员工列表 + * @param queryDTO + * @return + */ + List selectEmployeeList(@Param("queryDTO") EmployeeQueryExportDTO queryDTO); + + /** + * 批量更新禁用状态 + * + * @param employeeIds + * @param isDisabled + */ + void batchUpdateStatus(@Param("employeeIds") List employeeIds, @Param("isDisabled") Integer isDisabled); + + /** + * 登录 + * + * @param loginName + * @param loginPwd + * @return + */ + EmployeeDTO login(@Param("loginName") String loginName, @Param("loginPwd") String loginPwd); + + /** + * 通过登录名查询 + * + * @param loginName + * @param isDisabled + * @return + */ + EmployeeDTO getByLoginName(@Param("loginName") String loginName, @Param("isDisabled") Integer isDisabled); + + /** + * 通过手机号查询 + * + * @param phone + * @param isDisabled + * @return + */ + EmployeeDTO getByPhone(@Param("phone") String phone, @Param("isDisabled") Integer isDisabled); + + /** + * 获取所有员工 + * + * @return + */ + List listAll(); + + /** + * 获取某个部门员工数 + * + * @param departmentId + * @return + */ + Integer countByDepartmentId(@Param("departmentId") Long departmentId); + + /** + * 获取一批员工 + * + * @param employeeIds + * @return + */ + List getEmployeeByIds(@Param("ids") Collection employeeIds); + + + EmployeeDTO getEmployeeById(@Param("id") Long employeeId); + /** + * 获取某个部门的员工 + * + * @param departmentId + * @return + */ + List getEmployeeIdByDeptId(@Param("departmentId") Long departmentId); + + /** + * 获取某批部门的员工 + * + * @param departmentIds + * @return + */ + List getEmployeeIdByDeptIds(@Param("departmentIds") List departmentIds); + + + /** + * 员工重置密码 + * + * @param employeeId + * @param password + * @return + */ + Integer updatePassword(@Param("employeeId") Integer employeeId, @Param("password") String password); + + +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeService.java new file mode 100644 index 00000000..34c0cf30 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/EmployeeService.java @@ -0,0 +1,342 @@ +package com.gangquan360.smartadmin.module.employee; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.CommonConst; +import com.gangquan360.smartadmin.module.department.DepartmentDao; +import com.gangquan360.smartadmin.module.department.domain.entity.DepartmentEntity; +import com.gangquan360.smartadmin.module.employee.constant.EmployeeResponseCodeConst; +import com.gangquan360.smartadmin.module.employee.constant.EmployeeStatusEnum; +import com.gangquan360.smartadmin.module.employee.domain.bo.EmployeeBO; +import com.gangquan360.smartadmin.module.employee.domain.dto.*; +import com.gangquan360.smartadmin.module.employee.domain.entity.EmployeeEntity; +import com.gangquan360.smartadmin.module.employee.domain.vo.EmployeeVO; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.module.position.PositionService; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionRelationAddDTO; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionRelationResultDTO; +import com.gangquan360.smartadmin.module.privilege.service.PrivilegeEmployeeService; +import com.gangquan360.smartadmin.module.role.roleemployee.RoleEmployeeDao; +import com.gangquan360.smartadmin.module.role.roleemployee.domain.RoleEmployeeEntity; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartDigestUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import com.gangquan360.smartadmin.util.SmartVerificationUtil; +import com.google.common.collect.Lists; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Date; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * 员工管理 + * + * @author lidoudou + * @date 2017年12月21日上午11:54:52 + */ +@Service +public class EmployeeService { + + private static final String RESET_PASSWORD = "123456"; + + @Autowired + private EmployeeDao employeeDao; + + @Autowired + private DepartmentDao departmentDao; + + @Autowired + private RoleEmployeeDao roleEmployeeDao; + + @Autowired + private PositionService positionService; + + @Autowired + private PrivilegeEmployeeService privilegeEmployeeService; + + /** + * 员工基本信息的缓存 + */ + private static final ConcurrentHashMap employeeCache = new ConcurrentHashMap<>(); + + + public EmployeeBO getById(Long id) { + EmployeeBO employeeBO = employeeCache.get(id); + if (employeeBO == null) { + EmployeeEntity employeeEntity = employeeDao.selectById(id); + if (employeeEntity != null) { + Boolean superman = privilegeEmployeeService.isSuperman(id); + employeeBO = new EmployeeBO(employeeEntity, superman); + employeeCache.put(employeeEntity.getId(), employeeBO); + } + } + return employeeBO; + } + + /** + * 查询员工列表 + * + * @param queryDTO + * @return + */ + public ResponseDTO> selectEmployeeList(EmployeeQueryDTO queryDTO) { + Page pageParam = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + queryDTO.setIsDelete(JudgeEnum.NO.getValue()); + List empList = employeeDao.selectEmployeeList(pageParam, queryDTO); + empList.stream().forEach(e -> { + List positionRelationList = positionService.queryPositionByEmployeeId(e.getId()); + if (CollectionUtils.isNotEmpty(positionRelationList)) { + e.setPositionRelationList(positionRelationList); + e.setPositionName(positionRelationList.stream().map(PositionRelationResultDTO::getPositionName).collect(Collectors.joining(","))); + } + }); + return ResponseDTO.succData(SmartPaginationUtil.convert2PageInfoDTO(pageParam, empList, EmployeeVO.class)); + } + + /** + * 新增员工 + * + * @param employeeAddDto + * @param requestToken + * @return + */ + public ResponseDTO addEmployee(EmployeeAddDTO employeeAddDto, RequestTokenBO requestToken) { + EmployeeEntity entity = SmartBeanUtil.copy(employeeAddDto, EmployeeEntity.class); + if (StringUtils.isNotEmpty(employeeAddDto.getIdCard())) { + boolean checkResult = Pattern.matches(SmartVerificationUtil.ID_CARD, employeeAddDto.getIdCard()); + if (!checkResult) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.ID_CARD_ERROR); + } + } + if (StringUtils.isNotEmpty(employeeAddDto.getBirthday())) { + boolean checkResult = Pattern.matches(SmartVerificationUtil.DATE, employeeAddDto.getBirthday()); + if (!checkResult) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.BIRTHDAY_ERROR); + } + } + //同名员工 + EmployeeDTO sameNameEmployee = employeeDao.getByLoginName(entity.getLoginName(), EmployeeStatusEnum.NORMAL.getValue()); + if (null != sameNameEmployee) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.LOGIN_NAME_EXISTS); + } + //同电话员工 + EmployeeDTO samePhoneEmployee = employeeDao.getByPhone(entity.getLoginName(), EmployeeStatusEnum.NORMAL.getValue()); + if (null != samePhoneEmployee) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.PHONE_EXISTS); + } + Long departmentId = entity.getDepartmentId(); + DepartmentEntity department = departmentDao.selectById(departmentId); + if (department == null) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.DEPT_NOT_EXIST); + } + + //如果没有密码 默认设置为123456 + String pwd = entity.getLoginPwd(); + if (StringUtils.isBlank(pwd)) { + entity.setLoginPwd(SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, RESET_PASSWORD)); + } else { + entity.setLoginPwd(SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, entity.getLoginPwd())); + } + + entity.setCreateUser(requestToken.getRequestUserId()); + if (StringUtils.isEmpty(entity.getBirthday())) { + entity.setBirthday(null); + } + employeeDao.insert(entity); + + PositionRelationAddDTO positionRelAddDTO = new PositionRelationAddDTO(employeeAddDto.getPositionIdList(), entity.getId()); + //存储所选岗位信息 + positionService.addPositionRelation(positionRelAddDTO); + + return ResponseDTO.succ(); + } + + /** + * 更新禁用状态 + * + * @param employeeId + * @param status + * @return + */ + public ResponseDTO updateStatus(Long employeeId, Integer status) { + if (null == employeeId) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.EMP_NOT_EXISTS); + } + EmployeeBO entity = getById(employeeId); + if (null == entity) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.EMP_NOT_EXISTS); + } + List empIds = Lists.newArrayList(); + empIds.add(employeeId); + employeeDao.batchUpdateStatus(empIds, status); + employeeCache.remove(employeeId); + return ResponseDTO.succ(); + } + + /** + * 批量更新员工状态 + * + * @param batchUpdateStatusDTO + * @return + */ + public ResponseDTO batchUpdateStatus(EmployeeBatchUpdateStatusDTO batchUpdateStatusDTO) { + employeeDao.batchUpdateStatus(batchUpdateStatusDTO.getEmployeeIds(), batchUpdateStatusDTO.getStatus()); + if (batchUpdateStatusDTO.getEmployeeIds() != null) { + batchUpdateStatusDTO.getEmployeeIds().forEach(e -> employeeCache.remove(e)); + } + return ResponseDTO.succ(); + } + + /** + * 更新员工 + * + * @param updateDTO + * @return + */ + public ResponseDTO updateEmployee(EmployeeUpdateDTO updateDTO) { + Long employeeId = updateDTO.getId(); + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + if (null == employeeEntity) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.EMP_NOT_EXISTS); + } + if (StringUtils.isNotBlank(updateDTO.getIdCard())) { + boolean checkResult = Pattern.matches(SmartVerificationUtil.ID_CARD, updateDTO.getIdCard()); + if (!checkResult) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.ID_CARD_ERROR); + } + } + if (StringUtils.isNotEmpty(updateDTO.getBirthday())) { + boolean checkResult = Pattern.matches(SmartVerificationUtil.DATE, updateDTO.getBirthday()); + if (!checkResult) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.BIRTHDAY_ERROR); + } + } + Long departmentId = updateDTO.getDepartmentId(); + DepartmentEntity departmentEntity = departmentDao.selectById(departmentId); + if (departmentEntity == null) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.DEPT_NOT_EXIST); + } + EmployeeDTO sameNameEmployee = employeeDao.getByLoginName(updateDTO.getLoginName(), EmployeeStatusEnum.NORMAL.getValue()); + if (null != sameNameEmployee && !sameNameEmployee.getId().equals(employeeId)) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.LOGIN_NAME_EXISTS); + } + EmployeeDTO samePhoneEmployee = employeeDao.getByPhone(updateDTO.getLoginName(), EmployeeStatusEnum.NORMAL.getValue()); + if (null != samePhoneEmployee && !samePhoneEmployee.getId().equals(employeeId)) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.PHONE_EXISTS); + } + String newPwd = updateDTO.getLoginPwd(); + if (!StringUtils.isBlank(newPwd)) { + updateDTO.setLoginPwd(SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, updateDTO.getLoginPwd())); + } else { + updateDTO.setLoginPwd(employeeEntity.getLoginPwd()); + } + EmployeeEntity entity = SmartBeanUtil.copy(updateDTO, EmployeeEntity.class); + entity.setUpdateTime(new Date()); + if (StringUtils.isEmpty(entity.getBirthday())) { + entity.setBirthday(null); + } + if (CollectionUtils.isNotEmpty(updateDTO.getPositionIdList())) { + //删除旧的关联关系 添加新的关联关系 + positionService.removePositionRelation(entity.getId()); + PositionRelationAddDTO positionRelAddDTO = new PositionRelationAddDTO(updateDTO.getPositionIdList(), entity.getId()); + positionService.addPositionRelation(positionRelAddDTO); + } + entity.setIsDisabled(employeeEntity.getIsDisabled()); + entity.setIsLeave(employeeEntity.getIsLeave()); + entity.setCreateUser(employeeEntity.getCreateUser()); + entity.setCreateTime(employeeEntity.getCreateTime()); + entity.setUpdateTime(new Date()); + employeeDao.updateById(entity); + employeeCache.remove(employeeId); + return ResponseDTO.succ(); + } + + /** + * 删除员工 + * + * @param employeeId 员工ID + * @return + */ + public ResponseDTO deleteEmployeeById(Long employeeId) { + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + if (null == employeeEntity) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.EMP_NOT_EXISTS); + } + //假删 + employeeEntity.setIsDelete(JudgeEnum.YES.getValue().longValue()); + employeeDao.updateById(employeeEntity); + employeeCache.remove(employeeId); + return ResponseDTO.succ(); + } + + /** + * 更新用户角色 + * + * @param updateRolesDTO + * @return + */ + public ResponseDTO updateRoles(EmployeeUpdateRolesDTO updateRolesDTO) { + roleEmployeeDao.deleteByEmployeeId(updateRolesDTO.getEmployeeId()); + if (CollectionUtils.isNotEmpty(updateRolesDTO.getRoleIds())) { + List roleEmployeeEntities = Lists.newArrayList(); + RoleEmployeeEntity roleEmployeeEntity; + for (Long roleId : updateRolesDTO.getRoleIds()) { + roleEmployeeEntity = new RoleEmployeeEntity(); + roleEmployeeEntity.setEmployeeId(updateRolesDTO.getEmployeeId()); + roleEmployeeEntity.setRoleId(roleId); + roleEmployeeEntities.add(roleEmployeeEntity); + } + roleEmployeeDao.batchInsert(roleEmployeeEntities); + } + return ResponseDTO.succ(); + } + + /** + * 更新密码 + * + * @param updatePwdDTO + * @param requestToken + * @return + */ + public ResponseDTO updatePwd(EmployeeUpdatePwdDTO updatePwdDTO, RequestTokenBO requestToken) { + Long employeeId = requestToken.getRequestUserId(); + EmployeeEntity employee = employeeDao.selectById(employeeId); + if (employee == null) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.EMP_NOT_EXISTS); + } + if (!employee.getLoginPwd().equals(SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, updatePwdDTO.getOldPwd()))) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.PASSWORD_ERROR); + } + employee.setLoginPwd(SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, updatePwdDTO.getPwd())); + employeeDao.updateById(employee); + employeeCache.remove(employeeId); + return ResponseDTO.succ(); + } + + public ResponseDTO> getEmployeeByDeptId(Long departmentId) { + List list = employeeDao.getEmployeeIdByDeptId(departmentId); + return ResponseDTO.succData(list); + } + + /** + * 重置密码 + * + * @param employeeId + * @return + */ + public ResponseDTO resetPasswd(Integer employeeId) { + String md5Password = SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, RESET_PASSWORD); + employeeDao.updatePassword(employeeId, md5Password); + employeeCache.remove(employeeId); + return ResponseDTO.succ(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/constant/EmployeeResponseCodeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/constant/EmployeeResponseCodeConst.java new file mode 100644 index 00000000..5e3d45f7 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/constant/EmployeeResponseCodeConst.java @@ -0,0 +1,61 @@ +package com.gangquan360.smartadmin.module.employee.constant; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + +/** + * 员工常量类 + * 3001-3999 + * + * @author lidoudou + * @date 2017年12月19日下午19:04:52 + */ +public class EmployeeResponseCodeConst extends ResponseCodeConst { + + /** + * 员工不存在 + */ + public static final EmployeeResponseCodeConst EMP_NOT_EXISTS = new EmployeeResponseCodeConst(3001, "员工不存在!"); + + /** + * 更新员工信息失败 + */ + public static final EmployeeResponseCodeConst UPDATE_FAILED = new EmployeeResponseCodeConst(3002, "员工更新失败!"); + + /** + * 部门信息不存在 + */ + public static final EmployeeResponseCodeConst DEPT_NOT_EXIST = new EmployeeResponseCodeConst(3003, "部门信息不存在!"); + + /** + * 用户名或密码错误 + */ + public static final EmployeeResponseCodeConst LOGIN_FAILED = new EmployeeResponseCodeConst(3004, "用户名或密码错误!"); + + /** + * 您的账号已被禁用,不得登录系统 + */ + public static final EmployeeResponseCodeConst IS_DISABLED = new EmployeeResponseCodeConst(3005, "您的账号已被禁用,不得登录系统!"); + + /** + * 登录名已存在 + */ + public static final EmployeeResponseCodeConst LOGIN_NAME_EXISTS = new EmployeeResponseCodeConst(3006, "登录名已存在!"); + /** + * 密码输入有误,请重新输入 10115 + */ + public static final EmployeeResponseCodeConst PASSWORD_ERROR = new EmployeeResponseCodeConst(3007, "密码输入有误,请重新输入"); + /** + * 手机号已存在 + */ + public static final EmployeeResponseCodeConst PHONE_EXISTS = new EmployeeResponseCodeConst(3008, "手机号已经存在"); + + public static final EmployeeResponseCodeConst ID_CARD_ERROR = new EmployeeResponseCodeConst(3009, "请输入正确的身份证号"); + + public static final EmployeeResponseCodeConst BIRTHDAY_ERROR = new EmployeeResponseCodeConst(3010, "生日格式不正确"); + + public static final EmployeeResponseCodeConst VERIFICATION_CODE_INVALID = new EmployeeResponseCodeConst(3011, "验证码无效"); + + public EmployeeResponseCodeConst(int code, String msg) { + super(code, msg); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/constant/EmployeeStatusEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/constant/EmployeeStatusEnum.java new file mode 100644 index 00000000..45eafe0e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/constant/EmployeeStatusEnum.java @@ -0,0 +1,56 @@ +package com.gangquan360.smartadmin.module.employee.constant; + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 16:22 + * @since JDK1.8 + */ + +public enum EmployeeStatusEnum implements BaseEnum { + + /** + * 用户正常状态 1 + */ + NORMAL(0, "正常"), + + /** + * 用户已被禁用 0 + */ + DISABLED(1, "禁用"); + + private Integer value; + + private String desc; + + EmployeeStatusEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } + + /** + * 获取枚举类的值 + * + * @return Integer + */ + @Override + public Integer getValue() { + return value; + } + + /** + * 获取枚举类的说明 + * + * @return String + */ + @Override + public String getDesc() { + return this.desc; + } +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/bo/EmployeeBO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/bo/EmployeeBO.java new file mode 100644 index 00000000..ed22d060 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/bo/EmployeeBO.java @@ -0,0 +1,73 @@ +package com.gangquan360.smartadmin.module.employee.domain.bo; + +import com.gangquan360.smartadmin.module.employee.domain.entity.EmployeeEntity; +import lombok.Getter; + + +@Getter +public class EmployeeBO { + + /** + * 主键id + */ + private Long id; + + /** + * 登录账号 + */ + private String loginName; + + /** + * 员工名称 + */ + private String actualName; + + /** + * 别名 + */ + private String nickName; + + /** + * 手机号码 + */ + private String phone; + + /** + * 部门id + */ + private Long departmentId; + + /** + * 是否离职 + */ + private Integer isLeave; + + /** + * 是否被禁用 + */ + private Integer isDisabled; + + /** + * 删除状态 0否 1是 + */ + private Long isDelete; + + /** + * 是否为超级管理员 + */ + private Boolean isSuperman; + + public EmployeeBO(EmployeeEntity employeeEntity, boolean isSuperman) { + this.id = employeeEntity.getId(); + this.loginName = employeeEntity.getLoginName(); + this.actualName = employeeEntity.getActualName(); + this.nickName = employeeEntity.getNickName(); + this.phone = employeeEntity.getPhone(); + this.departmentId = employeeEntity.getDepartmentId(); + this.isLeave = employeeEntity.getIsLeave(); + this.isDisabled = employeeEntity.getIsDisabled(); + this.isDelete = employeeEntity.getIsDelete(); + this.isSuperman = isSuperman; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeAddDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeAddDTO.java new file mode 100644 index 00000000..4a9c95c7 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeAddDTO.java @@ -0,0 +1,63 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import com.gangquan360.smartadmin.util.SmartVerificationUtil; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import java.util.List; + +/** + * 添加员工 + * + * @author lidoudou + * @date 2017年12月19日下午2:06:31 + */ +@Data +public class EmployeeAddDTO { + + @ApiModelProperty("姓名") + @NotNull(message = "姓名不能为空") + private String actualName; + + @ApiModelProperty("登录名") + @NotNull(message = "姓名不能为空") + private String loginName; + + @ApiModelProperty("别名") + private String nickName; + + @ApiModelProperty("部门id") + @NotNull(message = "部门id不能为空") + private Long departmentId; + + @ApiModelProperty("是否启用") + @NotNull(message = "是否被禁用不能为空") + private Integer isDisabled; + + @ApiModelProperty("手机号") + @NotNull(message = "手机号不能为空") + @Pattern(regexp = SmartVerificationUtil.PHONE_REGEXP, message = "手机号格式不正确") + private String phone; + + @ApiModelProperty("身份证(可选)") + private String idCard; + + @ApiModelProperty("生日(可选)") + private String birthday; + + @ApiModelProperty("密码") + // @NotNull(message = "密码不能为空") + // @Length(min = 6, message = "密码最少为6位字符") + private String loginPwd; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("岗位ID 集合") + @NotEmpty(message = "岗位ID 集合不能为空") + private List positionIdList; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeBaseDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeBaseDTO.java new file mode 100644 index 00000000..35099d88 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeBaseDTO.java @@ -0,0 +1,52 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import com.gangquan360.smartadmin.util.SmartVerificationUtil; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; + +/** + * 添加员工 + * + * @author lidoudou + * @date 2017年12月19日下午2:06:31 + */ +@Data +public class EmployeeBaseDTO { + + @ApiModelProperty("姓名") + @NotNull(message = "姓名不能为空") + private String actualName; + + @ApiModelProperty("登录名") + @NotNull(message = "姓名不能为空") + private String loginName; + + @ApiModelProperty("别名") + private String nickName; + + @ApiModelProperty("部门id") + @NotNull(message = "部门id不能为空") + private Long departmentId; + + @ApiModelProperty("是否启用") + @NotNull(message = "是否被禁用不能为空") + private Integer isDisabled; + + @ApiModelProperty("手机号") + @NotNull(message = "手机号不能为空") + @Pattern(regexp = SmartVerificationUtil.PHONE_REGEXP, message = "手机号格式不正确") + private String phone; + + @ApiModelProperty("身份证(可选)") + private String idCard; + + @ApiModelProperty("生日(可选)") + private String birthday; + + @ApiModelProperty("邮箱") + private String email; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeBatchUpdateStatusDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeBatchUpdateStatusDTO.java new file mode 100644 index 00000000..1f2a2c29 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeBatchUpdateStatusDTO.java @@ -0,0 +1,26 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 批量更新 + * + * @author lidoudou + * @date 2017年12月21日上午13:17:52 + */ +@Data +public class EmployeeBatchUpdateStatusDTO { + + @ApiModelProperty("员工ids") + @NotNull(message = "员工ids不能为空") + private List employeeIds; + + @ApiModelProperty("状态") + @NotNull(message = "状态不能为空") + private Integer status; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeDTO.java new file mode 100644 index 00000000..f5033ec4 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeDTO.java @@ -0,0 +1,73 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionRelationResultDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * 员工列表DTO + * + * @author lidoudou + * @date 2017年12月21日上午09:09:31 + */ +@Data +public class EmployeeDTO { + + @ApiModelProperty("主键id") + private Long id; + + @ApiModelProperty("登录账号") + private String loginName; + + @ApiModelProperty("别名") + private String nickName; + + @ApiModelProperty("员工名称") + private String actualName; + + @ApiModelProperty("手机号码") + private String phone; + + @ApiModelProperty("身份证") + private String idCard; + + @ApiModelProperty("出生日期") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date birthday; + + @ApiModelProperty("创建者id") + private Long createUser; + + @ApiModelProperty("部门id") + private Long departmentId; + + @ApiModelProperty("是否离职") + private Integer isLeave; + + @ApiModelProperty("是否被禁用") + private Integer isDisabled; + + @ApiModelProperty("是否删除") + private Integer isDelete; + + @ApiModelProperty("部门名称") + private String departmentName; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + @ApiModelProperty("岗位关联信息") + private List positionRelationList; + + @ApiModelProperty("岗位名称") + private String positionName; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeLoginFormDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeLoginFormDTO.java new file mode 100644 index 00000000..c4220a64 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeLoginFormDTO.java @@ -0,0 +1,33 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 登录 + * + * @author lidoudou + * @date 2017年12月19日上午11:49:46 + */ +@Data +public class EmployeeLoginFormDTO { + + @NotNull(message = "登录名不能为空") + @ApiModelProperty(example = "sa") + private String loginName; + + @NotNull(message = "密码不能为空") + @ApiModelProperty(example = "123456") + private String loginPwd; + + @NotNull(message = "验证码id不能为空") + @ApiModelProperty(value = "验证码uuid") + private String codeUuid; + + @NotNull(message = "验证码不能为空") + @ApiModelProperty(value = "验证码") + private String code; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeQueryDTO.java new file mode 100644 index 00000000..c023261e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeQueryDTO.java @@ -0,0 +1,39 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 员工列表DTO + * + * @author lidoudou + * @date 2017年12月21日上午09:09:31 + */ +@Data +public class EmployeeQueryDTO extends PageParamDTO { + + private String phone; + + private String actualName; + + private String keyword; + + private Long departmentId; + + private Integer isLeave; + + private Integer isDisabled; + + /** + * 删除状态 0否 1是 + */ + @ApiModelProperty("删除状态 0否 1是 不需要传") + private Integer isDelete; + + @ApiModelProperty("员工id集合") + private List employeeIds; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeQueryExportDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeQueryExportDTO.java new file mode 100644 index 00000000..c94da314 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeQueryExportDTO.java @@ -0,0 +1,42 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * @author zzr + * 不带分页的查询条件 + */ +@Data +public class EmployeeQueryExportDTO { + + @ApiModelProperty(hidden = true) + private String phone; + + @ApiModelProperty("姓名") + private String actualName; + + @ApiModelProperty(hidden = true) + private String keyword; + + @ApiModelProperty(hidden = true) + private Long departmentId; + + @ApiModelProperty(hidden = true) + private Integer isLeave; + + @ApiModelProperty(hidden = true) + private Integer isDisabled; + + /** + * 删除状态 0否 1是 + */ + @ApiModelProperty(value = "删除状态 0否 1是 不需要传", hidden = true) + private Integer isDelete; + + @ApiModelProperty(value = "员工ID集合", hidden = true) + private List employeeIds; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdateDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdateDTO.java new file mode 100644 index 00000000..d266fd5d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdateDTO.java @@ -0,0 +1,28 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 添加员工 + * + * @author lidoudou + * @date 2017年12月19日下午2:06:31 + */ +@Data +public class EmployeeUpdateDTO extends EmployeeBaseDTO { + + @ApiModelProperty("员工id") + @NotNull(message = "员工id不能为空") + private Long id; + + @ApiModelProperty("密码") + private String loginPwd; + + @ApiModelProperty("岗位ID 集合") + private List positionIdList; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdatePwdDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdatePwdDTO.java new file mode 100644 index 00000000..2056c178 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdatePwdDTO.java @@ -0,0 +1,25 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 修改密码所需参数 + * + * @author cyj + * @date 2018-02-23 下午 4:53 + */ +@Data +public class EmployeeUpdatePwdDTO { + + @ApiModelProperty("新密码") + @NotNull + private String pwd; + + @ApiModelProperty("原密码") + @NotNull + private String oldPwd; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdateRolesDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdateRolesDTO.java new file mode 100644 index 00000000..b81b826f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/dto/EmployeeUpdateRolesDTO.java @@ -0,0 +1,29 @@ +package com.gangquan360.smartadmin.module.employee.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Data +public class EmployeeUpdateRolesDTO { + + @ApiModelProperty("员工id") + @NotNull(message = "员工id不能为空") + private Long employeeId; + + @ApiModelProperty("角色ids") + private List roleIds; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/entity/EmployeeEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/entity/EmployeeEntity.java new file mode 100644 index 00000000..b4b1da84 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/entity/EmployeeEntity.java @@ -0,0 +1,91 @@ +package com.gangquan360.smartadmin.module.employee.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +import java.io.Serializable; + +/** + * 员工实体类 + * + * @author lidoudou + * @date 2017年12月19日下午1:34:48 + */ +@Data +@TableName("t_employee") +public class EmployeeEntity extends BaseEntity implements Serializable { + + private static final long serialVersionUID = -8794328598524272806L; + + /** + * 登录账号 + */ + private String loginName; + + /** + * 登录密码 + */ + private String loginPwd; + + /** + * 员工名称 + */ + private String actualName; + + /** + * 别名 + */ + private String nickName; + + /** + * 手机号码 + */ + private String phone; + + /** + * 身份证 + */ + private String idCard; + + /** + * 出生日期 + */ + private String birthday; + + + /** + * 部门id + */ + private Long departmentId; + + /** + * 是否离职 + */ + private Integer isLeave; + + /** + * 是否被禁用 + */ + private Integer isDisabled; + /** + * 邮箱 + */ + private String email; + + /** + * 备注 + */ + private String remark; + + /** + * 创建者id + */ + private Long createUser; + + /** + * 删除状态 0否 1是 + */ + private Long isDelete; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/vo/EmployeeVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/vo/EmployeeVO.java new file mode 100644 index 00000000..8f9e9d36 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/employee/domain/vo/EmployeeVO.java @@ -0,0 +1,72 @@ +package com.gangquan360.smartadmin.module.employee.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionRelationResultDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; + +/** + * @author bhr + * @Description: 员工信息 + * @date 2019/8/28 9:04 + */ + +@Data +public class EmployeeVO { + + @ApiModelProperty("主键id") + private Long id; + + @ApiModelProperty("登录账号") + private String loginName; + + @ApiModelProperty("别名") + private String nickName; + + @ApiModelProperty("员工名称") + private String actualName; + + @ApiModelProperty("手机号码") + private String phone; + + @ApiModelProperty("身份证") + private String idCard; + + @ApiModelProperty("出生日期") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date birthday; + + @ApiModelProperty("创建者id") + private Long createUser; + + @ApiModelProperty("部门id") + private Long departmentId; + + @ApiModelProperty("是否离职") + private Integer isLeave; + + @ApiModelProperty("是否被禁用") + private Integer isDisabled; + + @ApiModelProperty("是否删除") + private Integer isDelete; + + @ApiModelProperty("部门名称") + private String departmentName; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + @ApiModelProperty("岗位关联信息") + private List positionRelationList; + + @ApiModelProperty("岗位名称") + private String positionName; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/FileController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/FileController.java new file mode 100644 index 00000000..bdb908af --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/FileController.java @@ -0,0 +1,93 @@ +package com.gangquan360.smartadmin.module.file; + +import com.gangquan360.smartadmin.common.anno.NoNeedLogin; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.file.constant.FileServiceTypeEnum; +import com.gangquan360.smartadmin.module.file.domain.dto.FileAddDTO; +import com.gangquan360.smartadmin.module.file.domain.dto.FileQueryDTO; +import com.gangquan360.smartadmin.module.file.domain.vo.FileVO; +import com.gangquan360.smartadmin.module.file.domain.vo.UploadVO; +import com.gangquan360.smartadmin.module.file.service.FileService; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.util.SmartRequestTokenUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +/** + * @Description: 文件服务 + * @Author: sbq + * @CreateDate: 2019/7/18 9:36 + * @Version: 1.0 + */ +@RestController +@Api(tags = {SwaggerTagConst.Admin.MANAGER_FILE}) +public class FileController { + + @Autowired + private FileService fileService; + + @ApiOperation(value = "文件本地上传", notes = "文件本地上传") + @PostMapping("/api/file/localUpload/{moduleType}") + public ResponseDTO localUpload(MultipartFile file, @PathVariable Integer moduleType) throws Exception { + return fileService.fileUpload(file, FileServiceTypeEnum.LOCAL, moduleType); + } + + @ApiOperation(value = "获取本地文件URL", notes = "获取文件URL") + @PostMapping("/api/file/get") + public ResponseDTO localGetFile(String path) { + return fileService.getFileUrl(path, FileServiceTypeEnum.LOCAL); + } + + @ApiOperation(value = "文件阿里云上传", notes = "文件阿里云上传") + @PostMapping("/api/file/aliYunUpload/{moduleType}") + public ResponseDTO aliYunUpload(MultipartFile file, @PathVariable Integer moduleType) throws Exception { + return fileService.fileUpload(file, FileServiceTypeEnum.ALI_OSS, moduleType); + } + + @ApiOperation(value = "获取阿里云文件URL", notes = "获取阿里云文件URL") + @PostMapping("/api/file/aliYunGet") + public ResponseDTO aliYunGet(String path) { + return fileService.getFileUrl(path, FileServiceTypeEnum.ALI_OSS); + } + + @ApiOperation(value = "文件七牛云上传", notes = "文件七牛云上传") + @PostMapping("/api/file/qiNiuUpload/{moduleType}") + public ResponseDTO qiNiuUpload(MultipartFile file, @PathVariable Integer moduleType) throws Exception { + return fileService.fileUpload(file, FileServiceTypeEnum.QI_NIU_OSS, moduleType); + } + + @ApiOperation(value = "获取七牛云文件URL", notes = "获取七牛云URL") + @PostMapping("/api/file/qiNiuGet") + public ResponseDTO qiNiuGet(String path) { + return fileService.getFileUrl(path, FileServiceTypeEnum.QI_NIU_OSS); + } + + @ApiOperation(value = "系统文件查询") + @PostMapping("/api/file/query") + public ResponseDTO> queryListByPage(@RequestBody FileQueryDTO queryDTO) { + return fileService.queryListByPage(queryDTO); + } + + @ApiOperation(value = "系统文件下载通用接口(流下载)") + @GetMapping("/api/file/downLoad") + @NoNeedLogin + public ResponseEntity downLoadById(Long id, HttpServletRequest request) { + return fileService.downLoadById(id, request); + } + + @ApiOperation(value = "系统文件保存通用接口") + @PostMapping("/api/file/save") + public ResponseDTO saveFile(@Valid @RequestBody FileAddDTO addDTO) { + RequestTokenBO requestToken = SmartRequestTokenUtil.getRequestUser(); + return fileService.saveFile(addDTO,requestToken); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/FileDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/FileDao.java new file mode 100644 index 00000000..01c3faa6 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/FileDao.java @@ -0,0 +1,72 @@ +package com.gangquan360.smartadmin.module.file; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.module.file.domain.dto.FileDTO; +import com.gangquan360.smartadmin.module.file.domain.dto.FileQueryDTO; +import com.gangquan360.smartadmin.module.file.domain.entity.FileEntity; +import com.gangquan360.smartadmin.module.file.domain.vo.FileVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author cyj + * @date 2018-01-05 上午 9:49 + */ +@Mapper +@Component +public interface FileDao extends BaseMapper { + + /** + * 批量添加上传文件 + * + * @param fileDTOList + * @return + */ + Integer insertFileBatch(List fileDTOList); + + + /** + * 批量添加上传文件 + * + * @param fileDTOList + * @return + */ + Integer insertFileEntityBatch(List fileDTOList); + + /** + * 批量删除 + * + * @param moduleId + * @return + */ + Integer deleteFilesByModuleId(@Param("moduleId") String moduleId); + + /** + * 批量删除 + * + * @param moduleId + * @param moduleType + * @return + */ + Integer deleteFilesByModuleIdAndModuleType(@Param("moduleId") String moduleId, @Param("moduleType") String moduleType); + + /** + * @param moduleId + * @return + */ + List listFilesByModuleId(@Param("moduleId") String moduleId); + + List listFilesByFileIds(@Param("fileIds") List fileIds); + + List listFilesByModuleIdAndModuleType(@Param("moduleId") String moduleId, @Param("moduleType") String moduleType); + + List listFilesByModuleIdAndModuleTypes(@Param("moduleId") String moduleId, @Param("moduleTypes") List moduleTypes); + + List listFilesByModuleIdsAndModuleType(@Param("moduleIds") List moduleIds, @Param("moduleType") String moduleType); + + List queryListByPage(Page page, @Param("queryDTO") FileQueryDTO queryDTO); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileModuleTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileModuleTypeEnum.java new file mode 100644 index 00000000..78670f2c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileModuleTypeEnum.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.module.file.constant; + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +/** + * [] + * + * @author yandanyang + * @version 1.0 + * @since JDK1.8 + */ +public enum FileModuleTypeEnum implements BaseEnum { + + /** + * path 首字符不能包含\ 或者/ + */ + + BACK_USER(1, "backUser/config", "backUser"); + + private Integer value; + + private String path; + + private String desc; + + FileModuleTypeEnum(Integer value, String path, String desc) { + this.value = value; + this.path = path; + this.desc = desc; + } + + public String getPath() { + return path; + } + + @Override + public Integer getValue() { + return this.value; + } + + @Override + public String getDesc() { + return this.desc; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileResponseCodeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileResponseCodeConst.java new file mode 100644 index 00000000..795bed17 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileResponseCodeConst.java @@ -0,0 +1,37 @@ +package com.gangquan360.smartadmin.module.file.constant; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +public class FileResponseCodeConst extends ResponseCodeConst { + + /** + * 4001 -4999 + */ + public static final FileResponseCodeConst FILE_EMPTY = new FileResponseCodeConst(4001, "上传文件不存在!"); + + public static final FileResponseCodeConst FILE_SIZE_ERROR = new FileResponseCodeConst(4002, "上传文件超过%s,请重新上传!"); + + public static final FileResponseCodeConst UNKNOWN_FILE_TYPE = new FileResponseCodeConst(4003, "未知的文件类型!"); + + public static final FileResponseCodeConst LOCAL_UPDATE_PREFIX_ERROR = new FileResponseCodeConst(4004, "文件本地上传缺少URL前缀配置[local_upload_url_prefix]"); + + public static final FileResponseCodeConst UPLOAD_ERROR = new FileResponseCodeConst(4005, "上传失败"); + + public static final FileResponseCodeConst URL_ERROR = new FileResponseCodeConst(4006, "获取URL失败"); + + public static final FileResponseCodeConst FILE_MODULE_ERROR = new FileResponseCodeConst(4007, "文件目录类型错误"); + + public FileResponseCodeConst(int code, String msg) { + super(code, msg); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileServiceNameConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileServiceNameConst.java new file mode 100644 index 00000000..96c649f3 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileServiceNameConst.java @@ -0,0 +1,24 @@ +package com.gangquan360.smartadmin.module.file.constant; +/** + * 文件服务名称常量 + * + * @author listen + * @date 2019/08/27 15:24 + */ +public class FileServiceNameConst { + + /** + * 阿里OSS文件服务 + */ + public static final String ALI_OSS = "ali_oss"; + + /** + * 七牛文件服务 + */ + public static final String QI_NIU_OSS = "qi_niu_oss"; + + /** + * 本地文件服务 + */ + public static final String LOCAL = "local"; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileServiceTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileServiceTypeEnum.java new file mode 100644 index 00000000..04046b20 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/constant/FileServiceTypeEnum.java @@ -0,0 +1,52 @@ +package com.gangquan360.smartadmin.module.file.constant; + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +/** + * 文件服务枚举类 + * + * @author listen + * @date 2019年8月27日 14:27:16 + */ +public enum FileServiceTypeEnum implements BaseEnum { + + /** + * 本地文件服务 + */ + LOCAL(1, FileServiceNameConst.LOCAL, "本地文件服务"), + + /** + * 阿里OSS文件服务 + */ + ALI_OSS(2, FileServiceNameConst.ALI_OSS, "阿里OSS文件服务"), + + /** + * 七牛文件服务 + */ + QI_NIU_OSS(3, FileServiceNameConst.QI_NIU_OSS, "七牛文件服务"); + + private Integer locationType; + + private String serviceName; + + private String desc; + + FileServiceTypeEnum(Integer locationType, String serviceName, String desc) { + this.locationType = locationType; + this.serviceName = serviceName; + this.desc = desc; + } + + public String getServiceName() { + return serviceName; + } + @Override + public Integer getValue() { + return this.locationType; + } + + @Override + public String getDesc() { + return this.desc; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileAddDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileAddDTO.java new file mode 100644 index 00000000..9121b56f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileAddDTO.java @@ -0,0 +1,40 @@ +package com.gangquan360.smartadmin.module.file.domain.dto; + +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.common.validator.en.CheckEnum; +import com.gangquan360.smartadmin.module.file.constant.FileServiceTypeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** +* @Description: 文件保存DTO +* @Author: sbq +* @CreateDate: 2019/9/11 15:05 +* @Version: 1.0 +*/ +@Data +public class FileAddDTO { + + @ApiModelProperty("相关业务id(无业务可写死一个id)") + @NotBlank(message = "相关业务id不能为空") + private String moduleId; + + @ApiModelProperty("相关业务类型(无模块写1)") + @NotBlank(message = "相关业务类型不能为空") + private String moduleType; + + @ApiModelPropertyEnum(enumDesc = "文件类型",value = FileServiceTypeEnum.class) + @CheckEnum(enumClazz = FileServiceTypeEnum.class,message = "文件类型错误") + private Integer fileLocationType; + + @ApiModelProperty("文件名称") + @NotBlank(message = "文件名称不能为空") + private String fileName; + + @ApiModelProperty("文件路径") + @NotBlank(message = "文件路径不能为空") + private String filePath; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileDTO.java new file mode 100644 index 00000000..a6998cf0 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileDTO.java @@ -0,0 +1,58 @@ +package com.gangquan360.smartadmin.module.file.domain.dto; + +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.module.file.constant.FileServiceTypeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.sql.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Data +public class FileDTO { + + @ApiModelProperty("主键") + private Long id; + + @ApiModelProperty("相关业务id") + private String moduleId; + + @ApiModelProperty("相关业务类型") + private String moduleType; + + @ApiModelPropertyEnum(FileServiceTypeEnum.class) + private Integer fileLocationType; + + @ApiModelProperty("文件名称") + private String fileName; + + @ApiModelProperty("文件大小") + private String fileSize; + + @ApiModelProperty("文件类型") + private String fileType; + + @ApiModelProperty("文件路径") + private String filePath; + + @ApiModelProperty("上传人") + private Long createUser; + + @ApiModelProperty("updateTime") + private Date updateTime; + + @ApiModelProperty("创建时间") + private Date createTime; + + @ApiModelProperty("文件展示url(可用于下载,注:七牛云下载url要拼接 ?attname=文件名.jpg)") + private String fileUrl; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileQueryDTO.java new file mode 100644 index 00000000..d6e547bd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/FileQueryDTO.java @@ -0,0 +1,33 @@ +package com.gangquan360.smartadmin.module.file.domain.dto; + +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import com.gangquan360.smartadmin.common.validator.en.CheckEnum; +import com.gangquan360.smartadmin.module.file.constant.FileModuleTypeEnum; +import com.gangquan360.smartadmin.module.file.constant.FileServiceTypeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @Description: 文件信息查询dto + * @Author: sbq + * @CreateDate: 2019/7/3 17:38 + * @Version: 1.0 + */ +@Data +public class FileQueryDTO extends PageParamDTO { + + @ApiModelProperty(value = "文件名称") + private String fileName; + + @ApiModelProperty(value = "业务类型") + @ApiModelPropertyEnum(FileModuleTypeEnum.class) + @CheckEnum(enumClazz = FileModuleTypeEnum.class, message = "文件业务类型错误") + private Integer moduleType; + + @ApiModelProperty(value = "文件位置") + @ApiModelPropertyEnum(FileServiceTypeEnum.class) + @CheckEnum(enumClazz = FileServiceTypeEnum.class, message = "文件位置类型错误") + private Integer fileLocationType; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/OSSConfig.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/OSSConfig.java new file mode 100644 index 00000000..cd4013a9 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/dto/OSSConfig.java @@ -0,0 +1,36 @@ +package com.gangquan360.smartadmin.module.file.domain.dto; + +import com.alibaba.fastjson.JSON; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/11 0011 下午 16:05 + * @since JDK1.8 + */ +@Data +public class OSSConfig { + + private String endpoint; + + private String accessKeyId; + + private String accessKeySecret; + + private String bucketName; + + @Override + public String toString() { + return "OSSConfig{" + + "endpoint='" + endpoint + '\'' + + ", accessKeyId='" + accessKeyId + '\'' + + ", accessKeySecret='" + accessKeySecret + '\'' + + ", bucketName='" + bucketName + '\'' + + '}'; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/entity/FileEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/entity/FileEntity.java new file mode 100644 index 00000000..b99e4dcd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/entity/FileEntity.java @@ -0,0 +1,58 @@ +package com.gangquan360.smartadmin.module.file.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +@TableName(value = "t_file") +public class FileEntity extends BaseEntity{ + + + /** + * 相关业务id + */ + private String moduleId; + /** + * 相关业务类型 + */ + private String moduleType; + /** + * 文件位置类型 + */ + private Integer fileLocationType; + /** + * 文件名称 + */ + private String fileName; + /** + * 文件大小 + */ + private String fileSize; + /** + * 文件类型,程序中枚举控制,文件类型:如身份证正面,三证合一等等 + */ + private String fileType; + /** + * 文件key,用于文件下载 + */ + private String filePath; + /** + * 创建人,即上传人 + */ + private Long createrUser; + +} + diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/vo/FileVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/vo/FileVO.java new file mode 100644 index 00000000..336282fd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/vo/FileVO.java @@ -0,0 +1,58 @@ +package com.gangquan360.smartadmin.module.file.domain.vo; + +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.module.file.constant.FileServiceTypeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.sql.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Data +public class FileVO { + + @ApiModelProperty("主键") + private Long id; + + @ApiModelProperty("相关业务id") + private String moduleId; + + @ApiModelProperty("相关业务类型") + private String moduleType; + + @ApiModelPropertyEnum(FileServiceTypeEnum.class) + private Integer fileLocationType; + + @ApiModelProperty("文件名称") + private String fileName; + + @ApiModelProperty("文件大小") + private String fileSize; + + @ApiModelProperty("文件类型") + private String fileType; + + @ApiModelProperty("文件路径") + private String filePath; + + @ApiModelProperty("上传人") + private Long createUser; + + @ApiModelProperty("updateTime") + private Date updateTime; + + @ApiModelProperty("创建时间") + private Date createTime; + + @ApiModelProperty("文件展示url(可用于下载,注:七牛云下载url要拼接 ?attname=文件名.jpg)") + private String fileUrl; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/vo/UploadVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/vo/UploadVO.java new file mode 100644 index 00000000..aff3a02e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/domain/vo/UploadVO.java @@ -0,0 +1,27 @@ +package com.gangquan360.smartadmin.module.file.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2018/12/11 0011 上午 10:57 + * @since JDK1.8 + */ +@Data +public class UploadVO { + + @ApiModelProperty(value = "文件名称") + private String fileName; + @ApiModelProperty(value = "url") + private String url; + @ApiModelProperty(value = "filePath") + private String filePath; + @ApiModelProperty(value = "文件大小") + private Long fileSize; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileService.java new file mode 100644 index 00000000..51c0d75b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileService.java @@ -0,0 +1,197 @@ +package com.gangquan360.smartadmin.module.file.service; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.file.FileDao; +import com.gangquan360.smartadmin.module.file.constant.FileModuleTypeEnum; +import com.gangquan360.smartadmin.module.file.constant.FileResponseCodeConst; +import com.gangquan360.smartadmin.module.file.constant.FileServiceTypeEnum; +import com.gangquan360.smartadmin.module.file.domain.dto.FileAddDTO; +import com.gangquan360.smartadmin.module.file.domain.dto.FileDTO; +import com.gangquan360.smartadmin.module.file.domain.dto.FileQueryDTO; +import com.gangquan360.smartadmin.module.file.domain.entity.FileEntity; +import com.gangquan360.smartadmin.module.file.domain.vo.FileVO; +import com.gangquan360.smartadmin.module.file.domain.vo.UploadVO; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.util.SmartBaseEnumUtil; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import com.google.common.collect.Lists; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Service +public class FileService { + + @Autowired + private FileDao fileDao; + + @Autowired + private java.util.Map fileServiceMap; + + /** + * 获取文件服务实现 + * + * @param typeEnum + * @return + */ + private IFileService getFileService(FileServiceTypeEnum typeEnum) { + /** + * 获取文件服务 + */ + String serviceName = typeEnum.getServiceName(); + IFileService fileService = fileServiceMap.get(serviceName); + if (null == fileService) { + throw new RuntimeException("未找到文件服务实现类:" + serviceName); + } + return fileService; + } + + /** + * 文件上传服务 + * + * @param file + * @param typeEnum 文件服务类型枚举类 + * @param moduleType 文件夹类型 + * @return + */ + public ResponseDTO fileUpload(MultipartFile file, FileServiceTypeEnum typeEnum, Integer moduleType) { + FileModuleTypeEnum moduleTypeEnum = SmartBaseEnumUtil.getEnumByValue(moduleType, FileModuleTypeEnum.class); + if (null == moduleTypeEnum) { + return ResponseDTO.wrap(FileResponseCodeConst.FILE_MODULE_ERROR); + } + // 获取文件服务 + IFileService fileService = this.getFileService(typeEnum); + ResponseDTO response = fileService.fileUpload(file, moduleTypeEnum.getPath()); + return response; + } + + /** + * 根据文件绝对路径 获取文件URL + * + * @param path + * @return + */ + public ResponseDTO getFileUrl(String path, FileServiceTypeEnum typeEnum) { + IFileService fileService = this.getFileService(typeEnum); + return fileService.getFileUrl(path); + } + + /** + * 批量插入 + * + * @param fileDTOList + */ + public void insertFileBatch(List fileDTOList) { + fileDao.insertFileBatch(fileDTOList); + } + + /** + * 根据module 删除文件信息 + * + * @param moduleId + * @return + */ + public void deleteFilesByModuleId(String moduleId) { + fileDao.deleteFilesByModuleId(moduleId); + } + + /** + * 根据module 获取文件信息 + * + * @param moduleId + * @return + */ + public List listFilesByModuleId(String moduleId) { + return fileDao.listFilesByModuleId(moduleId); + } + + /** + * @param filesStr 逗号分隔文件id字符串 + * @return + */ + public List getFileDTOList(String filesStr) { + if (StringUtils.isEmpty(filesStr)) { + return Lists.newArrayList(); + } + String[] fileIds = filesStr.split(","); + List fileIdList = Arrays.asList(fileIds).stream().map(e -> Long.valueOf(e)).collect(Collectors.toList()); + List files = fileDao.listFilesByFileIds(fileIdList); + return files; + } + + /** + * 分页查询文件列表 + * + * @param queryDTO + * @return + */ + public ResponseDTO> queryListByPage(FileQueryDTO queryDTO) { + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List fileList = fileDao.queryListByPage(page, queryDTO); + if (CollectionUtils.isNotEmpty(fileList)) { + fileList.forEach(e -> { + // 根据文件服务类 获取对应文件服务 查询 url + FileServiceTypeEnum serviceTypeEnum = SmartBaseEnumUtil.getEnumByValue(e.getFileLocationType(), FileServiceTypeEnum.class); + IFileService fileService = this.getFileService(serviceTypeEnum); + e.setFileUrl(fileService.getFileUrl(e.getFilePath()).getData()); + }); + } + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page, fileList); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * 根据id 下载文件 + * + * @param id + * @param request + * @return + */ + public ResponseEntity downLoadById(Long id, HttpServletRequest request) { + FileEntity entity = fileDao.selectById(id); + if (null == entity) { + throw new RuntimeException("文件信息不存在"); + } + + // 根据文件服务类 获取对应文件服务 查询 url + FileServiceTypeEnum serviceTypeEnum = SmartBaseEnumUtil.getEnumByValue(entity.getFileLocationType(), FileServiceTypeEnum.class); + IFileService fileService = this.getFileService(serviceTypeEnum); + ResponseEntity stream = fileService.fileDownload(entity.getFilePath(), entity.getFileName(), request); + return stream; + } + + /** + * 系统文件保存通用接口 + * @param addDTO + * @return + */ + public ResponseDTO saveFile(FileAddDTO addDTO, RequestTokenBO requestToken) { + FileEntity entity = SmartBeanUtil.copy(addDTO,FileEntity.class); + entity.setCreaterUser(requestToken.getRequestUserId()); + entity.setCreateTime(new Date()); + fileDao.insert(entity); + return ResponseDTO.succ(); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceAliYun.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceAliYun.java new file mode 100644 index 00000000..1872be3e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceAliYun.java @@ -0,0 +1,182 @@ +package com.gangquan360.smartadmin.module.file.service; + +import com.aliyun.oss.OSSClient; +import com.aliyun.oss.model.OSSObject; +import com.aliyun.oss.model.ObjectMetadata; +import com.aliyun.oss.model.PutObjectRequest; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.file.constant.FileResponseCodeConst; +import com.gangquan360.smartadmin.module.file.constant.FileServiceNameConst; +import com.gangquan360.smartadmin.module.file.domain.dto.OSSConfig; +import com.gangquan360.smartadmin.module.file.domain.vo.UploadVO; +import com.gangquan360.smartadmin.module.systemconfig.SystemConfigService; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigEnum; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/10 0010 上午 8:29 + * @since JDK1.8 + */ +@Slf4j +@Service(FileServiceNameConst.ALI_OSS) +public class FileServiceAliYun implements IFileService { + + @Autowired + private SystemConfigService systemConfigService; + + OSSClient ossClient = null; + + String accessConfig = null; + + @Override + public ResponseDTO fileUpload(MultipartFile multipartFile, String path) { + OSSConfig ossConfig = systemConfigService.selectByKey2Obj(SystemConfigEnum.Key.ALI_OSS.name(), OSSConfig.class); + try { + InputStream inputStream = new ByteArrayInputStream(multipartFile.getBytes()); + if (! ossConfig.toString().equals(accessConfig)) { + //accessKeyId 发生变动自动创建新的 + if (ossClient != null) { + ossClient.shutdown(); + } + ossClient = new OSSClient(ossConfig.getEndpoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret()); + accessConfig = ossConfig.toString(); + } + String uuid = UUID.randomUUID().toString().replace("-", ""); + String ossPath = path + "/" + uuid; + String fileName = multipartFile.getOriginalFilename(); + String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1); + ObjectMetadata meta = new ObjectMetadata(); + meta.setContentDisposition("attachment;filename=" + fileName); + Map userMetadata = new HashMap(); + userMetadata.put("fileName", fileName); + userMetadata.put("fileExt", fileExt); + userMetadata.put("fileSize", String.valueOf(multipartFile.getSize())); + meta.setUserMetadata(userMetadata); + meta.setContentType(this.getContentType(fileExt)); + PutObjectRequest putObjectRequest = new PutObjectRequest(ossConfig.getBucketName(), ossPath, inputStream, meta); + ossClient.putObject(putObjectRequest); + UploadVO localUploadVO = new UploadVO(); + localUploadVO.setUrl(this.getUrl(ossPath, ossConfig.getBucketName(), ossClient)); + localUploadVO.setFileName(fileName); + localUploadVO.setFilePath(ossPath); + localUploadVO.setFileSize(multipartFile.getSize()); + return ResponseDTO.succData(localUploadVO); + } catch (Exception e) { + log.error("ALI UPLOAD ERROR : {}", e); + } + return ResponseDTO.wrap(FileResponseCodeConst.UPLOAD_ERROR); + } + + @Override + public ResponseDTO getFileUrl(String path) { + OSSConfig ossConfig = systemConfigService.selectByKey2Obj(SystemConfigEnum.Key.ALI_OSS.name(), OSSConfig.class); + try { + if (! ossConfig.toString().equals(accessConfig)) { + //accessKeyId 发生变动自动创建新的 + if (ossClient != null) { + ossClient.shutdown(); + } + ossClient = new OSSClient(ossConfig.getEndpoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret()); + accessConfig = ossConfig.toString(); + } + String url = this.getUrl(path, ossConfig.getBucketName(), ossClient); + return ResponseDTO.succData(url); + } catch (Exception e) { + log.error("ALI getFileUrl ERROR : {}", e); + } + return ResponseDTO.wrap(FileResponseCodeConst.URL_ERROR); + } + + private String getUrl(String path, String bucketName, OSSClient ossClient) { + Date expiration = new Date(System.currentTimeMillis() + (60 * 60 * 1000)); + URL url = ossClient.generatePresignedUrl(bucketName, path, expiration); + return url.toString(); + } + + /** + * 流式下载(名称为原文件) + */ + @Override + public ResponseEntity fileDownload(String key, String fileName, HttpServletRequest request) { + File file = this.getFile(key, fileName); + if (file == null) { + throw new RuntimeException("文件不存在"); + } + return this.downloadMethod(file, request); + } + + /** + * 根据osskey获取文件 + * + * @param key + * @return + */ + public File getFile(String key, String fileName) { + OSSConfig ossConfig = systemConfigService.selectByKey2Obj(SystemConfigEnum.Key.ALI_OSS.name(), OSSConfig.class); + if (! ossConfig.toString().equals(accessConfig)) { + //accessKeyId 发生变动自动创建新的 + if (ossClient != null) { + ossClient.shutdown(); + } + ossClient = new OSSClient(ossConfig.getEndpoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret()); + accessConfig = ossConfig.toString(); + } + //获取oss对象 + OSSObject ossObject = ossClient.getObject(ossConfig.getBucketName(), key); + if (StringUtils.isBlank(fileName)) { + // 获取元信息 + ObjectMetadata objectMetadata = ossObject.getObjectMetadata(); + // 获取下载时文件名 + Map userMetadata = objectMetadata.getUserMetadata(); + fileName = userMetadata == null ? "" : userMetadata.get("filename"); + if (StringUtils.isBlank(fileName)) { + fileName = objectMetadata.getContentDisposition(); + } + } + // 创建文件 + File file = new File(fileName); + // 获得输入流 + InputStream objectContent = ossObject.getObjectContent(); + try { + // 输入流转换为字节流 + byte[] buffer = FileCopyUtils.copyToByteArray(objectContent); + // 字节流写入文件 + FileCopyUtils.copy(buffer, file); + // 关闭输入流 + objectContent.close(); + } catch (IOException e) { + log.error("文件获取失败:" + e); + return null; + } finally { + try { + ossObject.close(); + } catch (IOException e) { + log.error("", e); + } + } + return file; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceLocal.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceLocal.java new file mode 100644 index 00000000..a11a20ce --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceLocal.java @@ -0,0 +1,123 @@ +package com.gangquan360.smartadmin.module.file.service; + +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.file.constant.FileResponseCodeConst; +import com.gangquan360.smartadmin.module.file.constant.FileServiceNameConst; +import com.gangquan360.smartadmin.module.file.domain.vo.UploadVO; +import com.gangquan360.smartadmin.module.systemconfig.SystemConfigDao; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigEnum; +import com.gangquan360.smartadmin.module.systemconfig.domain.entity.SystemConfigEntity; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.IOException; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/11 0011 下午 16:15 + * @since JDK1.8 + */ +@Slf4j +@Service(FileServiceNameConst.LOCAL) +public class FileServiceLocal implements IFileService { + + @Autowired + private SystemConfigDao systemConfigDao; + + @Value("${spring.servlet.multipart.max-file-size}") + private String maxFileSize; + + @Value("${file-upload-service.path}") + private String fileParentPath; + + private static final Long DEFAULT_SIZE = 10 * 1024 * 1024L; + + @Override + public ResponseDTO fileUpload(MultipartFile multipartFile, String path) { + if (null == multipartFile) { + return ResponseDTO.wrap(FileResponseCodeConst.FILE_EMPTY); + } + Long maxSize = DEFAULT_SIZE; + if (StringUtils.isNotEmpty(maxFileSize)) { + String maxSizeStr = maxFileSize.toLowerCase().replace("mb", ""); + maxSize = Integer.valueOf(maxSizeStr) * 1024 * 1024L; + } + if (multipartFile.getSize() > maxSize) { + return ResponseDTO.wrap(FileResponseCodeConst.FILE_SIZE_ERROR, String.format(FileResponseCodeConst.FILE_SIZE_ERROR.getMsg(), maxFileSize)); + } + String filePath = fileParentPath; + String urlParent = this.localUrlPrefix(); + if (urlParent == null) { + return ResponseDTO.wrap(FileResponseCodeConst.LOCAL_UPDATE_PREFIX_ERROR); + } + if (StringUtils.isNotEmpty(path)) { + filePath = filePath + path + "/"; + urlParent = urlParent + path + "/"; + } + File directory = new File(filePath); + if (!directory.exists()) { + // 目录不存在,新建 + directory.mkdirs(); + } + UploadVO localUploadVO = new UploadVO(); + String newFileName; + File fileTemp; + String originalFileName; + originalFileName = multipartFile.getOriginalFilename(); + newFileName = this.generateFileName(originalFileName); + fileTemp = new File(new File(filePath + newFileName).getAbsolutePath()); + try { + multipartFile.transferTo(fileTemp); + localUploadVO.setUrl(urlParent + newFileName); + localUploadVO.setFileName(newFileName); + localUploadVO.setFilePath(path + "/" + newFileName); + localUploadVO.setFileSize(multipartFile.getSize()); + } catch (IOException e) { + if (fileTemp.exists() && fileTemp.isFile()) { + fileTemp.delete(); + } + log.error("", e); + return ResponseDTO.wrap(FileResponseCodeConst.UPLOAD_ERROR); + } + return ResponseDTO.succData(localUploadVO); + } + + @Override + public ResponseDTO getFileUrl(String path) { + String urlParent = this.localUrlPrefix(); + if (urlParent == null) { + return ResponseDTO.wrap(FileResponseCodeConst.LOCAL_UPDATE_PREFIX_ERROR); + } + String url = urlParent + path; + return ResponseDTO.succData(url); + } + + private String localUrlPrefix() { + SystemConfigEntity configEntity = systemConfigDao.getByKey(SystemConfigEnum.Key.LOCAL_UPLOAD_URL_PREFIX.name()); + if (configEntity == null) { + return null; + } + return configEntity.getConfigValue(); + } + + @Override + public ResponseEntity fileDownload(String key, String fileName, HttpServletRequest request) { + + String url = fileParentPath + key; + // 创建文件 + File file = new File(url); + return this.downloadMethod(file, request); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceQiNiuYun.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceQiNiuYun.java new file mode 100644 index 00000000..f09aeb6a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/FileServiceQiNiuYun.java @@ -0,0 +1,175 @@ +package com.gangquan360.smartadmin.module.file.service; + +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.file.constant.FileResponseCodeConst; +import com.gangquan360.smartadmin.module.file.constant.FileServiceNameConst; +import com.gangquan360.smartadmin.module.file.domain.dto.OSSConfig; +import com.gangquan360.smartadmin.module.file.domain.vo.UploadVO; +import com.gangquan360.smartadmin.module.systemconfig.SystemConfigService; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigEnum; +import com.qiniu.http.Response; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.UploadManager; +import com.qiniu.util.Auth; +import lombok.extern.slf4j.Slf4j; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.ResponseBody; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.UUID; + +/** + * [ 七牛云 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/10 0010 上午 8:30 + * @since JDK1.8 + */ +@Slf4j +@Service(FileServiceNameConst.QI_NIU_OSS) +public class FileServiceQiNiuYun implements IFileService { + + //1小时,可以自定义链接过期时间 + private static final Long expireInSeconds = 3600L; + + @Autowired + private SystemConfigService systemConfigService; + + UploadManager ossClient = null; + + String accessConfig = null; + + String token = null; + + @Override + public ResponseDTO fileUpload(MultipartFile multipartFile, String path) { + OSSConfig ossConfig = systemConfigService.selectByKey2Obj(SystemConfigEnum.Key.QI_NIU_OSS.name(), OSSConfig.class); + try { + InputStream inputStream = new ByteArrayInputStream(multipartFile.getBytes()); + if (! ossConfig.toString().equals(accessConfig)) { + //accessKeyId 发生变动自动重新创建新的UploadManager + ossClient = new UploadManager(new Configuration()); + token = Auth.create(ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret()). + uploadToken(ossConfig.getBucketName()); + accessConfig = ossConfig.toString(); + } + String uuid = UUID.randomUUID().toString().replace("-", ""); + String ossPath = path + "/" + uuid; + String fileName = multipartFile.getOriginalFilename(); + String fileExt = fileName.substring(fileName.lastIndexOf(".") + 1); + String mime = this.getContentType(fileExt); + Response res = ossClient.put(inputStream, ossPath, token, null, mime); + if (! res.isOK()) { + log.error("QINIU fileUpload ERROR : {}", res.toString()); + return ResponseDTO.wrap(FileResponseCodeConst.UPLOAD_ERROR); + } + UploadVO localUploadVO = new UploadVO(); + localUploadVO.setUrl(this.getFileUrl(ossPath).getData()); + localUploadVO.setFileName(fileName); + localUploadVO.setFilePath(ossPath); + localUploadVO.setFileSize(multipartFile.getSize()); + return ResponseDTO.succData(localUploadVO); + } catch (Exception e) { + log.error("QINIU fileUpload ERROR : {}", e); + } + return ResponseDTO.wrap(FileResponseCodeConst.UPLOAD_ERROR); + } + + @Override + public ResponseDTO getFileUrl(String path) { + OSSConfig ossConfig = systemConfigService.selectByKey2Obj(SystemConfigEnum.Key.QI_NIU_OSS.name(), OSSConfig.class); + try { + if (! ossConfig.toString().equals(accessConfig)) { + //accessKeyId 发生变动自动重新创建新的UploadManager + ossClient = new UploadManager(new Configuration()); + token = Auth.create(ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret()). + uploadToken(ossConfig.getBucketName()); + accessConfig = ossConfig.toString(); + } + String encodedFileName = URLEncoder.encode(path, "utf-8"); + String domainOfBucket = ossConfig.getEndpoint(); + String publicUrl = String.format("%s/%s", domainOfBucket, encodedFileName); + String accessKey = ossConfig.getAccessKeyId(); + String secretKey = ossConfig.getAccessKeySecret(); + Auth auth = Auth.create(accessKey, secretKey); + //1小时,可以自定义链接过期时间 + long expireInSeconds = 3600; + String finalUrl = auth.privateDownloadUrl(publicUrl, expireInSeconds); + return ResponseDTO.succData(finalUrl); + } catch (Exception e) { + log.error("QINIU getFileUrl ERROR : {}", e); + } + return ResponseDTO.wrap(FileResponseCodeConst.URL_ERROR); + } + + @Override + public ResponseEntity fileDownload(String key, String fileName, HttpServletRequest request) { + File file = this.getFile(key, fileName); + if (file == null) { + throw new RuntimeException("文件不存在"); + } + return this.downloadMethod(file, request); + } + + /** + * 获取下载路径 + */ + public String getDownloadUrl(String key) { + OSSConfig ossConfig = systemConfigService.selectByKey2Obj(SystemConfigEnum.Key.QI_NIU_OSS.name(), OSSConfig.class); + String domainOfBucket = ossConfig.getEndpoint(); + String finalUrl = ""; + try { + String encodedFileName = URLEncoder.encode(key, "utf-8").replace("+", "%20"); + String publicUrl = String.format("%s/%s", domainOfBucket, encodedFileName); + Auth auth = Auth.create(ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret()); + finalUrl = auth.privateDownloadUrl(publicUrl, expireInSeconds); + } catch (Exception e) { + log.error("QINIU download ERROR : {}", e); + } + return finalUrl; + } + + /** + * 获取文件 + */ + public File getFile(String key, String fileName) { + String finalUrl = getDownloadUrl(key); + OkHttpClient client = new OkHttpClient(); + Request req = new Request.Builder().url(finalUrl).build(); + okhttp3.Response resp = null; + File file = new File(fileName); + try { + resp = client.newCall(req).execute(); + if (resp.isSuccessful()) { + ResponseBody body = resp.body(); + InputStream objectContent = body.byteStream(); + // 输入流转换为字节流 + byte[] buffer = FileCopyUtils.copyToByteArray(objectContent); + // 字节流写入文件 + FileCopyUtils.copy(buffer, file); + // 关闭输入流 + objectContent.close(); + } + + } catch (IOException e) { + log.error("文件获取失败:" + e); + return null; + } finally { + } + return file; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/IFileService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/IFileService.java new file mode 100644 index 00000000..0cc35f36 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/file/service/IFileService.java @@ -0,0 +1,152 @@ +package com.gangquan360.smartadmin.module.file.service; + +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.file.domain.vo.UploadVO; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.util.FileCopyUtils; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.UUID; + +/** + * 文件服务接口 + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/11 0011 下午 16:42 + * @since JDK1.8 + */ +public interface IFileService { + + /** + * 文件上传 + * + * @param multipartFile + * @param path + * @return + */ + ResponseDTO fileUpload(MultipartFile multipartFile, String path); + + /** + * 获取文件url + * + * @param path + * @return + */ + ResponseDTO getFileUrl(String path); + + /** + * 文件下载 + * + * @param key + * @param fileName + * @param request + * @return + */ + ResponseEntity fileDownload(String key, String fileName, HttpServletRequest request); + + /** + * 生成文件名字 + * 当前年月日时分秒 +32位 uuid + 文件格式后缀 + * + * @param originalFileName + * @return String + */ + default String generateFileName(String originalFileName) { + String time = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddhhmms")); + String uuid = UUID.randomUUID().toString().replaceAll("-", ""); + String fileType = originalFileName.substring(originalFileName.lastIndexOf(".")); + return time + uuid + fileType; + } + + /** + * 获取文件类型 + * + * @param fileExt + * @return + */ + default String getContentType(String fileExt) { + // 文件的后缀名 + if ("bmp".equalsIgnoreCase(fileExt)) { + return "image/bmp"; + } + if ("gif".equalsIgnoreCase(fileExt)) { + return "image/gif"; + } + if ("jpeg".equalsIgnoreCase(fileExt) || "jpg".equalsIgnoreCase(fileExt) || ".png".equalsIgnoreCase(fileExt)) { + return "image/jpeg"; + } + if ("png".equalsIgnoreCase(fileExt)) { + return "image/png"; + } + if ("html".equalsIgnoreCase(fileExt)) { + return "text/html"; + } + if ("txt".equalsIgnoreCase(fileExt)) { + return "text/plain"; + } + if ("vsd".equalsIgnoreCase(fileExt)) { + return "application/vnd.visio"; + } + if ("ppt".equalsIgnoreCase(fileExt) || "pptx".equalsIgnoreCase(fileExt)) { + return "application/vnd.ms-powerpoint"; + } + if ("doc".equalsIgnoreCase(fileExt) || "docx".equalsIgnoreCase(fileExt)) { + return "application/msword"; + } + if ("xml".equalsIgnoreCase(fileExt)) { + return "text/xml"; + } + return ""; + } + + default ResponseEntity downloadMethod(File file, HttpServletRequest request) { + HttpHeaders heads = new HttpHeaders(); + heads.add(HttpHeaders.CONTENT_TYPE, "application/octet-stream; charset=utf-8"); + String fileName = file.getName(); + try { + if (request.getHeader("User-Agent").toLowerCase().indexOf("firefox") > 0) { + // firefox浏览器 + fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1"); + } else if (request.getHeader("User-Agent").toUpperCase().indexOf("MSIE") > 0) { + // IE浏览器 + fileName = URLEncoder.encode(fileName, "UTF-8"); + } else if (request.getHeader("User-Agent").toUpperCase().indexOf("EDGE") > 0) { + // WIN10浏览器 + fileName = URLEncoder.encode(fileName, "UTF-8"); + } else if (request.getHeader("User-Agent").toUpperCase().indexOf("CHROME") > 0) { + // 谷歌 + fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1"); + } else { + //万能乱码问题解决 + fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1"); + } + } catch (UnsupportedEncodingException e) { + // log.error("", e); + } + heads.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName); + try { + InputStream in = new FileInputStream(file); + // 输入流转换为字节流 + byte[] buffer = FileCopyUtils.copyToByteArray(in); + ResponseEntity responseEntity = new ResponseEntity<>(buffer, heads, HttpStatus.OK); + //file.delete(); + return responseEntity; + } catch (Exception e) { + // log.error("", e); + } + return null; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatController.java new file mode 100644 index 00000000..b40c8454 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatController.java @@ -0,0 +1,32 @@ +package com.gangquan360.smartadmin.module.heartbeat; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; + + +@Api(tags = {SwaggerTagConst.Admin.MANAGER_HEART_BEAT}) +@OperateLog +@RestController +public class HeartBeatController { + + @Autowired + private HeartBeatService heartBeatService; + + @PostMapping("/heartBeat/query") + @ApiOperation("查询心跳记录 @author zhuoda") + public ResponseDTO> query(@RequestBody @Valid PageParamDTO pageParamDTO){ + return heartBeatService.pageQuery(pageParamDTO); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordDao.java new file mode 100644 index 00000000..ca9fc96f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordDao.java @@ -0,0 +1,53 @@ +package com.gangquan360.smartadmin.module.heartbeat; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.pagination.Pagination; +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.List; + +/** + * 心跳日志数据库操作 + * + * @author : simajinqiang + * Date: 2018/7/9 + * Time: 17:37 + */ +@Component +@Mapper +public interface HeartBeatRecordDao extends BaseMapper { + + /** + * 新增心跳日志 + * + * @param heartBeatRecordEntity + */ + void insertHeartBeat(HeartBeatRecordEntity heartBeatRecordEntity); + + /** + * 更新心跳日志 + * + * @param id + * @param heartBeatTime + */ + void updateHeartBeatTimeById(@Param("id") Long id, @Param("heartBeatTime") Date heartBeatTime); + + /** + * 查询心跳日志 + * + * @param heartBeatRecordEntity + * @return + */ + HeartBeatRecordEntity query(HeartBeatRecordEntity heartBeatRecordEntity); + + + /** + * 分页查询心跳记录 + * @return + */ + List pageQuery(Pagination page); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordEntity.java new file mode 100644 index 00000000..3df2490d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordEntity.java @@ -0,0 +1,42 @@ +package com.gangquan360.smartadmin.module.heartbeat; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 心跳记录日志 + * User: simajinqiang + * Date: 2018/7/9 + * Time: 11:11 + */ +@Data +@TableName(value = "t_heart_beat_record") +public class HeartBeatRecordEntity extends BaseEntity implements Serializable { + + /** + * 项目名字 + */ + private String projectPath; + /** + * 服务器ip + */ + private String serverIp; + /** + * 进程号 + */ + private Integer processNo; + /** + * 进程开启时间 + */ + private Date processStartTime; + /** + * 心跳当前时间 + */ + private Date heartBeatTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordVO.java new file mode 100644 index 00000000..bea39703 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatRecordVO.java @@ -0,0 +1,36 @@ +package com.gangquan360.smartadmin.module.heartbeat; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 心跳记录日志 + * User: simajinqiang + * Date: 2018/7/9 + * Time: 11:11 + */ +@Data +public class HeartBeatRecordVO implements Serializable { + + private Integer id; + + @ApiModelProperty("项目名字") + private String projectPath; + + @ApiModelProperty("服务器ip") + private String serverIp; + + @ApiModelProperty("进程号") + private Integer processNo; + + @ApiModelProperty("进程开启时间") + private Date processStartTime; + + @ApiModelProperty("心跳当前时间") + private Date heartBeatTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatService.java new file mode 100644 index 00000000..21579985 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/heartbeat/HeartBeatService.java @@ -0,0 +1,91 @@ +package com.gangquan360.smartadmin.module.heartbeat; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.common.heartbeat.AbstractHeartBeatCommand; +import com.gangquan360.smartadmin.common.heartbeat.HeartBeatConfig; +import com.gangquan360.smartadmin.common.heartbeat.HeartBeatLogger; +import com.gangquan360.smartadmin.common.heartbeat.HeartBeatRecordDTO; +import com.gangquan360.smartadmin.config.SmartHeartBeatConfig; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import lombok.extern.slf4j.Slf4j; +import org.apache.poi.ss.formula.functions.T; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Slf4j +@Service +public class HeartBeatService extends AbstractHeartBeatCommand { + + @Autowired + private HeartBeatRecordDao heartBeatRecordDao; + + @Autowired + private SmartHeartBeatConfig heartBeatConfig; + + @PostConstruct + public void init() { + + HeartBeatConfig config = HeartBeatConfig.builder().delayHandlerTime(heartBeatConfig.getDelayHandlerTime()).intervalTime(heartBeatConfig.getIntervalTime()).build(); + + super.init(config, new HeartBeatLogger() { + @Override + public void error(String string) { + log.error(string); + } + + @Override + public void error(String string, Throwable e) { + log.error(string, e); + } + + @Override + public void info(String string) { + log.info(string); + } + }); + } + + @PreDestroy + @Override + public void destroy() { + super.destroy(); + } + + @Override + public void handler(HeartBeatRecordDTO heartBeatRecordDTO) { + HeartBeatRecordEntity heartBeatRecordEntity = SmartBeanUtil.copy(heartBeatRecordDTO, HeartBeatRecordEntity.class); + HeartBeatRecordEntity heartBeatRecordOld = heartBeatRecordDao.query(heartBeatRecordEntity); + if (heartBeatRecordOld == null) { + heartBeatRecordDao.insertHeartBeat(heartBeatRecordEntity); + } else { + heartBeatRecordDao.updateHeartBeatTimeById(heartBeatRecordOld.getId(), heartBeatRecordEntity.getHeartBeatTime()); + } + + } + + public ResponseDTO> pageQuery(PageParamDTO pageParamDTO) { + Page pageQueryInfo = SmartPaginationUtil.convert2PageQueryInfo(pageParamDTO); + List recordVOList = heartBeatRecordDao.pageQuery(pageQueryInfo); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(pageQueryInfo, recordVOList); + return ResponseDTO.succData(pageResultDTO); + + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorDao.java new file mode 100644 index 00000000..c2e31e45 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorDao.java @@ -0,0 +1,37 @@ +package com.gangquan360.smartadmin.module.idgenerator; + + +import com.gangquan360.smartadmin.module.idgenerator.domain.IdGeneratorEntity; +import com.gangquan360.smartadmin.module.idgenerator.domain.IdGeneratorLastNumberDTO; +import com.gangquan360.smartadmin.module.idgenerator.domain.IdGeneratorRecordDTO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * + * zhuo + */ +@Mapper +public interface IdGeneratorDao { + + IdGeneratorLastNumberDTO selectLastNumber(Long id); + + List selectAll(); + + void updateLastNumber(@Param("generatorId") Long generatorId, @Param("lastNumber") Long lastNumber); + + int replaceIdGeneratorRecord(@Param("generatorId") Long generatorId,// + @Param("year") int year,// + @Param("month") int month,// + @Param("day") int day,// + @Param("lastNumber") Long lastNumber); + + IdGeneratorRecordDTO selectHistoryLastNumber(@Param("generatorId") Long generatorId, + @Param("year") int year, + @Param("month") int month, + @Param("day") int day); + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorManager.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorManager.java new file mode 100644 index 00000000..de976b3b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorManager.java @@ -0,0 +1,66 @@ +package com.gangquan360.smartadmin.module.idgenerator; + +import com.gangquan360.smartadmin.common.exception.SmartBusinessException; +import com.gangquan360.smartadmin.module.idgenerator.domain.IdGeneratorLastNumberDTO; +import com.gangquan360.smartadmin.module.idgenerator.domain.IdGeneratorPOJO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.util.Date; + +/** + * 全局id生成器 + * zhuo + */ +@Service +public class IdGeneratorManager { + + @Autowired + private IdGeneratorDao idGeneratorDao; + + @Transactional(rollbackFor = Exception.class) + public long[] generate(IdGeneratorPOJO idGeneratorPOJO, int stepLength) { + IdGeneratorLastNumberDTO idGeneratorLastNumberDTO = idGeneratorDao.selectLastNumber(idGeneratorPOJO.getIdGeneratorEntity().getId()); + if (idGeneratorLastNumberDTO == null) { + throw new SmartBusinessException("IdGenerator, id 数据库不存在" + idGeneratorPOJO.getIdGeneratorEntity().getId()); + } + + Long lastNumber = idGeneratorLastNumberDTO.getLastNumber(); + if (lastNumber == null) { + lastNumber = idGeneratorPOJO.getIdGeneratorEntity().getInitNumber(); + } else { + lastNumber = lastNumber + 1; + } + + Date updateTime = idGeneratorLastNumberDTO.getUpdateTime(); + if (updateTime == null) { + updateTime = idGeneratorLastNumberDTO.getDatabaseTime(); + } + + Long startValue = -1L, endValue = -1L; + switch (idGeneratorPOJO.getIdGeneratorRuleTypeEnum()) { + case NO_CYCLE: + startValue = lastNumber.longValue(); + endValue = startValue + stepLength; + break; + default: + SimpleDateFormat format = new SimpleDateFormat(idGeneratorPOJO.getIdGeneratorRuleTypeEnum().getExt()); + if (format.format(idGeneratorLastNumberDTO.getDatabaseTime()).equals(format.format(updateTime))) { + startValue = lastNumber.longValue(); + endValue = startValue + stepLength; + } else { + startValue = idGeneratorPOJO.getIdGeneratorEntity().getInitNumber(); + endValue = startValue + stepLength; + } + break; + } + + idGeneratorDao.updateLastNumber(idGeneratorPOJO.getIdGeneratorEntity().getId(), endValue - 1); + LocalDate localDate = LocalDate.now(); + idGeneratorDao.replaceIdGeneratorRecord(idGeneratorPOJO.getIdGeneratorEntity().getId(), localDate.getYear(), localDate.getMonthValue(), localDate.getDayOfMonth(), endValue - 1); + return new long[]{startValue, endValue}; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorService.java new file mode 100644 index 00000000..079c6a41 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/IdGeneratorService.java @@ -0,0 +1,140 @@ +package com.gangquan360.smartadmin.module.idgenerator; + +import com.gangquan360.smartadmin.common.exception.SmartBusinessException; +import com.gangquan360.smartadmin.module.idgenerator.constant.IdGeneratorEnum; +import com.gangquan360.smartadmin.module.idgenerator.constant.IdGeneratorRuleTypeEnum; +import com.gangquan360.smartadmin.module.idgenerator.domain.IdGeneratorEntity; +import com.gangquan360.smartadmin.module.idgenerator.domain.IdGeneratorPOJO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * 全局id生成器 + * zhuo + */ +@Slf4j +@Service +public class IdGeneratorService { + + private Map idGeneratorMap; + + @Autowired + private IdGeneratorDao idGeneratorDao; + + @Autowired + private IdGeneratorManager idGeneratorManager; + + @PostConstruct + void init() { + this.idGeneratorMap = new ConcurrentHashMap<>(); + List idGeneratorEntities = idGeneratorDao.selectAll(); + if (idGeneratorEntities != null) { + idGeneratorEntities.forEach(e -> { + IdGeneratorRuleTypeEnum idGeneratorRuleTypeEnum = this.getIdGeneratorRuleTypeEnum(e.getRuleType()); + if (idGeneratorRuleTypeEnum != null) { + IdGeneratorPOJO idGeneratorPOJO = new IdGeneratorPOJO(idGeneratorRuleTypeEnum, e); + String ruleFormat = e.getRuleFormat(); + int startNInx = ruleFormat.indexOf("[n"); + int endNInx = ruleFormat.indexOf("n]"); + idGeneratorPOJO.setNumberCount(endNInx - startNInx); + idGeneratorPOJO.setHaveDay(ruleFormat.contains("[dd]")); + idGeneratorPOJO.setHaveMonth(ruleFormat.contains("[mm]")); + idGeneratorPOJO.setHaveYear(ruleFormat.contains("[yyyy]")); + this.idGeneratorMap.put(e.getId(), idGeneratorPOJO); + } else { + log.error("cannot find rule type , id : {}, key name : {} ", e.getId(), e.getKeyName()); + } + }); + } + } + + public String generate(IdGeneratorEnum idGeneratorEnum) { + return generate(idGeneratorEnum, 1).get(0); + } + + /** + * @param idGeneratorEnum + * @param stepLength + * @return + */ + public List generate(IdGeneratorEnum idGeneratorEnum, int stepLength) { + IdGeneratorPOJO idGeneratorPOJO = validateParams(idGeneratorEnum, stepLength); + long[] generateIds = idGeneratorManager.generate(idGeneratorPOJO, stepLength); + Long startValue = generateIds[0], endValue = generateIds[1]; + LocalDate now = LocalDate.now(); + String year = String.valueOf(now.getYear()); + String month = now.getMonthValue() > 9 ? String.valueOf(now.getMonthValue()) : "0" + now.getMonthValue(); + String day = now.getDayOfMonth() > 9 ? String.valueOf(now.getDayOfMonth()) : "0" + now.getDayOfMonth(); + ArrayList codeList = new ArrayList<>(); + for (long loop = startValue; loop < endValue; loop++) { + String generateBillCode = this.replaceAndFill(idGeneratorPOJO, loop, year, month, day); + codeList.add(generateBillCode); + } + return codeList; + } + + private IdGeneratorRuleTypeEnum getIdGeneratorRuleTypeEnum(String ruleType) { + for (IdGeneratorRuleTypeEnum en : IdGeneratorRuleTypeEnum.values()) { + if (en.name().equalsIgnoreCase(ruleType)) { + return en; + } + } + return null; + } + + private IdGeneratorPOJO validateParams(IdGeneratorEnum idGeneratorEnum, int stepLength) { + if (stepLength < 1) { + throw new SmartBusinessException("IdGenerator, step过短" + stepLength); + } + + IdGeneratorPOJO idGeneratorPOJO = this.idGeneratorMap.get(idGeneratorEnum.getId()); + if (idGeneratorPOJO == null) { + throw new SmartBusinessException("IdGenerator, id 不存在" + idGeneratorEnum); + } + return idGeneratorPOJO; + } + + /** + * 替换特殊rule,即替换[yyyy][mm][dd][nnn]等规则 + */ + private String replaceAndFill(IdGeneratorPOJO idGeneratorPOJO, Long number, String year, String month, String day) { + StringBuilder numberStringBuilder = new StringBuilder(); + int curNumberCount = String.valueOf(number).length(); + + if (idGeneratorPOJO.getNumberCount() > curNumberCount) { + int remain = idGeneratorPOJO.getNumberCount() - curNumberCount; + for (int i = 0; i < remain; i++) { + numberStringBuilder.append(0); + } + } + numberStringBuilder.append(number); + + StringBuilder nStringBuilder = new StringBuilder(); + nStringBuilder.append("\\["); + for (int i = 0; i < idGeneratorPOJO.getNumberCount(); i++) { + nStringBuilder.append("n"); + } + nStringBuilder.append("\\]"); + + String tempRuleFormat = new String(idGeneratorPOJO.getIdGeneratorEntity().getRuleFormat().getBytes()); + if (idGeneratorPOJO.isHaveYear()) { + tempRuleFormat = tempRuleFormat.replaceAll("\\[yyyy\\]", year); + } + if (idGeneratorPOJO.isHaveMonth()) { + tempRuleFormat = tempRuleFormat.replaceAll("\\[mm\\]", month); + } + if (idGeneratorPOJO.isHaveDay()) { + tempRuleFormat = tempRuleFormat.replaceAll("\\[dd\\]", day); + } + + return tempRuleFormat.replaceAll(nStringBuilder.toString(), numberStringBuilder.toString()); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/constant/IdGeneratorEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/constant/IdGeneratorEnum.java new file mode 100644 index 00000000..9d72dda2 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/constant/IdGeneratorEnum.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.module.idgenerator.constant; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/8 0008 下午 13:43 + * @since JDK1.8 + */ +public enum IdGeneratorEnum { + + + /** + * 测试generate + */ + TEST_ID_GENERATOR(2, "testIdGenerator"), + + + ORDER(1, "order"); + + private int id; + private String keyName; + + IdGeneratorEnum(int id, String keyName) { + this.id = id; + this.keyName = keyName; + } + + @Override + public String toString() { + return "IdGeneratorEnum{" + "id=" + id + ", keyName='" + keyName + '\'' + '}'; + } + + public int getId() { + return id; + } + + public String getKeyName() { + return keyName; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/constant/IdGeneratorRuleTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/constant/IdGeneratorRuleTypeEnum.java new file mode 100644 index 00000000..d087354b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/constant/IdGeneratorRuleTypeEnum.java @@ -0,0 +1,40 @@ +package com.gangquan360.smartadmin.module.idgenerator.constant; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/8 0008 下午 13:43 + * @since JDK1.8 + */ +public enum IdGeneratorRuleTypeEnum { + /** + * 没有周期 + */ + NO_CYCLE(""), + /** + * 年周期 + */ + YEAR_CYCLE("yyyy"), + /** + * 月周期 + */ + MONTH_CYCLE("yyyyMM"), + /** + * 日周期 + */ + DAY_CYCLE("yyyyMMdd"); + + private String ext; + + IdGeneratorRuleTypeEnum(String ext) { + this.ext = ext; + } + + public String getExt() { + return ext; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorEntity.java new file mode 100644 index 00000000..a245ff53 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorEntity.java @@ -0,0 +1,47 @@ +package com.gangquan360.smartadmin.module.idgenerator.domain; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * @author sun + * @Auther: anders + * @Date: 2018/8/7 0007 13:33 + * @Description: + */ +@Data +@TableName(value = "t_id_generator") +public class IdGeneratorEntity extends BaseEntity implements Serializable { + + private static final long serialVersionUID = 5582354131134766548L; + /** + * 英文key + */ + private String keyName; + /** + * 规则格式 + */ + private String ruleFormat; + /** + * 类型 + */ + private String ruleType; + /** + * 初始值 + */ + private Long initNumber; + /** + * 上次产生的id + */ + private Long lastNumber; + /** + * 备注 + */ + private String remark; + private Date updateTime; + private Date createTime; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorLastNumberDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorLastNumberDTO.java new file mode 100644 index 00000000..771c7b96 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorLastNumberDTO.java @@ -0,0 +1,38 @@ +package com.gangquan360.smartadmin.module.idgenerator.domain; + +import java.util.Date; + +/** + * @Auther: yandanyang + * @Date: 2018/8/7 0007 13:33 + * @Description: + */ +public class IdGeneratorLastNumberDTO { + private Date updateTime; + private Long lastNumber; + private Date databaseTime; + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public Long getLastNumber() { + return lastNumber; + } + + public void setLastNumber(Long lastNumber) { + this.lastNumber = lastNumber; + } + + public Date getDatabaseTime() { + return databaseTime; + } + + public void setDatabaseTime(Date databaseTime) { + this.databaseTime = databaseTime; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorPOJO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorPOJO.java new file mode 100644 index 00000000..210bfc26 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorPOJO.java @@ -0,0 +1,71 @@ +package com.gangquan360.smartadmin.module.idgenerator.domain; + +import com.gangquan360.smartadmin.module.idgenerator.constant.IdGeneratorRuleTypeEnum; + +/** + * @Auther: yandanyang + * @Date: 2018/8/7 0007 13:33 + * @Description: + */ +public class IdGeneratorPOJO { + + private IdGeneratorRuleTypeEnum idGeneratorRuleTypeEnum; + private IdGeneratorEntity idGeneratorEntity; + private int numberCount = 0; + private boolean haveYear = false; + private boolean haveMonth = false; + private boolean haveDay = false; + + public IdGeneratorPOJO(IdGeneratorRuleTypeEnum idGeneratorRuleTypeEnum, IdGeneratorEntity idGeneratorEntity) { + this.idGeneratorRuleTypeEnum = idGeneratorRuleTypeEnum; + this.idGeneratorEntity = idGeneratorEntity; + } + + public IdGeneratorRuleTypeEnum getIdGeneratorRuleTypeEnum() { + return idGeneratorRuleTypeEnum; + } + + public void setIdGeneratorRuleTypeEnum(IdGeneratorRuleTypeEnum idGeneratorRuleTypeEnum) { + this.idGeneratorRuleTypeEnum = idGeneratorRuleTypeEnum; + } + + public IdGeneratorEntity getIdGeneratorEntity() { + return idGeneratorEntity; + } + + public void setIdGeneratorEntity(IdGeneratorEntity idGeneratorEntity) { + this.idGeneratorEntity = idGeneratorEntity; + } + + public int getNumberCount() { + return numberCount; + } + + public void setNumberCount(int numberCount) { + this.numberCount = numberCount; + } + + public boolean isHaveYear() { + return haveYear; + } + + public void setHaveYear(boolean haveYear) { + this.haveYear = haveYear; + } + + public boolean isHaveMonth() { + return haveMonth; + } + + public void setHaveMonth(boolean haveMonth) { + this.haveMonth = haveMonth; + } + + public boolean isHaveDay() { + return haveDay; + } + + public void setHaveDay(boolean haveDay) { + this.haveDay = haveDay; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorRecordDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorRecordDTO.java new file mode 100644 index 00000000..3e13344c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/idgenerator/domain/IdGeneratorRecordDTO.java @@ -0,0 +1,22 @@ +package com.gangquan360.smartadmin.module.idgenerator.domain; + +import lombok.Data; + +/** + * @Auther: yandanyang + * @Date: 2018/8/7 0007 13:33 + * @Description: + */ +@Data +public class IdGeneratorRecordDTO { + + private Long generatorId; + + private Integer year; + + private Integer month; + + private Integer day; + + private Long lastNumber; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/LogService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/LogService.java new file mode 100644 index 00000000..06df389e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/LogService.java @@ -0,0 +1,75 @@ +package com.gangquan360.smartadmin.module.log; + +import com.gangquan360.smartadmin.module.log.orderoperatelog.OrderOperateLogDao; +import com.gangquan360.smartadmin.module.log.orderoperatelog.domain.entity.OrderOperateLogEntity; +import com.gangquan360.smartadmin.module.log.userloginlog.UserLoginLogDao; +import com.gangquan360.smartadmin.module.log.userloginlog.domain.UserLoginLogEntity; +import com.gangquan360.smartadmin.module.log.useroperatelog.UserOperateLogDao; +import com.gangquan360.smartadmin.module.log.useroperatelog.domain.UserOperateLogEntity; +import com.gangquan360.smartadmin.util.SmartThreadFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/4 0004 下午 16:19 + * @since JDK1.8 + */ +@Slf4j +@Service +public class LogService { + + private ThreadPoolExecutor threadPoolExecutor; + + @Autowired + private UserLoginLogDao userLoginLogDao; + + @Autowired + private OrderOperateLogDao orderOperateLogDao; + + @Autowired + private UserOperateLogDao userOperateLogDao; + + @PostConstruct + void init() { + if (threadPoolExecutor == null) { + threadPoolExecutor = new ThreadPoolExecutor(1, 1, 10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2000), SmartThreadFactory.create("LogAspect")); + } + } + + @PreDestroy + void destroy() { + if (threadPoolExecutor != null) { + threadPoolExecutor.shutdown(); + threadPoolExecutor = null; + } + } + + public void addLog(Object object) { + try { + if (object instanceof UserLoginLogEntity) { + threadPoolExecutor.execute(() -> userLoginLogDao.insert((UserLoginLogEntity) object)); + } + if (object instanceof OrderOperateLogEntity) { + threadPoolExecutor.execute(() -> orderOperateLogDao.insert((OrderOperateLogEntity) object)); + } + if (object instanceof UserOperateLogEntity) { + threadPoolExecutor.execute(() -> userOperateLogDao.insert((UserOperateLogEntity) object)); + } + } catch (Throwable e) { + log.error("userLogAfterAdvice:{}", e); + } + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogController.java new file mode 100644 index 00000000..2d847080 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogController.java @@ -0,0 +1,44 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.log.orderoperatelog.constant.OrderOperateLogOrderTypeEnum; +import com.gangquan360.smartadmin.module.log.orderoperatelog.domain.vo.OrderOperateLogVO; +import com.gangquan360.smartadmin.util.SmartStringUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * 单据操作记录Controller + * + * @author lidoudou + * @date: 2018/1/31 16:56 + */ + +@Api(tags = {SwaggerTagConst.Admin.MANAGER_ORDER_OPERATE_LOG}) +@OperateLog +@RestController +public class OrderOperateLogController { + + @Autowired + private OrderOperateLogService orderOperateLogService; + + @ApiOperation(value = "查询单据操作日志", notes = "查询单据操作日志") + @GetMapping("/orderOperateLog/list/{orderId}") + @ApiImplicitParams({@ApiImplicitParam(name = "orderId", value = "业务id", paramType = "path"), @ApiImplicitParam(name = "orderType", value = "业务类型" + OrderOperateLogOrderTypeEnum.INFO, paramType + = "query")}) + public ResponseDTO> list(@PathVariable Long orderId, String orderType) { + List orderTypeList = SmartStringUtil.splitConverToIntSet(orderType, ",").stream().collect(Collectors.toList()); + return orderOperateLogService.listOrderOperateLogsByOrderTypeAndOrderId(orderId, orderTypeList); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogDao.java new file mode 100644 index 00000000..4d075b9e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogDao.java @@ -0,0 +1,30 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.gangquan360.smartadmin.module.log.orderoperatelog.domain.entity.OrderOperateLogEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + *

+ * 各种单据操作记录 + * Mapper 接口 + *

+ * + * @author anders + * @since 2018-01-09 + */ +@Mapper +@Component +public interface OrderOperateLogDao extends BaseMapper { + + List listOrderOperateLogsByOrderTypeAndOrderId(@Param("orderId") Long orderId, @Param("orderTypeList") List orderTypeList); + + List listOrderOperateLogsByOrderTypeAndOrderIds(@Param("orderIds") List orderIds, @Param("orderTypeList") List orderTypeList); + + void batchInsert(List list); + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogService.java new file mode 100644 index 00000000..cea07785 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/OrderOperateLogService.java @@ -0,0 +1,63 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog; + +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.log.orderoperatelog.domain.dto.OrderOperateLogSaveDTO; +import com.gangquan360.smartadmin.module.log.orderoperatelog.domain.entity.OrderOperateLogEntity; +import com.gangquan360.smartadmin.module.log.orderoperatelog.domain.vo.OrderOperateLogVO; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartStringUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + *

+ * 各种单据操作记录 + * 服务实现类 + *

+ * + * @author anders + * @since 2018-01-09 + */ +@Service +public class OrderOperateLogService { + + @Autowired + private OrderOperateLogDao orderOperateLogDao; + + public void batchSaveOrderOperateLog(List orderOperateLogSaveDTOList) { + List entityList = new ArrayList<>(); + orderOperateLogSaveDTOList.forEach(e -> { + OrderOperateLogEntity orderOperateLogEntity = SmartBeanUtil.copy(e, OrderOperateLogEntity.class); + orderOperateLogEntity.setOperateType(e.getOperateType().getCode()); + if (SmartStringUtil.isNotBlank(e.getOperateContent())) { + orderOperateLogEntity.setOperateContent(e.getOperateContent()); + } else { + orderOperateLogEntity.setOperateContent(e.getOperateType().getMsg()); + } + orderOperateLogEntity.setOperateRemark(e.getOperateRemark()); + orderOperateLogEntity.setExtData(e.getExtData()); + orderOperateLogEntity.setCreateTime(new Date()); + orderOperateLogEntity.setOrderType(e.getOrderType().getType()); + entityList.add(orderOperateLogEntity); + }); + //批量添加 + orderOperateLogDao.batchInsert(entityList); + } + + public ResponseDTO> listOrderOperateLogsByOrderTypeAndOrderId(Long orderId, List orderTypeList) { + List orderOperateLogEntities = orderOperateLogDao.listOrderOperateLogsByOrderTypeAndOrderId(orderId, orderTypeList); + List dtoList = orderOperateLogEntities.stream().map(e -> SmartBeanUtil.copy(e, OrderOperateLogVO.class)).collect(Collectors.toList()); + return ResponseDTO.succData(dtoList); + } + + public ResponseDTO> listOrderOperateLogsByOrderTypeAndOrderIds(List orderIds, List orderTypeList) { + List orderOperateLogEntities = orderOperateLogDao.listOrderOperateLogsByOrderTypeAndOrderIds(orderIds, orderTypeList); + List dtoList = orderOperateLogEntities.stream().map(e -> SmartBeanUtil.copy(e, OrderOperateLogVO.class)).collect(Collectors.toList()); + return ResponseDTO.succData(dtoList); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogDefaultEmpEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogDefaultEmpEnum.java new file mode 100644 index 00000000..f066be65 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogDefaultEmpEnum.java @@ -0,0 +1,37 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog.constant; + +/** + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +public enum OrderOperateLogDefaultEmpEnum { + + DEFAULT_EMP(0,"系统"); + + + private Integer empId; + + private String empName; + + OrderOperateLogDefaultEmpEnum(Integer empId,String empName) { + this.empId = empId; + this.empName = empName; + } + + public int getEmpId() { + return empId; + } + + public String getEmpName() { + return empName; + } + + + +} + diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogOperateTypeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogOperateTypeConst.java new file mode 100644 index 00000000..66ed165c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogOperateTypeConst.java @@ -0,0 +1,30 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog.constant; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + +/** + * [ 8001 -8999 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +public class OrderOperateLogOperateTypeConst extends ResponseCodeConst { + + + public static final OrderOperateLogOperateTypeConst ADD = new OrderOperateLogOperateTypeConst(8001, "创建并提交"); + + public static final OrderOperateLogOperateTypeConst UPDATE = new OrderOperateLogOperateTypeConst(8002, "修改并提交"); + + public static final OrderOperateLogOperateTypeConst DELETE = new OrderOperateLogOperateTypeConst(8003, "删除"); + + + private OrderOperateLogOperateTypeConst(int code, String msg) { + super(code, msg); + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogOrderTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogOrderTypeEnum.java new file mode 100644 index 00000000..eeb5a3f0 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/constant/OrderOperateLogOrderTypeEnum.java @@ -0,0 +1,51 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog.constant; + +import java.util.Arrays; +import java.util.Optional; + +/** + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +public enum OrderOperateLogOrderTypeEnum { + + EXAMPLE(1, "样例"); + + + public static final String INFO = ""; + + private int type; + + private String typeName; + + OrderOperateLogOrderTypeEnum(int type, String typeName) { + this.type = type; + this.typeName = typeName; + } + + public int getType() { + return type; + } + + public String getTypeName() { + return typeName; + } + + public static OrderOperateLogOrderTypeEnum getValueByName(String name) { + OrderOperateLogOrderTypeEnum[] values = OrderOperateLogOrderTypeEnum.values(); + Optional first = Arrays.stream(values).filter(e -> e.getTypeName().equals(name)).findFirst(); + if (!first.isPresent()) { + return null; + } + if (!first.isPresent()) { + return null; + } + OrderOperateLogOrderTypeEnum orderType = first.get(); + return orderType; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/dto/OrderOperateLogSaveDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/dto/OrderOperateLogSaveDTO.java new file mode 100644 index 00000000..fb82c244 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/dto/OrderOperateLogSaveDTO.java @@ -0,0 +1,79 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog.domain.dto; + + +import com.gangquan360.smartadmin.module.log.orderoperatelog.constant.OrderOperateLogOperateTypeConst; +import com.gangquan360.smartadmin.module.log.orderoperatelog.constant.OrderOperateLogOrderTypeEnum; +import lombok.Data; +/** + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Data +public class OrderOperateLogSaveDTO { + + /** + * 各种单据的id + */ + private Long orderId; + + /** + * 单据类型 + */ + private OrderOperateLogOrderTypeEnum orderType; + + /** + * 操作类型 + */ + private OrderOperateLogOperateTypeConst operateType; + + /** + *操作类型 对应的中文 + */ + private String operateContent; + + /** + * 操作备注 + */ + private String operateRemark; + + /** + * 员工id + */ + private Long employeeId; + + /** + * 员工名称 + */ + private String employeeName; + + /** + * 额外信息 + */ + private String extData; + + public OrderOperateLogSaveDTO() { + } + + public OrderOperateLogSaveDTO(Long orderId, OrderOperateLogOrderTypeEnum orderType, OrderOperateLogOperateTypeConst operateType, String + operateRemark, Long employeeId, String employeeName, String extData) { + this.orderId = orderId; + this.orderType = orderType; + this.operateType = operateType; + this.operateRemark = operateRemark; + this.employeeId = employeeId; + this.employeeName = employeeName; + this.extData = extData; + } + + @Override + public String toString() { + return "OrderOperateLogSaveDTO{" + "orderId=" + orderId + ", orderType=" + orderType + ", operateType=" + operateType + ", operateRemark='" + + operateRemark + '\'' + ", employeeId=" + employeeId + ", employeeName='" + employeeName + '\'' + ", extData='" + extData + '\'' + '}'; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/dto/SupplierOrderOperateVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/dto/SupplierOrderOperateVO.java new file mode 100644 index 00000000..6329b588 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/dto/SupplierOrderOperateVO.java @@ -0,0 +1,44 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog.domain.dto; + +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; + +/** + * 预存款申请/提取单流水临时文件 + * @author zzr + */ +@Data +public class SupplierOrderOperateVO { + + /** + * 流水类型 + */ + private Integer tradingType; + + /** + * 总重 + */ + private BigDecimal totalWeight; + + /** + * 金额 + */ + private BigDecimal amount; + + /** + * 操作人名称 + */ + private String buyerName; + + /** + * 备注 + */ + private String remark; + + /** + * 创建时间 + */ + private Date createTime; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/entity/OrderOperateLogEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/entity/OrderOperateLogEntity.java new file mode 100644 index 00000000..4836c919 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/entity/OrderOperateLogEntity.java @@ -0,0 +1,60 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Builder; +import lombok.Data; + +import java.util.Date; + +/** + *

+ * 各种单据操作记录 + * + *

+ * + * @author anders + * @since 2018-01-09 + */ + +@Data +@Builder +@TableName("t_order_operate_log") +public class OrderOperateLogEntity extends BaseEntity{ + + /** + * 各种单据的id + */ + private Long orderId; + /** + * 单据类型 + */ + private Integer orderType; + /** + * 操作类型 + */ + private Integer operateType; + /** + * 操作类型 对应的中文 + */ + private String operateContent; + /** + * 操作备注 + */ + private String operateRemark; + /** + * 员工id + */ + private Long employeeId; + /** + * 员工名称 + */ + private String employeeName; + /** + * 额外信息 + */ + private String extData; + + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/vo/OrderOperateLogVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/vo/OrderOperateLogVO.java new file mode 100644 index 00000000..f4d511da --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/orderoperatelog/domain/vo/OrderOperateLogVO.java @@ -0,0 +1,69 @@ +package com.gangquan360.smartadmin.module.log.orderoperatelog.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * @author bhr + * @Description: 操作日志 + * @date 2019/8/28 9:31 + */ +@Data +public class OrderOperateLogVO { + + private Long id; + /** + * 各种单据的id + */ + @ApiModelProperty("各种单据的id") + private Long orderId; + /** + * 单据类型 + */ + @ApiModelProperty("单据类型") + private Integer orderType; + /** + * 操作类型 + */ + @ApiModelProperty("操作类型") + private Integer operateType; + /** + * 操作类型 对应的中文 + */ + @ApiModelProperty("操作类型 对应的中文") + private String operateContent; + /** + * 操作备注 + */ + @ApiModelProperty("操作备注") + private String operateRemark; + @ApiModelProperty("操作备注,包含审批人名使用别名显示") + private String operateSecondRemark; + /** + * 员工id + */ + @ApiModelProperty("员工id") + private Long employeeId; + /** + * 员工名称 + */ + @ApiModelProperty("员工名称") + private String employeeName; + /** + * 员工名称 + */ + @ApiModelProperty("员工别名") + private String employeeSecondName; + /** + * 额外信息 + */ + @ApiModelProperty("额外信息") + private String extData; + /** + * 创建时间 + */ + @ApiModelProperty("创建时间") + private Date createTime; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogController.java new file mode 100644 index 00000000..dcfea4fa --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogController.java @@ -0,0 +1,54 @@ +package com.gangquan360.smartadmin.module.log.userloginlog; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeQueryDTO; +import com.gangquan360.smartadmin.module.employee.domain.vo.EmployeeVO; +import com.gangquan360.smartadmin.module.log.userloginlog.domain.UserLoginLogDTO; +import com.gangquan360.smartadmin.module.log.userloginlog.domain.UserLoginLogQueryDTO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * [ 用户登录日志 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-05-15 10:25:21 + * @since JDK1.8 + */ +@RestController +@Api(tags = {SwaggerTagConst.Admin.MANAGER_USER_LOGIN_LOG}) +@OperateLog +public class UserLoginLogController { + + @Autowired + private UserLoginLogService userLoginLogService; + + @ApiOperation(value = "分页查询用户登录日志", notes = "@author yandanyang") + @PostMapping("/userLoginLog/page/query") + public ResponseDTO> queryByPage(@RequestBody UserLoginLogQueryDTO queryDTO) { + return userLoginLogService.queryByPage(queryDTO); + } + + @ApiOperation(value = "删除用户登录日志", notes = "@author yandanyang") + @GetMapping("/userLoginLog/delete/{id}") + public ResponseDTO delete(@PathVariable("id") Long id) { + return userLoginLogService.delete(id); + } + + @ApiOperation(value = "查询员工在线状态", notes = "@author zzr") + @PostMapping("/userOnLine/query") + public ResponseDTO> queryUserOnLine(@RequestBody @Valid EmployeeQueryDTO queryDTO) { + return userLoginLogService.queryUserOnLine(queryDTO); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogDao.java new file mode 100644 index 00000000..2392bc96 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogDao.java @@ -0,0 +1,47 @@ +package com.gangquan360.smartadmin.module.log.userloginlog; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.pagination.Pagination; +import com.gangquan360.smartadmin.module.log.userloginlog.domain.UserLoginLogQueryDTO; +import com.gangquan360.smartadmin.module.log.userloginlog.domain.UserLoginLogEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ 用户登录日志 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-05-15 10:25:21 + * @since JDK1.8 + */ +@Mapper +@Component +public interface UserLoginLogDao extends BaseMapper { + + /** + * 分页查询 + * @param queryDTO + * @return UserLoginLogEntity + */ + List queryByPage(Pagination page, @Param("queryDTO") UserLoginLogQueryDTO queryDTO); + + /** + * 根据id删除 + * @param id + * @return + */ + void deleteById(@Param("id") Long id); + + /** + * 批量删除 + * @param idList + * @return + */ + void deleteByIds(@Param("idList") List idList); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogService.java new file mode 100644 index 00000000..083e0f73 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/UserLoginLogService.java @@ -0,0 +1,82 @@ +package com.gangquan360.smartadmin.module.log.userloginlog; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.employee.EmployeeService; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeQueryDTO; +import com.gangquan360.smartadmin.module.employee.domain.vo.EmployeeVO; +import com.gangquan360.smartadmin.module.log.userloginlog.domain.UserLoginLogDTO; +import com.gangquan360.smartadmin.module.log.userloginlog.domain.UserLoginLogEntity; +import com.gangquan360.smartadmin.module.log.userloginlog.domain.UserLoginLogQueryDTO; +import com.gangquan360.smartadmin.module.websocket.WebSocketServer; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * [ 用户登录日志 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-05-15 10:25:21 + * @since JDK1.8 + */ +@Service +public class UserLoginLogService { + + @Autowired + private UserLoginLogDao userLoginLogDao; + + @Autowired + private EmployeeService employeeService; + + /** + * @author yandanyang + * @description 分页查询 + * @date 2019-05-15 10:25:21 + */ + public ResponseDTO> queryByPage(UserLoginLogQueryDTO queryDTO) { + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List entities = userLoginLogDao.queryByPage(page, queryDTO); + List dtoList = SmartBeanUtil.copyList(entities, UserLoginLogDTO.class); + page.setRecords(dtoList); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * @author yandanyang + * @description 删除 + * @date 2019-05-15 10:25:21 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long id) { + userLoginLogDao.deleteById(id); + return ResponseDTO.succ(); + } + + /** + * 查询员工在线状态 + * + * @param queryDTO + * @return + */ + public ResponseDTO> queryUserOnLine(EmployeeQueryDTO queryDTO) { + List onLineUserList = WebSocketServer.getOnLineUserList(); + if (CollectionUtils.isEmpty(onLineUserList)) { + return ResponseDTO.succ(); + } + queryDTO.setEmployeeIds(onLineUserList); + ResponseDTO> employeeList = employeeService.selectEmployeeList(queryDTO); + return employeeList; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogDTO.java new file mode 100644 index 00000000..9b0118d4 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogDTO.java @@ -0,0 +1,53 @@ +package com.gangquan360.smartadmin.module.log.userloginlog.domain; +import lombok.Data; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; + +/** + * [ 用户登录日志 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 12:27 + * @since JDK1.8 + */ +@Data +public class UserLoginLogDTO { + + @ApiModelProperty("主键") + private Long id; + + @ApiModelProperty("员工id") + private Long userId; + + @ApiModelProperty("用户名") + private String userName; + + @ApiModelProperty("用户ip") + private String remoteIp; + + @ApiModelProperty("用户端口") + private Integer remotePort; + + @ApiModelProperty("浏览器") + private String remoteBrowser; + + @ApiModelProperty("操作系统") + private String remoteOs; + + @ApiModelProperty("登录状态") + private Integer loginStatus; + + @ApiModelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogEntity.java new file mode 100644 index 00000000..5e04165d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogEntity.java @@ -0,0 +1,60 @@ +package com.gangquan360.smartadmin.module.log.userloginlog.domain; +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.*; + + +/** + * [ 用户登录日志] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-05-15 10:25:21 + * @since JDK1.8 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@TableName("t_user_login_log") +public class UserLoginLogEntity extends BaseEntity{ + + /** + * 员工id + */ + private Long userId; + + /** + * 用户名 + */ + private String userName; + /** + * 用户ip + */ + private String remoteIp; + + /** + * 用户端口 + */ + private Integer remotePort; + + /** + * 浏览器 + */ + private String remoteBrowser; + + /** + * 操作系统 + */ + private String remoteOs; + + /** + * 登录状态 + */ + private Integer loginStatus; + + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogQueryDTO.java new file mode 100644 index 00000000..02cb5ad2 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/userloginlog/domain/UserLoginLogQueryDTO.java @@ -0,0 +1,31 @@ +package com.gangquan360.smartadmin.module.log.userloginlog.domain; + +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ 用户登录日志 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-05-15 10:25:21 + * @since JDK1.8 + */ +@Data +public class UserLoginLogQueryDTO extends PageParamDTO { + + + @ApiModelProperty("开始日期") + private String startDate; + + @ApiModelProperty("结束日期") + private String endDate; + + + @ApiModelProperty("用户名") + private String userName; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogController.java new file mode 100644 index 00000000..a2f48f69 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogController.java @@ -0,0 +1,50 @@ +package com.gangquan360.smartadmin.module.log.useroperatelog; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.log.useroperatelog.domain.UserOperateLogDTO; +import com.gangquan360.smartadmin.module.log.useroperatelog.domain.UserOperateLogQueryDTO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-05-15 11:32:14 + * @since JDK1.8 + */ +@RestController +@Api(tags = {SwaggerTagConst.Admin.MANAGER_USER_OPERATE_LOG}) +@OperateLog +public class UserOperateLogController { + + @Autowired + private UserOperateLogService userOperateLogService; + + @ApiOperation(value = "分页查询",notes = "@author yandanyang") + @PostMapping("/userOperateLog/page/query") + public ResponseDTO> queryByPage(@RequestBody UserOperateLogQueryDTO queryDTO) { + return userOperateLogService.queryByPage(queryDTO); + } + + @ApiOperation(value="删除",notes = "@author yandanyang") + @GetMapping("/userOperateLog/delete/{id}") + public ResponseDTO delete(@PathVariable("id") Long id){ + return userOperateLogService.delete(id); + } + + + @ApiOperation(value="详情",notes = "@author yandanyang") + @GetMapping("/userOperateLog/detail/{id}") + public ResponseDTO detail(@PathVariable("id") Long id){ + return userOperateLogService.detail(id); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogDao.java new file mode 100644 index 00000000..9441a474 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogDao.java @@ -0,0 +1,47 @@ +package com.gangquan360.smartadmin.module.log.useroperatelog; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.pagination.Pagination; +import com.gangquan360.smartadmin.module.log.useroperatelog.domain.UserOperateLogQueryDTO; +import com.gangquan360.smartadmin.module.log.useroperatelog.domain.UserOperateLogEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-05-15 11:32:14 + * @since JDK1.8 + */ +@Mapper +@Component +public interface UserOperateLogDao extends BaseMapper { + + /** + * 分页查询 + * @param queryDTO + * @return UserOperateLogEntity + */ + List queryByPage(Pagination page, @Param("queryDTO") UserOperateLogQueryDTO queryDTO); + + /** + * 根据id删除 + * @param id + * @return + */ + void deleteById(@Param("id") Long id); + + /** + * 批量删除 + * @param idList + * @return + */ + void deleteByIds(@Param("idList") List idList); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogService.java new file mode 100644 index 00000000..f3aba984 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/UserOperateLogService.java @@ -0,0 +1,91 @@ +package com.gangquan360.smartadmin.module.log.useroperatelog; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.log.useroperatelog.domain.UserOperateLogDTO; +import com.gangquan360.smartadmin.module.log.useroperatelog.domain.UserOperateLogEntity; +import com.gangquan360.smartadmin.module.log.useroperatelog.domain.UserOperateLogQueryDTO; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-05-15 11:32:14 + * @since JDK1.8 + */ +@Service +public class UserOperateLogService { + + @Autowired + private UserOperateLogDao userOperateLogDao; + + /** + * @author yandanyang + * @description 分页查询 + * @date 2019-05-15 11:32:14 + */ + public ResponseDTO> queryByPage(UserOperateLogQueryDTO queryDTO) { + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List entities = userOperateLogDao.queryByPage(page, queryDTO); + List dtoList = SmartBeanUtil.copyList(entities, UserOperateLogDTO.class); + page.setRecords(dtoList); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * @author yandanyang + * @description 添加 + * @date 2019-05-15 11:32:14 + */ + public ResponseDTO add(UserOperateLogDTO addDTO) { + UserOperateLogEntity entity = SmartBeanUtil.copy(addDTO, UserOperateLogEntity.class); + userOperateLogDao.insert(entity); + return ResponseDTO.succ(); + } + + /** + * @author yandanyang + * @description 编辑 + * @date 2019-05-15 11:32:14 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(UserOperateLogDTO updateDTO) { + UserOperateLogEntity entity = SmartBeanUtil.copy(updateDTO, UserOperateLogEntity.class); + userOperateLogDao.updateById(entity); + return ResponseDTO.succ(); + } + + /** + * @author yandanyang + * @description 删除 + * @date 2019-05-15 11:32:14 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long id) { + userOperateLogDao.deleteById(id); + return ResponseDTO.succ(); + } + + /** + * @author yandanyang + * @description 根据ID查询 + * @date 2019-05-15 11:32:14 + */ + public ResponseDTO detail(Long id) { + UserOperateLogEntity entity = userOperateLogDao.selectById(id); + UserOperateLogDTO dto = SmartBeanUtil.copy(entity, UserOperateLogDTO.class); + return ResponseDTO.succData(dto); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogDTO.java new file mode 100644 index 00000000..ac23994f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogDTO.java @@ -0,0 +1,59 @@ +package com.gangquan360.smartadmin.module.log.useroperatelog.domain; +import lombok.Data; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 12:27 + * @since JDK1.8 + */ +@Data +public class UserOperateLogDTO { + + @ApiModelProperty("主键") + private Long id; + + @ApiModelProperty("用户id") + private Long userId; + + @ApiModelProperty("用户名称") + private String userName; + + @ApiModelProperty("操作模块") + private String module; + + @ApiModelProperty("操作内容") + private String content; + + @ApiModelProperty("请求路径") + private String url; + + @ApiModelProperty("请求方法") + private String method; + + @ApiModelProperty("请求参数") + private String param; + + @ApiModelProperty("请求结果 0失败 1成功") + private Integer result; + + @ApiModelProperty("失败原因") + private String failReason; + + @ApiModelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogEntity.java new file mode 100644 index 00000000..e578dcae --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogEntity.java @@ -0,0 +1,74 @@ +package com.gangquan360.smartadmin.module.log.useroperatelog.domain; +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-05-15 11:32:14 + * @since JDK1.8 + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +@TableName("t_user_operate_log") +public class UserOperateLogEntity extends BaseEntity{ + + + + /** + * 用户id + */ + private Long userId; + + /** + * 用户名称 + */ + private String userName; + /** + * 操作模块 + */ + private String module; + + /** + * 操作内容 + */ + private String content; + + /** + * 请求路径 + */ + private String url; + + /** + * 请求方法 + */ + private String method; + + /** + * 请求参数 + */ + private String param; + + /** + * 请求结果 0失败 1成功 + */ + private Integer result; + + /** + * 失败原因 + */ + private String failReason; + + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogQueryDTO.java new file mode 100644 index 00000000..4995dc6a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/log/useroperatelog/domain/UserOperateLogQueryDTO.java @@ -0,0 +1,34 @@ +package com.gangquan360.smartadmin.module.log.useroperatelog.domain; + +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-05-15 11:32:14 + * @since JDK1.8 + */ +@Data +public class UserOperateLogQueryDTO extends PageParamDTO { + + + @ApiModelProperty("开始日期") + private String startDate; + + @ApiModelProperty("结束日期") + private String endDate; + + + @ApiModelProperty("用户名称") + private String userName; + + @ApiModelProperty("请求结果 0失败 1成功") + private Integer resultFlag; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginController.java new file mode 100644 index 00000000..95022466 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginController.java @@ -0,0 +1,72 @@ +package com.gangquan360.smartadmin.module.login; + +import com.gangquan360.smartadmin.common.anno.NoNeedLogin; +import com.gangquan360.smartadmin.common.anno.NoValidPrivilege; +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeLoginFormDTO; +import com.gangquan360.smartadmin.module.login.domain.KaptchaVO; +import com.gangquan360.smartadmin.module.login.domain.LoginDetailVO; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.util.SmartRequestTokenUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +/** + * 后台登录 + * + * @author lidoudou + * @date 2017年12月19日上午11:46:04 + */ +@RestController +@Api(tags = {SwaggerTagConst.Admin.MANAGER_USER_LOGIN}) +@OperateLog +public class LoginController { + + @Autowired + private LoginService loginService; + + @PostMapping("/session/login") + @ApiOperation(value = "登录", notes = "登录") + @NoNeedLogin + public ResponseDTO login(@Valid @RequestBody EmployeeLoginFormDTO loginForm, HttpServletRequest request) { + return loginService.login(loginForm, request); + } + + + @GetMapping("/session/get") + @ApiOperation(value = "获取session", notes = "获取session") + @NoValidPrivilege + public ResponseDTO getSession() { + RequestTokenBO requestUser = SmartRequestTokenUtil.getRequestUser(); + return ResponseDTO.succData(loginService.getSession(requestUser)); + } + + @GetMapping("/session/logOut") + @ApiOperation(value = "退出登陆", notes = "退出登陆") + @NoValidPrivilege + public ResponseDTO logOut() { + RequestTokenBO requestToken = SmartRequestTokenUtil.getRequestUser(); + if (null == requestToken) { + return ResponseDTO.wrap(LoginResponseCodeConst.LOGIN_ERROR); + } + return loginService.logoutByToken(requestToken); + } + + @GetMapping("/session/verificationCode") + @ApiOperation(value = "获取验证码", notes = "获取验证码") + @NoNeedLogin + public ResponseDTO verificationCode() { + return loginService.verificationCode(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginResponseCodeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginResponseCodeConst.java new file mode 100644 index 00000000..f12a3a3a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginResponseCodeConst.java @@ -0,0 +1,21 @@ +package com.gangquan360.smartadmin.module.login; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + +/** + * 员工常量类 + * 1001-1999 + * + * @author lidoudou + * @date 2017年12月19日下午19:04:52 + */ +public class LoginResponseCodeConst extends ResponseCodeConst { + + public static final LoginResponseCodeConst LOGIN_ERROR = new LoginResponseCodeConst(1001, "您还未登录或登录失效,请重新登录!"); + + public static final LoginResponseCodeConst NOT_HAVE_PRIVILEGES = new LoginResponseCodeConst(1002, "对不起,您没有权限哦!"); + + public LoginResponseCodeConst(int code, String msg) { + super(code, msg); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginService.java new file mode 100644 index 00000000..220bc7bc --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginService.java @@ -0,0 +1,210 @@ +package com.gangquan360.smartadmin.module.login; + +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.CommonConst; +import com.gangquan360.smartadmin.module.department.DepartmentDao; +import com.gangquan360.smartadmin.module.department.domain.entity.DepartmentEntity; +import com.gangquan360.smartadmin.module.employee.EmployeeDao; +import com.gangquan360.smartadmin.module.employee.constant.EmployeeResponseCodeConst; +import com.gangquan360.smartadmin.module.employee.constant.EmployeeStatusEnum; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeLoginFormDTO; +import com.gangquan360.smartadmin.module.log.LogService; +import com.gangquan360.smartadmin.module.log.userloginlog.domain.UserLoginLogEntity; +import com.gangquan360.smartadmin.module.login.domain.KaptchaVO; +import com.gangquan360.smartadmin.module.login.domain.LoginDetailVO; +import com.gangquan360.smartadmin.module.login.domain.LoginPrivilegeDTO; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.module.privilege.domain.entity.PrivilegeEntity; +import com.gangquan360.smartadmin.module.privilege.service.PrivilegeEmployeeService; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartDigestUtil; +import com.gangquan360.smartadmin.util.SmartIPUtil; +import com.google.code.kaptcha.impl.DefaultKaptcha; +import eu.bitwalker.useragentutils.UserAgent; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.stereotype.Service; + +import javax.imageio.ImageIO; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 18:10 + * @since JDK1.8 + */ +@Slf4j +@Service +public class LoginService { + + private static final String VERIFICATION_CODE_REDIS_PREFIX = "vc_%s"; + + @Autowired + private EmployeeDao employeeDao; + + @Autowired + private DepartmentDao departmentDao; + + @Autowired + private PrivilegeEmployeeService privilegeEmployeeService; + + @Autowired + private LoginTokenService loginTokenService; + + @Autowired + private LogService logService; + + @Autowired + private DefaultKaptcha defaultKaptcha; + + @Autowired + private ValueOperations redisValueOperations; + + /** + * 登陆 + * + * @param loginForm 登录名 密码 + * @return 登录用户基本信息 + */ + public ResponseDTO login(@Valid EmployeeLoginFormDTO loginForm, HttpServletRequest request) { + String redisVerificationCode = redisValueOperations.get(loginForm.getCodeUuid()); + //增加删除已使用的验证码方式 频繁登录 + redisValueOperations.getOperations().delete(loginForm.getCodeUuid()); + if (StringUtils.isEmpty(redisVerificationCode)) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.VERIFICATION_CODE_INVALID); + } + if (!redisVerificationCode.equalsIgnoreCase(loginForm.getCode())) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.VERIFICATION_CODE_INVALID); + } + String loginPwd = SmartDigestUtil.encryptPassword(CommonConst.Password.SALT_FORMAT, loginForm.getLoginPwd()); + EmployeeDTO employeeDTO = employeeDao.login(loginForm.getLoginName(), loginPwd); + if (null == employeeDTO) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.LOGIN_FAILED); + } + if (EmployeeStatusEnum.DISABLED.equalsValue(employeeDTO.getIsDisabled())) { + return ResponseDTO.wrap(EmployeeResponseCodeConst.IS_DISABLED); + } + //jwt token赋值 + String compactJws = loginTokenService.generateToken(employeeDTO); + + LoginDetailVO loginDTO = SmartBeanUtil.copy(employeeDTO, LoginDetailVO.class); + + //获取前端功能权限 + loginDTO.setPrivilegeList(initEmployeePrivilege(employeeDTO.getId())); + + loginDTO.setXAccessToken(compactJws); + DepartmentEntity departmentEntity = departmentDao.selectById(employeeDTO.getDepartmentId()); + loginDTO.setDepartmentName(departmentEntity.getName()); + + //判断是否为超管 + Boolean isSuperman = privilegeEmployeeService.isSuperman(loginDTO.getId()); + loginDTO.setIsSuperMan(isSuperman); + //登陆操作日志 + UserAgent userAgent = UserAgent.parseUserAgentString(request.getHeader("User-Agent")); + UserLoginLogEntity logEntity = + UserLoginLogEntity.builder() + .userId(employeeDTO.getId()) + .userName(employeeDTO.getActualName()) + .remoteIp(SmartIPUtil.getRemoteIp(request)) + .remotePort(request.getRemotePort()) + .remoteBrowser(userAgent.getBrowser().getName()) + .remoteOs(userAgent.getOperatingSystem().getName()) + .loginStatus(JudgeEnum.YES.getValue()).build(); + logService.addLog(logEntity); + return ResponseDTO.succData(loginDTO); + } + + /** + * 手机端退出登陆,清除token缓存 + * + * @param requestToken + * @return 退出登陆是否成功,bool + */ + public ResponseDTO logoutByToken(RequestTokenBO requestToken) { + privilegeEmployeeService.removeCache(requestToken.getRequestUserId()); + return ResponseDTO.succ(); + } + + /** + * 获取验证码 + * + * @return + */ + public ResponseDTO verificationCode() { + KaptchaVO kaptchaVO = new KaptchaVO(); + String uuid = buildVerificationCodeRedisKey(UUID.randomUUID().toString()); + String kaptchaText = defaultKaptcha.createText(); + + String base64Code = ""; + + BufferedImage image = defaultKaptcha.createImage(kaptchaText); + ByteArrayOutputStream outputStream = null; + try { + outputStream = new ByteArrayOutputStream(); + ImageIO.write(image, "jpg", outputStream); + base64Code = Base64.encodeBase64String(outputStream.toByteArray()); + } catch (Exception e) { + log.error("verificationCode exception .{}", e); + } finally { + if (outputStream != null) { + try { + outputStream.close(); + } catch (Exception e) { + log.error("verificationCode outputStream close exception .{}", e); + } + } + } + kaptchaVO.setUuid(uuid); + kaptchaVO.setCode("data:image/png;base64," + base64Code); + redisValueOperations.set(uuid, kaptchaText, 60L, TimeUnit.SECONDS); + return ResponseDTO.succData(kaptchaVO); + } + + private String buildVerificationCodeRedisKey(String uuid) { + return String.format(VERIFICATION_CODE_REDIS_PREFIX, uuid); + } + + /** + * 初始化员工权限 + * + * @param employeeId + * @return + */ + public List initEmployeePrivilege(Long employeeId) { + List privilegeList = privilegeEmployeeService.getPrivilegesByEmployeeId(employeeId); + privilegeEmployeeService.updateCachePrivilege(employeeId, privilegeList); + return SmartBeanUtil.copyList(privilegeList, LoginPrivilegeDTO.class); + } + + public LoginDetailVO getSession(RequestTokenBO requestUser) { + LoginDetailVO loginDTO = SmartBeanUtil.copy(requestUser.getEmployeeBO(), LoginDetailVO.class); + List privilegeEntityList = privilegeEmployeeService.getEmployeeAllPrivilege(requestUser.getRequestUserId()); + if (privilegeEntityList == null) { + List loginPrivilegeDTOS = initEmployeePrivilege(requestUser.getRequestUserId()); + loginDTO.setPrivilegeList(loginPrivilegeDTOS); + } else { + loginDTO.setPrivilegeList(SmartBeanUtil.copyList(privilegeEntityList, LoginPrivilegeDTO.class)); + } + + //判断是否为超管 + Boolean isSuperman = privilegeEmployeeService.isSuperman(loginDTO.getId()); + loginDTO.setIsSuperMan(isSuperman); + return loginDTO; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginTokenService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginTokenService.java new file mode 100644 index 00000000..80e3ef4a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/LoginTokenService.java @@ -0,0 +1,118 @@ +package com.gangquan360.smartadmin.module.login; + +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import com.gangquan360.smartadmin.module.employee.EmployeeService; +import com.gangquan360.smartadmin.module.employee.constant.EmployeeStatusEnum; +import com.gangquan360.smartadmin.module.employee.domain.bo.EmployeeBO; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Date; +import java.util.UUID; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Slf4j +@Service +public class LoginTokenService { + + /** + * 过期时间一天 + */ + private static final int EXPIRE_SECONDS = 1 * 24 * 3600; + /** + * jwt加密字段 + */ + private static final String CLAIM_ID_KEY = "id"; + + @Value("${jwt.key}") + private String jwtKey; + + @Autowired + private EmployeeService employeeService; + + + /** + * 功能描述: 生成JWT TOKEN + * + * @param employeeDTO + * @return + * @auther yandanyang + * @date 2018/9/12 0012 上午 10:08 + */ + public String generateToken(EmployeeDTO employeeDTO) { + Long id = employeeDTO.getId(); + /**将token设置为jwt格式*/ + String baseToken = UUID.randomUUID().toString(); + LocalDateTime localDateTimeNow = LocalDateTime.now(); + LocalDateTime localDateTimeExpire = localDateTimeNow.plusSeconds(EXPIRE_SECONDS); + Date from = Date.from(localDateTimeNow.atZone(ZoneId.systemDefault()).toInstant()); + Date expire = Date.from(localDateTimeExpire.atZone(ZoneId.systemDefault()).toInstant()); + + Claims jwtClaims = Jwts.claims().setSubject(baseToken); + jwtClaims.put(CLAIM_ID_KEY, id); + String compactJws = Jwts.builder().setClaims(jwtClaims).setNotBefore(from).setExpiration(expire).signWith(SignatureAlgorithm.HS512, jwtKey).compact(); + + EmployeeBO employeeBO = employeeService.getById(id); + RequestTokenBO tokenBO = new RequestTokenBO(employeeBO); + + return compactJws; + } + + /** + * 功能描述: 根据登陆token获取登陆信息 + * + * @param + * @return + * @auther yandanyang + * @date 2018/9/12 0012 上午 10:11 + */ + public RequestTokenBO getEmployeeTokenInfo(String token) { + Long employeeId = -1L; + try { + Claims claims = Jwts.parser().setSigningKey(jwtKey).parseClaimsJws(token).getBody(); + String idStr = claims.get(CLAIM_ID_KEY).toString(); + employeeId = Long.valueOf(idStr); + } catch (Exception e) { + log.error("getEmployeeTokenInfo error:{}", e); + return null; + } + + EmployeeBO employeeBO = employeeService.getById(employeeId); + if (employeeBO == null) { + return null; + } + + if (EmployeeStatusEnum.DISABLED.getValue().equals(employeeBO.getIsDisabled())) { + return null; + } + + if (JudgeEnum.YES.equals(employeeBO.getIsLeave())) { + return null; + } + + if (JudgeEnum.YES.equals(employeeBO.getIsDelete())) { + return null; + } + + return new RequestTokenBO(employeeBO); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/KaptchaVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/KaptchaVO.java new file mode 100644 index 00000000..ce730e6a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/KaptchaVO.java @@ -0,0 +1,28 @@ +package com.gangquan360.smartadmin.module.login.domain; + +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/4 0004 上午 10:11 + * @since JDK1.8 + */ +@Data +public class KaptchaVO { + + /** + * 验证码UUID + */ + private String uuid; + + /** + * base64 验证码 + */ + private String code; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginCacheDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginCacheDTO.java new file mode 100644 index 00000000..7dd6e9ed --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginCacheDTO.java @@ -0,0 +1,28 @@ +package com.gangquan360.smartadmin.module.login.domain; + +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/9 0009 下午 17:32 + * @since JDK1.8 + */ +@Data +public class LoginCacheDTO { + + /** + * 基本信息 + */ + private EmployeeDTO employeeDTO; + + /** + * 过期时间 + */ + private Long expireTime; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginDetailVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginDetailVO.java new file mode 100644 index 00000000..671fc951 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginDetailVO.java @@ -0,0 +1,70 @@ +package com.gangquan360.smartadmin.module.login.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * 登录返回DTO + * + * @author lidoudou + * @date 2017年12月21日上午09:06:31 + */ +@Data +public class LoginDetailVO { + + @ApiModelProperty("主键id") + private Long id; + + @ApiModelProperty("登录账号") + private String loginName; + + @ApiModelProperty("别名") + private String nickName; + + @ApiModelProperty("员工名称") + private String actualName; + + @ApiModelProperty("手机号码") + private String phone; + + @ApiModelProperty("身份证") + private String idCard; + + @ApiModelProperty("出生日期") + @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8") + private Date birthday; + + @ApiModelProperty("创建者id") + private Long createUser; + + @ApiModelProperty("部门id") + private Long departmentId; + + @ApiModelProperty("是否离职") + private Integer isLeave; + + @ApiModelProperty("是否被禁用") + private Integer isDisabled; + + @ApiModelProperty("部门名称") + private String departmentName; + + @ApiModelProperty("邮箱") + private String email; + + @ApiModelProperty("登陆token") + private String xAccessToken; + + @ApiModelProperty("是否为超管") + private Boolean isSuperMan; + + @ApiModelProperty("权限列表") + private List privilegeList; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginPrivilegeDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginPrivilegeDTO.java new file mode 100644 index 00000000..1329964e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/LoginPrivilegeDTO.java @@ -0,0 +1,35 @@ +package com.gangquan360.smartadmin.module.login.domain; + +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.module.privilege.constant.PrivilegeTypeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/21 0021 上午 10:28 + * @since JDK1.8 + */ +@Data +public class LoginPrivilegeDTO { + + @ApiModelProperty("权限key") + private String key; + + @ApiModelPropertyEnum(enumDesc = "菜单类型",value = PrivilegeTypeEnum.class) + private Integer type; + + @ApiModelProperty("url") + private String url; + + @ApiModelProperty("父级key") + private String parentKey; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/RequestTokenBO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/RequestTokenBO.java new file mode 100644 index 00000000..e4019f6d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/login/domain/RequestTokenBO.java @@ -0,0 +1,26 @@ +package com.gangquan360.smartadmin.module.login.domain; + +import com.gangquan360.smartadmin.module.employee.domain.bo.EmployeeBO; +import lombok.Getter; + + +@Getter +public class RequestTokenBO { + + private Long requestUserId; + + private EmployeeBO employeeBO; + + public RequestTokenBO(EmployeeBO employeeBO) { + this.requestUserId = employeeBO.getId(); + this.employeeBO = employeeBO; + } + + @Override + public String toString() { + return "RequestTokenBO{" + + "requestUserId=" + requestUserId + + ", employeeBO=" + employeeBO + + '}'; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeController.java new file mode 100644 index 00000000..28681cc8 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeController.java @@ -0,0 +1,96 @@ +package com.gangquan360.smartadmin.module.notice; + +import com.gangquan360.smartadmin.common.anno.NoValidPrivilege; +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.notice.domain.dto.*; +import com.gangquan360.smartadmin.util.SmartRequestTokenUtil; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-07-11 16:19:48 + * @since JDK1.8 + */ +@RestController +@Api(tags = {SwaggerTagConst.Admin.MANAGER_NOTICE}) +public class NoticeController { + + @Autowired + private NoticeService noticeService; + + @ApiOperation(value = "分页查询全部消息", notes = "@author yandanyang") + @PostMapping("/notice/page/query") + @NoValidPrivilege + public ResponseDTO> queryByPage(@RequestBody NoticeQueryDTO queryDTO) { + return noticeService.queryByPage(queryDTO); + } + + @ApiOperation(value = "获取已收取的所有消息", notes = "@author yandanyang") + @PostMapping("/notice/receive/page/query") + @NoValidPrivilege + public ResponseDTO> queryReceiveByPage(@RequestBody NoticeReceiveQueryDTO queryDTO) { + return noticeService.queryReceiveByPage(queryDTO, SmartRequestTokenUtil.getRequestUser()); + } + + @ApiOperation(value = "分页查询未读消息", notes = "@author yandanyang") + @PostMapping("/notice/unread/page/query") + @NoValidPrivilege + public ResponseDTO> queryUnreadByPage(@RequestBody PageParamDTO queryDTO) { + return noticeService.queryUnreadByPage(queryDTO, SmartRequestTokenUtil.getRequestUser()); + } + + @ApiOperation(value = "添加", notes = "@author yandanyang") + @PostMapping("/notice/add") + @NoValidPrivilege + public ResponseDTO add(@RequestBody @Valid NoticeAddDTO addTO) { + return noticeService.add(addTO, SmartRequestTokenUtil.getRequestUser()); + } + + @ApiOperation(value = "修改", notes = "@author yandanyang") + @PostMapping("/notice/update") + @NoValidPrivilege + public ResponseDTO update(@RequestBody @Valid NoticeUpdateDTO updateDTO) { + return noticeService.update(updateDTO); + } + + @ApiOperation(value = "删除", notes = "@author yandanyang") + @GetMapping("/notice/delete/{id}") + @NoValidPrivilege + public ResponseDTO delete(@PathVariable("id") Long id) { + return noticeService.delete(id); + } + + @ApiOperation(value = "详情", notes = "@author yandanyang") + @GetMapping("/notice/detail/{id}") + @NoValidPrivilege + public ResponseDTO detail(@PathVariable("id") Long id) { + return noticeService.detail(id); + } + + @ApiOperation(value = "发送", notes = "@author yandanyang") + @GetMapping("/notice/send/{id}") + @NoValidPrivilege + public ResponseDTO send(@PathVariable("id") Long id) { + return noticeService.send(id, SmartRequestTokenUtil.getRequestUser()); + } + + @ApiOperation(value = "读取消息", notes = "@author yandanyang") + @GetMapping("/notice/read/{id}") + @NoValidPrivilege + public ResponseDTO read(@PathVariable("id") Long id) { + return noticeService.read(id, SmartRequestTokenUtil.getRequestUser()); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeManage.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeManage.java new file mode 100644 index 00000000..fa26796c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeManage.java @@ -0,0 +1,96 @@ +package com.gangquan360.smartadmin.module.notice; + +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.module.notice.dao.NoticeDao; +import com.gangquan360.smartadmin.module.notice.dao.NoticeReceiveRecordDao; +import com.gangquan360.smartadmin.module.notice.domain.dto.NoticeUpdateDTO; +import com.gangquan360.smartadmin.module.notice.domain.entity.NoticeEntity; +import com.gangquan360.smartadmin.module.notice.domain.entity.NoticeReceiveRecordEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/13 0013 下午 17:33 + * @since JDK1.8 + */ +@Service +public class NoticeManage { + + @Autowired + private NoticeDao noticeDao; + @Autowired + private NoticeReceiveRecordDao noticeReceiveRecordDao; + + /** + * 发送消息 + * @param entity + * @param requestToken + */ + @Transactional(rollbackFor = Exception.class) + public void send(NoticeEntity entity, RequestTokenBO requestToken){ + + entity.setSendStatus(JudgeEnum.YES.getValue()); + noticeDao.updateById(entity); + //默认发件人 已读此消息 + NoticeReceiveRecordEntity recordEntity = new NoticeReceiveRecordEntity(); + recordEntity.setEmployeeId(requestToken.getRequestUserId()); + recordEntity.setNoticeId(entity.getId()); + recordEntity.setCreateTime(new Date()); + recordEntity.setUpdateTime(new Date()); + noticeReceiveRecordDao.insert(recordEntity); + } + + + /** + * 保存读取记录 + * @param noticeId + * @param requestToken + */ + public void saveReadRecord(Long noticeId, RequestTokenBO requestToken){ + NoticeReceiveRecordEntity recordEntity = new NoticeReceiveRecordEntity(); + recordEntity.setEmployeeId(requestToken.getRequestUserId()); + recordEntity.setNoticeId(noticeId); + recordEntity.setCreateTime(new Date()); + recordEntity.setUpdateTime(new Date()); + noticeReceiveRecordDao.insert(recordEntity); + } + + + /** + * 消息删除 + * @param entity + */ + @Transactional(rollbackFor = Exception.class) + public void delete(NoticeEntity entity) { + if(JudgeEnum.YES.getValue().equals(entity.getSendStatus())){ + //消息已发送 执行逻辑删除 + noticeDao.logicDeleteById(entity.getId(),JudgeEnum.YES.getValue()); + }else{ + //消息未发送 执行真实删除 + noticeDao.deleteById(entity.getId()); + } + } + + /** + * 更新消息 + * @param entity + * @param updateDTO + */ + public void update(NoticeEntity entity,NoticeUpdateDTO updateDTO) { + entity.setTitle(updateDTO.getTitle()); + entity.setContent(updateDTO.getContent()); + entity.setSendStatus(JudgeEnum.NO.getValue()); + entity.setDeleted(JudgeEnum.NO.getValue()); + noticeDao.updateById(entity); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeService.java new file mode 100644 index 00000000..b98f1dd0 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/NoticeService.java @@ -0,0 +1,234 @@ +package com.gangquan360.smartadmin.module.notice; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.module.notice.dao.NoticeDao; +import com.gangquan360.smartadmin.module.notice.dao.NoticeReceiveRecordDao; +import com.gangquan360.smartadmin.module.notice.domain.dto.*; +import com.gangquan360.smartadmin.module.notice.domain.entity.NoticeEntity; +import com.gangquan360.smartadmin.module.notice.domain.entity.NoticeReceiveRecordEntity; +import com.gangquan360.smartadmin.module.websocket.WebSocketServer; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-07-11 16:19:48 + * @since JDK1.8 + */ +@Service +public class NoticeService { + + @Autowired + private NoticeDao noticeDao; + + @Autowired + private NoticeReceiveRecordDao noticeReceiveRecordDao; + + @Autowired + private NoticeManage noticeManage; + + /** + * @author yandanyang + * @description 分页查询 + * @date 2019-07-11 16:19:48 + */ + public ResponseDTO> queryByPage(NoticeQueryDTO queryDTO) { + queryDTO.setDeleted(JudgeEnum.NO.getValue()); + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List dtoList = noticeDao.queryByPage(page, queryDTO); + page.setRecords(dtoList); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * 获取当前登录人的消息列表 + * + * @param queryDTO + * @param requestToken + * @return + */ + public ResponseDTO> queryReceiveByPage(NoticeReceiveQueryDTO queryDTO, RequestTokenBO requestToken) { + queryDTO.setEmployeeId(requestToken.getRequestUserId()); + queryDTO.setSendStatus(JudgeEnum.YES.getValue()); + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List dtoList = noticeDao.queryReceiveByPage(page, queryDTO); + dtoList.forEach(e -> { + if (e.getReceiveTime() == null) { + e.setReadStatus(JudgeEnum.NO.getValue()); + } else { + e.setReadStatus(JudgeEnum.YES.getValue()); + } + }); + page.setRecords(dtoList); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * 获取我的未读消息 + * + * @param queryDTO + * @param requestToken + * @return + */ + public ResponseDTO> queryUnreadByPage(PageParamDTO queryDTO, RequestTokenBO requestToken) { + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List dtoList = noticeDao.queryUnreadByPage(page, requestToken.getRequestUserId(), JudgeEnum.YES.getValue()); + page.setRecords(dtoList); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * @author yandanyang + * @description 添加 + * @date 2019-07-11 16:19:48 + */ + public ResponseDTO add(NoticeAddDTO addDTO, RequestTokenBO requestToken) { + NoticeEntity entity = SmartBeanUtil.copy(addDTO, NoticeEntity.class); + entity.setCreateTime(new Date()); + entity.setUpdateTime(new Date()); + entity.setCreateUser(requestToken.getRequestUserId()); + entity.setSendStatus(JudgeEnum.NO.getValue()); + entity.setDeleted(JudgeEnum.NO.getValue()); + noticeDao.insert(entity); + return ResponseDTO.succ(); + } + + /** + * @author yandanyang + * @description 编辑 + * @date 2019-07-11 16:19:48 + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(NoticeUpdateDTO updateDTO) { + NoticeEntity entity = noticeDao.selectById(updateDTO.getId()); + if (entity == null) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "此系统通知不存在"); + } + if (JudgeEnum.YES.getValue().equals(entity.getSendStatus())) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "此系统通知已发送无法修改"); + } + noticeManage.update(entity, updateDTO); + return ResponseDTO.succ(); + } + + /** + * @author yandanyang + * @description 删除 + * @date 2019-07-11 16:19:48 + */ + public ResponseDTO delete(Long id) { + NoticeEntity entity = noticeDao.selectById(id); + if (entity == null) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "此系统通知不存在"); + } + noticeManage.delete(entity); + return ResponseDTO.succ(); + } + + /** + * @author yandanyang + * @description 根据ID查询 + * @date 2019-07-11 16:19:48 + */ + public ResponseDTO detail(Long id) { + NoticeDetailVO noticeDTO = noticeDao.detail(id); + return ResponseDTO.succData(noticeDTO); + } + + /** + * 获取某人的未读消息数 + * + * @param employeeId + * @return + */ + private Integer getUnreadCount(Long employeeId) { + return noticeDao.noticeUnreadCount(employeeId, JudgeEnum.YES.getValue()); + } + + /** + * 发送给所有在线用户未读消息数 + * + * @param id + * @param requestToken + * @return + */ + public ResponseDTO send(Long id, RequestTokenBO requestToken) { + NoticeEntity entity = noticeDao.selectById(id); + if (entity == null) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "此系统通知不存在"); + } + noticeManage.send(entity, requestToken); + this.sendMessage(requestToken); + return ResponseDTO.succ(); + } + + /** + * 发送系统通知 ,发送人不进行接收,需再事务外调用 以防止数据隔离级别不同造成未读消息数异常 + * + * @param requestToken + */ + private void sendMessage(RequestTokenBO requestToken) { + List onLineEmployeeIds = WebSocketServer.getOnLineUserList(); + if (CollectionUtils.isEmpty(onLineEmployeeIds)) { + return; + } + //在线用户已读消息数 + Map readCountMap = new HashMap<>(); + List readCountList = noticeDao.readCount(onLineEmployeeIds); + if (CollectionUtils.isNotEmpty(readCountList)) { + readCountMap = readCountList.stream().collect(Collectors.toMap(NoticeReadCountDTO :: getEmployeeId, NoticeReadCountDTO :: getReadCount)); + } + //已发送消息数 + Integer noticeCount = noticeDao.noticeCount(JudgeEnum.YES.getValue()); + for (Long employeeId : onLineEmployeeIds) { + Integer readCount = readCountMap.get(employeeId) == null ? 0 : readCountMap.get(employeeId); + Integer unReadCount = noticeCount - readCount; + if (! requestToken.getRequestUserId().equals(employeeId)) { + WebSocketServer.sendOneOnLineUser(unReadCount.toString(), employeeId); + } + } + } + + /** + * 读取消息 + * + * @param id + * @param requestToken + * @return + */ + public ResponseDTO read(Long id, RequestTokenBO requestToken) { + NoticeDetailVO noticeDTO = noticeDao.detail(id); + + NoticeReceiveRecordEntity recordEntity = noticeReceiveRecordDao.selectByEmployeeAndNotice(requestToken.getRequestUserId(), id); + if (recordEntity != null) { + return ResponseDTO.succData(noticeDTO); + } + noticeManage.saveReadRecord(id, requestToken); + this.sendMessage(requestToken); + return ResponseDTO.succData(noticeDTO); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/dao/NoticeDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/dao/NoticeDao.java new file mode 100644 index 00000000..7c3235e9 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/dao/NoticeDao.java @@ -0,0 +1,99 @@ +package com.gangquan360.smartadmin.module.notice.dao; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.pagination.Pagination; +import com.gangquan360.smartadmin.module.notice.domain.dto.*; +import com.gangquan360.smartadmin.module.notice.domain.entity.NoticeEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-07-11 16:19:48 + * @since JDK1.8 + */ +@Mapper +@Component +public interface NoticeDao extends BaseMapper { + + /** + * 分页查询 + * @param queryDTO + * @return NoticeEntity + */ + List queryByPage(Pagination page, @Param("queryDTO") NoticeQueryDTO queryDTO); + + + /** + * 获取某人的未读消息 + * @param page + * @param employeeId + * @return + */ + List queryUnreadByPage(Pagination page, @Param("employeeId") Long employeeId, @Param("sendStatus") Integer sendStatus); + + + /** + * 获取 + * @param page + * @param queryDTO + * @return + */ + List queryReceiveByPage(Pagination page, @Param("queryDTO") NoticeReceiveQueryDTO queryDTO); + + /** + * 详情 + * @param id + * @return + */ + NoticeDetailVO detail(@Param("id") Long id); + + /** + * 根据id删除 逻辑删除 + * @param id + * @param deletedFlag + */ + void logicDeleteById(@Param("id") Long id,@Param("deletedFlag") Integer deletedFlag); + + + + /** + * 批量逻辑删除 + * @param idList + * @param deletedFlag + * @return + */ + void logicDeleteByIds(@Param("idList") List idList,@Param("deletedFlag") Integer deletedFlag); + + /** + * 获取消息总数 + * @return + */ + Integer noticeCount(@Param("sendStatus") Integer sendStatus); + + + /** + * 获取已读消息数 + * @param employeeIds + * @return + */ + List readCount(@Param("employeeIds") List employeeIds); + + + /** + * 获取某人的未读消息数 + * @param employeeId + * @param sendStatus + * @return + */ + Integer noticeUnreadCount(@Param("employeeId") Long employeeId, @Param("sendStatus") Integer sendStatus); + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/dao/NoticeReceiveRecordDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/dao/NoticeReceiveRecordDao.java new file mode 100644 index 00000000..f91bc31f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/dao/NoticeReceiveRecordDao.java @@ -0,0 +1,48 @@ +package com.gangquan360.smartadmin.module.notice.dao; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.gangquan360.smartadmin.module.notice.domain.entity.NoticeReceiveRecordEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-07-11 16:19:48 + * @since JDK1.8 + */ +@Mapper +@Component +public interface NoticeReceiveRecordDao extends BaseMapper { + + /** + * 批量删除 + * + * @param noticeId + * @return + */ + void deleteByNoticeId(@Param("noticeId") Long noticeId); + + /** + * 批量插入 + * + * @param rolePrivilegeList + */ + void batchInsert(List rolePrivilegeList); + + /** + * 根据员工和系统通知获取读取记录 + * + * @param employeeId + * @param noticeId + * @return + */ + NoticeReceiveRecordEntity selectByEmployeeAndNotice(@Param("employeeId") Long employeeId, @Param("noticeId") Long noticeId); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeAddDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeAddDTO.java new file mode 100644 index 00000000..29dc1d1b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeAddDTO.java @@ -0,0 +1,28 @@ +package com.gangquan360.smartadmin.module.notice.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 12:27 + * @since JDK1.8 + */ +@Data +public class NoticeAddDTO { + + @ApiModelProperty("消息标题") + @Length(max = 200) + private String title; + + @ApiModelProperty("消息内容") + @Length(max = 5000) + private String content; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeDetailVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeDetailVO.java new file mode 100644 index 00000000..1083cfc4 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeDetailVO.java @@ -0,0 +1,30 @@ +package com.gangquan360.smartadmin.module.notice.domain.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 12:27 + * @since JDK1.8 + */ +@Data +public class NoticeDetailVO extends NoticeVO { + + + @ApiModelProperty("消息内容") + private String content; + + @ApiModelProperty("更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date updateTime; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeQueryDTO.java new file mode 100644 index 00000000..d20ccedd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeQueryDTO.java @@ -0,0 +1,34 @@ +package com.gangquan360.smartadmin.module.notice.domain.dto; + +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date 2019-07-11 16:19:48 + * @since JDK1.8 + */ +@Data +public class NoticeQueryDTO extends PageParamDTO { + + + @ApiModelProperty("开始日期") + private String startDate; + + @ApiModelProperty("结束日期") + private String endDate; + + + @ApiModelProperty("消息标题") + private String title; + + @ApiModelProperty(value = "是否删除",hidden = true) + private Integer deleted; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReadCountDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReadCountDTO.java new file mode 100644 index 00000000..e6245d00 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReadCountDTO.java @@ -0,0 +1,26 @@ +package com.gangquan360.smartadmin.module.notice.domain.dto; + +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/12 0012 上午 8:11 + * @since JDK1.8 + */ +@Data +public class NoticeReadCountDTO { + /** + * 员工id + */ + private Long employeeId; + /** + * 已读消息数 + */ + private Integer readCount; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReceiveDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReceiveDTO.java new file mode 100644 index 00000000..055af2b6 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReceiveDTO.java @@ -0,0 +1,43 @@ +package com.gangquan360.smartadmin.module.notice.domain.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/12 0012 上午 11:53 + * @since JDK1.8 + */ +@Data +public class NoticeReceiveDTO{ + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("消息标题") + private String title; + + + @ApiModelProperty("消息创建人") + private Long createUser; + + @ApiModelProperty("消息创建人名称") + private String createUserName; + + @ApiModelProperty("结束时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date receiveTime; + + @ApiModelPropertyEnum(enumDesc = "读取状态",value = JudgeEnum.class) + private Integer readStatus; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReceiveQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReceiveQueryDTO.java new file mode 100644 index 00000000..2f93b651 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeReceiveQueryDTO.java @@ -0,0 +1,25 @@ +package com.gangquan360.smartadmin.module.notice.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/12 0012 下午 12:32 + * @since JDK1.8 + */ +@Data +public class NoticeReceiveQueryDTO extends NoticeQueryDTO{ + + @ApiModelProperty(value = "当前登录人",hidden = true) + private Long employeeId; + + @ApiModelProperty(value = "发送状态",hidden = true) + private Integer sendStatus; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeUpdateDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeUpdateDTO.java new file mode 100644 index 00000000..48ec9056 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeUpdateDTO.java @@ -0,0 +1,21 @@ +package com.gangquan360.smartadmin.module.notice.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/11 0011 下午 16:24 + * @since JDK1.8 + */ +@Data +public class NoticeUpdateDTO extends NoticeAddDTO{ + + @ApiModelProperty("id") + private Long id; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeVO.java new file mode 100644 index 00000000..de5ab85c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/dto/NoticeVO.java @@ -0,0 +1,42 @@ +package com.gangquan360.smartadmin.module.notice.domain.dto; +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import lombok.Data; +import java.util.Date; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 12:27 + * @since JDK1.8 + */ +@Data +public class NoticeVO { + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("消息标题") + private String title; + + + @ApiModelProperty("消息创建人") + private Long createUser; + + @ApiModelPropertyEnum(enumDesc = "发送状态",value = JudgeEnum.class) + private Integer sendStatus; + + @ApiModelProperty("消息创建人名称") + private String createUserName; + + @ApiModelProperty("创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private Date createTime; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/entity/NoticeEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/entity/NoticeEntity.java new file mode 100644 index 00000000..782e8ae6 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/entity/NoticeEntity.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.module.notice.domain.entity; +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-07-11 16:19:48 + * @since JDK1.8 + */ +@Data +@TableName("t_notice") +public class NoticeEntity extends BaseEntity { + + /** + * 消息标题 + */ + private String title; + + /** + * 消息内容 + */ + private String content; + + /** + * 消息创建人 + */ + private Long createUser; + + /** + * 发送状态 + */ + private Integer sendStatus; + + /** + * 删除状态 + */ + private Integer deleted; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/entity/NoticeReceiveRecordEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/entity/NoticeReceiveRecordEntity.java new file mode 100644 index 00000000..6af997ea --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/notice/domain/entity/NoticeReceiveRecordEntity.java @@ -0,0 +1,33 @@ +package com.gangquan360.smartadmin.module.notice.domain.entity; +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019-07-11 16:19:48 + * @since JDK1.8 + */ +@Data +@TableName("t_notice_receive_record") +public class NoticeReceiveRecordEntity extends BaseEntity{ + + + /** + * 消息id + */ + private Long noticeId; + + /** + * 消息接收人 + */ + private Long employeeId; + + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionController.java new file mode 100644 index 00000000..548068ca --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionController.java @@ -0,0 +1,59 @@ +package com.gangquan360.smartadmin.module.position; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionAddDTO; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionQueryDTO; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionResultVO; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionUpdateDTO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * @author zzr + */ +@Api(tags = {SwaggerTagConst.Admin.MANAGER_JOB}) +@OperateLog +@RestController +public class PositionController { + + @Autowired + private PositionService positionService; + + @ApiOperation(value = "分页查询所有岗位", notes = "分页查询所有岗位 @author zzr") + @PostMapping("/position/getListPage") + public ResponseDTO> getJobPage(@RequestBody @Valid PositionQueryDTO queryDTO) { + return positionService.queryPositionByPage(queryDTO); + } + + @ApiOperation(value = "添加岗位", notes = "添加岗位 @author zzr") + @PostMapping("/position/add") + public ResponseDTO addJob(@RequestBody @Valid PositionAddDTO addDTO) { + return positionService.addPosition(addDTO); + } + + @ApiOperation(value = "更新岗位", notes = "更新岗位 @author zzr") + @PostMapping("/position/update") + public ResponseDTO updateJob(@RequestBody @Valid PositionUpdateDTO updateDTO) { + return positionService.updatePosition(updateDTO); + } + + @ApiOperation(value = "根据ID查询岗位", notes = "根据ID查询岗位 @author zzr") + @GetMapping("/position/queryById/{id}") + public ResponseDTO queryJobById(@PathVariable Long id) { + return positionService.queryPositionById(id); + } + + @ApiOperation(value = "根据ID删除岗位", notes = "根据ID删除岗位 @author zzr") + @GetMapping("/position/remove/{id}") + public ResponseDTO removeJob(@PathVariable Long id) { + return positionService.removePosition(id); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionDao.java new file mode 100644 index 00000000..ebb0a968 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionDao.java @@ -0,0 +1,56 @@ +package com.gangquan360.smartadmin.module.position; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.pagination.Pagination; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionQueryDTO; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionRelationAddDTO; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionRelationQueryDTO; +import com.gangquan360.smartadmin.module.position.domain.dto.PositionRelationResultDTO; +import com.gangquan360.smartadmin.module.position.domain.entity.PositionEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * @author zzr + */ +@Mapper +@Component +public interface PositionDao extends BaseMapper { + + /** + * 查询岗位列表 + * + * @param page + * @param queryDTO + * @return + */ + List selectByPage(Pagination page, PositionQueryDTO queryDTO); + + /** + * 查询岗位与人员关系 + * + * @param positionRelationQueryDTO + * @return + */ + List selectRelation(PositionRelationQueryDTO positionRelationQueryDTO); + + /** + * 批量添加岗位 人员 关联关系 + * + * @param positionRelationAddDTO + * @return + */ + Integer insertBatchRelation(@Param("batchDTO")PositionRelationAddDTO positionRelationAddDTO); + + /** + * 删除指定人员的 岗位关联关系 + * + * @param employeeId + * @return + */ + Integer deleteRelationByEmployeeId(@Param("employeeId") Long employeeId); + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionResponseCodeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionResponseCodeConst.java new file mode 100644 index 00000000..5e8d66da --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionResponseCodeConst.java @@ -0,0 +1,16 @@ +package com.gangquan360.smartadmin.module.position; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + +/** + * @author zzr + */ +public class PositionResponseCodeConst extends ResponseCodeConst { + + public static final PositionResponseCodeConst REMOVE_DEFINE = new PositionResponseCodeConst(13000, "还有人关联该岗位,不能删除"); + + protected PositionResponseCodeConst(int code, String msg) { + super(code, msg); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionService.java new file mode 100644 index 00000000..60a7c8db --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/PositionService.java @@ -0,0 +1,124 @@ +package com.gangquan360.smartadmin.module.position; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.position.domain.dto.*; +import com.gangquan360.smartadmin.module.position.domain.entity.PositionEntity; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author zzr + */ +@Service +public class PositionService { + + @Autowired + private PositionDao positionDao; + + /** + * 查询岗位 + * + * @param queryDTO + * @return + */ + public ResponseDTO> queryPositionByPage(PositionQueryDTO queryDTO) { + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List entityList = positionDao.selectByPage(page, queryDTO); + page.setRecords(entityList.stream().map(e -> SmartBeanUtil.copy(e, PositionResultVO.class)).collect(Collectors.toList())); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * 新增岗位 + * + * @param addDTO + * @return + */ + public ResponseDTO addPosition(PositionAddDTO addDTO) { + PositionEntity positionEntity = SmartBeanUtil.copy(addDTO, PositionEntity.class); + positionDao.insert(positionEntity); + return ResponseDTO.succ(); + } + + /** + * 修改岗位 + * + * @param updateDTO + * @return + */ + public ResponseDTO updatePosition(PositionUpdateDTO updateDTO) { + PositionEntity positionEntity = SmartBeanUtil.copy(updateDTO, PositionEntity.class); + positionDao.updateById(positionEntity); + return ResponseDTO.succ(); + } + + /** + * 根据ID查询 + * + * @param id + * @return + */ + public ResponseDTO queryPositionById(Long id) { + return ResponseDTO.succData(SmartBeanUtil.copy(positionDao.selectById(id), PositionResultVO.class)); + } + + /** + * 删除岗位 + */ + public ResponseDTO removePosition(Long id) { + //查询是否还有人关联该岗位 + PositionRelationQueryDTO positionRelationQueryDTO = new PositionRelationQueryDTO(); + positionRelationQueryDTO.setPositionId(id); + List dtoList = positionDao.selectRelation(positionRelationQueryDTO); + if (CollectionUtils.isNotEmpty(dtoList)) { + return ResponseDTO.wrap(PositionResponseCodeConst.REMOVE_DEFINE); + } + positionDao.deleteById(id); + return ResponseDTO.succ(); + } + + /** + * 添加岗位关联关系 + * + * @param positionRelAddDTO + * @return + */ + public ResponseDTO addPositionRelation(PositionRelationAddDTO positionRelAddDTO) { + positionDao.insertBatchRelation(positionRelAddDTO); + return ResponseDTO.succ(); + } + + /** + * 删除指定用户的岗位关联关系 + * + * @param employeeId + * @return + */ + public ResponseDTO removePositionRelation(Long employeeId) { + positionDao.deleteRelationByEmployeeId(employeeId); + return ResponseDTO.succ(); + } + + /** + * 根据员工ID查询 所关联的岗位信息 + * + * @param employeeId + * @return + */ + public List queryPositionByEmployeeId(Long employeeId) { + PositionRelationQueryDTO positionRelationQueryDTO = new PositionRelationQueryDTO(); + positionRelationQueryDTO.setEmployeeId(employeeId); + List positionRelationList = positionDao.selectRelation(positionRelationQueryDTO); + return positionRelationList; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionAddDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionAddDTO.java new file mode 100644 index 00000000..b061af61 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionAddDTO.java @@ -0,0 +1,28 @@ +package com.gangquan360.smartadmin.module.position.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; + +/** + * 岗位 + * + * @author zzr + */ +@Data +public class PositionAddDTO { + + /** + * 岗位名称 + */ + @ApiModelProperty("岗位名称") + @NotBlank(message = "岗位名称不能为空") + private String positionName; + + /** + * 岗位描述 + */ + @ApiModelProperty("岗位描述") + private String remark; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionQueryDTO.java new file mode 100644 index 00000000..b4bd5d8e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionQueryDTO.java @@ -0,0 +1,18 @@ +package com.gangquan360.smartadmin.module.position.domain.dto; + +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 岗位 + * + * @author zzr + */ +@Data +public class PositionQueryDTO extends PageParamDTO { + + @ApiModelProperty("岗位名称") + private String positionName; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationAddDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationAddDTO.java new file mode 100644 index 00000000..fbbbaaf1 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationAddDTO.java @@ -0,0 +1,32 @@ +package com.gangquan360.smartadmin.module.position.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 岗位关系 + * + * @author zzr + */ +@Data +public class PositionRelationAddDTO { + + @ApiModelProperty("岗位ID") + @NotNull(message = "岗位ID 不能为空") + private List positionIdList; + + @ApiModelProperty("员工ID") + @NotNull(message = "员工ID 不能为空") + private Long employeeId; + + public PositionRelationAddDTO() { + } + + public PositionRelationAddDTO(List positionIdList, Long employeeId) { + this.positionIdList = positionIdList; + this.employeeId = employeeId; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationQueryDTO.java new file mode 100644 index 00000000..ed6803f5 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationQueryDTO.java @@ -0,0 +1,20 @@ +package com.gangquan360.smartadmin.module.position.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 岗位关系 + * + * @author zzr + */ +@Data +public class PositionRelationQueryDTO { + + @ApiModelProperty("岗位ID") + private Long positionId; + + @ApiModelProperty("员工ID") + private Long employeeId; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationResultDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationResultDTO.java new file mode 100644 index 00000000..865e3431 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionRelationResultDTO.java @@ -0,0 +1,40 @@ +package com.gangquan360.smartadmin.module.position.domain.dto; + +import lombok.Data; + +import java.util.Date; + +/** + * 岗位关联关系 + * + * @author zzr + */ +@Data +public class PositionRelationResultDTO { + + /** + * 岗位ID + */ + private Long positionId; + + /** + * 员工ID + */ + private Long employeeId; + + /** + * 岗位名称 + */ + private String positionName; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionResultVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionResultVO.java new file mode 100644 index 00000000..ff317fb0 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionResultVO.java @@ -0,0 +1,41 @@ +package com.gangquan360.smartadmin.module.position.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * @author zzr + */ +@Data +public class PositionResultVO { + + @ApiModelProperty("主键") + private Long id; + + /** + * 更新时间 + */ + @ApiModelProperty("更新时间") + private Date updateTime; + + /** + * 创建时间 + */ + @ApiModelProperty("创建时间") + private Date createTime; + + /** + * 岗位名称 + */ + @ApiModelProperty("岗位名称") + private String positionName; + + /** + * 岗位描述 + */ + @ApiModelProperty("岗位描述") + private String remark; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionUpdateDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionUpdateDTO.java new file mode 100644 index 00000000..52c2e1cd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/dto/PositionUpdateDTO.java @@ -0,0 +1,16 @@ +package com.gangquan360.smartadmin.module.position.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * 岗位 + * + * @author zzr + */ +@Data +public class PositionUpdateDTO extends PositionAddDTO { + + @ApiModelProperty("主键") + private Long id; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/entity/PositionEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/entity/PositionEntity.java new file mode 100644 index 00000000..23d1c9d6 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/entity/PositionEntity.java @@ -0,0 +1,26 @@ +package com.gangquan360.smartadmin.module.position.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * 岗位 + * + * @author zzr + */ +@Data +@TableName("t_position") +public class PositionEntity extends BaseEntity { + + /** + * 岗位名称 + */ + private String positionName; + + /** + * 岗位描述 + */ + private String remark; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/entity/PositionRelationEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/entity/PositionRelationEntity.java new file mode 100644 index 00000000..1478134b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/position/domain/entity/PositionRelationEntity.java @@ -0,0 +1,26 @@ +package com.gangquan360.smartadmin.module.position.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * 岗位关联关系 + * + * @author zzr + */ +@Data +@TableName("t_position_relation") +public class PositionRelationEntity extends BaseEntity { + + /** + * 岗位ID + */ + private Long positionId; + + /** + * 员工ID + */ + private Long employeeId; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/constant/PrivilegeResponseCodeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/constant/PrivilegeResponseCodeConst.java new file mode 100644 index 00000000..dd5f09fc --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/constant/PrivilegeResponseCodeConst.java @@ -0,0 +1,24 @@ +package com.gangquan360.smartadmin.module.privilege.constant; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + + +/** + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +public class PrivilegeResponseCodeConst extends ResponseCodeConst { + + public static final PrivilegeResponseCodeConst PRIVILEGE_NOT_EXISTS = new PrivilegeResponseCodeConst(7001, "当前数据不存在,请联系你的管理员!"); + + public static final PrivilegeResponseCodeConst ROUTER_KEY_NO_REPEAT = new PrivilegeResponseCodeConst(7002, "模块和页面的“功能Key”值不能重复!"); + + public PrivilegeResponseCodeConst(int code, String msg) { + super(code, msg); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/constant/PrivilegeTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/constant/PrivilegeTypeEnum.java new file mode 100644 index 00000000..137d5f20 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/constant/PrivilegeTypeEnum.java @@ -0,0 +1,49 @@ +package com.gangquan360.smartadmin.module.privilege.constant; + + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +import java.util.Arrays; +import java.util.Optional; + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +public enum PrivilegeTypeEnum implements BaseEnum { + + + MENU(1,"菜单"), + + POINTS(2,"功能点"); + + private Integer value; + + private String desc; + + PrivilegeTypeEnum(Integer value,String desc){ + this.value = value; + this.desc = desc; + } + @Override + public Integer getValue() { + return this.value; + } + + @Override + public String getDesc() { + return this.desc; + } + + public static PrivilegeTypeEnum selectByValue(Integer value) { + Optional first = Arrays.stream(PrivilegeTypeEnum.values()).filter(e -> e.getValue().equals(value)).findFirst(); + return !first.isPresent() ? null : first.get(); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/controller/PrivilegeController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/controller/PrivilegeController.java new file mode 100644 index 00000000..f1126a3f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/controller/PrivilegeController.java @@ -0,0 +1,68 @@ +package com.gangquan360.smartadmin.module.privilege.controller; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.privilege.domain.dto.*; +import com.gangquan360.smartadmin.module.privilege.service.PrivilegeService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * [ 与员工权限相关:角色权限关系、权限列表 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@OperateLog +@RestController +@Api(tags = {SwaggerTagConst.Admin.MANAGER_PRIVILEGE}) +public class PrivilegeController { + + @Autowired + private PrivilegeService privilegeService; + + @GetMapping("/privilege/getAllUrl") + @ApiOperation(value = "获取所有请求路径", notes = "获取所有请求路径") + public ResponseDTO> getAllUrl() { + return privilegeService.getPrivilegeUrlDTOList(); + } + + @ApiOperation(value = "菜单批量保存") + @PostMapping("/privilege/menu/batchSaveMenu") + public ResponseDTO menuBatchSave(@Valid @RequestBody List menuList) { + return privilegeService.menuBatchSave(menuList); +// return ResponseDTO.succ(); + } + + @ApiOperation(value = "查询所有菜单项") + @PostMapping("/privilege/menu/queryAll") + public ResponseDTO> queryAll() { + return privilegeService.menuQueryAll(); + } + + + @ApiOperation(value = "保存更新功能点") + @PostMapping("/privilege/function/saveOrUpdate") + public ResponseDTO functionSaveOrUpdate(@Valid @RequestBody PrivilegeFunctionDTO privilegeFunctionDTO) { + return privilegeService.functionSaveOrUpdate(privilegeFunctionDTO); +// return ResponseDTO.succ(); + } + + @ApiOperation(value = "查询菜单功能点", notes = "更新") + @PostMapping("/privilege/function/query/{menuKey}") + public ResponseDTO> functionQuery(@PathVariable String menuKey) { + return privilegeService.functionQuery(menuKey); + } + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/dao/PrivilegeDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/dao/PrivilegeDao.java new file mode 100644 index 00000000..aaa8d5cd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/dao/PrivilegeDao.java @@ -0,0 +1,87 @@ +package com.gangquan360.smartadmin.module.privilege.dao; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.gangquan360.smartadmin.module.privilege.domain.entity.PrivilegeEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Mapper +@Component +public interface PrivilegeDao extends BaseMapper { + + /** + * 根据权限key删除 + * @param keyList + */ + void delByKeyList(@Param("keyList") List keyList); + /** + * 根据权限parentkey删除 + * @param keyList + */ + void delByParentKeyList(@Param("keyList") List keyList); + + /** + * 批量保存 + * @param privilegeList + */ + void batchInsert(List privilegeList); + + /** + * 批量更新 + * @param privilegeList + */ + void batchUpdate(@Param("updateList") List privilegeList); + + /** + * 根据父节点key查询 + * @param parentKey + * @return + */ + List selectByParentKey(@Param("parentKey") String parentKey); + + /** + * 根据权限key查询 + * @param key + * @return + */ + PrivilegeEntity selectByKey(@Param("key") String key); + + /** + * 根据类型查询 + * @param type + * @return + */ + List selectByExcludeType(@Param("type") Integer type); + + /** + * 根据类型查询 + * @param type + * @return + */ + List selectByType(@Param("type") Integer type); + + /** + * 查询所有权限 + * @return + */ + List selectAll(); + + + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeFunctionDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeFunctionDTO.java new file mode 100644 index 00000000..8feca1be --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeFunctionDTO.java @@ -0,0 +1,41 @@ +package com.gangquan360.smartadmin.module.privilege.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/20 0020 下午 16:45 + * @since JDK1.8 + */ +@Data +public class PrivilegeFunctionDTO { + + @ApiModelProperty("功能点名称") + @NotBlank(message = "功能点名称不能为空") + private String functionName; + + @ApiModelProperty("所属菜单Key") + @NotBlank(message = "所属菜单Key不能为空") + private String menuKey; + + @ApiModelProperty("功能点Key") + @NotBlank(message = "功能点Key不能为空") + private String functionKey; + + @ApiModelProperty("url列表") + private String url; + + @ApiModelProperty("排序") + @NotNull(message = "请输入功能点顺序") + private Integer sort; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeFunctionVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeFunctionVO.java new file mode 100644 index 00000000..337317a3 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeFunctionVO.java @@ -0,0 +1,41 @@ +package com.gangquan360.smartadmin.module.privilege.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/20 0020 下午 16:45 + * @since JDK1.8 + */ +@Data +public class PrivilegeFunctionVO { + + @ApiModelProperty("功能点名称") + @NotBlank(message = "功能点名称不能为空") + private String functionName; + + @ApiModelProperty("所属菜单Key") + @NotBlank(message = "所属菜单Key不能为空") + private String menuKey; + + @ApiModelProperty("功能点Key") + @NotBlank(message = "功能点Key不能为空") + private String functionKey; + + @ApiModelProperty("url列表") + @NotEmpty(message = "url列表不能为空") + private String url; + + @ApiModelProperty("顺序") + private Integer sort; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeMenuDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeMenuDTO.java new file mode 100644 index 00000000..fc13811d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeMenuDTO.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.module.privilege.domain.dto; + +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.module.privilege.constant.PrivilegeTypeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/20 0020 下午 16:32 + * @since JDK1.8 + */ +@Data +public class PrivilegeMenuDTO { + + @ApiModelPropertyEnum(enumDesc = "菜单类型",value = PrivilegeTypeEnum.class) + @NotNull + private Integer type; + + @ApiModelProperty("菜单名") + @NotNull(message = "菜单名不能为空") + private String menuName; + + @ApiModelProperty("菜单Key") + @NotNull(message = "菜单Key不能为空") + private String menuKey; + + @ApiModelProperty("父级菜单Key,根节点不传") + private String parentKey; + + @ApiModelProperty("前端路由path") + @NotNull(message = "前端路由path不能为空") + private String url; + + @ApiModelProperty("排序字段") + @NotNull(message = "菜单项顺序不能为空") + private Integer sort; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeMenuListVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeMenuListVO.java new file mode 100644 index 00000000..62aec553 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeMenuListVO.java @@ -0,0 +1,37 @@ +package com.gangquan360.smartadmin.module.privilege.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/8/20 0020 下午 16:41 + * @since JDK1.8 + */ +@Data +public class PrivilegeMenuListVO { + + @ApiModelProperty("菜单名") + private String menuName; + + @ApiModelProperty("菜单Key") + private String menuKey; + + @ApiModelProperty("菜单父级Key") + private String parentKey; + + @ApiModelProperty("顺序") + private Integer sort; + + @ApiModelProperty("子菜单列表") + private List menuList; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeRequestUrlVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeRequestUrlVO.java new file mode 100644 index 00000000..87757aaa --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/dto/PrivilegeRequestUrlVO.java @@ -0,0 +1,27 @@ +package com.gangquan360.smartadmin.module.privilege.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/28 0028 上午 9:20 + * @since JDK1.8 + */ +@Data +public class PrivilegeRequestUrlVO { + + @ApiModelProperty("注释说明") + private String comment; + + @ApiModelProperty("controller.method") + private String name; + + @ApiModelProperty("url") + private String url; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/entity/PrivilegeEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/entity/PrivilegeEntity.java new file mode 100644 index 00000000..0eab5264 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/domain/entity/PrivilegeEntity.java @@ -0,0 +1,55 @@ +package com.gangquan360.smartadmin.module.privilege.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +import java.io.Serializable; + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +@TableName("t_privilege") +public class PrivilegeEntity extends BaseEntity implements Serializable { + private static final long serialVersionUID = 3848408566432915214L; + + /** + * 功能权限类型:1.模块 2.页面 3.功能点 4.子模块 + */ + private Integer type; + + /** + * 菜单名称 + */ + private String name; + + /** + * 路由name 英文关键字 + */ + private String key; + + + private String url; + + /** + * 排序 + */ + private Integer sort; + + + /** + * 父级key + */ + private String parentKey; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeEmployeeService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeEmployeeService.java new file mode 100644 index 00000000..e843ff1f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeEmployeeService.java @@ -0,0 +1,196 @@ +package com.gangquan360.smartadmin.module.privilege.service; + +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import com.gangquan360.smartadmin.common.exception.SmartBusinessException; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import com.gangquan360.smartadmin.module.privilege.constant.PrivilegeTypeEnum; +import com.gangquan360.smartadmin.module.privilege.dao.PrivilegeDao; +import com.gangquan360.smartadmin.module.privilege.domain.entity.PrivilegeEntity; +import com.gangquan360.smartadmin.module.role.roleemployee.RoleEmployeeDao; +import com.gangquan360.smartadmin.module.role.roleprivilege.RolePrivilegeDao; +import com.gangquan360.smartadmin.module.systemconfig.SystemConfigService; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigEnum; +import com.gangquan360.smartadmin.module.systemconfig.domain.dto.SystemConfigDTO; +import com.gangquan360.smartadmin.util.SmartStringUtil; +import com.google.common.collect.Lists; +import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.concurrent.ConcurrentMap; +import java.util.stream.Collectors; + +/** + * [ 后台员工权限缓存方法 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/28 0028 下午 14:07 + * @since JDK1.8 + */ +@Service +public class PrivilegeEmployeeService { + + /** + * 后台用户权限缓存 > + */ + private ConcurrentMap>> employeePrivileges = new ConcurrentLinkedHashMap.Builder>>().maximumWeightedCapacity(1000).build(); + private ConcurrentMap> employeePrivilegeListMap = new ConcurrentLinkedHashMap.Builder>().maximumWeightedCapacity(1000).build(); + + @Autowired + private SystemConfigService systemConfigService; + + @Autowired + private RoleEmployeeDao roleEmployeeDao; + + @Autowired + private RolePrivilegeDao rolePrivilegeDao; + + @Autowired + private PrivilegeDao privilegeDao; + + /** + * 移除某人缓存中的权限 + * + * @param employeeId + */ + public void removeCache(Long employeeId) { + this.employeePrivileges.remove(employeeId); + } + + /** + * 检查某人是否有访问某个方法的权限 + * + * @param requestTokenBO + * @param controllerName + * @param methodName + * @return + */ + public Boolean checkEmployeeHavePrivilege(RequestTokenBO requestTokenBO, String controllerName, String methodName) { + if (StringUtils.isEmpty(controllerName) || StringUtils.isEmpty(methodName)) { + return false; + } + Boolean isSuperman = requestTokenBO.getEmployeeBO().getIsSuperman(); + if (isSuperman) { + return true; + } + Map> privileges = this.getPrivileges(requestTokenBO.getRequestUserId()); + List urlList = privileges.get(controllerName.toLowerCase()); + if (CollectionUtils.isEmpty(urlList)) { + return false; + } + return urlList.contains(methodName); + } + + public List getEmployeeAllPrivilege(Long employeeId){ + return employeePrivilegeListMap.get(employeeId); + } + + /** + * 判断是否为超级管理员 + * + * @param employeeId + * @return + */ + public Boolean isSuperman(Long employeeId) { + SystemConfigDTO systemConfig = systemConfigService.getCacheByKey(SystemConfigEnum.Key.EMPLOYEE_SUPERMAN); + if (systemConfig == null) { + throw new SmartBusinessException("缺少系统配置项[" + SystemConfigEnum.Key.EMPLOYEE_SUPERMAN.name() + "]"); + } + + List superManIdsList = SmartStringUtil.splitConverToLongList(systemConfig.getConfigValue(), ","); + return superManIdsList.contains(employeeId); + } + + /** + * 根据员工ID 获取 权限信息 + * + * @param employeeId + * @return + */ + public List getPrivilegesByEmployeeId(Long employeeId) { + // 如果是超管的话 + Boolean isSuperman = this.isSuperman(employeeId); + if (isSuperman) { + List privilegeEntities = privilegeDao.selectAll(); + if (privilegeEntities == null) { + return Lists.newArrayList(); + } + return privilegeEntities; + } + List privilegeEntities = loadPrivilegeFromDb(employeeId); + this.updateCachePrivilege(employeeId, privilegeEntities); + return privilegeEntities; + } + + /** + * 获取某人所能访问的方法 + * + * @param employeeId + * @return + */ + private Map> getPrivileges(Long employeeId) { + Map> privileges = employeePrivileges.get(employeeId); + if (privileges != null) { + return privileges; + } + List privilegeEntities = this.loadPrivilegeFromDb(employeeId); + return updateCachePrivilege(employeeId, privilegeEntities); + } + + private List loadPrivilegeFromDb(Long employeeId) { + List roleIdList = roleEmployeeDao.selectRoleIdByEmployeeId(employeeId); + if (CollectionUtils.isEmpty(roleIdList)) { + return Lists.newArrayList(); + } + List privilegeEntities = rolePrivilegeDao.listByRoleIds(roleIdList, JudgeEnum.YES.getValue()); + if (privilegeEntities != null) { + return privilegeEntities; + } + return Collections.emptyList(); + } + + public Map> updateCachePrivilege(Long employeeId, List privilegeEntities) { + employeePrivilegeListMap.put(employeeId,privilegeEntities); + List privilegeList = new ArrayList<>(); + Map> privilegeMap = new HashMap<>(16); + if (CollectionUtils.isNotEmpty(privilegeEntities)) { + List> setList = + privilegeEntities.stream().filter(e -> e.getType().equals(PrivilegeTypeEnum.POINTS.getValue())).map(PrivilegeEntity :: getUrl).collect(Collectors.toList()).stream().map(e -> SmartStringUtil.splitConvertToList(e, ",")).collect(Collectors.toList()); + setList.forEach(privilegeList :: addAll); + } + privilegeList.forEach(item -> { + List path = SmartStringUtil.splitConvertToList(item, "\\."); + String controllerName = path.get(0).toLowerCase(); + String methodName = path.get(1); + List methodNameList = privilegeMap.get(controllerName); + if (null == methodNameList) { + methodNameList = new ArrayList(); + } + if (! methodNameList.contains(methodName)) { + methodNameList.add(methodName); + } + privilegeMap.put(controllerName, methodNameList); + }); + + employeePrivileges.put(employeeId, privilegeMap); + return privilegeMap; + } + + public void updateOnlineEmployeePrivilegeByRoleId(Long roleId) { + List roleEmployeeList = roleEmployeeDao.selectEmployeeByRoleId(roleId); + List employeeIdList = roleEmployeeList.stream().map(e -> e.getId()).collect(Collectors.toList()); + + for (Long empId : employeePrivileges.keySet()) { + if (employeeIdList.contains(empId)) { + getPrivilegesByEmployeeId(empId); + } + } + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeRequestUrlService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeRequestUrlService.java new file mode 100644 index 00000000..3be2af57 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeRequestUrlService.java @@ -0,0 +1,117 @@ +package com.gangquan360.smartadmin.module.privilege.service; + +import com.gangquan360.smartadmin.constant.CommonConst; +import com.gangquan360.smartadmin.module.privilege.domain.dto.PrivilegeRequestUrlVO; +import com.gangquan360.smartadmin.util.SmartStringUtil; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.stereotype.Service; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.method.RequestMappingInfo; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; + +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * [ 初始化 分离前后台权限URL ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/28 0028 上午 9:13 + * @since JDK1.8 + */ +@Service +public class PrivilegeRequestUrlService { + + /** + * 系统所有requestUrl + */ + private CopyOnWriteArrayList privilegeUrlDTOList = Lists.newCopyOnWriteArrayList(); + + @Autowired + private WebApplicationContext applicationContext; + + @PostConstruct + public void initAllUrl() { + this.privilegeUrlDTOList.clear(); + + RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class); + //获取url与类和方法的对应信息 + Map map = mapping.getHandlerMethods(); + map.forEach((info, handlerMethod) -> { + //只对Rest 服务进行权限验证 + RestController restAnnotation = AnnotationUtils.findAnnotation(handlerMethod.getMethod().getDeclaringClass(), RestController.class); + if (restAnnotation == null) { + ResponseBody responseBody = handlerMethod.getMethod().getAnnotation(ResponseBody.class); + if (responseBody == null) { + return; + } + } + //获取url的Set集合,一个方法可能对应多个url + Set patterns = info.getPatternsCondition().getPatterns(); + if (CollectionUtils.isEmpty(patterns)) { + return; + } + String className = (String) handlerMethod.getBean(); + String methodName = handlerMethod.getMethod().getName(); + List list = SmartStringUtil.splitConvertToList(className, "\\."); + String controllerName = list.get(list.size() - 1); + String name = controllerName + "." + methodName; + + ApiOperation apiOperation = handlerMethod.getMethod().getAnnotation(ApiOperation.class); + String methodComment = null; + if (apiOperation != null) { + methodComment = apiOperation.value(); + } else { + ApiModelProperty apiModelProperty = handlerMethod.getMethod().getAnnotation(ApiModelProperty.class); + if (apiModelProperty != null) { + methodComment = apiModelProperty.value(); + } else { + methodComment = handlerMethod.getMethod().getName(); + } + } + Set urlSet = this.getUrlSet(patterns); + for (String url : urlSet) { + PrivilegeRequestUrlVO privilegeUrlDTO = new PrivilegeRequestUrlVO(); + privilegeUrlDTO.setUrl(url); + privilegeUrlDTO.setName(name); + privilegeUrlDTO.setComment(methodComment); + this.privilegeUrlDTOList.add(privilegeUrlDTO); + } + + }); + } + + private Set getUrlSet(Set patterns) { + Set urlSet = Sets.newHashSet(); + for (String url : patterns) { + for (String ignoreUrl : CommonConst.CommonCollection.IGNORE_URL_MAPPING) { + if (url.startsWith(ignoreUrl)) { + urlSet.add(url.substring(ignoreUrl.length() - 1)); + } else { + urlSet.add(url); + } + } + } + return urlSet; + } + + public List getPrivilegeList() { + return this.privilegeUrlDTOList; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeService.java new file mode 100644 index 00000000..94b0ac9e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/privilege/service/PrivilegeService.java @@ -0,0 +1,217 @@ +package com.gangquan360.smartadmin.module.privilege.service; + +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.privilege.constant.PrivilegeTypeEnum; +import com.gangquan360.smartadmin.module.privilege.dao.PrivilegeDao; +import com.gangquan360.smartadmin.module.privilege.domain.dto.*; +import com.gangquan360.smartadmin.module.privilege.domain.entity.PrivilegeEntity; +import com.gangquan360.smartadmin.module.role.roleprivilege.RolePrivilegeDao; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.google.common.collect.Lists; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * [ 后台员工权限 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Service +public class PrivilegeService { + + @Autowired + private PrivilegeRequestUrlService privilegeRequestUrlService; + + @Autowired + private PrivilegeDao privilegeDao; + + @Autowired + private RolePrivilegeDao rolePrivilegeDao; + + /** + * 获取系统所有请求路径 + * + * @return + */ + public ResponseDTO> getPrivilegeUrlDTOList() { + List privilegeUrlList = privilegeRequestUrlService.getPrivilegeList(); + return ResponseDTO.succData(privilegeUrlList); + } + + /** + * 批量保存权限菜单项 + * + * @param menuList + * @return + */ + @Transactional(rollbackFor = Throwable.class) + public ResponseDTO menuBatchSave(List menuList) { + if (CollectionUtils.isEmpty(menuList)) { + return ResponseDTO.succ(); + } + List privilegeList = privilegeDao.selectByExcludeType(PrivilegeTypeEnum.POINTS.getValue()); + //若数据库无数据 直接全部保存 + if (CollectionUtils.isEmpty(privilegeList)) { + List menuSaveEntity = this.buildPrivilegeMenuEntity(menuList); + privilegeDao.batchInsert(menuSaveEntity); + return ResponseDTO.succ(); + } + //处理需更新的菜单项 + Map storageMap = menuList.stream().collect(Collectors.toMap(PrivilegeMenuDTO::getMenuKey, e -> e)); + Set menuKeyList = storageMap.keySet(); + List updatePrivilegeList = privilegeList.stream().filter(e -> menuKeyList.contains(e.getKey())).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(updatePrivilegeList)) { + this.rebuildPrivilegeMenuEntity(storageMap, updatePrivilegeList); + privilegeDao.batchUpdate(updatePrivilegeList); + } + //处理需删除的菜单项 + List delKeyList = privilegeList.stream().filter(e -> !menuKeyList.contains(e.getKey())).map(PrivilegeEntity::getKey).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(delKeyList)) { + privilegeDao.delByKeyList(delKeyList); + //处理需删除的功能点 + privilegeDao.delByParentKeyList(delKeyList); + rolePrivilegeDao.deleteByPrivilegeKey(delKeyList); + } + + //处理需新增的菜单项 + List dbKeyList = privilegeList.stream().map(PrivilegeEntity::getKey).collect(Collectors.toList()); + List addPrivilegeList = menuList.stream().filter(e -> !dbKeyList.contains(e.getMenuKey())).collect(Collectors.toList()); + if (CollectionUtils.isNotEmpty(addPrivilegeList)) { + List menuAddEntity = this.buildPrivilegeMenuEntity(addPrivilegeList); + privilegeDao.batchInsert(menuAddEntity); + } + return ResponseDTO.succ(); + } + + /** + * 构建权限菜单项类别 + * + * @param menuList + * @return + */ + private List buildPrivilegeMenuEntity(List menuList) { + List privilegeList = Lists.newArrayList(); + PrivilegeEntity privilegeEntity; + for (PrivilegeMenuDTO menuDTO : menuList) { + privilegeEntity = new PrivilegeEntity(); + privilegeEntity.setKey(menuDTO.getMenuKey()); + privilegeEntity.setName(menuDTO.getMenuName()); + privilegeEntity.setParentKey(menuDTO.getParentKey()); + privilegeEntity.setType(menuDTO.getType()); + privilegeEntity.setSort(menuDTO.getSort()); + privilegeEntity.setUrl(menuDTO.getUrl()); + privilegeList.add(privilegeEntity); + } + return privilegeList; + } + + /** + * 更新权限菜单项 + * + * @param menuMap + * @param menuEntityList + */ + private void rebuildPrivilegeMenuEntity(Map menuMap, List menuEntityList) { + for (PrivilegeEntity menuEntity : menuEntityList) { + PrivilegeMenuDTO menuDTO = menuMap.get(menuEntity.getKey()); + menuEntity.setName(menuDTO.getMenuName()); + menuEntity.setParentKey(menuDTO.getParentKey()); + menuEntity.setType(menuDTO.getType()); + menuEntity.setSort(menuDTO.getSort()); + } + + } + + /** + * 查询所有的权限菜单 + * + * @return + */ + public ResponseDTO> menuQueryAll() { + List privilegeEntityList = privilegeDao.selectByType(PrivilegeTypeEnum.MENU.getValue()); + if (CollectionUtils.isEmpty(privilegeEntityList)) { + return ResponseDTO.succData(Lists.newArrayList()); + } + + List voList = privilegeEntityList.stream().map( e-> { + PrivilegeMenuListVO vo = new PrivilegeMenuListVO(); + vo.setMenuKey(e.getKey()); + vo.setMenuName(e.getName()); + vo.setParentKey(e.getParentKey()); + vo.setSort(e.getSort()); + return vo; + }).collect(Collectors.toList()); + + return ResponseDTO.succData(voList); + } + + + /** + * 保存更新功能点 + * + * @param privilegeFunctionDTO + * @return + */ + public ResponseDTO functionSaveOrUpdate(PrivilegeFunctionDTO privilegeFunctionDTO) { + String functionKey = privilegeFunctionDTO.getFunctionKey(); + PrivilegeEntity functionEntity = privilegeDao.selectByKey(functionKey); + if (functionEntity == null) { + functionEntity = new PrivilegeEntity(); + functionEntity.setName(privilegeFunctionDTO.getFunctionName()); + functionEntity.setParentKey(privilegeFunctionDTO.getMenuKey()); + functionEntity.setType(PrivilegeTypeEnum.POINTS.getValue()); + functionEntity.setUrl(privilegeFunctionDTO.getUrl()); + functionEntity.setKey(privilegeFunctionDTO.getFunctionKey()); + functionEntity.setSort(privilegeFunctionDTO.getSort()); + functionEntity.setCreateTime(new Date()); + functionEntity.setUpdateTime(new Date()); + privilegeDao.insert(functionEntity); + } else { + functionEntity.setUrl(privilegeFunctionDTO.getUrl()); + functionEntity.setName(privilegeFunctionDTO.getFunctionName()); + functionEntity.setParentKey(privilegeFunctionDTO.getMenuKey()); + functionEntity.setSort(privilegeFunctionDTO.getSort()); + privilegeDao.updateById(functionEntity); + } + return ResponseDTO.succ(); + } + + /** + * 查询功能点 + * + * @param menuKey + * @return + */ + public ResponseDTO> functionQuery(String menuKey) { + List functionPrivilegeList = privilegeDao.selectByParentKey(menuKey); + if (CollectionUtils.isEmpty(functionPrivilegeList)) { + return ResponseDTO.succData(Lists.newArrayList()); + } + List functionList = Lists.newArrayList(); + PrivilegeFunctionVO functionDTO; + for (PrivilegeEntity functionEntity : functionPrivilegeList) { + functionDTO = new PrivilegeFunctionVO(); + functionDTO.setFunctionKey(functionEntity.getKey()); + functionDTO.setFunctionName(functionEntity.getName()); + functionDTO.setMenuKey(functionEntity.getParentKey()); + functionDTO.setUrl(functionEntity.getUrl()); + functionDTO.setSort(functionEntity.getSort()); + functionList.add(functionDTO); + } + return ResponseDTO.succData(functionList); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/QuartzConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/QuartzConst.java new file mode 100644 index 00000000..de28155d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/QuartzConst.java @@ -0,0 +1,17 @@ +package com.gangquan360.smartadmin.module.quartz.constant; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 15:21 + * @since JDK1.8 + */ +public class QuartzConst { + public static final String QUARTZ_PARAMS_KEY="TASK_PARAMS"; + public static final String JOB_KEY_PREFIX="TASK_"; + public static final String TRIGGER_KEY_PREFIX="TRIGGER_"; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/TaskResultEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/TaskResultEnum.java new file mode 100644 index 00000000..72e95146 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/TaskResultEnum.java @@ -0,0 +1,47 @@ +package com.gangquan360.smartadmin.module.quartz.constant; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 14:19 + * @since JDK1.8 + */ +public enum TaskResultEnum { + + SUCCESS(0,"成功"), + /** + * + */ + FAIL(1,"失败"); + + public static final String INFO="0:成功,1:失败"; + + private Integer status; + + private String desc; + + TaskResultEnum(Integer status , String desc) { + this.status = status; + this.desc = desc; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/TaskStatusEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/TaskStatusEnum.java new file mode 100644 index 00000000..19e24a87 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/constant/TaskStatusEnum.java @@ -0,0 +1,47 @@ +package com.gangquan360.smartadmin.module.quartz.constant; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 14:19 + * @since JDK1.8 + */ +public enum TaskStatusEnum { + + NORMAL(0,"正常"), + /** + * + */ + PAUSE(1,"暂停"); + + public static final String INFO="0:正常,1:暂停"; + + private Integer status; + + private String desc; + + TaskStatusEnum(Integer status ,String desc) { + this.status = status; + this.desc = desc; + } + + public Integer getStatus() { + return status; + } + + public void setStatus(Integer status) { + this.status = status; + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/controller/QuartzController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/controller/QuartzController.java new file mode 100644 index 00000000..2b76fd16 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/controller/QuartzController.java @@ -0,0 +1,81 @@ +package com.gangquan360.smartadmin.module.quartz.controller; + +import com.gangquan360.smartadmin.common.anno.NoValidPrivilege; +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.quartz.domain.dto.*; +import com.gangquan360.smartadmin.module.quartz.service.QuartzTaskService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@OperateLog +@RestController +@Api(tags = {SwaggerTagConst.Admin.MANAGER_TASK_SCHEDULER}) +public class QuartzController { + + @Autowired + private QuartzTaskService quartzTaskService; + + + @PostMapping("/quartz/task/query") + @ApiOperation(value = "查询任务") + @NoValidPrivilege + public ResponseDTO> query(@RequestBody @Valid QuartzQueryDTO queryDTO){ + return quartzTaskService.query(queryDTO); + } + + + @PostMapping("/quartz/task/queryLog") + @ApiOperation(value = "查询任务运行日志") + @NoValidPrivilege + public ResponseDTO> queryLog(@RequestBody @Valid QuartzLogQueryDTO queryDTO){ + return quartzTaskService.queryLog(queryDTO); + } + + @PostMapping("/quartz/task/saveOrUpdate") + @ApiOperation(value = "新建更新任务") + public ResponseDTO saveOrUpdateTask(@RequestBody @Valid QuartzTaskDTO quartzTaskDTO)throws Exception{ + return quartzTaskService.saveOrUpdateTask(quartzTaskDTO); + } + + @GetMapping("/quartz/task/run/{taskId}") + @ApiOperation(value = "立即运行某个任务") + public ResponseDTO runTask(@PathVariable("taskId") Long taskId)throws Exception{ + return quartzTaskService.runTask(taskId); + } + + @GetMapping("/quartz/task/pause/{taskId}") + @ApiOperation(value = "暂停某个任务") + public ResponseDTO pauseTask(@PathVariable("taskId")Long taskId)throws Exception{ + return quartzTaskService.pauseTask(taskId); + } + + @GetMapping("/quartz/task/resume/{taskId}") + @ApiOperation(value = "恢复某个任务") + public ResponseDTO resumeTask(@PathVariable("taskId")Long taskId)throws Exception{ + return quartzTaskService.resumeTask(taskId); + } + + @GetMapping("/quartz/task/delete/{taskId}") + @ApiOperation(value = "删除某个任务") + public ResponseDTO deleteTask(@PathVariable("taskId")Long taskId)throws Exception{ + return quartzTaskService.deleteTask(taskId); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/dao/QuartzTaskDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/dao/QuartzTaskDao.java new file mode 100644 index 00000000..9813aa71 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/dao/QuartzTaskDao.java @@ -0,0 +1,42 @@ +package com.gangquan360.smartadmin.module.quartz.dao; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.module.quartz.domain.dto.QuartzQueryDTO; +import com.gangquan360.smartadmin.module.quartz.domain.dto.QuartzTaskVO; +import com.gangquan360.smartadmin.module.quartz.domain.entity.QuartzTaskEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 14:35 + * @since JDK1.8 + */ +@Mapper +@Component +public interface QuartzTaskDao extends BaseMapper { + + /** + * 更新任务状态 + * @param taskId + * @param taskStatus + */ + void updateStatus(@Param("taskId") Integer taskId,@Param("taskStatus") Integer taskStatus); + + /** + * 查询列表 + * @param queryDTO + * @return + */ + List queryList(Page page, @Param("queryDTO")QuartzQueryDTO queryDTO); + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/dao/QuartzTaskLogDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/dao/QuartzTaskLogDao.java new file mode 100644 index 00000000..0202e663 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/dao/QuartzTaskLogDao.java @@ -0,0 +1,35 @@ +package com.gangquan360.smartadmin.module.quartz.dao; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.module.quartz.domain.dto.QuartzLogQueryDTO; +import com.gangquan360.smartadmin.module.quartz.domain.dto.QuartzTaskLogVO; +import com.gangquan360.smartadmin.module.quartz.domain.entity.QuartzTaskLogEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 14:35 + * @since JDK1.8 + */ +@Mapper +@Component +public interface QuartzTaskLogDao extends BaseMapper{ + + + /** + * 查询列表 + * @param queryDTO + * @return + */ + List queryList(Page page, @Param("queryDTO")QuartzLogQueryDTO queryDTO); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzLogQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzLogQueryDTO.java new file mode 100644 index 00000000..40450853 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzLogQueryDTO.java @@ -0,0 +1,25 @@ +package com.gangquan360.smartadmin.module.quartz.domain.dto; + +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/15 0015 上午 11:29 + * @since JDK1.8 + */ +@Data +public class QuartzLogQueryDTO extends PageParamDTO { + + @ApiModelProperty(value = "任务Id(不能为空)") + @NotNull(message = "任务Id不能为空") + private Integer taskId; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzQueryDTO.java new file mode 100644 index 00000000..1257291b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzQueryDTO.java @@ -0,0 +1,16 @@ +package com.gangquan360.smartadmin.module.quartz.domain.dto; + +import com.gangquan360.smartadmin.common.domain.PageParamDTO; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/15 0015 上午 11:29 + * @since JDK1.8 + */ +public class QuartzQueryDTO extends PageParamDTO { +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskDTO.java new file mode 100644 index 00000000..001a7a27 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskDTO.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.module.quartz.domain.dto; + +import com.gangquan360.smartadmin.module.quartz.constant.TaskStatusEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 15:42 + * @since JDK1.8 + */ +@Data +public class QuartzTaskDTO { + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("任务名称") + @NotNull(message = "任务名称不能为空") + private String taskName; + + @ApiModelProperty("任务Bean") + @NotNull(message = "任务Bean不能为空") + private String taskBean; + + @ApiModelProperty("任务参数") + private String taskParams; + + @ApiModelProperty("cron") + @NotNull(message = "cron表达式不能为空") + private String taskCron; + + @ApiModelProperty("任务状态:"+ TaskStatusEnum.INFO) + private Integer taskStatus; + + @ApiModelProperty("任务备注") + private String remark; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskLogVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskLogVO.java new file mode 100644 index 00000000..c5015d62 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskLogVO.java @@ -0,0 +1,49 @@ +package com.gangquan360.smartadmin.module.quartz.domain.dto; + +import com.gangquan360.smartadmin.module.quartz.constant.TaskResultEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 15:42 + * @since JDK1.8 + */ +@Data +public class QuartzTaskLogVO { + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("任务id") + private Long taskId; + + @ApiModelProperty("任务名称") + private String taskName; + + @ApiModelProperty("任务参数") + private String taskParams; + + @ApiModelProperty("任务处理状态:"+ TaskResultEnum.INFO) + private Integer processStatus; + + @ApiModelProperty("任务时长ms") + private Long processDuration; + + @ApiModelProperty("处理日志") + private String processLog; + + @ApiModelProperty("创建时间") + private Date createTime; + + + @ApiModelProperty("主机ip") + private String ipAddress; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskVO.java new file mode 100644 index 00000000..20c2c38f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/dto/QuartzTaskVO.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.module.quartz.domain.dto; + +import com.gangquan360.smartadmin.module.quartz.constant.TaskStatusEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 15:42 + * @since JDK1.8 + */ +@Data +public class QuartzTaskVO { + + @ApiModelProperty("id") + private Long id; + + @ApiModelProperty("任务名称") + @NotNull(message = "任务名称不能为空") + private String taskName; + + @ApiModelProperty("任务Bean") + @NotNull(message = "任务Bean不能为空") + private String taskBean; + + @ApiModelProperty("任务参数") + private String taskParams; + + @ApiModelProperty("cron") + @NotNull(message = "cron表达式不能为空") + private String taskCron; + + @ApiModelProperty("任务状态:"+ TaskStatusEnum.INFO) + private Integer taskStatus; + + @ApiModelProperty("任务备注") + private String remark; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/entity/QuartzTaskEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/entity/QuartzTaskEntity.java new file mode 100644 index 00000000..a25b58dd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/entity/QuartzTaskEntity.java @@ -0,0 +1,49 @@ +package com.gangquan360.smartadmin.module.quartz.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 13:45 + * @since JDK1.8 + */ +@Data +@TableName("t_quartz_task") +public class QuartzTaskEntity extends BaseEntity{ + /** + * 任务名称参数 + */ + private String taskName; + /** + * 任务类 + */ + private String taskBean; + + /** + * 任务参数 + */ + private String taskParams; + + /** + * cron + */ + private String taskCron; + + /** + * 任务状态 + */ + private Integer taskStatus; + + /** + * 备注 + */ + private String remark; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/entity/QuartzTaskLogEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/entity/QuartzTaskLogEntity.java new file mode 100644 index 00000000..cd3c6dc0 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/domain/entity/QuartzTaskLogEntity.java @@ -0,0 +1,50 @@ +package com.gangquan360.smartadmin.module.quartz.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 13:45 + * @since JDK1.8 + */ +@Data +@TableName("t_quartz_task_log") +public class QuartzTaskLogEntity extends BaseEntity{ + /** + * 任务名称参数 + */ + private Long taskId; + /** + * 任务名称 + */ + private String taskName; + /** + * 任务参数 + */ + private String taskParams; + /** + * 任务处理状态 + */ + private Integer processStatus; + + /** + * 任务时长ms + */ + private Long processDuration; + + /** + * 处理日志 + */ + private String processLog; + + + private String ipAddress; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTask.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTask.java new file mode 100644 index 00000000..010ab318 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTask.java @@ -0,0 +1,78 @@ +package com.gangquan360.smartadmin.module.quartz.service; + +import com.gangquan360.smartadmin.module.quartz.constant.QuartzConst; +import com.gangquan360.smartadmin.module.quartz.constant.TaskResultEnum; +import com.gangquan360.smartadmin.module.quartz.domain.entity.QuartzTaskEntity; +import com.gangquan360.smartadmin.module.quartz.domain.entity.QuartzTaskLogEntity; +import com.gangquan360.smartadmin.module.quartz.task.ITask; +import com.gangquan360.smartadmin.third.SmartApplicationContext; +import com.gangquan360.smartadmin.util.SmartIPUtil; +import com.gangquan360.smartadmin.util.SmartQuartzUtil; +import org.quartz.JobDetail; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.quartz.JobKey; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +public class QuartzTask extends QuartzJobBean { + + @Override + protected void executeInternal(JobExecutionContext context) throws JobExecutionException { + JobDetail jobDetail = context.getJobDetail(); + Object params = jobDetail.getJobDataMap().get(QuartzConst.QUARTZ_PARAMS_KEY); + JobKey jobKey = jobDetail.getKey(); + + Long taskId = SmartQuartzUtil.getTaskIdByJobKey(jobKey); + QuartzTaskService quartzTaskService = (QuartzTaskService) SmartApplicationContext.getBean("quartzTaskService"); + QuartzTaskEntity quartzTaskEntity = quartzTaskService.getByTaskId(taskId); + + QuartzTaskLogService quartzTaskLogService = (QuartzTaskLogService) SmartApplicationContext.getBean("quartzTaskLogService"); + + QuartzTaskLogEntity taskLogEntity = new QuartzTaskLogEntity(); + taskLogEntity.setTaskId(taskId); + taskLogEntity.setIpAddress(SmartIPUtil.getLocalHostIP()); + taskLogEntity.setTaskName(quartzTaskEntity.getTaskName()); + String paramsStr = null; + if (params != null) { + paramsStr = params.toString(); + taskLogEntity.setTaskParams(paramsStr); + } + taskLogEntity.setUpdateTime(new Date()); + taskLogEntity.setCreateTime(new Date()); + //任务开始时间 + long startTime = System.currentTimeMillis(); + try { + ITask taskClass = (ITask) SmartApplicationContext.getBean(quartzTaskEntity.getTaskBean()); + taskClass.execute(paramsStr); + taskLogEntity.setProcessStatus(TaskResultEnum.SUCCESS.getStatus()); + } catch (Exception e) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw, true); + e.printStackTrace(pw); + pw.flush(); + sw.flush(); + taskLogEntity.setProcessStatus(TaskResultEnum.FAIL.getStatus()); + taskLogEntity.setProcessLog(sw.toString()); + } finally { + long times = System.currentTimeMillis() - startTime; + taskLogEntity.setProcessDuration(times); + quartzTaskLogService.save(taskLogEntity); + } + + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTaskLogService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTaskLogService.java new file mode 100644 index 00000000..8a396991 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTaskLogService.java @@ -0,0 +1,28 @@ +package com.gangquan360.smartadmin.module.quartz.service; + +import com.gangquan360.smartadmin.module.quartz.dao.QuartzTaskLogDao; +import com.gangquan360.smartadmin.module.quartz.domain.entity.QuartzTaskLogEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 14:50 + * @since JDK1.8 + */ +@Service +public class QuartzTaskLogService { + + @Autowired + private QuartzTaskLogDao quartzTaskLogDao; + + + public void save(QuartzTaskLogEntity logEntity){ + quartzTaskLogDao.insert(logEntity); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTaskService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTaskService.java new file mode 100644 index 00000000..75c2f914 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/service/QuartzTaskService.java @@ -0,0 +1,316 @@ +package com.gangquan360.smartadmin.module.quartz.service; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.quartz.constant.QuartzConst; +import com.gangquan360.smartadmin.module.quartz.constant.TaskStatusEnum; +import com.gangquan360.smartadmin.module.quartz.dao.QuartzTaskDao; +import com.gangquan360.smartadmin.module.quartz.dao.QuartzTaskLogDao; +import com.gangquan360.smartadmin.module.quartz.domain.dto.*; +import com.gangquan360.smartadmin.module.quartz.domain.entity.QuartzTaskEntity; +import com.gangquan360.smartadmin.third.SmartApplicationContext; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import com.gangquan360.smartadmin.util.SmartQuartzUtil; +import lombok.extern.slf4j.Slf4j; +import org.quartz.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 14:50 + * @since JDK1.8 + */ +@Slf4j +@Service +public class QuartzTaskService { + + @Autowired + private QuartzTaskDao quartzTaskDao; + + @Autowired + private QuartzTaskLogDao quartzTaskLogDao; + + @Autowired + private Scheduler scheduler; + + /** + * 查询列表 + * + * @param queryDTO + * @return + */ + public ResponseDTO> query(QuartzQueryDTO queryDTO) { + Page pageParam = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List taskList = quartzTaskDao.queryList(pageParam, queryDTO); + pageParam.setRecords(taskList); + return ResponseDTO.succData(SmartPaginationUtil.convert2PageInfoDTO(pageParam)); + } + + /** + * 查询运行日志 + * + * @param queryDTO + * @return + */ + public ResponseDTO> queryLog(QuartzLogQueryDTO queryDTO) { + Page pageParam = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List taskList = quartzTaskLogDao.queryList(pageParam, queryDTO); + pageParam.setRecords(taskList); + return ResponseDTO.succData(SmartPaginationUtil.convert2PageInfoDTO(pageParam)); + } + + /** + * 保存或更新 + * + * @param quartzTaskDTO + * @return + * @throws Exception + */ + @Transactional(rollbackFor = Throwable.class) + public ResponseDTO saveOrUpdateTask(QuartzTaskDTO quartzTaskDTO) throws Exception { + ResponseDTO baseValid = this.baseValid(quartzTaskDTO); + if (! baseValid.isSuccess()) { + return baseValid; + } + Long taskId = quartzTaskDTO.getId(); + if (taskId == null) { + return this.saveTask(quartzTaskDTO); + } else { + return this.updateTask(quartzTaskDTO); + } + } + + private ResponseDTO baseValid(QuartzTaskDTO quartzTaskDTO) { + Object taskBean = null; + try { + taskBean = SmartApplicationContext.getBean(quartzTaskDTO.getTaskBean()); + } catch (Exception e) { + log.error("taskBean 不存在{}", e); + } + if (taskBean == null) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "taskBean 不存在"); + } + if (! CronExpression.isValidExpression(quartzTaskDTO.getTaskCron())) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "请传入正确的正则表达式"); + } + return ResponseDTO.succ(); + } + + private ResponseDTO saveTask(QuartzTaskDTO quartzTaskDTO) throws Exception { + QuartzTaskEntity taskEntity = SmartBeanUtil.copy(quartzTaskDTO, QuartzTaskEntity.class); + taskEntity.setTaskStatus(TaskStatusEnum.NORMAL.getStatus()); + taskEntity.setUpdateTime(new Date()); + taskEntity.setCreateTime(new Date()); + quartzTaskDao.insert(taskEntity); + this.createQuartzTask(scheduler, taskEntity); + return ResponseDTO.succ(); + } + + private ResponseDTO updateTask(QuartzTaskDTO quartzTaskDTO) throws Exception { + QuartzTaskEntity updateEntity = quartzTaskDao.selectById(quartzTaskDTO.getId()); + if (updateEntity == null) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "task不存在"); + } + QuartzTaskEntity taskEntity = SmartBeanUtil.copy(quartzTaskDTO, QuartzTaskEntity.class); + //任务状态不能更新 + taskEntity.setTaskStatus(updateEntity.getTaskStatus()); + taskEntity.setUpdateTime(new Date()); + quartzTaskDao.updateById(taskEntity); + this.updateQuartzTask(scheduler, taskEntity); + return ResponseDTO.succ(); + } + + /** + * 立即运行 + * + * @param taskId + * @return + * @throws Exception + */ + public ResponseDTO runTask(Long taskId) throws Exception { + QuartzTaskEntity quartzTaskEntity = quartzTaskDao.selectById(taskId); + if (quartzTaskEntity == null) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "task不存在"); + } + this.runQuartzTask(scheduler, quartzTaskEntity); + return ResponseDTO.succ(); + } + + /** + * 暂停运行 + * + * @param taskId + * @return + * @throws Exception + */ + @Transactional(rollbackFor = Throwable.class) + public ResponseDTO pauseTask(Long taskId) throws Exception { + QuartzTaskEntity quartzTaskEntity = quartzTaskDao.selectById(taskId); + if (quartzTaskEntity == null) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "task不存在"); + } + quartzTaskEntity.setTaskStatus(TaskStatusEnum.PAUSE.getStatus()); + quartzTaskDao.updateById(quartzTaskEntity); + this.pauseQuartzTask(scheduler, taskId); + return ResponseDTO.succ(); + } + + /** + * 恢复任务 + * + * @param taskId + * @return + * @throws Exception + */ + @Transactional(rollbackFor = Throwable.class) + public ResponseDTO resumeTask(Long taskId) throws Exception { + QuartzTaskEntity quartzTaskEntity = quartzTaskDao.selectById(taskId); + if (quartzTaskEntity == null) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "task不存在"); + } + quartzTaskEntity.setTaskStatus(TaskStatusEnum.NORMAL.getStatus()); + quartzTaskDao.updateById(quartzTaskEntity); + this.resumeQuartzTask(scheduler, taskId); + return ResponseDTO.succ(); + } + + /** + * 删除任务 + * + * @param taskId + * @return + * @throws Exception + */ + public ResponseDTO deleteTask(Long taskId) throws Exception { + QuartzTaskEntity quartzTaskEntity = quartzTaskDao.selectById(taskId); + if (quartzTaskEntity == null) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM, "task不存在"); + } + quartzTaskDao.deleteById(taskId); + this.deleteQuartzTask(scheduler, taskId); + return ResponseDTO.succ(); + } + + /** + * 通过任务Id 获取任务实体 + * + * @param taskId + * @return + */ + public QuartzTaskEntity getByTaskId(Long taskId) { + return quartzTaskDao.selectById(taskId); + } + + /** + * 创建任务 + * + * @param scheduler + * @param taskEntity + * @throws Exception + */ + public void createQuartzTask(Scheduler scheduler, QuartzTaskEntity taskEntity) throws Exception { + JobKey jobKey = SmartQuartzUtil.getJobKey(taskEntity.getId()); + JobDetail jobDetail = JobBuilder.newJob(QuartzTask.class).withIdentity(jobKey).build(); + + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(taskEntity.getTaskCron()).withMisfireHandlingInstructionDoNothing(); + + TriggerKey triggerKey = SmartQuartzUtil.getTriggerKey(Long.valueOf(taskEntity.getId())); + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); + + jobDetail.getJobDataMap().put(QuartzConst.QUARTZ_PARAMS_KEY, taskEntity.getTaskParams()); + scheduler.scheduleJob(jobDetail, trigger); + } + + /** + * 更新任务 + * + * @param scheduler + * @param taskEntity + * @throws Exception + */ + private void updateQuartzTask(Scheduler scheduler, QuartzTaskEntity taskEntity) throws Exception { + TriggerKey triggerKey = SmartQuartzUtil.getTriggerKey(Long.valueOf(taskEntity.getId())); + + CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(taskEntity.getTaskCron()).withMisfireHandlingInstructionDoNothing(); + + CronTrigger trigger = this.getCronTrigger(scheduler, Long.valueOf(taskEntity.getId())); + + trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); + + trigger.getJobDataMap().put(QuartzConst.QUARTZ_PARAMS_KEY, taskEntity.getTaskParams()); + + scheduler.rescheduleJob(triggerKey, trigger); + //如果更新之前任务是暂停状态,此时再次暂停任务 + if (TaskStatusEnum.PAUSE.getStatus().equals(taskEntity.getTaskStatus())) { + this.pauseQuartzTask(scheduler, Long.valueOf(taskEntity.getId())); + } + } + + private CronTrigger getCronTrigger(Scheduler scheduler, Long taskId) throws Exception { + TriggerKey triggerKey = SmartQuartzUtil.getTriggerKey(taskId); + return (CronTrigger) scheduler.getTrigger(triggerKey); + } + + /** + * 立即运行 + * + * @param scheduler + * @param taskEntity + * @throws Exception + */ + private void runQuartzTask(Scheduler scheduler, QuartzTaskEntity taskEntity) throws Exception { + JobDataMap dataMap = new JobDataMap(); + dataMap.put(QuartzConst.QUARTZ_PARAMS_KEY, taskEntity.getTaskParams()); + JobKey jobKey = SmartQuartzUtil.getJobKey(taskEntity.getId()); + scheduler.triggerJob(jobKey, dataMap); + } + + /** + * 暂停任务 + * + * @param scheduler + * @param taskId + * @throws Exception + */ + private void pauseQuartzTask(Scheduler scheduler, Long taskId) throws Exception { + JobKey jobKey = SmartQuartzUtil.getJobKey(taskId); + scheduler.pauseJob(jobKey); + } + + /** + * 恢复任务 + * + * @param scheduler + * @param taskId + * @throws Exception + */ + private void resumeQuartzTask(Scheduler scheduler, Long taskId) throws Exception { + JobKey jobKey = SmartQuartzUtil.getJobKey(taskId); + scheduler.resumeJob(jobKey); + } + + /** + * 删除任务 + * + * @param scheduler + * @param taskId + * @throws Exception + */ + private void deleteQuartzTask(Scheduler scheduler, Long taskId) throws Exception { + JobKey jobKey = SmartQuartzUtil.getJobKey(taskId); + scheduler.deleteJob(jobKey); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/task/ITask.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/task/ITask.java new file mode 100644 index 00000000..cfdd3067 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/task/ITask.java @@ -0,0 +1,16 @@ +package com.gangquan360.smartadmin.module.quartz.task; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 14:23 + * @since JDK1.8 + */ +public interface ITask { + + void execute(String paramJson) throws Exception; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/task/test/Example.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/task/test/Example.java new file mode 100644 index 00000000..a4c4b43f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/quartz/task/test/Example.java @@ -0,0 +1,26 @@ +package com.gangquan360.smartadmin.module.quartz.task.test; + +import com.gangquan360.smartadmin.module.quartz.task.ITask; +import com.gangquan360.smartadmin.util.SmartDateUtil; +import org.springframework.stereotype.Component; + +import java.util.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 14:26 + * @since JDK1.8 + */ +@Component("exampleTask") +public class Example implements ITask { + + @Override + public void execute(String paramJson) throws Exception { + System.out.println(SmartDateUtil.formatYMDHMS(new Date()) + ",今天搬了" + System.currentTimeMillis() + "块砖,paramJson:" + paramJson); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleController.java new file mode 100644 index 00000000..88ff9ab5 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleController.java @@ -0,0 +1,60 @@ +package com.gangquan360.smartadmin.module.role.basic; +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleAddDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleUpdateDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * 角色管理路由 + * + * @author listen + * @date 2017/12/28 10:10 + */ +@Api(tags = {SwaggerTagConst.Admin.MANAGER_ROLE}) +@OperateLog +@RestController +public class RoleController { + + @Autowired + private RoleService roleService; + + @ApiOperation(value = "添加角色", notes = "添加角色") + @PostMapping("/role/add") + public ResponseDTO addRole(@Valid @RequestBody RoleAddDTO roleAddDTO) { + return roleService.addRole(roleAddDTO); + } + + @ApiOperation(value = "删除角色", notes = "根据id删除角色") + @GetMapping("/role/delete/{roleId}") + public ResponseDTO deleteRole(@PathVariable("roleId") Long roleId) { + return roleService.deleteRole(roleId); + } + + @ApiOperation(value = "更新角色", notes = "更新角色") + @PostMapping("/role/update") + public ResponseDTO updateRole(@Valid @RequestBody RoleUpdateDTO roleUpdateDTO) { + return roleService.updateRole(roleUpdateDTO); + } + + @ApiOperation(value = "获取角色数据", notes = "根据id获取角色数据") + @GetMapping("/role/get/{roleId}") + public ResponseDTO getRole(@PathVariable("roleId") Long roleId) { + return roleService.getRoleById(roleId); + } + + @ApiOperation(value = "获取所有角色", notes = "获取所有角色数据") + @GetMapping("/role/getAll") + public ResponseDTO> getAllRole() { + return roleService.getAllRole(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleDao.java new file mode 100644 index 00000000..22c6c1e2 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleDao.java @@ -0,0 +1,26 @@ +package com.gangquan360.smartadmin.module.role.basic; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.gangquan360.smartadmin.module.role.basic.domain.entity.RoleEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 13:00 + * @since JDK1.8 + */ +@Mapper +@Component +public interface RoleDao extends BaseMapper { + + + RoleEntity getByRoleName(@Param("roleName") String name); + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleResponseCodeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleResponseCodeConst.java new file mode 100644 index 00000000..62bb0573 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleResponseCodeConst.java @@ -0,0 +1,24 @@ +package com.gangquan360.smartadmin.module.role.basic; +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + +/** + * + * @author yandanyang + * 角色业务状态码 6001 - 6999 + */ +public class RoleResponseCodeConst extends ResponseCodeConst { + + /** + * 10501 角色名称已存在 + */ + public static final RoleResponseCodeConst ROLE_NAME_EXISTS = new RoleResponseCodeConst(6001, "角色名称已存在"); + + /** + * 10502 角色不存在 + */ + public static final RoleResponseCodeConst ROLE_NOT_EXISTS = new RoleResponseCodeConst(6002, "角色不存在"); + + public RoleResponseCodeConst(int code, String msg) { + super(code, msg); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleService.java new file mode 100644 index 00000000..9f90c3ae --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/RoleService.java @@ -0,0 +1,115 @@ +package com.gangquan360.smartadmin.module.role.basic; + +import com.baomidou.mybatisplus.mapper.EntityWrapper; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleAddDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleUpdateDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleVO; +import com.gangquan360.smartadmin.module.role.basic.domain.entity.RoleEntity; +import com.gangquan360.smartadmin.module.role.roleemployee.RoleEmployeeDao; +import com.gangquan360.smartadmin.module.role.roleprivilege.RolePrivilegeDao; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 角色管理业务 + * + * @author listen + * @date 2017/12/28 09:37 + */ +@Service +public class RoleService { + + @Autowired + private RoleDao roleDao; + + @Autowired + private RolePrivilegeDao rolePrivilegeDao; + + @Autowired + private RoleEmployeeDao roleEmployeeDao; + + /** + * 新增添加角色 + * + * @param roleAddDTO + * @return ResponseDTO + */ + public ResponseDTO addRole(RoleAddDTO roleAddDTO) { + RoleEntity employeeRoleEntity = roleDao.getByRoleName(roleAddDTO.getRoleName()); + if (null != employeeRoleEntity) { + return ResponseDTO.wrap(RoleResponseCodeConst.ROLE_NAME_EXISTS); + } + RoleEntity roleEntity = SmartBeanUtil.copy(roleAddDTO, RoleEntity.class); + roleDao.insert(roleEntity); + return ResponseDTO.succ(); + } + + /** + * 根据角色id 删除 + * + * @param roleId + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO deleteRole(Long roleId) { + RoleEntity roleEntity = roleDao.selectById(roleId); + if (null == roleEntity) { + return ResponseDTO.wrap(RoleResponseCodeConst.ROLE_NOT_EXISTS); + } + roleDao.deleteById(roleId); + rolePrivilegeDao.deleteByRoleId(roleId); + roleEmployeeDao.deleteByRoleId(roleId); + return ResponseDTO.succ(); + } + + /** + * 更新角色 + * + * @param roleUpdateDTO + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO updateRole(RoleUpdateDTO roleUpdateDTO) { + if (null == roleDao.selectById(roleUpdateDTO.getId())) { + return ResponseDTO.wrap(RoleResponseCodeConst.ROLE_NOT_EXISTS); + } + RoleEntity employeeRoleEntity = roleDao.getByRoleName(roleUpdateDTO.getRoleName()); + if (null != employeeRoleEntity && ! employeeRoleEntity.getId().equals(roleUpdateDTO.getId())) { + return ResponseDTO.wrap(RoleResponseCodeConst.ROLE_NAME_EXISTS); + } + RoleEntity roleEntity = SmartBeanUtil.copy(roleUpdateDTO, RoleEntity.class); + roleDao.updateById(roleEntity); + return ResponseDTO.succ(); + } + + /** + * 根据id获取角色数据 + * + * @param roleId + * @return ResponseDTO + */ + public ResponseDTO getRoleById(Long roleId) { + RoleEntity roleEntity = roleDao.selectById(roleId); + if (null == roleEntity) { + return ResponseDTO.wrap(RoleResponseCodeConst.ROLE_NOT_EXISTS); + } + RoleVO role = SmartBeanUtil.copy(roleEntity, RoleVO.class); + return ResponseDTO.succData(role); + } + + /** + * 获取所有角色列表 + * + * @return ResponseDTO + */ + public ResponseDTO> getAllRole() { + List roleEntityList = roleDao.selectList(new EntityWrapper()); + List roleList = SmartBeanUtil.copyList(roleEntityList, RoleVO.class); + return ResponseDTO.succData(roleList); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleAddDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleAddDTO.java new file mode 100644 index 00000000..f0f5af9a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleAddDTO.java @@ -0,0 +1,33 @@ +package com.gangquan360.smartadmin.module.role.basic.domain.dto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotNull; + +/** + * 角色添加DTO + * + * @author listen + * @date 2017/12/28 09:40 + */ +@Data +public class RoleAddDTO { + + /** + * 角色名称 + */ + @ApiModelProperty("角色名称") + @NotNull(message = "角色名称不能为空") + @Length(min = 1, max = 20, message = "角色名称(1-20)个字符") + private String roleName; + + /** + * 角色描述 + */ + @ApiModelProperty("角色描述") + @Length(max = 255, message = "角色描述最多255个字符") + private String remark; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleBatchDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleBatchDTO.java new file mode 100644 index 00000000..487675ca --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleBatchDTO.java @@ -0,0 +1,30 @@ +package com.gangquan360.smartadmin.module.role.basic.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.util.List; + +/** + * 批量添加角色员工DTO + * + * @author listen + * @date 2017/12/29 15:38 + */ +@Data +public class RoleBatchDTO { + + @ApiModelProperty("角色id") + @NotNull(message = "角色id不能为空") + protected Long roleId; + + /** + * 员工id集合 + */ + @ApiModelProperty(value = "员工id集合") + @NotEmpty(message = "员工id不能为空") + protected List employeeIds; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleQueryDTO.java new file mode 100644 index 00000000..b46eda46 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleQueryDTO.java @@ -0,0 +1,25 @@ +package com.gangquan360.smartadmin.module.role.basic.domain.dto; +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +public class RoleQueryDTO extends PageParamDTO { + + @ApiModelProperty("角色名称") + private String roleName; + + @ApiModelProperty("角色id") + private String roleId; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleSelectedVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleSelectedVO.java new file mode 100644 index 00000000..b16854f6 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleSelectedVO.java @@ -0,0 +1,21 @@ +package com.gangquan360.smartadmin.module.role.basic.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 15:27 + * @since JDK1.8 + */ +@Data +public class RoleSelectedVO extends RoleVO { + + @ApiModelProperty("角色名称") + private Boolean selected; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleUpdateDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleUpdateDTO.java new file mode 100644 index 00000000..27f6a773 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleUpdateDTO.java @@ -0,0 +1,24 @@ +package com.gangquan360.smartadmin.module.role.basic.domain.dto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 角色更新修改DTO + * + * @author listen + * @date 2017/12/28 09:40 + */ +@Data +public class RoleUpdateDTO extends RoleAddDTO { + + /** + * 角色id + */ + @ApiModelProperty("角色id") + @NotNull(message = "角色id不能为空") + protected Long id; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleVO.java new file mode 100644 index 00000000..f8bdbbdd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/dto/RoleVO.java @@ -0,0 +1,27 @@ +package com.gangquan360.smartadmin.module.role.basic.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 15:27 + * @since JDK1.8 + */ +@Data +public class RoleVO { + + @ApiModelProperty("角色ID") + private Long id; + + @ApiModelProperty("角色名称") + private String roleName; + + @ApiModelProperty("角色备注") + private String remark; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/entity/RoleEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/entity/RoleEntity.java new file mode 100644 index 00000000..ab28dca9 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/basic/domain/entity/RoleEntity.java @@ -0,0 +1,25 @@ +package com.gangquan360.smartadmin.module.role.basic.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * [ 角色 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 13:01 + * @since JDK1.8 + */ +@Data +@TableName("t_role") +public class RoleEntity extends BaseEntity { + + + private String roleName; + + private String remark; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeController.java new file mode 100644 index 00000000..12045d46 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeController.java @@ -0,0 +1,73 @@ +package com.gangquan360.smartadmin.module.role.roleemployee; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.employee.domain.vo.EmployeeVO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleBatchDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleQueryDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleSelectedVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * 用户角色管理路由 + * + * @author listen + * @date 2017/12/28 10:10 + */ +@Api(tags = {SwaggerTagConst.Admin.MANAGER_ROLE_USER}) +@OperateLog +@RestController +public class RoleEmployeeController { + + @Autowired + private RoleEmployeeService roleEmployeeService; + + @ApiOperation(value = "获取角色成员-员工列表", notes = "获取角色成员-员工列表(分页)") + @PostMapping("/role/listEmployee") + public ResponseDTO> listEmployeeByName(@Valid @RequestBody RoleQueryDTO queryDTO) { + return roleEmployeeService.listEmployeeByName(queryDTO); + } + + @ApiOperation(value = "根据角色id获取角色员工列表(无分页)", notes = "根据角色id获取角色成员-员工列表") + @GetMapping("/role/listAllEmployee/{roleId}") + public ResponseDTO> listAllEmployeeRoleId(@PathVariable Long roleId) { + return roleEmployeeService.getAllEmployeeByRoleId(roleId); + } + + @ApiOperation(value = "从角色成员列表中移除员工", notes = "从角色成员列表中移除员工") + @ApiImplicitParams({@ApiImplicitParam(name = "employeeId", value = "员工id", paramType = "query", required = true), @ApiImplicitParam(name = "roleId", value = "角色id", paramType = "query", + required = true)}) + @GetMapping("/role/removeEmployee") + public ResponseDTO removeEmployee(Long employeeId, Long roleId) { + return roleEmployeeService.removeEmployeeRole(employeeId, roleId); + } + + @ApiOperation(value = "从角色成员列表中批量移除员工", notes = "从角色成员列表中批量移除员工") + @PostMapping("/role/removeEmployeeList") + public ResponseDTO removeEmployeeList(@Valid @RequestBody RoleBatchDTO removeDTO) { + return roleEmployeeService.batchRemoveEmployeeRole(removeDTO); + } + + @ApiOperation(value = "角色成员列表中批量添加员工", notes = "角色成员列表中批量添加员工") + @PostMapping("/role/addEmployeeList") + public ResponseDTO addEmployeeList(@Valid @RequestBody RoleBatchDTO addDTO) { + return roleEmployeeService.batchAddEmployeeRole(addDTO); + } + + @ApiOperation(value = "通过员工id获取所有角色以及员工具有的角色", notes = "通过员工id获取所有角色以及员工具有的角色") + @GetMapping("/role/getRoles/{employeeId}") + @ApiImplicitParams({@ApiImplicitParam(name = "employeeId", value = "员工id", paramType = "path", required = true)}) + public ResponseDTO> getRoleByEmployeeId(@PathVariable Long employeeId) { + return roleEmployeeService.getRolesByEmployeeId(employeeId); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeDao.java new file mode 100644 index 00000000..5f09bd37 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeDao.java @@ -0,0 +1,80 @@ +package com.gangquan360.smartadmin.module.role.roleemployee; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleQueryDTO; +import com.gangquan360.smartadmin.module.role.roleemployee.domain.RoleEmployeeEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 13:00 + * @since JDK1.8 + */ +@Mapper +@Component +public interface RoleEmployeeDao extends BaseMapper { + + /** + * 根据员工id 查询所有的角色 + * @param employeeId + * @return + */ + List selectRoleIdByEmployeeId(@Param("employeeId") Long employeeId); + + /** + * + * @param page + * @param queryDTO + * @return + */ + List selectEmployeeByNamePage(Page page,@Param("queryDTO") RoleQueryDTO queryDTO); + + /** + * + * @param roleId + * @return + */ + List selectEmployeeByRoleId(@Param("roleId") Long roleId); + /** + * 根据员工信息删除 + * @param employeeId + */ + void deleteByEmployeeId(@Param("employeeId") Long employeeId); + + /** + * 删除某个角色的所有关系 + * @param roleId + */ + void deleteByRoleId(@Param("roleId")Long roleId); + + /** + * 根据员工和 角色删除关系 + * @param employeeId + * @param roleId + */ + void deleteByEmployeeIdRoleId(@Param("employeeId") Long employeeId,@Param("roleId")Long roleId); + + /** + * 批量删除某个角色下的某批用户的关联关系 + * @param roleId + * @param employeeIds + */ + void batchDeleteEmployeeRole(@Param("roleId") Long roleId,@Param("employeeIds")List employeeIds); + + /** + * 批量新增 + * @param roleRelationList + */ + void batchInsert(List roleRelationList); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeService.java new file mode 100644 index 00000000..e49ad43a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/RoleEmployeeService.java @@ -0,0 +1,133 @@ +package com.gangquan360.smartadmin.module.role.roleemployee; + +import com.baomidou.mybatisplus.mapper.EntityWrapper; +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.department.DepartmentDao; +import com.gangquan360.smartadmin.module.department.domain.entity.DepartmentEntity; +import com.gangquan360.smartadmin.module.employee.domain.dto.EmployeeDTO; +import com.gangquan360.smartadmin.module.employee.domain.vo.EmployeeVO; +import com.gangquan360.smartadmin.module.role.basic.RoleDao; +import com.gangquan360.smartadmin.module.role.basic.RoleResponseCodeConst; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleBatchDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleQueryDTO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleSelectedVO; +import com.gangquan360.smartadmin.module.role.basic.domain.dto.RoleVO; +import com.gangquan360.smartadmin.module.role.roleemployee.domain.RoleEmployeeEntity; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import com.google.common.collect.Lists; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * 角色管理业务 + * + * @author zzr + * @date 2019/4/3 + */ +@Service +public class RoleEmployeeService { + + @Autowired + private RoleEmployeeDao roleEmployeeDao; + + @Autowired + private RoleDao roleDao; + + @Autowired + private DepartmentDao departmentDao; + + /** + * 通过角色id,分页获取成员员工列表 + * + * @param queryDTO + * @return + */ + public ResponseDTO> listEmployeeByName(RoleQueryDTO queryDTO) { + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List employeeDTOS = roleEmployeeDao.selectEmployeeByNamePage(page, queryDTO); + employeeDTOS.stream().filter(e -> e.getDepartmentId() != null).forEach(employeeDTO -> { + DepartmentEntity departmentEntity = departmentDao.selectById(employeeDTO.getDepartmentId()); + employeeDTO.setDepartmentName(departmentEntity.getName()); + }); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page, employeeDTOS, EmployeeVO.class); + return ResponseDTO.succData(pageResultDTO); + } + + public ResponseDTO> getAllEmployeeByRoleId(Long roleId) { + List employeeDTOS = roleEmployeeDao.selectEmployeeByRoleId(roleId); + List list = SmartBeanUtil.copyList(employeeDTOS, EmployeeVO.class); + return ResponseDTO.succData(list); + } + + /** + * 移除员工角色 + * + * @param employeeId + * @param roleId + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO removeEmployeeRole(Long employeeId, Long roleId) { + if (null == employeeId || null == roleId) { + return ResponseDTO.wrap(RoleResponseCodeConst.ERROR_PARAM); + } + roleEmployeeDao.deleteByEmployeeIdRoleId(employeeId, roleId); + return ResponseDTO.succ(); + } + + /** + * 批量删除角色的成员员工 + * + * @param removeDTO + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO batchRemoveEmployeeRole(RoleBatchDTO removeDTO) { + List employeeIdList = removeDTO.getEmployeeIds(); + roleEmployeeDao.batchDeleteEmployeeRole(removeDTO.getRoleId(), employeeIdList); + return ResponseDTO.succ(); + } + + /** + * 批量添加角色的成员员工 + * + * @param addDTO + * @return ResponseDTO + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO batchAddEmployeeRole(RoleBatchDTO addDTO) { + Long roleId = addDTO.getRoleId(); + List employeeIdList = addDTO.getEmployeeIds(); + roleEmployeeDao.deleteByRoleId(roleId); + List roleRelationEntities = Lists.newArrayList(); + RoleEmployeeEntity employeeRoleRelationEntity; + for (Long employeeId : employeeIdList) { + employeeRoleRelationEntity = new RoleEmployeeEntity(); + employeeRoleRelationEntity.setRoleId(roleId); + employeeRoleRelationEntity.setEmployeeId(employeeId); + roleRelationEntities.add(employeeRoleRelationEntity); + } + roleEmployeeDao.batchInsert(roleRelationEntities); + return ResponseDTO.succ(); + } + + /** + * 通过员工id获取员工角色 + * + * @param employeeId + * @return + */ + public ResponseDTO> getRolesByEmployeeId(Long employeeId) { + List roleIds = roleEmployeeDao.selectRoleIdByEmployeeId(employeeId); + List roleList = roleDao.selectList(new EntityWrapper()); + List result = SmartBeanUtil.copyList(roleList, RoleSelectedVO.class); + result.stream().forEach(item -> item.setSelected(roleIds.contains(item.getId()))); + return ResponseDTO.succData(result); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/domain/RoleEmployeeDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/domain/RoleEmployeeDTO.java new file mode 100644 index 00000000..1578bdbc --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/domain/RoleEmployeeDTO.java @@ -0,0 +1,21 @@ +package com.gangquan360.smartadmin.module.role.roleemployee.domain; + +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 15:27 + * @since JDK1.8 + */ +@Data +public class RoleEmployeeDTO { + + private Long roleId; + + private Long employeeId; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/domain/RoleEmployeeEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/domain/RoleEmployeeEntity.java new file mode 100644 index 00000000..75337357 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleemployee/domain/RoleEmployeeEntity.java @@ -0,0 +1,24 @@ +package com.gangquan360.smartadmin.module.role.roleemployee.domain; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * [ 角色 员工关系] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/27 0027 下午 13:01 + * @since JDK1.8 + */ +@Data +@TableName("t_role_employee") +public class RoleEmployeeEntity extends BaseEntity{ + + private Long roleId; + + private Long employeeId; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeController.java new file mode 100644 index 00000000..63fa38fa --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeController.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.module.role.roleprivilege; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.role.roleprivilege.domain.dto.RolePrivilegeDTO; +import com.gangquan360.smartadmin.module.role.roleprivilege.domain.dto.RolePrivilegeTreeVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * [ 与员工权限相关:角色权限关系、权限列表 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@OperateLog +@RestController +@Api(tags = {SwaggerTagConst.Admin.MANAGER_ROLE_PRIVILEGE}) +public class RolePrivilegeController { + + @Autowired + private RolePrivilegeService rolePrivilegeService; + + @ApiOperation(value = "更新角色权限", notes = "更新角色权限") + @PostMapping("/privilege/updateRolePrivilege") + public ResponseDTO updateRolePrivilege(@Valid @RequestBody RolePrivilegeDTO updateDTO) { + return rolePrivilegeService.updateRolePrivilege(updateDTO); + } + + @ApiOperation(value = "获取角色可选的功能权限", notes = "获取角色可选的功能权限") + @GetMapping("/privilege/listPrivilegeByRoleId/{roleId}") + public ResponseDTO listPrivilegeByRoleId(@PathVariable("roleId") Long roleId) { + return rolePrivilegeService.listPrivilegeByRoleId(roleId); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeDao.java new file mode 100644 index 00000000..2c2bff6b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeDao.java @@ -0,0 +1,58 @@ +package com.gangquan360.smartadmin.module.role.roleprivilege; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.gangquan360.smartadmin.module.privilege.domain.entity.PrivilegeEntity; +import com.gangquan360.smartadmin.module.role.roleprivilege.domain.entity.RolePrivilegeEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/28 0028 下午 12:23 + * @since JDK1.8 + */ +@Mapper +@Component +public interface RolePrivilegeDao extends BaseMapper { + + /** + * 根据角色id删除 + * @param roleId + */ + void deleteByRoleId(@Param("roleId")Long roleId); + + /** + * 删除权限所关联的角色信息 + * @param privilegeKeyList + */ + void deleteByPrivilegeKey(@Param("privilegeKeyList")List privilegeKeyList); + + + /** + * 批量添加 + * @param rolePrivilegeList + */ + void batchInsert(List rolePrivilegeList); + + /** + * 查询某批角色的权限 + * @param roleIds + * @return + */ + List listByRoleIds(@Param("roleIds")List roleIds,@Param("normalStatus")Integer normalStatus); + + /** + * 查询某个角色的权限 + * @param roleId + * @return + */ + List listByRoleId(@Param("roleId")Long roleId); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeService.java new file mode 100644 index 00000000..28017fcf --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/RolePrivilegeService.java @@ -0,0 +1,129 @@ +package com.gangquan360.smartadmin.module.role.roleprivilege; + +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.module.privilege.dao.PrivilegeDao; +import com.gangquan360.smartadmin.module.privilege.domain.entity.PrivilegeEntity; +import com.gangquan360.smartadmin.module.privilege.service.PrivilegeEmployeeService; +import com.gangquan360.smartadmin.module.role.basic.RoleDao; +import com.gangquan360.smartadmin.module.role.basic.RoleResponseCodeConst; +import com.gangquan360.smartadmin.module.role.basic.domain.entity.RoleEntity; +import com.gangquan360.smartadmin.module.role.roleprivilege.domain.dto.RolePrivilegeDTO; +import com.gangquan360.smartadmin.module.role.roleprivilege.domain.dto.RolePrivilegeSimpleDTO; +import com.gangquan360.smartadmin.module.role.roleprivilege.domain.dto.RolePrivilegeTreeVO; +import com.gangquan360.smartadmin.module.role.roleprivilege.domain.entity.RolePrivilegeEntity; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.google.common.collect.Lists; +import org.apache.commons.collections.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * [ 后台员工权限 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Service +public class RolePrivilegeService { + + @Autowired + private PrivilegeDao privilegeDao; + + @Autowired + private RoleDao roleDao; + + @Autowired + private RolePrivilegeDao rolePrivilegeDao; + + @Autowired + private PrivilegeEmployeeService privilegeEmployeeService; + + /** + * 更新角色权限 + * + * @param updateDTO + * @return ResponseDTO + */ + public ResponseDTO updateRolePrivilege(RolePrivilegeDTO updateDTO) { + Long roleId = updateDTO.getRoleId(); + RoleEntity roleEntity = roleDao.selectById(roleId); + if (null == roleEntity) { + return ResponseDTO.wrap(RoleResponseCodeConst.ROLE_NOT_EXISTS); + } + rolePrivilegeDao.deleteByRoleId(roleId); + List rolePrivilegeList = Lists.newArrayList(); + RolePrivilegeEntity rolePrivilegeEntity; + for (String privilegeKey : updateDTO.getPrivilegeKeyList()) { + rolePrivilegeEntity = new RolePrivilegeEntity(); + rolePrivilegeEntity.setRoleId(roleId); + rolePrivilegeEntity.setPrivilegeKey(privilegeKey); + rolePrivilegeList.add(rolePrivilegeEntity); + } + rolePrivilegeDao.batchInsert(rolePrivilegeList); + privilegeEmployeeService.updateOnlineEmployeePrivilegeByRoleId(roleId); + return ResponseDTO.succ(); + } + + public ResponseDTO listPrivilegeByRoleId(Long roleId) { + RolePrivilegeTreeVO rolePrivilegeTreeDTO = new RolePrivilegeTreeVO(); + rolePrivilegeTreeDTO.setRoleId(roleId); + + List privilegeDTOList = privilegeDao.selectAll(); + if (CollectionUtils.isEmpty(privilegeDTOList)) { + rolePrivilegeTreeDTO.setPrivilege(Lists.newArrayList()); + rolePrivilegeTreeDTO.setSelectedKey(Lists.newArrayList()); + return ResponseDTO.succData(rolePrivilegeTreeDTO); + } + //构造权限树 + List privilegeList = this.buildPrivilegeTree(privilegeDTOList); + //设置选中状态 + List rolePrivilegeEntityList = rolePrivilegeDao.listByRoleId(roleId); + List privilegeKeyList = rolePrivilegeEntityList.stream().map(e -> e.getKey()).collect(Collectors.toList()); + rolePrivilegeTreeDTO.setPrivilege(privilegeList); + rolePrivilegeTreeDTO.setSelectedKey(privilegeKeyList); + return ResponseDTO.succData(rolePrivilegeTreeDTO); + } + + private List buildPrivilegeTree(List privilegeEntityList) { + List privilegeTree = Lists.newArrayList(); + List rootPrivilege = privilegeEntityList.stream().filter(e -> e.getParentKey() == null).collect(Collectors.toList()); + rootPrivilege.sort(Comparator.comparing(PrivilegeEntity::getSort)); + if (CollectionUtils.isEmpty(rootPrivilege)) { + return privilegeTree; + } + privilegeTree = SmartBeanUtil.copyList(rootPrivilege, RolePrivilegeSimpleDTO.class); + privilegeTree.forEach(e -> e.setChildren(Lists.newArrayList())); + this.buildChildPrivilegeList(privilegeEntityList, privilegeTree); + return privilegeTree; + } + + private void buildChildPrivilegeList(List privilegeEntityList, List parentMenuList) { + List parentKeyList = parentMenuList.stream().map(RolePrivilegeSimpleDTO :: getKey).collect(Collectors.toList()); + List childEntityList = privilegeEntityList.stream().filter(e -> parentKeyList.contains(e.getParentKey())).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(childEntityList)) { + return; + } + Map> listMap = childEntityList.stream().collect(Collectors.groupingBy(PrivilegeEntity :: getParentKey)); + for (RolePrivilegeSimpleDTO rolePrivilegeSimpleDTO : parentMenuList) { + String key = rolePrivilegeSimpleDTO.getKey(); + List privilegeEntities = listMap.get(key); + if (CollectionUtils.isEmpty(privilegeEntities)) { + continue; + } + privilegeEntities.sort(Comparator.comparing(PrivilegeEntity::getSort)); + List privilegeList = SmartBeanUtil.copyList(privilegeEntities, RolePrivilegeSimpleDTO.class); + privilegeList.forEach(e -> e.setChildren(Lists.newArrayList())); + rolePrivilegeSimpleDTO.setChildren(privilegeList); + this.buildChildPrivilegeList(privilegeEntityList, privilegeList); + } + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeDTO.java new file mode 100644 index 00000000..5b09bf58 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeDTO.java @@ -0,0 +1,35 @@ +package com.gangquan360.smartadmin.module.role.roleprivilege.domain.dto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.util.List; +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +public class RolePrivilegeDTO { + + /** + * 角色id + */ + @ApiModelProperty("角色id") + @NotNull(message = "角色id不能为空") + private Long roleId; + + /** + * 功能权限id 集合 + */ + @ApiModelProperty("功能权限Key集合") + @NotNull(message = "功能权限集合不能为空") + private List privilegeKeyList; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeSimpleDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeSimpleDTO.java new file mode 100644 index 00000000..c44dc937 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeSimpleDTO.java @@ -0,0 +1,43 @@ +package com.gangquan360.smartadmin.module.role.roleprivilege.domain.dto; + +import com.gangquan360.smartadmin.common.anno.ApiModelPropertyEnum; +import com.gangquan360.smartadmin.module.privilege.constant.PrivilegeTypeEnum; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +/** + * 角色功能权限 + * + * @author listen + * @date 2018/01/03 08:48 + */ +@Data +public class RolePrivilegeSimpleDTO { + + @ApiModelProperty("父级Key") + private String parentKey; + /** + * 功能名称 + */ + @ApiModelProperty("名称") + private String name; + + @ApiModelPropertyEnum(enumDesc = "类型",value = PrivilegeTypeEnum.class) + private Integer type; + + @ApiModelProperty("key") + private String key; + + @ApiModelProperty("url") + private String url; + + @ApiModelProperty("排序") + private Integer sort; + + @ApiModelProperty("子级列表") + private List children; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeTreeVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeTreeVO.java new file mode 100644 index 00000000..7b7893c2 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/dto/RolePrivilegeTreeVO.java @@ -0,0 +1,19 @@ +package com.gangquan360.smartadmin.module.role.roleprivilege.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class RolePrivilegeTreeVO { + + @ApiModelProperty("角色ID") + private Long roleId; + + @ApiModelProperty("权限列表") + private List privilege; + + @ApiModelProperty("选中的权限") + private List selectedKey; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/entity/RolePrivilegeEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/entity/RolePrivilegeEntity.java new file mode 100644 index 00000000..f30b7a3e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/role/roleprivilege/domain/entity/RolePrivilegeEntity.java @@ -0,0 +1,32 @@ +package com.gangquan360.smartadmin.module.role.roleprivilege.domain.entity; +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +/** + * + * [ 角色 权限关系 ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +@TableName("t_role_privilege") +public class RolePrivilegeEntity extends BaseEntity { + + /** + * 角色 id + */ + private Long roleId; + + /** + * 功能权限 id + */ + private String privilegeKey; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadCommand.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadCommand.java new file mode 100644 index 00000000..5922a7c0 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadCommand.java @@ -0,0 +1,52 @@ +package com.gangquan360.smartadmin.module.smartreload; + +import com.gangquan360.smartadmin.common.reload.abstracts.AbstractSmartReloadCommand4Spring; +import com.gangquan360.smartadmin.common.reload.domain.entity.ReloadItem; +import com.gangquan360.smartadmin.common.reload.domain.entity.SmartReloadResult; +import com.gangquan360.smartadmin.module.smartreload.dao.ReloadItemDao; +import com.gangquan360.smartadmin.module.smartreload.dao.ReloadResultDao; +import com.gangquan360.smartadmin.module.smartreload.domain.entity.ReloadItemEntity; +import com.gangquan360.smartadmin.module.smartreload.domain.entity.ReloadResultEntity; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * Smart Reload 业务 + * + * @author listen + * @date 2018/02/10 09:18 + */ +@Component +public class SmartReloadCommand extends AbstractSmartReloadCommand4Spring { + + @Autowired + private ReloadItemDao reloadItemDao; + + @Autowired + private ReloadResultDao reloadResultDao; + + /** + * 读取数据库中SmartReload项 + * + * @return List + */ + @Override + public List readReloadItem() { + List reloadItemEntityList = reloadItemDao.selectList(null); + return SmartBeanUtil.copyList(reloadItemEntityList, ReloadItem.class); + } + + /** + * 保存reload结果 + * + * @param smartReloadResult + */ + @Override + public void handleReloadResult(SmartReloadResult smartReloadResult) { + ReloadResultEntity reloadResultEntity = SmartBeanUtil.copy(smartReloadResult, ReloadResultEntity.class); + reloadResultDao.insert(reloadResultEntity); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadController.java new file mode 100644 index 00000000..97e71b23 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadController.java @@ -0,0 +1,52 @@ +package com.gangquan360.smartadmin.module.smartreload; + +import com.gangquan360.smartadmin.common.anno.NoValidPrivilege; +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.smartreload.domain.dto.ReloadItemUpdateDTO; +import com.gangquan360.smartadmin.module.smartreload.domain.dto.ReloadItemVO; +import com.gangquan360.smartadmin.module.smartreload.domain.dto.ReloadResultVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.List; + +/** + * Smart Reload 路由 + * + * @author listen + * @date 2018/02/10 09:18 + */ +@Api(tags = {SwaggerTagConst.Admin.MANAGER_SMART_RELOAD}) +@OperateLog +@RestController +public class SmartReloadController { + + @Autowired + private SmartReloadService smartReloadService; + + @ApiOperation(value = "获取全部Smart-reload项", notes = "获取全部Smart-reload项") + @GetMapping("/smartReload/all") + @NoValidPrivilege + public ResponseDTO> listAllReloadItem() { + return smartReloadService.listAllReloadItem(); + } + + @ApiOperation(value = "获取reload result", notes = "获取reload result") + @GetMapping("/smartReload/result/{tag}") + @NoValidPrivilege + public ResponseDTO> queryReloadResult(@PathVariable("tag") String tag) { + return smartReloadService.listReloadItemResult(tag); + } + + @ApiOperation("通过tag更新标识") + @PostMapping("/smartReload/update") + @NoValidPrivilege + public ResponseDTO updateByTag(@RequestBody @Valid ReloadItemUpdateDTO updateDTO) { + return smartReloadService.updateByTag(updateDTO); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadService.java new file mode 100644 index 00000000..49ad7180 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/SmartReloadService.java @@ -0,0 +1,103 @@ +package com.gangquan360.smartadmin.module.smartreload; + +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.common.reload.SmartReloadManager; +import com.gangquan360.smartadmin.module.smartreload.dao.ReloadItemDao; +import com.gangquan360.smartadmin.module.smartreload.dao.ReloadResultDao; +import com.gangquan360.smartadmin.module.smartreload.domain.dto.ReloadItemUpdateDTO; +import com.gangquan360.smartadmin.module.smartreload.domain.dto.ReloadItemVO; +import com.gangquan360.smartadmin.module.smartreload.domain.dto.ReloadResultVO; +import com.gangquan360.smartadmin.module.smartreload.domain.entity.ReloadItemEntity; +import com.gangquan360.smartadmin.module.smartreload.domain.entity.ReloadResultEntity; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.sql.Timestamp; +import java.util.List; +import java.util.concurrent.TimeUnit; + +/** + * Smart initDefines 业务 + * + * @author listen + * @date 2018/02/10 13:49 + */ +@Service +public class SmartReloadService { + + @Autowired + private SmartReloadManager smartReloadManager; + + @Autowired + private SmartReloadCommand smartReloadCommand; + + @Autowired + private ReloadItemDao reloadItemDao; + + @Autowired + private ReloadResultDao reloadResultDao; + + @Value("${smart-reload.time-interval}") + private Long timeInterval; + + @PostConstruct + public void init() { + smartReloadManager.addCommand(smartReloadCommand, 10, timeInterval, TimeUnit.SECONDS); + } + + /** + * 注册到SmartReload里 + */ + public void register(Object reload) { + smartReloadManager.register(reload); + } + + /** + * 获取所有 initDefines 项 + * + * @return + */ + public ResponseDTO> listAllReloadItem() { + List reloadItemEntityList = reloadItemDao.selectList(null); + List reloadItemDTOList = SmartBeanUtil.copyList(reloadItemEntityList, ReloadItemVO.class); + return ResponseDTO.succData(reloadItemDTOList); + } + + /** + * 根据 tag + * 获取所有 initDefines 运行结果 + * + * @return ResponseDTO + */ + public ResponseDTO> listReloadItemResult(String tag) { + ReloadResultEntity query = new ReloadResultEntity(); + query.setTag(tag); + List reloadResultEntityList = reloadResultDao.query(tag); + List reloadResultDTOList = SmartBeanUtil.copyList(reloadResultEntityList, ReloadResultVO.class); + return ResponseDTO.succData(reloadResultDTOList); + } + + /** + * 通过标签更新标识符 + * + * @param updateDTO + * @return + */ + public ResponseDTO updateByTag(ReloadItemUpdateDTO updateDTO) { + ReloadItemEntity entity = new ReloadItemEntity(); + entity.setTag(updateDTO.getTag()); + ReloadItemEntity reloadItemEntity = reloadItemDao.selectById(entity.getTag()); + if (null == reloadItemEntity) { + return ResponseDTO.wrap(ResponseCodeConst.NOT_EXISTS); + } + reloadItemEntity.setIdentification(updateDTO.getIdentification()); + reloadItemEntity.setUpdateTime(new Timestamp(System.currentTimeMillis())); + reloadItemEntity.setArgs(updateDTO.getArgs()); + reloadItemDao.updateById(reloadItemEntity); + return ResponseDTO.succ(); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/dao/ReloadItemDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/dao/ReloadItemDao.java new file mode 100644 index 00000000..e5b56605 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/dao/ReloadItemDao.java @@ -0,0 +1,15 @@ +package com.gangquan360.smartadmin.module.smartreload.dao; +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.gangquan360.smartadmin.module.smartreload.domain.entity.ReloadItemEntity; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Component; + +/** + * t_reload_item 数据表dao + * + * @author listen + * @date 2018/02/10 09:23 + */ +@Component +@Mapper +public interface ReloadItemDao extends BaseMapper {} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/dao/ReloadResultDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/dao/ReloadResultDao.java new file mode 100644 index 00000000..b78244c2 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/dao/ReloadResultDao.java @@ -0,0 +1,23 @@ +package com.gangquan360.smartadmin.module.smartreload.dao; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.gangquan360.smartadmin.module.smartreload.domain.entity.ReloadResultEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * t_reload_result 数据表dao + * + * @author listen + * @date 2018/02/10 09:23 + */ +@Component +@Mapper +public interface ReloadResultDao extends BaseMapper { + + + List query(@Param("tag") String tag); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadItemUpdateDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadItemUpdateDTO.java new file mode 100644 index 00000000..15e8e860 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadItemUpdateDTO.java @@ -0,0 +1,29 @@ +package com.gangquan360.smartadmin.module.smartreload.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +/** + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Data +public class ReloadItemUpdateDTO { + + @ApiModelProperty("标签") + @NotBlank(message = "标签不能为空") + private String tag; + + @ApiModelProperty("状态标识") + @NotBlank(message = "状态标识不能为空") + private String identification; + + @ApiModelProperty("reload时传入的参数,可以为空") + private String args; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadItemVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadItemVO.java new file mode 100644 index 00000000..571dd599 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadItemVO.java @@ -0,0 +1,46 @@ +package com.gangquan360.smartadmin.module.smartreload.domain.dto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * initDefines 项 DTO 类 + * + * @author listen + * @date 2018/02/10 09:29 + */ +@Data +public class ReloadItemVO { + + /** + * 加载项标签 + */ + @ApiModelProperty("加载项标签") + private String tag; + + /** + * 参数 + */ + @ApiModelProperty("参数") + private String args; + + /** + * 状态标识 + */ + @ApiModelProperty("状态标识") + private String identification; + + /** + * 更新时间 + */ + @ApiModelProperty("最后更新时间") + private Date updateTime; + + /** + * 创建时间 + */ + @ApiModelProperty("创建时间") + private Date createTime; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadResultVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadResultVO.java new file mode 100644 index 00000000..0db01ee7 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/dto/ReloadResultVO.java @@ -0,0 +1,47 @@ +package com.gangquan360.smartadmin.module.smartreload.domain.dto; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.util.Date; + +/** + * reload_result DTO 类 + * + * @author listen + * @date 2018/02/10 09:29 + */ +@Data +public class ReloadResultVO { + + /** + * 加载项标签 + */ + private String tag; + + /** + * 参数 + */ + private String args; + + /** + * 状态标识 + */ + private String identification; + + /** + * 运行结果 + */ + private Boolean result; + + /** + * 异常 + */ + private String exception; + + /** + * 创建时间 + */ + private Date createTime; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/entity/ReloadItemEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/entity/ReloadItemEntity.java new file mode 100644 index 00000000..c5be854a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/entity/ReloadItemEntity.java @@ -0,0 +1,46 @@ +package com.gangquan360.smartadmin.module.smartreload.domain.entity; +import com.baomidou.mybatisplus.annotations.TableId; +import com.baomidou.mybatisplus.annotations.TableName; +import com.baomidou.mybatisplus.enums.IdType; +import lombok.Data; + +import java.util.Date; + +/** + * t_reload_item 数据表 实体类 + * + * @author listen + * @date 2018/02/10 09:29 + */ +@Data +@TableName("t_reload_item") +public class ReloadItemEntity { + + /** + * 加载项标签 + */ + @TableId(type = IdType.INPUT) + private String tag; + + /** + * 参数 + */ + private String args; + + /** + * 运行标识 + */ + private String identification; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 创建时间 + */ + private Date createTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/entity/ReloadResultEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/entity/ReloadResultEntity.java new file mode 100644 index 00000000..e04f197d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/smartreload/domain/entity/ReloadResultEntity.java @@ -0,0 +1,48 @@ +package com.gangquan360.smartadmin.module.smartreload.domain.entity; +import com.baomidou.mybatisplus.annotations.TableName; +import lombok.Data; + +import java.util.Date; + +/** + * t_reload_result 数据表 实体类 + * + * @author listen + * @date 2018/02/10 09:29 + */ +@Data +@TableName("t_reload_result") +public class ReloadResultEntity { + + /** + * 加载项标签 + */ + private String tag; + + /** + * 运行标识 + */ + private String identification; + + /** + * 参数 + */ + private String args; + + /** + * 运行结果 + */ + private Boolean result; + + /** + * 异常 + */ + private String exception; + + /** + * 创建时间 + */ + private Date createTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigController.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigController.java new file mode 100644 index 00000000..da12c4ff --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigController.java @@ -0,0 +1,70 @@ +package com.gangquan360.smartadmin.module.systemconfig; + +import com.gangquan360.smartadmin.common.anno.OperateLog; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.constant.SwaggerTagConst; +import com.gangquan360.smartadmin.module.systemconfig.domain.dto.SystemConfigAddDTO; +import com.gangquan360.smartadmin.module.systemconfig.domain.dto.SystemConfigQueryDTO; +import com.gangquan360.smartadmin.module.systemconfig.domain.dto.SystemConfigUpdateDTO; +import com.gangquan360.smartadmin.module.systemconfig.domain.dto.SystemConfigVO; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.validation.Valid; +import java.util.List; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Api(tags = {SwaggerTagConst.Admin.MANAGER_SYSTEM_CONFIG}) +@OperateLog +@RestController +public class SystemConfigController { + + @Autowired + private SystemConfigService systemConfigService; + + @ApiOperation(value = "分页查询所有系统配置", notes = "分页查询所有系统配置") + @PostMapping("systemConfig/getListPage") + public ResponseDTO> getSystemConfigPage(@RequestBody @Valid SystemConfigQueryDTO queryDTO) { + return systemConfigService.getSystemConfigPage(queryDTO); + } + + @ApiOperation(value = "添加配置参数", notes = "添加配置参数") + @PostMapping("systemConfig/add") + public ResponseDTO addSystemConfig(@RequestBody @Valid SystemConfigAddDTO configAddDTO) { + return systemConfigService.addSystemConfig(configAddDTO); + } + + @ApiOperation(value = "修改配置参数", notes = "修改配置参数") + @PostMapping("systemConfig/update") + public ResponseDTO updateSystemConfig(@RequestBody @Valid SystemConfigUpdateDTO updateDTO) { + return systemConfigService.updateSystemConfig(updateDTO); + } + + @ApiOperation(value = "根据分组查询所有系统配置", notes = "根据分组查询所有系统配置") + @GetMapping("systemConfig/getListByGroup") + public ResponseDTO> getListByGroup(String group) { + return systemConfigService.getListByGroup(group); + } + + @ApiOperation(value = "通过key获取对应的信息", notes = "通过key获取对应的信息") + @GetMapping("systemConfig/selectByKey") + public ResponseDTO selectByKey(String configKey) { + return systemConfigService.selectByKey(configKey); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigDao.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigDao.java new file mode 100644 index 00000000..53654d97 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigDao.java @@ -0,0 +1,62 @@ +package com.gangquan360.smartadmin.module.systemconfig; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.pagination.Pagination; +import com.gangquan360.smartadmin.module.systemconfig.domain.dto.SystemConfigQueryDTO; +import com.gangquan360.smartadmin.module.systemconfig.domain.entity.SystemConfigEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 系统参数配置 t_system_config Dao层 + * + * @author GHQ + * @date 2017-12-23 14:25 + */ +@Component +@Mapper +public interface SystemConfigDao extends BaseMapper { + + /** + * 查询所有系统配置(分页) + * + * @param page + * @return + */ + List selectSystemSettingList(Pagination page, SystemConfigQueryDTO queryDTO); + + /** + * 根据key查询获取数据 + * + * @param key + * @return + */ + SystemConfigEntity getByKey(@Param("key") String key); + + /** + * 根据key查询获取数据 排除掉某個id的数据 + * @param key + * @param excludeId + * @return + */ + SystemConfigEntity getByKeyExcludeId(@Param("key") String key,@Param("excludeId") Long excludeId); + /** + * 查询所有系统配置 + * + * @return + */ + List selectSystemSettingList(); + + /** + * 根据分组查询所有系统配置 + * @param group + * @return + */ + List getListByGroup(String group); + + + SystemConfigEntity selectByKeyAndGroup(@Param("configKey") String configKey, @Param("group") String group); +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigService.java new file mode 100644 index 00000000..9a691071 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/SystemConfigService.java @@ -0,0 +1,250 @@ +package com.gangquan360.smartadmin.module.systemconfig; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.constant.JudgeEnum; +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import com.gangquan360.smartadmin.common.domain.ResponseDTO; +import com.gangquan360.smartadmin.common.exception.SmartBusinessException; +import com.gangquan360.smartadmin.common.reload.annotation.SmartReload; +import com.gangquan360.smartadmin.constant.SmartReloadTagConst; +import com.gangquan360.smartadmin.module.smartreload.SmartReloadService; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigDataType; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigEnum; +import com.gangquan360.smartadmin.module.systemconfig.constant.SystemConfigResponseCodeConst; +import com.gangquan360.smartadmin.module.systemconfig.domain.dto.*; +import com.gangquan360.smartadmin.module.systemconfig.domain.entity.SystemConfigEntity; +import com.gangquan360.smartadmin.util.SmartBeanUtil; +import com.gangquan360.smartadmin.util.SmartPaginationUtil; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Pattern; + +/** + * 系统配置业务类 + * + * @author GHQ + * @date 2017-12-23 15:09 + */ +@Slf4j +@Service +public class SystemConfigService { + + /** + * 系统配置缓存 + */ + private ConcurrentHashMap systemConfigMap = new ConcurrentHashMap<>(); + + @Autowired + private SystemConfigDao systemConfigDao; + + @Autowired + private SmartReloadService smartReloadService; + + /** + * 初始化系统设置缓存 + */ + @PostConstruct + private void initSystemConfigCache() { + List entityList = systemConfigDao.selectSystemSettingList(); + if (CollectionUtils.isEmpty(entityList)) { + return; + } + + systemConfigMap.clear(); + entityList.forEach(entity -> this.systemConfigMap.put(entity.getConfigKey().toLowerCase(), entity)); + log.info("系统设置缓存初始化完毕:{}", systemConfigMap.size()); + + smartReloadService.register(this); + } + + @SmartReload(SmartReloadTagConst.SYSTEM_CONFIG) + public boolean reload(String args) { + this.initSystemConfigCache(); + log.warn("<> <<{}>> , args {} reload success ", SmartReloadTagConst.SYSTEM_CONFIG, args); + return true; + } + + /** + * 分页获取系统配置 + * + * @param queryDTO + * @return + */ + public ResponseDTO> getSystemConfigPage(SystemConfigQueryDTO queryDTO) { + Page page = SmartPaginationUtil.convert2PageQueryInfo(queryDTO); + List entityList = systemConfigDao.selectSystemSettingList(page, queryDTO); + PageResultDTO pageResultDTO = SmartPaginationUtil.convert2PageInfoDTO(page, entityList, SystemConfigVO.class); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * 根据参数key获得一条数据(数据库) + * + * @param configKey + * @return + */ + public ResponseDTO selectByKey(String configKey) { + SystemConfigEntity entity = systemConfigDao.getByKey(configKey); + if (entity == null) { + return ResponseDTO.wrap(SystemConfigResponseCodeConst.NOT_EXIST); + } + SystemConfigVO configDTO = SmartBeanUtil.copy(entity, SystemConfigVO.class); + return ResponseDTO.succData(configDTO); + } + + /** + * 根据参数key获得一条数据 并转换为 对象 + * + * @param configKey + * @param clazz + * @param + * @return + */ + public T selectByKey2Obj(String configKey, Class clazz) { + SystemConfigEntity entity = systemConfigDao.getByKey(configKey); + if (entity == null) { + return null; + } + SystemConfigDTO configDTO = SmartBeanUtil.copy(entity, SystemConfigDTO.class); + String configValue = configDTO.getConfigValue(); + if (StringUtils.isEmpty(configValue)) { + return null; + } + T obj = JSON.parseObject(configValue, clazz); + return obj; + } + + public SystemConfigDTO getCacheByKey(SystemConfigEnum.Key key) { + SystemConfigEntity entity = this.systemConfigMap.get(key.name().toLowerCase()); + if (entity == null) { + throw new SmartBusinessException("缺少系统配置[" + key.name() + "]"); + } + return SmartBeanUtil.copy(entity, SystemConfigDTO.class); + } + + /** + * 添加系统配置 + * + * @param configAddDTO + * @return + */ + public ResponseDTO addSystemConfig(SystemConfigAddDTO configAddDTO) { + SystemConfigEntity entity = systemConfigDao.getByKey(configAddDTO.getConfigKey()); + if (entity != null) { + return ResponseDTO.wrap(SystemConfigResponseCodeConst.ALREADY_EXIST); + } + ResponseDTO valueValid = this.configValueValid(configAddDTO.getConfigKey(),configAddDTO.getConfigValue()); + if(!valueValid.isSuccess()){ + return valueValid; + } + SystemConfigEntity addEntity = SmartBeanUtil.copy(configAddDTO, SystemConfigEntity.class); + addEntity.setIsUsing(JudgeEnum.YES.getValue()); + systemConfigDao.insert(addEntity); + //刷新缓存 + this.initSystemConfigCache(); + return ResponseDTO.succ(); + } + + /** + * 更新系统配置 + * + * @param updateDTO + * @return + */ + public ResponseDTO updateSystemConfig(SystemConfigUpdateDTO updateDTO) { + SystemConfigEntity entity = systemConfigDao.selectById(updateDTO.getId()); + //系统配置不存在 + if (entity == null) { + return ResponseDTO.wrap(SystemConfigResponseCodeConst.NOT_EXIST); + } + SystemConfigEntity alreadyEntity = systemConfigDao.getByKeyExcludeId(updateDTO.getConfigKey(), updateDTO.getId()); + if (alreadyEntity != null) { + return ResponseDTO.wrap(SystemConfigResponseCodeConst.ALREADY_EXIST); + } + ResponseDTO valueValid = this.configValueValid(updateDTO.getConfigKey(),updateDTO.getConfigValue()); + if(!valueValid.isSuccess()){ + return valueValid; + } + entity = SmartBeanUtil.copy(updateDTO, SystemConfigEntity.class); + systemConfigDao.updateById(entity); + + //刷新缓存 + this.initSystemConfigCache(); + return ResponseDTO.succ(); + } + + + private ResponseDTO configValueValid(String configKey , String configValue){ + SystemConfigEnum.Key configKeyEnum = SystemConfigEnum.Key.selectByKey(configKey); + if(configKeyEnum == null){ + return ResponseDTO.succ(); + } + SystemConfigDataType dataType = configKeyEnum.getDataType(); + if(dataType == null){ + return ResponseDTO.succ(); + } + if(dataType.name().equals(SystemConfigDataType.TEXT.name())){ + return ResponseDTO.succ(); + } + if(dataType.name().equals(SystemConfigDataType.JSON.name())){ + try { + JSONObject jsonStr = JSONObject.parseObject(configValue); + return ResponseDTO.succ(); + } catch (Exception e) { + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM,"数据格式不是JSON,请修改后提交。"); + } + } + if(StringUtils.isNotEmpty(dataType.getValid())){ + Boolean valid = Pattern.matches(dataType.getValid(), configValue); + if(valid){ + return ResponseDTO.succ(); + } + return ResponseDTO.wrap(ResponseCodeConst.ERROR_PARAM,"数据格式不是"+dataType.name().toLowerCase()+",请修改后提交。"); + } + + return ResponseDTO.succ(); + } + + /** + * 根据分组名称 获取获取系统设置 + * + * @param group + * @return + */ + public ResponseDTO> getListByGroup(String group) { + + List entityList = systemConfigDao.getListByGroup(group); + if (CollectionUtils.isEmpty(entityList)) { + return ResponseDTO.succData(Lists.newArrayList()); + } + List systemConfigList = SmartBeanUtil.copyList(entityList, SystemConfigVO.class); + return ResponseDTO.succData(systemConfigList); + } + + /** + * 根据分组名称 获取获取系统设置 + * + * @param group + * @return + */ + public List getListByGroup(SystemConfigEnum.Group group) { + List entityList = systemConfigDao.getListByGroup(group.name()); + if (CollectionUtils.isEmpty(entityList)) { + return Lists.newArrayList(); + } + List systemConfigList = SmartBeanUtil.copyList(entityList, SystemConfigDTO.class); + return systemConfigList; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigDataType.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigDataType.java new file mode 100644 index 00000000..e02da00e --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigDataType.java @@ -0,0 +1,67 @@ +package com.gangquan360.smartadmin.module.systemconfig.constant; + +import com.gangquan360.smartadmin.util.SmartVerificationUtil; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/9/4 0004 上午 11:43 + * @since JDK1.8 + */ +public enum SystemConfigDataType { + /** + * 整数 + */ + INTEGER(SmartVerificationUtil.INTEGER), + /** + * 文本 + */ + TEXT(null), + /** + * url地址 + */ + URL(SmartVerificationUtil.URL), + /** + * 邮箱 + */ + EMAIL(SmartVerificationUtil.EMAIL), + /** + * JSON 字符串 + */ + JSON(null), + /** + * 2019-08 + */ + YEAR_MONTH(SmartVerificationUtil.YEAR_MONTH), + /** + * 2019-08-01 + */ + DATE(SmartVerificationUtil.DATE), + /** + * 2019-08-01 10:23 + */ + DATE_TIME(SmartVerificationUtil.DATE_TIME), + /** + * 10:23-10:56 + */ + TIME_SECTION(SmartVerificationUtil.TIME_SECTION), + /** + * 10:23 + */ + TIME(SmartVerificationUtil.TIME); + + private String valid; + + + SystemConfigDataType(String valid){ + this.valid = valid; + } + + public String getValid() { + return valid; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigEnum.java new file mode 100644 index 00000000..0007f44b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigEnum.java @@ -0,0 +1,65 @@ +package com.gangquan360.smartadmin.module.systemconfig.constant; + + +import java.util.Arrays; +import java.util.Optional; + +/** + * [ 系统配置常量类 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +public class SystemConfigEnum { + + public enum Group { + BACK + } + + public enum Key { + + /** + * 超管id + */ + EMPLOYEE_SUPERMAN(SystemConfigDataType.TEXT), + /** + * 阿里云OSS配置项 + */ + ALI_OSS(SystemConfigDataType.JSON), + /** + * 七牛云OSS配置项 + */ + QI_NIU_OSS(SystemConfigDataType.JSON), + /** + * 本地文件上传url前缀 + */ + LOCAL_UPLOAD_URL_PREFIX(SystemConfigDataType.URL), + /** + * 邮件配置 + */ + EMAIL_CONFIG(SystemConfigDataType.JSON); + + + private SystemConfigDataType dataType; + + Key(SystemConfigDataType dataType){ + this.dataType = dataType; + } + + + public SystemConfigDataType getDataType() { + return dataType; + } + + public static Key selectByKey(String key) { + Key[] values = Key.values(); + Optional first = Arrays.stream(values).filter(e -> e.name().equalsIgnoreCase(key)).findFirst(); + return !first.isPresent() ? null : first.get(); + } + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigResponseCodeConst.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigResponseCodeConst.java new file mode 100644 index 00000000..b95700e4 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/constant/SystemConfigResponseCodeConst.java @@ -0,0 +1,29 @@ +package com.gangquan360.smartadmin.module.systemconfig.constant; +import com.gangquan360.smartadmin.common.constant.ResponseCodeConst; + +/** + * + * [ 5001-5999 ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +public class SystemConfigResponseCodeConst extends ResponseCodeConst { + + /** + * 配置参数已存在 10201 + */ + public static final SystemConfigResponseCodeConst ALREADY_EXIST = new SystemConfigResponseCodeConst(5001, "配置参数已存在"); + /** + * 配置参数不存在 10203 + */ + public static final SystemConfigResponseCodeConst NOT_EXIST = new SystemConfigResponseCodeConst(5002, "配置参数不存在"); + + public SystemConfigResponseCodeConst(int code, String msg) { + super(code, msg); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigAddDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigAddDTO.java new file mode 100644 index 00000000..fbae679f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigAddDTO.java @@ -0,0 +1,45 @@ +package com.gangquan360.smartadmin.module.systemconfig.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Data +public class SystemConfigAddDTO { + + @ApiModelProperty("参数key") + @NotBlank(message = "参数key不能为空") + @Length(max = 255, message = "参数key最多255个字符") + private String configKey; + + @ApiModelProperty("参数的值") + @NotBlank(message = "参数的值不能为空") + @Length(max = 65530, message = "参数的值最多65530个字符") + private String configValue; + + @ApiModelProperty("参数名称") + @NotBlank(message = "参数名称不能为空") + @Length(max = 255, message = "参数名称最多255个字符") + private String configName; + + @ApiModelProperty("参数类别") + @NotBlank(message = "参数类别不能为空") + @Length(max = 255, message = "参数类别最多255个字符") + private String configGroup; + + @ApiModelProperty("备注") + @Length(max = 255, message = "备注最多255个字符") + private String remark; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigDTO.java new file mode 100644 index 00000000..d17f91e1 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigDTO.java @@ -0,0 +1,50 @@ +package com.gangquan360.smartadmin.module.systemconfig.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +public class SystemConfigDTO { + + @ApiModelProperty("主键") + private Long id; + + @ApiModelProperty("参数key") + private String configKey; + + @ApiModelProperty("参数的值") + private String configValue; + + @ApiModelProperty("参数名称") + private String configName; + + @ApiModelProperty("参数类别") + private String configGroup; + + @ApiModelProperty("是否使用0 是 1否") + private Integer isUsing; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("创建时间") + private Date createTime; + + @ApiModelProperty("上次修改时间") + private Date updateTime; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigQueryDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigQueryDTO.java new file mode 100644 index 00000000..08030ba8 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigQueryDTO.java @@ -0,0 +1,29 @@ +package com.gangquan360.smartadmin.module.systemconfig.domain.dto; + + +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +public class SystemConfigQueryDTO extends PageParamDTO { + + @ApiModelProperty("参数KEY") + private String key; + + @ApiModelProperty("参数类别") + private String configGroup; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigUpdateDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigUpdateDTO.java new file mode 100644 index 00000000..1c59b8e3 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigUpdateDTO.java @@ -0,0 +1,25 @@ +package com.gangquan360.smartadmin.module.systemconfig.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * + * [ ] + * + * @version 1.0 + * @since JDK1.8 + * @author yandanyang + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + */ +@Data +public class SystemConfigUpdateDTO extends SystemConfigAddDTO{ + + @ApiModelProperty("id") + @NotNull(message = "id不能为空") + private Long id; +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigVO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigVO.java new file mode 100644 index 00000000..246e4950 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/dto/SystemConfigVO.java @@ -0,0 +1,48 @@ +package com.gangquan360.smartadmin.module.systemconfig.domain.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +@Data +public class SystemConfigVO { + + @ApiModelProperty("主键") + private Long id; + + @ApiModelProperty("参数key") + private String configKey; + + @ApiModelProperty("参数的值") + private String configValue; + + @ApiModelProperty("参数名称") + private String configName; + + @ApiModelProperty("参数类别") + private String configGroup; + + @ApiModelProperty("是否使用0 是 1否") + private Integer isUsing; + + @ApiModelProperty("备注") + private String remark; + + @ApiModelProperty("创建时间") + private Date createTime; + + @ApiModelProperty("上次修改时间") + private Date updateTime; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/entity/SystemConfigEntity.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/entity/SystemConfigEntity.java new file mode 100644 index 00000000..56345b64 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/systemconfig/domain/entity/SystemConfigEntity.java @@ -0,0 +1,51 @@ +package com.gangquan360.smartadmin.module.systemconfig.domain.entity; + +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +import lombok.Data; + +import java.io.Serializable; + +/** + * 系统配置参数 实体类 + * + * @author GHQ + * @date 2017-12-23 13:41 + */ +@Data +@TableName(value = "t_system_config") +public class SystemConfigEntity extends BaseEntity implements Serializable { + + private static final long serialVersionUID = 257284726400352502L; + + /** + * 参数key + */ + private String configKey; + + /** + * 参数的值 + */ + private String configValue; + + /** + * 参数名称 + */ + private String configName; + + /** + * 参数类别 + */ + private String configGroup; + + /** + * 是否使用0 是 1否 + */ + private Integer isUsing; + + /** + * 备注 + */ + private String remark; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/MessageTypeEnum.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/MessageTypeEnum.java new file mode 100644 index 00000000..d2512306 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/MessageTypeEnum.java @@ -0,0 +1,44 @@ +package com.gangquan360.smartadmin.module.websocket; + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/10 0010 下午 19:11 + * @since JDK1.8 + */ +public enum MessageTypeEnum implements BaseEnum{ + + SYS_NOTICE(1,"系统通知"), + + PRIVATE_LETTER(2,"私信"), + + HEART_BEAT(3,"心跳"); + + + private Integer value; + + private String desc; + + + MessageTypeEnum(Integer value,String desc){ + this.value = value; + this.desc = desc; + } + + + @Override + public Integer getValue() { + return this.value; + } + + @Override + public String getDesc() { + return this.desc; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/WebSocketServer.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/WebSocketServer.java new file mode 100644 index 00000000..5474e03c --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/WebSocketServer.java @@ -0,0 +1,199 @@ +package com.gangquan360.smartadmin.module.websocket; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.TypeReference; +import com.gangquan360.smartadmin.module.websocket.domain.MessageCommonDTO; +import com.gangquan360.smartadmin.module.websocket.domain.MessageDTO; +import com.gangquan360.smartadmin.module.websocket.domain.WebSocketHeartBeatDTO; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import javax.websocket.*; +import javax.websocket.server.PathParam; +import javax.websocket.server.ServerEndpoint; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/10 0010 下午 16:09 + * @since JDK1.8 + */ +@Slf4j +@ServerEndpoint("/webSocket/{employeeId}") +@Component +public class WebSocketServer { + + /** + * 当前在线用户 employee,expireTime + */ + private static ConcurrentHashMap onLineUser = new ConcurrentHashMap<>(); + + /** + * 当前在线用户所对应的 socket session信息 + */ + private static ConcurrentHashMap webSocketSession = new ConcurrentHashMap<>(); + + @OnOpen + public void onOpen(Session session, @PathParam("employeeId") Long employeeId) { + if (employeeId == null) { + return; + } + webSocketSession.put(employeeId, session); + log.info("连接打开"); + } + + /** + * 不做处理如果 前台可以监听到浏览器关闭 此处处理在线人数也可 + * + * @param session + */ + @OnClose + public void onClose(Session session) { + + log.info("连接关闭"); + } + + @OnError + public void onError(Session session, Throwable error) { + log.error("socket error,{}", error); + error.printStackTrace(); + } + + /** + * 此方法接收 前台信息 + * + * @param message + * @param session + */ + @OnMessage + public void onMessage(String message, Session session) { + if (StringUtils.isEmpty(message)) { + return; + } + MessageCommonDTO messageCommonDTO = JSON.parseObject(message, new TypeReference() {}); + if (MessageTypeEnum.HEART_BEAT.getValue().equals(messageCommonDTO.getMessageType())) { + this.heartBeatHandle(messageCommonDTO.getJsonStr()); + } + } + + /** + * 更新用户过期时间 + * + * @param json + */ + private void heartBeatHandle(String json) { + Long currentDate = System.currentTimeMillis(); + Long expireTime = currentDate + 5 * 1000; + WebSocketHeartBeatDTO heartBeatDTO = JSON.parseObject(json, new TypeReference() {}); + Long employeeId = heartBeatDTO.getEmployeeId(); + onLineUser.put(employeeId, expireTime); + } + + /** + * 移除过期用户,如果用户超过5s未获取到心跳列表则清除在线用户信息 + */ + @Scheduled(cron = "0/5 * * * * ?") + private void removeOnLineUser() { + Long currentDate = System.currentTimeMillis(); + Iterator> it = onLineUser.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry entry = it.next(); + Long key = entry.getKey(); + Long value = entry.getValue(); + Long userExpireTime = value + 5 * 1000; + if (currentDate > userExpireTime) { + onLineUser.remove(key); + webSocketSession.remove(key); + } + } + } + + /** + * 此方法用户后台发送消息 + * + * @param messageDTO + */ + public static void sendMessage(MessageDTO messageDTO) { + //系统通知 + if (MessageTypeEnum.SYS_NOTICE.getValue().equals(messageDTO.getMessageType())) { + sendAllOnLineUser(messageDTO.getMessage(), messageDTO.getFromUserId()); + } + //站内信 + if (MessageTypeEnum.PRIVATE_LETTER.getValue().equals(messageDTO.getMessageType())) { + sendOneOnLineUser(messageDTO.getMessage(), messageDTO.getToUserId()); + } + } + + /** + * 通知所有在线用户 + * + * @param message + */ + public static void sendAllOnLineUser(String message, Long fromUserId) { + for (Entry entry : webSocketSession.entrySet()) { + Session session = entry.getValue(); + Long userId = entry.getKey(); + try { + //不想消息创建人推送消息 + if (! userId.equals(fromUserId)) { + session.getBasicRemote().sendText(message); + } + } catch (IOException e) { + log.error("推送消息到{},发送错误{}", userId, e); + log.error("", e); + } + + } + } + + /** + * 通知某人 + * + * @param message + * @param toUserId + */ + public static void sendOneOnLineUser(String message, Long toUserId) { + Session session = webSocketSession.get(toUserId); + if (session == null) { + log.error("推送消息到{},用户不在线", toUserId); + } + try { + session.getBasicRemote().sendText(message); + } catch (IOException e) { + log.error("推送消息到{},发送错误{}", toUserId, e); + log.error("", e); + } + } + + /** + * 获取所有在线用户id + * + * @return + */ + public static List getOnLineUserList() { + return Lists.newArrayList(onLineUser.keySet()); + } + + /** + * 获取当前在线用户数 + * + * @return + */ + public static Integer getOnLineUserCount() { + return onLineUser.entrySet().size(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/MessageCommonDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/MessageCommonDTO.java new file mode 100644 index 00000000..fb9611c0 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/MessageCommonDTO.java @@ -0,0 +1,29 @@ +package com.gangquan360.smartadmin.module.websocket.domain; + +import com.gangquan360.smartadmin.module.websocket.MessageTypeEnum; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/13 0013 下午 14:37 + * @since JDK1.8 + */ +@Data +public class MessageCommonDTO { + /** + * 消息类型 {@link MessageTypeEnum} + */ + private Integer messageType; + + /** + * 具体消息内容 + */ + private String jsonStr; + + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/MessageDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/MessageDTO.java new file mode 100644 index 00000000..ca1ec32d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/MessageDTO.java @@ -0,0 +1,41 @@ +package com.gangquan360.smartadmin.module.websocket.domain; + +import com.gangquan360.smartadmin.module.websocket.MessageTypeEnum; +import lombok.Builder; +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/10 0010 下午 18:50 + * @since JDK1.8 + */ +@Data +@Builder +public class MessageDTO { + + /** + * 消息类型 {@link MessageTypeEnum} + */ + private Integer messageType; + + /** + * 消息体 + */ + private String message; + + /** + * 发送者 + */ + private Long fromUserId; + + /** + * 接收者,系统通知可为null + */ + private Long toUserId; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/WebSocketHeartBeatDTO.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/WebSocketHeartBeatDTO.java new file mode 100644 index 00000000..bef2fd9f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/module/websocket/domain/WebSocketHeartBeatDTO.java @@ -0,0 +1,23 @@ +package com.gangquan360.smartadmin.module.websocket.domain; + +import lombok.Data; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/7/13 0013 下午 14:39 + * @since JDK1.8 + */ +@Data +public class WebSocketHeartBeatDTO { + + /** + * 当前登录人id + */ + private Long employeeId; + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/third/SmartApplicationContext.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/third/SmartApplicationContext.java new file mode 100644 index 00000000..a14759d8 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/third/SmartApplicationContext.java @@ -0,0 +1,80 @@ +package com.gangquan360.smartadmin.third; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.stereotype.Component; + +/** + * [ApplicationContextHelper] + * + * @author yandanyang + * @version 1.0 + * @since JDK1.8 + */ +@Component +public class SmartApplicationContext implements ApplicationContextAware { + /** + * 上下文对象实例 + */ + private static ApplicationContext applicationContext = null; + + @Override + public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { + if(SmartApplicationContext.applicationContext == null){ + + SmartApplicationContext.applicationContext = applicationContext; + + } + } + + /** + * 获取applicationContext + * @return + */ + public static ApplicationContext getApplicationContext() { + return applicationContext; + } + + /** + * 通过name获取 Bean. + * @param name + * @return + */ + public static Object getBean(String name){ + ApplicationContext applicationContext = getApplicationContext(); + if(applicationContext == null){ + return null; + } + return applicationContext.getBean(name); + } + + /** + * 通过class获取Bean. + * @param clazz + * @param + * @return + */ + public static T getBean(Class clazz){ + ApplicationContext applicationContext = getApplicationContext(); + if(applicationContext == null){ + return null; + } + return applicationContext.getBean(clazz); + } + + /** + * 通过name,以及Clazz返回指定的Bean + * @param name + * @param clazz + * @param + * @return + */ + public static T getBean(String name,Class clazz){ + ApplicationContext applicationContext = getApplicationContext(); + if(applicationContext == null){ + return null; + } + return applicationContext.getBean(name, clazz); + } +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/third/SmartRedisService.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/third/SmartRedisService.java new file mode 100644 index 00000000..78aa5c32 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/third/SmartRedisService.java @@ -0,0 +1,622 @@ +package com.gangquan360.smartadmin.third; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.*; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +/** + * [ redis 一顿操作 ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/3/26 0026 下午 18:12 + * @since JDK1.8 + */ +@Slf4j +@Component +public class SmartRedisService { + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private ValueOperations redisValueOperations; + + @Autowired + private HashOperations redisHashOperations; + + @Autowired + private ListOperations redisListOperations; + + @Autowired + private SetOperations redisSetOperations; + + /** + * 指定缓存失效时间 + * + * @param key 键 + * @param time 时间(秒) + * @return + */ + public boolean expire(String key, long time) { + try { + if (time > 0) { + redisTemplate.expire(key, time, TimeUnit.SECONDS); + } + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 根据key 获取过期时间 + * + * @param key 键 不能为null + * @return 时间(秒) 返回0代表为永久有效 + */ + public long getExpire(String key) { + return redisTemplate.getExpire(key, TimeUnit.SECONDS); + } + + /** + * 判断key是否存在 + * + * @param key 键 + * @return true 存在 false不存在 + */ + public boolean hasKey(String key) { + try { + return redisTemplate.hasKey(key); + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 删除缓存 + * + * @param key 可以传一个值 或多个 + */ + @SuppressWarnings("unchecked") + public void del(String... key) { + if (key != null && key.length > 0) { + if (key.length == 1) { + redisTemplate.delete(key[0]); + } else { + redisTemplate.delete(CollectionUtils.arrayToList(key)); + } + } + } + + //============================String============================= + + /** + * 普通缓存获取 + * + * @param key 键 + * @return 值 + */ + public String get(String key) { + return key == null ? null : redisValueOperations.get(key); + } + + public T getObject(String key, Class clazz) { + Object json = this.get(key); + if (json == null) { + return null; + } + T obj = JSON.parseObject(json.toString(), clazz); + return obj; + } + + public List getList(String key, Class clz) { + Object json = this.get(key); + if (json == null) { + return Lists.newArrayList(); + } + List list = JSONObject.parseArray(json.toString(), clz); + return list; + } + + /** + * 普通缓存放入 + * + * @param key 键 + * @param value 值 + * @return true成功 false失败 + */ + public boolean set(String key, String value) { + try { + redisValueOperations.set(key, value); + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + + } + + /** + * 普通缓存放入并设置时间 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 + * @return true成功 false 失败 + */ + public boolean set(String key, String value, long time) { + try { + if (time > 0) { + redisValueOperations.set(key, value, time, TimeUnit.SECONDS); + } else { + set(key, value); + } + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 递增 + * + * @param key 键 + * @param delta 要增加几(大于0) + * @return + */ + public long incr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递增因子必须大于0"); + } + return redisValueOperations.increment(key, delta); + } + + /** + * 递减 + * + * @param key 键 + * @param delta 要减少几(小于0) + * @return + */ + public long decr(String key, long delta) { + if (delta < 0) { + throw new RuntimeException("递减因子必须大于0"); + } + return redisValueOperations.increment(key, - delta); + } + + //================================Map================================= + + /** + * HashGet + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return 值 + */ + public Object hget(String key, String item) { + return redisHashOperations.get(key, item); + } + + /** + * 获取hashKey对应的所有键值 + * + * @param key 键 + * @return 对应的多个键值 + */ + public Map hmget(String key) { + return redisHashOperations.entries(key); + } + + /** + * HashSet + * + * @param key 键 + * @param map 对应多个键值 + * @return true 成功 false 失败 + */ + public boolean hmset(String key, Map map) { + try { + redisHashOperations.putAll(key, map); + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * HashSet 并设置时间 + * + * @param key 键 + * @param map 对应多个键值 + * @param time 时间(秒) + * @return true成功 false失败 + */ + public boolean hmset(String key, Map map, long time) { + try { + redisHashOperations.putAll(key, map); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value) { + try { + redisHashOperations.put(key, item, value); + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 向一张hash表中放入数据,如果不存在将创建 + * + * @param key 键 + * @param item 项 + * @param value 值 + * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间 + * @return true 成功 false失败 + */ + public boolean hset(String key, String item, Object value, long time) { + try { + redisHashOperations.put(key, item, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 删除hash表中的值 + * + * @param key 键 不能为null + * @param item 项 可以使多个 不能为null + */ + public void hdel(String key, Object... item) { + redisHashOperations.delete(key, item); + } + + /** + * 判断hash表中是否有该项的值 + * + * @param key 键 不能为null + * @param item 项 不能为null + * @return true 存在 false不存在 + */ + public boolean hHasKey(String key, String item) { + return redisHashOperations.hasKey(key, item); + } + + /** + * hash递增 如果不存在,就会创建一个 并把新增后的值返回 + * + * @param key 键 + * @param item 项 + * @param by 要增加几(大于0) + * @return + */ + public double hincr(String key, String item, double by) { + return redisHashOperations.increment(key, item, by); + } + + /** + * hash递减 + * + * @param key 键 + * @param item 项 + * @param by 要减少记(小于0) + * @return + */ + public double hdecr(String key, String item, double by) { + return redisHashOperations.increment(key, item, - by); + } + + //============================set============================= + + /** + * 根据key获取Set中的所有值 + * + * @param key 键 + * @return + */ + public Set sGet(String key) { + try { + return redisSetOperations.members(key); + } catch (Exception e) { + log.error("", e); + return null; + } + } + + /** + * 根据value从一个set中查询,是否存在 + * + * @param key 键 + * @param value 值 + * @return true 存在 false不存在 + */ + public boolean sHasKey(String key, Object value) { + try { + return redisSetOperations.isMember(key, value); + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 将数据放入set缓存 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSet(String key, Object... values) { + try { + return redisSetOperations.add(key, values); + } catch (Exception e) { + log.error("", e); + return 0; + } + } + + /** + * 将set数据放入缓存 + * + * @param key 键 + * @param time 时间(秒) + * @param values 值 可以是多个 + * @return 成功个数 + */ + public long sSetAndTime(String key, long time, Object... values) { + try { + Long count = redisSetOperations.add(key, values); + if (time > 0) { + expire(key, time); + } + return count; + } catch (Exception e) { + log.error("", e); + return 0; + } + } + + /** + * 获取set缓存的长度 + * + * @param key 键 + * @return + */ + public long sGetSetSize(String key) { + try { + return redisSetOperations.size(key); + } catch (Exception e) { + log.error("", e); + return 0; + } + } + + /** + * 移除值为value的 + * + * @param key 键 + * @param values 值 可以是多个 + * @return 移除的个数 + */ + public long setRemove(String key, Object... values) { + try { + Long count = redisSetOperations.remove(key, values); + return count; + } catch (Exception e) { + log.error("", e); + return 0; + } + } + //===============================list================================= + + /** + * 获取list缓存的内容 + * + * @param key 键 + * @param start 开始 + * @param end 结束 0 到 -1代表所有值 + * @return + */ + public List lGet(String key, long start, long end) { + try { + return redisListOperations.range(key, start, end); + } catch (Exception e) { + log.error("", e); + return null; + } + } + + /** + * 获取list缓存的所有内容 + * + * @param key + * @return + */ + public List lGetAll(String key) { + return lGet(key, 0, - 1); + } + + /** + * 获取list缓存的长度 + * + * @param key 键 + * @return + */ + public long lGetListSize(String key) { + try { + return redisListOperations.size(key); + } catch (Exception e) { + log.error("", e); + return 0; + } + } + + /** + * 通过索引 获取list中的值 + * + * @param key 键 + * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推 + * @return + */ + public Object lGetIndex(String key, long index) { + try { + return redisListOperations.index(key, index); + } catch (Exception e) { + log.error("", e); + return null; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, Object value) { + try { + redisListOperations.rightPush(key, value); + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, Object value, long time) { + try { + redisListOperations.rightPush(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @return + */ + public boolean lSet(String key, List value) { + try { + redisListOperations.rightPushAll(key, value); + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 将list放入缓存 + * + * @param key 键 + * @param value 值 + * @param time 时间(秒) + * @return + */ + public boolean lSet(String key, List value, long time) { + try { + redisListOperations.rightPushAll(key, value); + if (time > 0) { + expire(key, time); + } + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 根据索引修改list中的某条数据 + * + * @param key 键 + * @param index 索引 + * @param value 值 + * @return + */ + public boolean lUpdateIndex(String key, long index, Object value) { + try { + redisListOperations.set(key, index, value); + return true; + } catch (Exception e) { + log.error("", e); + return false; + } + } + + /** + * 移除N个值为value + * + * @param key 键 + * @param count 移除多少个 + * @param value 值 + * @return 移除的个数 + */ + public long lRemove(String key, long count, Object value) { + try { + Long remove = redisListOperations.remove(key, count, value); + return remove; + } catch (Exception e) { + log.error("", e); + return 0; + } + } +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBaseEnumUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBaseEnumUtil.java new file mode 100644 index 00000000..cfed468f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBaseEnumUtil.java @@ -0,0 +1,85 @@ +package com.gangquan360.smartadmin.util; + +import com.gangquan360.smartadmin.common.domain.BaseEnum; + +/** + * 枚举工具类 + * + * @author listen + * @date 2017/10/10 18:17 + */ +public class SmartBaseEnumUtil { + + /** + * 校验int类型的参数与枚举类比较是否合法 + * + * @param value 参数 + * @param enumClass 枚举类必须实现BaseEnum接口 + * @return boolean + * @Author listen + */ + public static boolean checkEnum(Integer value, Class enumClass) { + if (null == value) { + return false; + } + BaseEnum[] enums = enumClass.getEnumConstants(); + for (BaseEnum baseEnum : enums) { + if (baseEnum.equalsValue(value)) { + return true; + } + } + return false; + } + + /** + * 获取枚举类的说明 value : info 的形式 + * + * @param enumClass + * @return String + */ + public static String getEnumDesc(Class enumClass) { + BaseEnum[] enums = enumClass.getEnumConstants(); + // value : info 的形式 + StringBuilder sb = new StringBuilder(); + for (BaseEnum baseEnum : enums) { + sb.append(baseEnum.getValue() + ":" + baseEnum.getDesc() + ","); + } + return sb.toString(); + } + + /** + * 获取与int Code相匹配的枚举类的info + * + * @param value 参数 + * @param enumClass 枚举类必须实现BaseEnum接口 + * @return String 如无匹配枚举则返回null + */ + public static String getEnumDescByValue(Integer value, Class enumClass) { + BaseEnum[] enums = enumClass.getEnumConstants(); + for (BaseEnum baseEnum : enums) { + if (baseEnum.equalsValue(value)) { + return baseEnum.getDesc(); + } + } + return null; + } + + /** + * 根据int类型的参数与获取枚举类的实例 + * + * @param value 参数 + * @param enumClass 枚举类必须实现BaseEnum接口 + * @return BaseEnum 无匹配值返回null + * @Author listen + */ + public static T getEnumByValue(Object value, Class enumClass) { + T[] enums = enumClass.getEnumConstants(); + for (T baseEnum : enums) { + if (baseEnum.equalsValue(value)) { + return baseEnum; + } + } + return null; + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBeanUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBeanUtil.java new file mode 100644 index 00000000..2c2d3701 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBeanUtil.java @@ -0,0 +1,56 @@ +package com.gangquan360.smartadmin.util; + +import org.springframework.beans.BeanUtils; + +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class SmartBeanUtil { + + /** + * 复制bean的属性 + * + * @param source 源 要复制的对象 + * @param target 目标 复制到此对象 + */ + public static void copyProperties(Object source, Object target) { + BeanUtils.copyProperties(source, target); + } + + /** + * 复制对象 + * + * @param source 源 要复制的对象 + * @param target 目标 复制到此对象 + * @param + * @return + */ + public static T copy(Object source, Class target) { + try { + T newInstance = target.newInstance(); + BeanUtils.copyProperties(source, newInstance); + return newInstance; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 复制list + * + * @param source + * @param target + * @param + * @param + * @return + */ + public static List copyList(List source, Class target) { + + if (null == source || source.isEmpty()) { + return Collections.emptyList(); + } + return source.stream().map(e -> copy(e, target)).collect(Collectors.toList()); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBigDecimalUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBigDecimalUtil.java new file mode 100644 index 00000000..0672dc9d --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartBigDecimalUtil.java @@ -0,0 +1,303 @@ +package com.gangquan360.smartadmin.util; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.NumberFormat; + +/** + * 全局 BigDecimal 工具类 + * + * @author listen + * @date 2018/01/17 13:54 + */ +public class SmartBigDecimalUtil { + + /** + * 价格类型 保留小数点 2 + */ + public static final int PRICE_DECIMAL_POINT = 2; + + /** + * 价格类型 保留小数点 6 + */ + public static final int SIX_PRICE_DECIMAL_POINT = 6; + + /** + * 重量类型保留小数点 3 + */ + public static final int WEIGHT_DECIMAL_POINT = 3; + + /** + * 金额相关计算方法:四舍五入 保留2位小数点 + */ + public static class Amount { + + public static BigDecimal add(BigDecimal num1, BigDecimal num2) { + return setScale(num1.add(num2), PRICE_DECIMAL_POINT); + } + public static BigDecimal multiply(BigDecimal num1, BigDecimal num2) { + return setScale(num1.multiply(num2), PRICE_DECIMAL_POINT); + } + public static BigDecimal subtract(BigDecimal num1, BigDecimal num2) { + return setScale(num1.subtract(num2), PRICE_DECIMAL_POINT); + } + public static BigDecimal divide(BigDecimal num1, BigDecimal num2) { + return setScale(num1.divide(num2, RoundingMode.HALF_UP), PRICE_DECIMAL_POINT); + } + } + + /** + * 金额相关计算方法:四舍五入 保留2位小数点 + */ + public static class AmountSix { + + public static BigDecimal add(BigDecimal num1, BigDecimal num2) { + return setScale(num1.add(num2), SIX_PRICE_DECIMAL_POINT); + } + public static BigDecimal multiply(BigDecimal num1, BigDecimal num2) { + return setScale(num1.multiply(num2), SIX_PRICE_DECIMAL_POINT); + } + public static BigDecimal subtract(BigDecimal num1, BigDecimal num2) { + return setScale(num1.subtract(num2), SIX_PRICE_DECIMAL_POINT); + } + public static BigDecimal divide(BigDecimal num1, BigDecimal num2) { + return num1.divide(num2, PRICE_DECIMAL_POINT, RoundingMode.HALF_UP); + } + } + + /** + * 重量相关计算方法:四舍五入 保留3位小数点 + */ + public static class Weight { + + public static BigDecimal add(BigDecimal num1, BigDecimal num2) { + return setScale(num1.add(num2), WEIGHT_DECIMAL_POINT); + } + public static BigDecimal multiply(BigDecimal num1, BigDecimal num2) { + return setScale(num1.multiply(num2), WEIGHT_DECIMAL_POINT); + } + public static BigDecimal subtract(BigDecimal num1, BigDecimal num2) { + return setScale(num1.subtract(num2), WEIGHT_DECIMAL_POINT); + } + public static BigDecimal divide(BigDecimal num1, BigDecimal num2) { + return num1.divide(num2, WEIGHT_DECIMAL_POINT, RoundingMode.HALF_UP); + } + } + + /** + * BigDecimal 加法 num1 + num2 + * 未做非空校验 + * + * @param num1 + * @param num2 + * @param point 请使用BigDecimalUtils.PRICE_DECIMAL_POINT | BigDecimalUtils.WEIGHT_DECIMAL_POINT + * @return BigDecimal + */ + public static BigDecimal add(BigDecimal num1, BigDecimal num2, int point) { + return setScale(num1.add(num2), point); + } + + /** + * BigDecimal 乘法 num1 x num2 + * 未做非空校验 + * + * @param num1 + * @param num2 + * @param point 请使用BigDecimalUtils.PRICE_DECIMAL_POINT | BigDecimalUtils.WEIGHT_DECIMAL_POINT + * @return BigDecimal + */ + public static BigDecimal multiply(BigDecimal num1, BigDecimal num2, int point) { + return setScale(num1.multiply(num2), point); + } + + /** + * BigDecimal 减法 num1 - num2 + * 未做非空校验 + * + * @param num1 + * @param num2 + * @param point 请使用BigDecimalUtils.PRICE_DECIMAL_POINT | BigDecimalUtils.WEIGHT_DECIMAL_POINT + * @return BigDecimal + */ + public static BigDecimal subtract(BigDecimal num1, BigDecimal num2, int point) { + return setScale(num1.subtract(num2), point); + } + + /** + * BigDecimal 除法 num1/num2 + * 未做非空校验 + * + * @param num1 + * @param num2 + * @param point 请使用BigDecimalUtils.PRICE_DECIMAL_POINT | BigDecimalUtils.WEIGHT_DECIMAL_POINT + * @return BigDecimal + */ + public static BigDecimal divide(BigDecimal num1, BigDecimal num2, int point) { + return num1.divide(num2, point, RoundingMode.HALF_UP); + } + + /** + * 设置小数点类型为 四舍五入 + * + * @param num + * @param point + * @return BigDecimal + */ + public static BigDecimal setScale(BigDecimal num, int point) { + return num.setScale(point, RoundingMode.HALF_UP); + } + + /** + * 比较 num1 是否大于 num2 + * + * @param num1 + * @param num2 + * @return boolean + */ + public static boolean isGreaterThan(BigDecimal num1, BigDecimal num2) { + return num1.compareTo(num2) == 1; + } + + /** + * 比较 num1 是否大于等于 num2 + * + * @param num1 + * @param num2 + * @return boolean + */ + public static boolean isGreaterOrEqual(BigDecimal num1, BigDecimal num2) { + return isGreaterThan(num1, num2) || equals(num1, num2); + } + + /** + * 比较 num1 是否小于 num2 + * + * @param num1 + * @param num2 + * @return boolean + */ + public static boolean isLessThan(BigDecimal num1, BigDecimal num2) { + return num1.compareTo(num2) == - 1; + } + + /** + * 比较 num1 是否小于等于 num2 + * + * @param num1 + * @param num2 + * @return boolean + */ + public static boolean isLessOrEqual(BigDecimal num1, BigDecimal num2) { + return isLessThan(num1, num2) || equals(num1, num2); + } + + /** + * 比较 num1 是否等于 num2 + * + * @param num1 + * @param num2 + * @return + */ + public static boolean equals(BigDecimal num1, BigDecimal num2) { + return num1.compareTo(num2) == 0; + } + + /** + * 计算 num1 / num2 的百分比 + * + * @param num1 + * @param num2 + * @return String + */ + public static String getPercentage(BigDecimal num1, BigDecimal num2) { + BigDecimal result = num1.divide(num2, 4, RoundingMode.HALF_UP); + NumberFormat percent = NumberFormat.getPercentInstance(); + percent.setMaximumFractionDigits(2); + return percent.format(result.doubleValue()); + } + + /** + * 计算 num1 / num2 的百分比 + * + * @param num1 + * @param num2 + * @param point 保留几位小数 + * @return String + */ + public static BigDecimal bigDecimalPercent(Integer num1, Integer num2, int point) { + if (num1 == null || num2 == null) { + return BigDecimal.ZERO; + } + if (num2.equals(Integer.valueOf(0))) { + return BigDecimal.ZERO; + } + BigDecimal bigDecimalNum1 = new BigDecimal(num1); + BigDecimal bigDecimalNum2 = new BigDecimal(num2); + return bigDecimalPercent(bigDecimalNum1, bigDecimalNum2, point); + } + + /** + * 计算 num1 / num2 的百分比 + * + * @param num1 + * @param num2 + * @param point 保留几位小数 + * @return String + */ + public static BigDecimal bigDecimalPercent(BigDecimal num1, BigDecimal num2, int point) { + if (num1 == null || num2 == null) { + return BigDecimal.ZERO; + } + if (equals(BigDecimal.ZERO, num2)) { + return BigDecimal.ZERO; + } + BigDecimal percent = num1.divide(num2, point + 2, RoundingMode.HALF_UP); + BigDecimal percent100 = percent.multiply(new BigDecimal(100)).setScale(point); + return percent100; + } + + /** + * 判断num是否为空 或者 零 + * + * @param num + * @return String + */ + public static Boolean isEmpty(BigDecimal num) { + return null == num || equals(BigDecimal.ZERO, num); + } + + /** + * 判断num是否 不等于null 并且不等于零 + * + * @param num + * @return String + */ + public static Boolean isNotEmpty(BigDecimal num) { + return ! isEmpty(num); + } + + /** + * 转换为万 + * + * @param num + * @param point + * @return + */ + public static BigDecimal convertTenThousand(BigDecimal num, int point) { + BigDecimal decimal = num.divide(new BigDecimal(10000), point, RoundingMode.HALF_UP); + return decimal; + } + + /** + * 转换为负数 + * + * @param num + * @return + */ + public static BigDecimal convertToMinusNumber(BigDecimal num) { + if (isLessOrEqual(num, BigDecimal.ZERO)) { + return num; + } + return BigDecimal.ZERO.subtract(num); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartDateUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartDateUtil.java new file mode 100644 index 00000000..28a602b4 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartDateUtil.java @@ -0,0 +1,521 @@ +package com.gangquan360.smartadmin.util; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateUtils; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 线程安全的date工具类 + * + * @author jiaozi + */ +public class SmartDateUtil extends DateUtils { + + private static final ThreadLocal dateFormats = new ThreadLocal() { + @Override + protected DateFormats initialValue() { + return new DateFormats(); + } + }; + + public static final int HOUR_MIN = 60; + + public static final int DAY_MI_SECOND = 24 * 60 * 60 * 1000; + + public static String formatYMD(Date date) { + return dateFormats.get().ymd.format(date); + } + + public static String formatYMDDigital(Date date) { + return dateFormats.get().ymdDigital.format(date); + } + + public static String formatYMDHMSDigital(Date date) { + return dateFormats.get().ymdhmsDigital.format(date); + } + + public static String formatYM(Date date) { + return dateFormats.get().ym.format(date); + } + + public static String formatHMS(Date date) { + return dateFormats.get().hms.format(date); + } + + public static String formatHM(Date date) { + return dateFormats.get().hm.format(date); + } + + public static String formatYMDHM(Date date) { + return dateFormats.get().ymdhm.format(date); + } + + public static String formatYMDHMS(Date date) { + return dateFormats.get().ymdhms.format(date); + } + + public static String formatYMDChinese(Date date) { + return dateFormats.get().ymdChinese.format(date); + } + + public static String formatYMDSlash(Date date) { + return dateFormats.get().ymdSlash.format(date); + } + + public static Date parseYMD(String dateStr) { + return parse(dateFormats.get().ymd, dateStr); + } + + public static Date parseYMDDigital(String dateStr) { + return parse(dateFormats.get().ymdDigital, dateStr); + } + + public static Date parseYMDHMSDigital(String dateStr) { + return parse(dateFormats.get().ymdhmsDigital, dateStr); + } + + public static Date parseformatYMDChinese(String dateStr) { + return parse(dateFormats.get().ymdChinese, dateStr); + } + + public static Date parseYM(String dateStr) { + return parse(dateFormats.get().ym, dateStr); + } + + public static Date parseYMDHMS(String dateStr) { + + return parse(dateFormats.get().ymdhms, dateStr); + } + + public static Date parseYMDHM(String dateStr) { + return parse(dateFormats.get().ymdhm, dateStr); + } + + public static Date parseTodayHMS(String dateStr) { + String today = formatYMD(new Date()); + String todayDateStr = String.format("%s %s", today, dateStr); + return parse(dateFormats.get().ymdhms, todayDateStr); + } + + /** + * 判断当前时间是否在某段时间内 参数不区分先后顺序 + */ + public static boolean isDuringTwoDate(Date date, Date another) { + long dateTime = date.getTime(); + long anotherTime = another.getTime(); + long currentTime = System.currentTimeMillis(); + + if (currentTime > dateTime && currentTime < anotherTime) { + return true; + } else if (currentTime > anotherTime && currentTime < dateTime) { + return true; + } else { + return false; + } + } + + public static Date parse(SimpleDateFormat format, String dateStr) { + try { + Date d = format.parse(dateStr); + Calendar c = Calendar.getInstance(); + c.setTime(d); + int year = c.get(Calendar.YEAR); + if (year >= 1000 && year <= 9999) { + return d; + } else { + return null; + } + } catch (Exception ex) { + return null; + } + } + + public static long daysOffset(Date date1, Date date2) { + date1 = parseYMD(formatYMD(date1)); + date2 = parseYMD(formatYMD(date2)); + return (date1.getTime() - date2.getTime()) / DAY_MI_SECOND; + } + + /** + * 今天是星期几 , 7表示星期日 + * + * @return + */ + public static int getTodayDayOfWeek() { + Calendar now = Calendar.getInstance(); + int dayOfweek = now.get(Calendar.DAY_OF_WEEK); + dayOfweek--; + if (dayOfweek == 0) { + dayOfweek = 7; + } + return dayOfweek; + } + + public static boolean isTodaytDay(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + Calendar todayCalendar = Calendar.getInstance(); + if (calendar.get(Calendar.YEAR) != todayCalendar.get(Calendar.YEAR)) { + return false; + } else if (calendar.get(Calendar.MONTH) != todayCalendar.get(Calendar.MONTH)) { + return false; + } else if (calendar.get(Calendar.DAY_OF_MONTH) != todayCalendar.get(Calendar.DAY_OF_MONTH)) { + return false; + } + return true; + } + + /** + * 设置Calendar的小时、分钟、秒、毫秒 + * + * @param calendar 日历 + * @param hour 小时 + * @param minute 分钟 + * @param second 秒 + * @param milliSecond 毫秒 + */ + public static void setCalender(Calendar calendar, int hour, int minute, int second, int milliSecond) { + calendar.set(Calendar.HOUR_OF_DAY, hour); + calendar.set(Calendar.MINUTE, minute); + calendar.set(Calendar.SECOND, second); + calendar.set(Calendar.MILLISECOND, milliSecond); + } + + /** + * 获取指定天开始时间 + * + * @param date 日期 + * @return 获得该日期的开始 + */ + public static Date getDayBegin(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + setCalender(calendar, 0, 0, 0, 0); + return calendar.getTime(); + } + + /** + * 获取指定天结束时间 + * + * @param date 日期 + * @return 获得该日期的结束 + */ + public static Date getDayEnd(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + setCalender(calendar, 23, 59, 59, 999); + return calendar.getTime(); + } + + /** + * 获取该日期当月第一天 + * + * @param date + * @return + */ + public static Date getMonthBegin(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(getDayBegin(date)); + calendar.set(Calendar.DAY_OF_MONTH, 1); + return calendar.getTime(); + } + + /** + * 获取该日期当月最后一天getAgeByBirthday + * + * @param date + * @return + */ + public static Date getMonthEnd(Date date) { + Calendar calendar = Calendar.getInstance(); + calendar.setTime(getDayEnd(date)); + calendar.add(Calendar.MONTH, 1); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.add(Calendar.DAY_OF_MONTH, - 1); + return calendar.getTime(); + } + + public static String timeDifference(Date endDate) { + Date nowDate = new Date(); + long nd = 1000 * 24 * 60 * 60; + long nh = 1000 * 60 * 60; + long nm = 1000 * 60; + // 获得两个时间的毫秒时间差异 + long diff = nowDate.getTime() - endDate.getTime(); + // 计算差多少天 + long day = diff / nd; + if (day > 0) { + return day + "天前"; + } + // 计算差多少小时 + long hour = diff % nd / nh; + if (hour > 0) { + return hour + "小时前"; + } + // 计算差多少分钟 + long min = diff % nd % nh / nm; + if (min > 0) { + return "1小时内"; + } + return "1小时内"; + } + + /** + * 计算所用时长 + * + * @param startDate + * @param endDate + * @return + */ + public static BigDecimal timeDifferenceMin(Date startDate, Date endDate) { + long nm = 1000 * 60; + // 获得两个时间的毫秒时间差异 + long diff = endDate.getTime() - startDate.getTime(); + BigDecimal min = BigDecimal.valueOf(diff).divide(BigDecimal.valueOf(nm), RoundingMode.HALF_UP); + return min; + } + + /** + * 功能描述: 是否为当天 + * + * @param dateStr yyyy-mm-dd + * @return + * @auther yandanyang + * @date 2018/10/16 0016 下午 17:43 + */ + public static boolean isCurrentDayYMD(String dateStr) { + if (StringUtils.isEmpty(dateStr)) { + return true; + } + String current = SmartDateUtil.formatYMD(new Date()); + if (current.equals(dateStr)) { + return true; + } + return false; + } + + /** + * 功能描述: 是否为当月 + * + * @param dateStr yyyy-mm-dd + * @return + * @auther yandanyang + * @date 2018/10/16 0016 下午 17:43 + */ + public static boolean isCurrentMonthYMD(String dateStr) { + if (StringUtils.isEmpty(dateStr)) { + return true; + } + String queryDate = SmartDateUtil.formatYM(SmartDateUtil.parseYMD(dateStr)); + String current = SmartDateUtil.formatYM(new Date()); + if (current.equals(queryDate)) { + return true; + } + return false; + } + + public static boolean isCurrentMonthYM(String dateStr) { + if (StringUtils.isEmpty(dateStr)) { + return true; + } + String current = SmartDateUtil.formatYM(new Date()); + if (current.equals(dateStr)) { + return true; + } + return false; + } + + /** + * 获取本周的开始时间 + * + * @return + */ + public static Date getBeginDayOfWeek() { + Date date = new Date(); + if (date == null) { + return null; + } + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + int dayofweek = cal.get(Calendar.DAY_OF_WEEK); + if (dayofweek == 1) { + dayofweek += 7; + } + cal.add(Calendar.DATE, 2 - dayofweek); + return getDayBegin(cal.getTime()); + } + + /** + * 获取本周的结束时间 + * + * @return + */ + public static Date getEndDayOfWeek() { + Calendar cal = Calendar.getInstance(); + cal.setTime(getBeginDayOfWeek()); + cal.add(Calendar.DAY_OF_WEEK, 6); + Date weekEndSta = cal.getTime(); + return getDayEnd(weekEndSta); + } + + /** + * 获取两个日期区间的日期(包括这两个日期) + */ + public static List getiIntervalDate(String dateBegin, String dateEnd) { + List dateList = new ArrayList<>(); + Date startDate = SmartDateUtil.parseYMD(dateBegin); + Date endDate = SmartDateUtil.parseYMD(dateEnd); + Calendar cal = Calendar.getInstance(); + cal.setTime(startDate); + dateList.add(dateBegin); + while (cal.getTime().compareTo(endDate) < 0) { + cal.add(Calendar.DAY_OF_MONTH, 1); + dateList.add(SmartDateUtil.formatYMD(cal.getTime())); + } + return dateList; + } + + /** + * 返回某个日期后几天的日期 + * + * @param date + * @param i + * @return + */ + public static Date getNextDay(Date date, int i) { + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + cal.set(Calendar.DATE, cal.get(Calendar.DATE) + i); + return cal.getTime(); + } + + /** + * 返回某个日期前几天的日期 + * + * @param date + * @param i + * @return + */ + public static Date getFrontDay(Date date, int i) { + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + cal.set(Calendar.DATE, cal.get(Calendar.DATE) - i); + return cal.getTime(); + } + + /** + * 获取昨天的开始时间 + * + * @return + */ + public static Date getBeginDayOfYesterday() { + Calendar cal = new GregorianCalendar(); + cal.setTime(getDayBegin(new Date())); + cal.add(Calendar.DAY_OF_MONTH, - 1); + return cal.getTime(); + } + + /** + * 获取昨天的结束时间 + * + * @return + */ + public static Date getEndDayOfYesterDay() { + Calendar cal = new GregorianCalendar(); + cal.setTime(getDayEnd(new Date())); + cal.add(Calendar.DAY_OF_MONTH, - 1); + return cal.getTime(); + } + + public static Integer getDayNumOfMonth(Date date) { + Calendar c = Calendar.getInstance(); + c.setTime(date); + Integer num = c.getActualMaximum(Calendar.DAY_OF_MONTH); + return num; + } + + /** + * 转换日期(格式:年-月-日 时:分--分自定义) + */ + public static String formatYMDH(Date date, String minute) { + String ymdhm = dateFormats.get().ymdh + ":" + minute; + SimpleDateFormat format = new SimpleDateFormat(ymdhm); + return format.format(date); + } + + /** + * 获取几个月后的日期 + */ + public static Date getAfterMonth(Date inputDate, int number) { + Calendar c = Calendar.getInstance();//获得一个日历的实例 + c.setTime(inputDate);//设置日历时间 + c.add(Calendar.MONTH, number);//在日历的月份上增加月 + return c.getTime(); + } + + /** + * 计算当前月有多少天 + */ + public static int getDays(int year, int month) { + int days = 0; + if (month != 2) { + switch (month) { + case 1: + case 3: + case 5: + case 7: + case 8: + case 10: + case 12: + days = 31; + break; + case 4: + case 6: + case 9: + case 11: + days = 30; + + } + } else { + // 闰年 + if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) { + days = 29; + } else { + days = 28; + } + } + System.out.println("当月有" + days + "天!"); + return days; + } + +} + +class DateFormats { + + public final SimpleDateFormat hms = new SimpleDateFormat("HH:mm:ss"); + + public final SimpleDateFormat hm = new SimpleDateFormat("HH:mm"); + + public final SimpleDateFormat ymdhm = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + + public final SimpleDateFormat ymd = new SimpleDateFormat("yyyy-MM-dd"); + + public final SimpleDateFormat ym = new SimpleDateFormat("yyyy-MM"); + + public final SimpleDateFormat ymdhms = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + public final SimpleDateFormat ymdChinese = new SimpleDateFormat("yyyy年MM月dd日"); + + public final SimpleDateFormat ymdSlash = new SimpleDateFormat("yyyy/MM/dd"); + + public final SimpleDateFormat ymdDigital = new SimpleDateFormat("yyyyMMdd"); + + public final SimpleDateFormat ymdhmsDigital = new SimpleDateFormat("yyyyMMddHHmmss"); + + public static final String ymdh = "yyyy-MM-dd HH"; +} + diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartDigestUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartDigestUtil.java new file mode 100644 index 00000000..c36f2a2f --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartDigestUtil.java @@ -0,0 +1,17 @@ +package com.gangquan360.smartadmin.util; + +import org.apache.commons.codec.digest.DigestUtils; + +public class SmartDigestUtil extends DigestUtils { + + /** + * md5加盐加密 + * + * @param salt + * @param password + * @return + */ + public static String encryptPassword(String salt, String password) { + return SmartDigestUtil.md5Hex(String.format(salt, password)); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartHttpUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartHttpUtil.java new file mode 100644 index 00000000..27d62cd0 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartHttpUtil.java @@ -0,0 +1,151 @@ +package com.gangquan360.smartadmin.util; + +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +/** + * [ HttpUtils ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +public class SmartHttpUtil { + + public static String sendGet(String url, Map params, Map header) throws Exception { + HttpGet httpGet = null; + String body = ""; + try { + CloseableHttpClient httpClient = HttpClients.createDefault(); + List mapList = new ArrayList<>(); + if (params != null) { + for (Entry entry : params.entrySet()) { + mapList.add(entry.getKey() + "=" + entry.getValue()); + } + } + if (CollectionUtils.isNotEmpty(mapList)) { + url = url + "?"; + String paramsStr = StringUtils.join(mapList, "&"); + url = url + paramsStr; + } + httpGet = new HttpGet(url); + httpGet.setHeader("Content-type", "application/json; charset=utf-8"); + httpGet.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); + if (header != null) { + for (Entry entry : header.entrySet()) { + httpGet.setHeader(entry.getKey(), entry.getValue()); + } + } + HttpResponse response = httpClient.execute(httpGet); + + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != HttpStatus.SC_OK) { + throw new RuntimeException("请求失败"); + } else { + body = EntityUtils.toString(response.getEntity(), "UTF-8"); + } + } catch (Exception e) { + throw e; + } finally { + if (httpGet != null) { + httpGet.releaseConnection(); + } + } + return body; + } + + public static String sendPostJson(String url, String json, Map header) throws Exception { + HttpPost httpPost = null; + String body = ""; + try { + CloseableHttpClient httpClient = HttpClients.createDefault(); + httpPost = new HttpPost(url); + httpPost.setHeader("Content-type", "application/json; charset=utf-8"); + httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); + if (header != null) { + for (Entry entry : header.entrySet()) { + httpPost.setHeader(entry.getKey(), entry.getValue()); + } + } + StringEntity entity = new StringEntity(json, Charset.forName("UTF-8")); + entity.setContentEncoding("UTF-8"); + entity.setContentType("application/json"); + httpPost.setEntity(entity); + HttpResponse response = httpClient.execute(httpPost); + + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != HttpStatus.SC_OK) { + throw new RuntimeException("请求失败"); + } else { + body = EntityUtils.toString(response.getEntity(), "UTF-8"); + } + } catch (Exception e) { + throw e; + } finally { + if (httpPost != null) { + httpPost.releaseConnection(); + } + } + return body; + } + + public static String sendPostForm(String url, Map params, Map header) throws Exception { + HttpPost httpPost = null; + String body = ""; + try { + CloseableHttpClient httpClient = HttpClients.createDefault(); + httpPost = new HttpPost(url); + httpPost.setHeader("Content-type", "application/x-www-form-urlencoded"); + httpPost.setHeader("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)"); + if (header != null) { + for (Entry entry : header.entrySet()) { + httpPost.setHeader(entry.getKey(), entry.getValue()); + } + } + List nvps = new ArrayList<>(); + if (params != null) { + for (Entry entry : params.entrySet()) { + nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); + } + } + //设置参数到请求对象中 + httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8")); + HttpResponse response = httpClient.execute(httpPost); + + int statusCode = response.getStatusLine().getStatusCode(); + if (statusCode != HttpStatus.SC_OK) { + throw new RuntimeException("请求失败"); + } else { + body = EntityUtils.toString(response.getEntity(), "UTF-8"); + } + } catch (Exception e) { + throw e; + } finally { + if (httpPost != null) { + httpPost.releaseConnection(); + } + } + return body; + } + +} \ No newline at end of file diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartIPUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartIPUtil.java new file mode 100644 index 00000000..f85116b2 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartIPUtil.java @@ -0,0 +1,159 @@ +package com.gangquan360.smartadmin.util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/5/5 0005 下午 15:34 + * @since JDK1.8 + */ +public class SmartIPUtil { + + public static final String IP_URL = "http://ip.taobao.com/service/getIpInfo.php"; + + public static String getLocalHostIP() { + // 本地IP,如果没有配置外网IP则返回它 + String localIp = null; + // 外网IP + String netIp = null; + try { + Enumeration netInterfaces = NetworkInterface.getNetworkInterfaces(); + InetAddress ip = null; + // 是否找到外网IP + boolean finded = false; + while (netInterfaces.hasMoreElements() && ! finded) { + NetworkInterface ni = netInterfaces.nextElement(); + Enumeration address = ni.getInetAddresses(); + while (address.hasMoreElements()) { + ip = address.nextElement(); + // 外网IP + if (! ip.isSiteLocalAddress() && ! ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == - 1) { + netIp = ip.getHostAddress(); + finded = true; + break; + } else if (ip.isSiteLocalAddress() && ! ip.isLoopbackAddress() && ip.getHostAddress().indexOf(":") == - 1) { + // 内网IP + localIp = ip.getHostAddress(); + } + } + } + } catch (SocketException e) { + e.getMessage(); + } + if (netIp != null && ! "".equals(netIp)) { + return netIp; + } else { + return localIp; + } + } + + public static String getRemoteIp(HttpServletRequest request) { + // 获取请求主机IP地址,如果通过代理进来,则透过防火墙获取真实IP地址 + + String ip = getXForwardedForIp(request); + if (ipValid(ip)) { + return realIp(ip); + } + ip = request.getHeader("Proxy-Client-IP"); + if (ipValid(ip)) { + return realIp(ip); + } + ip = request.getHeader("HTTP_CLIENT_IP"); + if (ipValid(ip)) { + return realIp(ip); + } + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + if (ipValid(ip)) { + return realIp(ip); + } + + ip = request.getRemoteAddr(); + return realIp(ip); + } + + private static String getXForwardedForIp(HttpServletRequest request) { + String ip = request.getHeader("x-forwarded-for"); + //ip 无效直接返回 + if (! ipValid(ip)) { + return ""; + } + if (ip.length() > 15) { + String[] ips = ip.split(","); + for (String strIp : ips) { + if (! ("unknown".equalsIgnoreCase(strIp))) { + ip = strIp; + break; + } + } + return ip; + } + return ip; + } + + private static Boolean ipValid(String ip) { + if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) { + return false; + } + return true; + } + + private static String realIp(String ip) { + if (StringUtils.isEmpty(ip)) { + return ""; + } + return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip; + } + + public static String getRemoteLocation(HttpServletRequest request) { + String ip = getRemoteIp(request); + return getIpLocation(ip); + } + + public static String getIpLocation(String ip) { + String location = "未知"; + if (StringUtils.isEmpty(ip)) { + return location; + } + Map param = new HashMap<>(); + param.put("ip", ip); + + try { + String rspStr = SmartHttpUtil.sendGet(IP_URL, param, null); + if (StringUtils.isEmpty(rspStr)) { + return location; + } + JSONObject jsonObject = JSON.parseObject(rspStr); + String data = jsonObject.getString("data"); + JSONObject jsonData = JSON.parseObject(data); + String region = jsonData.getString("region"); + String city = jsonData.getString("city"); + location = region + " " + city; + if (location.contains("内网IP")) { + location = "内网(" + ip + ")"; + } + } catch (Exception e) { + + } + return location; + } + + public static void main(String[] args) { + System.out.printf(getIpLocation("172.16.0.221")); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartPaginationUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartPaginationUtil.java new file mode 100644 index 00000000..6aeed4b0 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartPaginationUtil.java @@ -0,0 +1,86 @@ +package com.gangquan360.smartadmin.util; + +import com.baomidou.mybatisplus.plugins.Page; +import com.gangquan360.smartadmin.common.domain.PageParamDTO; +import com.gangquan360.smartadmin.common.domain.PageResultDTO; +import org.apache.poi.ss.formula.functions.T; + +import java.util.List; + +/** + * 分页工具类 + * + * @author GHQ + * @date 2017-12-23 16:40 + */ + +public class SmartPaginationUtil { + + public static PageResultDTO convert2PageInfoDTO(Page page) { + PageResultDTO result = new PageResultDTO<>(); + result.setPageNum(page.getCurrent()); + result.setPageSize(page.getSize()); + result.setTotal(Long.valueOf(page.getTotal())); + result.setPages(page.getPages()); + result.setList(page.getRecords()); + return result; + } + + public static Page convert2PageQueryInfo(PageParamDTO baseDTO) { + Page page = new Page<>(); + Boolean sort = baseDTO.getSort(); + if (null != sort && SmartStringUtil.isNoneBlank(baseDTO.getOrderByField())) { + page.setAsc(sort); + page.setOrderByField(baseDTO.getOrderByField()); + } + page.setCurrent(baseDTO.getPageNum()); + page.setSize(baseDTO.getPageSize()); + if (null != baseDTO.getSearchCount()) { + page.setSearchCount(baseDTO.getSearchCount()); + } + return page; + } + + /** + * 转换为 PageResultDTO 对象 + * + * @param page + * @param sourceList 原list + * @param targetClazz 目标类 + * @return + * @author yandanyang + * @date 2018年5月16日 下午6:05:28 + */ + public static PageResultDTO convert2PageInfoDTO(Page page, List sourceList, Class targetClazz) { + PageResultDTO pageResultDTO = setPage(page); + List records = SmartBeanUtil.copyList(sourceList, targetClazz); + page.setRecords(records); + pageResultDTO.setList(records); + return pageResultDTO; + } + + /** + * 转换为 PageResultDTO 对象 + * + * @param page + * @param sourceList list + * @return + * @author yandanyang + * @date 2018年5月16日 下午6:05:28 + */ + public static PageResultDTO convert2PageInfoDTO(Page page, List sourceList) { + PageResultDTO pageResultDTO = setPage(page); + page.setRecords(sourceList); + pageResultDTO.setList(sourceList); + return pageResultDTO; + } + + private static PageResultDTO setPage(Page page) { + PageResultDTO pageResultDTO = new PageResultDTO(); + pageResultDTO.setPageNum(page.getCurrent()); + pageResultDTO.setPageSize(page.getSize()); + pageResultDTO.setTotal(Long.valueOf(page.getTotal())); + pageResultDTO.setPages(page.getPages()); + return pageResultDTO; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartQuartzUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartQuartzUtil.java new file mode 100644 index 00000000..7b1506bd --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartQuartzUtil.java @@ -0,0 +1,43 @@ +package com.gangquan360.smartadmin.util; + +import com.gangquan360.smartadmin.module.quartz.constant.QuartzConst; +import org.apache.commons.lang3.StringUtils; +import org.quartz.JobKey; +import org.quartz.TriggerKey; + +/** + * [ ] + * + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2018 1024lab.netInc. All rights reserved. + * @date 2019/4/13 0013 下午 15:16 + * @since JDK1.8 + */ +public class SmartQuartzUtil { + + public static Long getTaskIdByJobKey(JobKey jobKey) { + String name = jobKey.getName(); + return Long.valueOf(StringUtils.replace(name, QuartzConst.JOB_KEY_PREFIX, "")); + } + + public static Integer getTaskIdByTriggerKey(TriggerKey triggerKey) { + String name = triggerKey.getName(); + return Integer.valueOf(StringUtils.replace(name, QuartzConst.TRIGGER_KEY_PREFIX, "")); + } + + /** + * 获取触发器key + */ + public static TriggerKey getTriggerKey(Long taskId) { + return TriggerKey.triggerKey(QuartzConst.TRIGGER_KEY_PREFIX + taskId); + } + + /** + * 获取jobKey + */ + public static JobKey getJobKey(Long taskId) { + return JobKey.jobKey(QuartzConst.JOB_KEY_PREFIX + taskId); + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartRequestTokenUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartRequestTokenUtil.java new file mode 100644 index 00000000..b8f3f39a --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartRequestTokenUtil.java @@ -0,0 +1,51 @@ +package com.gangquan360.smartadmin.util; + +import com.gangquan360.smartadmin.module.login.domain.RequestTokenBO; +import org.springframework.web.context.request.RequestAttributes; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +/** + * @author yandanyang + * @version 1.0 + * @company 1024lab.net + * @copyright (c) 2019 1024lab.netInc. All rights reserved. + * @date + * @since JDK1.8 + */ +public class SmartRequestTokenUtil { + + private static final String USER_KEY = "smart_admin_user"; + + private static ThreadLocal RequestUserThreadLocal = new ThreadLocal(); + + public static void setUser(HttpServletRequest request, RequestTokenBO requestToken) { + request.setAttribute(USER_KEY, requestToken); + RequestUserThreadLocal.set(requestToken); + } + + public static RequestTokenBO getThreadLocalUser() { + return RequestUserThreadLocal.get(); + } + + public static RequestTokenBO getRequestUser() { + RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); + if (requestAttributes != null) { + HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest(); + if (request != null) { + return (RequestTokenBO) request.getAttribute(USER_KEY); + } + } + return null; + } + + public static Long getRequestUserId() { + RequestTokenBO requestUser = getRequestUser(); + if (null == requestUser) { + return null; + } + return requestUser.getRequestUserId(); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartSendMailUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartSendMailUtil.java new file mode 100644 index 00000000..8ff2ed6b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartSendMailUtil.java @@ -0,0 +1,243 @@ +package com.gangquan360.smartadmin.util; + +import lombok.extern.slf4j.Slf4j; + +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; +import javax.mail.Transport; +import javax.mail.internet.*; +import javax.mail.util.ByteArrayDataSource; +import java.io.InputStream; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Properties; +import java.util.regex.Pattern; + +@Slf4j +public class SmartSendMailUtil { + + /** + * 邮箱正则表达式 + */ + static final Pattern pattern = Pattern.compile("^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$"); + + public static void main(String[] args) throws Exception { + // 发件人的 邮箱 和 密码(替换为自己的邮箱和密码) + // PS: 某些邮箱服务器为了增加邮箱本身密码的安全性,给 SMTP 客户端设置了独立密码(有的邮箱称为“授权码”), + // 对于开启了独立密码的邮箱, 这里的邮箱密码必需使用这个独立密码(授权码)。 + String myEmailAccount = "xxxxx@163.com"; + String myEmailPassword = "xxxxxx"; + // 发件人邮箱的 SMTP 服务器地址, 必须准确, 不同邮件服务器地址不同, 一般(只是一般, 绝非绝对)格式为: smtp.xxx.com + // 网易163邮箱的 SMTP 服务器地址为: smtp.163.com + String myEmailSMTPHost = "smtp.163.com"; + // 收件人邮箱(替换为自己知道的有效邮箱) + String[] toMailAccountList = new String[]{"421316927@qq.com"}; + SmartSendMailUtil.sendMail(myEmailAccount, myEmailPassword, "", toMailAccountList, "", myEmailSMTPHost, "测试发送邮件", "测试发送邮件"); + + } + + /** + * 发送文本邮件 + * + * @param sendMail 发件人邮箱 + * @param sendMailPwd 发件人密码 + * @param sendMailName 发件人昵称(可选) + * @param receiveMail 收件人邮箱 + * @param receiveMailName 收件人昵称(可选) + * @param sendSMTPHost 发件人邮箱的 SMTP 服务器地址, 必须准确, 不同邮件服务器地址不同, 一般(只是一般, 绝非绝对)格式为: smtp.xxx.com + * @param title 邮件主题 + * @param content 邮件正文 + * @author Administrator + * @date 2017年12月13日 下午1:51:38 + */ + public static void sendMail(String sendMail, String sendMailPwd, String sendMailName, String[] receiveMail, String receiveMailName, String sendSMTPHost, String title, String content) { + + Session session = createSession(sendSMTPHost); + // 3. 创建一封邮件 + MimeMessage message; + try { + message = createMimeMessage(session, sendMail, sendMailName, receiveMail, receiveMailName, title, content); + // 4. 根据 Session 获取邮件传输对象 + Transport transport = session.getTransport(); + + // 5. 使用 邮箱账号 和 密码 连接邮件服务器, 这里认证的邮箱必须与 message 中的发件人邮箱一致, 否则报错 + // + // PS_01: 成败的判断关键在此一句, 如果连接服务器失败, 都会在控制台输出相应失败原因的 log, + // 仔细查看失败原因, 有些邮箱服务器会返回错误码或查看错误类型的链接, 根据给出的错误 + // 类型到对应邮件服务器的帮助网站上查看具体失败原因。 + // + // PS_02: 连接失败的原因通常为以下几点, 仔细检查代码: + // (1) 邮箱没有开启 SMTP 服务; + // (2) 邮箱密码错误, 例如某些邮箱开启了独立密码; + // (3) 邮箱服务器要求必须要使用 SSL 安全连接; + // (4) 请求过于频繁或其他原因, 被邮件服务器拒绝服务; + // (5) 如果以上几点都确定无误, 到邮件服务器网站查找帮助。 + // + // PS_03: 仔细看log, 认真看log, 看懂log, 错误原因都在log已说明。 + transport.connect(sendMail, sendMailPwd); + // 6. 发送邮件, 发到所有的收件地址, message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人 + transport.sendMessage(message, message.getAllRecipients()); + // 7. 关闭连接 + transport.close(); + } catch (Exception e) { + log.error("", e); + } + + } + + /** + * 发送带附件的邮件 + * + * @param sendMail 发件人邮箱 + * @param sendMailPwd 发件人密码 + * @param sendMailName 发件人昵称(可选) + * @param receiveMail 收件人邮箱 + * @param receiveMailName 收件人昵称(可选) + * @param sendSMTPHost 发件人邮箱的 SMTP 服务器地址, 必须准确, 不同邮件服务器地址不同, 一般(只是一般, 绝非绝对)格式为: smtp.xxx.com + * @param title 邮件主题 + * @param content 邮件正文 + * @author Administrator + * @date 2017年12月13日 下午1:51:38 + */ + public static void sendFileMail(String sendMail, String sendMailPwd, String sendMailName, String[] receiveMail, String receiveMailName, String sendSMTPHost, String title, String content, + InputStream is, String fileName, String port) { + + Session session = createSSLSession(sendSMTPHost, port, sendMailName, sendMailPwd); + // 3. 创建一封邮件 + MimeMessage message; + try { + message = createMimeMessage(session, sendMail, sendMailName, receiveMail, receiveMailName, title, content); + // 5. Content: 邮件正文(可以使用html标签)(内容有广告嫌疑,避免被邮件服务器误认为是滥发广告以至返回失败,请修改发送内容) + MimeMultipart mm = new MimeMultipart(); + MimeBodyPart text = new MimeBodyPart(); + text.setContent(content, "text/html;charset=UTF-8"); + mm.addBodyPart(text); + if (null != is && is.available() > 0) { + MimeBodyPart attachment = new MimeBodyPart(); + DataSource source = new ByteArrayDataSource(is, "application/msexcel"); + // 将附件数据添加到"节点" + attachment.setDataHandler(new DataHandler(source)); + // 设置附件的文件名(需要编码) + attachment.setFileName(MimeUtility.encodeText(fileName)); + // 10. 设置文本和 附件 的关系(合成一个大的混合"节点" / Multipart ) + // 如果有多个附件,可以创建多个多次添加 + mm.addBodyPart(attachment); + } + message.setContent(mm); + message.saveChanges(); + // 4. 根据 Session 获取邮件传输对象 + Transport transport = session.getTransport("smtp"); + transport.connect(sendSMTPHost, sendMail, sendMailPwd); + // // 6. 发送邮件, 发到所有的收件地址, message.getAllRecipients() 获取到的是在创建邮件对象时添加的所有收件人, 抄送人, 密送人 + transport.sendMessage(message, message.getAllRecipients()); + // 7. 关闭连接 + } catch (Exception e) { + log.error("", e); + } + + } + + /** + * 创建session + * + * @author lidoudou + * @date 2019/2/16 14:59 + */ + private static Session createSSLSession(String sendSMTPHost, String port, String userName, String pwd) { + // 1. 创建参数配置, 用于连接邮件服务器的参数配置 + Properties props = new Properties(); // 参数配置 + + props.setProperty("mail.smtp.user", userName); + props.setProperty("mail.smtp.password", pwd); + props.setProperty("mail.smtp.host", sendSMTPHost); + props.setProperty("mail.smtp.port", port); + props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + props.setProperty("mail.smtp.socketFactory.fallback", "false"); + props.setProperty("mail.smtp.socketFactory.port", port); + props.put("mail.smtp.auth", "true"); + + // 2. 根据配置创建会话对象, 用于和邮件服务器交互 + Session session = Session.getDefaultInstance(props, new Authenticator() { + //身份认证 + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(userName, pwd); + } + }); + session.setDebug(true); // 设置为debug模式, 可以查看详细的发送 log + return session; + } + + /** + * 创建session + * + * @author lidoudou + * @date 2019/2/16 14:59 + */ + private static Session createSession(String sendSMTPHost) { + // 1. 创建参数配置, 用于连接邮件服务器的参数配置 + Properties props = new Properties(); // 参数配置 + props.setProperty("mail.transport.protocol", "smtp"); // 使用的协议(JavaMail规范要求) + props.setProperty("mail.smtp.host", sendSMTPHost); // 发件人的邮箱的 SMTP 服务器地址 + props.setProperty("mail.smtp.auth", "true"); // 需要请求认证 + // PS: 某些邮箱服务器要求 SMTP 连接需要使用 SSL 安全认证 (为了提高安全性, 邮箱支持SSL连接, 也可以自己开启), + // 如果无法连接邮件服务器, 仔细查看控制台打印的 log, 如果有有类似 “连接失败, 要求 SSL 安全连接” 等错误, + // 打开下面 /* ... */ 之间的注释代码, 开启 SSL 安全连接。 + /* + * // SMTP 服务器的端口 (非 SSL 连接的端口一般默认为 25, 可以不添加, 如果开启了 SSL 连接, // 需要改为对应邮箱的 SMTP 服务器的端口, + * 具体可查看对应邮箱服务的帮助, // QQ邮箱的SMTP(SLL)端口为465或587, 其他邮箱自行去查看) final String smtpPort = "465"; + * props.setProperty("mail.smtp.port", smtpPort); + * props.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory"); + * props.setProperty("mail.smtp.socketFactory.fallback", "false"); + * props.setProperty("mail.smtp.socketFactory.port", smtpPort); + */ + // 2. 根据配置创建会话对象, 用于和邮件服务器交互 + Session session = Session.getInstance(props); + session.setDebug(true); // 设置为debug模式, 可以查看详细的发送 log + return session; + } + + /** + * 创建一封只包含文本的简单邮件 + * + * @param session 和服务器交互的会话 + * @param sendMail 发件人邮箱 + * @param sendMailName 发件人昵称 + * @param receiveMail 收件人邮箱 + * @param receiveMailName 收件人昵称 + * @param title 邮件主题 + * @param content 邮件正文 + * @return + * @throws Exception + * @author Administrator + * @date 2017年12月13日 下午1:55:45 + */ + public static MimeMessage createMimeMessage(Session session, String sendMail, String sendMailName, String[] receiveMail, String receiveMailName, String title, String content) throws Exception { + // 1. 创建一封邮件 + MimeMessage message = new MimeMessage(session); + // 2. From: 发件人(昵称有广告嫌疑,避免被邮件服务器误认为是滥发广告以至返回失败,请修改昵称) + message.setFrom(new InternetAddress(sendMail, sendMailName, "UTF-8")); + // 3. To: 收件人(可以增加多个收件人、抄送、密送) + List to = new LinkedList<>(); + for (String s : receiveMail) { + if (pattern.matcher(s).matches()) { + to.add(new InternetAddress(s)); + } + } + //Address[] addresses = new Address[]{new InternetAddress(receiveMail),new InternetAddress(receiveMail)}; + message.addRecipients(MimeMessage.RecipientType.TO, to.toArray((new InternetAddress[to.size()]))); + // 4. Subject: 邮件主题(标题有广告嫌疑,避免被邮件服务器误认为是滥发广告以至返回失败,请修改标题) + message.setSubject(title, "UTF-8"); + // 5. Content: 邮件正文(可以使用html标签)(内容有广告嫌疑,避免被邮件服务器误认为是滥发广告以至返回失败,请修改发送内容) + message.setContent(content, "text/html;charset=UTF-8"); + // 6. 设置发件时间 + message.setSentDate(new Date()); + // 7. 保存设置 + message.saveChanges(); + return message; + } +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartStringUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartStringUtil.java new file mode 100644 index 00000000..b3d82d0b --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartStringUtil.java @@ -0,0 +1,311 @@ +package com.gangquan360.smartadmin.util; + +import org.apache.commons.lang3.StringUtils; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * 字符串操作类,包括分割,转换,大写首字母 + * + * @author jiaozi + */ +public class SmartStringUtil extends StringUtils { + + // ===============split ======================= + + public static Set splitConvertToSet(String str, String split) { + if (isEmpty(str)) { + return new HashSet(); + } + String[] splitArr = str.split(split); + HashSet set = new HashSet(splitArr.length); + for (String string : splitArr) { + set.add(string); + } + return set; + } + + public static List splitConvertToList(String str, String split) { + if (isEmpty(str)) { + return new ArrayList(); + } + String[] splitArr = str.split(split); + ArrayList list = new ArrayList(splitArr.length); + for (String string : splitArr) { + list.add(string); + } + return list; + } + + // ===============split Integer======================= + + public static List splitConverToIntList(String str, String split, int defaultVal) { + if (isEmpty(str)) { + return new ArrayList(); + } + String[] strArr = str.split(split); + List list = new ArrayList(strArr.length); + for (int i = 0; i < strArr.length; i++) { + try { + int parseInt = Integer.parseInt(strArr[i]); + list.add(parseInt); + } catch (NumberFormatException e) { + list.add(defaultVal); + continue; + } + } + return list; + } + + public static Set splitConverToIntSet(String str, String split, int defaultVal) { + if (isEmpty(str)) { + return new HashSet(); + } + String[] strArr = str.split(split); + HashSet set = new HashSet(strArr.length); + for (int i = 0; i < strArr.length; i++) { + try { + int parseInt = Integer.parseInt(strArr[i]); + set.add(parseInt); + } catch (NumberFormatException e) { + set.add(defaultVal); + continue; + } + } + return set; + } + + public static Set splitConverToIntSet(String str, String split) { + return splitConverToIntSet(str, split, 0); + } + + public static List splitConverToIntList(String str, String split) { + return splitConverToIntList(str, split, 0); + } + + public static int[] splitConvertToIntArray(String str, String split, int defaultVal) { + if (isEmpty(str)) { + return new int[0]; + } + String[] strArr = str.split(split); + int[] result = new int[strArr.length]; + for (int i = 0; i < strArr.length; i++) { + try { + result[i] = Integer.parseInt(strArr[i]); + } catch (NumberFormatException e) { + result[i] = defaultVal; + continue; + } + } + return result; + } + + public static int[] splitConvertToIntArray(String str, String split) { + return splitConvertToIntArray(str, split, 0); + } + + // ===============split 2 Long======================= + + public static List splitConverToLongList(String str, String split, long defaultVal) { + if (isEmpty(str)) { + return new ArrayList(); + } + String[] strArr = str.split(split); + List list = new ArrayList(strArr.length); + for (int i = 0; i < strArr.length; i++) { + try { + long parseLong = Long.parseLong(strArr[i]); + list.add(parseLong); + } catch (NumberFormatException e) { + list.add(defaultVal); + continue; + } + } + return list; + } + + public static List splitConverToLongList(String str, String split) { + return splitConverToLongList(str, split, 0L); + } + + public static long[] splitConvertToLongArray(String str, String split, long defaultVal) { + if (isEmpty(str)) { + return new long[0]; + } + String[] strArr = str.split(split); + long[] result = new long[strArr.length]; + for (int i = 0; i < strArr.length; i++) { + try { + result[i] = Long.parseLong(strArr[i]); + } catch (NumberFormatException e) { + result[i] = defaultVal; + continue; + } + } + return result; + } + + public static long[] splitConvertToLongArray(String str, String split) { + return splitConvertToLongArray(str, split, 0L); + } + + // ===============split convert byte======================= + + public static List splitConverToByteList(String str, String split, byte defaultVal) { + if (isEmpty(str)) { + return new ArrayList(); + } + String[] strArr = str.split(split); + List list = new ArrayList(strArr.length); + for (int i = 0; i < strArr.length; i++) { + try { + byte parseByte = Byte.parseByte(strArr[i]); + list.add(parseByte); + } catch (NumberFormatException e) { + list.add(defaultVal); + continue; + } + } + return list; + } + + public static List splitConverToByteList(String str, String split) { + return splitConverToByteList(str, split, (byte) 0); + } + + public static byte[] splitConvertToByteArray(String str, String split, byte defaultVal) { + if (isEmpty(str)) { + return new byte[0]; + } + String[] strArr = str.split(split); + byte[] result = new byte[strArr.length]; + for (int i = 0; i < strArr.length; i++) { + try { + result[i] = Byte.parseByte(strArr[i]); + } catch (NumberFormatException e) { + result[i] = defaultVal; + continue; + } + } + return result; + } + + public static byte[] splitConvertToByteArray(String str, String split) { + return splitConvertToByteArray(str, split, (byte) 0); + } + + // ===============split convert double======================= + + public static List splitConverToDoubleList(String str, String split, double defaultVal) { + if (isEmpty(str)) { + return new ArrayList(); + } + String[] strArr = str.split(split); + List list = new ArrayList(strArr.length); + for (int i = 0; i < strArr.length; i++) { + try { + double parseByte = Double.parseDouble(strArr[i]); + list.add(parseByte); + } catch (NumberFormatException e) { + list.add(defaultVal); + continue; + } + } + return list; + } + + public static List splitConverToDoubleList(String str, String split) { + return splitConverToDoubleList(str, split, 0); + } + + public static double[] splitConvertToDoubleArray(String str, String split, double defaultVal) { + if (isEmpty(str)) { + return new double[0]; + } + String[] strArr = str.split(split); + double[] result = new double[strArr.length]; + for (int i = 0; i < strArr.length; i++) { + try { + result[i] = Double.parseDouble(strArr[i]); + } catch (NumberFormatException e) { + result[i] = defaultVal; + continue; + } + } + return result; + } + + public static double[] splitConvertToDoubleArray(String str, String split) { + return splitConvertToDoubleArray(str, split, 0); + } + + // ===============solit convert float======================= + + public static List splitConverToFloatList(String str, String split, float defaultVal) { + if (isEmpty(str)) { + return new ArrayList(); + } + String[] strArr = str.split(split); + List list = new ArrayList(strArr.length); + for (int i = 0; i < strArr.length; i++) { + try { + float parseByte = Float.parseFloat(strArr[i]); + list.add(parseByte); + } catch (NumberFormatException e) { + list.add(defaultVal); + continue; + } + } + return list; + } + + public static List splitConverToFloatList(String str, String split) { + return splitConverToFloatList(str, split, 0f); + } + + public static float[] splitConvertToFloatArray(String str, String split, float defaultVal) { + if (isEmpty(str)) { + return new float[0]; + } + String[] strArr = str.split(split); + float[] result = new float[strArr.length]; + for (int i = 0; i < strArr.length; i++) { + try { + result[i] = Float.parseFloat(strArr[i]); + } catch (NumberFormatException e) { + result[i] = defaultVal; + continue; + } + } + return result; + } + + public static float[] splitConvertToFloatArray(String str, String split) { + return splitConvertToFloatArray(str, split, 0f); + } + + // ===============upperCase======================= + + /** + * 将首字母大写 + * + * @param str + * @return + */ + public static String upperCaseFirstChar(String str) { + if (str == null || str.isEmpty()) { + return str; + } + char firstChar = str.charAt(0); + if (Character.isUpperCase(firstChar)) { + return str; + } + char[] values = str.toCharArray(); + values[0] = Character.toUpperCase(firstChar); + return new String(values); + } + +} diff --git a/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartThreadFactory.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartThreadFactory.java new file mode 100644 index 00000000..a6b34c25 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartThreadFactory.java @@ -0,0 +1,44 @@ +package com.gangquan360.smartadmin.util; + +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * 拥有自己的thread facotry是为了jstack时候能看到是哪个线程 + * + * @author jiaozi + */ +public class SmartThreadFactory implements ThreadFactory { + + public static SmartThreadFactory create(String namePrefix) { + return new SmartThreadFactory(namePrefix); + } + + private final AtomicInteger poolNumber = new AtomicInteger(1); + + private final ThreadGroup group; + + private final AtomicInteger threadNumber = new AtomicInteger(1); + + private final String namePrefix; + + private SmartThreadFactory(String namePrefix) { + SecurityManager s = System.getSecurityManager(); + group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); + this.namePrefix = namePrefix + " pool " + poolNumber.getAndIncrement() + "-thread-"; + } + + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(group, r, namePrefix + 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/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartVerificationUtil.java b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartVerificationUtil.java new file mode 100644 index 00000000..76b6f879 --- /dev/null +++ b/java/smart-admin-api/src/main/java/com/gangquan360/smartadmin/util/SmartVerificationUtil.java @@ -0,0 +1,95 @@ +package com.gangquan360.smartadmin.util; + +import java.util.regex.Pattern; +/** + * 验证工具类 + * + * @author listen + * @date 2017/11/06 10:54 + */ +public class SmartVerificationUtil { + + + + /** + * 手机号码验证规则 + */ + public static final String PHONE_REGEXP = "^1[0-9]{10}"; + + /** + * 固定号码验证规则 + */ + public static final String FIXED_PHONE_REGEXP = "^0\\d{2,3}-[1-9]\\d{6,7}$"; + + /** + * 密码正则校验 + */ + public static final String PWD_REGEXP = "^[A-Za-z0-9.]{6,15}$"; + + /** + * 车牌号 + */ + public static final String CAR_NUMBER = + "([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼]{1}(([A-HJ-Z]{1}[A-HJ-NP-Z0-9]{5})|([A-HJ-Z]{1}(([DF]{1}[A-HJ-NP-Z0-9]{1}[0-9]{4})|([0-9]{5}[DF]{1})))|" + "([A-HJ-Z" + "]{1}[A-D0-9]{1}[0-9]{3}警)))|" + + "([0-9]{6}使)|((([沪粤川云桂鄂陕蒙藏黑辽渝]{1}A)|鲁B|闽D|蒙E|蒙H)[0-9]{4}领)|(WJ[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼·•]{1}[0-9]{4}[TDSHBXJ0-9]{1})|" + "([VKHBSLJNGCE]{1}[A-DJ-PR" + "-TVY]{1}[0-9]{5})"; + + /** + * 日期年月日校验 yyyy-MM-dd HH:mm:ss + */ + public static final String DATE_TIME = "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9" + + "]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$"; + + /** + * 日期校验 yyyy-MM-dd + */ + public static final String DATE = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))" + + "|(02-(0[1-9]|[1][0-9]|2[0-8])))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)" + "([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9" + + "][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|(" + "(([0-9]{2})(0[48]|[2468][048]|[13579][26])|(" + "(0[48" + "]|[2468][048]|[3579][26])00))-02-29)"; + + /** + * 年月校验 例: 2019-10 + */ + public static final String YEAR_MONTH = "^\\d{4}-((0([1-9]))|(1(0|1|2)))$"; + + + /** + * 时间区间验证 10:23-19:00 + */ + public static final String TIME_SECTION= "^(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9])-(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9])$"; + + /** + * 时间验证 10:23 + */ + public static final String TIME = "^(0[0-9]|1[0-9]|2[0-3]):(0[0-9]|[1-5][0-9])$"; + + /** + * 身份证号 + */ + public static final String ID_CARD = "(^\\d{15}$)|(^\\d{18}$)|(^\\d{17}(\\d|X|x)$)"; + + /** + * URL + */ + public static final String URL = "[a-zA-z]+://[^\\s]*"; + + /** + * 邮箱 + */ + public static final String EMAIL = "[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[\\w](?:[\\w-]*[\\w])?"; + + /** + * 整数 + */ + public static final String INTEGER = "^-?[1-9]\\d*$"; + + /** + * 小数 + */ + public static final String DOUBLE = "^-?[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*$"; + + + public static void main(String[] args) { + boolean matches = Pattern.matches(INTEGER, "1"); + System.out.println(matches); + } +} diff --git a/java/smart-admin-api/src/main/resources/banner.txt b/java/smart-admin-api/src/main/resources/banner.txt new file mode 100644 index 00000000..cd18d69c --- /dev/null +++ b/java/smart-admin-api/src/main/resources/banner.txt @@ -0,0 +1,8 @@ + / ____| | | /\ | | (_) +| (___ _ __ ___ __ _ _ __| |_ / \ __| |_ __ ___ _ _ __ + \___ \| '_ ` _ \ / _` | '__| __| / /\ \ / _` | '_ ` _ \| | '_ \ + ____) | | | | | | (_| | | | |_ / ____ \ (_| | | | | | | | | | | +|_____/|_| |_| |_|\__,_|_| \__/_/ \_\__,_|_| |_| |_|_|_| |_| + +SmartAdmin v1.0.0 + diff --git a/java/smart-admin-api/src/main/resources/dev/application.properties b/java/smart-admin-api/src/main/resources/dev/application.properties new file mode 100644 index 00000000..ad34ca04 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/dev/application.properties @@ -0,0 +1,122 @@ +######################### server ################### +server.servlet.context-path=/smart-admin-api +server.port=10086 +spring.profiles.active=dev + +######################### tomcat ################### +server.tomcat.basedir=/home/logs/smartadmin/tomcat-logs +server.tomcat.accesslog.enabled=true +server.tomcat.accesslog.pattern=%t %{X-Forwarded-For}i %a "%r" %s %D (%D ms) + +######################### jackson ######################### +spring.jackson.serialization.write-enums-using-to-string=true +spring.jackson.deserialization.read-enums-using-to-string=true +spring.jackson.deserialization.fail-on-unknown-properties=false +spring.jackson.default-property-inclusion=always +spring.jackson.date-format=yyyy-MM-dd HH:mm:ss +spring.jackson.time-zone=GMT+8 +spring.jackson.serialization.write-dates-as-timestamps=false + +######################### http file ######################### +spring.servlet.multipart.max-file-size=30MB +spring.servlet.multipart.max-request-size=30MB +file-upload-service.path=/home/upload/ +file-upload-service.geturl=http://172.16.0.145/smartAdmin/file/ + +######################### database ######################### +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/smart-admin-dev?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC +spring.datasource.username=erp +spring.datasource.password=listen1015 +spring.datasource.initial-size=2 +spring.datasource.min-idle=1 +spring.datasource.max-active=10 +spring.datasource.max-wait=60000 +spring.datasource.time-between-eviction-runs-millis=60000 +spring.datasource.min-evictable-edle-time-millis=300000 +spring.datasource.driver-class-name=com.mysql.jdbc.Driver +spring.datasource.filters=stat +spring.datasource.druid.username=druid +spring.datasource.druid.password=Gq123456 +spring.datasource.druid.login.enabled=false + +######################### redis ####################################### +spring.redis.database=13 +spring.redis.host=172.16.0.145 +spring.redis.jedis.pool.max-active=100 +spring.redis.jedis.pool.min-idle=5 +spring.redis.jedis.pool.max-idle=10 +spring.redis.jedis.pool.max-wait=30000ms +spring.redis.port=50000 +spring.redis.timeout=10000ms +spring.redis.password= + +########################## rest http pool ######################### +#\u6700\u5927\u8FDE\u63A5\u6570 +http.pool.max-total=100 +#\u5355\u8DEF\u7531\u6700\u5927\u8FDE\u63A5\u6570 +http.pool.default-max-per-route=25 +#\u670D\u52A1\u5668\u8FD4\u56DE\u6570\u636E(response)\u7684\u65F6\u95F4 +http.pool.socket-timeout=8000 +#\u8FDE\u63A5\u4E0A\u670D\u52A1\u5668(\u63E1\u624B\u6210\u529F)\u7684\u65F6\u95F4 +http.pool.connect-timeout=8000 +#\u4ECE\u8FDE\u63A5\u6C60\u4E2D\u83B7\u53D6\u8FDE\u63A5\u7684\u8D85\u65F6\u65F6\u95F4 +http.pool.connection-request-timeout=8000 + +######################### mybatis\u914D\u7F6E ######################### +mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl +# mybatis-plus \u5B57\u6BB5\u9A7C\u5CF0\u81EA\u52A8\u8F6C\u6362 +mybatis-plus.configuration.map-underscore-to-camel-case=true +mybatis-plus.mapper-locations=classpath:/mapper/*Mapper.xml,/mapper/*/*Mapper.xml +mybatis-plus.typeAliasesPackage=com.gangquan360.smartadmin.*.*.domain.entity +mybatis-plus.global-config.refresh-mapper=true +mybatis-plus.global-config.db-column-underline=true + +######################### swagger ######################### +swagger.apiGroupName=smartAdmin +swagger.title=smartAdmin +swagger.description=smartAdmin +swagger.version=1.0 +swagger.serviceUrl=http://localhost:10086/smart-admin-api +swagger.packAge=com.gangquan360.smartadmin.module + +######################### jwt ######################### +jwt.key=smart-admin-jwt-key + +########################## smart reload ######################### +smart-reload.thread-count=1 +smart-reload.time-interval=5 + +######################### cros ######################### +access-control-allow-origin=* + +######################### heart beat ######################### +heart-beat.delayHandlerTime=60000 +heart-beat.intervalTime=180000 + +######################### quartz ############################# +#\u8C03\u5EA6\u6807\u8BC6\u540D \u96C6\u7FA4\u4E2D\u6BCF\u4E00\u4E2A\u5B9E\u4F8B\u90FD\u5FC5\u987B\u4F7F\u7528\u76F8\u540C\u7684\u540D\u79F0 +spring.quartz.properties.org.quartz.scheduler.instanceName=devClusteredScheduler +spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO +#\u8FDC\u7A0B\u7BA1\u7406\u76F8\u5173\u7684\u914D\u7F6E,\u5168\u90E8\u5173\u95ED +spring.quartz.properties.org.quartz.scheduler.rmi.export=false +spring.quartz.properties.org.quartz.scheduler.rmi.proxy=false +#\u8DF3\u8FC7quartz\u7248\u672C\u68C0\u67E5 +spring.quartz.properties.org.quartz.scheduler.skipUpdateCheck=true +#\u6570\u636E\u4FDD\u5B58\u65B9\u5F0F\u4E3A\u6301\u4E45\u5316 +spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX +spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate +spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_ +spring.quartz.properties.org.quartz.jobStore.isClustered=true +#\u8C03\u5EA6\u5B9E\u4F8B\u5931\u6548\u7684\u68C0\u67E5\u65F6\u95F4\u95F4\u9694 +spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=10000 +spring.quartz.properties.org.quartz.jobStore.useProperties=false +#\u8C03\u5EA6\u7EBF\u7A0B +spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool +spring.quartz.properties.org.quartz.threadPool.threadCount=2 +spring.quartz.properties.org.quartz.threadPool.threadPriority=5 +spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true +spring.quartz.properties.org.quartz.threadPool.threadNamePrefix=quartz +spring.quartz.job-store-type=jdbc +#ALWAYS,EMBEDDED,NEVER +spring.quartz.jdbc.initialize-schema=NEVER +spring.quartz.jdbc.schema=classpath:sql/quartz_mysql_2.3.0.sql diff --git a/java/smart-admin-api/src/main/resources/dev/log4j2.xml b/java/smart-admin-api/src/main/resources/dev/log4j2.xml new file mode 100644 index 00000000..86c514a3 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/dev/log4j2.xml @@ -0,0 +1,97 @@ + + + + + /home/logs/smart-admin/dev/logs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/codegenerator/TableMapper.xml b/java/smart-admin-api/src/main/resources/mapper/codegenerator/TableMapper.xml new file mode 100644 index 00000000..13be97b7 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/codegenerator/TableMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/datascope/DataScopeRoleMapper.xml b/java/smart-admin-api/src/main/resources/mapper/datascope/DataScopeRoleMapper.xml new file mode 100644 index 00000000..84d4d0b1 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/datascope/DataScopeRoleMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + DELETE FROM t_role_data_scope + WHERE role_id = #{roleId} + + + + INSERT INTO t_role_data_scope (data_scope_type,view_type,role_id,update_time,create_time) VALUES + + ( + #{item.dataScopeType}, + #{item.viewType}, + #{item.roleId}, + now(), + now() + ) + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/department/DepartmentMapper.xml b/java/smart-admin-api/src/main/resources/mapper/department/DepartmentMapper.xml new file mode 100644 index 00000000..19904e31 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/department/DepartmentMapper.xml @@ -0,0 +1,54 @@ + + + + + + + + + + d.id, + d.name, + d.short_name, + d.manager_id, + d.parent_id, + d.sort, + d.update_time, + d.create_time + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/email/EmailMapper.xml b/java/smart-admin-api/src/main/resources/mapper/email/EmailMapper.xml new file mode 100644 index 00000000..fcfb0813 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/email/EmailMapper.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + delete from t_email where id = #{id} + + + + delete from t_email where id in + + #{item} + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/employee/EmployeeMapper.xml b/java/smart-admin-api/src/main/resources/mapper/employee/EmployeeMapper.xml new file mode 100644 index 00000000..79f48c02 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/employee/EmployeeMapper.xml @@ -0,0 +1,183 @@ + + + + + + + + + + + e.id, + e.login_name, + e.login_pwd, + e.actual_name, + e.nick_name, + e.phone, + e.id_card, + e.birthday, + e.email, + e.department_id, + e.is_leave, + e.is_disabled, + e.remark, + e.is_delete, + e.update_time, + e.create_time + + + + + + + UPDATE t_employee e + set e.is_disabled = #{isDisabled} + WHERE id in + + #{item} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE t_employee + SET login_pwd = #{password} + WHERE id = #{employeeId} + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/file/FileMapper.xml b/java/smart-admin-api/src/main/resources/mapper/file/FileMapper.xml new file mode 100644 index 00000000..9b4a32ef --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/file/FileMapper.xml @@ -0,0 +1,100 @@ + + + + + + + + + + INSERT INTO t_file ( + module_id, + module_type, + file_name, + file_size, + file_type, + file_path, + creater_user, + file_location_type + ) + VALUES + + (#{item.moduleId},#{item.moduleType},#{item.fileName},#{item.fileSize},#{item.fileType},#{item.filePath},#{item.createrUser},#{item.createrUserType},#{item.fileLocationType}) + + + + + INSERT INTO t_file ( + module_id, + module_type, + file_name, + file_size, + file_type, + file_path, + creater_user, + file_location_type + ) + VALUES + + (#{item.moduleId},#{item.moduleType},#{item.fileName},#{item.fileSize},#{item.fileType},#{item.filePath},#{item.createrUser},#{item.createrUserType},#{item.fileLocationType}) + + + + + DELETE FROM t_file WHERE module_id =#{moduleId} + + + + DELETE FROM t_file WHERE module_id =#{moduleId} and module_type=#{moduleType} + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/heartbeat/HeartBeatRecordMapper.xml b/java/smart-admin-api/src/main/resources/mapper/heartbeat/HeartBeatRecordMapper.xml new file mode 100644 index 00000000..97b8521d --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/heartbeat/HeartBeatRecordMapper.xml @@ -0,0 +1,41 @@ + + + + + + + INSERT INTO t_heart_beat_record ( + project_path, + server_ip, + process_no, + process_start_time, + heart_beat_time + ) + VALUES + (#{projectPath}, + #{serverIp}, + #{processNo}, + #{processStartTime}, + #{heartBeatTime}) + + + + update t_heart_beat_record + set heart_beat_time = #{heartBeatTime} + + id = #{id} + + + + + + + diff --git a/java/smart-admin-api/src/main/resources/mapper/idgenerator/IdGeneratorMapper.xml b/java/smart-admin-api/src/main/resources/mapper/idgenerator/IdGeneratorMapper.xml new file mode 100644 index 00000000..55ad8557 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/idgenerator/IdGeneratorMapper.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + update t_id_generator set last_number = #{lastNumber}, update_time = now() where id = #{generatorId} + + + + replace into `t_id_generator_record` (`generator_id`, `year`, `month`, `day`, `last_number`) values (#{generatorId}, #{year}, #{month}, #{day}, #{lastNumber}) + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/log/OrderOperateLogMapper.xml b/java/smart-admin-api/src/main/resources/mapper/log/OrderOperateLogMapper.xml new file mode 100644 index 00000000..3ed401bb --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/log/OrderOperateLogMapper.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + INSERT INTO t_order_operate_log (order_id,order_type, operate_type, operate_content, operate_remark, employee_id, employee_name,ext_data,update_time,create_time) VALUES + + (#{item.orderId}, + #{item.orderType}, + #{item.operateType}, + #{item.operateContent}, + #{item.operateRemark}, + #{item.employeeId}, + #{item.employeeName}, + #{item.extData}, + #{item.updateTime} + #{item.createTime} + ) + + + + + diff --git a/java/smart-admin-api/src/main/resources/mapper/log/UserLoginLogMapper.xml b/java/smart-admin-api/src/main/resources/mapper/log/UserLoginLogMapper.xml new file mode 100644 index 00000000..f97f4853 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/log/UserLoginLogMapper.xml @@ -0,0 +1,46 @@ + + + + + + + + + + + delete from t_user_login_log where id = #{id} + + + + delete from t_user_login_log where id in + + #{item} + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/log/UserOperateLogMapper.xml b/java/smart-admin-api/src/main/resources/mapper/log/UserOperateLogMapper.xml new file mode 100644 index 00000000..c84d3a5a --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/log/UserOperateLogMapper.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + delete from t_user_operate_log where id = #{id} + + + + delete from t_user_operate_log where id in + + #{item} + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/notice/NoticeMapper.xml b/java/smart-admin-api/src/main/resources/mapper/notice/NoticeMapper.xml new file mode 100644 index 00000000..dd9e50e8 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/notice/NoticeMapper.xml @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UPDATE t_notice + set deleted = #{deletedFlag} + WHERE id =#{id} + + + + + UPDATE t_notice set deleted = #{deletedFlag} where id in + + #{item} + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/notice/NoticeReceiveRecordMapper.xml b/java/smart-admin-api/src/main/resources/mapper/notice/NoticeReceiveRecordMapper.xml new file mode 100644 index 00000000..cee64902 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/notice/NoticeReceiveRecordMapper.xml @@ -0,0 +1,39 @@ + + + + + + + + + delete from t_notice_receive_record where notice_id = #{noticeId} + + + + INSERT INTO t_notice_receive_record (notice_id, employee_id, update_time, create_time) VALUES + + ( + #{item.noticeId}, + #{item.employeeId}, + now(), + now() + ) + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/position/PositionMapper.xml b/java/smart-admin-api/src/main/resources/mapper/position/PositionMapper.xml new file mode 100644 index 00000000..cfb7792d --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/position/PositionMapper.xml @@ -0,0 +1,59 @@ + + + + + + + id, + position_name, + remark, + update_time, + create_time + + + + + + + + INSERT INTO t_position_relation (position_id,employee_id) VALUES + + (#{item},#{batchDTO.employeeId}) + + + + + + DELETE FROM t_position_relation WHERE employee_id = #{employeeId} + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/privilege/PrivilegeMapper.xml b/java/smart-admin-api/src/main/resources/mapper/privilege/PrivilegeMapper.xml new file mode 100644 index 00000000..896e1282 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/privilege/PrivilegeMapper.xml @@ -0,0 +1,111 @@ + + + + + + + + p.id, + p.type, + p.name, + p.key, + p.url, + p.sort, + p.parent_key, + p.update_time, + p.create_time + + + + + + + + + + DELETE FROM t_privilege + WHERE `key` IN + + #{item} + + + + + DELETE FROM t_privilege + WHERE parent_key IN + + #{item} + + + + + INSERT INTO t_privilege (`type`, `name`, `key`,url,sort,parent_key,create_time,update_time) VALUES + + ( + #{item.type}, + #{item.name}, + #{item.key}, + #{item.url}, + #{item.sort}, + #{item.parentKey}, + now(), + now() + ) + + + + + + UPDATE t_privilege + SET `type`=#{item.type},`name`=#{item.name},url=#{item.url},sort=#{item.sort},parent_key=#{item.parentKey},update_time=now() + WHERE `key` = #{item.key} + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/quartz/QuartzTaskLogMapper.xml b/java/smart-admin-api/src/main/resources/mapper/quartz/QuartzTaskLogMapper.xml new file mode 100644 index 00000000..570a8053 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/quartz/QuartzTaskLogMapper.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + tl.id, + tl.task_id, + tl.task_name, + tl.task_params, + tl.process_status, + tl.process_duration, + tl.process_log, + tl.ip_address, + tl.update_time, + tl.create_time + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/quartz/QuartzTaskMapper.xml b/java/smart-admin-api/src/main/resources/mapper/quartz/QuartzTaskMapper.xml new file mode 100644 index 00000000..8701f6d5 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/quartz/QuartzTaskMapper.xml @@ -0,0 +1,36 @@ + + + + + + + + t.id, + t.task_name, + t.task_bean, + t.task_params, + t.task_cron, + t.task_status, + t.remark, + t.update_time, + t.create_time + + + + + + + + UPDATE t_quartz_task t + set t.task_status = #{taskStatus} + WHERE t.id = #{taskId} + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/role/RoleEmployeeMapper.xml b/java/smart-admin-api/src/main/resources/mapper/role/RoleEmployeeMapper.xml new file mode 100644 index 00000000..7d60225a --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/role/RoleEmployeeMapper.xml @@ -0,0 +1,124 @@ + + + + + + + + + + er.id, + er.role_id, + er.employee_id, + er.update_time, + er.create_time + + + + + + + + + + + + + DELETE FROM t_role_employee + WHERE employee_id = #{employeeId} + + + + + DELETE FROM t_role_employee + WHERE role_id = #{roleId} + + + + DELETE FROM t_role_employee + WHERE role_id = #{roleId} and employee_id = #{employeeId} + + + + + DELETE FROM t_role_employee + WHERE role_id = #{roleId} and employee_id in + + #{item} + + + + + INSERT INTO t_role_employee (role_id, employee_id, update_time, create_time) VALUES + + ( + #{item.roleId}, + #{item.employeeId}, + now(), + now() + ) + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/role/RoleMapper.xml b/java/smart-admin-api/src/main/resources/mapper/role/RoleMapper.xml new file mode 100644 index 00000000..7c791e2f --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/role/RoleMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + r.id, + r.role_name, + r.remark, + r.update_time, + r.create_time + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/role/RolePrivilegeMapper.xml b/java/smart-admin-api/src/main/resources/mapper/role/RolePrivilegeMapper.xml new file mode 100644 index 00000000..b9f2cb83 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/role/RolePrivilegeMapper.xml @@ -0,0 +1,72 @@ + + + + + + + + + + rp.id, + rp.role_id, + rp.privilege_key, + rp.update_time, + rp.create_time + + + + + DELETE FROM t_role_privilege + WHERE role_id = #{roleId} + + + + DELETE FROM t_role_privilege + WHERE privilege_key in + + #{item} + + + + + + INSERT INTO t_role_privilege (role_id, privilege_key, update_time, create_time) VALUES + + ( + #{item.roleId}, + #{item.privilegeKey}, + now(), + now() + ) + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/smartreload/ReloadItemMapper.xml b/java/smart-admin-api/src/main/resources/mapper/smartreload/ReloadItemMapper.xml new file mode 100644 index 00000000..f9106a5b --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/smartreload/ReloadItemMapper.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/smartreload/ReloadResultMapper.xml b/java/smart-admin-api/src/main/resources/mapper/smartreload/ReloadResultMapper.xml new file mode 100644 index 00000000..864d93ad --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/smartreload/ReloadResultMapper.xml @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/mapper/systemconfig/SystemConfigMapper.xml b/java/smart-admin-api/src/main/resources/mapper/systemconfig/SystemConfigMapper.xml new file mode 100644 index 00000000..6604274c --- /dev/null +++ b/java/smart-admin-api/src/main/resources/mapper/systemconfig/SystemConfigMapper.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/pre/application.properties b/java/smart-admin-api/src/main/resources/pre/application.properties new file mode 100644 index 00000000..ad34ca04 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/pre/application.properties @@ -0,0 +1,122 @@ +######################### server ################### +server.servlet.context-path=/smart-admin-api +server.port=10086 +spring.profiles.active=dev + +######################### tomcat ################### +server.tomcat.basedir=/home/logs/smartadmin/tomcat-logs +server.tomcat.accesslog.enabled=true +server.tomcat.accesslog.pattern=%t %{X-Forwarded-For}i %a "%r" %s %D (%D ms) + +######################### jackson ######################### +spring.jackson.serialization.write-enums-using-to-string=true +spring.jackson.deserialization.read-enums-using-to-string=true +spring.jackson.deserialization.fail-on-unknown-properties=false +spring.jackson.default-property-inclusion=always +spring.jackson.date-format=yyyy-MM-dd HH:mm:ss +spring.jackson.time-zone=GMT+8 +spring.jackson.serialization.write-dates-as-timestamps=false + +######################### http file ######################### +spring.servlet.multipart.max-file-size=30MB +spring.servlet.multipart.max-request-size=30MB +file-upload-service.path=/home/upload/ +file-upload-service.geturl=http://172.16.0.145/smartAdmin/file/ + +######################### database ######################### +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/smart-admin-dev?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC +spring.datasource.username=erp +spring.datasource.password=listen1015 +spring.datasource.initial-size=2 +spring.datasource.min-idle=1 +spring.datasource.max-active=10 +spring.datasource.max-wait=60000 +spring.datasource.time-between-eviction-runs-millis=60000 +spring.datasource.min-evictable-edle-time-millis=300000 +spring.datasource.driver-class-name=com.mysql.jdbc.Driver +spring.datasource.filters=stat +spring.datasource.druid.username=druid +spring.datasource.druid.password=Gq123456 +spring.datasource.druid.login.enabled=false + +######################### redis ####################################### +spring.redis.database=13 +spring.redis.host=172.16.0.145 +spring.redis.jedis.pool.max-active=100 +spring.redis.jedis.pool.min-idle=5 +spring.redis.jedis.pool.max-idle=10 +spring.redis.jedis.pool.max-wait=30000ms +spring.redis.port=50000 +spring.redis.timeout=10000ms +spring.redis.password= + +########################## rest http pool ######################### +#\u6700\u5927\u8FDE\u63A5\u6570 +http.pool.max-total=100 +#\u5355\u8DEF\u7531\u6700\u5927\u8FDE\u63A5\u6570 +http.pool.default-max-per-route=25 +#\u670D\u52A1\u5668\u8FD4\u56DE\u6570\u636E(response)\u7684\u65F6\u95F4 +http.pool.socket-timeout=8000 +#\u8FDE\u63A5\u4E0A\u670D\u52A1\u5668(\u63E1\u624B\u6210\u529F)\u7684\u65F6\u95F4 +http.pool.connect-timeout=8000 +#\u4ECE\u8FDE\u63A5\u6C60\u4E2D\u83B7\u53D6\u8FDE\u63A5\u7684\u8D85\u65F6\u65F6\u95F4 +http.pool.connection-request-timeout=8000 + +######################### mybatis\u914D\u7F6E ######################### +mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl +# mybatis-plus \u5B57\u6BB5\u9A7C\u5CF0\u81EA\u52A8\u8F6C\u6362 +mybatis-plus.configuration.map-underscore-to-camel-case=true +mybatis-plus.mapper-locations=classpath:/mapper/*Mapper.xml,/mapper/*/*Mapper.xml +mybatis-plus.typeAliasesPackage=com.gangquan360.smartadmin.*.*.domain.entity +mybatis-plus.global-config.refresh-mapper=true +mybatis-plus.global-config.db-column-underline=true + +######################### swagger ######################### +swagger.apiGroupName=smartAdmin +swagger.title=smartAdmin +swagger.description=smartAdmin +swagger.version=1.0 +swagger.serviceUrl=http://localhost:10086/smart-admin-api +swagger.packAge=com.gangquan360.smartadmin.module + +######################### jwt ######################### +jwt.key=smart-admin-jwt-key + +########################## smart reload ######################### +smart-reload.thread-count=1 +smart-reload.time-interval=5 + +######################### cros ######################### +access-control-allow-origin=* + +######################### heart beat ######################### +heart-beat.delayHandlerTime=60000 +heart-beat.intervalTime=180000 + +######################### quartz ############################# +#\u8C03\u5EA6\u6807\u8BC6\u540D \u96C6\u7FA4\u4E2D\u6BCF\u4E00\u4E2A\u5B9E\u4F8B\u90FD\u5FC5\u987B\u4F7F\u7528\u76F8\u540C\u7684\u540D\u79F0 +spring.quartz.properties.org.quartz.scheduler.instanceName=devClusteredScheduler +spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO +#\u8FDC\u7A0B\u7BA1\u7406\u76F8\u5173\u7684\u914D\u7F6E,\u5168\u90E8\u5173\u95ED +spring.quartz.properties.org.quartz.scheduler.rmi.export=false +spring.quartz.properties.org.quartz.scheduler.rmi.proxy=false +#\u8DF3\u8FC7quartz\u7248\u672C\u68C0\u67E5 +spring.quartz.properties.org.quartz.scheduler.skipUpdateCheck=true +#\u6570\u636E\u4FDD\u5B58\u65B9\u5F0F\u4E3A\u6301\u4E45\u5316 +spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX +spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate +spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_ +spring.quartz.properties.org.quartz.jobStore.isClustered=true +#\u8C03\u5EA6\u5B9E\u4F8B\u5931\u6548\u7684\u68C0\u67E5\u65F6\u95F4\u95F4\u9694 +spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=10000 +spring.quartz.properties.org.quartz.jobStore.useProperties=false +#\u8C03\u5EA6\u7EBF\u7A0B +spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool +spring.quartz.properties.org.quartz.threadPool.threadCount=2 +spring.quartz.properties.org.quartz.threadPool.threadPriority=5 +spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true +spring.quartz.properties.org.quartz.threadPool.threadNamePrefix=quartz +spring.quartz.job-store-type=jdbc +#ALWAYS,EMBEDDED,NEVER +spring.quartz.jdbc.initialize-schema=NEVER +spring.quartz.jdbc.schema=classpath:sql/quartz_mysql_2.3.0.sql diff --git a/java/smart-admin-api/src/main/resources/pre/log4j2.xml b/java/smart-admin-api/src/main/resources/pre/log4j2.xml new file mode 100644 index 00000000..f1942baf --- /dev/null +++ b/java/smart-admin-api/src/main/resources/pre/log4j2.xml @@ -0,0 +1,97 @@ + + + + + /home/logs/smart-admin/dev/logs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/prod/application.properties b/java/smart-admin-api/src/main/resources/prod/application.properties new file mode 100644 index 00000000..e42e3f94 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/prod/application.properties @@ -0,0 +1,122 @@ +######################### server ################### +server.servlet.context-path=/smart-admin-api +server.port=10088 +spring.profiles.active=@profiles.active@ + +######################### tomcat ################### +server.tomcat.basedir=/home/logs/smart-admin/tomcat-logs +server.tomcat.accesslog.enabled=true +server.tomcat.accesslog.pattern=%t %{X-Forwarded-For}i %a "%r" %s %D (%D ms) + +######################### jackson ######################### +spring.jackson.serialization.write-enums-using-to-string=true +spring.jackson.deserialization.read-enums-using-to-string=true +spring.jackson.deserialization.fail-on-unknown-properties=false + +spring.jackson.default-property-inclusion=always +spring.jackson.date-format=yyyy-MM-dd HH:mm:ss +spring.jackson.time-zone=GMT+8 +spring.jackson.serialization.write-dates-as-timestamps=false + +######################### http file ######################### +spring.servlet.multipart.max-file-size=30MB +spring.servlet.multipart.max-request-size=30MB +file-upload-service.path=/home/upload/smart-admin-file +file-upload-service.geturl=http://smartadmin.gangquan360.com/demoAdmin/file/ + +######################### database ######################### +spring.datasource.url=jdbc:mysql://172.16.0.201:3306/smart-admin-prod?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true +spring.datasource.username=smart-admin +spring.datasource.password=Admin@123457 +spring.datasource.initial-size=2 +spring.datasource.min-idle=1 +spring.datasource.max-active=10 +spring.datasource.max-wait=60000 +spring.datasource.time-between-eviction-runs-millis=60000 +spring.datasource.min-evictable-edle-time-millis=300000 +spring.datasource.driver-class-name=com.mysql.jdbc.Driver +spring.datasource.filters=stat +spring.datasource.druid.username=druid +spring.datasource.druid.password=Gq123456 +spring.datasource.druid.login.enabled=false + +######################### redis ####################################### +spring.redis.database=13 +spring.redis.host=127.0.0.1 +spring.redis.jedis.pool.max-active=100 +spring.redis.jedis.pool.min-idle=5 +spring.redis.jedis.pool.max-idle=10 +spring.redis.jedis.pool.max-wait=30000ms +spring.redis.port=6379 +spring.redis.timeout=10000ms +spring.redis.password=Gq123456@ + +########################## rest http pool ######################### +#\u6700\u5927\u8FDE\u63A5\u6570 +http.pool.max-total=100 +#\u5355\u8DEF\u7531\u6700\u5927\u8FDE\u63A5\u6570 +http.pool.default-max-per-route=25 +#\u670D\u52A1\u5668\u8FD4\u56DE\u6570\u636E(response)\u7684\u65F6\u95F4 +http.pool.socket-timeout=8000 +#\u8FDE\u63A5\u4E0A\u670D\u52A1\u5668(\u63E1\u624B\u6210\u529F)\u7684\u65F6\u95F4 +http.pool.connect-timeout=8000 +#\u4ECE\u8FDE\u63A5\u6C60\u4E2D\u83B7\u53D6\u8FDE\u63A5\u7684\u8D85\u65F6\u65F6\u95F4 +http.pool.connection-request-timeout=8000 + +######################### mybatis\u914D\u7F6E ######################### +mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl +# mybatis-plus \u5B57\u6BB5\u9A7C\u5CF0\u81EA\u52A8\u8F6C\u6362 +mybatis-plus.configuration.map-underscore-to-camel-case=true +mybatis-plus.mapper-locations=classpath:/mapper/*Mapper.xml,/mapper/*/*Mapper.xml +mybatis-plus.typeAliasesPackage=com.gangquan360.smartadmin.*.*.domain.entity +mybatis-plus.global-config.refresh-mapper=true +mybatis-plus.global-config.db-column-underline=true + +######################### swagger ######################### +swagger.apiGroupName=smartAdmin +swagger.title=smartAdmin +swagger.description=smartAdmin +swagger.version=1.0 +swagger.serviceUrl=http://localhost:10086/smart-admin-api +swagger.packAge=com.gangquan360.smartadmin.module + +######################### jwt ######################### +jwt.key=smart-admin-jwt-key + +########################## smart reload ######################### +smart-reload.thread-count=2 +smart-reload.time-interval=20 +######################### cros ######################### +access-control-allow-origin=preview.smartadmin.1024lab.net +######################### heart beat ######################### +heart-beat.delayHandlerTime=60000 +heart-beat.intervalTime=180000 + +######################### quartz ############################# +#\u8C03\u5EA6\u6807\u8BC6\u540D \u96C6\u7FA4\u4E2D\u6BCF\u4E00\u4E2A\u5B9E\u4F8B\u90FD\u5FC5\u987B\u4F7F\u7528\u76F8\u540C\u7684\u540D\u79F0 +spring.quartz.properties.org.quartz.scheduler.instanceName=prodClusteredScheduler +spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO +#\u8FDC\u7A0B\u7BA1\u7406\u76F8\u5173\u7684\u914D\u7F6E,\u5168\u90E8\u5173\u95ED +spring.quartz.properties.org.quartz.scheduler.rmi.export=false +spring.quartz.properties.org.quartz.scheduler.rmi.proxy=false +#\u8DF3\u8FC7quartz\u7248\u672C\u68C0\u67E5 +spring.quartz.properties.org.quartz.scheduler.skipUpdateCheck=true +#\u6570\u636E\u4FDD\u5B58\u65B9\u5F0F\u4E3A\u6301\u4E45\u5316 +spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX +spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate +spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_ +spring.quartz.properties.org.quartz.jobStore.isClustered=true +#\u8C03\u5EA6\u5B9E\u4F8B\u5931\u6548\u7684\u68C0\u67E5\u65F6\u95F4\u95F4\u9694 +spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=10000 +spring.quartz.properties.org.quartz.jobStore.useProperties=false +#\u8C03\u5EA6\u7EBF\u7A0B +spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool +spring.quartz.properties.org.quartz.threadPool.threadCount=2 +spring.quartz.properties.org.quartz.threadPool.threadPriority=5 +spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true +spring.quartz.properties.org.quartz.threadPool.threadNamePrefix=quartz + +spring.quartz.job-store-type=jdbc +#ALWAYS,EMBEDDED,NEVER +spring.quartz.jdbc.initialize-schema=NEVER +spring.quartz.jdbc.schema=classpath:sql/quartz_mysql_2.3.0.sql diff --git a/java/smart-admin-api/src/main/resources/prod/log4j2.xml b/java/smart-admin-api/src/main/resources/prod/log4j2.xml new file mode 100644 index 00000000..4991f76e --- /dev/null +++ b/java/smart-admin-api/src/main/resources/prod/log4j2.xml @@ -0,0 +1,97 @@ + + + + + /home/logs/smart-admin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/sit/application.properties b/java/smart-admin-api/src/main/resources/sit/application.properties new file mode 100644 index 00000000..ad34ca04 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/sit/application.properties @@ -0,0 +1,122 @@ +######################### server ################### +server.servlet.context-path=/smart-admin-api +server.port=10086 +spring.profiles.active=dev + +######################### tomcat ################### +server.tomcat.basedir=/home/logs/smartadmin/tomcat-logs +server.tomcat.accesslog.enabled=true +server.tomcat.accesslog.pattern=%t %{X-Forwarded-For}i %a "%r" %s %D (%D ms) + +######################### jackson ######################### +spring.jackson.serialization.write-enums-using-to-string=true +spring.jackson.deserialization.read-enums-using-to-string=true +spring.jackson.deserialization.fail-on-unknown-properties=false +spring.jackson.default-property-inclusion=always +spring.jackson.date-format=yyyy-MM-dd HH:mm:ss +spring.jackson.time-zone=GMT+8 +spring.jackson.serialization.write-dates-as-timestamps=false + +######################### http file ######################### +spring.servlet.multipart.max-file-size=30MB +spring.servlet.multipart.max-request-size=30MB +file-upload-service.path=/home/upload/ +file-upload-service.geturl=http://172.16.0.145/smartAdmin/file/ + +######################### database ######################### +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/smart-admin-dev?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=UTC +spring.datasource.username=erp +spring.datasource.password=listen1015 +spring.datasource.initial-size=2 +spring.datasource.min-idle=1 +spring.datasource.max-active=10 +spring.datasource.max-wait=60000 +spring.datasource.time-between-eviction-runs-millis=60000 +spring.datasource.min-evictable-edle-time-millis=300000 +spring.datasource.driver-class-name=com.mysql.jdbc.Driver +spring.datasource.filters=stat +spring.datasource.druid.username=druid +spring.datasource.druid.password=Gq123456 +spring.datasource.druid.login.enabled=false + +######################### redis ####################################### +spring.redis.database=13 +spring.redis.host=172.16.0.145 +spring.redis.jedis.pool.max-active=100 +spring.redis.jedis.pool.min-idle=5 +spring.redis.jedis.pool.max-idle=10 +spring.redis.jedis.pool.max-wait=30000ms +spring.redis.port=50000 +spring.redis.timeout=10000ms +spring.redis.password= + +########################## rest http pool ######################### +#\u6700\u5927\u8FDE\u63A5\u6570 +http.pool.max-total=100 +#\u5355\u8DEF\u7531\u6700\u5927\u8FDE\u63A5\u6570 +http.pool.default-max-per-route=25 +#\u670D\u52A1\u5668\u8FD4\u56DE\u6570\u636E(response)\u7684\u65F6\u95F4 +http.pool.socket-timeout=8000 +#\u8FDE\u63A5\u4E0A\u670D\u52A1\u5668(\u63E1\u624B\u6210\u529F)\u7684\u65F6\u95F4 +http.pool.connect-timeout=8000 +#\u4ECE\u8FDE\u63A5\u6C60\u4E2D\u83B7\u53D6\u8FDE\u63A5\u7684\u8D85\u65F6\u65F6\u95F4 +http.pool.connection-request-timeout=8000 + +######################### mybatis\u914D\u7F6E ######################### +mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl +# mybatis-plus \u5B57\u6BB5\u9A7C\u5CF0\u81EA\u52A8\u8F6C\u6362 +mybatis-plus.configuration.map-underscore-to-camel-case=true +mybatis-plus.mapper-locations=classpath:/mapper/*Mapper.xml,/mapper/*/*Mapper.xml +mybatis-plus.typeAliasesPackage=com.gangquan360.smartadmin.*.*.domain.entity +mybatis-plus.global-config.refresh-mapper=true +mybatis-plus.global-config.db-column-underline=true + +######################### swagger ######################### +swagger.apiGroupName=smartAdmin +swagger.title=smartAdmin +swagger.description=smartAdmin +swagger.version=1.0 +swagger.serviceUrl=http://localhost:10086/smart-admin-api +swagger.packAge=com.gangquan360.smartadmin.module + +######################### jwt ######################### +jwt.key=smart-admin-jwt-key + +########################## smart reload ######################### +smart-reload.thread-count=1 +smart-reload.time-interval=5 + +######################### cros ######################### +access-control-allow-origin=* + +######################### heart beat ######################### +heart-beat.delayHandlerTime=60000 +heart-beat.intervalTime=180000 + +######################### quartz ############################# +#\u8C03\u5EA6\u6807\u8BC6\u540D \u96C6\u7FA4\u4E2D\u6BCF\u4E00\u4E2A\u5B9E\u4F8B\u90FD\u5FC5\u987B\u4F7F\u7528\u76F8\u540C\u7684\u540D\u79F0 +spring.quartz.properties.org.quartz.scheduler.instanceName=devClusteredScheduler +spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO +#\u8FDC\u7A0B\u7BA1\u7406\u76F8\u5173\u7684\u914D\u7F6E,\u5168\u90E8\u5173\u95ED +spring.quartz.properties.org.quartz.scheduler.rmi.export=false +spring.quartz.properties.org.quartz.scheduler.rmi.proxy=false +#\u8DF3\u8FC7quartz\u7248\u672C\u68C0\u67E5 +spring.quartz.properties.org.quartz.scheduler.skipUpdateCheck=true +#\u6570\u636E\u4FDD\u5B58\u65B9\u5F0F\u4E3A\u6301\u4E45\u5316 +spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX +spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate +spring.quartz.properties.org.quartz.jobStore.tablePrefix=QRTZ_ +spring.quartz.properties.org.quartz.jobStore.isClustered=true +#\u8C03\u5EA6\u5B9E\u4F8B\u5931\u6548\u7684\u68C0\u67E5\u65F6\u95F4\u95F4\u9694 +spring.quartz.properties.org.quartz.jobStore.clusterCheckinInterval=10000 +spring.quartz.properties.org.quartz.jobStore.useProperties=false +#\u8C03\u5EA6\u7EBF\u7A0B +spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool +spring.quartz.properties.org.quartz.threadPool.threadCount=2 +spring.quartz.properties.org.quartz.threadPool.threadPriority=5 +spring.quartz.properties.org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true +spring.quartz.properties.org.quartz.threadPool.threadNamePrefix=quartz +spring.quartz.job-store-type=jdbc +#ALWAYS,EMBEDDED,NEVER +spring.quartz.jdbc.initialize-schema=NEVER +spring.quartz.jdbc.schema=classpath:sql/quartz_mysql_2.3.0.sql diff --git a/java/smart-admin-api/src/main/resources/sit/log4j2.xml b/java/smart-admin-api/src/main/resources/sit/log4j2.xml new file mode 100644 index 00000000..ac533c99 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/sit/log4j2.xml @@ -0,0 +1,97 @@ + + + + + /home/logs/smart-admin/dev/logs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/sql/quartz_mysql_2.3.0.sql b/java/smart-admin-api/src/main/resources/sql/quartz_mysql_2.3.0.sql new file mode 100644 index 00000000..8968c23f --- /dev/null +++ b/java/smart-admin-api/src/main/resources/sql/quartz_mysql_2.3.0.sql @@ -0,0 +1,179 @@ +# +# In your Quartz properties file, you'll need to set +# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate +# +# +# By: Ron Cordell - roncordell +# I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM. + +DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS; +DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE; +DROP TABLE IF EXISTS QRTZ_LOCKS; +DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_TRIGGERS; +DROP TABLE IF EXISTS QRTZ_JOB_DETAILS; +DROP TABLE IF EXISTS QRTZ_CALENDARS; + +CREATE TABLE QRTZ_JOB_DETAILS( +SCHED_NAME VARCHAR(120) NOT NULL, +JOB_NAME VARCHAR(190) NOT NULL, +JOB_GROUP VARCHAR(190) NOT NULL, +DESCRIPTION VARCHAR(250) NULL, +JOB_CLASS_NAME VARCHAR(250) NOT NULL, +IS_DURABLE VARCHAR(1) NOT NULL, +IS_NONCONCURRENT VARCHAR(1) NOT NULL, +IS_UPDATE_DATA VARCHAR(1) NOT NULL, +REQUESTS_RECOVERY VARCHAR(1) NOT NULL, +JOB_DATA BLOB NULL, +PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_NAME VARCHAR(190) NOT NULL, +TRIGGER_GROUP VARCHAR(190) NOT NULL, +JOB_NAME VARCHAR(190) NOT NULL, +JOB_GROUP VARCHAR(190) NOT NULL, +DESCRIPTION VARCHAR(250) NULL, +NEXT_FIRE_TIME BIGINT(13) NULL, +PREV_FIRE_TIME BIGINT(13) NULL, +PRIORITY INTEGER NULL, +TRIGGER_STATE VARCHAR(16) NOT NULL, +TRIGGER_TYPE VARCHAR(8) NOT NULL, +START_TIME BIGINT(13) NOT NULL, +END_TIME BIGINT(13) NULL, +CALENDAR_NAME VARCHAR(190) NULL, +MISFIRE_INSTR SMALLINT(2) NULL, +JOB_DATA BLOB NULL, +PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), +FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP) +REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_NAME VARCHAR(190) NOT NULL, +TRIGGER_GROUP VARCHAR(190) NOT NULL, +REPEAT_COUNT BIGINT(7) NOT NULL, +REPEAT_INTERVAL BIGINT(12) NOT NULL, +TIMES_TRIGGERED BIGINT(10) NOT NULL, +PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), +FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_CRON_TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_NAME VARCHAR(190) NOT NULL, +TRIGGER_GROUP VARCHAR(190) NOT NULL, +CRON_EXPRESSION VARCHAR(120) NOT NULL, +TIME_ZONE_ID VARCHAR(80), +PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), +FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_SIMPROP_TRIGGERS + ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(190) NOT NULL, + TRIGGER_GROUP VARCHAR(190) NOT NULL, + STR_PROP_1 VARCHAR(512) NULL, + STR_PROP_2 VARCHAR(512) NULL, + STR_PROP_3 VARCHAR(512) NULL, + INT_PROP_1 INT NULL, + INT_PROP_2 INT NULL, + LONG_PROP_1 BIGINT NULL, + LONG_PROP_2 BIGINT NULL, + DEC_PROP_1 NUMERIC(13,4) NULL, + DEC_PROP_2 NUMERIC(13,4) NULL, + BOOL_PROP_1 VARCHAR(1) NULL, + BOOL_PROP_2 VARCHAR(1) NULL, + PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), + FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) + REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_BLOB_TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_NAME VARCHAR(190) NOT NULL, +TRIGGER_GROUP VARCHAR(190) NOT NULL, +BLOB_DATA BLOB NULL, +PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP), +INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP), +FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP) +REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_CALENDARS ( +SCHED_NAME VARCHAR(120) NOT NULL, +CALENDAR_NAME VARCHAR(190) NOT NULL, +CALENDAR BLOB NOT NULL, +PRIMARY KEY (SCHED_NAME,CALENDAR_NAME)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( +SCHED_NAME VARCHAR(120) NOT NULL, +TRIGGER_GROUP VARCHAR(190) NOT NULL, +PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_FIRED_TRIGGERS ( +SCHED_NAME VARCHAR(120) NOT NULL, +ENTRY_ID VARCHAR(95) NOT NULL, +TRIGGER_NAME VARCHAR(190) NOT NULL, +TRIGGER_GROUP VARCHAR(190) NOT NULL, +INSTANCE_NAME VARCHAR(190) NOT NULL, +FIRED_TIME BIGINT(13) NOT NULL, +SCHED_TIME BIGINT(13) NOT NULL, +PRIORITY INTEGER NOT NULL, +STATE VARCHAR(16) NOT NULL, +JOB_NAME VARCHAR(190) NULL, +JOB_GROUP VARCHAR(190) NULL, +IS_NONCONCURRENT VARCHAR(1) NULL, +REQUESTS_RECOVERY VARCHAR(1) NULL, +PRIMARY KEY (SCHED_NAME,ENTRY_ID)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_SCHEDULER_STATE ( +SCHED_NAME VARCHAR(120) NOT NULL, +INSTANCE_NAME VARCHAR(190) NOT NULL, +LAST_CHECKIN_TIME BIGINT(13) NOT NULL, +CHECKIN_INTERVAL BIGINT(13) NOT NULL, +PRIMARY KEY (SCHED_NAME,INSTANCE_NAME)) +ENGINE=InnoDB; + +CREATE TABLE QRTZ_LOCKS ( +SCHED_NAME VARCHAR(120) NOT NULL, +LOCK_NAME VARCHAR(40) NOT NULL, +PRIMARY KEY (SCHED_NAME,LOCK_NAME)) +ENGINE=InnoDB; + +CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY); +CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP); + +CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); +CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP); +CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME); +CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); +CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE); +CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE); +CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE); +CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME); +CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME); +CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME); +CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE); +CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE); + +CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME); +CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY); +CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP); +CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP); +CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP); +CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP); + +commit; diff --git a/java/smart-admin-api/src/main/resources/sql/smart-admin.sql b/java/smart-admin-api/src/main/resources/sql/smart-admin.sql new file mode 100644 index 00000000..664c3bea --- /dev/null +++ b/java/smart-admin-api/src/main/resources/sql/smart-admin.sql @@ -0,0 +1,1497 @@ +-- -------------------------------------------------------- +-- 主机: 127.0.0.1 +-- 服务器版本: 5.7.20-log - MySQL Community Server (GPL) +-- 服务器操作系统: Win64 +-- HeidiSQL 版本: 10.2.0.5670 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; + + +-- 导出 smart-admin-dev 的数据库结构 +DROP DATABASE IF EXISTS `smart-admin-dev`; +CREATE DATABASE IF NOT EXISTS `smart-admin-dev` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci */; +USE `smart-admin-dev`; + +-- 导出 表 smart-admin-dev.t_department 结构 +DROP TABLE IF EXISTS `t_department`; +CREATE TABLE IF NOT EXISTS `t_department` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '部门主键id', + `name` varchar(50) NOT NULL COMMENT '部门名称', + `short_name` varchar(50) DEFAULT NULL COMMENT '部门简称', + `manager_id` int(10) unsigned DEFAULT NULL COMMENT '部门负责人id', + `parent_id` int(10) unsigned DEFAULT NULL COMMENT '部门的父级id', + `sort` int(10) NOT NULL COMMENT '部门排序', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `parent_id` (`parent_id`) +) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8mb4 COMMENT='部门表'; + +-- 正在导出表 smart-admin-dev.t_department 的数据:~20 rows (大约) +DELETE FROM `t_department`; +/*!40000 ALTER TABLE `t_department` DISABLE KEYS */; +INSERT INTO `t_department` (`id`, `name`, `short_name`, `manager_id`, `parent_id`, `sort`, `update_time`, `create_time`) VALUES + (1, '1024创新实验室', 'ZWGWL', 16, 0, 1, '2019-04-03 10:41:25', '2019-04-03 10:41:25'), + (2, '二级部门-2', NULL, 15, 1, 17, '2019-04-15 16:45:10', '2019-04-15 16:45:10'), + (4, '二级部门-1', '管理', 14, 1, 20, '2019-04-17 16:14:55', '2019-04-17 16:14:55'), + (8, '三级部门-1', NULL, NULL, 4, 8, '2019-04-25 12:25:52', '2019-04-25 12:25:52'), + (9, '四级部门-1', NULL, NULL, 8, 9, '2019-04-25 12:26:36', '2019-04-25 12:26:36'), + (10, '五级部门-1', NULL, NULL, 9, 10, '2019-04-25 12:26:49', '2019-04-25 12:26:49'), + (11, '六级部门-1', NULL, NULL, 10, 11, '2019-04-25 12:26:59', '2019-04-25 12:26:59'), + (12, '七级部门-1', NULL, NULL, 11, 12, '2019-04-25 12:27:18', '2019-04-25 12:27:18'), + (13, '八级部门-1', NULL, NULL, 12, 13, '2019-04-25 12:27:34', '2019-04-25 12:27:34'), + (14, '九级部门-1', NULL, NULL, 13, 14, '2019-04-25 12:27:47', '2019-04-25 12:27:47'), + (15, '十级部门-1', NULL, NULL, 14, 15, '2019-04-25 12:28:16', '2019-04-25 12:28:16'), + (16, '十一级部门部门部部门门嘻嘻哈哈-1', NULL, 13, 15, 16, '2019-04-25 14:56:40', '2019-04-25 14:56:40'), + (17, '信息中心', NULL, 16, 1, 4, '2019-04-26 11:53:50', '2019-04-26 11:53:50'), + (18, '测试部门', NULL, 16, 17, 18, '2019-04-26 11:54:06', '2019-04-26 11:54:06'), + (19, '张娇测试', NULL, NULL, 2, 22, '2019-04-26 14:36:18', '2019-04-26 14:36:18'), + (20, '子部门', NULL, NULL, 2, 23, '2019-04-26 14:36:28', '2019-04-26 14:36:28'), + (22, '张静如', NULL, 16, 1, 2, '2019-04-28 14:21:44', '2019-04-28 14:21:44'), + (23, '张静如2', NULL, 22, 4, 19, '2019-04-28 14:22:48', '2019-04-28 14:22:48'), + (24, '测试', NULL, 18, 23, 24, '2019-04-29 10:12:42', '2019-04-29 10:12:42'), + (25, '测试', NULL, 18, 23, 25, '2019-04-29 10:12:42', '2019-04-29 10:12:42'); +/*!40000 ALTER TABLE `t_department` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_email 结构 +DROP TABLE IF EXISTS `t_email`; +CREATE TABLE IF NOT EXISTS `t_email` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '标题', + `to_emails` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '收件人', + `send_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '发送状态 0未发送 1已发送', + `content` longtext COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮件内容', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=87 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 正在导出表 smart-admin-dev.t_email 的数据:~56 rows (大约) +DELETE FROM `t_email`; +/*!40000 ALTER TABLE `t_email` DISABLE KEYS */; +INSERT INTO `t_email` (`id`, `title`, `to_emails`, `send_status`, `content`, `create_time`, `update_time`) VALUES + (20, '新增测试12345', '新增测试@11.com', 1, '

这是内容

', '2019-08-30 15:35:12', '2019-08-30 15:35:12'), + (21, 'b', 'asdf@33.com', 1, '

c

', '2019-09-06 14:25:33', '2019-09-06 14:25:33'), + (23, 'string', 'string', 0, 'string', '2019-09-06 06:55:01', '2019-09-06 06:55:01'), + (24, 'string', 'string', 0, 'string', '2019-09-06 06:55:01', '2019-09-06 06:55:01'), + (26, 'string', 'string', 0, 'string', '2019-09-06 07:01:32', '2019-09-06 07:01:32'), + (27, 'string', 'string', 0, 'string', '2019-09-06 07:01:32', '2019-09-06 07:01:32'), + (37, 'ewqwe', '适者生存@22.cc', 1, '

qweqwe

', '2019-11-09 10:00:46', '2019-11-09 10:00:46'), + (38, 'ewqwe', '适者生存@22.cc', 1, '

qweqwe

', '2019-11-09 10:00:49', '2019-11-09 10:00:49'), + (39, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:04:54', '2019-11-09 10:04:54'), + (40, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:04:57', '2019-11-09 10:04:57'), + (41, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:04:57', '2019-11-09 10:04:57'), + (42, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:04:58', '2019-11-09 10:04:58'), + (43, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:04:59', '2019-11-09 10:04:59'), + (44, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:04:59', '2019-11-09 10:04:59'), + (45, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:05:16', '2019-11-09 10:05:16'), + (46, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:06:29', '2019-11-09 10:06:29'), + (47, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:07:02', '2019-11-09 10:07:02'), + (48, 'dsfds', 'dsfsd@qq.ccc', 1, '

fsdfs

', '2019-11-09 10:07:16', '2019-11-09 10:07:16'), + (49, '2342', '11@ss.cc', 1, '

234234

', '2019-11-09 10:08:13', '2019-11-09 10:08:13'), + (50, '2342', '11@ss.cc', 1, '

234234

', '2019-11-09 10:08:30', '2019-11-09 10:08:30'), + (51, '2342', '11@ss.cc', 1, '

234234

', '2019-11-09 10:08:50', '2019-11-09 10:08:50'), + (52, '2342', '11@ss.cc', 1, '

234234

', '2019-11-09 10:09:09', '2019-11-09 10:09:09'), + (53, '2342', '11@ss.cc', 1, '

234234

', '2019-11-09 10:09:31', '2019-11-09 10:09:31'), + (54, '2342', '11@ss.cc', 1, '

234234

', '2019-11-09 10:12:24', '2019-11-09 10:12:24'), + (55, '2342', '11@ss.cc', 1, '

234234

', '2019-11-09 10:13:13', '2019-11-09 10:13:13'), + (56, 'asdasd', '3423@aqq.cc', 0, '

asdasd

', '2019-11-09 10:20:42', '2019-11-09 10:20:42'), + (57, 'asdasd', '3423@aqq.cc', 0, '

asdasd

', '2019-11-09 10:20:52', '2019-11-09 10:20:52'), + (58, 'asdasd', '3423@aqq.cc', 0, '

asdasd

', '2019-11-09 10:21:16', '2019-11-09 10:21:16'), + (59, 'asdasd', '3423@aqq.cc', 0, '

asdasd

', '2019-11-09 10:21:24', '2019-11-09 10:21:24'), + (60, 'asdasd', '3423@aqq.cc', 0, '

asdasd

', '2019-11-09 10:21:30', '2019-11-09 10:21:30'), + (61, 'asdasd', '3423@aqq.cc', 0, '

asdasd

', '2019-11-09 10:21:53', '2019-11-09 10:21:53'), + (62, 'a21312', '23423@qq.cc', 0, '

asdasdas

', '2019-11-09 10:23:40', '2019-11-09 10:23:40'), + (63, '11', '1234@qq.com', 0, '

23

', '2019-11-15 15:35:12', '2019-11-15 15:35:12'), + (64, '11', '1234@qq.com', 0, '

23

', '2019-11-15 15:35:15', '2019-11-15 15:35:15'), + (65, '11', '1234@qq.com', 0, '

23

', '2019-11-15 15:35:16', '2019-11-15 15:35:16'), + (66, 'eeee', '1234@qq.com', 0, '

    eee2233

', '2019-11-15 17:00:00', '2019-11-15 17:00:00'), + (67, 'eeee', '1234@qq.com', 0, '

    eee2233

', '2019-11-15 17:00:03', '2019-11-15 17:00:03'), + (68, 'eeee', '1234@qq.com', 0, '

    eee2233

', '2019-11-15 17:00:04', '2019-11-15 17:00:04'), + (69, '22223', '1017146812@qq.com', 0, '

    e34233

', '2019-11-15 17:00:33', '2019-11-15 17:00:33'), + (70, '22223', '1017146812@qq.com', 0, '

    e34233

', '2019-11-15 17:00:34', '2019-11-15 17:00:34'), + (71, '22223', '1017146812@qq.com', 0, '

    e34233

', '2019-11-15 17:00:34', '2019-11-15 17:00:34'), + (72, '22223', '12232', 0, '

    e34233

', '2019-11-15 17:00:49', '2019-11-15 17:00:49'), + (73, '22223', '12232@qq.com', 0, '

    e34233

', '2019-11-15 17:00:56', '2019-11-15 17:00:56'), + (74, 'dsasdasd', 'asdas@qq.com', 0, '

asdasd

', '2019-11-16 08:51:44', '2019-11-16 08:51:44'), + (75, 'dsasdasd', 'asdas@qq.com', 0, '

asdasd

', '2019-11-16 09:05:10', '2019-11-16 09:05:10'), + (76, 'dsasdasd', 'asdas@qq.com', 0, '

asdasd

', '2019-11-16 09:05:14', '2019-11-16 09:05:14'), + (77, 'dsasdasd', 'asdas@qq.com', 0, '

asdasd

', '2019-11-16 09:06:34', '2019-11-16 09:06:34'), + (78, 'dsasdasd', 'asdas@qq.com', 0, '

asdasd

', '2019-11-16 09:07:09', '2019-11-16 09:07:09'), + (79, 'dsasdasd', 'asdas@qq.com', 0, '

asdasd

', '2019-11-16 09:07:30', '2019-11-16 09:07:30'), + (80, 'dsasdasd', 'asdas@qq.com', 0, '

asdasd

', '2019-11-16 09:07:32', '2019-11-16 09:07:32'), + (81, 'dsasdasd', 'asdas@qq.com', 0, '

asdasd

', '2019-11-16 09:08:29', '2019-11-16 09:08:29'), + (82, 'sdfs', 'ss@ss.cc', 0, '

dsdsf

', '2019-11-16 09:08:46', '2019-11-16 09:08:46'), + (83, 'asdasd', 'asd@qq.vv', 0, '

asdas

', '2019-11-16 09:09:18', '2019-11-16 09:09:18'), + (84, 'asdasd', 'asd@qq.vv', 0, '

asdas

', '2019-11-16 09:09:42', '2019-11-16 09:09:42'), + (85, 'asdasd', 'asd@qq.vv', 0, '

asdas

', '2019-11-16 09:09:46', '2019-11-16 09:09:46'), + (86, 'dasdad', 'dasda@ss.cc', 1, '

dasasdas

', '2019-11-16 09:10:05', '2019-11-16 09:10:05'); +/*!40000 ALTER TABLE `t_email` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_employee 结构 +DROP TABLE IF EXISTS `t_employee`; +CREATE TABLE IF NOT EXISTS `t_employee` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `login_name` varchar(30) CHARACTER SET utf8 NOT NULL COMMENT '登录帐号', + `login_pwd` varchar(50) CHARACTER SET utf8 NOT NULL COMMENT '登录密码', + `actual_name` varchar(30) CHARACTER SET utf8 NOT NULL COMMENT '员工名称', + `nick_name` varchar(30) DEFAULT '' COMMENT '别名', + `phone` varchar(15) CHARACTER SET utf8 DEFAULT NULL COMMENT '手机号码', + `id_card` varchar(18) CHARACTER SET utf8 DEFAULT NULL COMMENT '身份证', + `birthday` date DEFAULT NULL COMMENT '出生日期', + `email` varchar(50) DEFAULT NULL COMMENT '邮箱', + `department_id` int(10) unsigned NOT NULL COMMENT '部门id', + `is_leave` int(10) NOT NULL DEFAULT '0' COMMENT '是否离职1是', + `is_disabled` int(10) NOT NULL DEFAULT '0' COMMENT '是否被禁用 0否1是', + `remark` varchar(200) DEFAULT NULL COMMENT '备注', + `create_user` int(10) unsigned NOT NULL COMMENT '创建者id', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `is_delete` int(10) NOT NULL DEFAULT '0' COMMENT '是否删除0否 1是', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=40 DEFAULT CHARSET=utf8mb4 COMMENT='员工表'; + +-- 正在导出表 smart-admin-dev.t_employee 的数据:~28 rows (大约) +DELETE FROM `t_employee`; +/*!40000 ALTER TABLE `t_employee` DISABLE KEYS */; +INSERT INTO `t_employee` (`id`, `login_name`, `login_pwd`, `actual_name`, `nick_name`, `phone`, `id_card`, `birthday`, `email`, `department_id`, `is_leave`, `is_disabled`, `remark`, `create_user`, `update_time`, `create_time`, `is_delete`) VALUES + (1, 'sa', 'c655798e4648c540812a1b8f48759af7', '管理员', '15515515515', '13112312131', '410306199202020020', '1992-02-02', NULL, 1, 0, 0, NULL, 0, '2019-04-27 09:56:17', '2018-05-11 09:38:54', 0), + (11, 'role1', 'c655798e4648c540812a1b8f48759af7', '角色测试1', '', '18123245230', '', '1970-01-01', '', 4, 0, 0, NULL, 1, '2019-04-27 09:56:17', '2019-04-25 12:30:22', 0), + (12, 'role2', 'c655798e4648c540812a1b8f48759af7', '角色测试2', '', '18121451241', '', NULL, '', 4, 0, 0, NULL, 1, '2019-08-01 10:04:38', '2019-04-25 12:31:11', 0), + (13, 'lihaifan', 'c655798e4648c540812a1b8f48759af7', 'lihaifan', '', '18399485774', '', NULL, '', 1, 0, 0, NULL, 1, '2019-04-27 09:56:17', '2019-04-25 13:50:44', 0), + (14, 'lipeng', 'c655798e4648c540812a1b8f48759af7', '李鹏1', '', '13937988294', '', NULL, '', 2, 0, 0, NULL, 1, '2019-04-27 09:56:17', '2019-04-25 14:34:47', 0), + (15, 'huangwenli', 'c655798e4648c540812a1b8f48759af7', '黄文丽', '', '15515515515', '', NULL, '', 16, 0, 0, NULL, 1, '2019-04-27 09:56:17', '2019-04-26 10:05:05', 0), + (16, 'huangwenli1', 'c655798e4648c540812a1b8f48759af7', '黄文丽', '', '15515515515', '', NULL, '', 15, 0, 0, NULL, 1, '2019-04-27 14:04:19', '2019-04-26 10:25:04', 0), + (17, 'zhangjiao', 'c655798e4648c540812a1b8f48759af7', '张娇', '阿娇', '15670390391', '410305199102020020', '1991-02-02', '86484@qq.com', 19, 0, 0, NULL, 1, '2019-08-05 16:33:57', '2019-04-26 14:37:23', 0), + (18, 'zhangjiao1', 'c655798e4648c540812a1b8f48759af7', '张娇1', '', '15670390391', '', '2019-04-18', '6666@qq.com', 20, 0, 0, NULL, 1, '2019-08-05 16:33:57', '2019-04-26 14:45:55', 0), + (19, 'zhenxiaocang', 'c655798e4648c540812a1b8f48759af7', '珍小藏', '', '15670390391', '', NULL, '', 19, 0, 1, NULL, 1, '2019-09-09 08:34:35', '2019-04-26 14:46:57', 0), + (20, 'matengfei', 'c655798e4648c540812a1b8f48759af7', '马腾飞', '', '15670390393', '', NULL, '', 19, 0, 0, NULL, 1, '2019-08-05 16:33:57', '2019-04-26 14:47:24', 0), + (21, 'ceshi123', 'c655798e4648c540812a1b8f48759af7', '测试人员', '', '18829938477', '', NULL, '', 1, 0, 1, NULL, 13, '2019-04-27 09:56:17', '2019-04-27 09:38:07', 1), + (22, 'zhangjingru', 'c655798e4648c540812a1b8f48759af7', '张静如', '', '15600000000', '', NULL, '', 1, 0, 0, NULL, 1, '2019-09-04 09:06:47', '2019-04-28 14:05:03', 0), + (23, 'sdfsdfdsfsdfdsfdsf', 'c655798e4648c540812a1b8f48759af7', 'werewr', '', '15698585858', '', NULL, '', 19, 0, 0, NULL, 1, '2019-09-05 16:13:03', '2019-04-28 16:26:27', 0), + (25, 'shq2019', 'c655798e4648c540812a1b8f48759af7', 'shq', 'shq', '18798801298', '410281199309024040', '1993-09-02', '', 17, 0, 0, NULL, 1, '2019-08-05 16:33:57', '2019-05-05 09:13:41', 0), + (26, 'zhangjiao666', 'c655798e4648c540812a1b8f48759af7', 'tom我是五个字12', '', '15612345678', '', NULL, '', 18, 0, 0, NULL, 1, '2019-08-05 16:33:57', '2019-05-05 15:34:10', 0), + (28, 'dfsfgds', 'c655798e4648c540812a1b8f48759af7', 'fds', '', '15854127845', '', NULL, '', 22, 0, 1, NULL, 1, '2019-09-06 08:58:40', '2019-05-06 10:36:57', 0), + (29, 'abcabc', 'c655798e4648c540812a1b8f48759af7', 'abccba', 'aaabac', '13311112222', '', NULL, '', 17, 0, 0, NULL, 1, '2019-08-05 16:33:57', '2019-07-10 17:00:58', 0), + (30, 'gengweigang', 'c655798e4648c540812a1b8f48759af7', '耿为刚', 'geng', '15038588418', '', NULL, '', 17, 0, 0, NULL, 1, '2019-08-08 14:35:51', '2019-08-08 14:35:51', 0), + (31, 'gengweigang1', 'c655798e4648c540812a1b8f48759af7', '耿为刚1', '这是别名', '15038588418', '410322193312123232', '1933-12-12', '32@qq.com', 18, 0, 0, NULL, 30, '2019-08-23 09:27:22', '2019-08-23 09:25:50', 0), + (32, 'ceshi123', 'c655798e4648c540812a1b8f48759af7', '测试', '测试', '15670702651', '', NULL, '', 17, 0, 0, NULL, 1, '2019-09-04 09:05:48', '2019-09-03 11:48:04', 0), + (33, 'ceshi321', 'c655798e4648c540812a1b8f48759af7', '测试', '测试', '15670702651', '', NULL, '', 17, 0, 1, NULL, 1, '2019-09-03 15:51:16', '2019-09-03 11:49:17', 0), + (34, 'ceshi123321', 'c655798e4648c540812a1b8f48759af7', '123', '', '15600000000', '', NULL, '', 22, 0, 1, NULL, 1, '2019-09-06 08:58:37', '2019-09-04 09:13:54', 0), + (35, 'guoqingfeng', 'c655798e4648c540812a1b8f48759af7', '郭青枫', '', '15670702651', '', NULL, '', 18, 0, 0, NULL, 1, '2019-09-04 15:09:00', '2019-09-04 15:09:00', 0), + (36, 'li327263458', 'c655798e4648c540812a1b8f48759af7', 'lipeng', '', '13937988294', '', NULL, '', 17, 0, 0, NULL, 1, '2019-09-09 17:01:39', '2019-09-09 17:01:39', 0), + (37, 'test123', 'c655798e4648c540812a1b8f48759af7', 'test', '', '13211110201', '', NULL, '', 18, 0, 1, NULL, 1, '2019-11-14 16:08:08', '2019-11-08 09:32:39', 0), + (38, 'tiantian', 'c655798e4648c540812a1b8f48759af7', '天天管理员', '', '13574502368', '', NULL, '', 17, 0, 0, NULL, 1, '2019-11-14 02:08:08', '2019-11-08 11:09:46', 0), + (39, 'wang13211111', 'c655798e4648c540812a1b8f48759af7', 'ceshi111', 'dddd', '13244553212', '', NULL, '', 25, 0, 0, NULL, 38, '2019-11-15 17:14:34', '2019-11-15 17:03:04', 0); +/*!40000 ALTER TABLE `t_employee` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_file 结构 +DROP TABLE IF EXISTS `t_file`; +CREATE TABLE IF NOT EXISTS `t_file` ( + `id` int(10) NOT NULL AUTO_INCREMENT COMMENT '主键ID', + `module_id` varchar(50) NOT NULL COMMENT '相关业务id', + `module_type` varchar(50) NOT NULL COMMENT '相关业务类型', + `file_name` varchar(255) DEFAULT NULL COMMENT '文件名称', + `file_size` varchar(255) DEFAULT NULL COMMENT '文件大小', + `file_type` varchar(50) DEFAULT NULL COMMENT '文件类型,程序中枚举控制,文件类型:如身份证正面,三证合一等等', + `file_path` varchar(255) NOT NULL COMMENT '文件key,用于文件下载', + `file_location_type` int(10) NOT NULL COMMENT '文件位置类型', + `creater_user` int(10) NOT NULL COMMENT '创建人,即上传人', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '上次更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE, + KEY `module_id_module_type` (`module_id`,`module_type`) USING BTREE, + KEY `module_type` (`module_type`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +-- 正在导出表 smart-admin-dev.t_file 的数据:~23 rows (大约) +DELETE FROM `t_file`; +/*!40000 ALTER TABLE `t_file` DISABLE KEYS */; +INSERT INTO `t_file` (`id`, `module_id`, `module_type`, `file_name`, `file_size`, `file_type`, `file_path`, `file_location_type`, `creater_user`, `update_time`, `create_time`) VALUES + (1, '1', '1', '阿里云1.jpg', NULL, NULL, 'backUser/config/d1788b717be24f14ba526f25397b936f', 2, 1, NULL, '2019-07-05 10:38:15'), + (2, '2', '1', '1.jpg', NULL, NULL, 'backUser/config/8895ec770c4e4e558c6d9b54eb00dffc', 2, 1, '2019-07-18 09:20:59', '2019-07-18 09:20:25'), + (3, '3', '1', '随笔.txt', NULL, NULL, 'backUser/config/f5cbc4c9a56f4fa7ad0ba58b0aa5d169', 2, 1, NULL, '2019-07-18 09:22:47'), + (4, '3', '1', '1.jpg', NULL, NULL, 'backUser/config/2019071809245603e0a4e449a4bf3aa28ee731c309040.jpg', 1, 1, NULL, '2019-07-18 09:24:51'), + (6, '4', '1', '1.jpg', NULL, NULL, 'backUser/config/ddcb8214ba274dec9bb2c33e0e246391', 3, 1, NULL, '2019-07-19 16:19:43'), + (7, '5', '1', 'sql.txt', NULL, NULL, 'backUser/config/cfbdf9562c894405b5b6f64f71fa812a', 3, 1, NULL, '2019-07-19 17:41:55'), + (9, '1', '1', '20190912023241a6132f5713b54e1fb490f4ea88115747.md', NULL, NULL, 'backUser/config/20190912023241a6132f5713b54e1fb490f4ea88115747.md', 1, 1, '2019-09-12 15:25:35', '2019-09-12 14:32:42'), + (10, '1', '1', '201909120232499804998573f643ff8e58189d23485629.mjs', NULL, NULL, 'backUser/config/201909120232499804998573f643ff8e58189d23485629.mjs', 1, 1, '2019-09-12 15:25:19', '2019-09-12 14:32:50'), + (11, '1', '1', '201909120326564cdc8df7b8cc49cfb273926877f047f5.json', NULL, NULL, 'backUser/config/201909120326564cdc8df7b8cc49cfb273926877f047f5.json', 1, 1, NULL, '2019-09-12 15:26:56'), + (12, '1', '1', '201909120343357104b7f1cc684f5797ada35c06aba770.json', NULL, NULL, 'backUser/config/201909120343357104b7f1cc684f5797ada35c06aba770.json', 1, 1, NULL, '2019-09-12 15:43:36'), + (13, '1', '1', '201909120343427e408141a0ea467ea2e012f7086a6265.json', NULL, NULL, 'backUser/config/201909120343427e408141a0ea467ea2e012f7086a6265.json', 1, 1, NULL, '2019-09-12 15:43:42'), + (14, '1', '1', '20190912034543b4d3a061fb2e416c899fe2ff6b9327e0.ts', NULL, NULL, 'backUser/config/20190912034543b4d3a061fb2e416c899fe2ff6b9327e0.ts', 1, 1, NULL, '2019-09-12 15:45:43'), + (15, '1', '1', '20190912034550a5dc04ce79b14a1cb2bb76545c909aa8.md', NULL, NULL, 'backUser/config/20190912034550a5dc04ce79b14a1cb2bb76545c909aa8.md', 1, 1, NULL, '2019-09-12 15:45:51'), + (16, '1', '1', 'LICENCE', NULL, NULL, 'backUser/config/cc02b99c0ec548f1a2231b70b7d569b8', 2, 1, NULL, '2019-09-12 15:47:22'), + (17, '1', '1', 'bignumber.min.js', NULL, NULL, 'backUser/config/bda49e8ad6d242fe8735b2023dfbf125', 2, 1, NULL, '2019-09-12 15:47:29'), + (18, '1', '1', '20190912034880a881fa8fbc841bfb7194ff312bd1058.json', NULL, NULL, 'backUser/config/20190912034880a881fa8fbc841bfb7194ff312bd1058.json', 1, 1, NULL, '2019-09-12 15:48:08'), + (19, '1', '1', '20190912034816ece14084acf345a79396a0f4347c4e44.md', NULL, NULL, 'backUser/config/20190912034816ece14084acf345a79396a0f4347c4e44.md', 1, 1, NULL, '2019-09-12 15:48:16'), + (20, '1', '1', '20191024054412fac4b4e04c574c6eab71f91e13a8a0b6.jpg', NULL, NULL, 'backUser/config/20191024054412fac4b4e04c574c6eab71f91e13a8a0b6.jpg', 1, 1, NULL, '2019-10-24 17:44:13'), + (21, '1', '1', '20191106042073f7ef01bde3046bd8e01928f397230bd.jpg', NULL, NULL, 'backUser/config/20191106042073f7ef01bde3046bd8e01928f397230bd.jpg', 1, 1, NULL, '2019-11-06 02:20:13'), + (22, '1', '1', '201911130802024b8a2ebf80543a98241bb464682650d.jpg', NULL, NULL, 'backUser/config/201911130802024b8a2ebf80543a98241bb464682650d.jpg', 1, 1, NULL, '2019-11-13 06:02:01'), + (23, '1', '1', '20191113080210d1d98eea46364d268b2a03fa03f7a446.jpg', NULL, NULL, 'backUser/config/20191113080210d1d98eea46364d268b2a03fa03f7a446.jpg', 1, 1, NULL, '2019-11-13 06:02:14'), + (24, '1', '1', '20191115043844e92b25e70fb140a1885614b978469ca9.jpg', NULL, NULL, 'backUser/config/20191115043844e92b25e70fb140a1885614b978469ca9.jpg', 1, 38, NULL, '2019-11-15 02:38:45'), + (25, '1', '1', '20191116060546d3a2c703cb5546b3851612907cc3786f.png', NULL, NULL, 'backUser/config/20191116060546d3a2c703cb5546b3851612907cc3786f.png', 1, 1, NULL, '2019-11-16 10:05:47'); +/*!40000 ALTER TABLE `t_file` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_heart_beat_record 结构 +DROP TABLE IF EXISTS `t_heart_beat_record`; +CREATE TABLE IF NOT EXISTS `t_heart_beat_record` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增id', + `project_path` varchar(100) DEFAULT NULL COMMENT '项目名称', + `server_ip` varchar(200) DEFAULT NULL COMMENT '服务器ip', + `process_no` int(10) DEFAULT NULL COMMENT '进程号', + `process_start_time` datetime DEFAULT NULL COMMENT '进程开启时间', + `heart_beat_time` datetime DEFAULT NULL COMMENT '心跳时间', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +-- 正在导出表 smart-admin-dev.t_heart_beat_record 的数据:~2 rows (大约) +DELETE FROM `t_heart_beat_record`; +/*!40000 ALTER TABLE `t_heart_beat_record` DISABLE KEYS */; +INSERT INTO `t_heart_beat_record` (`id`, `project_path`, `server_ip`, `process_no`, `process_start_time`, `heart_beat_time`) VALUES + (1, '/home/server/smart-admin/dev', '192.168.122.1;172.16.0.145', 14843, '2019-11-16 03:11:50', '2019-11-16 03:58:01'), + (2, 'F:\\codespace\\idea\\gangquan360\\foundation', '172.16.1.188;192.168.56.1', 227992, '2019-11-16 10:02:39', '2019-11-16 10:06:50'); +/*!40000 ALTER TABLE `t_heart_beat_record` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_id_generator 结构 +DROP TABLE IF EXISTS `t_id_generator`; +CREATE TABLE IF NOT EXISTS `t_id_generator` ( + `id` int(11) DEFAULT NULL, + `key_name` varchar(50) NOT NULL COMMENT '英文key', + `rule_format` varchar(500) NOT NULL COMMENT '规则格式。no_cycle没有周期, year_cycle 年周期, month_cycle月周期, day_cycle 日周期', + `rule_type` varchar(50) NOT NULL COMMENT '格式[yyyy]表示年,[mm]标识月,[dd]表示日,[nnn]表示三位数字', + `init_number` int(11) NOT NULL DEFAULT '1' COMMENT '初始值', + `last_number` int(11) DEFAULT NULL COMMENT '上次产生的id, 默认为空', + `remark` varchar(1000) NOT NULL COMMENT '备注', + `update_time` datetime DEFAULT NULL, + `create_time` datetime NOT NULL, + UNIQUE KEY `key_name` (`key_name`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='id生成器定义表'; + +-- 正在导出表 smart-admin-dev.t_id_generator 的数据:~2 rows (大约) +DELETE FROM `t_id_generator`; +/*!40000 ALTER TABLE `t_id_generator` DISABLE KEYS */; +INSERT INTO `t_id_generator` (`id`, `key_name`, `rule_format`, `rule_type`, `init_number`, `last_number`, `remark`, `update_time`, `create_time`) VALUES + (2, 'goods_num', '[nnnnnnn]', 'NO_CYCLE', 1, NULL, '商品编号', '2019-04-09 09:48:04', '2019-03-29 14:14:12'), + (1, 'order', '[yyyy][mm][dd][nnnnn]', 'DAY_CYCLE', 1, 1, '订单编号', '2019-03-30 11:25:42', '2019-03-29 14:14:12'); +/*!40000 ALTER TABLE `t_id_generator` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_id_generator_record 结构 +DROP TABLE IF EXISTS `t_id_generator_record`; +CREATE TABLE IF NOT EXISTS `t_id_generator_record` ( + `generator_id` int(11) NOT NULL, + `year` int(11) NOT NULL, + `month` int(11) NOT NULL, + `day` int(11) NOT NULL, + `last_number` int(11) NOT NULL, + PRIMARY KEY (`generator_id`,`year`,`month`,`day`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='id_generator记录表'; + +-- 正在导出表 smart-admin-dev.t_id_generator_record 的数据:~5 rows (大约) +DELETE FROM `t_id_generator_record`; +/*!40000 ALTER TABLE `t_id_generator_record` DISABLE KEYS */; +INSERT INTO `t_id_generator_record` (`generator_id`, `year`, `month`, `day`, `last_number`) VALUES + (1, 2019, 3, 30, 1), + (2, 2019, 3, 30, 1), + (2, 2019, 4, 3, 2), + (2, 2019, 4, 8, 2), + (2, 2019, 4, 9, 1); +/*!40000 ALTER TABLE `t_id_generator_record` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_notice 结构 +DROP TABLE IF EXISTS `t_notice`; +CREATE TABLE IF NOT EXISTS `t_notice` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `title` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '消息标题', + `content` longtext COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '消息内容', + `deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '删除状态:0未删除 0删除 ', + `send_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '发送状态 0未发送 1发送', + `create_user` bigint(20) NOT NULL COMMENT '消息创建人', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=108 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 正在导出表 smart-admin-dev.t_notice 的数据:~14 rows (大约) +DELETE FROM `t_notice`; +/*!40000 ALTER TABLE `t_notice` DISABLE KEYS */; +INSERT INTO `t_notice` (`id`, `title`, `content`, `deleted`, `send_status`, `create_user`, `create_time`, `update_time`) VALUES + (93, '大扫把', '晓冬吃大便', 1, 1, 1, '2019-07-13 17:54:13', '2019-07-13 17:54:21'), + (95, '4444444', '444444444444', 1, 1, 1, '2019-07-13 17:54:53', '2019-09-04 09:42:02'), + (96, '3434', '444444', 1, 1, 1, '2019-07-13 17:58:42', '2019-11-08 09:05:24'), + (97, '44444', '555555555555', 1, 1, 1, '2019-07-13 17:58:54', '2019-09-03 16:19:50'), + (98, '《青花瓷》', '素胚勾勒出青花笔锋浓转淡\n瓶身描绘的牡丹一如你初妆\n冉冉檀香透过窗心事我了然\n周杰伦 青花瓷\n周杰伦 青花瓷\n宣纸上走笔至此搁一半\n釉色渲染仕女图韵味被私藏\n而你嫣然的一笑如含苞待放\n你的美一缕飘散\n去到我去不了的地方\n天青色等烟雨 而我在等你\n炊烟袅袅升起 隔江千万里\n在瓶底书刻隶仿前朝的飘逸\n就当我为遇见你伏笔\n天青色等烟雨 而我在等你\n月色被打捞起 晕开了结局\n如传世的青花瓷自顾自美丽\n你眼带笑意\n色白花青的锦鲤跃然于碗底\n临摹宋体落款时却惦记着你\n你隐藏在窑烧里千年的秘密\n极细腻犹如绣花针落地\n篱外芭蕉惹骤雨门环惹铜绿\n而我路过那江南小镇惹了你\n在泼墨山水画里\n你从墨色深处被隐去\n天青色等烟雨 而我在等你\n炊烟袅袅升起 隔江千万里\n在瓶底书刻隶仿前朝的飘逸\n就当我为遇见你伏笔\n天青色等烟雨 而我在等你\n月色被打捞起 晕开了结局\n如传世的青花瓷自顾自美丽\n你眼带笑意\n天青色等烟雨 而我在等你\n炊烟袅袅升起 隔江千万里\n在瓶底书刻隶仿前朝的飘逸\n就当我为遇见你伏笔\n天青色等烟雨 而我在等你\n月色被打捞起 晕开了结局\n如传世的青花瓷自顾自美丽\n你眼带笑意 ', 1, 1, 1, '2019-08-05 16:36:44', '2019-09-02 17:53:12'), + (99, '1', '2', 1, 1, 30, '2019-08-08 14:53:58', '2019-08-08 14:54:07'), + (100, '呵呵', '呵呵', 1, 1, 1, '2019-08-20 16:52:53', '2019-09-02 17:46:59'), + (101, 'aa', 'bbcc', 1, 1, 30, '2019-08-23 09:51:01', '2019-08-23 09:51:28'), + (102, '1', '2', 0, 1, 1, '2019-09-05 14:28:10', '2019-09-05 14:28:10'), + (103, '12', '22', 0, 1, 1, '2019-09-05 14:29:30', '2019-09-05 14:29:30'), + (104, 'a', 'b', 1, 1, 30, '2019-09-06 14:21:18', '2019-09-06 14:24:07'), + (105, '22222222222', '1111', 0, 0, 1, '2019-11-07 19:05:56', '2019-11-07 19:05:56'), + (106, '423', '234', 0, 0, 37, '2019-11-08 21:48:19', '2019-11-08 21:48:19'), + (107, 'AAS', 's\'da\'ssdas', 1, 1, 1, '2019-11-13 19:06:55', '2019-11-14 09:07:06'); +/*!40000 ALTER TABLE `t_notice` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_notice_receive_record 结构 +DROP TABLE IF EXISTS `t_notice_receive_record`; +CREATE TABLE IF NOT EXISTS `t_notice_receive_record` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `notice_id` bigint(20) NOT NULL COMMENT '消息id', + `employee_id` bigint(20) NOT NULL COMMENT '用户id', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=141 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 正在导出表 smart-admin-dev.t_notice_receive_record 的数据:~27 rows (大约) +DELETE FROM `t_notice_receive_record`; +/*!40000 ALTER TABLE `t_notice_receive_record` DISABLE KEYS */; +INSERT INTO `t_notice_receive_record` (`id`, `notice_id`, `employee_id`, `create_time`, `update_time`) VALUES + (114, 93, 1, '2019-07-13 17:54:16', '2019-07-13 17:54:16'), + (115, 95, 1, '2019-07-13 17:54:55', '2019-07-13 17:54:55'), + (116, 95, 22, '2019-07-13 17:58:03', '2019-07-13 17:58:03'), + (117, 93, 22, '2019-07-13 17:58:05', '2019-07-13 17:58:05'), + (118, 96, 1, '2019-07-13 17:58:44', '2019-07-13 17:58:44'), + (119, 97, 1, '2019-07-13 17:58:58', '2019-07-13 17:58:58'), + (120, 98, 1, '2019-08-05 16:37:01', '2019-08-05 16:37:01'), + (121, 99, 30, '2019-08-08 14:54:05', '2019-08-08 14:54:05'), + (122, 99, 1, '2019-08-08 15:15:44', '2019-08-08 15:15:44'), + (123, 100, 1, '2019-08-20 16:53:29', '2019-08-20 16:53:29'), + (124, 101, 30, '2019-08-23 09:51:11', '2019-08-23 09:51:11'), + (125, 101, 1, '2019-08-23 12:46:27', '2019-08-23 12:46:27'), + (126, 102, 1, '2019-09-05 14:28:32', '2019-09-05 14:28:32'), + (127, 104, 30, '2019-09-06 14:23:58', '2019-09-06 14:23:58'), + (128, 104, 1, '2019-09-06 15:25:13', '2019-09-06 15:25:13'), + (129, 101, 14, '2019-11-02 21:46:13', '2019-11-02 21:46:13'), + (130, 102, 14, '2019-11-02 21:46:14', '2019-11-02 21:46:14'), + (131, 104, 14, '2019-11-02 21:46:15', '2019-11-02 21:46:15'), + (132, 98, 14, '2019-11-02 21:46:18', '2019-11-02 21:46:18'), + (133, 103, 37, '2019-11-07 19:58:06', '2019-11-07 19:58:06'), + (134, 103, 1, '2019-11-07 20:03:54', '2019-11-07 20:03:54'), + (135, 107, 1, '2019-11-13 19:07:02', '2019-11-13 19:07:02'), + (136, 107, 38, '2019-11-15 02:11:04', '2019-11-15 02:11:04'), + (137, 104, 38, '2019-11-15 02:11:17', '2019-11-15 02:11:17'), + (138, 101, 38, '2019-11-15 02:26:33', '2019-11-15 02:26:33'), + (139, 98, 38, '2019-11-15 02:29:32', '2019-11-15 02:29:32'), + (140, 100, 38, '2019-11-15 03:19:18', '2019-11-15 03:19:18'); +/*!40000 ALTER TABLE `t_notice_receive_record` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_order_operate_log 结构 +DROP TABLE IF EXISTS `t_order_operate_log`; +CREATE TABLE IF NOT EXISTS `t_order_operate_log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `order_id` int(11) NOT NULL COMMENT '各种单据的id', + `order_type` int(11) NOT NULL COMMENT '单据类型', + `operate_type` int(11) NOT NULL COMMENT '操作类型', + `operate_content` text NOT NULL COMMENT '操作类型 对应的中文', + `operate_remark` text COMMENT '操作备注', + `employee_id` int(11) NOT NULL COMMENT '员工id', + `employee_name` varchar(1000) NOT NULL COMMENT '员工名称', + `ext_data` text COMMENT '额外信息', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) USING BTREE, + KEY `order_id_order_type` (`order_id`,`order_type`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='各种单据操作记录\r\n'; + +-- 正在导出表 smart-admin-dev.t_order_operate_log 的数据:~0 rows (大约) +DELETE FROM `t_order_operate_log`; +/*!40000 ALTER TABLE `t_order_operate_log` DISABLE KEYS */; +/*!40000 ALTER TABLE `t_order_operate_log` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_position 结构 +DROP TABLE IF EXISTS `t_position`; +CREATE TABLE IF NOT EXISTS `t_position` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `position_name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '岗位名称', + `remark` varchar(255) CHARACTER SET utf8 DEFAULT NULL COMMENT '岗位描述', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='岗位表'; + +-- 正在导出表 smart-admin-dev.t_position 的数据:~13 rows (大约) +DELETE FROM `t_position`; +/*!40000 ALTER TABLE `t_position` DISABLE KEYS */; +INSERT INTO `t_position` (`id`, `position_name`, `remark`, `update_time`, `create_time`) VALUES + (1, 'java develop', 'java develop is good job', '2019-07-03 15:18:45', '2019-07-03 15:18:45'), + (2, 'android develop', 'android develop is good job', '2019-07-04 16:11:11', '2019-07-04 16:11:00'), + (3, '测试岗位1', '这是内容11', '2019-09-02 16:39:33', '2019-07-10 14:03:50'), + (8, '测试岗位2', '测试岗位2.。', '2019-09-04 10:19:40', '2019-09-04 10:19:32'), + (9, '测试岗位3', '测试岗位3', '2019-09-05 14:39:43', '2019-09-05 14:39:43'), + (10, '测试岗位4', '测试岗位4', '2019-09-05 14:39:48', '2019-09-05 14:39:48'), + (11, '测试岗位5', '测试岗位5', '2019-09-05 14:39:53', '2019-09-05 14:39:53'), + (12, '测试岗位6', '测试岗位6', '2019-09-05 14:39:58', '2019-09-05 14:39:58'), + (13, '测试岗位7', '测试岗位7', '2019-09-05 14:40:03', '2019-09-05 14:40:03'), + (14, '测试岗位8', '测试岗位8', '2019-09-05 14:40:09', '2019-09-05 14:40:09'), + (15, '测试岗位9', '测试岗位9', '2019-09-05 14:40:19', '2019-09-05 14:40:19'), + (16, 'aaa22222', 'ddddddddddd', '2019-11-15 17:04:29', '2019-11-06 15:58:37'), + (17, 'ddd', 'fsdef', '2019-11-15 17:04:40', '2019-11-15 17:04:40'); +/*!40000 ALTER TABLE `t_position` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_position_relation 结构 +DROP TABLE IF EXISTS `t_position_relation`; +CREATE TABLE IF NOT EXISTS `t_position_relation` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT, + `position_id` int(10) DEFAULT NULL COMMENT '岗位ID', + `employee_id` int(10) DEFAULT NULL COMMENT '员工ID', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `job_id` (`position_id`) USING BTREE, + KEY `employee_id` (`employee_id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=53 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='岗位关联表'; + +-- 正在导出表 smart-admin-dev.t_position_relation 的数据:~27 rows (大约) +DELETE FROM `t_position_relation`; +/*!40000 ALTER TABLE `t_position_relation` DISABLE KEYS */; +INSERT INTO `t_position_relation` (`id`, `position_id`, `employee_id`, `update_time`, `create_time`) VALUES + (14, 1, 28, '2019-07-10 16:40:14', '2019-07-10 16:40:14'), + (18, 1, 29, '2019-07-11 10:18:22', '2019-07-11 10:18:22'), + (19, 3, 29, '2019-07-11 10:18:22', '2019-07-11 10:18:22'), + (20, 2, 29, '2019-07-11 10:18:22', '2019-07-11 10:18:22'), + (21, 1, 30, '2019-08-08 14:35:51', '2019-08-08 14:35:51'), + (22, 2, 30, '2019-08-08 14:35:51', '2019-08-08 14:35:51'), + (23, 3, 30, '2019-08-08 14:35:51', '2019-08-08 14:35:51'), + (26, 2, 31, '2019-08-23 09:26:44', '2019-08-23 09:26:44'), + (27, 3, 31, '2019-08-23 09:26:44', '2019-08-23 09:26:44'), + (28, 3, 32, '2019-09-04 09:05:47', '2019-09-04 09:05:47'), + (29, 2, 32, '2019-09-04 09:05:47', '2019-09-04 09:05:47'), + (30, 3, 22, '2019-09-04 09:06:46', '2019-09-04 09:06:46'), + (31, 2, 22, '2019-09-04 09:06:46', '2019-09-04 09:06:46'), + (35, 8, 35, '2019-09-04 15:09:00', '2019-09-04 15:09:00'), + (36, 3, 35, '2019-09-04 15:09:00', '2019-09-04 15:09:00'), + (37, 15, 23, '2019-09-05 16:13:02', '2019-09-05 16:13:02'), + (38, 14, 23, '2019-09-05 16:13:02', '2019-09-05 16:13:02'), + (39, 13, 23, '2019-09-05 16:13:02', '2019-09-05 16:13:02'), + (40, 3, 34, '2019-09-06 08:55:18', '2019-09-06 08:55:18'), + (41, 2, 34, '2019-09-06 08:55:18', '2019-09-06 08:55:18'), + (42, 1, 34, '2019-09-06 08:55:18', '2019-09-06 08:55:18'), + (43, 14, 36, '2019-09-09 17:01:39', '2019-09-09 17:01:39'), + (44, 3, 37, '2019-11-08 09:32:39', '2019-11-08 09:32:39'), + (46, 8, 38, '2019-11-14 16:08:05', '2019-11-14 16:08:05'), + (50, 16, 39, '2019-11-15 17:07:04', '2019-11-15 17:07:04'), + (51, 13, 39, '2019-11-15 17:07:04', '2019-11-15 17:07:04'), + (52, 14, 39, '2019-11-15 17:07:04', '2019-11-15 17:07:04'); +/*!40000 ALTER TABLE `t_position_relation` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_privilege 结构 +DROP TABLE IF EXISTS `t_privilege`; +CREATE TABLE IF NOT EXISTS `t_privilege` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '功能权限表主键id', + `type` tinyint(11) NOT NULL COMMENT '1.菜单 2.功能点', + `name` varchar(50) NOT NULL COMMENT '菜单名称', + `key` varchar(1000) NOT NULL COMMENT '路由name 英文关键字', + `url` text COMMENT '路由path/type=3为API接口', + `sort` int(11) NOT NULL DEFAULT '0' COMMENT '排序', + `parent_key` varchar(1000) DEFAULT NULL COMMENT '父级key', + `update_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + UNIQUE KEY `key` (`key`) USING BTREE, + KEY `type` (`type`) USING BTREE, + KEY `parent_key` (`parent_key`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=106 DEFAULT CHARSET=utf8 COMMENT='权限功能表'; + +-- 正在导出表 smart-admin-dev.t_privilege 的数据:~103 rows (大约) +DELETE FROM `t_privilege`; +/*!40000 ALTER TABLE `t_privilege` DISABLE KEYS */; +INSERT INTO `t_privilege` (`id`, `type`, `name`, `key`, `url`, `sort`, `parent_key`, `update_time`, `create_time`) VALUES + (1, 1, '人员管理', 'Employee', '/employee', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (2, 1, '角色管理', 'RoleManage', '/employee/role', 0, 'Employee', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (3, 1, '岗位管理', 'PositionList', '/employee/position', 0, 'Employee', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (4, 1, '员工管理', 'RoleEmployeeManage', '/employee/role-employee-manage', 0, 'Employee', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (5, 1, '系统设置', 'SystemSetting', '/system-setting', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (6, 1, '系统参数', 'SystemConfig', '/system-setting/system-config', 0, 'SystemSetting', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (8, 1, '菜单管理', 'SystemPrivilege', '/system-setting/system-privilege', 0, 'SystemSetting', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (9, 1, '消息管理', 'Notice', '/notice', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (10, 1, '通知管理', 'NoticeList', '/notice/notice-list', 0, 'Notice', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (11, 1, '个人消息', 'PersonNotice', '/notice/person-notice', 0, 'Notice', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (12, 1, '邮件管理', 'Email', '/email', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (13, 1, '邮件管理', 'EmailList', '/email/email-list', 0, 'Email', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (14, 1, '发送邮件', 'SendMail', '/email/send-mail', 0, 'Email', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (15, 1, '用户日志', 'UserLog', '/user-log', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (16, 1, '用户操作日志', 'UserOperateLog', '/user-log/user-operate-log', 0, 'UserLog', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (17, 1, '用户登录日志', 'UserLoginLog', '/user-log/user-login-log', 0, 'UserLog', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (18, 1, '系统监控', 'Monitor', '/monitor', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (19, 1, '在线人数', 'OnlineUser', '/monitor/online-user', 0, 'Monitor', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (20, 1, 'SQL监控', 'Sql', '/monitor/sql', 0, 'Monitor', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (21, 1, '定时任务', 'Task', '/task', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (22, 1, '任务管理', 'TaskList', '/system-setting/task-list', 0, 'Task', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (23, 1, '动态加载', 'Reload', '/reload', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (24, 1, 'SmartReload', 'SmartReloadList', '/reload/smart-reload-list', 0, 'Reload', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (25, 1, '接口文档', 'ApiDoc', '/api-doc', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (26, 1, 'Swagger接口文档', 'Swagger', '/api-doc/swagger', 0, 'ApiDoc', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (27, 1, '三级路由', 'ThreeRouter', '/three-router', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (28, 1, '三级菜单', 'LevelTwo', '/three-router/level-two', 0, 'ThreeRouter', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (29, 1, '三级A', 'RoleOneTwo', '/three-router/level-two/level-three1', 0, 'LevelTwo', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (30, 1, '三级B', 'RoleTwoTwo', '/three-router/level-two/level-three2', 0, 'LevelTwo', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (31, 1, '二级菜单', 'RoleOneOne', '/three-router/level-two2', 0, 'ThreeRouter', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (32, 1, 'KeepAlive', 'KeepAlive', '/keep-alive', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (33, 1, 'KeepAlive列表', 'KeepAliveContentList', '/keep-alive/content-list', 0, 'KeepAlive', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (34, 1, 'KeepAlive表单', 'KeepAliveAddContent', '/keep-alive/add-content', 0, 'KeepAlive', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (35, 1, '心跳服务', 'HeartBeat', '/heart-beat', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (36, 1, '心跳服务', 'HeartBeatList', '/heart-beat/heart-beat-list', 0, 'HeartBeat', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (37, 1, '文件服务', 'File', '/file', 0, NULL, '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (38, 1, '文件列表', 'FileList', '/file/file-list', 0, 'File', '2019-11-14 14:05:10', '2019-11-01 11:28:07'), + (39, 2, '添加角色', 'add-role', 'roleController.addRole', 0, 'RoleManage', '2019-11-01 11:47:29', '2019-11-01 11:47:29'), + (40, 2, '删除角色', 'delete-role', 'roleController.deleteRole', 1, 'RoleManage', '2019-11-01 11:47:43', '2019-11-01 11:47:43'), + (41, 2, '编辑角色', 'update-role', 'roleController.updateRole', 2, 'RoleManage', '2019-11-01 11:47:55', '2019-11-01 11:47:55'), + (42, 2, '修改角色权限', 'update-role-privilege', 'rolePrivilegeController.updateRolePrivilege', 3, 'RoleManage', '2019-11-01 11:48:09', '2019-11-01 11:48:09'), + (43, 2, '添加成员', 'add-employee-role', 'roleEmployeeController.addEmployeeList', 4, 'RoleManage', '2019-11-05 10:38:11', '2019-11-05 10:38:11'), + (44, 2, '查询成员', 'search-employee-list', 'roleEmployeeController.listAllEmployeeRoleId,roleEmployeeController.listEmployeeByName,roleController.getAllRole,rolePrivilegeController.listPrivilegeByRoleId', 7, 'RoleManage', '2019-11-05 10:39:04', '2019-11-05 10:39:04'), + (45, 2, '移除成员', 'delete-employee-role', 'roleEmployeeController.removeEmployee', 5, 'RoleManage', '2019-11-05 10:40:09', '2019-11-05 10:40:09'), + (46, 2, '批量移除', 'delete-employee-role-batch', 'roleEmployeeController.removeEmployeeList', 6, 'RoleManage', '2019-11-05 10:40:27', '2019-11-05 10:40:27'), + (47, 2, '查询数据范围', 'query-data-scope', 'dataScopeController.dataScopeList,dataScopeController.dataScopeListByRole,rolePrivilegeController.listPrivilegeByRoleId,privilegeController.queryAll,privilegeController.getAllUrl', 8, 'RoleManage', '2019-11-05 10:40:57', '2019-11-05 10:40:57'), + (48, 2, '更新数据范围', 'update-data-scope', 'dataScopeController.dataScopeBatchSet', 9, 'RoleManage', '2019-11-05 10:41:03', '2019-11-05 10:41:03'), + (49, 2, '查询', 'search-position', 'positionController.queryJobById,positionController.getJobPage', 0, 'PositionList', '2019-11-05 10:41:30', '2019-11-05 10:41:30'), + (50, 2, '添加', 'add-position', 'positionController.addJob', 1, 'PositionList', '2019-11-05 10:41:40', '2019-11-05 10:41:40'), + (51, 2, '修改', 'update-position', 'positionController.updateJob', 2, 'PositionList', '2019-11-05 10:41:49', '2019-11-05 10:41:49'), + (52, 2, '删除', 'delete-position', 'positionController.removeJob', 3, 'PositionList', '2019-11-05 10:41:57', '2019-11-05 10:41:57'), + (53, 2, '添加部门', 'add-department', 'departmentController.addDepartment', 0, 'RoleEmployeeManage', '2019-11-05 11:11:18', '2019-11-05 11:11:18'), + (54, 2, '编辑部门', 'update-department', 'departmentController.updateDepartment', 1, 'RoleEmployeeManage', '2019-11-05 11:11:29', '2019-11-05 11:11:29'), + (55, 2, '删除部门', 'delete-department', 'departmentController.delDepartment', 2, 'RoleEmployeeManage', '2019-11-05 11:11:48', '2019-11-05 11:11:48'), + (56, 2, '查询', 'search-department', 'departmentController.listAll,departmentController.getDepartment,departmentController.listDepartmentEmployee,departmentController.listDepartment,employeeController.query', 3, 'RoleEmployeeManage', '2019-11-05 11:12:09', '2019-11-05 11:12:09'), + (57, 2, '添加成员', 'add-employee', 'employeeController.addEmployee', 4, 'RoleEmployeeManage', '2019-11-05 17:06:23', '2019-11-05 17:06:23'), + (58, 2, '编辑成员', 'update-employee', 'employeeController.updateEmployee', 5, 'RoleEmployeeManage', '2019-11-05 17:06:57', '2019-11-05 17:06:57'), + (59, 2, '禁用', 'disabled-employee', 'employeeController.updateStatus', 6, 'RoleEmployeeManage', '2019-11-05 17:14:35', '2019-11-05 17:14:35'), + (60, 2, '批量操作', 'disabled-employee-batch', 'employeeController.batchUpdateStatus', 7, 'RoleEmployeeManage', '2019-11-05 17:19:23', '2019-11-05 17:19:23'), + (61, 2, '员工角色编辑', 'update-employee-role', 'employeeController.updateRoles', 8, 'RoleEmployeeManage', '2019-11-05 17:21:15', '2019-11-05 17:21:15'), + (62, 2, '重置密码', 'reset-employee-password', 'employeeController.resetPasswd', 10, 'RoleEmployeeManage', '2019-11-05 17:22:13', '2019-11-05 17:22:13'), + (63, 2, '删除员工', 'delete-employee', 'employeeController.deleteEmployeeById', 9, 'RoleEmployeeManage', '2019-11-05 17:22:27', '2019-11-05 17:22:27'), + (64, 2, '查询系统参数', 'system-params-search', 'systemConfigController.selectByKey,systemConfigController.getListByGroup,systemConfigController.getSystemConfigPage', 0, 'SystemConfig', '2019-11-05 17:23:41', '2019-11-05 17:23:41'), + (65, 2, '添加系统参数', 'system-params-add', 'systemConfigController.addSystemConfig', 1, 'SystemConfig', '2019-11-05 17:26:00', '2019-11-05 17:26:00'), + (66, 2, '修改系统参数', 'system-config-update', 'systemConfigController.updateSystemConfig', 2, 'SystemConfig', '2019-11-05 17:26:07', '2019-11-05 17:26:07'), + (67, 2, '搜索系统参数', 'system-config-search', 'systemConfigController.selectByKey,systemConfigController.getListByGroup,systemConfigController.getSystemConfigPage', 3, 'SystemConfig', '2019-11-05 17:26:44', '2019-11-05 17:26:44'), + (69, 2, '编辑', 'privilege-main-update', 'privilegeController.menuBatchSave,privilegeController.functionSaveOrUpdate', 0, 'SystemPrivilege', '2019-11-05 17:27:28', '2019-11-05 17:27:28'), + (70, 2, '查询', 'privilege-main-search', 'privilegeController.queryAll,privilegeController.getAllUrl,privilegeController.functionQuery', 1, 'SystemPrivilege', '2019-11-05 17:28:45', '2019-11-05 17:28:45'), + (71, 2, '查询', 'notice-query', 'noticeController.queryReceiveByPage,noticeController.queryUnreadByPage,noticeController.queryByPage,noticeController.detail', 0, 'NoticeList', '2019-11-05 17:30:16', '2019-11-05 17:30:16'), + (72, 2, '添加', 'notice-add', 'noticeController.add', 1, 'NoticeList', '2019-11-05 17:30:28', '2019-11-05 17:30:28'), + (73, 2, '修改', 'notice-edit', 'noticeController.update', 2, 'NoticeList', '2019-11-05 17:31:24', '2019-11-05 17:31:24'), + (74, 2, '删除', 'notice-delete', 'noticeController.delete', 3, 'NoticeList', '2019-11-06 11:12:32', '2019-11-06 11:12:32'), + (75, 2, '详情', 'notice-detail', 'noticeController.detail', 4, 'NoticeList', '2019-11-06 11:12:44', '2019-11-06 11:12:44'), + (76, 2, '发送', 'notice-send', 'noticeController.send', 5, 'NoticeList', '2019-11-06 11:12:51', '2019-11-06 11:12:51'), + (77, 2, '查询', 'person-notice-query', 'noticeController.queryReceiveByPage,noticeController.queryUnreadByPage,noticeController.queryByPage', 0, 'PersonNotice', '2019-11-06 11:13:27', '2019-11-06 11:13:27'), + (78, 2, '详情', 'person-notice-detail', 'noticeController.detail', 1, 'PersonNotice', '2019-11-06 11:13:35', '2019-11-06 11:13:35'), + (79, 2, '查询', 'email-query', 'emailController.queryByPage,emailController.detail', 0, 'EmailList', '2019-11-06 11:13:49', '2019-11-06 11:13:49'), + (80, 2, '新增', 'email-add', 'emailController.add', 1, 'EmailList', '2019-11-06 11:14:02', '2019-11-06 11:14:02'), + (81, 2, '编辑', 'email-update', 'emailController.update', 2, 'EmailList', '2019-11-06 11:14:08', '2019-11-06 11:14:08'), + (82, 2, '删除', 'email-delete', 'emailController.delete', 3, 'EmailList', '2019-11-06 11:14:16', '2019-11-06 11:14:16'), + (83, 2, '发送', 'email-send', 'emailController.send', 0, 'SendMail', '2019-11-06 11:14:40', '2019-11-06 11:14:40'), + (84, 2, '查询', 'user-operate-log-search', 'userOperateLogController.queryByPage', 0, 'UserOperateLog', '2019-11-06 11:15:04', '2019-11-06 11:15:04'), + (85, 2, '详情', 'user-operate-log-detail', 'userOperateLogController.detail', 1, 'UserOperateLog', '2019-11-06 11:15:16', '2019-11-06 11:15:16'), + (86, 2, '删除', 'user-operate-log-delete', 'userOperateLogController.delete', 2, 'UserOperateLog', '2019-11-06 11:15:25', '2019-11-06 11:15:25'), + (87, 2, '查询', 'user-login-log-search', 'userLoginLogController.queryByPage', 0, 'UserLoginLog', '2019-11-06 11:15:43', '2019-11-06 11:15:43'), + (88, 2, '删除', 'user-login-log-delete', 'userLoginLogController.delete', 1, 'UserLoginLog', '2019-11-06 11:15:49', '2019-11-06 11:15:49'), + (89, 2, '查询', 'online-user-search', 'userLoginLogController.queryUserOnLine', 0, 'OnlineUser', '2019-11-06 11:16:05', '2019-11-06 11:16:05'), + (90, 2, '查询任务', 'task-search', 'quartzController.query', 0, 'TaskList', '2019-11-06 11:16:24', '2019-11-06 11:16:24'), + (91, 2, '刷新任务', 'task-refresh', 'quartzController.query', 1, 'TaskList', '2019-11-06 11:16:50', '2019-11-06 11:16:50'), + (92, 2, '添加任务', 'task-add', 'quartzController.saveOrUpdateTask', 2, 'TaskList', '2019-11-06 11:17:04', '2019-11-06 11:17:04'), + (93, 2, '编辑任务', 'task-update', 'quartzController.saveOrUpdateTask', 3, 'TaskList', '2019-11-06 11:17:17', '2019-11-06 11:17:17'), + (94, 2, '暂停任务', 'task-pause', 'quartzController.pauseTask', 4, 'TaskList', '2019-11-06 11:17:25', '2019-11-06 11:17:25'), + (95, 2, '恢复任务', 'task-resume', 'quartzController.resumeTask', 5, 'TaskList', '2019-11-06 11:17:31', '2019-11-06 11:17:31'), + (96, 2, '立即运行任务', 'task-run', 'quartzController.runTask', 6, 'TaskList', '2019-11-06 11:17:38', '2019-11-06 11:17:38'), + (97, 2, '查看任务日志', 'task-query-log', 'quartzController.queryLog', 7, 'TaskList', '2019-11-06 11:17:47', '2019-11-06 11:17:47'), + (98, 2, '删除任务', 'task-delete', 'quartzController.deleteTask', 8, 'TaskList', '2019-11-06 11:17:53', '2019-11-06 11:17:53'), + (99, 2, '查询', 'smart-reload-search', 'smartReloadController.listAllReloadItem', 0, 'SmartReloadList', '2019-11-06 11:18:06', '2019-11-06 11:18:06'), + (100, 2, '执行reload', 'smart-reload-update', 'smartReloadController.updateByTag', 1, 'SmartReloadList', '2019-11-06 11:18:14', '2019-11-06 11:18:14'), + (101, 2, '查看执行结果', 'smart-reload-result', 'smartReloadController.queryReloadResult', 2, 'SmartReloadList', '2019-11-06 11:18:19', '2019-11-06 11:18:19'), + (102, 2, '查询任务', 'heart-beat-query', 'heartBeatController.query', 0, 'HeartBeatList', '2019-11-06 11:18:38', '2019-11-06 11:18:38'), + (103, 2, '查询', 'file-filePage-query', 'fileController.queryListByPage,fileController.localGetFile,fileController.downLoadById', 0, 'FileList', '2019-11-06 11:19:06', '2019-11-06 11:19:06'), + (104, 2, '上传', 'file-filePage-upload', 'fileController.qiNiuUpload,fileController.localUpload,fileController.aliYunUpload,fileController.saveFile', 1, 'FileList', '2019-11-06 11:19:36', '2019-11-06 11:19:36'), + (105, 2, '下载', 'file-filePage-download', 'fileController.downLoadById', 2, 'FileList', '2019-11-16 10:05:02', '2019-11-16 10:05:02'); +/*!40000 ALTER TABLE `t_privilege` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_quartz_task 结构 +DROP TABLE IF EXISTS `t_quartz_task`; +CREATE TABLE IF NOT EXISTS `t_quartz_task` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `task_name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务名称', + `task_bean` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'spring bean名称', + `task_params` varchar(1000) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '任务参数', + `task_cron` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '运行cron表达式', + `task_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '任务状态0:正常,1:暂停', + `remark` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 正在导出表 smart-admin-dev.t_quartz_task 的数据:~5 rows (大约) +DELETE FROM `t_quartz_task`; +/*!40000 ALTER TABLE `t_quartz_task` DISABLE KEYS */; +INSERT INTO `t_quartz_task` (`id`, `task_name`, `task_bean`, `task_params`, `task_cron`, `task_status`, `remark`, `update_time`, `create_time`) VALUES + (9, '2312332', 'exampleTask', '21314', '*/5 * * * * ?', 1, NULL, '2019-09-06 14:41:55', '2019-04-19 15:24:26'), + (13, '567', 'exampleTask', 'ads', '*/5 * * * * ?', 1, NULL, '2019-09-04 16:37:25', '2019-04-23 15:32:17'), + (21, '11', 'exampleTask', '11', '*/5 * * * * ?', 1, NULL, '2019-09-04 16:37:30', '2019-04-26 17:29:21'), + (22, '33', 'exampleTask', '333', '*/5 * * * * ?', 1, NULL, '2019-04-26 17:29:36', '2019-04-26 17:29:36'), + (23, '1', 'exampleTask', '3', '*/5 * * * * ?', 0, NULL, '2019-09-05 17:21:12', '2019-04-26 17:29:50'); +/*!40000 ALTER TABLE `t_quartz_task` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_quartz_task_log 结构 +DROP TABLE IF EXISTS `t_quartz_task_log`; +CREATE TABLE IF NOT EXISTS `t_quartz_task_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `task_id` int(11) NOT NULL COMMENT '任务id', + `task_name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '任务名称', + `task_params` varchar(1000) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '任务参数', + `process_status` tinyint(4) NOT NULL COMMENT '任务处理状态0:成功,1:失败', + `process_duration` bigint(11) NOT NULL DEFAULT '0' COMMENT '运行时长', + `process_log` text COLLATE utf8mb4_unicode_ci COMMENT '日志', + `ip_address` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '运行主机ip', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=732881 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 正在导出表 smart-admin-dev.t_quartz_task_log 的数据:~11 rows (大约) +DELETE FROM `t_quartz_task_log`; +/*!40000 ALTER TABLE `t_quartz_task_log` DISABLE KEYS */; +INSERT INTO `t_quartz_task_log` (`id`, `task_id`, `task_name`, `task_params`, `process_status`, `process_duration`, `process_log`, `ip_address`, `update_time`, `create_time`) VALUES + (732870, 9, '231233', '2131', 0, 5, NULL, '127.0.0.1', '2019-05-05 15:28:01', '2019-05-05 15:28:01'), + (732871, 9, '231233', '2131', 0, 32, NULL, '172.16.0.145', '2019-05-05 15:54:40', '2019-05-05 15:54:40'), + (732872, 22, '33', '333', 0, 31, NULL, '172.16.0.145', '2019-05-07 16:20:31', '2019-05-07 16:20:31'), + (732873, 9, '231233', '2131', 0, 304, NULL, '172.16.0.145', '2019-08-02 09:29:36', '2019-08-02 09:29:36'), + (732874, 9, '231233', '2131', 0, 24, NULL, '172.16.0.145', '2019-08-08 16:48:49', '2019-08-08 16:48:49'), + (732875, 9, '231233', '2131', 0, 147, NULL, '172.16.0.145', '2019-08-23 09:41:08', '2019-08-23 09:41:08'), + (732876, 9, '231233', '2131', 0, 610, NULL, '172.16.0.145', '2019-08-26 16:16:34', '2019-08-26 16:16:34'), + (732877, 9, '2312332', '2131', 0, 27, NULL, '172.16.0.145', '2019-09-05 14:34:51', '2019-09-05 14:34:51'), + (732878, 9, '2312332', '2131', 0, 5, NULL, '172.16.0.145', '2019-09-05 17:18:17', '2019-09-05 17:18:17'), + (732879, 9, '2312332', '2131', 0, 1, NULL, '172.16.0.145', '2019-09-05 17:20:15', '2019-09-05 17:20:15'), + (732880, 9, '2312332', '2131', 0, 5, NULL, '172.16.0.145', '2019-09-06 14:42:04', '2019-09-06 14:42:04'); +/*!40000 ALTER TABLE `t_quartz_task_log` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_reload_item 结构 +DROP TABLE IF EXISTS `t_reload_item`; +CREATE TABLE IF NOT EXISTS `t_reload_item` ( + `tag` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '项名称', + `args` varchar(255) DEFAULT NULL COMMENT '参数 可选', + `identification` varchar(255) CHARACTER SET utf8 NOT NULL COMMENT '运行标识', + `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`tag`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- 正在导出表 smart-admin-dev.t_reload_item 的数据:~1 rows (大约) +DELETE FROM `t_reload_item`; +/*!40000 ALTER TABLE `t_reload_item` DISABLE KEYS */; +INSERT INTO `t_reload_item` (`tag`, `args`, `identification`, `update_time`, `create_time`) VALUES + ('system_config', '234', 'xxxx', '2019-11-14 16:46:21', '2019-04-18 11:48:27'); +/*!40000 ALTER TABLE `t_reload_item` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_reload_result 结构 +DROP TABLE IF EXISTS `t_reload_result`; +CREATE TABLE IF NOT EXISTS `t_reload_result` ( + `tag` varchar(255) NOT NULL, + `identification` varchar(255) NOT NULL COMMENT '运行标识', + `args` varchar(255) DEFAULT NULL, + `result` tinyint(3) unsigned NOT NULL COMMENT '是否成功 ', + `exception` text, + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +-- 正在导出表 smart-admin-dev.t_reload_result 的数据:~126 rows (大约) +DELETE FROM `t_reload_result`; +/*!40000 ALTER TABLE `t_reload_result` DISABLE KEYS */; +INSERT INTO `t_reload_result` (`tag`, `identification`, `args`, `result`, `exception`, `create_time`) VALUES + ('system_config', '23', '', 1, NULL, '2019-09-07 17:26:04'), + ('system_config', '23', '', 1, NULL, '2019-09-07 17:28:16'), + ('system_config', '23', '', 1, NULL, '2019-09-07 17:35:39'), + ('system_config', '23', '', 1, NULL, '2019-09-07 17:42:58'), + ('system_config', '23', '', 1, NULL, '2019-09-09 08:30:13'), + ('system_config', '23', '', 1, NULL, '2019-09-11 10:38:19'), + ('system_config', '23', '', 1, NULL, '2019-09-11 10:42:46'), + ('system_config', '23', '', 1, NULL, '2019-09-11 10:49:27'), + ('system_config', '23', '', 1, NULL, '2019-09-11 11:09:10'), + ('system_config', '23', '', 1, NULL, '2019-09-11 11:10:06'), + ('system_config', '23', '', 1, NULL, '2019-09-11 11:18:17'), + ('system_config', '23', '', 1, NULL, '2019-09-11 11:41:18'), + ('system_config', '23', '', 1, NULL, '2019-09-11 11:45:41'), + ('system_config', '23', '', 1, NULL, '2019-09-11 11:46:37'), + ('system_config', '23', '', 1, NULL, '2019-09-11 11:50:35'), + ('system_config', '23', '', 1, NULL, '2019-09-11 14:55:00'), + ('system_config', '23', '', 1, NULL, '2019-09-11 15:26:19'), + ('system_config', '23', '', 1, NULL, '2019-09-11 15:35:51'), + ('system_config', '23', '', 1, NULL, '2019-09-11 15:36:19'), + ('system_config', '23', '', 1, NULL, '2019-09-11 15:36:53'), + ('system_config', '23', '', 1, NULL, '2019-09-11 15:37:58'), + ('system_config', '23', '', 1, NULL, '2019-09-11 15:41:37'), + ('system_config', '23', '', 1, NULL, '2019-09-16 10:12:29'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:14:08'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:18:24'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:23:07'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:24:17'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:30:17'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:31:40'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:32:34'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:52:31'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:55:10'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:55:47'), + ('system_config', '23', '', 1, NULL, '2019-09-20 17:58:49'), + ('system_config', '23', '', 1, NULL, '2019-09-21 10:53:47'), + ('system_config', '23', '', 1, NULL, '2019-09-22 18:24:21'), + ('system_config', '23', '', 1, NULL, '2019-09-24 09:04:42'), + ('system_config', '23', '', 1, NULL, '2019-10-15 11:06:12'), + ('system_config', '23', '', 1, NULL, '2019-10-15 11:22:10'), + ('system_config', '23', '', 1, NULL, '2019-10-15 16:42:16'), + ('system_config', '23', '', 1, NULL, '2019-10-19 15:18:54'), + ('system_config', '23', '', 1, NULL, '2019-10-19 16:50:10'), + ('system_config', '23', '', 1, NULL, '2019-10-21 15:52:25'), + ('system_config', '23', '', 1, NULL, '2019-10-23 10:24:38'), + ('system_config', '23', '', 1, NULL, '2019-10-23 10:28:45'), + ('system_config', '23', '', 1, NULL, '2019-10-23 16:35:45'), + ('system_config', '23', '', 1, NULL, '2019-10-23 16:38:48'), + ('system_config', '23', '', 1, NULL, '2019-10-25 08:52:22'), + ('system_config', '23', '', 1, NULL, '2019-10-28 16:04:30'), + ('system_config', '23', '', 1, NULL, '2019-10-30 19:59:24'), + ('system_config', '23', '', 1, NULL, '2019-10-31 14:29:26'), + ('system_config', '23', '', 1, NULL, '2019-10-31 14:35:38'), + ('system_config', '23', '', 1, NULL, '2019-10-31 15:58:39'), + ('system_config', '23', '', 1, NULL, '2019-10-31 17:34:48'), + ('system_config', '23', '', 1, NULL, '2019-11-01 11:23:26'), + ('system_config', '23', '', 1, NULL, '2019-11-01 14:55:34'), + ('system_config', '23', '', 1, NULL, '2019-11-02 08:49:44'), + ('system_config', '23', '', 1, NULL, '2019-11-02 09:40:52'), + ('system_config', '23', '', 1, NULL, '2019-11-02 09:42:48'), + ('system_config', '23', '', 1, NULL, '2019-11-02 09:47:38'), + ('system_config', '23', '', 1, NULL, '2019-11-02 09:50:57'), + ('system_config', '23', '', 1, NULL, '2019-11-02 09:51:32'), + ('system_config', '23', '', 1, NULL, '2019-11-02 09:51:48'), + ('system_config', '23', '', 1, NULL, '2019-11-02 15:48:21'), + ('system_config', '23', '', 1, NULL, '2019-11-02 20:48:44'), + ('system_config', '23', '', 1, NULL, '2019-11-02 21:27:50'), + ('system_config', '23', '', 1, NULL, '2019-11-03 22:10:32'), + ('system_config', '23', '', 1, NULL, '2019-11-03 22:10:32'), + ('system_config', '23', '', 1, NULL, '2019-11-04 09:10:24'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-05 10:24:51'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 11:22:42'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 11:25:54'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 11:27:04'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 11:28:00'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 11:34:06'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 11:34:43'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 11:53:11'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 11:56:05'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 13:52:39'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 15:29:29'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 16:05:36'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 16:06:13'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 16:13:22'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 16:19:38'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 16:21:37'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-06 16:22:23'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-08 08:50:08'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-08 13:37:34'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 08:35:08'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 08:54:38'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 09:00:32'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 09:01:24'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 09:24:16'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 09:26:46'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 09:43:13'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 09:44:48'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 10:28:30'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-09 11:24:19'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-11 09:40:42'), + ('system_config', '23', '4234234', 1, NULL, '2019-11-13 17:25:42'), + ('system_config', '23343', '2423', 1, NULL, '2019-11-13 20:29:19'), + ('system_config', '23343', '2423', 1, NULL, '2019-11-13 20:29:23'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 11:43:57'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 11:50:18'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 11:51:13'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 11:52:03'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 11:53:02'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 13:49:11'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 13:51:05'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 13:53:53'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 13:55:57'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 16:15:44'), + ('system_config', '23343', '234', 1, NULL, '2019-11-14 16:39:36'), + ('system_config', '23343234234', '234', 1, NULL, '2019-11-14 16:41:05'), + ('system_config', '23343234234', '234', 1, NULL, '2019-11-14 16:41:05'), + ('system_config', 'aaaa', '234', 1, NULL, '2019-11-14 16:41:20'), + ('system_config', 'aaaa', '234', 1, NULL, '2019-11-14 16:41:25'), + ('system_config', '111', '234', 1, NULL, '2019-11-14 16:43:20'), + ('system_config', '111', '234', 1, NULL, '2019-11-14 16:44:13'), + ('system_config', 'xxxx', '234', 1, NULL, '2019-11-14 16:46:26'), + ('system_config', 'xxxx', '234', 1, NULL, '2019-11-14 16:46:39'), + ('system_config', 'xxxx', '234', 1, NULL, '2019-11-14 16:48:47'), + ('system_config', 'xxxx', '234', 1, NULL, '2019-11-15 14:39:55'), + ('system_config', 'xxxx', '234', 1, NULL, '2019-11-16 08:47:43'), + ('system_config', 'xxxx', '234', 1, NULL, '2019-11-16 17:12:10'), + ('system_config', 'xxxx', '234', 1, NULL, '2019-11-16 18:02:57'); +/*!40000 ALTER TABLE `t_reload_result` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_role 结构 +DROP TABLE IF EXISTS `t_role`; +CREATE TABLE IF NOT EXISTS `t_role` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `role_name` varchar(20) NOT NULL COMMENT '角色名称', + `remark` varchar(255) DEFAULT NULL COMMENT '角色描述', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=50 DEFAULT CHARSET=utf8 COMMENT='角色表'; + +-- 正在导出表 smart-admin-dev.t_role 的数据:~14 rows (大约) +DELETE FROM `t_role`; +/*!40000 ALTER TABLE `t_role` DISABLE KEYS */; +INSERT INTO `t_role` (`id`, `role_name`, `remark`, `update_time`, `create_time`) VALUES + (1, '管理员', '', '2019-06-21 12:09:34', '2019-06-21 12:09:34'), + (34, '销售', '', '2019-08-30 09:30:50', '2019-08-30 09:30:50'), + (35, '总经理', '', '2019-08-30 09:31:05', '2019-08-30 09:31:05'), + (36, '董事长', '', '2019-08-30 09:31:11', '2019-08-30 09:31:11'), + (37, '财务', '', '2019-08-30 09:31:16', '2019-08-30 09:31:16'), + (38, '运营', '', '2019-08-30 09:31:22', '2019-08-30 09:31:22'), + (40, '测试角色1', '测试角色1', '2019-09-05 15:05:38', '2019-09-05 15:05:38'), + (41, '测试角色2', '测试角色2', '2019-09-05 15:05:43', '2019-09-05 15:05:43'), + (42, '测试角色3', '测试角色3', '2019-09-05 15:05:49', '2019-09-05 15:05:49'), + (43, '测试角色4', '测试角色4', '2019-09-05 15:05:56', '2019-09-05 15:05:56'), + (45, '测试角色6', '测试角色6', '2019-09-05 15:06:06', '2019-09-05 15:06:06'), + (46, '测试角色7', '测试角色7', '2019-09-05 15:06:18', '2019-09-05 15:06:18'), + (47, '测试角色8', '测试角色8', '2019-09-05 15:06:25', '2019-09-05 15:06:25'), + (48, '测试角色9', '测试角色9', '2019-11-15 17:06:11', '2019-09-05 15:06:30'); +/*!40000 ALTER TABLE `t_role` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_role_data_scope 结构 +DROP TABLE IF EXISTS `t_role_data_scope`; +CREATE TABLE IF NOT EXISTS `t_role_data_scope` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `data_scope_type` int(11) NOT NULL COMMENT '数据范围id', + `view_type` int(11) NOT NULL COMMENT '数据范围类型', + `role_id` int(11) NOT NULL COMMENT '角色id', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 正在导出表 smart-admin-dev.t_role_data_scope 的数据:~4 rows (大约) +DELETE FROM `t_role_data_scope`; +/*!40000 ALTER TABLE `t_role_data_scope` DISABLE KEYS */; +INSERT INTO `t_role_data_scope` (`id`, `data_scope_type`, `view_type`, `role_id`, `update_time`, `create_time`) VALUES + (5, 0, 2, 9, '2019-04-29 15:01:04', '2019-04-29 15:01:04'), + (14, 0, 2, 40, '2019-09-05 15:25:37', '2019-09-05 15:25:37'), + (15, 0, 0, 1, '2019-09-06 08:35:45', '2019-09-06 08:35:45'), + (16, 0, 3, 34, '2019-11-06 16:08:02', '2019-11-06 16:08:02'); +/*!40000 ALTER TABLE `t_role_data_scope` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_role_employee 结构 +DROP TABLE IF EXISTS `t_role_employee`; +CREATE TABLE IF NOT EXISTS `t_role_employee` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `role_id` int(11) NOT NULL COMMENT '角色id', + `employee_id` int(11) NOT NULL COMMENT '员工id', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=214 DEFAULT CHARSET=utf8mb4 COMMENT='角色员工功能表'; + +-- 正在导出表 smart-admin-dev.t_role_employee 的数据:~25 rows (大约) +DELETE FROM `t_role_employee`; +/*!40000 ALTER TABLE `t_role_employee` DISABLE KEYS */; +INSERT INTO `t_role_employee` (`id`, `role_id`, `employee_id`, `update_time`, `create_time`) VALUES + (121, 38, 22, '2019-09-04 09:23:09', '2019-09-04 09:23:09'), + (130, 1, 30, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (131, 1, 17, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (132, 1, 26, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (135, 1, 12, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (136, 1, 11, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (137, 1, 16, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (138, 1, 18, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (139, 1, 19, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (140, 1, 20, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (141, 1, 23, '2019-09-05 15:32:40', '2019-09-05 15:32:40'), + (147, 1, 35, '2019-09-06 09:00:27', '2019-09-06 09:00:27'), + (148, 40, 35, '2019-09-06 09:00:27', '2019-09-06 09:00:27'), + (165, 40, 32, '2019-11-08 10:39:35', '2019-11-08 10:39:35'), + (166, 34, 32, '2019-11-08 10:39:35', '2019-11-08 10:39:35'), + (167, 38, 32, '2019-11-08 10:39:35', '2019-11-08 10:39:35'), + (168, 38, 36, '2019-11-08 10:40:16', '2019-11-08 10:40:16'), + (169, 40, 36, '2019-11-08 10:40:16', '2019-11-08 10:40:16'), + (170, 37, 36, '2019-11-08 10:40:16', '2019-11-08 10:40:16'), + (174, 38, 37, '2019-11-08 11:05:39', '2019-11-08 11:05:39'), + (175, 42, 37, '2019-11-08 11:05:39', '2019-11-08 11:05:39'), + (188, 1, 1, '2019-11-15 16:05:33', '2019-11-15 16:05:33'), + (211, 40, 38, '2019-11-15 16:54:54', '2019-11-15 16:54:54'), + (212, 34, 29, '2019-11-16 18:04:04', '2019-11-16 18:04:04'), + (213, 45, 29, '2019-11-16 18:04:04', '2019-11-16 18:04:04'); +/*!40000 ALTER TABLE `t_role_employee` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_role_privilege 结构 +DROP TABLE IF EXISTS `t_role_privilege`; +CREATE TABLE IF NOT EXISTS `t_role_privilege` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `role_id` int(11) NOT NULL COMMENT '角色id', + `privilege_key` varchar(1000) NOT NULL COMMENT '权限key', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=10835 DEFAULT CHARSET=utf8mb4 COMMENT='角色权限功能表'; + +-- 正在导出表 smart-admin-dev.t_role_privilege 的数据:~322 rows (大约) +DELETE FROM `t_role_privilege`; +/*!40000 ALTER TABLE `t_role_privilege` DISABLE KEYS */; +INSERT INTO `t_role_privilege` (`id`, `role_id`, `privilege_key`, `update_time`, `create_time`) VALUES + (3506, 48, 'search-position', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3507, 48, 'add-position', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3508, 48, 'update-position', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3509, 48, 'delete-position', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3510, 48, 'add-role', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3511, 48, 'delete-role', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3512, 48, 'update-role', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3513, 48, 'update-role-privilege', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3514, 48, 'add-employee-role', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3515, 48, 'delete-employee-role', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3516, 48, 'delete-employee-role-batch', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3517, 48, 'search-employee-list', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3518, 48, 'query-data-scope', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3519, 48, 'update-data-scope', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3520, 48, 'add-department', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3521, 48, 'update-department', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3522, 48, 'delete-department', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3523, 48, 'search-department', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3524, 48, 'add-employee', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3525, 48, 'update-employee', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3526, 48, 'delete-employee', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3527, 48, 'disabled-employee', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3528, 48, 'reset-employee-password', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3529, 48, 'set-employee-role', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3530, 48, 'disabled-employee-batch', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3531, 48, 'update-employee-role', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3533, 48, 'system-params-search', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3534, 48, 'system-params-add', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3535, 48, 'system-config-update', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3536, 48, 'system-config-search', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3537, 48, 'privilegeMainSearch', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3538, 48, 'privilegeMainUpdate', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3539, 48, 'task-search', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3540, 48, 'task-refresh', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3541, 48, 'task-add', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3542, 48, 'task-update', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3543, 48, 'task-pause', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3544, 48, 'task-resume', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3545, 48, 'task-run', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3546, 48, 'task-query-log', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3547, 48, 'task-delete', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3548, 48, 'systemCodeVersionsQuery', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3552, 48, 'roleOneTwo-add', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3555, 48, 'apiDocument', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3557, 48, 'reload', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3559, 48, 'smart-reload-search', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3560, 48, 'smart-reload-update', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3561, 48, 'smart-reload-result', '2019-09-06 15:28:07', '2019-09-06 15:28:07'), + (3575, 45, 'task-search', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3576, 45, 'task-refresh', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3577, 45, 'task-add', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3578, 45, 'task-update', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3579, 45, 'task-pause', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3580, 45, 'task-resume', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3581, 45, 'task-run', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3582, 45, 'task-query-log', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3583, 45, 'task-delete', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3586, 45, 'add-role', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3587, 45, 'delete-role', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3588, 45, 'update-role', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3589, 45, 'update-role-privilege', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3590, 45, 'add-employee-role', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3591, 45, 'delete-employee-role', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3592, 45, 'delete-employee-role-batch', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3593, 45, 'search-employee-list', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3594, 45, 'query-data-scope', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3595, 45, 'update-data-scope', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3597, 45, 'search-position', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3598, 45, 'add-position', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3599, 45, 'update-position', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3600, 45, 'delete-position', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3602, 45, 'add-department', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3603, 45, 'set-employee-role', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3604, 45, 'update-department', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3605, 45, 'delete-department', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3606, 45, 'search-department', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3607, 45, 'add-employee', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3608, 45, 'update-employee', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3609, 45, 'disabled-employee', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3610, 45, 'disabled-employee-batch', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3611, 45, 'update-employee-role', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3612, 45, 'delete-employee', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (3613, 45, 'reset-employee-password', '2019-09-06 15:28:17', '2019-09-06 15:28:17'), + (8112, 41, 'SystemSetting', '2019-11-08 11:21:22', '2019-11-08 11:21:22'), + (8113, 41, 'SystemPrivilege', '2019-11-08 11:21:22', '2019-11-08 11:21:22'), + (8114, 41, 'privilege-main-update', '2019-11-08 11:21:22', '2019-11-08 11:21:22'), + (8115, 41, 'privilege-main-search', '2019-11-08 11:21:22', '2019-11-08 11:21:22'), + (8549, 35, 'SystemSetting', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8550, 35, 'SystemConfig', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8551, 35, 'SystemPrivilege', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8552, 35, 'Notice', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8553, 35, 'NoticeList', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8554, 35, 'PersonNotice', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8555, 35, 'Email', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8556, 35, 'EmailList', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8557, 35, 'UserLog', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8558, 35, 'UserOperateLog', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8559, 35, 'UserLoginLog', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8560, 35, 'system-config-search', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8561, 35, 'privilege-main-update', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8562, 35, 'privilege-main-search', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8563, 35, 'notice-query', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8564, 35, 'notice-add', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8565, 35, 'notice-edit', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8566, 35, 'notice-delete', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8567, 35, 'person-notice-query', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8568, 35, 'person-notice-detail', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8569, 35, 'email-query', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8570, 35, 'email-add', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8571, 35, 'email-update', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8572, 35, 'user-operate-log-search', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8573, 35, 'user-login-log-search', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (8574, 35, 'system-config-update', '2019-11-15 15:47:52', '2019-11-15 15:47:52'), + (9005, 37, 'SystemSetting', '2019-11-15 16:33:09', '2019-11-15 16:33:09'), + (9006, 37, 'SystemConfig', '2019-11-15 16:33:09', '2019-11-15 16:33:09'), + (9007, 37, 'system-params-search', '2019-11-15 16:33:09', '2019-11-15 16:33:09'), + (9008, 37, 'system-params-add', '2019-11-15 16:33:09', '2019-11-15 16:33:09'), + (9009, 37, 'system-config-update', '2019-11-15 16:33:09', '2019-11-15 16:33:09'), + (9368, 34, 'SystemSetting', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9369, 34, 'SystemConfig', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9370, 34, 'SystemPrivilege', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9371, 34, 'system-params-search', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9372, 34, 'system-params-add', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9373, 34, 'privilege-main-search', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9374, 34, 'Task', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9375, 34, 'TaskList', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9376, 34, 'task-search', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9377, 34, 'task-refresh', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9378, 34, 'task-add', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9379, 34, 'task-update', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9380, 34, 'task-pause', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9381, 34, 'task-resume', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9382, 34, 'task-run', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9383, 34, 'task-query-log', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9384, 34, 'task-delete', '2019-11-15 16:45:39', '2019-11-15 16:45:39'), + (9536, 42, 'Task', '2019-11-15 16:50:40', '2019-11-15 16:50:40'), + (9537, 42, 'TaskList', '2019-11-15 16:50:40', '2019-11-15 16:50:40'), + (9538, 42, 'task-search', '2019-11-15 16:50:40', '2019-11-15 16:50:40'), + (9539, 42, 'task-add', '2019-11-15 16:50:40', '2019-11-15 16:50:40'), + (9540, 42, 'task-update', '2019-11-15 16:50:40', '2019-11-15 16:50:40'), + (9541, 42, 'task-query-log', '2019-11-15 16:50:40', '2019-11-15 16:50:40'), + (9674, 38, 'Employee', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9675, 38, 'PositionList', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9676, 38, 'SystemSetting', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9677, 38, 'SystemConfig', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9678, 38, 'Notice', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9679, 38, 'PersonNotice', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9680, 38, 'Email', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9681, 38, 'EmailList', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9682, 38, 'SendMail', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9683, 38, 'Monitor', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9684, 38, 'OnlineUser', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9685, 38, 'Task', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9686, 38, 'TaskList', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9687, 38, 'KeepAlive', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9688, 38, 'KeepAliveContentList', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9689, 38, 'HeartBeat', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9690, 38, 'HeartBeatList', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9691, 38, 'File', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9692, 38, 'FileList', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9693, 38, 'search-position', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9694, 38, 'system-params-search', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9695, 38, 'system-config-update', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9696, 38, 'system-config-search', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9697, 38, 'person-notice-query', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9698, 38, 'person-notice-detail', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9699, 38, 'email-query', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9700, 38, 'email-send', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9701, 38, 'online-user-search', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9702, 38, 'task-search', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9703, 38, 'heart-beat-query', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9704, 38, 'file-filePage-query', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9705, 38, 'file-filePage-upload', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (9706, 38, 'task-refresh', '2019-11-15 16:53:47', '2019-11-15 16:53:47'), + (10585, 40, 'Employee', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10586, 40, 'RoleManage', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10587, 40, 'PositionList', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10588, 40, 'RoleEmployeeManage', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10589, 40, 'SystemSetting', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10590, 40, 'SystemConfig', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10591, 40, 'SystemPrivilege', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10592, 40, 'Notice', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10593, 40, 'NoticeList', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10594, 40, 'PersonNotice', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10595, 40, 'Email', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10596, 40, 'SendMail', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10597, 40, 'Task', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10598, 40, 'TaskList', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10599, 40, 'add-role', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10600, 40, 'delete-role', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10601, 40, 'update-role', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10602, 40, 'update-role-privilege', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10603, 40, 'add-employee-role', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10604, 40, 'search-employee-list', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10605, 40, 'delete-employee-role', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10606, 40, 'delete-employee-role-batch', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10607, 40, 'query-data-scope', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10608, 40, 'update-data-scope', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10609, 40, 'search-position', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10610, 40, 'add-position', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10611, 40, 'update-position', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10612, 40, 'search-department', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10613, 40, 'system-params-add', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10614, 40, 'system-config-search', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10615, 40, 'privilege-main-search', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10616, 40, 'notice-query', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10617, 40, 'notice-add', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10618, 40, 'notice-edit', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10619, 40, 'notice-delete', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10620, 40, 'notice-detail', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10621, 40, 'notice-send', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10622, 40, 'person-notice-query', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10623, 40, 'email-send', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10624, 40, 'task-search', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10625, 40, 'task-refresh', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10626, 40, 'task-add', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10627, 40, 'task-update', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10628, 40, 'task-query-log', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10629, 40, 'task-delete', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10630, 40, 'delete-department', '2019-11-15 17:19:42', '2019-11-15 17:19:42'), + (10733, 1, 'Employee', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10734, 1, 'RoleManage', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10735, 1, 'PositionList', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10736, 1, 'RoleEmployeeManage', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10737, 1, 'SystemSetting', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10738, 1, 'SystemConfig', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10739, 1, 'SystemPrivilege', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10740, 1, 'Notice', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10741, 1, 'NoticeList', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10742, 1, 'PersonNotice', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10743, 1, 'Email', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10744, 1, 'EmailList', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10745, 1, 'SendMail', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10746, 1, 'UserLog', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10747, 1, 'UserOperateLog', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10748, 1, 'UserLoginLog', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10749, 1, 'Monitor', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10750, 1, 'OnlineUser', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10751, 1, 'Sql', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10752, 1, 'Task', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10753, 1, 'TaskList', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10754, 1, 'Reload', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10755, 1, 'SmartReloadList', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10756, 1, 'ApiDoc', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10757, 1, 'Swagger', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10758, 1, 'ThreeRouter', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10759, 1, 'LevelTwo', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10760, 1, 'RoleOneTwo', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10761, 1, 'RoleTwoTwo', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10762, 1, 'RoleOneOne', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10763, 1, 'KeepAlive', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10764, 1, 'KeepAliveContentList', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10765, 1, 'KeepAliveAddContent', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10766, 1, 'HeartBeat', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10767, 1, 'HeartBeatList', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10768, 1, 'File', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10769, 1, 'FileList', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10770, 1, 'add-role', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10771, 1, 'delete-role', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10772, 1, 'update-role', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10773, 1, 'update-role-privilege', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10774, 1, 'add-employee-role', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10775, 1, 'search-employee-list', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10776, 1, 'delete-employee-role', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10777, 1, 'delete-employee-role-batch', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10778, 1, 'query-data-scope', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10779, 1, 'update-data-scope', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10780, 1, 'search-position', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10781, 1, 'add-position', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10782, 1, 'update-position', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10783, 1, 'delete-position', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10784, 1, 'add-department', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10785, 1, 'update-department', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10786, 1, 'delete-department', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10787, 1, 'search-department', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10788, 1, 'add-employee', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10789, 1, 'update-employee', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10790, 1, 'disabled-employee', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10791, 1, 'disabled-employee-batch', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10792, 1, 'update-employee-role', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10793, 1, 'reset-employee-password', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10794, 1, 'delete-employee', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10795, 1, 'system-params-search', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10796, 1, 'system-params-add', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10797, 1, 'system-config-update', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10798, 1, 'system-config-search', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10799, 1, 'privilege-main-update', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10800, 1, 'privilege-main-search', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10801, 1, 'notice-query', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10802, 1, 'notice-add', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10803, 1, 'notice-edit', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10804, 1, 'notice-delete', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10805, 1, 'notice-detail', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10806, 1, 'notice-send', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10807, 1, 'person-notice-query', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10808, 1, 'person-notice-detail', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10809, 1, 'email-query', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10810, 1, 'email-add', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10811, 1, 'email-update', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10812, 1, 'email-delete', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10813, 1, 'email-send', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10814, 1, 'user-operate-log-search', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10815, 1, 'user-operate-log-detail', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10816, 1, 'user-operate-log-delete', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10817, 1, 'user-login-log-search', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10818, 1, 'user-login-log-delete', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10819, 1, 'online-user-search', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10820, 1, 'task-search', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10821, 1, 'task-refresh', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10822, 1, 'task-add', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10823, 1, 'task-update', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10824, 1, 'task-pause', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10825, 1, 'task-resume', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10826, 1, 'task-run', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10827, 1, 'task-query-log', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10828, 1, 'task-delete', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10829, 1, 'smart-reload-search', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10830, 1, 'smart-reload-update', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10831, 1, 'smart-reload-result', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10832, 1, 'heart-beat-query', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10833, 1, 'file-filePage-query', '2019-11-16 18:04:10', '2019-11-16 18:04:10'), + (10834, 1, 'file-filePage-upload', '2019-11-16 18:04:10', '2019-11-16 18:04:10'); +/*!40000 ALTER TABLE `t_role_privilege` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_system_config 结构 +DROP TABLE IF EXISTS `t_system_config`; +CREATE TABLE IF NOT EXISTS `t_system_config` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `config_name` varchar(255) NOT NULL COMMENT '参数名字', + `config_key` varchar(255) NOT NULL COMMENT '参数key', + `config_value` text NOT NULL, + `config_group` varchar(255) NOT NULL COMMENT '参数类别', + `is_using` int(10) NOT NULL COMMENT '是否使用0 否 1 是', + `remark` varchar(255) DEFAULT NULL, + `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '上次修改时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC; + +-- 正在导出表 smart-admin-dev.t_system_config 的数据:~8 rows (大约) +DELETE FROM `t_system_config`; +/*!40000 ALTER TABLE `t_system_config` DISABLE KEYS */; +INSERT INTO `t_system_config` (`id`, `config_name`, `config_key`, `config_value`, `config_group`, `is_using`, `remark`, `update_time`, `create_time`) VALUES + (1, '超级管理员', 'employee_superman', '12,13,1', 'employee', 1, '123r8566456', '2019-11-14 16:40:48', '2018-08-18 16:28:03'), + (13, '本地上传URL前缀', 'local_upload_url_prefix', 'http://172.16.0.145/smartAdmin/file/', 'upload', 1, '', '2019-09-04 16:23:49', '2019-04-26 17:06:53'), + (14, '阿里云上传配置', 'ali_oss', '{"accessKeyId":"","accessKeySecret":"","bucketName":"sit","endpoint":"http://oss-cn-beijing.aliyuncs.com"}', 'upload', 1, 'eefwfwfds', '2019-11-16 18:04:30', '2019-05-11 18:00:06'), + (15, '邮件发配置', 'email_config', '{"password":"wy656112","smtpHost":"smtp.163.com","username":"simajq@163.com"}', 'email', 1, NULL, '2019-09-04 16:42:17', '2019-05-13 16:57:48'), + (16, '七牛云上传配置', 'qi_niu_oss', '{"accessKeyId":"rX7HgY1ZLpUD25JrA-uwMM_jj-","accessKeySecret":"","bucketName":"sun-smart-admin","endpoint":"http://puvpyay08.bkt.clouddn.com"}', 'upload', 1, NULL, '2019-11-16 18:04:42', '2019-07-19 16:05:56'), + (17, 'test', 'ww_1', 'ewr', '3', 1, 'testoo', '2019-11-08 09:43:36', '2019-11-08 09:27:19'), + (18, '4234', '42342', '423423', '23423', 1, '423423111111111111111111111111111111111111423423111111111111111111111111111111111111423423111111111111111111111111111111111111423423111111111111111111111111111111111111423423111111111111111111111111111111111111', '2019-11-14 14:58:39', '2019-11-14 11:22:49'), + (19, 'test323@', 'test', '123456', '11_', 1, 'gggggg', '2019-11-15 16:24:52', '2019-11-15 16:24:52'); +/*!40000 ALTER TABLE `t_system_config` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_user_login_log 结构 +DROP TABLE IF EXISTS `t_user_login_log`; +CREATE TABLE IF NOT EXISTS `t_user_login_log` ( + `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` int(11) NOT NULL COMMENT '员工id', + `user_name` varchar(50) NOT NULL COMMENT '用户名', + `remote_ip` varchar(50) DEFAULT NULL COMMENT '用户ip', + `remote_port` int(11) DEFAULT NULL COMMENT '用户端口', + `remote_browser` varchar(100) DEFAULT NULL COMMENT '浏览器', + `remote_os` varchar(50) DEFAULT NULL COMMENT '操作系统', + `login_status` tinyint(4) NOT NULL COMMENT '登录状态 0 失败 1成功', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`), + KEY `customer_id` (`user_id`) USING BTREE, + KEY `auditor_id` (`remote_browser`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=1742 DEFAULT CHARSET=utf8mb4 COMMENT='用户登录日志'; + +-- 正在导出表 smart-admin-dev.t_user_login_log 的数据:~122 rows (大约) +DELETE FROM `t_user_login_log`; +/*!40000 ALTER TABLE `t_user_login_log` DISABLE KEYS */; +INSERT INTO `t_user_login_log` (`id`, `user_id`, `user_name`, `remote_ip`, `remote_port`, `remote_browser`, `remote_os`, `login_status`, `update_time`, `create_time`) VALUES + (1501, 30, '耿为刚', '172.16.1.234', 61406, 'Chrome', 'Windows 10', 1, '2019-09-06 14:19:47', '2019-09-06 14:19:47'), + (1502, 30, '耿为刚', '172.16.1.234', 61405, 'Chrome', 'Windows 10', 1, '2019-09-06 14:20:46', '2019-09-06 14:20:46'), + (1503, 30, '耿为刚', '172.16.1.234', 62213, 'Chrome', 'Windows 10', 1, '2019-09-06 14:28:50', '2019-09-06 14:28:50'), + (1505, 30, '耿为刚', '172.16.1.234', 62478, 'Chrome', 'Windows 10', 1, '2019-09-06 14:32:57', '2019-09-06 14:32:57'), + (1506, 1, '管理员', '127.0.0.1', 55613, 'Chrome', 'Windows 10', 1, '2019-09-06 14:35:48', '2019-09-06 14:35:48'), + (1507, 1, '管理员', '172.16.1.234', 63132, 'Chrome', 'Windows 10', 1, '2019-09-06 14:38:43', '2019-09-06 14:38:43'), + (1508, 30, '耿为刚', '172.16.1.234', 63132, 'Chrome', 'Windows 10', 1, '2019-09-06 14:41:36', '2019-09-06 14:41:36'), + (1509, 1, '管理员', '172.16.1.234', 63332, 'Chrome', 'Windows 10', 1, '2019-09-06 14:42:37', '2019-09-06 14:42:37'), + (1511, 1, '管理员', '172.16.1.166', 29923, 'Chrome', 'Windows 10', 1, '2019-09-06 15:09:22', '2019-09-06 15:09:22'), + (1512, 1, '管理员', '172.16.1.113', 58150, 'Chrome', 'Windows 7', 1, '2019-09-06 15:23:31', '2019-09-06 15:23:31'), + (1513, 1, '管理员', '172.16.1.166', 31226, 'Chrome', 'Windows 10', 1, '2019-09-06 15:24:51', '2019-09-06 15:24:51'), + (1514, 1, '管理员', '172.16.1.113', 58300, 'Chrome', 'Windows 7', 1, '2019-09-06 15:25:04', '2019-09-06 15:25:04'), + (1515, 1, '管理员', '172.16.1.113', 58300, 'Chrome', 'Windows 7', 1, '2019-09-06 15:25:26', '2019-09-06 15:25:26'), + (1516, 1, '管理员', '172.16.1.166', 31243, 'Chrome', 'Windows 10', 1, '2019-09-06 15:25:29', '2019-09-06 15:25:29'), + (1517, 1, '管理员', '172.16.1.221', 61458, 'Chrome', 'Windows 10', 1, '2019-09-06 15:27:07', '2019-09-06 15:27:07'), + (1518, 1, '管理员', '172.16.1.166', 31243, 'Chrome', 'Windows 10', 1, '2019-09-06 15:27:09', '2019-09-06 15:27:09'), + (1519, 1, '管理员', '172.16.1.113', 58300, 'Chrome', 'Windows 7', 1, '2019-09-06 15:27:10', '2019-09-06 15:27:10'), + (1520, 1, '管理员', '172.16.1.166', 31551, 'Chrome', 'Windows 10', 1, '2019-09-06 15:30:01', '2019-09-06 15:30:01'), + (1521, 1, '管理员', '172.16.4.160', 50527, 'Chrome', 'Windows 10', 1, '2019-09-06 15:50:20', '2019-09-06 15:50:20'), + (1522, 1, '管理员', '172.16.1.166', 36381, 'Chrome', 'Windows 10', 1, '2019-09-06 16:20:46', '2019-09-06 16:20:46'), + (1523, 1, '管理员', '172.16.1.166', 40039, 'Chrome', 'Windows 10', 1, '2019-09-06 17:02:33', '2019-09-06 17:02:33'), + (1524, 1, '管理员', '172.16.1.166', 41014, 'Chrome', 'Windows 10', 1, '2019-09-06 17:16:09', '2019-09-06 17:16:09'), + (1525, 1, '管理员', '172.16.1.188', 56577, 'Chrome', 'Windows 7', 1, '2019-09-07 08:36:31', '2019-09-07 08:36:31'), + (1526, 1, '管理员', '172.16.1.48', 60852, 'Chrome', 'Windows 10', 1, '2019-09-07 08:45:02', '2019-09-07 08:45:02'), + (1527, 1, '管理员', '172.16.4.85', 4818, 'Chrome', 'Windows 10', 1, '2019-09-07 09:04:44', '2019-09-07 09:04:44'), + (1528, 1, '管理员', '172.16.4.85', 5230, 'Chrome', 'Windows 10', 1, '2019-09-07 09:25:41', '2019-09-07 09:25:41'), + (1529, 1, '管理员', '172.16.1.166', 10251, 'Chrome', 'Windows 10', 1, '2019-09-07 10:15:20', '2019-09-07 10:15:20'), + (1530, 1, '管理员', '172.16.1.48', 63877, 'Chrome', 'Windows 10', 1, '2019-09-07 11:26:19', '2019-09-07 11:26:19'), + (1531, 1, '管理员', '172.16.1.166', 26667, 'Chrome', 'Windows 10', 1, '2019-09-07 14:08:15', '2019-09-07 14:08:15'), + (1532, 1, '管理员', '172.16.4.85', 10604, 'Chrome', 'Windows 10', 1, '2019-09-07 14:08:33', '2019-09-07 14:08:33'), + (1533, 1, '管理员', '172.16.4.85', 10604, 'Chrome', 'Windows 10', 1, '2019-09-07 14:08:50', '2019-09-07 14:08:50'), + (1534, 1, '管理员', '172.16.1.166', 26812, 'Chrome', 'Windows 10', 1, '2019-09-07 14:14:09', '2019-09-07 14:14:09'), + (1535, 1, '管理员', '172.16.1.188', 52924, 'Chrome', 'Windows 7', 1, '2019-09-07 14:37:16', '2019-09-07 14:37:16'), + (1536, 1, '管理员', '172.16.1.188', 56721, 'Chrome', 'Windows 7', 1, '2019-09-07 14:49:37', '2019-09-07 14:49:37'), + (1537, 1, '管理员', '172.16.1.188', 52839, 'Chrome', 'Windows 7', 1, '2019-09-07 15:33:04', '2019-09-07 15:33:04'), + (1538, 1, '管理员', '172.16.1.166', 32489, 'Chrome', 'Windows 10', 1, '2019-09-07 15:48:02', '2019-09-07 15:48:02'), + (1539, 1, '管理员', '172.16.1.166', 32847, 'Chrome', 'Windows 10', 1, '2019-09-07 15:52:25', '2019-09-07 15:52:25'), + (1540, 1, '管理员', '172.16.1.166', 33456, 'Chrome', 'Windows 10', 1, '2019-09-07 16:00:01', '2019-09-07 16:00:01'), + (1541, 1, '管理员', '172.16.1.188', 61015, 'Chrome', 'Windows 7', 1, '2019-09-07 17:05:49', '2019-09-07 17:05:49'), + (1542, 1, '管理员', '127.0.0.1', 51566, 'Chrome', 'Windows 7', 1, '2019-09-07 17:31:20', '2019-09-07 17:31:20'), + (1543, 1, '管理员', '127.0.0.1', 54228, 'Chrome', 'Windows 7', 1, '2019-09-07 17:41:12', '2019-09-07 17:41:12'), + (1544, 1, '管理员', '127.0.0.1', 54957, 'Chrome', 'Windows 7', 1, '2019-09-07 17:43:21', '2019-09-07 17:43:21'), + (1545, 1, '管理员', '172.16.4.85', 2336, 'Chrome', 'Windows 10', 1, '2019-09-07 18:25:51', '2019-09-07 18:25:51'), + (1546, 1, '管理员', '127.0.0.1', 52161, 'Chrome', 'Windows 7', 1, '2019-09-09 08:30:47', '2019-09-09 08:30:47'), + (1547, 1, '管理员', '172.16.4.85', 5903, 'Chrome', 'Windows 10', 1, '2019-09-09 08:47:47', '2019-09-09 08:47:47'), + (1548, 1, '管理员', '172.16.1.243', 55673, 'Chrome', 'Windows 10', 1, '2019-09-09 11:25:02', '2019-09-09 11:25:02'), + (1549, 1, '管理员', '172.16.4.85', 4672, 'Chrome', 'Windows 10', 1, '2019-09-09 11:25:34', '2019-09-09 11:25:34'), + (1550, 1, '管理员', '172.16.1.188', 61186, 'Chrome', 'Windows 7', 1, '2019-09-09 11:39:24', '2019-09-09 11:39:24'), + (1551, 1, '管理员', '172.16.4.85', 3032, 'Chrome', 'Windows 10', 1, '2019-09-09 14:17:53', '2019-09-09 14:17:53'), + (1552, 1, '管理员', '172.16.4.85', 5829, 'Chrome', 'Windows 10', 1, '2019-09-09 14:54:27', '2019-09-09 14:54:27'), + (1553, 1, '管理员', '172.16.1.166', 23398, 'Chrome', 'Windows 10', 1, '2019-09-09 15:06:50', '2019-09-09 15:06:50'), + (1554, 1, '管理员', '172.16.5.60', 61094, 'Chrome', 'Windows 10', 1, '2019-09-09 15:20:50', '2019-09-09 15:20:50'), + (1555, 1, '管理员', '172.16.4.85', 10566, 'Chrome', 'Windows 10', 1, '2019-09-09 15:51:22', '2019-09-09 15:51:22'), + (1556, 1, '管理员', '172.16.1.166', 32190, 'Chrome', 'Windows 10', 1, '2019-09-09 17:00:59', '2019-09-09 17:00:59'), + (1557, 1, '管理员', '172.16.5.60', 54502, 'Chrome', 'Windows 10', 1, '2019-09-10 09:10:48', '2019-09-10 09:10:48'), + (1558, 1, '管理员', '172.16.4.85', 10659, 'Chrome', 'Windows 10', 1, '2019-09-10 09:21:48', '2019-09-10 09:21:48'), + (1559, 1, '管理员', '172.16.4.85', 3363, 'Chrome', 'Windows 10', 1, '2019-09-10 10:56:23', '2019-09-10 10:56:23'), + (1560, 1, '管理员', '172.16.4.85', 4460, 'Chrome', 'Windows 10', 1, '2019-09-10 14:23:44', '2019-09-10 14:23:44'), + (1561, 1, '管理员', '172.16.4.85', 7344, 'Chrome', 'Windows 10', 1, '2019-09-10 14:59:52', '2019-09-10 14:59:52'), + (1562, 1, '管理员', '172.16.5.89', 49996, 'Chrome', 'Windows 10', 1, '2019-09-10 18:08:04', '2019-09-10 18:08:04'), + (1563, 1, '管理员', '172.16.1.38', 50152, 'Chrome', 'Windows 10', 1, '2019-09-11 10:19:27', '2019-09-11 10:19:27'), + (1564, 1, '管理员', '172.16.1.38', 50173, 'Chrome', 'Windows 10', 1, '2019-09-11 10:20:38', '2019-09-11 10:20:38'), + (1565, 1, '管理员', '172.16.4.141', 60881, 'Chrome', 'Windows 10', 1, '2019-09-11 14:52:02', '2019-09-11 14:52:02'), + (1566, 1, '管理员', '172.16.4.93', 52688, 'Chrome', 'Windows 10', 1, '2019-09-11 15:15:14', '2019-09-11 15:15:14'), + (1567, 1, '管理员', '172.16.5.127', 54993, 'Chrome', 'Windows 10', 1, '2019-09-12 14:29:58', '2019-09-12 14:29:58'), + (1568, 1, '管理员', '172.16.5.127', 57424, 'Chrome', 'Windows 10', 1, '2019-09-12 15:26:46', '2019-09-12 15:26:46'), + (1569, 1, '管理员', '172.16.5.127', 58073, 'Chrome', 'Windows 10', 1, '2019-09-12 15:41:54', '2019-09-12 15:41:54'), + (1570, 1, '管理员', '172.16.5.146', 63230, 'Chrome', 'Windows 10', 1, '2019-09-16 10:17:15', '2019-09-16 10:17:15'), + (1571, 1, '管理员', '172.16.5.146', 52857, 'Chrome', 'Windows 10', 1, '2019-09-16 11:17:18', '2019-09-16 11:17:18'), + (1572, 1, '管理员', '172.16.1.190', 64527, 'Chrome', 'Windows 10', 1, '2019-09-19 14:06:45', '2019-09-19 14:06:45'), + (1573, 1, '管理员', '127.0.0.1', 53267, 'Chrome', 'Windows 7', 1, '2019-09-20 17:24:33', '2019-09-20 17:24:33'), + (1574, 1, '管理员', '127.0.0.1', 53267, 'Chrome', 'Windows 7', 1, '2019-09-20 17:24:43', '2019-09-20 17:24:43'), + (1575, 1, '管理员', '127.0.0.1', 53267, 'Chrome', 'Windows 7', 1, '2019-09-20 17:24:59', '2019-09-20 17:24:59'), + (1576, 1, '管理员', '127.0.0.1', 53267, 'Chrome', 'Windows 7', 1, '2019-09-20 17:26:05', '2019-09-20 17:26:05'), + (1577, 1, '管理员', '127.0.0.1', 60612, 'Chrome', 'Windows 7', 1, '2019-09-20 17:56:06', '2019-09-20 17:56:06'), + (1578, 1, '管理员', '172.16.1.202', 58066, 'Chrome', 'Windows 7', 1, '2019-09-22 18:25:03', '2019-09-22 18:25:03'), + (1579, 1, '管理员', '172.16.1.48', 52290, 'Chrome', 'Windows 10', 1, '2019-09-23 16:01:16', '2019-09-23 16:01:16'), + (1580, 1, '管理员', '172.16.4.141', 60997, 'Chrome', 'Windows 10', 1, '2019-09-23 17:16:55', '2019-09-23 17:16:55'), + (1581, 1, '管理员', '172.16.5.146', 53246, 'Chrome', 'Windows 10', 1, '2019-09-23 17:54:14', '2019-09-23 17:54:14'), + (1582, 1, '管理员', '127.0.0.1', 51987, 'Chrome', 'Windows 7', 1, '2019-09-24 09:16:37', '2019-09-24 09:16:37'), + (1583, 1, '管理员', '172.16.1.202', 55724, 'Chrome', 'Windows 7', 1, '2019-09-24 12:57:39', '2019-09-24 12:57:39'), + (1584, 1, '管理员', '172.16.1.166', 51876, 'Chrome', 'Windows 10', 1, '2019-09-24 16:24:37', '2019-09-24 16:24:37'), + (1585, 1, '管理员', '172.16.1.202', 51648, 'Chrome', 'Windows 7', 1, '2019-09-24 19:26:39', '2019-09-24 19:26:39'), + (1586, 1, '管理员', '172.16.1.234', 60984, 'Chrome', 'Windows 10', 1, '2019-09-26 10:52:07', '2019-09-26 10:52:07'), + (1587, 1, '管理员', '172.16.1.234', 63440, 'Chrome', 'Windows 10', 1, '2019-09-26 11:30:54', '2019-09-26 11:30:54'), + (1588, 1, '管理员', '172.16.1.202', 51956, 'Chrome', 'Windows 7', 1, '2019-09-27 20:55:08', '2019-09-27 20:55:08'), + (1589, 1, '管理员', '172.16.1.48', 56166, 'Chrome', 'Windows 10', 1, '2019-09-30 08:59:13', '2019-09-30 08:59:13'), + (1590, 1, '管理员', '172.16.1.202', 51448, 'Chrome', 'Windows 7', 1, '2019-09-30 09:00:13', '2019-09-30 09:00:13'), + (1591, 1, '管理员', '172.16.1.188', 62679, 'Chrome', 'Windows 7', 1, '2019-10-15 11:25:26', '2019-10-15 11:25:26'), + (1592, 1, '管理员', '172.16.1.234', 54034, 'Chrome', 'Windows 10', 1, '2019-10-18 10:47:14', '2019-10-18 10:47:14'), + (1593, 1, '管理员', '172.16.1.234', 64515, 'Chrome', 'Windows 10', 1, '2019-10-18 13:32:10', '2019-10-18 13:32:10'), + (1594, 1, '管理员', '172.16.1.234', 50211, 'Chrome', 'Windows 10', 1, '2019-10-18 13:56:19', '2019-10-18 13:56:19'), + (1595, 1, '管理员', '172.16.1.234', 55469, 'Chrome', 'Windows 10', 1, '2019-10-18 14:56:24', '2019-10-18 14:56:24'), + (1596, 1, '管理员', '172.16.1.234', 56392, 'Chrome', 'Windows 10', 1, '2019-10-18 15:08:25', '2019-10-18 15:08:25'), + (1597, 1, '管理员', '172.16.1.234', 60896, 'Chrome', 'Windows 10', 1, '2019-10-18 16:14:15', '2019-10-18 16:14:15'), + (1598, 1, '管理员', '172.16.1.234', 50590, 'Chrome', 'Windows 10', 1, '2019-10-19 08:38:54', '2019-10-19 08:38:54'), + (1599, 1, '管理员', '172.16.1.166', 4879, 'Chrome', 'Windows 10', 1, '2019-10-19 09:19:08', '2019-10-19 09:19:08'), + (1600, 1, '管理员', '172.16.1.188', 62895, 'Chrome', 'Windows 7', 1, '2019-10-19 13:49:29', '2019-10-19 13:49:29'), + (1601, 1, '管理员', '172.16.1.234', 58144, 'Chrome', 'Windows 10', 1, '2019-10-19 14:55:50', '2019-10-19 14:55:50'), + (1602, 1, '管理员', '127.0.0.1', 61033, 'Chrome', 'Windows 7', 1, '2019-10-19 15:19:38', '2019-10-19 15:19:38'), + (1603, 1, '管理员', '172.16.1.188', 58944, 'Chrome', 'Windows 7', 1, '2019-10-19 16:48:49', '2019-10-19 16:48:49'), + (1604, 1, '管理员', '172.16.1.188', 63950, 'Chrome', 'Windows 7', 1, '2019-10-21 08:10:38', '2019-10-21 08:10:38'), + (1605, 1, '管理员', '172.16.1.188', 64899, 'Chrome', 'Windows 7', 1, '2019-10-21 08:17:40', '2019-10-21 08:17:40'), + (1606, 1, '管理员', '172.16.1.221', 53180, 'Chrome', 'Windows 10', 1, '2019-10-21 15:52:36', '2019-10-21 15:52:36'), + (1607, 1, '管理员', '172.16.1.221', 56067, 'Chrome', 'Windows 10', 1, '2019-10-23 10:19:39', '2019-10-23 10:19:39'), + (1608, 1, '管理员', '172.16.1.221', 57692, 'Chrome', 'Windows 10', 1, '2019-10-23 16:36:39', '2019-10-23 16:36:39'), + (1609, 1, '管理员', '172.16.1.188', 57180, 'Chrome', 'Windows 7', 1, '2019-10-24 08:26:21', '2019-10-24 08:26:21'), + (1610, 1, '管理员', '172.16.0.196', 61409, 'Chrome', 'Windows 10', 1, '2019-10-24 08:26:55', '2019-10-24 08:26:55'), + (1611, 1, '管理员', '172.16.1.234', 51906, 'Chrome', 'Windows 10', 1, '2019-10-24 15:56:50', '2019-10-24 15:56:50'), + (1612, 1, '管理员', '172.16.1.234', 56793, 'Chrome', 'Windows 10', 1, '2019-10-24 17:04:54', '2019-10-24 17:04:54'), + (1613, 30, '耿为刚', '172.16.1.234', 60368, 'Chrome', 'Windows 10', 1, '2019-10-24 17:51:13', '2019-10-24 17:51:13'), + (1614, 1, '管理员', '172.16.1.234', 60368, 'Chrome', 'Windows 10', 1, '2019-10-24 17:51:56', '2019-10-24 17:51:56'), + (1615, 30, '耿为刚', '172.16.1.234', 60589, 'Chrome 65', 'Windows 10', 1, '2019-10-24 17:52:52', '2019-10-24 17:52:52'), + (1616, 1, '管理员', '172.16.1.234', 52998, 'Chrome', 'Windows 10', 1, '2019-10-25 09:28:13', '2019-10-25 09:28:13'), + (1617, 1, '管理员', '172.16.1.234', 54948, 'Chrome', 'Windows 10', 1, '2019-10-25 10:01:34', '2019-10-25 10:01:34'), + (1618, 1, '管理员', '172.16.1.234', 56800, 'Chrome', 'Windows 10', 1, '2019-10-25 10:32:53', '2019-10-25 10:32:53'), + (1619, 1, '管理员', '127.0.0.1', 59071, 'Chrome', 'Windows 7', 1, '2019-10-28 16:05:21', '2019-10-28 16:05:21'), + (1620, 1, '管理员', '127.0.0.1', 60106, 'Chrome', 'Windows 7', 1, '2019-10-28 16:11:29', '2019-10-28 16:11:29'), + (1621, 1, '管理员', '127.0.0.1', 63479, 'Chrome', 'Windows 7', 1, '2019-10-28 16:28:59', '2019-10-28 16:28:59'), + (1622, 1, '管理员', '127.0.0.1', 63479, 'Chrome', 'Windows 7', 1, '2019-10-28 16:29:55', '2019-10-28 16:29:55'), + (1623, 1, '管理员', '127.0.0.1', 57588, 'Chrome', 'Windows 7', 1, '2019-10-29 15:37:03', '2019-10-29 15:37:03'), + (1741, 1, '管理员', '127.0.0.1', 54621, 'Chrome', 'Windows 7', 1, '2019-11-16 18:03:45', '2019-11-16 18:03:45'); +/*!40000 ALTER TABLE `t_user_login_log` ENABLE KEYS */; + +-- 导出 表 smart-admin-dev.t_user_operate_log 结构 +DROP TABLE IF EXISTS `t_user_operate_log`; +CREATE TABLE IF NOT EXISTS `t_user_operate_log` ( + `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键', + `user_id` int(11) NOT NULL COMMENT '用户id', + `user_name` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户名称', + `module` varchar(50) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '操作模块', + `content` varchar(500) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '操作内容', + `url` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '请求路径', + `method` varchar(100) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '请求方法', + `param` text COLLATE utf8mb4_unicode_ci COMMENT '请求参数', + `result` tinyint(4) DEFAULT NULL COMMENT '请求结果 0失败 1成功', + `fail_reason` longtext COLLATE utf8mb4_unicode_ci COMMENT '失败原因', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +-- 正在导出表 smart-admin-dev.t_user_operate_log 的数据:~32 rows (大约) +DELETE FROM `t_user_operate_log`; +/*!40000 ALTER TABLE `t_user_operate_log` DISABLE KEYS */; +INSERT INTO `t_user_operate_log` (`id`, `user_id`, `user_name`, `module`, `content`, `url`, `method`, `param`, `result`, `fail_reason`, `update_time`, `create_time`) VALUES + (1, 1, '管理员', '管理端-角色权限', '获取角色可选的功能权限', '/smart-admin-api/privilege/listPrivilegeByRoleId/0', 'com.gangquan360.smartadmin.module.role.roleprivilege.RolePrivilegeController.listPrivilegeByRoleId', 'Long[0]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (2, 1, '管理员', '管理端-角色', '获取所有角色', '/smart-admin-api/role/getAll', 'com.gangquan360.smartadmin.module.role.basic.RoleController.getAllRole', '', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (3, 1, '管理员', '管理端-角色权限', '获取角色可选的功能权限', '/smart-admin-api/privilege/listPrivilegeByRoleId/1', 'com.gangquan360.smartadmin.module.role.roleprivilege.RolePrivilegeController.listPrivilegeByRoleId', 'Long[1]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (4, 1, '管理员', '管理端-岗位', '分页查询所有岗位', '/smart-admin-api/position/getListPage', 'com.gangquan360.smartadmin.module.position.PositionController.getJobPage', 'PositionQueryDTO[{"pageNum":1,"pageSize":10,"positionName":"","searchCount":true,"sort":false}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (5, 1, '管理员', '管理端-角色', '获取所有角色', '/smart-admin-api/role/getAll', 'com.gangquan360.smartadmin.module.role.basic.RoleController.getAllRole', '', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (6, 1, '管理员', '管理端-部门', '根据部门名称查询部门及员工列表', '/smart-admin-api/department/listEmployeeByDepartmentName', 'com.gangquan360.smartadmin.module.department.DepartmentController.listDepartmentEmployee', 'String[""]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (7, 1, '管理员', '管理端-部门', '查询部门及员工列表', '/smart-admin-api/department/listEmployee', 'com.gangquan360.smartadmin.module.department.DepartmentController.listDepartmentEmployee', '', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (8, 1, '管理员', '管理端-用户', '员工管理查询', '/smart-admin-api/employee/query', 'com.gangquan360.smartadmin.module.employee.EmployeeController.query', 'EmployeeQueryDTO[{"isDelete":0,"isDisabled":0,"keyword":"","pageNum":1,"pageSize":10}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (9, 1, '管理员', '管理端-用户', '员工重置密码', '/smart-admin-api/employee/resetPasswd/29', 'com.gangquan360.smartadmin.module.employee.EmployeeController.resetPasswd', 'Integer[29]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (10, 1, '管理员', '管理端-用户', '员工管理查询', '/smart-admin-api/employee/query', 'com.gangquan360.smartadmin.module.employee.EmployeeController.query', 'EmployeeQueryDTO[{"isDelete":0,"isDisabled":0,"keyword":"","pageNum":1,"pageSize":10}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (11, 1, '管理员', '管理端-角色用户', '通过员工id获取所有角色以及员工具有的角色', '/smart-admin-api/role/getRoles/29', 'com.gangquan360.smartadmin.module.role.roleemployee.RoleEmployeeController.getRoleByEmployeeId', 'Long[29]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (12, 1, '管理员', '管理端-用户', '单个员工角色授权', '/smart-admin-api/employee/updateRoles', 'com.gangquan360.smartadmin.module.employee.EmployeeController.updateRoles', 'EmployeeUpdateRolesDTO[{"employeeId":29,"roleIds":[34,45]}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (13, 1, '管理员', '管理端-用户', '员工管理查询', '/smart-admin-api/employee/query', 'com.gangquan360.smartadmin.module.employee.EmployeeController.query', 'EmployeeQueryDTO[{"isDelete":0,"isDisabled":0,"keyword":"","pageNum":1,"pageSize":10}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (14, 1, '管理员', '管理端-角色权限', '更新角色权限', '/smart-admin-api/privilege/updateRolePrivilege', 'com.gangquan360.smartadmin.module.role.roleprivilege.RolePrivilegeController.updateRolePrivilege', 'RolePrivilegeDTO[{"privilegeKeyList":["Employee","RoleManage","PositionList","RoleEmployeeManage","SystemSetting","SystemConfig","SystemPrivilege","Notice","NoticeList","PersonNotice","Email","EmailList","SendMail","UserLog","UserOperateLog","UserLoginLog","Monitor","OnlineUser","Sql","Task","TaskList","Reload","SmartReloadList","ApiDoc","Swagger","ThreeRouter","LevelTwo","RoleOneTwo","RoleTwoTwo","RoleOneOne","KeepAlive","KeepAliveContentList","KeepAliveAddContent","HeartBeat","HeartBeatList","File","FileList","add-role","delete-role","update-role","update-role-privilege","add-employee-role","search-employee-list","delete-employee-role","delete-employee-role-batch","query-data-scope","update-data-scope","search-position","add-position","update-position","delete-position","add-department","update-department","delete-department","search-department","add-employee","update-employee","disabled-employee","disabled-employee-batch","update-employee-role","reset-employee-password","delete-employee","system-params-search","system-params-add","system-config-update","system-config-search","privilege-main-update","privilege-main-search","notice-query","notice-add","notice-edit","notice-delete","notice-detail","notice-send","person-notice-query","person-notice-detail","email-query","email-add","email-update","email-delete","email-send","user-operate-log-search","user-operate-log-detail","user-operate-log-delete","user-login-log-search","user-login-log-delete","online-user-search","task-search","task-refresh","task-add","task-update","task-pause","task-resume","task-run","task-query-log","task-delete","smart-reload-search","smart-reload-update","smart-reload-result","heart-beat-query","file-filePage-query","file-filePage-upload"],"roleId":1}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (15, 1, '管理员', '管理端-角色权限', '获取角色可选的功能权限', '/smart-admin-api/privilege/listPrivilegeByRoleId/1', 'com.gangquan360.smartadmin.module.role.roleprivilege.RolePrivilegeController.listPrivilegeByRoleId', 'Long[1]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (16, 1, '管理员', '管理端-系统配置', '分页查询所有系统配置', '/smart-admin-api/systemConfig/getListPage', 'com.gangquan360.smartadmin.module.systemconfig.SystemConfigController.getSystemConfigPage', 'SystemConfigQueryDTO[{"key":"","pageNum":1,"pageSize":10}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (17, 1, '管理员', '管理端-系统配置', '修改配置参数', '/smart-admin-api/systemConfig/update', 'com.gangquan360.smartadmin.module.systemconfig.SystemConfigController.updateSystemConfig', 'SystemConfigUpdateDTO[{"configGroup":"upload","configKey":"ali_oss","configName":"阿里云上传配置","configValue":"{\\"accessKeyId\\":\\"\\",\\"accessKeySecret\\":\\"\\",\\"bucketName\\":\\"sit\\",\\"endpoint\\":\\"http://oss-cn-beijing.aliyuncs.com\\"}","id":14,"remark":"eefwfwfds"}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (18, 1, '管理员', '管理端-系统配置', '分页查询所有系统配置', '/smart-admin-api/systemConfig/getListPage', 'com.gangquan360.smartadmin.module.systemconfig.SystemConfigController.getSystemConfigPage', 'SystemConfigQueryDTO[{"key":"","pageNum":1,"pageSize":10}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (19, 1, '管理员', '管理端-系统配置', '修改配置参数', '/smart-admin-api/systemConfig/update', 'com.gangquan360.smartadmin.module.systemconfig.SystemConfigController.updateSystemConfig', 'SystemConfigUpdateDTO[{"configGroup":"upload","configKey":"qi_niu_oss","configName":"七牛云上传配置","configValue":"{\\"accessKeyId\\":\\"rX7HgY1ZLpUD25JrA-uwMM_jj-\\",\\"accessKeySecret\\":\\"\\",\\"bucketName\\":\\"sun-smart-admin\\",\\"endpoint\\":\\"http://puvpyay08.bkt.clouddn.com\\"}","id":16}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (20, 1, '管理员', '管理端-系统配置', '分页查询所有系统配置', '/smart-admin-api/systemConfig/getListPage', 'com.gangquan360.smartadmin.module.systemconfig.SystemConfigController.getSystemConfigPage', 'SystemConfigQueryDTO[{"key":"","pageNum":1,"pageSize":10}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (21, 1, '管理员', '通用-权限', '获取所有请求路径', '/smart-admin-api/privilege/getAllUrl', 'com.gangquan360.smartadmin.module.privilege.controller.PrivilegeController.getAllUrl', '', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (22, 1, '管理员', '通用-权限', '查询所有菜单项', '/smart-admin-api/privilege/menu/queryAll', 'com.gangquan360.smartadmin.module.privilege.controller.PrivilegeController.queryAll', '', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (23, 1, '管理员', '通用-权限', '查询菜单功能点', '/smart-admin-api/privilege/function/query/FileList', 'com.gangquan360.smartadmin.module.privilege.controller.PrivilegeController.functionQuery', 'String["FileList"]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (24, 1, '管理员', '通用-权限', '保存更新功能点', '/smart-admin-api/privilege/function/saveOrUpdate', 'com.gangquan360.smartadmin.module.privilege.controller.PrivilegeController.functionSaveOrUpdate', 'PrivilegeFunctionDTO[{"functionKey":"file-filePage-download","functionName":"下载","menuKey":"FileList","sort":2,"url":"fileController.downLoadById"}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (25, 1, '管理员', '通用-权限', '查询菜单功能点', '/smart-admin-api/privilege/function/query/FileList', 'com.gangquan360.smartadmin.module.privilege.controller.PrivilegeController.functionQuery', 'String["FileList"]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (26, 1, '管理员', '通用-邮件发送', '分页查询', '/smart-admin-api/email/page/query', 'com.gangquan360.smartadmin.module.email.EmailController.queryByPage', 'EmailQueryDTO[{"endDate":"","pageNum":1,"pageSize":10,"searchCount":true,"startDate":""}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (27, 1, '管理员', '管理端-用户操作日志', '分页查询', '/smart-admin-api/userOperateLog/page/query', 'com.gangquan360.smartadmin.module.log.useroperatelog.UserOperateLogController.queryByPage', 'UserOperateLogQueryDTO[{"endDate":"","pageNum":1,"pageSize":10,"searchCount":true,"sort":false,"startDate":"","userName":""}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (28, 1, '管理员', '管理端-用户登录日志', '分页查询用户登录日志', '/smart-admin-api/userLoginLog/page/query', 'com.gangquan360.smartadmin.module.log.userloginlog.UserLoginLogController.queryByPage', 'UserLoginLogQueryDTO[{"endDate":"","pageNum":1,"pageSize":10,"searchCount":true,"sort":false,"startDate":"","userName":""}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (29, 1, '管理员', '管理端-用户登录日志', '查询员工在线状态', '/smart-admin-api/userOnLine/query', 'com.gangquan360.smartadmin.module.log.userloginlog.UserLoginLogController.queryUserOnLine', 'EmployeeQueryDTO[{"actualName":"","employeeIds":[1],"isDelete":0,"pageNum":1,"pageSize":10}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (30, 1, '管理员', '管理端-任务调度', '查询任务', '/smart-admin-api/quartz/task/query', 'com.gangquan360.smartadmin.module.quartz.controller.QuartzController.query', 'QuartzQueryDTO[{"pageNum":1,"pageSize":10}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (31, 1, '管理员', '管理端-smart reload', '获取全部Smart-reload项', '/smart-admin-api/smartReload/all', 'com.gangquan360.smartadmin.module.smartreload.SmartReloadController.listAllReloadItem', '', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'), + (32, 1, '管理员', '通用-心跳服务', '查询心跳记录 @author zhuoda', '/smart-admin-api/heartBeat/query', 'com.gangquan360.smartadmin.module.heartbeat.HeartBeatController.query', 'PageParamDTO[{"pageNum":1,"pageSize":10}]', 1, NULL, '2019-11-01 00:00:00', '2019-11-01 00:00:00'); +/*!40000 ALTER TABLE `t_user_operate_log` ENABLE KEYS */; + +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IF(@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, @OLD_FOREIGN_KEY_CHECKS) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; diff --git a/java/smart-admin-api/src/main/resources/templates/codegenerator/Controller.java.vm b/java/smart-admin-api/src/main/resources/templates/codegenerator/Controller.java.vm new file mode 100644 index 00000000..a04de01b --- /dev/null +++ b/java/smart-admin-api/src/main/resources/templates/codegenerator/Controller.java.vm @@ -0,0 +1,64 @@ +package ${basePackage}.module.${modulePackage}.controller; + +import ${basePackage}.common.constant.SwaggerTagConst; +import ${basePackage}.common.domain.PageInfoDTO; +import ${basePackage}.common.domain.ResponseDTO; +import ${basePackage}.module.${modulePackage}.domain.dto.${moduleClass}DTO; +import ${basePackage}.module.${modulePackage}.domain.dto.${moduleClass}QueryDTO; +import ${basePackage}.module.${modulePackage}.service.${moduleClass}Service; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * [ ${tableDesc} ] + * + * @author ${author} + * @version 1.0 + * @company ${company} + * @copyright (c) 2019 ${company}Inc. All rights reserved. + * @date ${date} + * @since JDK1.8 + */ +@RestController +@Api(tags = {"${tableDesc}"}) +public class ${moduleClass}Controller { + + @Autowired + private ${moduleClass}Service ${moduleVar}Service; + + @ApiOperation(value = "分页查询${tableDesc}",notes = "@author ${author}") + @PostMapping("/${moduleVar}/page/query") + public ResponseDTO> queryByPage(@RequestBody ${moduleClass}QueryDTO queryDTO) { + return ${moduleVar}Service.queryByPage(queryDTO); + } + + @ApiOperation(value = "添加${tableDesc}",notes = "@author ${author}") + @PostMapping("/${moduleVar}/add") + public ResponseDTO add(@RequestBody @Valid ${moduleClass}DTO addTO){ + return ${moduleVar}Service.add(addTO); + } + + @ApiOperation(value="修改${tableDesc}",notes = "@author ${author}") + @PostMapping("/${moduleVar}/update") + public ResponseDTO update(@RequestBody @Valid ${moduleClass}DTO updateDTO){ + return ${moduleVar}Service.update(updateDTO); + } + + + @ApiOperation(value="删除${tableDesc}",notes = "@author ${author}") + @GetMapping("/${moduleVar}/delete/{id}") + public ResponseDTO delete(@PathVariable("id") Long id){ + return ${moduleVar}Service.delete(id); + } + + + @ApiOperation(value="详情${tableDesc}",notes = "@author ${author}") + @GetMapping("/${moduleVar}/detail/{id}") + public ResponseDTO<${moduleClass}DTO> detail(@PathVariable("id") Long id){ + return ${moduleVar}Service.detail(id); + } +} diff --git a/java/smart-admin-api/src/main/resources/templates/codegenerator/DTO.java.vm b/java/smart-admin-api/src/main/resources/templates/codegenerator/DTO.java.vm new file mode 100644 index 00000000..fa4e8d18 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/templates/codegenerator/DTO.java.vm @@ -0,0 +1,34 @@ +package ${basePackage}.module.${modulePackage}.domain.dto; +import lombok.Data; +#foreach ($dtoImport in $dtoImports) +$dtoImport +#end +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; + +/** + * [ ${tableDesc} ] + * + * @author ${author} + * @version 1.0 + * @company ${company} + * @copyright (c) 2018 ${company}Inc. All rights reserved. + * @date 2019/3/27 0027 下午 12:27 + * @since JDK1.8 + */ +@Data +public class ${moduleClass}DTO { + +#foreach ($column in $columnList) +#if($column.fieldType == 'Date') + @ApiModelProperty("${column.columnDesc}") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") + private $column.fieldType $column.fieldName; +#else + @ApiModelProperty("${column.columnDesc}") + private $column.fieldType $column.fieldName; +#end + +#end + +} diff --git a/java/smart-admin-api/src/main/resources/templates/codegenerator/Dao.java.vm b/java/smart-admin-api/src/main/resources/templates/codegenerator/Dao.java.vm new file mode 100644 index 00000000..c491c70d --- /dev/null +++ b/java/smart-admin-api/src/main/resources/templates/codegenerator/Dao.java.vm @@ -0,0 +1,48 @@ +package ${basePackage}.module.${modulePackage}.dao; + +import com.baomidou.mybatisplus.mapper.BaseMapper; +import com.baomidou.mybatisplus.plugins.pagination.Pagination; +import ${basePackage}.module.${modulePackage}.domain.dto.${moduleClass}QueryDTO; +import ${basePackage}.module.${modulePackage}.domain.entity.${moduleClass}Entity; +import ${basePackage}.utils.PaginationUtil; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * [ ${tableDesc} ] + * + * @author ${author} + * @version 1.0 + * @company ${company} + * @copyright (c) 2018 ${company}Inc. All rights reserved. + * @date ${date} + * @since JDK1.8 + */ +@Mapper +@Component +public interface ${moduleClass}Dao extends BaseMapper<${moduleClass}Entity> { + + /** + * 分页查询 + * @param queryDTO + * @return ${moduleClass}Entity + */ + List<${moduleClass}Entity> queryByPage(Pagination page, @Param("queryDTO") ${moduleClass}QueryDTO queryDTO); + + /** + * 根据id删除 + * @param id + * @return + */ + void deleteById(@Param("id") Long id); + + /** + * 批量删除 + * @param idList + * @return + */ + void deleteByIds(@Param("idList") List idList); +} diff --git a/java/smart-admin-api/src/main/resources/templates/codegenerator/Dao.xml.vm b/java/smart-admin-api/src/main/resources/templates/codegenerator/Dao.xml.vm new file mode 100644 index 00000000..f41cff53 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/templates/codegenerator/Dao.xml.vm @@ -0,0 +1,77 @@ + + + + + + + + + + + delete from ${tableName} where id = #{id} + + + + delete from ${tableName} where id in + + #{item} + + + + \ No newline at end of file diff --git a/java/smart-admin-api/src/main/resources/templates/codegenerator/Entity.java.vm b/java/smart-admin-api/src/main/resources/templates/codegenerator/Entity.java.vm new file mode 100644 index 00000000..fc07de61 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/templates/codegenerator/Entity.java.vm @@ -0,0 +1,35 @@ +package ${basePackage}.module.${modulePackage}.domain.entity; +import com.baomidou.mybatisplus.annotations.TableName; +import com.gangquan360.smartadmin.common.domain.BaseEntity; +#foreach ($entityImport in $entityImports) +$entityImport +#end +import lombok.Data; + +import java.io.Serializable; + +/** + * [ ${tableDesc} ] + * + * @author ${author} + * @version 1.0 + * @company ${company} + * @copyright (c) 2018 ${company}Inc. All rights reserved. + * @date ${date} + * @since JDK1.8 + */ +@Data +@TableName("${tableName}") +public class ${moduleClass}Entity extends BaseEntity{ + +#foreach ($column in $columnList) + +#if($column.columnName != 'id' && $column.fieldName != 'updateTime' && $column.fieldName != 'createTime') + /** + * $column.columnDesc + */ + private $column.fieldType $column.fieldName; +#end +#end + +} diff --git a/java/smart-admin-api/src/main/resources/templates/codegenerator/QueryDTO.java.vm b/java/smart-admin-api/src/main/resources/templates/codegenerator/QueryDTO.java.vm new file mode 100644 index 00000000..8ebf55bf --- /dev/null +++ b/java/smart-admin-api/src/main/resources/templates/codegenerator/QueryDTO.java.vm @@ -0,0 +1,43 @@ +package ${basePackage}.module.${modulePackage}.domain.dto; + +import ${basePackage}.common.domain.PageBaseDTO; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +#foreach ($queryImport in $queryImports) +$queryImport +#end + +/** + * [ ${tableDesc} ] + * + * @author ${author} + * @version 1.0 + * @company ${company} + * @copyright (c) 2019 ${company}Inc. All rights reserved. + * @date ${date} + * @since JDK1.8 + */ +@Data +public class ${moduleClass}QueryDTO extends PageBaseDTO { + +#foreach ($queryField in $queryFieldList) + +#if($queryField.sqlOperate == 'in') + @ApiModelProperty("${queryField.columnDesc}") + private List<${queryField.fieldType}> ${queryField.fieldName}List; +#elseif($queryField.sqlOperate == 'time_equals') + @ApiModelProperty("${queryField.columnDesc}") + private String ${queryField.fieldName}; +#elseif($queryField.sqlOperate == 'time_between') + @ApiModelProperty("开始日期") + private String startDate; + + @ApiModelProperty("结束日期") + private String endDate; +#else + @ApiModelProperty("${queryField.columnDesc}") + private ${queryField.fieldType} ${queryField.fieldName}; +#end + +#end +} diff --git a/java/smart-admin-api/src/main/resources/templates/codegenerator/Service.java.vm b/java/smart-admin-api/src/main/resources/templates/codegenerator/Service.java.vm new file mode 100644 index 00000000..88e418a7 --- /dev/null +++ b/java/smart-admin-api/src/main/resources/templates/codegenerator/Service.java.vm @@ -0,0 +1,95 @@ +package ${basePackage}.module.${modulePackage}.service; + +import com.baomidou.mybatisplus.plugins.Page; +import ${basePackage}.common.domain.PageInfoDTO; +import ${basePackage}.common.domain.ResponseDTO; +import ${basePackage}.module.${modulePackage}.dao.${moduleClass}Dao; +import ${basePackage}.module.${modulePackage}.domain.dto.${moduleClass}DTO; +import ${basePackage}.module.${modulePackage}.domain.dto.${moduleClass}QueryDTO; +import ${basePackage}.module.${modulePackage}.domain.entity.${moduleClass}Entity; +import ${basePackage}.utils.PaginationUtil; +import com.gangquan360.smartutil.bean.SmartBeanUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +/** + * [ ${tableDesc} ] + * + * @author ${author} + * @version 1.0 + * @company ${company} + * @copyright (c) 2019 ${company}Inc. All rights reserved. + * @date ${date} + * @since JDK1.8 + */ +@Service +public class ${moduleClass}Service { + + @Autowired + private ${moduleClass}Dao ${moduleVar}Dao; + + + /** + * @author ${author} + * @description 分页查询 + * @date ${date} + */ + public ResponseDTO> queryByPage(${moduleClass}QueryDTO queryDTO) { + Page page = PaginationUtil.convert2PageQueryInfo(queryDTO); + List<${moduleClass}Entity> entities = ${moduleVar}Dao.queryByPage(page, queryDTO); + List<${moduleClass}DTO> dtoList = SmartBeanUtil.copyList(entities, ${moduleClass}DTO.class); + page.setRecords(dtoList); + PageInfoDTO<${moduleClass}DTO> pageResultDTO = PaginationUtil.convert2PageInfoDTO(page); + return ResponseDTO.succData(pageResultDTO); + } + + /** + * @author ${author} + * @description 添加 + * @date ${date} + */ + public ResponseDTO add(${moduleClass}DTO addDTO) { + ${moduleClass}Entity entity = SmartBeanUtil.copy(addDTO, ${moduleClass}Entity.class); + ${moduleVar}Dao.insert(entity); + return ResponseDTO.succ(); + } + + + /** + * @author ${author} + * @description 编辑 + * @date ${date} + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO update(${moduleClass}DTO updateDTO) { + ${moduleClass}Entity entity = SmartBeanUtil.copy(updateDTO, ${moduleClass}Entity.class); + ${moduleVar}Dao.updateById(entity); + return ResponseDTO.succ(); + } + + + /** + * @author ${author} + * @description 删除 + * @date ${date} + */ + @Transactional(rollbackFor = Exception.class) + public ResponseDTO delete(Long id) { + ${moduleVar}Dao.deleteById(id); + return ResponseDTO.succ(); + } + + /** + * @author ${author} + * @description 根据ID查询 + * @date ${date} + */ + public ResponseDTO<${moduleClass}DTO> detail(Long id){ + ${moduleClass}Entity entity = ${moduleVar}Dao.selectById(id); + ${moduleClass}DTO dto = SmartBeanUtil.copy(entity,${moduleClass}DTO.class); + return ResponseDTO.succData(dto); + } +} diff --git a/java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/BaseTest.java b/java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/BaseTest.java new file mode 100644 index 00000000..65606abe --- /dev/null +++ b/java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/BaseTest.java @@ -0,0 +1,29 @@ +package com.gangquan360.smartadmin; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * 测试基类 + * + * @author lizongliang + * @date 2017/09/29 10:54 + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SmartAdminApplication.class,webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class BaseTest { + + @Before + public void before() { + System.out.println("测试开始------------------"); + } + + @After + public void after() { + System.out.println("测试结束------------------"); + } +} diff --git a/java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/SmartAdminApplicationTests.java b/java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/SmartAdminApplicationTests.java new file mode 100644 index 00000000..3113a8bb --- /dev/null +++ b/java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/SmartAdminApplicationTests.java @@ -0,0 +1,11 @@ +package com.gangquan360.smartadmin; + +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = SmartAdminApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +public class SmartAdminApplicationTests { + +} \ No newline at end of file diff --git a/java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/module/codegenerator/CodeGeneratorServiceTest.java b/java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/module/codegenerator/CodeGeneratorServiceTest.java new file mode 100644 index 00000000..b3a2ffde --- /dev/null +++ b/java/smart-admin-api/src/test/java/com/gangquan360/smartadmin/module/codegenerator/CodeGeneratorServiceTest.java @@ -0,0 +1,39 @@ +package com.gangquan360.smartadmin.module.codegenerator; + +import com.gangquan360.smartadmin.BaseTest; +import com.gangquan360.smartadmin.module.codegenerator.service.CodeGeneratorService; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; + +/** + * IdGeneratorService Tester. + * + * @author lizongliang + * @version 1.0 + */ +public class CodeGeneratorServiceTest extends BaseTest { + + @Autowired + private CodeGeneratorService codeGeneratorService; + + @Test + public void testGenerate() throws Exception { + // CodeGeneratorQueryColumnDTO createTimeBetween = CodeGeneratorQueryColumnDTO.builder() + // .columnName("create_time") + // .sqlOperate(SqlOperateTypeEnum.TIME_BETWEEN).build(); + // CodeGeneratorQueryColumnDTO like = CodeGeneratorQueryColumnDTO.builder() + // .columnName("title") + // .sqlOperate(SqlOperateTypeEnum.LIKE).build(); + // + // List queryColumnList = Lists.newArrayList(createTimeBetween,like); + // CodeGeneratorDTO codeGenerator = CodeGeneratorDTO.builder() + // .author("yandanyang") + // .company("钢圈") + // .tableName("t_notice") + // .tablePrefix("t_") + // .basePackage("com.gangquan360.smartadmin") + // .queryColumnList(queryColumnList).build(); + // codeGeneratorService.codeGenerator(codeGenerator); + } + +} diff --git a/java/smart-admin-parent/README.md b/java/smart-admin-parent/README.md new file mode 100644 index 00000000..28e28bed --- /dev/null +++ b/java/smart-admin-parent/README.md @@ -0,0 +1 @@ +admin的项目采用maven bom和maven module的形式 \ No newline at end of file diff --git a/java/smart-admin-parent/pom.xml b/java/smart-admin-parent/pom.xml new file mode 100644 index 00000000..10a279c9 --- /dev/null +++ b/java/smart-admin-parent/pom.xml @@ -0,0 +1,547 @@ + + + 4.0.0 + + com.gangquan360 + smart-admin-parent + 1.0.0 + pom + + + 1.8 + 3.3.0.ga + 2.10.0 + 2.1.9.RELEASE + Finchley.SR1 + 5.1.10.RELEASE + 2.0.5.RELEASE + 1.5.0 + 1.0.6 + 2.0.1 + 3.0.1.RELEASE + 3.0.2.RELEASE + 2.3.0 + 3.0.9.RELEASE + 1.7 + 2.7.0 + 1.3.0 + 6.3.2.jre8-preview + 1.2.9 + 8.18.0 + 23.1-jre + 1.2.3 + 2.7.0 + [7.2.0, 7.2.99] + 1.3.1 + 1.2.9 + 0.9.0 + 0.0.1-RC11 + 6.0.2.Final + 2.0.0.Final + 3.0.1-b08 + 1.0.29 + 3.3.2 + 2.1.6 + 1.0.4 + 1.4.2 + 2.0 + 1.0.0-SNAPSHOT + 2.0.2.RELEASE + 3.15 + 3.3.0 + 3.3.4 + 1.9.3 + 3.1.0 + 2.1.11.RELEASE + 2.1.11.RELEASE + 1.6.4 + 1.21 + 2.3.2 + 1.18.8 + 4.2.2 + + + + + + velocity + org.apache.velocity + ${velocity.version} + + + org.springframework + spring-framework-bom + ${spring-framework-bom.version} + pom + import + + + org.springframework.boot + spring-boot-dependencies + ${smartadmin.springboot.version} + pom + import + + + org.springframework.boot + spring-boot-starter-actuator + ${actuator.version} + + + org.springframework.boot + spring-boot-starter-quartz + 2.0.5.RELEASE + + + org.jolokia + jolokia-core + ${jolokia.version} + + + io.micrometer + micrometer-registry-influx + ${micrometer.version} + + + com.alibaba + fastjson + ${fastjson.version} + + + + + com.alibaba + druid + ${druid.version} + + + + + com.github.binarywang + weixin-java-mp + ${weixin-sdk.version} + + + + org.springframework.kafka + spring-kafka + ${kafka.version} + + + org.springframework.kafka + spring-kafka-test + ${kafka.version} + + + + + org.springframework.cloud + spring-cloud-dependencies + ${smartadmin.springcloud.version} + pom + import + + + + + org.hibernate + hibernate-validator + ${hibernate-validator-version} + + + + javax.validation + validation-api + ${javax.validation-version} + + + + org.glassfish + javax.el + ${javax.el-version} + + + + + org.apache.logging.log4j + log4j-web + ${log4j.web.version} + + + + + com.github.mxab.thymeleaf.extras + thymeleaf-extras-data-attribute + ${thymeleaf-extras-data-attribute.version} + + + org.thymeleaf.extras + thymeleaf-extras-java8time + ${thymeleaf-extras-java8time.version} + + + org.thymeleaf.extras + thymeleaf-extras-springsecurity4 + ${thymeleaf-extras-springsecurity4.version} + + + nz.net.ultraq.thymeleaf + thymeleaf-layout-dialect + ${thymeleaf-layout-dialect.version} + + + org.thymeleaf + thymeleaf + ${thymeleaf.version} + + + javassist + org.javassist + + + + + org.thymeleaf + thymeleaf-spring5 + ${thymeleaf.version} + + + + + + org.springframework.boot + spring-boot-starter-data-redis + ${smartadmin.springboot.version} + + + + org.springframework.boot + spring-boot-starter-test + ${smartadmin.springboot.version} + test + + + + + io.springfox + springfox-swagger2 + ${swagger.version} + + + + io.springfox + springfox-swagger-ui + ${swagger.version} + + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + ${mybatis-spring-boot.version} + + + + + com.microsoft.sqlserver + mssql-jdbc + ${sql-server.version} + + + + + com.alibaba + fastjson + ${fastjson.version} + + + + + com.netflix.feign + feign-gson + ${feign-gson-version} + + + com.google.code.gson + gson + 2.8.5 + + + + + org.springframework.boot + spring-boot-starter-cache + ${smartadmin.springboot.version} + + + + + com.google.guava + guava + ${guava-version} + + + + + com.github.pagehelper + pagehelper-spring-boot-starter + ${pagehelper-version} + + + + + com.aliyun.oss + aliyun-sdk-oss + ${oss.version} + + + com.qiniu + qiniu-java-sdk + ${qiniu.version} + + + commons-fileupload + commons-fileupload + ${fileupload.version} + + + + io.jsonwebtoken + jjwt + ${jjwt.version} + + + + + com.openhtmltopdf + openhtmltopdf-core + ${openhtml.version} + + + + + com.openhtmltopdf + openhtmltopdf-pdfbox + ${openhtml.version} + + + + + com.openhtmltopdf + openhtmltopdf-java2d + ${openhtml.version} + + + + + cn.afterturn + easypoi-base + ${easypoi-version} + + + + + cn.afterturn + easypoi-web + ${easypoi-version} + + + + cn.afterturn + easypoi-annotation + ${easypoi-version} + + + + org.apache.poi + poi + ${apache-poi-version} + + + + org.apache.poi + poi-ooxml-schemas + ${apache-poi-version} + + + + org.apache.poi + poi-ooxml + ${apache-poi-version} + + + + + cn.jpush.api + jpush-client + ${jpush-api-version} + + + commons-beanutils + commons-beanutils + ${commons-beanutils.version} + + + org.fusesource + sigar + ${sigar.version} + + + eu.bitwalker + UserAgentUtils + ${userAgent.version} + + + com.github.penggle + kaptcha + ${kaptcha.version} + + + + com.googlecode.concurrentlinkedhashmap + concurrentlinkedhashmap-lru + ${concurrentlinkedhashmap-version} + + + + org.apache.velocity + velocity-engine-core + ${velocity-engine-core.version} + test + + + + com.baomidou + mybatis-plus + ${mybatisplus.version} + + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + + + + com.baomidou + mybatisplus-spring-boot-starter + + + spring-boot-starter-logging + org.springframework.boot + + + ${mybatisplus-spring-boot-starter.version} + + + + org.projectlombok + lombok + ${lombok.version} + provided + + + + + + + + + src/main/java + + **/*.* + + + + false + src/main/resources + + dev/* + sit/* + pre/* + prod/* + + + + src/main/resources/${profiles.active} + true + + *.properties + + + + src/main/resources/${profiles.active} + false + + *.* + + + + + + + pl.project13.maven + git-commit-id-plugin + 2.2.4 + + + org.apache.maven.plugins + maven-compiler-plugin + + ${java.version} + ${java.version} + UTF-8 + + + + org.springframework.boot + spring-boot-maven-plugin + ${smartadmin.springboot.version} + + ${main-class} + + + + + repackage + + + + + + + + + + + + dev + + dev + + + true + + + + sit + + sit + + + + pre + + pre + + + + prod + + prod + + + + \ No newline at end of file