From 716b6303e316085564b695d1af6a77d278af67f5 Mon Sep 17 00:00:00 2001 From: zhuoda Date: Tue, 16 Jul 2024 00:20:02 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90V3.5.0=E3=80=911=E3=80=81=E3=80=90?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E3=80=91=E8=BD=BB=E9=87=8F=E7=BA=A7=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=20SmartJob;2=E3=80=81=E3=80=90?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E3=80=91=E7=AB=99=E5=86=85=E4=BF=A1;3?= =?UTF-8?q?=E3=80=81=E3=80=90=E6=96=B0=E5=A2=9E=E3=80=91=E4=B8=AA=E4=BA=BA?= =?UTF-8?q?=E4=B8=AD=E5=BF=83;4=E3=80=81=E3=80=90=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E3=80=91=E5=B2=97=E4=BD=8D=E7=AE=A1=E7=90=86;5=E3=80=81?= =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96=E3=80=91=E9=83=A8=E9=97=A8=E5=91=98?= =?UTF-8?q?=E5=B7=A5=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- smart-admin-api/pom.xml | 35 + .../admin/constant/AdminSwaggerTagConst.java | 3 + .../department/domain/vo/DepartmentVO.java | 8 + .../controller/EmployeeController.java | 14 + .../domain/entity/EmployeeEntity.java | 10 + .../employee/domain/form/EmployeeAddForm.java | 8 + .../domain/form/EmployeeUpdateAvatarForm.java | 28 + .../system/employee/domain/vo/EmployeeVO.java | 7 + .../employee/service/EmployeeService.java | 62 +- .../system/login/domain/RequestEmployee.java | 9 + .../system/login/service/LoginService.java | 23 + .../controller/PositionController.java | 75 + .../system/position/dao/PositionDao.java | 41 + .../domain/entity/PositionEntity.java | 61 + .../position/domain/form/PositionAddForm.java | 34 + .../domain/form/PositionQueryForm.java | 23 + .../domain/form/PositionUpdateForm.java | 24 + .../system/position/domain/vo/PositionVO.java | 40 + .../position/manager/PositionManager.java | 20 + .../position/service/PositionService.java | 105 + .../role/manager/RoleEmployeeManager.java | 2 +- .../support/AdminLoginLogController.java | 11 + .../support/AdminOperateLogController.java | 11 + .../support/AdminSmartJobController.java | 79 + .../src/main/resources/dev/application.yaml | 8 +- .../mapper/system/PositionMapper.xml | 25 + .../src/main/resources/pre/application.yaml | 6 - .../src/main/resources/prod/application.yaml | 6 - .../src/main/resources/test/application.yaml | 10 +- smart-admin-api/sa-base/pom.xml | 13 + .../serializer/DictValueVoSerializer.java | 2 +- .../serializer/enumeration/EnumSerialize.java | 25 + .../enumeration/EnumSerializer.java | 53 + .../sa/base/common/util/SmartIpUtil.java | 39 + .../lab1024/sa/base/config/SwaggerConfig.java | 54 +- .../sa/base/constant/SwaggerTagConst.java | 4 + .../base/handler/GlobalExceptionHandler.java | 6 - .../sa/base/listener/WebServerListener.java | 19 +- .../module/support/config/ConfigService.java | 12 +- .../job/api/SmartJobClientManager.java | 164 + .../support/job/api/SmartJobService.java | 246 + .../api/domain/SmartJobEnabledUpdateForm.java | 27 + .../job/api/domain/SmartJobExecuteForm.java | 28 + .../job/api/domain/SmartJobLogQueryForm.java | 34 + .../support/job/api/domain/SmartJobLogVO.java | 56 + .../support/job/api/domain/SmartJobMsg.java | 59 + .../job/api/domain/SmartJobQueryForm.java | 30 + .../job/api/domain/SmartJobUpdateForm.java | 63 + .../support/job/api/domain/SmartJobVO.java | 66 + .../job/config/SmartJobAutoConfiguration.java | 52 + .../support/job/config/SmartJobConfig.java | 39 + .../support/job/constant/SmartJobConst.java | 22 + .../job/constant/SmartJobTriggerTypeEnum.java | 30 + .../support/job/constant/SmartJobUtil.java | 188 + .../module/support/job/core/SmartJob.java | 28 + .../support/job/core/SmartJobExecutor.java | 147 + .../support/job/core/SmartJobLauncher.java | 148 + .../support/job/core/SmartJobScheduler.java | 178 + .../support/job/repository/SmartJobDao.java | 32 + .../job/repository/SmartJobLogDao.java | 32 + .../job/repository/SmartJobRepository.java | 42 + .../job/repository/domain/SmartJobEntity.java | 84 + .../repository/domain/SmartJobLogEntity.java | 81 + .../support/job/sample/SmartJobSample1.java | 29 + .../support/job/sample/SmartJobSample2.java | 48 + .../support/job/sample/package-info.java | 5 + .../loginlog/domain/LoginLogQueryForm.java | 6 + .../message/constant/MessageTemplateEnum.java | 31 + .../message/constant/MessageTypeEnum.java | 27 + .../message/controller/MessageController.java | 68 + .../support/message/dao/MessageDao.java | 46 + .../support/message/domain/MessageEntity.java | 70 + .../message/domain/MessageQueryForm.java | 44 + .../message/domain/MessageSendForm.java | 45 + .../domain/MessageTemplateSendForm.java | 41 + .../support/message/domain/MessageVO.java | 48 + .../message/service/MessageManager.java | 18 + .../message/service/MessageService.java | 108 + .../domain/OperateLogQueryForm.java | 5 + .../module/support/redis/RedissonService.java | 139 + .../reload/core/SmartReloadManager.java | 41 +- .../src/main/resources/dev/sa-base.yaml | 15 +- .../mapper/support/LoginLogMapper.xml | 9 + .../mapper/support/MessageMapper.xml | 56 + .../mapper/support/OperateLogMapper.xml | 6 + .../mapper/support/SmartJobLogMapper.xml | 35 + .../mapper/support/SmartJobMapper.xml | 28 + .../src/main/resources/pre/sa-base.yaml | 15 +- .../src/main/resources/prod/sa-base.yaml | 21 +- .../src/main/resources/test/sa-base.yaml | 22 +- .../.env.development | 2 +- .../javascript-ant-design-vue3/.env.test | 2 +- .../javascript-ant-design-vue3/package.json | 18 +- .../src/api/support/job-api.js | 34 + .../src/api/support/login-log-api.js | 4 + .../src/api/support/message-api.js | 16 + .../src/api/support/operate-log-api.js | 4 + .../src/api/system/employee-api.js | 12 + .../src/api/system/position-api.js | 55 + .../system/position-select/index.vue | 79 + .../src/config/app-config.js | 4 + .../business/message/message-const.js | 30 + .../src/constants/index.js | 4 + .../src/constants/layout-const.js | 11 + .../src/constants/support/job-const.js | 18 + .../src/constants/support/table-id-const.js | 3 + .../src/i18n/lang/en-US/index.js | 2 + .../src/i18n/lang/zh-CN/index.js | 2 + .../header-user-space/header-avatar.vue | 41 +- .../header-user-space/header-message.vue | 181 +- .../header-user-space/header-setting.vue | 78 +- .../components/header-user-space/index.vue | 22 +- .../page-tag/components/antd-tab.vue | 223 + .../page-tag/components/default-tab.vue | 222 + .../src/layout/components/page-tag/index.vue | 216 +- .../src/layout/side-expand-layout.vue | 24 +- .../src/layout/side-layout.vue | 12 +- .../javascript-ant-design-vue3/src/main.js | 1 + .../src/plugins/smart-enums-plugin.js | 3 + .../src/router/system/home.js | 9 + .../src/router/system/login.js | 2 +- .../src/store/modules/system/app-config.js | 4 +- .../src/store/modules/system/user.js | 31 +- .../src/theme/color.js | 26 +- .../src/theme/smart-admin.less | 16 +- .../components/category-tree-table.vue | 2 +- .../views/business/erp/goods/goods-list.vue | 34 +- .../components/enterprise-bank-list.vue | 36 +- .../components/enterprise-employee-list.vue | 10 +- .../components/enterprise-invoice-list.vue | 36 +- .../oa/enterprise/enterprise-list.vue | 30 +- .../oa/notice/notice-employee-list.vue | 73 +- .../views/business/oa/notice/notice-list.vue | 16 +- .../support/change-log/change-log-list.vue | 36 +- .../code-generator/code-generator-list.vue | 38 +- .../src/views/support/config/config-list.vue | 27 +- .../src/views/support/dict/index.vue | 39 +- .../src/views/support/file/file-list.vue | 46 +- .../support/heart-beat/heart-beat-list.vue | 38 +- .../management/components/help-doc-list.vue | 2 +- .../support/job/components/job-form-modal.vue | 248 + .../job/components/job-log-list-modal.vue | 200 + .../src/views/support/job/job-list.vue | 322 + .../support/login-fail/login-fail-list.vue | 28 +- .../support/login-log/login-log-list.vue | 38 +- .../support/operate-log/operate-log-list.vue | 38 +- .../src/views/system/account/account-menu.js | 39 + .../account/components/center/index.vue | 277 + .../account/components/login-log/index.vue | 192 + .../message/components/message-detail.vue | 46 + .../account/components/message/index.vue | 171 + .../account/components/notice/index.vue | 6 + .../account/components/operate-log/index.vue | 193 + .../account/components/password/index.vue | 88 + .../src/views/system/account/index.vue | 98 + .../components/department-form-modal.vue} | 0 .../system/department/department-list.vue | 258 + .../components/department-children/index.vue | 58 + .../components/department-tree/index.vue | 245 + .../employee-department-form-modal/index.vue | 0 .../components/employee-form-modal/index.vue | 232 + .../components/employee-list/index.vue | 412 + .../employee-password-dialog/index.vue | 0 .../{department => }/department-mitt.js | 0 .../employee/{department => }/index.vue | 12 +- .../src/views/system/login2/login.vue | 14 +- .../src/views/system/login3/login.vue | 14 +- .../src/views/system/menu/menu-list.vue | 30 +- .../views/system/position/position-form.vue | 124 + .../views/system/position/position-list.vue | 262 + .../role/components/role-data-scope/index.vue | 4 +- .../components/role-employee-list/index.vue | 274 + .../role/components/role-form-modal/index.vue | 22 +- .../role/components/role-list/index.vue | 116 + .../role/components/role-setting/index.vue | 0 .../role/components/role-tree/index.less | 0 .../role/components/role-tree/index.vue | 74 + .../role-tree/role-tree-checkbox.vue | 49 + .../components/role-tree/role-tree-menu.vue | 64 + .../components/role-tree/role-tree-point.vue | 0 .../system/{employee => }/role/index.vue | 0 .../.env.development | 8 + .../typescript-ant-design-vue3/.env.localhost | 8 + .../typescript-ant-design-vue3/.env.pre | 8 + .../.env.production | 8 + .../typescript-ant-design-vue3/.env.test | 8 + .../typescript-ant-design-vue3/.eslintignore | 17 + .../typescript-ant-design-vue3/.eslintrc.js | 76 + .../typescript-ant-design-vue3/.gitignore | 6 + .../typescript-ant-design-vue3/.prettierrc.js | 31 + .../.stylelintignore | 3 + .../.stylelintrc.js | 70 + .../typescript-ant-design-vue3/README.md | 2 - .../typescript-ant-design-vue3/index.html | 24 + .../typescript-ant-design-vue3/package.json | 85 + .../public/favicon.ico | Bin 0 -> 16958 bytes .../typescript-ant-design-vue3/src/App.vue | 38 + .../src/api/base-model/page-param-model.ts | 35 + .../src/api/base-model/page-result-model.ts | 50 + .../src/api/base-model/response-model.ts | 30 + .../src/api/base-model/sort-item-model.ts | 24 + .../src/api/business/category/category-api.js | 34 + .../src/api/business/goods/goods-api.js | 31 + .../src/api/business/message/message-api.js | 22 + .../src/api/business/oa/bank-api.js | 42 + .../src/api/business/oa/enterprise-api.js | 69 + .../src/api/business/oa/invoice-api.js | 44 + .../src/api/business/oa/notice-api.js | 74 + .../support/api-encrypt/api-encrypt-api.js | 40 + .../src/api/support/cache/cache-api.js | 25 + .../api/support/change-log/change-log-api.js | 45 + .../code-generator/code-generator-api.js | 46 + .../src/api/support/config/config-api.js | 29 + .../support/data-tracer/data-tracer-api.js | 18 + .../src/api/support/dict/dict-api.js | 59 + .../src/api/support/feedback/feedback-api.js | 21 + .../src/api/support/file/file-api.js | 38 + .../api/support/heart-beat/heart-beat-api.js | 17 + .../src/api/support/help-doc/help-doc-api.js | 59 + .../support/help-doc/help-doc-catalog-api.js | 32 + .../src/api/support/job/job-api.js | 30 + .../api/support/login-fail/login-fail-api.js | 26 + .../api/support/login-log/login-log-api.js | 17 + .../support/operate-log/operate-log-api.js | 21 + .../src/api/support/reload/reload-api.js | 25 + .../serial-number/serial-number-api.js | 25 + .../src/api/support/table/table-column-api.js | 26 + .../api/system/department/department-api.js | 55 + .../src/api/system/employee/employee-api.js | 98 + .../src/api/system/home/home-api.js | 29 + .../src/api/system/login/login-api.js | 51 + .../src/api/system/menu/menu-api.js | 54 + .../src/api/system/role-menu/role-menu-api.js | 28 + .../src/api/system/role/role-api.js | 110 + .../src/assets/images/1024lab/1024lab-gzh.jpg | Bin 0 -> 27898 bytes .../src/assets/images/1024lab/gzh.jpg | Bin 0 -> 27313 bytes .../assets/images/1024lab/xiaozhen-gzh.jpg | Bin 0 -> 8786 bytes .../assets/images/1024lab/zhuoda-wechat.jpg | Bin 0 -> 42080 bytes .../src/assets/images/login/ali-icon.png | Bin 0 -> 2506 bytes .../src/assets/images/login/blue-login-bg.png | Bin 0 -> 391076 bytes .../src/assets/images/login/douyin-icon.png | Bin 0 -> 3160 bytes .../src/assets/images/login/feishu-icon.png | Bin 0 -> 2608 bytes .../src/assets/images/login/google-icon.png | Bin 0 -> 3066 bytes .../src/assets/images/login/left-bg1.png | Bin 0 -> 362923 bytes .../src/assets/images/login/left-bg2.png | Bin 0 -> 239736 bytes .../src/assets/images/login/login-bg.png | Bin 0 -> 185224 bytes .../src/assets/images/login/login-bg2.png | Bin 0 -> 278769 bytes .../src/assets/images/login/login-bg3.png | Bin 0 -> 211157 bytes .../src/assets/images/login/login-bg4 .png | Bin 0 -> 403238 bytes .../login/login-form-open-eyes-close.png | Bin 0 -> 4914 bytes .../images/login/login-form-open-eyes.png | Bin 0 -> 6557 bytes .../src/assets/images/login/login-qr.png | Bin 0 -> 11297 bytes .../src/assets/images/login/qq-icon.png | Bin 0 -> 3697 bytes .../src/assets/images/login/wechat-icon.png | Bin 0 -> 3726 bytes .../src/assets/images/login/weibo-icon.png | Bin 0 -> 3388 bytes .../src/assets/images/logo/logo-min.png | Bin 0 -> 2079 bytes .../src/assets/images/logo/logo.png | Bin 0 -> 6053 bytes .../images/logo/smart-admin-logo-white.png | Bin 0 -> 8106 bytes .../assets/images/logo/smart-admin-logo.png | Bin 0 -> 14325 bytes .../src/assets/images/notice/edit_icon.png | Bin 0 -> 700 bytes .../src/assets/images/notice/file_icon.png | Bin 0 -> 488 bytes .../business/category-tree-select/index.vue | 85 + .../oa/enterprise-bank-select/index.vue | 109 + .../oa/enterprise-invoice-select/index.vue | 108 + .../business/oa/enterprise-select/index.vue | 85 + .../framework/area-cascader/index.vue | 91 + .../area-cascader/province-city-district.ts | 17546 ++++++++++++++++ .../framework/area-cascader/province-city.ts | 1727 ++ .../framework/boolean-select/index.vue | 81 + .../framework/icon-select/index.vue | 133 + .../framework/iframe/iframe-index.vue | 18 + .../iframe/route-default-component.vue | 3 + .../framework/smart-enum-checkbox/index.vue | 55 + .../framework/smart-enum-radio/index.vue | 63 + .../framework/smart-enum-select/index.vue | 68 + .../framework/smart-loading/index.ts | 20 + .../components/framework/wangeditor/index.vue | 109 + .../components/support/data-tracer/index.vue | 239 + .../support/dict-key-select/index.vue | 78 + .../components/support/dict-select/index.vue | 116 + .../support/file-preview-modal/index.vue | 83 + .../components/support/file-preview/index.vue | 79 + .../components/support/file-upload/index.vue | 199 + .../support/table-operator/index.vue | 163 + .../smart-table-column-merge.ts | 54 + .../smart-table-column-modal.vue | 280 + .../system/department-tree-select/index.vue | 58 + .../system/employee-select/index.vue | 97 + .../employee-table-select-modal/index.vue | 182 + .../system/menu-tree-select/index.vue | 76 + .../src/config/app-config.ts | 49 + .../constants/business/erp/category-const.ts | 25 + .../src/constants/business/erp/goods-const.ts | 28 + .../business/message/message-const.ts | 30 + .../constants/business/oa/enterprise-const.ts | 25 + .../src/constants/business/oa/notice-const.ts | 37 + .../src/constants/common-const.ts | 69 + .../src/constants/index.ts | 40 + .../src/constants/layout-const.ts | 33 + .../src/constants/local-storage-key-const.ts | 33 + .../src/constants/regular-const.ts | 28 + .../src/constants/support/change-log-const.ts | 32 + .../constants/support/code-generator-const.ts | 120 + .../constants/support/data-tracer-const.ts | 31 + .../src/constants/support/file-const.ts | 33 + .../src/constants/support/login-log-const.ts | 30 + .../src/constants/support/table-id-const.ts | 57 + .../src/constants/system/employee-const.ts | 30 + .../src/constants/system/home-const.ts | 15 + .../constants/system/login-device-const.ts | 34 + .../src/constants/system/menu-const.ts | 50 + .../src/directives/privilege.ts | 31 + .../src/i18n/index.ts | 41 + .../src/i18n/lang/en-US/index.ts | 17 + .../src/i18n/lang/zh-CN/index.ts | 17 + .../header-user-space/header-avatar.vue | 126 + .../header-user-space/header-message.vue | 116 + .../header-reset-password-modal/index.vue | 85 + .../header-user-space/header-setting.vue | 201 + .../components/header-user-space/index.vue | 108 + .../menu-location-breadcrumb/index.vue | 35 + .../page-tag/components/antd-tab.vue | 223 + .../page-tag/components/default-tab.vue | 221 + .../src/layout/components/page-tag/index.vue | 23 + .../components/side-expand-menu/index.vue | 51 + .../side-expand-menu/recursion-menu.vue | 101 + .../components/side-expand-menu/sub-menu.vue | 46 + .../components/side-expand-menu/top-menu.vue | 125 + .../components/contact-modal.vue | 102 + .../components/feedback-modal.vue | 85 + .../layout/components/side-help-doc/index.vue | 227 + .../src/layout/components/side-menu/index.vue | 118 + .../components/side-menu/recursion-menu.vue | 104 + .../layout/components/side-menu/sub-menu.vue | 45 + .../layout/components/smart-footer/index.vue | 34 + .../src/layout/smart-help-doc-layout.vue | 302 + .../src/layout/smart-keep-alive.ts | 39 + .../src/layout/smart-layout.vue | 24 + .../src/layout/smart-side-expand-layout.vue | 237 + .../src/layout/smart-side-layout.vue | 241 + .../src/lib/axios.ts | 282 + .../src/lib/default-time-ranges.ts | 83 + .../src/lib/encrypt.ts | 87 + .../src/lib/highlight-line-number.ts | 226 + .../src/lib/smart-sentry.ts | 24 + .../src/lib/smart-wartermark.ts | 114 + .../typescript-ant-design-vue3/src/main.ts | 90 + .../src/plugins/privilege-plugin.ts | 30 + .../src/plugins/smart-enums-plugin.ts | 80 + .../src/router/index.ts | 156 + .../src/router/routers.ts | 14 + .../src/router/support/help-doc.ts | 28 + .../src/router/system/home.ts | 40 + .../src/router/system/login.ts | 22 + .../src/shims-vue.d.ts | 29 + .../src/store/index.ts | 12 + .../src/store/modules/model/UserTagNav.ts | 36 + .../src/store/modules/system/app-config.ts | 57 + .../src/store/modules/system/role.ts | 95 + .../src/store/modules/system/spin.ts | 34 + .../src/store/modules/system/user.ts | 309 + .../src/theme/color/bezierEasing.less | 110 + .../src/theme/color/colorPalette.less | 81 + .../src/theme/color/colors.less | 162 + .../src/theme/color/tinyColor.less | 1184 ++ .../src/theme/default.less | 872 + .../src/theme/index.less | 154 + .../src/theme/smart-admin.less | 112 + .../src/types/config.d.ts | 62 + .../src/types/env.d.ts | 18 + .../src/types/json-viewer.d.ts | 11 + .../src/types/smart-enum.d.ts | 28 + .../src/types/user.d.ts | 57 + .../src/utils/cookie-util.ts | 29 + .../src/utils/local-util.ts | 21 + .../src/utils/str-util.ts | 46 + .../components/category-form-modal.vue | 96 + .../components/category-tree-table.vue | 163 + .../business/erp/catalog/custom-catalog.vue | 18 + .../business/erp/catalog/goods-catalog.vue | 18 + .../erp/goods/components/goods-form-modal.vue | 150 + .../views/business/erp/goods/goods-list.vue | 309 + .../components/message-handle-setup.js | 37 + .../message/components/receiver-select.vue | 105 + .../src/views/business/message/index.vue | 214 + .../components/enterprise-bank-list.vue | 239 + .../enterprise-bank-operate-modal.vue | 133 + .../components/enterprise-employee-list.vue | 275 + .../components/enterprise-invoice-list.vue | 243 + .../enterprise-invoice-operate-modal.vue | 127 + .../components/enterprise-operate-modal.vue | 243 + .../oa/enterprise/enterprise-detail.vue | 130 + .../oa/enterprise/enterprise-list.vue | 283 + .../notice/components/notice-form-drawer.vue | 307 + .../components/notice-form-visible-modal.vue | 71 + ...otice-form-visible-transfer-department.vue | 204 + .../notice-form-visible-transfer-employee.vue | 252 + .../components/notice-view-record-list.vue | 161 + .../business/oa/notice/notice-detail.vue | 144 + .../oa/notice/notice-employee-detail.vue | 153 + .../oa/notice/notice-employee-list.vue | 239 + .../views/business/oa/notice/notice-list.vue | 352 + .../support/api-encrypt/api-encrypt-index.vue | 260 + .../src/views/support/cache/cache-list.vue | 112 + .../support/change-log/change-log-form.vue | 138 + .../support/change-log/change-log-list.vue | 317 + .../support/change-log/change-log-modal.vue | 44 + .../code-generator/code-generator-list.vue | 178 + .../code-generator/code-generator-util.ts | 171 + ...code-generator-table-config-form-basic.vue | 275 + ...ode-generator-table-config-form-delete.vue | 128 + ...code-generator-table-config-form-field.vue | 222 + ...or-table-config-form-insert-and-update.vue | 293 + ...enerator-table-config-form-query-field.vue | 257 + ...enerator-table-config-form-table-field.vue | 150 + .../form/code-generator-table-config-form.vue | 225 + .../preview/code-generator-preview-modal.vue | 202 + .../support/config/config-form-modal.vue | 99 + .../src/views/support/config/config-list.vue | 170 + .../components/dict-key-operate-modal.vue | 95 + .../dict/components/dict-value-modal.vue | 221 + .../components/dict-value-operate-modal.vue | 101 + .../src/views/support/dict/index.vue | 237 + .../views/support/feedback/feedback-list.vue | 166 + .../src/views/support/file/file-list.vue | 292 + .../support/heart-beat/heart-beat-list.vue | 166 + .../help-doc-catalog-form-modal.vue | 132 + .../help-doc-catalog-tree-select.vue | 89 + .../components/help-doc-catalog-tree.vue | 354 + .../components/help-doc-form-drawer.vue | 204 + .../management/components/help-doc-list.vue | 267 + .../management/help-doc-manage-list.vue | 55 + .../help-doc/management/help-doc-mitt.ts | 11 + .../components/help-doc-view-record-list.vue | 168 + .../help-doc/user-view/help-doc-user-view.vue | 150 + .../src/views/support/job/job-list.vue | 239 + .../support/login-fail/login-fail-list.vue | 247 + .../support/login-log/login-log-list.vue | 194 + .../operate-log/operate-log-detail-modal.vue | 139 + .../support/operate-log/operate-log-list.vue | 220 + .../support/reload/do-reload-form-modal.vue | 90 + .../src/views/support/reload/reload-list.vue | 133 + .../support/reload/reload-result-list.vue | 100 + .../serial-number-generate-form-modal.vue | 107 + .../serial-number/serial-number-list.vue | 143 + .../serial-number-record-list.vue | 115 + .../src/views/system/40X/403.vue | 24 + .../src/views/system/40X/404.vue | 24 + .../account/components/center/index.vue | 7 + .../account/components/message/index.vue | 7 + .../account/components/password/index.vue | 7 + .../system/account/components/safe/index.vue | 7 + .../src/views/system/account/index.vue | 96 + .../employee/department-manage/index.vue | 252 + .../components/department-children/index.vue | 0 .../department-form-modal/index.vue | 138 + .../components/department-tree/index.vue | 112 +- .../employee-department-form-modal/index.vue | 94 + .../components/employee-form-modal/index.vue | 14 +- .../components/employee-list/index.vue | 12 +- .../employee-password-dialog/index.vue | 79 + .../employee/department/department-mitt.ts | 11 + .../system/employee/department/index.vue | 72 + .../role/components/role-data-scope/index.vue | 157 + .../components/role-employee-list/index.vue | 13 +- .../role/components/role-form-modal/index.vue | 111 + .../role/components/role-list/index.vue | 4 +- .../role/components/role-setting/index.vue | 44 + .../role/components/role-tree/index.less | 78 + .../role/components/role-tree/index.vue | 4 +- .../role-tree/role-tree-checkbox.vue | 6 +- .../components/role-tree/role-tree-menu.vue | 4 +- .../components/role-tree/role-tree-point.vue | 33 + .../src/views/system/employee/role/index.vue | 45 + .../system/home/components/changelog-card.vue | 107 + .../home/components/default-home-card.vue | 60 + .../home/components/echarts/category.vue | 92 + .../system/home/components/echarts/gauge.vue | 119 + .../home/components/echarts/gradient.vue | 210 + .../system/home/components/echarts/pie.vue | 78 + .../home/components/official-account-card.vue | 86 + .../quick-entry/home-quick-entry-modal.vue | 81 + .../quick-entry/home-quick-entry.vue | 149 + .../quick-entry/init-quick-entry-list.js | 27 + .../home/components/to-be-done-card.vue | 158 + .../src/views/system/home/home-header.vue | 159 + .../src/views/system/home/home-notice.vue | 129 + .../src/views/system/home/index.less | 65 + .../src/views/system/home/index.vue | 87 + .../src/views/system/login/login.less | 208 + .../src/views/system/login/login.vue | 241 + .../src/views/system/login2/login.less | 196 + .../src/views/system/login2/login.vue | 184 + .../src/views/system/login3/login.less | 204 + .../src/views/system/login3/login.vue | 186 + .../menu/components/menu-operate-modal.vue | 309 + .../menu/components/menu-tree-select.vue | 50 + .../views/system/menu/menu-data-handler.ts | 151 + .../system/menu/menu-list-table-columns.ts | 83 + .../src/views/system/menu/menu-list.vue | 258 + .../src/vite-env.d.ts | 1 + .../typescript-ant-design-vue3/tsconfig.json | 42 + .../typescript-ant-design-vue3/vite.config.ts | 65 + smart_admin_v3.sql | 609 +- 504 files changed, 59745 insertions(+), 1110 deletions(-) create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateAvatarForm.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/controller/PositionController.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/dao/PositionDao.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/entity/PositionEntity.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionAddForm.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionQueryForm.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionUpdateForm.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/vo/PositionVO.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/manager/PositionManager.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/service/PositionService.java create mode 100644 smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSmartJobController.java create mode 100644 smart-admin-api/sa-admin/src/main/resources/mapper/system/PositionMapper.xml create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/enumeration/EnumSerialize.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/enumeration/EnumSerializer.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/SmartJobClientManager.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/SmartJobService.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobEnabledUpdateForm.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobExecuteForm.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobLogQueryForm.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobLogVO.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobMsg.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobQueryForm.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobUpdateForm.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobVO.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/config/SmartJobAutoConfiguration.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/config/SmartJobConfig.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobConst.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobTriggerTypeEnum.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobUtil.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJob.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobExecutor.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobLauncher.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobScheduler.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobDao.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobLogDao.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobRepository.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/domain/SmartJobEntity.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/domain/SmartJobLogEntity.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/SmartJobSample1.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/SmartJobSample2.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/package-info.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/constant/MessageTemplateEnum.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/constant/MessageTypeEnum.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/controller/MessageController.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/dao/MessageDao.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageEntity.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageQueryForm.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageSendForm.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageTemplateSendForm.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageVO.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/service/MessageManager.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/service/MessageService.java create mode 100644 smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/redis/RedissonService.java create mode 100644 smart-admin-api/sa-base/src/main/resources/mapper/support/MessageMapper.xml create mode 100644 smart-admin-api/sa-base/src/main/resources/mapper/support/SmartJobLogMapper.xml create mode 100644 smart-admin-api/sa-base/src/main/resources/mapper/support/SmartJobMapper.xml create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/api/support/job-api.js create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/api/support/message-api.js create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/api/system/position-api.js create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/components/system/position-select/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/constants/business/message/message-const.js create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/constants/support/job-const.js create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/layout/components/page-tag/components/antd-tab.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/layout/components/page-tag/components/default-tab.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/support/job/components/job-form-modal.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/support/job/components/job-log-list-modal.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/support/job/job-list.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/account/account-menu.js create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/account/components/center/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/account/components/login-log/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/account/components/message/components/message-detail.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/account/components/message/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/account/components/notice/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/account/components/operate-log/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/account/components/password/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/account/index.vue rename smart-admin-web/javascript-ant-design-vue3/src/views/system/{employee/department/components/department-form-modal/index.vue => department/components/department-form-modal.vue} (100%) create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/department/department-list.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/employee/components/department-children/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/employee/components/department-tree/index.vue rename smart-admin-web/javascript-ant-design-vue3/src/views/system/employee/{department => }/components/employee-department-form-modal/index.vue (100%) create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/employee/components/employee-form-modal/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/employee/components/employee-list/index.vue rename smart-admin-web/javascript-ant-design-vue3/src/views/system/employee/{department => }/components/employee-password-dialog/index.vue (100%) rename smart-admin-web/javascript-ant-design-vue3/src/views/system/employee/{department => }/department-mitt.js (100%) rename smart-admin-web/javascript-ant-design-vue3/src/views/system/employee/{department => }/index.vue (82%) create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/position/position-form.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/position/position-list.vue rename smart-admin-web/javascript-ant-design-vue3/src/views/system/{employee => }/role/components/role-data-scope/index.vue (97%) create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/role/components/role-employee-list/index.vue rename smart-admin-web/javascript-ant-design-vue3/src/views/system/{employee => }/role/components/role-form-modal/index.vue (88%) create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/role/components/role-list/index.vue rename smart-admin-web/javascript-ant-design-vue3/src/views/system/{employee => }/role/components/role-setting/index.vue (100%) rename smart-admin-web/javascript-ant-design-vue3/src/views/system/{employee => }/role/components/role-tree/index.less (100%) create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/role/components/role-tree/index.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/role/components/role-tree/role-tree-checkbox.vue create mode 100644 smart-admin-web/javascript-ant-design-vue3/src/views/system/role/components/role-tree/role-tree-menu.vue rename smart-admin-web/javascript-ant-design-vue3/src/views/system/{employee => }/role/components/role-tree/role-tree-point.vue (100%) rename smart-admin-web/javascript-ant-design-vue3/src/views/system/{employee => }/role/index.vue (100%) create mode 100644 smart-admin-web/typescript-ant-design-vue3/.env.development create mode 100644 smart-admin-web/typescript-ant-design-vue3/.env.localhost create mode 100644 smart-admin-web/typescript-ant-design-vue3/.env.pre create mode 100644 smart-admin-web/typescript-ant-design-vue3/.env.production create mode 100644 smart-admin-web/typescript-ant-design-vue3/.env.test create mode 100644 smart-admin-web/typescript-ant-design-vue3/.eslintignore create mode 100644 smart-admin-web/typescript-ant-design-vue3/.eslintrc.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/.gitignore create mode 100644 smart-admin-web/typescript-ant-design-vue3/.prettierrc.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/.stylelintignore create mode 100644 smart-admin-web/typescript-ant-design-vue3/.stylelintrc.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/index.html create mode 100644 smart-admin-web/typescript-ant-design-vue3/package.json create mode 100644 smart-admin-web/typescript-ant-design-vue3/public/favicon.ico create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/App.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/base-model/page-param-model.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/base-model/page-result-model.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/base-model/response-model.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/base-model/sort-item-model.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/business/category/category-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/business/goods/goods-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/business/message/message-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/business/oa/bank-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/business/oa/enterprise-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/business/oa/invoice-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/business/oa/notice-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/api-encrypt/api-encrypt-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/cache/cache-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/change-log/change-log-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/code-generator/code-generator-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/config/config-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/data-tracer/data-tracer-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/dict/dict-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/feedback/feedback-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/file/file-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/heart-beat/heart-beat-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/help-doc/help-doc-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/help-doc/help-doc-catalog-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/job/job-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/login-fail/login-fail-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/login-log/login-log-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/operate-log/operate-log-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/reload/reload-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/serial-number/serial-number-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/support/table/table-column-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/system/department/department-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/system/employee/employee-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/system/home/home-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/system/login/login-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/system/menu/menu-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/system/role-menu/role-menu-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/api/system/role/role-api.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/1024lab/1024lab-gzh.jpg create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/1024lab/gzh.jpg create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/1024lab/xiaozhen-gzh.jpg create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/1024lab/zhuoda-wechat.jpg create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/ali-icon.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/blue-login-bg.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/douyin-icon.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/feishu-icon.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/google-icon.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/left-bg1.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/left-bg2.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/login-bg.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/login-bg2.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/login-bg3.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/login-bg4 .png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/login-form-open-eyes-close.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/login-form-open-eyes.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/login-qr.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/qq-icon.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/wechat-icon.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/login/weibo-icon.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/logo/logo-min.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/logo/logo.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/logo/smart-admin-logo-white.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/logo/smart-admin-logo.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/notice/edit_icon.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/assets/images/notice/file_icon.png create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/business/category-tree-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/business/oa/enterprise-bank-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/business/oa/enterprise-invoice-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/business/oa/enterprise-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/area-cascader/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/area-cascader/province-city-district.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/area-cascader/province-city.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/boolean-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/icon-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/iframe/iframe-index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/iframe/route-default-component.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/smart-enum-checkbox/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/smart-enum-radio/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/smart-enum-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/smart-loading/index.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/framework/wangeditor/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/support/data-tracer/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/support/dict-key-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/support/dict-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/support/file-preview-modal/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/support/file-preview/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/support/file-upload/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/support/table-operator/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/support/table-operator/smart-table-column-merge.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/support/table-operator/smart-table-column-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/system/department-tree-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/system/employee-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/system/employee-table-select-modal/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/components/system/menu-tree-select/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/config/app-config.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/business/erp/category-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/business/erp/goods-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/business/message/message-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/business/oa/enterprise-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/business/oa/notice-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/common-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/index.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/layout-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/local-storage-key-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/regular-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/support/change-log-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/support/code-generator-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/support/data-tracer-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/support/file-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/support/login-log-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/support/table-id-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/system/employee-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/system/home-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/system/login-device-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/constants/system/menu-const.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/directives/privilege.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/i18n/index.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/i18n/lang/en-US/index.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/i18n/lang/zh-CN/index.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/header-user-space/header-avatar.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/header-user-space/header-message.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/header-user-space/header-reset-password-modal/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/header-user-space/header-setting.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/header-user-space/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/menu-location-breadcrumb/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/page-tag/components/antd-tab.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/page-tag/components/default-tab.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/page-tag/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-expand-menu/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-expand-menu/recursion-menu.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-expand-menu/sub-menu.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-expand-menu/top-menu.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-help-doc/components/contact-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-help-doc/components/feedback-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-help-doc/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-menu/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-menu/recursion-menu.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/side-menu/sub-menu.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/components/smart-footer/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/smart-help-doc-layout.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/smart-keep-alive.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/smart-layout.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/smart-side-expand-layout.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/layout/smart-side-layout.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/lib/axios.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/lib/default-time-ranges.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/lib/encrypt.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/lib/highlight-line-number.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/lib/smart-sentry.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/lib/smart-wartermark.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/main.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/plugins/privilege-plugin.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/plugins/smart-enums-plugin.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/router/index.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/router/routers.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/router/support/help-doc.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/router/system/home.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/router/system/login.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/shims-vue.d.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/store/index.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/store/modules/model/UserTagNav.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/store/modules/system/app-config.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/store/modules/system/role.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/store/modules/system/spin.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/store/modules/system/user.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/theme/color/bezierEasing.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/theme/color/colorPalette.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/theme/color/colors.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/theme/color/tinyColor.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/theme/default.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/theme/index.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/theme/smart-admin.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/types/config.d.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/types/env.d.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/types/json-viewer.d.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/types/smart-enum.d.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/types/user.d.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/utils/cookie-util.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/utils/local-util.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/utils/str-util.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/erp/catalog/components/category-form-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/erp/catalog/components/category-tree-table.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/erp/catalog/custom-catalog.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/erp/catalog/goods-catalog.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/erp/goods/components/goods-form-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/erp/goods/goods-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/message/components/message-handle-setup.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/message/components/receiver-select.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/message/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/enterprise/components/enterprise-bank-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/enterprise/components/enterprise-bank-operate-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/enterprise/components/enterprise-employee-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/enterprise/components/enterprise-invoice-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/enterprise/components/enterprise-invoice-operate-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/enterprise/components/enterprise-operate-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-detail.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/enterprise/enterprise-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/notice/components/notice-form-drawer.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/notice/components/notice-form-visible-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/notice/components/notice-form-visible-transfer-department.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/notice/components/notice-form-visible-transfer-employee.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/notice/components/notice-view-record-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/notice/notice-detail.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/notice/notice-employee-detail.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/notice/notice-employee-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/business/oa/notice/notice-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/api-encrypt/api-encrypt-index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/cache/cache-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/change-log/change-log-form.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/change-log/change-log-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/change-log/change-log-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/code-generator-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/code-generator-util.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/components/form/code-generator-table-config-form-basic.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/components/form/code-generator-table-config-form-delete.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/components/form/code-generator-table-config-form-field.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/components/form/code-generator-table-config-form-insert-and-update.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/components/form/code-generator-table-config-form-query-field.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/components/form/code-generator-table-config-form-table-field.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/components/form/code-generator-table-config-form.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/code-generator/components/preview/code-generator-preview-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/config/config-form-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/config/config-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/dict/components/dict-key-operate-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/dict/components/dict-value-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/dict/components/dict-value-operate-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/dict/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/feedback/feedback-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/file/file-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/heart-beat/heart-beat-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/help-doc/management/components/help-doc-catalog-form-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/help-doc/management/components/help-doc-catalog-tree-select.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/help-doc/management/components/help-doc-catalog-tree.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/help-doc/management/components/help-doc-form-drawer.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/help-doc/management/components/help-doc-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/help-doc/management/help-doc-manage-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/help-doc/management/help-doc-mitt.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/help-doc/user-view/components/help-doc-view-record-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/help-doc/user-view/help-doc-user-view.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/job/job-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/login-fail/login-fail-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/login-log/login-log-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/operate-log/operate-log-detail-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/operate-log/operate-log-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/reload/do-reload-form-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/reload/reload-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/reload/reload-result-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/serial-number/serial-number-generate-form-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/serial-number/serial-number-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/support/serial-number/serial-number-record-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/40X/403.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/40X/404.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/account/components/center/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/account/components/message/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/account/components/password/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/account/components/safe/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/account/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/department-manage/index.vue rename smart-admin-web/{javascript-ant-design-vue3 => typescript-ant-design-vue3}/src/views/system/employee/department/components/department-children/index.vue (100%) create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/department/components/department-form-modal/index.vue rename smart-admin-web/{javascript-ant-design-vue3 => typescript-ant-design-vue3}/src/views/system/employee/department/components/department-tree/index.vue (62%) create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/department/components/employee-department-form-modal/index.vue rename smart-admin-web/{javascript-ant-design-vue3 => typescript-ant-design-vue3}/src/views/system/employee/department/components/employee-form-modal/index.vue (96%) rename smart-admin-web/{javascript-ant-design-vue3 => typescript-ant-design-vue3}/src/views/system/employee/department/components/employee-list/index.vue (96%) create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/department/components/employee-password-dialog/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/department/department-mitt.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/department/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/role/components/role-data-scope/index.vue rename smart-admin-web/{javascript-ant-design-vue3 => typescript-ant-design-vue3}/src/views/system/employee/role/components/role-employee-list/index.vue (97%) create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/role/components/role-form-modal/index.vue rename smart-admin-web/{javascript-ant-design-vue3 => typescript-ant-design-vue3}/src/views/system/employee/role/components/role-list/index.vue (97%) create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/role/components/role-setting/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/role/components/role-tree/index.less rename smart-admin-web/{javascript-ant-design-vue3 => typescript-ant-design-vue3}/src/views/system/employee/role/components/role-tree/index.vue (95%) rename smart-admin-web/{javascript-ant-design-vue3 => typescript-ant-design-vue3}/src/views/system/employee/role/components/role-tree/role-tree-checkbox.vue (91%) rename smart-admin-web/{javascript-ant-design-vue3 => typescript-ant-design-vue3}/src/views/system/employee/role/components/role-tree/role-tree-menu.vue (97%) create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/role/components/role-tree/role-tree-point.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/employee/role/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/changelog-card.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/default-home-card.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/echarts/category.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/echarts/gauge.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/echarts/gradient.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/echarts/pie.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/official-account-card.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/quick-entry/home-quick-entry-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/quick-entry/home-quick-entry.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/quick-entry/init-quick-entry-list.js create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/components/to-be-done-card.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/home-header.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/home-notice.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/index.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/home/index.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/login/login.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/login/login.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/login2/login.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/login2/login.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/login3/login.less create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/login3/login.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/menu/components/menu-operate-modal.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/menu/components/menu-tree-select.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/menu/menu-data-handler.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/menu/menu-list-table-columns.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/views/system/menu/menu-list.vue create mode 100644 smart-admin-web/typescript-ant-design-vue3/src/vite-env.d.ts create mode 100644 smart-admin-web/typescript-ant-design-vue3/tsconfig.json create mode 100644 smart-admin-web/typescript-ant-design-vue3/vite.config.ts diff --git a/smart-admin-api/pom.xml b/smart-admin-api/pom.xml index 1231a8ab..b08d256d 100644 --- a/smart-admin-api/pom.xml +++ b/smart-admin-api/pom.xml @@ -36,6 +36,7 @@ 3.12.0 4.4 1.13 + 1.9 2.12.0 3.3.2 5.2.4 @@ -52,6 +53,7 @@ 1.59 2.13.4 1.2.0 + 3.25.0 @@ -193,6 +195,12 @@ + + org.apache.commons + commons-text + ${commons-text.version} + + org.apache.logging.log4j log4j-spring-boot @@ -306,6 +314,33 @@ smartdb ${smartdb.version} + + + + org.redisson + redisson-spring-boot-starter + ${redisson.version} + + + org.springframework.boot + spring-boot-starter-actuator + + + org.redisson + redisson-spring-data-32 + + + objenesis + org.objenesis + + + + + org.redisson + redisson-spring-data-27 + ${redisson.version} + + diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java index 9388b482..c5319d63 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/constant/AdminSwaggerTagConst.java @@ -25,6 +25,7 @@ public class AdminSwaggerTagConst extends SwaggerTagConst { public static final String OA_INVOICE = "OA办公-发票信息"; public static final String OA_NOTICE = "OA办公-通知公告"; + } @@ -48,6 +49,8 @@ public class AdminSwaggerTagConst extends SwaggerTagConst { public static final String SYSTEM_ROLE_MENU = "系统-角色-菜单"; + public static final String SYSTEM_POSITION = "系统-职务管理"; + } diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentVO.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentVO.java index f52e28b5..3566f877 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentVO.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/department/domain/vo/DepartmentVO.java @@ -3,6 +3,8 @@ package net.lab1024.sa.admin.module.system.department.domain.vo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import java.time.LocalDateTime; + /** * 部门 * @@ -33,4 +35,10 @@ public class DepartmentVO { @Schema(description = "排序") private Integer sort; + @Schema(description = "更新时间") + private LocalDateTime updateTime; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + } diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/controller/EmployeeController.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/controller/EmployeeController.java index 05a6b41f..a79b4355 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/controller/EmployeeController.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/controller/EmployeeController.java @@ -52,6 +52,20 @@ public class EmployeeController { return employeeService.updateEmployee(employeeUpdateForm); } + @Operation(summary = "更新登录人信息 @author 善逸") + @PostMapping("/employee/update/login") + public ResponseDTO updateByLogin(@Valid @RequestBody EmployeeUpdateForm employeeUpdateForm) { + employeeUpdateForm.setEmployeeId(SmartRequestUtil.getRequestUserId()); + return employeeService.updateEmployee(employeeUpdateForm); + } + + @Operation(summary = "更新登录人头像 @author 善逸") + @PostMapping("/employee/update/avatar") + public ResponseDTO updateAvatar(@Valid @RequestBody EmployeeUpdateAvatarForm employeeUpdateAvatarForm) { + employeeUpdateAvatarForm.setEmployeeId(SmartRequestUtil.getRequestUserId()); + return employeeService.updateAvatar(employeeUpdateAvatarForm); + } + @Operation(summary = "更新员工禁用/启用状态 @author 卓大") @GetMapping("/employee/update/disabled/{employeeId}") @SaCheckPermission("system:employee:disabled") diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java index b84ba8b8..692f831a 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/entity/EmployeeEntity.java @@ -38,6 +38,11 @@ public class EmployeeEntity { */ private String actualName; + /** + * 头像 + */ + private String avatar; + /** * 性别 */ @@ -53,6 +58,11 @@ public class EmployeeEntity { */ private Long departmentId; + /** + * 职务级别ID + */ + private Long positionId; + /** * 是否为超级管理员: 0 不是,1是 */ diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeAddForm.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeAddForm.java index 367aa81c..bd7b4e63 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeAddForm.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeAddForm.java @@ -53,4 +53,12 @@ public class EmployeeAddForm { @Schema(description = "角色列表") private List roleIdList; + + @Schema(description = "备注") + @Length(max = 30, message = "备注最多200字符") + private String remark; + + @Schema(description = "职务级别ID") + private Long positionId; + } diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateAvatarForm.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateAvatarForm.java new file mode 100644 index 00000000..dc280542 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/form/EmployeeUpdateAvatarForm.java @@ -0,0 +1,28 @@ +package net.lab1024.sa.admin.module.system.employee.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.util.SmartVerificationUtil; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.Pattern; + +/** + * 修改登录人头像 + * + * @Author 1024创新实验室: 善逸 + * @Date 2024年6月30日00:26:35 + * @Wechat zhuoda1024 + * @Email lab1024@163.com + * @Copyright 1024创新实验室 + */ +@Data +public class EmployeeUpdateAvatarForm { + + @Schema(hidden = true) + private Long employeeId; + + @Schema(description = "头像") + @NotBlank(message = "头像不能为空哦") + private String avatar; +} diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/vo/EmployeeVO.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/vo/EmployeeVO.java index 42110a4d..5ab64c53 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/vo/EmployeeVO.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/domain/vo/EmployeeVO.java @@ -55,4 +55,11 @@ public class EmployeeVO { @Schema(description = "角色名称列表") private List roleNameList; + + @Schema(description = "职务ID") + private Long positionId; + + @Schema(description = "职务名称") + private String positionName; + } diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java index 1f734cb8..eb037d42 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/employee/service/EmployeeService.java @@ -12,6 +12,9 @@ import net.lab1024.sa.admin.module.system.employee.domain.entity.EmployeeEntity; import net.lab1024.sa.admin.module.system.employee.domain.form.*; import net.lab1024.sa.admin.module.system.employee.domain.vo.EmployeeVO; import net.lab1024.sa.admin.module.system.employee.manager.EmployeeManager; +import net.lab1024.sa.admin.module.system.login.service.LoginService; +import net.lab1024.sa.admin.module.system.position.dao.PositionDao; +import net.lab1024.sa.admin.module.system.position.domain.entity.PositionEntity; import net.lab1024.sa.admin.module.system.role.dao.RoleEmployeeDao; import net.lab1024.sa.admin.module.system.role.domain.vo.RoleEmployeeVO; import net.lab1024.sa.base.common.code.UserErrorCode; @@ -24,6 +27,7 @@ import net.lab1024.sa.base.common.util.SmartPageUtil; import net.lab1024.sa.base.module.support.securityprotect.service.ProtectPasswordService; import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.collections4.CollectionUtils; +import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -37,7 +41,7 @@ import java.util.stream.Collectors; * @Date 2021-12-29 21:52:46 * @Wechat zhuoda1024 * @Email lab1024@163.com - * @Copyright 1024创新实验室 + * @Copyright 1024创新实验室 */ @Service public class EmployeeService { @@ -62,6 +66,13 @@ public class EmployeeService { @Resource private ProtectPasswordService protectPasswordService; + @Resource + @Lazy + private LoginService loginService; + + @Resource + private PositionDao positionDao; + public EmployeeEntity getById(Long employeeId) { return employeeDao.selectById(employeeId); } @@ -69,7 +80,6 @@ public class EmployeeService { /** * 查询员工列表 - * */ public ResponseDTO> queryEmployee(EmployeeQueryForm employeeQueryForm) { employeeQueryForm.setDeletedFlag(false); @@ -86,16 +96,22 @@ public class EmployeeService { return ResponseDTO.ok(pageResult); } - List employeeIdList = employeeList.stream().map(EmployeeVO::getEmployeeId).collect(Collectors.toList()); // 查询员工角色 - List roleEmployeeEntityList = roleEmployeeDao.selectRoleByEmployeeIdList(employeeIdList); + List employeeIdList = employeeList.stream().map(EmployeeVO::getEmployeeId).collect(Collectors.toList()); + List roleEmployeeEntityList = employeeIdList.isEmpty() ? Collections.emptyList() : roleEmployeeDao.selectRoleByEmployeeIdList(employeeIdList); Map> employeeRoleIdListMap = roleEmployeeEntityList.stream().collect(Collectors.groupingBy(RoleEmployeeVO::getEmployeeId, Collectors.mapping(RoleEmployeeVO::getRoleId, Collectors.toList()))); Map> employeeRoleNameListMap = roleEmployeeEntityList.stream().collect(Collectors.groupingBy(RoleEmployeeVO::getEmployeeId, Collectors.mapping(RoleEmployeeVO::getRoleName, Collectors.toList()))); + // 查询员工职位 + List positionIdList = employeeList.stream().map(EmployeeVO::getPositionId).filter(Objects::nonNull).collect(Collectors.toList()); + List positionEntityList = positionIdList.isEmpty() ? Collections.emptyList() : positionDao.selectBatchIds(positionIdList); + Map positionNameMap = positionEntityList.stream().collect(Collectors.toMap(PositionEntity::getPositionId, PositionEntity::getPositionName)); + employeeList.forEach(e -> { e.setRoleIdList(employeeRoleIdListMap.getOrDefault(e.getEmployeeId(), Lists.newArrayList())); e.setRoleNameList(employeeRoleNameListMap.getOrDefault(e.getEmployeeId(), Lists.newArrayList())); e.setDepartmentName(departmentService.getDepartmentPath(e.getDepartmentId())); + e.setPositionName(positionNameMap.get(e.getPositionId())); }); PageResult pageResult = SmartPageUtil.convert2PageResult(pageParam, employeeList); return ResponseDTO.ok(pageResult); @@ -103,7 +119,6 @@ public class EmployeeService { /** * 新增员工 - * */ public synchronized ResponseDTO addEmployee(EmployeeAddForm employeeAddForm) { // 校验名称是否重复 @@ -143,7 +158,6 @@ public class EmployeeService { /** * 更新员工 - * */ public synchronized ResponseDTO updateEmployee(EmployeeUpdateForm employeeUpdateForm) { @@ -183,12 +197,38 @@ public class EmployeeService { // 更新数据 employeeManager.updateEmployee(entity, employeeUpdateForm.getRoleIdList()); + // 清除员工缓存 + loginService.clearLoginEmployeeCache(employeeId); + + return ResponseDTO.ok(); + } + + + /** + * 更新登录人头像 + * + * @param employeeUpdateAvatarForm + * @return + */ + public ResponseDTO updateAvatar(EmployeeUpdateAvatarForm employeeUpdateAvatarForm) { + Long employeeId = employeeUpdateAvatarForm.getEmployeeId(); + EmployeeEntity employeeEntity = employeeDao.selectById(employeeId); + if (employeeEntity == null) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + // 更新头像 + EmployeeEntity updateEntity = new EmployeeEntity(); + updateEntity.setEmployeeId(employeeId); + updateEntity.setAvatar(employeeUpdateAvatarForm.getAvatar()); + employeeDao.updateById(updateEntity); + + // 清除员工缓存 + loginService.clearLoginEmployeeCache(employeeId); return ResponseDTO.ok(); } /** * 更新禁用/启用状态 - * */ public ResponseDTO updateDisableFlag(Long employeeId) { if (null == employeeId) { @@ -210,7 +250,6 @@ public class EmployeeService { /** * 批量删除员工 - * */ public ResponseDTO batchUpdateDeleteFlag(List employeeIdList) { if (CollectionUtils.isEmpty(employeeIdList)) { @@ -239,7 +278,6 @@ public class EmployeeService { /** * 批量更新部门 - * */ public ResponseDTO batchUpdateDepartment(EmployeeBatchUpdateDepartmentForm batchUpdateDepartmentForm) { List employeeIdList = batchUpdateDepartmentForm.getEmployeeIdList(); @@ -262,7 +300,6 @@ public class EmployeeService { /** * 更新密码 - * */ public ResponseDTO updatePassword(EmployeeUpdatePasswordForm updatePasswordForm) { Long employeeId = updatePasswordForm.getEmployeeId(); @@ -299,7 +336,6 @@ public class EmployeeService { /** * 获取某个部门的员工信息 - * */ public ResponseDTO> getAllEmployeeByDepartmentId(Long departmentId, Boolean disabledFlag) { List employeeEntityList = employeeDao.selectByDepartmentId(departmentId, disabledFlag); @@ -326,7 +362,6 @@ public class EmployeeService { /** * 重置密码 - * */ public ResponseDTO resetPassword(Integer employeeId) { String password = protectPasswordService.randomPassword(); @@ -336,7 +371,6 @@ public class EmployeeService { /** * 获取 加密后 的密码 - * */ public static String getEncryptPwd(String password) { return DigestUtils.md5Hex(String.format(PASSWORD_SALT_FORMAT, password)); @@ -345,7 +379,6 @@ public class EmployeeService { /** * 查询全部员工 - * */ public ResponseDTO> queryAllEmployee(Boolean disabledFlag) { List employeeList = employeeDao.selectEmployeeByDisabledAndDeleted(disabledFlag, Boolean.FALSE); @@ -354,7 +387,6 @@ public class EmployeeService { /** * 根据登录名获取员工 - * */ public EmployeeEntity getByLoginName(String loginName) { return employeeDao.getByLoginName(loginName, null); diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/RequestEmployee.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/RequestEmployee.java index 600d8fc9..5ba92785 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/RequestEmployee.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/domain/RequestEmployee.java @@ -31,6 +31,9 @@ public class RequestEmployee implements RequestUser { @Schema(description = "员工名称") private String actualName; + @Schema(description = "头像") + private String avatar; + @SchemaEnum(GenderEnum.class) private Integer gender; @@ -43,9 +46,15 @@ public class RequestEmployee implements RequestUser { @Schema(description = "部门名称") private String departmentName; + @Schema(description = "是否禁用") + private Boolean disabledFlag; + @Schema(description = "是否为超管") private Boolean administratorFlag; + @Schema(description = "备注") + private String remark; + @Schema(description = "请求ip") private String ip; diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java index c2cf7346..e32e177f 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/login/service/LoginService.java @@ -32,6 +32,7 @@ import net.lab1024.sa.base.module.support.captcha.CaptchaService; import net.lab1024.sa.base.module.support.captcha.domain.CaptchaVO; import net.lab1024.sa.base.module.support.config.ConfigKeyEnum; import net.lab1024.sa.base.module.support.config.ConfigService; +import net.lab1024.sa.base.module.support.file.service.IFileStorageService; import net.lab1024.sa.base.module.support.loginlog.LoginLogResultEnum; import net.lab1024.sa.base.module.support.loginlog.LoginLogService; import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogEntity; @@ -39,6 +40,7 @@ import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogVO; import net.lab1024.sa.base.module.support.securityprotect.domain.LoginFailEntity; import net.lab1024.sa.base.module.support.securityprotect.service.ProtectLoginService; import net.lab1024.sa.base.module.support.securityprotect.service.ProtectPasswordService; +import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -110,6 +112,9 @@ public class LoginService implements StpInterface { @Resource private ProtectPasswordService profectPasswordService; + @Resource + private IFileStorageService fileStorageService; + /** * 获取验证码 */ @@ -252,6 +257,15 @@ public class LoginService implements StpInterface { DepartmentVO department = departmentService.getDepartmentById(employeeEntity.getDepartmentId()); requestEmployee.setDepartmentName(null == department ? StringConst.EMPTY : department.getName()); + // 头像信息 + String avatar = employeeEntity.getAvatar(); + if(StringUtils.isNotBlank(avatar)){ + ResponseDTO getFileUrl = fileStorageService.getFileUrl(avatar); + if(BooleanUtils.isTrue(getFileUrl.getOk())){ + requestEmployee.setAvatar(getFileUrl.getData()); + } + } + return requestEmployee; } @@ -341,6 +355,15 @@ public class LoginService implements StpInterface { return ResponseDTO.ok(); } + /** + * 清除员工登录缓存 + * @param employeeId + */ + public void clearLoginEmployeeCache(Long employeeId){ + // 清空登录信息缓存 + loginEmployeeCache.remove(employeeId); + } + /** * 保存登录日志 */ diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/controller/PositionController.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/controller/PositionController.java new file mode 100644 index 00000000..5a6c83ba --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/controller/PositionController.java @@ -0,0 +1,75 @@ +package net.lab1024.sa.admin.module.system.position.controller; + +import net.lab1024.sa.admin.constant.AdminSwaggerTagConst; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionAddForm; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionQueryForm; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionUpdateForm; +import net.lab1024.sa.admin.module.system.position.domain.vo.PositionVO; +import net.lab1024.sa.admin.module.system.position.service.PositionService; +import net.lab1024.sa.base.common.domain.ValidateList; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.domain.PageResult; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; +import io.swagger.v3.oas.annotations.tags.Tag; +import io.swagger.v3.oas.annotations.Operation; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +/** + * 职务表 Controller + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@RestController +@Tag(name = AdminSwaggerTagConst.System.SYSTEM_POSITION) +public class PositionController { + + @Resource + private PositionService positionService; + + @Operation(summary = "分页查询 @author kaiyun") + @PostMapping("/position/queryPage") + public ResponseDTO> queryPage(@RequestBody @Valid PositionQueryForm queryForm) { + return ResponseDTO.ok(positionService.queryPage(queryForm)); + } + + @Operation(summary = "添加 @author kaiyun") + @PostMapping("/position/add") + public ResponseDTO add(@RequestBody @Valid PositionAddForm addForm) { + return positionService.add(addForm); + } + + @Operation(summary = "更新 @author kaiyun") + @PostMapping("/position/update") + public ResponseDTO update(@RequestBody @Valid PositionUpdateForm updateForm) { + return positionService.update(updateForm); + } + + @Operation(summary = "批量删除 @author kaiyun") + @PostMapping("/position/batchDelete") + public ResponseDTO batchDelete(@RequestBody ValidateList idList) { + return positionService.batchDelete(idList); + } + + @Operation(summary = "单个删除 @author kaiyun") + @GetMapping("/position/delete/{positionId}") + public ResponseDTO batchDelete(@PathVariable Long positionId) { + return positionService.delete(positionId); + } + + + @Operation(summary = "不分页查询 @author kaiyun") + @GetMapping("/position/queryList") + public ResponseDTO> queryList() { + return ResponseDTO.ok(positionService.queryList()); + } +} diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/dao/PositionDao.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/dao/PositionDao.java new file mode 100644 index 00000000..fbd9b9b3 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/dao/PositionDao.java @@ -0,0 +1,41 @@ +package net.lab1024.sa.admin.module.system.position.dao; + +import java.util.List; +import net.lab1024.sa.admin.module.system.position.domain.entity.PositionEntity; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionQueryForm; +import net.lab1024.sa.admin.module.system.position.domain.vo.PositionVO; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +/** + * 职务表 Dao + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Mapper +@Component +public interface PositionDao extends BaseMapper { + + /** + * 分页 查询 + * + * @param page + * @param queryForm + * @return + */ + List queryPage(Page page, @Param("queryForm") PositionQueryForm queryForm); + + + /** + * 查询 + * @param deletedFlag + * @return + */ + List queryList(@Param("deletedFlag") Boolean deletedFlag); +} diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/entity/PositionEntity.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/entity/PositionEntity.java new file mode 100644 index 00000000..0beac2a3 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/entity/PositionEntity.java @@ -0,0 +1,61 @@ +package net.lab1024.sa.admin.module.system.position.domain.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; + +import java.time.LocalDateTime; + +import lombok.Data; + +/** + * 职务表 实体类 + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +@TableName("t_position") +public class PositionEntity { + + /** + * 职务ID + */ + @TableId(type = IdType.AUTO) + private Long positionId; + + /** + * 职务名称 + */ + private String positionName; + + /** + * 职级 + */ + private String level; + + /** + * 排序 + */ + private Integer sort; + + /** + * 备注 + */ + private String remark; + + private Boolean deletedFlag; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionAddForm.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionAddForm.java new file mode 100644 index 00000000..58d89ed8 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionAddForm.java @@ -0,0 +1,34 @@ +package net.lab1024.sa.admin.module.system.position.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +import lombok.Data; + +/** + * 职务表 新建表单 + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +public class PositionAddForm { + + @Schema(description = "职务名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotBlank(message = "职务名称 不能为空") + private String positionName; + + @Schema(description = "职级") + private String level; + + @Schema(description = "排序") + @NotNull(message = "排序不能为空") + private Integer sort; + + @Schema(description = "备注") + private String remark; + +} \ No newline at end of file diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionQueryForm.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionQueryForm.java new file mode 100644 index 00000000..c6b71550 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionQueryForm.java @@ -0,0 +1,23 @@ +package net.lab1024.sa.admin.module.system.position.domain.form; + +import net.lab1024.sa.base.common.domain.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 职务表 分页查询表单 + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +public class PositionQueryForm extends PageParam{ + + @Schema(description = "关键字查询") + private String keywords; + + @Schema(hidden = true) + private Boolean deletedFlag; +} \ No newline at end of file diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionUpdateForm.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionUpdateForm.java new file mode 100644 index 00000000..298334c8 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/form/PositionUpdateForm.java @@ -0,0 +1,24 @@ +package net.lab1024.sa.admin.module.system.position.domain.form; + +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.validation.constraints.NotNull; + +import lombok.Data; + +/** + * 职务表 更新表单 + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +public class PositionUpdateForm extends PositionAddForm { + + @Schema(description = "职务ID", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "职务ID 不能为空") + private Long positionId; + +} \ No newline at end of file diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/vo/PositionVO.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/vo/PositionVO.java new file mode 100644 index 00000000..ee178840 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/domain/vo/PositionVO.java @@ -0,0 +1,40 @@ +package net.lab1024.sa.admin.module.system.position.domain.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Data; + +/** + * 职务表 列表VO + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Data +public class PositionVO { + + + @Schema(description = "职务ID") + private Long positionId; + + @Schema(description = "职务名称") + private String positionName; + + @Schema(description = "职级") + private String level; + + @Schema(description = "排序") + private Integer sort; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + private LocalDateTime updateTime; + +} \ No newline at end of file diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/manager/PositionManager.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/manager/PositionManager.java new file mode 100644 index 00000000..1759de88 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/manager/PositionManager.java @@ -0,0 +1,20 @@ +package net.lab1024.sa.admin.module.system.position.manager; + +import net.lab1024.sa.admin.module.system.position.dao.PositionDao; +import net.lab1024.sa.admin.module.system.position.domain.entity.PositionEntity; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.stereotype.Service; + +/** + * 职务表 Manager + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ +@Service +public class PositionManager extends ServiceImpl { + + +} diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/service/PositionService.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/service/PositionService.java new file mode 100644 index 00000000..1d132969 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/position/service/PositionService.java @@ -0,0 +1,105 @@ +package net.lab1024.sa.admin.module.system.position.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.admin.module.system.position.dao.PositionDao; +import net.lab1024.sa.admin.module.system.position.domain.entity.PositionEntity; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionAddForm; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionQueryForm; +import net.lab1024.sa.admin.module.system.position.domain.form.PositionUpdateForm; +import net.lab1024.sa.admin.module.system.position.domain.vo.PositionVO; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; + +/** + * 职务表 Service + * + * @Author kaiyun + * @Date 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ + +@Service +public class PositionService { + + @Resource + private PositionDao positionDao; + + /** + * 分页查询 + * + * @param queryForm + * @return + */ + public PageResult queryPage(PositionQueryForm queryForm) { + queryForm.setDeletedFlag(Boolean.FALSE); + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List list = positionDao.queryPage(page, queryForm); + PageResult pageResult = SmartPageUtil.convert2PageResult(page, list); + return pageResult; + } + + /** + * 添加 + */ + public ResponseDTO add(PositionAddForm addForm) { + PositionEntity positionEntity = SmartBeanUtil.copy(addForm, PositionEntity.class); + positionDao.insert(positionEntity); + return ResponseDTO.ok(); + } + + /** + * 更新 + * + * @param updateForm + * @return + */ + public ResponseDTO update(PositionUpdateForm updateForm) { + PositionEntity positionEntity = SmartBeanUtil.copy(updateForm, PositionEntity.class); + positionDao.updateById(positionEntity); + return ResponseDTO.ok(); + } + + /** + * 批量删除 + * + * @param idList + * @return + */ + public ResponseDTO batchDelete(List idList) { + if (CollectionUtils.isEmpty(idList)){ + return ResponseDTO.ok(); + } + + positionDao.deleteBatchIds(idList); + return ResponseDTO.ok(); + } + + /** + * 单个删除 + */ + public ResponseDTO delete(Long positionId) { + if (null == positionId){ + return ResponseDTO.ok(); + } + + positionDao.deleteById(positionId); + return ResponseDTO.ok(); + } + + /** + * 分页查询 + * + * @return + */ + public List queryList() { + List list = positionDao.queryList(Boolean.FALSE); + return list; + } +} diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleEmployeeManager.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleEmployeeManager.java index e403f19f..f8fbd6f2 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleEmployeeManager.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/role/manager/RoleEmployeeManager.java @@ -2,10 +2,10 @@ package net.lab1024.sa.admin.module.system.role.manager; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import net.lab1024.sa.admin.module.system.role.dao.RoleEmployeeDao; +import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEmployeeEntity; import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import net.lab1024.sa.admin.module.system.role.domain.entity.RoleEmployeeEntity; import java.util.List; diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminLoginLogController.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminLoginLogController.java index 48d9b716..ba3f5a02 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminLoginLogController.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminLoginLogController.java @@ -5,7 +5,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; import net.lab1024.sa.base.common.controller.SupportBaseController; import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; import net.lab1024.sa.base.constant.SwaggerTagConst; import net.lab1024.sa.base.module.support.loginlog.LoginLogService; import net.lab1024.sa.base.module.support.loginlog.domain.LoginLogQueryForm; @@ -39,5 +41,14 @@ public class AdminLoginLogController extends SupportBaseController { return loginLogService.queryByPage(queryForm); } + @Operation(summary = "分页查询当前登录人信息 @author 善逸") + @PostMapping("/loginLog/page/query/login") + public ResponseDTO> queryByPageLogin(@RequestBody LoginLogQueryForm queryForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + queryForm.setUserId(requestUser.getUserId()); + queryForm.setUserType(requestUser.getUserType().getValue()); + return loginLogService.queryByPage(queryForm); + } + } diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminOperateLogController.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminOperateLogController.java index b7c082f7..8624cbc8 100644 --- a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminOperateLogController.java +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminOperateLogController.java @@ -5,7 +5,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.Operation; import net.lab1024.sa.base.common.controller.SupportBaseController; import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; import net.lab1024.sa.base.constant.SwaggerTagConst; import net.lab1024.sa.base.module.support.operatelog.OperateLogService; import net.lab1024.sa.base.module.support.operatelog.domain.OperateLogQueryForm; @@ -44,4 +46,13 @@ public class AdminOperateLogController extends SupportBaseController { return operateLogService.detail(operateLogId); } + @Operation(summary = "分页查询当前登录人信息 @author 善逸") + @PostMapping("/operateLog/page/query/login") + public ResponseDTO> queryByPageLogin(@RequestBody OperateLogQueryForm queryForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + queryForm.setOperateUserId(requestUser.getUserId()); + queryForm.setOperateUserType(requestUser.getUserType().getValue()); + return operateLogService.queryByPage(queryForm); + } + } diff --git a/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSmartJobController.java b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSmartJobController.java new file mode 100644 index 00000000..d987ca39 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/java/net/lab1024/sa/admin/module/system/support/AdminSmartJobController.java @@ -0,0 +1,79 @@ +package net.lab1024.sa.admin.module.system.support; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.job.api.SmartJobService; +import net.lab1024.sa.base.module.support.job.api.domain.*; +import net.lab1024.sa.base.module.support.job.config.SmartJobAutoConfiguration; +import net.lab1024.sa.base.module.support.repeatsubmit.annoation.RepeatSubmit; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; + +/** + * 定时任务 管理接口 + * + * @author huke + * @date 2024/6/17 20:41 + */ +@Tag(name = SwaggerTagConst.Support.JOB) +@RestController +@ConditionalOnBean(SmartJobAutoConfiguration.class) +public class AdminSmartJobController extends SupportBaseController { + + @Autowired + private SmartJobService jobService; + + @Operation(summary = "定时任务-立即执行 @huke") + @PostMapping("/job/execute") + @RepeatSubmit + public ResponseDTO execute(@RequestBody @Valid SmartJobExecuteForm executeForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + executeForm.setUpdateName(requestUser.getUserName()); + return jobService.execute(executeForm); + } + + @Operation(summary = "定时任务-查询详情 @huke") + @GetMapping("/job/{jobId}") + public ResponseDTO queryJobInfo(@PathVariable Integer jobId) { + return jobService.queryJobInfo(jobId); + } + + @Operation(summary = "定时任务-分页查询 @huke") + @PostMapping("/job/query") + public ResponseDTO> queryJob(@RequestBody @Valid SmartJobQueryForm queryForm) { + return jobService.queryJob(queryForm); + } + + @Operation(summary = "定时任务-更新-任务信息 @huke") + @PostMapping("/job/update") + @RepeatSubmit + public ResponseDTO updateJob(@RequestBody @Valid SmartJobUpdateForm updateForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + updateForm.setUpdateName(requestUser.getUserName()); + return jobService.updateJob(updateForm); + } + + @Operation(summary = "定时任务-更新-开启状态 @huke") + @PostMapping("/job/update/enabled") + @RepeatSubmit + public ResponseDTO updateJobEnabled(@RequestBody @Valid SmartJobEnabledUpdateForm updateForm) { + RequestUser requestUser = SmartRequestUtil.getRequestUser(); + updateForm.setUpdateName(requestUser.getUserName()); + return jobService.updateJobEnabled(updateForm); + } + + @Operation(summary = "定时任务-执行记录-分页查询 @huke") + @PostMapping("/job/log/query") + public ResponseDTO> queryJobLog(@RequestBody @Valid SmartJobLogQueryForm queryForm) { + return jobService.queryJobLog(queryForm); + } +} \ No newline at end of file diff --git a/smart-admin-api/sa-admin/src/main/resources/dev/application.yaml b/smart-admin-api/sa-admin/src/main/resources/dev/application.yaml index f0e4b2b2..ba540719 100644 --- a/smart-admin-api/sa-admin/src/main/resources/dev/application.yaml +++ b/smart-admin-api/sa-admin/src/main/resources/dev/application.yaml @@ -8,7 +8,7 @@ # 项目配置: 名称、日志目录 project: name: sa-admin - log-directory: /home/logs/smart_admin_v3/${project.name}/${spring.profiles.active} + log-directory: ${localPath:/home}/logs/smart_admin_v3/${project.name}/${spring.profiles.active} # 项目端口和url根路径 server: @@ -21,12 +21,6 @@ spring: profiles: active: '@profiles.active@' -# swagger文档 -swagger: - host: localhost:${server.port} - tag-class: net.lab1024.sa.admin.constant.AdminSwaggerTagConst - - ####################################### 安全等级保护 相关配置 ################################################## # # # 建议开启 "三级等保" 所要求的配置,具体如下: # diff --git a/smart-admin-api/sa-admin/src/main/resources/mapper/system/PositionMapper.xml b/smart-admin-api/sa-admin/src/main/resources/mapper/system/PositionMapper.xml new file mode 100644 index 00000000..bdc93ea5 --- /dev/null +++ b/smart-admin-api/sa-admin/src/main/resources/mapper/system/PositionMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file diff --git a/smart-admin-api/sa-admin/src/main/resources/pre/application.yaml b/smart-admin-api/sa-admin/src/main/resources/pre/application.yaml index f0e4b2b2..cbac6806 100644 --- a/smart-admin-api/sa-admin/src/main/resources/pre/application.yaml +++ b/smart-admin-api/sa-admin/src/main/resources/pre/application.yaml @@ -21,12 +21,6 @@ spring: profiles: active: '@profiles.active@' -# swagger文档 -swagger: - host: localhost:${server.port} - tag-class: net.lab1024.sa.admin.constant.AdminSwaggerTagConst - - ####################################### 安全等级保护 相关配置 ################################################## # # # 建议开启 "三级等保" 所要求的配置,具体如下: # diff --git a/smart-admin-api/sa-admin/src/main/resources/prod/application.yaml b/smart-admin-api/sa-admin/src/main/resources/prod/application.yaml index f0e4b2b2..cbac6806 100644 --- a/smart-admin-api/sa-admin/src/main/resources/prod/application.yaml +++ b/smart-admin-api/sa-admin/src/main/resources/prod/application.yaml @@ -21,12 +21,6 @@ spring: profiles: active: '@profiles.active@' -# swagger文档 -swagger: - host: localhost:${server.port} - tag-class: net.lab1024.sa.admin.constant.AdminSwaggerTagConst - - ####################################### 安全等级保护 相关配置 ################################################## # # # 建议开启 "三级等保" 所要求的配置,具体如下: # diff --git a/smart-admin-api/sa-admin/src/main/resources/test/application.yaml b/smart-admin-api/sa-admin/src/main/resources/test/application.yaml index f0e4b2b2..e6af9476 100644 --- a/smart-admin-api/sa-admin/src/main/resources/test/application.yaml +++ b/smart-admin-api/sa-admin/src/main/resources/test/application.yaml @@ -8,11 +8,11 @@ # 项目配置: 名称、日志目录 project: name: sa-admin - log-directory: /home/logs/smart_admin_v3/${project.name}/${spring.profiles.active} + log-directory: /home/project/smartadmin/sit/log # 项目端口和url根路径 server: - port: 1024 + port: 11024 servlet: context-path: / @@ -21,12 +21,6 @@ spring: profiles: active: '@profiles.active@' -# swagger文档 -swagger: - host: localhost:${server.port} - tag-class: net.lab1024.sa.admin.constant.AdminSwaggerTagConst - - ####################################### 安全等级保护 相关配置 ################################################## # # # 建议开启 "三级等保" 所要求的配置,具体如下: # diff --git a/smart-admin-api/sa-base/pom.xml b/smart-admin-api/sa-base/pom.xml index ac20877c..870fb9d8 100644 --- a/smart-admin-api/sa-base/pom.xml +++ b/smart-admin-api/sa-base/pom.xml @@ -113,6 +113,11 @@ commons-pool2 + + org.apache.commons + commons-text + + org.springframework spring-mock @@ -264,6 +269,14 @@ ${smartdb.version} + + org.redisson + redisson-spring-boot-starter + + + org.redisson + redisson-spring-data-27 + diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/DictValueVoSerializer.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/DictValueVoSerializer.java index 7a81a14e..fceba7b4 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/DictValueVoSerializer.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/DictValueVoSerializer.java @@ -40,7 +40,7 @@ public class DictValueVoSerializer extends JsonSerializer { List dictValueVOList = Lists.newArrayList(); valueCodeList.forEach(e->{ if(StringUtils.isNotBlank(e)){ - DictValueVO dictValueVO = dictCacheService.selectValueByValueCode(value); + DictValueVO dictValueVO = dictCacheService.selectValueByValueCode(e); if(dictValueVO != null){ dictValueVOList.add(dictValueVO); } diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/enumeration/EnumSerialize.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/enumeration/EnumSerialize.java new file mode 100644 index 00000000..ace962b5 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/enumeration/EnumSerialize.java @@ -0,0 +1,25 @@ +package net.lab1024.sa.base.common.json.serializer.enumeration; + +import com.fasterxml.jackson.annotation.JacksonAnnotationsInside; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 枚举类 序列化 注解 + * + * @author huke + * @date 2024年6月29日 + */ +@Target(ElementType.FIELD) +@Retention(RetentionPolicy.RUNTIME) +@JacksonAnnotationsInside +@JsonSerialize(using = EnumSerializer.class, nullsUsing = EnumSerializer.class) +public @interface EnumSerialize { + + Class value(); +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/enumeration/EnumSerializer.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/enumeration/EnumSerializer.java new file mode 100644 index 00000000..9cd2324d --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/json/serializer/enumeration/EnumSerializer.java @@ -0,0 +1,53 @@ +package net.lab1024.sa.base.common.json.serializer.enumeration; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.BeanProperty; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; +import com.fasterxml.jackson.databind.ser.ContextualSerializer; +import net.lab1024.sa.base.common.constant.StringConst; +import net.lab1024.sa.base.common.enumeration.BaseEnum; +import net.lab1024.sa.base.common.util.SmartEnumUtil; +import net.lab1024.sa.base.common.util.SmartStringUtil; + +import java.io.IOException; +import java.util.stream.Collectors; + +/** + * 枚举 序列化 + * + * @author huke + * @date 2024年6月29日 + */ +public class EnumSerializer extends JsonSerializer implements ContextualSerializer { + + private Class enumClazz; + + @Override + public void serialize(Object value, JsonGenerator gen, SerializerProvider serializers) throws IOException { + gen.writeObject(value); + String fieldName = gen.getOutputContext().getCurrentName() + "Desc"; + Object desc; + // 多个枚举类 逗号分割 + if (value instanceof String && String.valueOf(value).contains(StringConst.SEPARATOR)) { + desc = SmartStringUtil.splitConvertToIntList(String.valueOf(value), StringConst.SEPARATOR) + .stream().map(e -> SmartEnumUtil.getEnumDescByValue(e, enumClazz)).collect(Collectors.toList()); + + } else { + BaseEnum anEnum = SmartEnumUtil.getEnumByValue(value, enumClazz); + desc = null != anEnum ? anEnum.getDesc() : null; + } + gen.writeObjectField(fieldName, desc); + } + + @Override + public JsonSerializer createContextual(SerializerProvider prov, BeanProperty property) throws JsonMappingException { + EnumSerialize annotation = property.getAnnotation(EnumSerialize.class); + if (null == annotation) { + return prov.findValueSerializer(property.getType(), property); + } + enumClazz = annotation.value(); + return this; + } +} \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartIpUtil.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartIpUtil.java index 887df77b..254cdb71 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartIpUtil.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/common/util/SmartIpUtil.java @@ -4,8 +4,12 @@ import lombok.extern.slf4j.Slf4j; import net.lab1024.sa.base.common.constant.StringConst; import org.lionsoul.ip2region.xdb.Searcher; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Enumeration; import java.util.List; /** @@ -81,4 +85,39 @@ public class SmartIpUtil { } } + /** + * 获取本机第一个ip + * + * @return + */ + public static String getLocalFirstIp() { + List list = getLocalIp(); + return list.size() > 0 ? list.get(0) : null; + } + + /** + * 获取本机ip + * + * @return + */ + public static List getLocalIp() { + List ipList = new ArrayList<>(); + try { + Enumeration networkInterfaces = NetworkInterface.getNetworkInterfaces(); + while (networkInterfaces.hasMoreElements()) { + NetworkInterface networkInterface = networkInterfaces.nextElement(); + Enumeration inetAddresses = networkInterface.getInetAddresses(); + while (inetAddresses.hasMoreElements()) { + InetAddress inetAddress = inetAddresses.nextElement(); + // 排除回环地址和IPv6地址 + if (!inetAddress.isLoopbackAddress() && !inetAddress.getHostAddress().contains(StringConst.COLON)) { + ipList.add(inetAddress.getHostAddress()); + } + } + } + } catch (SocketException e) { + e.printStackTrace(); + } + return ipList; + } } diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/config/SwaggerConfig.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/config/SwaggerConfig.java index 0f7f3542..c1f343d1 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/config/SwaggerConfig.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/config/SwaggerConfig.java @@ -1,5 +1,6 @@ package net.lab1024.sa.base.config; +import com.google.common.collect.Lists; import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; @@ -10,14 +11,25 @@ import lombok.extern.slf4j.Slf4j; import net.lab1024.sa.base.common.constant.RequestHeaderConst; import net.lab1024.sa.base.common.swagger.SmartOperationCustomizer; import net.lab1024.sa.base.constant.SwaggerTagConst; -import org.springdoc.core.GroupedOpenApi; +import org.apache.commons.lang3.StringUtils; +import org.springdoc.core.*; +import org.springdoc.core.customizers.OpenApiBuilderCustomizer; +import org.springdoc.core.customizers.ServerBaseUrlCustomizer; +import org.springdoc.core.providers.JavadocProvider; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import java.util.List; +import java.util.Optional; + /** * springdoc-openapi 配置 - * + * nginx配置前缀时如果需要访问【/swagger-ui/index.html】需添加额外nginx配置 + * location /v3/api-docs/ { + * proxy_pass http://127.0.0.1:11024/v3/api-docs/; + * } * @Author 1024创新实验室-主任: 卓大 * @Date 2020-03-25 22:54:46 * @Wechat zhuoda1024 @@ -28,6 +40,11 @@ import org.springframework.context.annotation.Configuration; @Configuration @Conditional(SystemEnvironmentConfig.class) public class SwaggerConfig { + /** + * 用于解决/swagger-ui/index.html页面ServersUrl 测试环境部署错误问题 + */ + @Value("${springdoc.swagger-ui.server-base-url:''}") + private String serverBaseUrl; public static final String[] SWAGGER_WHITELIST = { "/swagger-ui/**", @@ -78,4 +95,37 @@ public class SwaggerConfig { .addOperationCustomizer(new SmartOperationCustomizer()) .build(); } + + /** + * 以下代码可以用于设置 /swagger-ui/index.html 的serverBaseUrl + * 如果使用knife4j则不需要 + * @param openAPI + * @param securityParser + * @param springDocConfigProperties + * @param propertyResolverUtils + * @param openApiBuilderCustomizers + * @param serverBaseUrlCustomizers + * @param javadocProvider + * @return + */ + @Bean + public OpenAPIService openApiBuilder(Optional openAPI, + SecurityService securityParser, + SpringDocConfigProperties springDocConfigProperties, + PropertyResolverUtils propertyResolverUtils, + Optional> openApiBuilderCustomizers, + Optional> serverBaseUrlCustomizers, + Optional javadocProvider) { + List list = Lists.newArrayList(new ServerBaseUrlCustomizer() { + @Override + public String customize(String baseUrl) { + if (StringUtils.isNotBlank(serverBaseUrl)) { + return serverBaseUrl; + } + return baseUrl; + } + }); + return new OpenAPIService(openAPI, securityParser, springDocConfigProperties, + propertyResolverUtils, openApiBuilderCustomizers, Optional.of(list), javadocProvider); + } } diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/constant/SwaggerTagConst.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/constant/SwaggerTagConst.java index a6b9e562..8a9642d7 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/constant/SwaggerTagConst.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/constant/SwaggerTagConst.java @@ -48,6 +48,10 @@ public class SwaggerTagConst { public static final String TABLE_COLUMN = "业务支撑-列自定义"; public static final String PROTECT = "业务支撑-网络安全"; + + public static final String JOB = "业务支撑-定时任务"; + + public static final String MESSAGE = "业务支撑-消息"; } } diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/handler/GlobalExceptionHandler.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/handler/GlobalExceptionHandler.java index 01d6356e..3bafe3e6 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/handler/GlobalExceptionHandler.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/handler/GlobalExceptionHandler.java @@ -9,7 +9,6 @@ import net.lab1024.sa.base.common.domain.SystemEnvironment; import net.lab1024.sa.base.common.enumeration.SystemEnvironmentEnum; import net.lab1024.sa.base.common.exception.BusinessException; import org.springframework.beans.TypeMismatchException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.validation.BindException; import org.springframework.validation.FieldError; @@ -59,10 +58,6 @@ public class GlobalExceptionHandler { @ResponseBody @ExceptionHandler({TypeMismatchException.class, BindException.class}) public ResponseDTO paramExceptionHandler(Exception e) { - if (!systemEnvironment.isProd()) { - log.error("全局参数异常,URL:{}", getCurrentRequestUrl(), e); - } - if (e instanceof BindException) { if (e instanceof MethodArgumentNotValidException) { List fieldErrors = ((MethodArgumentNotValidException) e).getBindingResult().getFieldErrors(); @@ -75,7 +70,6 @@ public class GlobalExceptionHandler { String errorMsg = UserErrorCode.PARAM_ERROR.getMsg() + ":" + error; return ResponseDTO.error(UserErrorCode.PARAM_ERROR, errorMsg); } - return ResponseDTO.error(UserErrorCode.PARAM_ERROR); } diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/listener/WebServerListener.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/listener/WebServerListener.java index 19fe7793..8faa6acf 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/listener/WebServerListener.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/listener/WebServerListener.java @@ -86,14 +86,15 @@ public class WebServerListener implements ApplicationListener configCache = new ConcurrentHashMap<>(); + private final ConcurrentHashMap CONFIG_CACHE = new ConcurrentHashMap<>(); @Resource private ConfigDao configDao; @@ -52,13 +52,13 @@ public class ConfigService { */ @PostConstruct private void loadConfigCache() { - configCache.clear(); + CONFIG_CACHE.clear(); List entityList = configDao.selectList(null); if (CollectionUtils.isEmpty(entityList)) { return; } - entityList.forEach(entity -> this.configCache.put(entity.getConfigKey().toLowerCase(), entity)); - log.info("################# 系统配置缓存初始化完毕:{} ###################", configCache.size()); + entityList.forEach(entity -> this.CONFIG_CACHE.put(entity.getConfigKey().toLowerCase(), entity)); + log.info("################# 系统配置缓存初始化完毕:{} ###################", CONFIG_CACHE.size()); } /** @@ -70,7 +70,7 @@ public class ConfigService { if (null == configEntity) { return; } - this.configCache.put(configEntity.getConfigKey().toLowerCase(), configEntity); + this.CONFIG_CACHE.put(configEntity.getConfigKey().toLowerCase(), configEntity); } /** @@ -100,7 +100,7 @@ public class ConfigService { if (StrUtil.isBlank(configKey)) { return null; } - ConfigEntity entity = this.configCache.get(configKey.toLowerCase()); + ConfigEntity entity = this.CONFIG_CACHE.get(configKey.toLowerCase()); return SmartBeanUtil.copy(entity, ConfigVO.class); } diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/SmartJobClientManager.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/SmartJobClientManager.java new file mode 100644 index 00000000..044ddf65 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/SmartJobClientManager.java @@ -0,0 +1,164 @@ +package net.lab1024.sa.base.module.support.job.api; + +import cn.hutool.core.util.IdUtil; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.base.module.support.job.api.domain.SmartJobMsg; +import net.lab1024.sa.base.module.support.job.config.SmartJobAutoConfiguration; +import net.lab1024.sa.base.module.support.job.core.SmartJob; +import net.lab1024.sa.base.module.support.job.core.SmartJobExecutor; +import net.lab1024.sa.base.module.support.job.core.SmartJobLauncher; +import net.lab1024.sa.base.module.support.job.repository.SmartJobRepository; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobEntity; +import org.redisson.api.RLock; +import org.redisson.api.RTopic; +import org.redisson.api.RedissonClient; +import org.redisson.api.listener.MessageListener; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.stereotype.Service; + +import javax.annotation.PreDestroy; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +/** + * smart job 执行端管理 + * 分布式系统之间 用发布/订阅消息的形式 来管理多个job + * + * @author huke + * @date 2024/6/22 20:31 + */ +@ConditionalOnBean(SmartJobAutoConfiguration.class) +@Slf4j +@Service +public class SmartJobClientManager { + + private final SmartJobLauncher jobLauncher; + + private final SmartJobRepository jobRepository; + + private final List jobInterfaceList; + + private static final String EXECUTE_LOCK = "smart-job-lock-msg-execute-"; + + private static final String TOPIC = "smart-job-instance"; + + private final RedissonClient redissonClient; + + private final RTopic topic; + + private final SmartJobMsgListener jobMsgListener; + + public SmartJobClientManager(SmartJobLauncher jobLauncher, + SmartJobRepository jobRepository, + List jobInterfaceList, + RedissonClient redissonClient) { + this.jobLauncher = jobLauncher; + this.jobRepository = jobRepository; + this.jobInterfaceList = jobInterfaceList; + this.redissonClient = redissonClient; + + // 添加监听器 + this.topic = redissonClient.getTopic(TOPIC); + this.jobMsgListener = new SmartJobMsgListener(); + topic.addListener(SmartJobMsg.class, jobMsgListener); + log.info("==== SmartJob ==== client-manager init"); + } + + /** + * 发布消息 + */ + public void publishToClient(SmartJobMsg msgDTO) { + msgDTO.setMsgId(IdUtil.fastSimpleUUID()); + topic.publish(msgDTO); + } + + /** + * 处理消息 + */ + private class SmartJobMsgListener implements MessageListener { + + @Override + public void onMessage(CharSequence channel, SmartJobMsg msg) { + log.info("==== SmartJob ==== on-message :{}", msg); + // 判断消息类型 业务简单就直接判断 复杂的话可以策略模式 + SmartJobMsg.MsgTypeEnum msgType = msg.getMsgType(); + // 更新任务 + if (SmartJobMsg.MsgTypeEnum.UPDATE_JOB == msgType) { + updateJob(msg.getJobId()); + } + // 执行任务 + if (SmartJobMsg.MsgTypeEnum.EXECUTE_JOB == msgType) { + executeJob(msg); + } + } + } + + /** + * 获取任务执行类 + * + * @param jobClass + * @return + */ + private Optional queryJobImpl(String jobClass) { + return jobInterfaceList.stream().filter(e -> Objects.equals(e.getClassName(), jobClass)).findFirst(); + } + + /** + * 更新任务 + * + * @param jobId + */ + private void updateJob(Integer jobId) { + SmartJobEntity jobEntity = jobRepository.getJobDao().selectById(jobId); + if (null == jobEntity) { + return; + } + jobLauncher.startOrRefreshJob(Lists.newArrayList(jobEntity)); + } + + /** + * 立即执行任务 + * + * @param msg + */ + private void executeJob(SmartJobMsg msg) { + Integer jobId = msg.getJobId(); + SmartJobEntity jobEntity = jobRepository.getJobDao().selectById(jobId); + if (null == jobEntity) { + return; + } + // 获取定时任务实现类 + Optional optional = this.queryJobImpl(jobEntity.getJobClass()); + if (!optional.isPresent()) { + return; + } + + // 获取执行锁 无需主动释放 + RLock rLock = redissonClient.getLock(EXECUTE_LOCK + msg.getMsgId()); + try { + boolean getLock = rLock.tryLock(0, 20, TimeUnit.SECONDS); + if (!getLock) { + return; + } + } catch (InterruptedException e) { + log.error("==== SmartJob ==== msg execute err:", e); + return; + } + + // 通过执行器 执行任务 + jobEntity.setParam(msg.getParam()); + SmartJobExecutor jobExecutor = new SmartJobExecutor(jobEntity, jobRepository, optional.get(), redissonClient); + jobExecutor.execute(msg.getUpdateName()); + } + + + @PreDestroy + public void destroy() { + topic.removeListener(jobMsgListener); + } + + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/SmartJobService.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/SmartJobService.java new file mode 100644 index 00000000..1600acbc --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/SmartJobService.java @@ -0,0 +1,246 @@ +package net.lab1024.sa.base.module.support.job.api; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Lists; +import net.lab1024.sa.base.common.code.UserErrorCode; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.job.api.domain.*; +import net.lab1024.sa.base.module.support.job.config.SmartJobAutoConfiguration; +import net.lab1024.sa.base.module.support.job.constant.SmartJobTriggerTypeEnum; +import net.lab1024.sa.base.module.support.job.constant.SmartJobUtil; +import net.lab1024.sa.base.module.support.job.repository.SmartJobDao; +import net.lab1024.sa.base.module.support.job.repository.SmartJobLogDao; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobEntity; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobLogEntity; +import org.apache.commons.collections4.CollectionUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +/** + * 定时任务 接口业务管理 + * 如果不需要通过接口管理定时任务 可以删除此类 + * + * @author huke + * @date 2024/6/17 20:41 + */ +@ConditionalOnBean(SmartJobAutoConfiguration.class) +@Service +public class SmartJobService { + + @Resource + private SmartJobDao jobDao; + + @Resource + private SmartJobLogDao jobLogDao; + + @Resource + private SmartJobClientManager jobClientManager; + + /** + * 查询 定时任务详情 + * + * @param jobId + * @return + */ + public ResponseDTO queryJobInfo(Integer jobId) { + SmartJobEntity jobEntity = jobDao.selectById(jobId); + if (null == jobEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + SmartJobVO jobVO = SmartBeanUtil.copy(jobEntity, SmartJobVO.class); + // 处理设置job详情 + this.handleJobInfo(Lists.newArrayList(jobVO)); + return ResponseDTO.ok(jobVO); + } + + /** + * 分页查询 定时任务 + * + * @param queryForm + * @return + */ + public ResponseDTO> queryJob(SmartJobQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List jobList = jobDao.query(page, queryForm); + PageResult pageResult = SmartPageUtil.convert2PageResult(page, jobList); + // 处理设置job详情 + this.handleJobInfo(jobList); + return ResponseDTO.ok(pageResult); + } + + /** + * 处理设置 任务信息 + * + * @param jobList + */ + private void handleJobInfo(List jobList) { + if (CollectionUtils.isEmpty(jobList)) { + return; + } + // 查询最后一次执行记录 + List logIdList = jobList.stream().map(SmartJobVO::getLastExecuteLogId).filter(Objects::nonNull).collect(Collectors.toList()); + Map lastLogMap = Collections.emptyMap(); + if (CollectionUtils.isNotEmpty(logIdList)) { + lastLogMap = jobLogDao.selectBatchIds(logIdList) + .stream() + .collect(Collectors.toMap(SmartJobLogEntity::getLogId, e -> SmartBeanUtil.copy(e, SmartJobLogVO.class))); + } + + // 循环处理任务信息 + for (SmartJobVO jobVO : jobList) { + // 设置最后一次执行记录 + Long lastExecuteLogId = jobVO.getLastExecuteLogId(); + if (null != lastExecuteLogId) { + jobVO.setLastJobLog(lastLogMap.get(lastExecuteLogId)); + } + // 计算未来5次执行时间 + if (jobVO.getEnabledFlag()) { + List nextTimeList = SmartJobUtil.queryNextTimeFromNow(jobVO.getTriggerType(), jobVO.getTriggerValue(), jobVO.getLastExecuteTime(), 5); + jobVO.setNextJobExecuteTimeList(nextTimeList); + } + } + } + + /** + * 分页查询 定时任务-执行记录 + * + * @param queryForm + * @return + */ + public ResponseDTO> queryJobLog(SmartJobLogQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List jobList = jobLogDao.query(page, queryForm); + PageResult pageResult = SmartPageUtil.convert2PageResult(page, jobList); + return ResponseDTO.ok(pageResult); + } + + /** + * 更新定时任务 + * + * @param updateForm + * @return + */ + public ResponseDTO updateJob(SmartJobUpdateForm updateForm) { + // 校验参数 + Integer jobId = updateForm.getJobId(); + SmartJobEntity jobEntity = jobDao.selectById(jobId); + if (null == jobEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + // 校验触发时间配置 + String triggerType = updateForm.getTriggerType(); + String triggerValue = updateForm.getTriggerValue(); + if (SmartJobTriggerTypeEnum.CRON.equalsValue(triggerType) && !SmartJobUtil.checkCron(triggerValue)) { + return ResponseDTO.userErrorParam("cron表达式错误"); + } + if (SmartJobTriggerTypeEnum.FIXED_DELAY.equalsValue(triggerType) && !SmartJobUtil.checkFixedDelay(triggerValue)) { + return ResponseDTO.userErrorParam("固定间隔错误:整数且大于0"); + } + + // 更新数据 + jobEntity = SmartBeanUtil.copy(updateForm, SmartJobEntity.class); + jobDao.updateById(jobEntity); + + // 更新执行端 + SmartJobMsg jobMsg = new SmartJobMsg(); + jobMsg.setJobId(jobId); + jobMsg.setMsgType(SmartJobMsg.MsgTypeEnum.UPDATE_JOB); + jobMsg.setUpdateName(updateForm.getUpdateName()); + jobClientManager.publishToClient(jobMsg); + return ResponseDTO.ok(); + } + + /** + * 更新定时任务-是否开启 + * + * @param updateForm + * @return + */ + public ResponseDTO updateJobEnabled(SmartJobEnabledUpdateForm updateForm) { + Integer jobId = updateForm.getJobId(); + SmartJobEntity jobEntity = jobDao.selectById(jobId); + if (null == jobEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + Boolean enabledFlag = updateForm.getEnabledFlag(); + if (Objects.equals(enabledFlag, jobEntity.getEnabledFlag())) { + return ResponseDTO.ok(); + } + // 更新数据 + jobEntity = new SmartJobEntity(); + jobEntity.setJobId(jobId); + jobEntity.setEnabledFlag(enabledFlag); + jobEntity.setUpdateName(updateForm.getUpdateName()); + jobDao.updateById(jobEntity); + + // 更新执行端 + SmartJobMsg jobMsg = new SmartJobMsg(); + jobMsg.setJobId(jobId); + jobMsg.setMsgType(SmartJobMsg.MsgTypeEnum.UPDATE_JOB); + jobMsg.setUpdateName(updateForm.getUpdateName()); + jobClientManager.publishToClient(jobMsg); + return ResponseDTO.ok(); + } + + /** + * 执行定时任务 + * 忽略任务的开启状态,立即执行一次 + * + * @param executeForm + * @return + */ + public ResponseDTO execute(SmartJobExecuteForm executeForm) { + Integer jobId = executeForm.getJobId(); + SmartJobEntity jobEntity = jobDao.selectById(jobId); + if (null == jobEntity) { + return ResponseDTO.error(UserErrorCode.DATA_NOT_EXIST); + } + + // 更新执行端 + SmartJobMsg jobMsg = new SmartJobMsg(); + jobMsg.setJobId(jobId); + jobMsg.setParam(executeForm.getParam()); + jobMsg.setMsgType(SmartJobMsg.MsgTypeEnum.EXECUTE_JOB); + jobMsg.setUpdateName(executeForm.getUpdateName()); + jobClientManager.publishToClient(jobMsg); + return ResponseDTO.ok(); + } + + /** + * 新增定时任务 + * ps:目前没有业务场景需要通过接口 添加任务 + * 因为新增定时任务无论如何都需要 手动编码 + * 需要时手动给数据库增加一条就行 + * + * @return + * @author huke + */ + public ResponseDTO addJob() { + return ResponseDTO.userErrorParam("暂未支持"); + } + + /** + * 移除定时任务 + * ps:目前没有业务场景需要通过接口移除,理由同 {@link SmartJobService#addJob}, + * 彻底移除始终都需要手动删除代码 + * 如果只是想暂停任务执行,可以调用 {@link SmartJobService#updateJobEnabled} + * + * @return + * @author huke + */ + public ResponseDTO delJob() { + return ResponseDTO.userErrorParam("暂未支持"); + } +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobEnabledUpdateForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobEnabledUpdateForm.java new file mode 100644 index 00000000..d92a9aa7 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobEnabledUpdateForm.java @@ -0,0 +1,27 @@ +package net.lab1024.sa.base.module.support.job.api.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 定时任务-更新-开启状态 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Data +public class SmartJobEnabledUpdateForm { + + @Schema(description = "任务id") + @NotNull(message = "任务id不能为空") + private Integer jobId; + + @Schema(description = "是否启用") + @NotNull(message = "是否启用不能为空") + private Boolean enabledFlag; + + @Schema(hidden = true) + private String updateName; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobExecuteForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobExecuteForm.java new file mode 100644 index 00000000..a4d3b913 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobExecuteForm.java @@ -0,0 +1,28 @@ +package net.lab1024.sa.base.module.support.job.api.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotNull; + +/** + * 定时任务-手动执行 + * + * @author huke + * @date 2024/6/18 20:30 + */ +@Data +public class SmartJobExecuteForm { + + @Schema(description = "任务id") + @NotNull(message = "任务id不能为空") + private Integer jobId; + + @Schema(description = "定时任务参数|可选") + @Length(max = 2000, message = "定时任务参数最多2000字符") + private String param; + + @Schema(hidden = true) + private String updateName; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobLogQueryForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobLogQueryForm.java new file mode 100644 index 00000000..f405e7d5 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobLogQueryForm.java @@ -0,0 +1,34 @@ +package net.lab1024.sa.base.module.support.job.api.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; +import org.hibernate.validator.constraints.Length; + +import java.time.LocalDate; + +/** + * 定时任务-执行记录 分页查询 + * + * @author huke + * @date 2024/6/17 20:50 + */ +@Data +public class SmartJobLogQueryForm extends PageParam { + + @Schema(description = "搜索词|可选") + @Length(max = 50, message = "搜索词最多50字符") + private String searchWord; + + @Schema(description = "任务id|可选") + private Integer jobId; + + @Schema(description = "是否成功|可选") + private Boolean successFlag; + + @Schema(description = "开始时间|可选", example = "2024-06-06") + private LocalDate startTime; + + @Schema(description = "截止时间|可选", example = "2025-10-15") + private LocalDate endTime; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobLogVO.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobLogVO.java new file mode 100644 index 00000000..dc60cb72 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobLogVO.java @@ -0,0 +1,56 @@ +package net.lab1024.sa.base.module.support.job.api.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 定时任务-执行记录 vo + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Data +public class SmartJobLogVO { + + @Schema(description = "logId") + private Long logId; + + @Schema(description = "任务id") + private Integer jobId; + + @Schema(description = "任务名称") + private String jobName; + + @Schema(description = "定时任务参数|可选") + private String param; + + @Schema(description = "执行结果是否成功") + private Boolean successFlag; + + @Schema(description = "开始执行时间") + private LocalDateTime executeStartTime; + + @Schema(description = "执行时长-毫秒") + private Long executeTimeMillis; + + @Schema(description = "执行结果描述") + private String executeResult; + + @Schema(description = "执行结束时间") + private LocalDateTime executeEndTime; + + @Schema(description = "ip") + private String ip; + + @Schema(description = "进程id") + private String processId; + + @Schema(description = "程序目录") + private String programPath; + + private String createName; + + private LocalDateTime createTime; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobMsg.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobMsg.java new file mode 100644 index 00000000..c7cba95e --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobMsg.java @@ -0,0 +1,59 @@ +package net.lab1024.sa.base.module.support.job.api.domain; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 定时任务 发布/订阅消息对象 + * + * @author huke + * @date 2024/6/20 21:10 + */ +@Data +public class SmartJobMsg { + + /** + * 消息id 无需设置 + */ + private String msgId; + + /** + * 任务id + */ + private Integer jobId; + + /** + * 任务参数 + */ + private String param; + + /** + * 消息类型 + */ + private MsgTypeEnum msgType; + + /** + * 更新人 + */ + private String updateName; + + @Getter + @AllArgsConstructor + public enum MsgTypeEnum implements BaseEnum { + + /** + * 1 更新任务 + */ + UPDATE_JOB(1, "更新任务"), + + EXECUTE_JOB(2, "执行任务"), + + ; + + private final Integer value; + + private final String desc; + } +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobQueryForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobQueryForm.java new file mode 100644 index 00000000..a6091af7 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobQueryForm.java @@ -0,0 +1,30 @@ +package net.lab1024.sa.base.module.support.job.api.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import net.lab1024.sa.base.module.support.job.constant.SmartJobTriggerTypeEnum; +import org.hibernate.validator.constraints.Length; + +/** + * 定时任务 分页查询 + * + * @author huke + * @date 2024/6/17 20:50 + */ +@Data +public class SmartJobQueryForm extends PageParam { + + @Schema(description = "搜索词|可选") + @Length(max = 50, message = "搜索词最多50字符") + private String searchWord; + + @SchemaEnum(desc = "触发类型", value = SmartJobTriggerTypeEnum.class) + @CheckEnum(value = SmartJobTriggerTypeEnum.class, message = "触发类型错误") + private String triggerType; + + @Schema(description = "是否启用|可选") + private Boolean enabledFlag; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobUpdateForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobUpdateForm.java new file mode 100644 index 00000000..e30028f4 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobUpdateForm.java @@ -0,0 +1,63 @@ +package net.lab1024.sa.base.module.support.job.api.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import net.lab1024.sa.base.module.support.job.constant.SmartJobTriggerTypeEnum; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +/** + * 定时任务 更新 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Data +public class SmartJobUpdateForm { + + @Schema(description = "任务id") + @NotNull(message = "任务id不能为空") + private Integer jobId; + + @Schema(description = "任务名称") + @NotBlank(message = "任务名称不能为空") + @Length(max = 100, message = "任务名称最多100字符") + private String jobName; + + @Schema(description = "任务执行类") + @NotBlank(message = "任务执行类不能为空") + @Length(max = 200, message = "任务执行类最多200字符") + private String jobClass; + + @SchemaEnum(desc = "触发类型", value = SmartJobTriggerTypeEnum.class) + @CheckEnum(value = SmartJobTriggerTypeEnum.class, required = true, message = "触发类型错误") + private String triggerType; + + @Schema(description = "触发配置") + @NotBlank(message = "触发配置不能为空") + @Length(max = 100, message = "触发配置最多100字符") + private String triggerValue; + + @Schema(description = "定时任务参数|可选") + @Length(max = 1000, message = "定时任务参数最多1000字符") + private String param; + + @Schema(description = "是否开启") + @NotNull(message = "是否开启不能为空") + private Boolean enabledFlag; + + @Schema(description = "备注") + @Length(max = 250, message = "任务备注最多250字符") + private String remark; + + @NotNull(message = "排序不能为空") + @Schema(description = "排序") + private Integer sort; + + @Schema(hidden = true) + private String updateName; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobVO.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobVO.java new file mode 100644 index 00000000..d83d98be --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/api/domain/SmartJobVO.java @@ -0,0 +1,66 @@ +package net.lab1024.sa.base.module.support.job.api.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.json.serializer.enumeration.EnumSerialize; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.module.support.job.constant.SmartJobTriggerTypeEnum; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * 定时任务 vo + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Data +public class SmartJobVO { + + @Schema(description = "任务id") + private Integer jobId; + + @Schema(description = "任务名称") + private String jobName; + + @Schema(description = "执行类") + private String jobClass; + + @SchemaEnum(desc = "触发类型", value = SmartJobTriggerTypeEnum.class) + @EnumSerialize(SmartJobTriggerTypeEnum.class) + private String triggerType; + + @Schema(description = "触发配置") + private String triggerValue; + + @Schema(description = "定时任务参数|可选") + private String param; + + @Schema(description = "是否启用") + private Boolean enabledFlag; + + @Schema(description = "最后一执行时间") + private LocalDateTime lastExecuteTime; + + @Schema(description = "最后一次执行记录id") + private Long lastExecuteLogId; + + @Schema(description = "备注") + private String remark; + + @Schema(description = "排序") + private Integer sort; + + private String updateName; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; + + @Schema(description = "上次执行记录") + private SmartJobLogVO lastJobLog; + + @Schema(description = "未来N次任务执行时间") + private List nextJobExecuteTimeList; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/config/SmartJobAutoConfiguration.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/config/SmartJobAutoConfiguration.java new file mode 100644 index 00000000..25ad8726 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/config/SmartJobAutoConfiguration.java @@ -0,0 +1,52 @@ +package net.lab1024.sa.base.module.support.job.config; + +import net.lab1024.sa.base.module.support.job.core.SmartJob; +import net.lab1024.sa.base.module.support.job.core.SmartJobLauncher; +import net.lab1024.sa.base.module.support.job.repository.SmartJobRepository; +import org.redisson.api.RedissonClient; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.List; + +/** + * 定时任务 配置 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Configuration +@EnableConfigurationProperties(SmartJobConfig.class) +@ConditionalOnProperty( + prefix = SmartJobConfig.CONFIG_PREFIX, + name = "enabled", + havingValue = "true" +) +public class SmartJobAutoConfiguration { + + private final SmartJobConfig jobConfig; + + private final SmartJobRepository jobRepository; + + private final List jobInterfaceList; + + public SmartJobAutoConfiguration(SmartJobConfig jobConfig, + SmartJobRepository jobRepository, + List jobInterfaceList) { + this.jobConfig = jobConfig; + this.jobRepository = jobRepository; + this.jobInterfaceList = jobInterfaceList; + } + + /** + * 定时任务启动器 + * + * @return + */ + @Bean + public SmartJobLauncher initJobLauncher(RedissonClient redissonClient) { + return new SmartJobLauncher(jobConfig, jobRepository, jobInterfaceList, redissonClient); + } +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/config/SmartJobConfig.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/config/SmartJobConfig.java new file mode 100644 index 00000000..d2bee0d8 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/config/SmartJobConfig.java @@ -0,0 +1,39 @@ +package net.lab1024.sa.base.module.support.job.config; + + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * smart job 配置 + * 与配置文件参数对应 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@ConfigurationProperties(prefix = SmartJobConfig.CONFIG_PREFIX) +@Data +public class SmartJobConfig { + + public static final String CONFIG_PREFIX = "smart.job"; + + /** + * 任务执行核心线程数 偶数 默认2 + */ + private Integer corePoolSize = 2; + + /** + * 任务延迟初始化 默认30秒 + */ + private Integer initDelay = 30; + + /** + * 数据库配置检测-开关 默认开启 + */ + private Boolean dbRefreshEnabled = true; + + /** + * 数据库配置检测-执行间隔 默认120秒 + */ + private Integer dbRefreshInterval = 120; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobConst.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobConst.java new file mode 100644 index 00000000..4409ad33 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobConst.java @@ -0,0 +1,22 @@ +package net.lab1024.sa.base.module.support.job.constant; + +/** + * smart job 常量 + * + * @author huke + * @date 2024/6/19 20:25 + */ +public class SmartJobConst { + + public static final String SYSTEM_NAME = "system"; + + public static final String LOGO = " _____ __ __ __ \n" + + " / ___/____ ___ ____ ______/ /_ / /___ / /_ \n" + + " \\__ \\/ __ `__ \\/ __ `/ ___/ __/ __ / / __ \\/ __ \\\n" + + " ___/ / / / / / / /_/ / / / /_ / /_/ / /_/ / /_/ /\n" + + "/____/_/ /_/ /_/\\__,_/_/ \\__/ \\____/\\____/_.___/ \n" + + "-->任务执行线程池:%s\n" + + "-->任务初始化延迟:%s秒\n" + + "-->数据库配置检测:%s\n\n"; + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobTriggerTypeEnum.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobTriggerTypeEnum.java new file mode 100644 index 00000000..c2368c61 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobTriggerTypeEnum.java @@ -0,0 +1,30 @@ +package net.lab1024.sa.base.module.support.job.constant; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * job 任务触发类型 枚举类 + * + * @author huke + * @date 2024年6月29日 + **/ +@AllArgsConstructor +@Getter +public enum SmartJobTriggerTypeEnum implements BaseEnum { + + /** + * 1 cron表达式 + */ + CRON("cron", "cron表达式"), + + FIXED_DELAY("fixed_delay", "固定间隔"), + + ; + + private final String value; + + private final String desc; +} + diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobUtil.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobUtil.java new file mode 100644 index 00000000..adb2497d --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/constant/SmartJobUtil.java @@ -0,0 +1,188 @@ +package net.lab1024.sa.base.module.support.job.constant; + +import org.springframework.scheduling.support.CronExpression; + +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * smart job util + * + * @author huke + * @date 2024/6/18 20:00 + */ +public class SmartJobUtil { + + private SmartJobUtil() { + } + + /** + * 校验cron表达式 是否合法 + * + * @param cron + * @return + */ + public static boolean checkCron(String cron) { + return CronExpression.isValidExpression(cron); + } + + /** + * 校验固定间隔 值是否合法 + * + * @param val + * @return + */ + public static boolean checkFixedDelay(String val) { + int intVal; + try { + intVal = Integer.parseInt(val); + } catch (NumberFormatException e) { + return false; + } + return intVal > 0; + } + + /** + * 打印一些展示信息到控制台 + * 环保绿 + * + * @param info + */ + public static void printInfo(String info) { + System.out.printf("\033[32;1m %s \033[0m", info); + } + + /** + * 查询未来N次执行时间 从最后一次时间时间 开始计算 + * + * @param triggerType + * @param triggerVal + * @param lastExecuteTime + * @param num + * @return + */ + public static List queryNextTimeFromLast(String triggerType, + String triggerVal, + LocalDateTime lastExecuteTime, + int num) { + List nextTimeList = null; + if (SmartJobTriggerTypeEnum.CRON.equalsValue(triggerType)) { + nextTimeList = SmartJobUtil.queryNextTime(triggerVal, lastExecuteTime, num); + } else if (SmartJobTriggerTypeEnum.FIXED_DELAY.equalsValue(triggerType)) { + nextTimeList = SmartJobUtil.queryNextTime(getFixedDelayVal(triggerVal), lastExecuteTime, num); + } + return nextTimeList; + } + + /** + * 查询未来N次执行时间 从当前时间 开始计算 + * + * @param triggerType + * @param triggerVal + * @param lastExecuteTime + * @param num + * @return + */ + public static List queryNextTimeFromNow(String triggerType, + String triggerVal, + LocalDateTime lastExecuteTime, + int num) { + LocalDateTime nowTime = LocalDateTime.now(); + List nextTimeList = null; + if (SmartJobTriggerTypeEnum.CRON.equalsValue(triggerType)) { + nextTimeList = SmartJobUtil.queryNextTime(triggerVal, nowTime, num); + } else if (SmartJobTriggerTypeEnum.FIXED_DELAY.equalsValue(triggerType)) { + Integer fixedDelay = getFixedDelayVal(triggerVal); + LocalDateTime startTime = null == lastExecuteTime || lastExecuteTime.plusSeconds(fixedDelay).isBefore(nowTime) + ? nowTime : lastExecuteTime; + nextTimeList = SmartJobUtil.queryNextTime(fixedDelay, startTime, num); + } + return nextTimeList; + } + + /** + * 根据cron表达式 计算N次执行时间 + * + * @param cron + * @param startTime + * @param num + * @return + */ + public static List queryNextTime(String cron, LocalDateTime startTime, int num) { + if (null == startTime) { + return Collections.emptyList(); + } + CronExpression parse = CronExpression.parse(cron); + List timeList = new ArrayList<>(num); + for (int i = 0; i < num; i++) { + startTime = parse.next(startTime); + timeList.add(startTime); + } + return timeList; + } + + /** + * 根据 固定间隔 计算N次执行时间 + * + * @param fixDelaySecond + * @param startTime + * @param num + * @return + */ + public static List queryNextTime(Integer fixDelaySecond, LocalDateTime startTime, int num) { + if (null == startTime) { + return Collections.emptyList(); + } + List timeList = new ArrayList<>(num); + for (int i = 0; i < num; i++) { + startTime = startTime.plusSeconds(fixDelaySecond); + timeList.add(startTime); + } + return timeList; + } + + /** + * 获取固定间隔时间 + * + * @param val + * @return + */ + public static Integer getFixedDelayVal(String val) { + return Integer.parseInt(val); + } + + /** + * 获取当前 Java 应用程序的工作目录 + * + * @return + */ + public static String getProgramPath() { + return System.getProperty("user.dir"); + } + + /** + * 获取当前 Java 应用程序的进程id + * + * @return + */ + public static String getProcessId() { + RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean(); + return runtime.getName().split("@")[0]; + } + + public static void main(String[] args) { + LocalDateTime startTime = LocalDateTime.now(); + List timeList = SmartJobUtil.queryNextTime("5 * * * * *", startTime, 3); + System.out.println(timeList); + + timeList = SmartJobUtil.queryNextTime(10, startTime, 3); + System.out.println(timeList); + + System.out.println("project path ->" + getProgramPath()); + System.out.println("project process id ->" + getProcessId()); + } +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJob.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJob.java new file mode 100644 index 00000000..75496429 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJob.java @@ -0,0 +1,28 @@ +package net.lab1024.sa.base.module.support.job.core; + +/** + * 定时任务 执行接口 + * + * @author huke + * @date 2024/6/17 21:30 + */ +public interface SmartJob { + + /** + * 默认方法 + * 获取当前任务类名 + * + * @return + */ + default String getClassName() { + return this.getClass().getName(); + } + + /** + * 执行定时任务 + * + * @param param 可选参数 任务不需要时不用管 + * @return 可null, 自行组织语言描述执行结果,例如:本次处理数据N条 等 + */ + String run(String param); +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobExecutor.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobExecutor.java new file mode 100644 index 00000000..b933df47 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobExecutor.java @@ -0,0 +1,147 @@ +package net.lab1024.sa.base.module.support.job.core; + +import cn.hutool.core.exceptions.ExceptionUtil; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.base.common.util.SmartIpUtil; +import net.lab1024.sa.base.module.support.job.constant.SmartJobConst; +import net.lab1024.sa.base.module.support.job.constant.SmartJobUtil; +import net.lab1024.sa.base.module.support.job.repository.SmartJobRepository; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobEntity; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobLogEntity; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.util.StopWatch; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.concurrent.TimeUnit; + +/** + * 定时任务 执行器 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Slf4j +public class SmartJobExecutor implements Runnable { + + private final SmartJobEntity jobEntity; + + private final SmartJobRepository jobRepository; + + private final SmartJob jobInterface; + + private final RedissonClient redissonClient; + + private static final String EXECUTE_LOCK = "smart-job-lock-execute-"; + + public SmartJobExecutor(SmartJobEntity jobEntity, + SmartJobRepository jobRepository, + SmartJob jobInterface, + RedissonClient redissonClient) { + this.jobEntity = jobEntity; + this.jobRepository = jobRepository; + this.jobInterface = jobInterface; + this.redissonClient = redissonClient; + } + + /** + * 系统线程执行 + */ + @Override + public void run() { + // 获取当前任务执行锁 最多持有30s自动释放 + Integer jobId = jobEntity.getJobId(); + RLock rLock = redissonClient.getLock(EXECUTE_LOCK + jobId); + try { + boolean lock = rLock.tryLock(0, 30, TimeUnit.SECONDS); + if (!lock) { + return; + } + // 查询上次执行时间 校验执行间隔 + SmartJobEntity dbJobEntity = jobRepository.getJobDao().selectById(jobId); + if (null == dbJobEntity) { + return; + } + LocalDateTime lastExecuteTime = dbJobEntity.getLastExecuteTime(); + if (null != lastExecuteTime) { + LocalDateTime nextTime = SmartJobUtil.queryNextTimeFromLast(jobEntity.getTriggerType(), jobEntity.getTriggerValue(), lastExecuteTime, 1).get(0); + if (LocalDateTime.now().isBefore(nextTime)) { + return; + } + } + // 执行任务 + SmartJobLogEntity logEntity = this.execute(SmartJobConst.SYSTEM_NAME); + log.info("==== SmartJob ==== execute job->{},time-millis->{}ms", jobEntity.getJobName(), logEntity.getExecuteTimeMillis()); + } catch (Throwable t) { + log.error("==== SmartJob ==== execute err:", t); + } finally { + if (rLock.isHeldByCurrentThread()) { + rLock.unlock(); + } + } + } + + /** + * 执行任务 + * + * @param executorName + */ + public SmartJobLogEntity execute(String executorName) { + // 执行计时 + LocalDateTime startTime = LocalDateTime.now(); + StopWatch stopWatch = new StopWatch(); + stopWatch.start(); + + // 执行任务 + boolean successFlag = true; + String executeResult; + try { + executeResult = jobInterface.run(jobEntity.getParam()); + stopWatch.stop(); + } catch (Throwable t) { + stopWatch.stop(); + successFlag = false; + // ps:异常信息不大于数据库字段长度限制 + executeResult = ExceptionUtil.stacktraceToString(t, 1800); + log.error("==== SmartJob ==== execute err:", t); + } + + // 保存执行记录 + Integer jobId = jobEntity.getJobId(); + SmartJobLogEntity logEntity = new SmartJobLogEntity(); + logEntity.setJobId(jobId); + logEntity.setJobName(jobEntity.getJobName()); + logEntity.setParam(jobEntity.getParam()); + logEntity.setSuccessFlag(successFlag); + // 执行开始 结束时间 + logEntity.setExecuteStartTime(startTime); + long totalTimeMillis = stopWatch.getTotalTimeMillis(); + logEntity.setExecuteTimeMillis(totalTimeMillis); + logEntity.setExecuteEndTime(startTime.plus(totalTimeMillis, ChronoUnit.MILLIS)); + // 执行结果 + logEntity.setExecuteResult(executeResult); + logEntity.setIp(SmartIpUtil.getLocalFirstIp()); + logEntity.setProcessId(SmartJobUtil.getProcessId()); + logEntity.setProgramPath(SmartJobUtil.getProgramPath()); + logEntity.setCreateName(executorName); + + // 更新上次执行 + SmartJobEntity updateJobEntity = new SmartJobEntity(); + updateJobEntity.setJobId(jobId); + updateJobEntity.setLastExecuteTime(startTime); + + // 持久化数据 + jobRepository.saveLog(logEntity, updateJobEntity); + return logEntity; + } + + /** + * 查询 当前任务信息 + * + * @return + */ + public SmartJobEntity getJob() { + return jobEntity; + } +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobLauncher.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobLauncher.java new file mode 100644 index 00000000..8aece190 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobLauncher.java @@ -0,0 +1,148 @@ +package net.lab1024.sa.base.module.support.job.core; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.base.module.support.job.config.SmartJobConfig; +import net.lab1024.sa.base.module.support.job.constant.SmartJobConst; +import net.lab1024.sa.base.module.support.job.constant.SmartJobUtil; +import net.lab1024.sa.base.module.support.job.repository.SmartJobRepository; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobEntity; +import org.redisson.api.RedissonClient; +import org.springframework.util.CollectionUtils; + +import javax.annotation.PreDestroy; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * 定时任务 作业启动类 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Slf4j +public class SmartJobLauncher { + + private final SmartJobRepository jobRepository; + + private final List jobInterfaceList; + + private final RedissonClient redissonClient; + + public SmartJobLauncher(SmartJobConfig jobConfig, + SmartJobRepository jobRepository, + List jobInterfaceList, + RedissonClient redissonClient) { + this.jobRepository = jobRepository; + this.jobInterfaceList = jobInterfaceList; + this.redissonClient = redissonClient; + + // init job scheduler + SmartJobScheduler.init(jobConfig); + + // 任务自动检测配置 固定1个线程 + Integer initDelay = jobConfig.getInitDelay(); + Boolean refreshEnabled = jobConfig.getDbRefreshEnabled(); + Integer refreshInterval = jobConfig.getDbRefreshInterval(); + + ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("SmartJobLauncher-%d").build(); + ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, factory); + Runnable launcherRunnable = () -> { + try { + // 查询所有任务 + List smartJobList = this.queryJob(); + this.startOrRefreshJob(smartJobList); + } catch (Throwable t) { + log.error("SmartJob Error:", t); + } + // 只在启动时 执行一次 + if (!refreshEnabled) { + executor.shutdown(); + } + }; + executor.scheduleWithFixedDelay(launcherRunnable, initDelay, refreshInterval, TimeUnit.SECONDS); + + // 打印信息 + String refreshDesc = refreshEnabled ? "开启|检测间隔" + refreshInterval + "秒" : "关闭"; + String format = String.format(SmartJobConst.LOGO, jobConfig.getCorePoolSize(), initDelay, refreshDesc); + SmartJobUtil.printInfo(format); + } + + /** + * 查询数据库 + * 启动/刷新任务 + */ + public void startOrRefreshJob(List smartJobList) { + // 查询任务配置 + if (CollectionUtils.isEmpty(smartJobList) || CollectionUtils.isEmpty(jobInterfaceList)) { + log.info("==== SmartJob ==== job list empty"); + return; + } + + // 任务实现类 + Map jobImplMap = jobInterfaceList.stream().collect(Collectors.toMap(SmartJob::getClassName, Function.identity())); + for (SmartJobEntity jobEntity : smartJobList) { + // 任务是否存在 判断是否需要更新 + Integer jobId = jobEntity.getJobId(); + SmartJobEntity oldJobEntity = SmartJobScheduler.getJobInfo(jobId); + if (null != oldJobEntity) { + // 不需要更新 + if (!isNeedUpdate(oldJobEntity, jobEntity)) { + continue; + } + // 需要更新 移除原任务 + SmartJobScheduler.removeJob(jobId); + } + // 任务未开启 + if (!jobEntity.getEnabledFlag()) { + continue; + } + // 查找任务实现类 + SmartJob jobImpl = jobImplMap.get(jobEntity.getJobClass()); + if (null == jobImpl) { + continue; + } + // 添加任务 + SmartJobExecutor jobExecute = new SmartJobExecutor(jobEntity, jobRepository, jobImpl, redissonClient); + SmartJobScheduler.addJob(jobExecute); + } + List runjJobList = SmartJobScheduler.getJobInfo(); + List jobNameList = runjJobList.stream().map(SmartJobEntity::getJobName).collect(Collectors.toList()); + log.info("==== SmartJob ==== start/refresh job num:{}->{}", runjJobList.size(), jobNameList); + } + + /** + * 查询全部任务 + * + * @return + */ + private List queryJob() { + return jobRepository.getJobDao().selectList(null); + } + + /** + * 手动判断 任务配置 是否需要更新 + * 新增字段的话 在这个方法里增加判断 + * + * @return + */ + private static boolean isNeedUpdate(SmartJobEntity oldJob, SmartJobEntity newJob) { + // cron为空时 fixedDelay 才有意义 + return !Objects.equals(oldJob.getEnabledFlag(), newJob.getEnabledFlag()) + || !Objects.equals(oldJob.getTriggerType(), newJob.getTriggerType()) + || !Objects.equals(oldJob.getTriggerValue(), newJob.getTriggerValue()) + || !Objects.equals(oldJob.getJobClass(), newJob.getJobClass()); + } + + @PreDestroy + public void destroy() { + SmartJobScheduler.destroy(); + log.info("==== SmartJob ==== destroy job"); + } +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobScheduler.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobScheduler.java new file mode 100644 index 00000000..67067364 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/core/SmartJobScheduler.java @@ -0,0 +1,178 @@ +package net.lab1024.sa.base.module.support.job.core; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.base.module.support.job.config.SmartJobConfig; +import net.lab1024.sa.base.module.support.job.constant.SmartJobTriggerTypeEnum; +import net.lab1024.sa.base.module.support.job.constant.SmartJobUtil; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobEntity; +import org.apache.commons.lang3.tuple.Pair; +import org.springframework.scheduling.Trigger; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; +import org.springframework.scheduling.support.CronTrigger; +import org.springframework.scheduling.support.PeriodicTrigger; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * 定时任务 调度管理 + * + * @author huke + * @date 2024/6/22 21:30 + */ +@Slf4j +public class SmartJobScheduler { + + /** + * Spring线程池任务调度器 + */ + private static ThreadPoolTaskScheduler TASK_SCHEDULER; + + /** + * 定时任务 map + */ + private static Map>> JOB_FUTURE_MAP; + + private SmartJobScheduler() { + + } + + /** + * 初始化任务调度配置 + */ + public static void init(SmartJobConfig config) { + TASK_SCHEDULER = new ThreadPoolTaskScheduler(); + ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("SmartJobExecutor-%d").build(); + TASK_SCHEDULER.setThreadFactory(threadFactory); + TASK_SCHEDULER.setPoolSize(config.getCorePoolSize()); + // 线程池在关闭时会等待所有任务完成 + TASK_SCHEDULER.setWaitForTasksToCompleteOnShutdown(true); + // 在调用shutdown方法后,等待任务完成的最长时间 + TASK_SCHEDULER.setAwaitTerminationSeconds(10); + // 错误处理 + TASK_SCHEDULER.setErrorHandler((t) -> log.error("SmartJobExecute Err:", t)); + // 当一个任务在被调度执行前被取消时,是否应该从线程池的任务队列中移除 + TASK_SCHEDULER.setRemoveOnCancelPolicy(true); + TASK_SCHEDULER.initialize(); + + JOB_FUTURE_MAP = new ConcurrentHashMap<>(); + } + + /** + * 获取任务执行对象 + * + * @param jobId + * @return + */ + public static ScheduledFuture getJobFuture(Integer jobId) { + Pair> pair = JOB_FUTURE_MAP.get(jobId); + if (null == pair) { + return null; + } + return pair.getRight(); + } + + /** + * 获取当前所有执行任务 + * + * @return + */ + public static List getJobInfo() { + return JOB_FUTURE_MAP.values().stream().map(Pair::getLeft).collect(Collectors.toList()); + } + + /** + * 获取任务执行实体类 + * + * @param jobId + * @return + */ + public static SmartJobEntity getJobInfo(Integer jobId) { + Pair> pair = JOB_FUTURE_MAP.get(jobId); + if (null == pair) { + return null; + } + return pair.getLeft(); + } + + /** + * 添加任务 + * + * @param jobExecute + * @return + */ + public static void addJob(SmartJobExecutor jobExecute) { + // 任务是否存在 + SmartJobEntity jobEntity = jobExecute.getJob(); + Integer jobId = jobEntity.getJobId(); + if (JOB_FUTURE_MAP.containsKey(jobId)) { + // 移除任务 + removeJob(jobId); + } + // 任务触发类型 + Trigger trigger = null; + String triggerType = jobEntity.getTriggerType(); + String triggerValue = jobEntity.getTriggerValue(); + // 优先 cron 表达式 + if (SmartJobTriggerTypeEnum.CRON.equalsValue(triggerType)) { + trigger = new CronTrigger(triggerValue); + } else if (SmartJobTriggerTypeEnum.FIXED_DELAY.equalsValue(triggerType)) { + trigger = new PeriodicTrigger(SmartJobUtil.getFixedDelayVal(triggerValue), TimeUnit.SECONDS); + } + String jobName = jobEntity.getJobName(); + if (null == trigger) { + log.error("==== SmartJob ==== trigger-value not null {}", jobName); + return; + } + // 执行任务 + ScheduledFuture schedule = TASK_SCHEDULER.schedule(jobExecute, trigger); + JOB_FUTURE_MAP.put(jobId, Pair.of(jobEntity, schedule)); + log.info("==== SmartJob ==== add job:{}", jobName); + } + + /** + * 移除任务 + * 等待任务执行完成后移除 + * + * @param jobId + */ + public static void removeJob(Integer jobId) { + ScheduledFuture jobFuture = getJobFuture(jobId); + if (null == jobFuture) { + return; + } + // 结束任务 + stopJob(jobFuture); + JOB_FUTURE_MAP.remove(jobId); + log.info("==== SmartJob ==== remove job:{}", jobId); + } + + /** + * 停止所有定时任务 + */ + public static void destroy() { + // 启动一个有序的关闭过程,在这个过程中,不再接受新的任务提交,但已提交的任务(包括正在执行的和队列中等待的)会被允许执行完成。 + TASK_SCHEDULER.destroy(); + JOB_FUTURE_MAP.clear(); + } + + /** + * 结束任务 + * 如果任务还没有开始执行,会直接被取消。 + * 如果任务已经开始执行,此时不会中断执行中的线程,任务会执行完成再被取消 + * + * @param scheduledFuture + */ + private static void stopJob(ScheduledFuture scheduledFuture) { + if (null == scheduledFuture || scheduledFuture.isCancelled()) { + return; + } + scheduledFuture.cancel(false); + } +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobDao.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobDao.java new file mode 100644 index 00000000..703a90de --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobDao.java @@ -0,0 +1,32 @@ +package net.lab1024.sa.base.module.support.job.repository; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.base.module.support.job.api.domain.SmartJobQueryForm; +import net.lab1024.sa.base.module.support.job.api.domain.SmartJobVO; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 定时任务 dao + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Mapper +@Component +public interface SmartJobDao extends BaseMapper { + + /** + * 定时任务-分页查询 + * + * @param page + * @param queryForm + * @return + */ + List query(Page page, @Param("query") SmartJobQueryForm queryForm); +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobLogDao.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobLogDao.java new file mode 100644 index 00000000..edaf8fc8 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobLogDao.java @@ -0,0 +1,32 @@ +package net.lab1024.sa.base.module.support.job.repository; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.base.module.support.job.api.domain.SmartJobLogQueryForm; +import net.lab1024.sa.base.module.support.job.api.domain.SmartJobLogVO; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobLogEntity; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 定时任务-执行记录 dao + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Mapper +@Component +public interface SmartJobLogDao extends BaseMapper { + + /** + * 定时任务-执行记录-分页查询 + * + * @param page + * @param queryForm + * @return + */ + List query(Page page, @Param("query") SmartJobLogQueryForm queryForm); +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobRepository.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobRepository.java new file mode 100644 index 00000000..baa1d596 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/SmartJobRepository.java @@ -0,0 +1,42 @@ +package net.lab1024.sa.base.module.support.job.repository; + +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobEntity; +import net.lab1024.sa.base.module.support.job.repository.domain.SmartJobLogEntity; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * job 持久化业务 + * + * @author huke + * @date 2024/6/22 22:28 + */ +@Service +public class SmartJobRepository { + + @Autowired + private SmartJobDao jobDao; + + @Autowired + private SmartJobLogDao jobLogDao; + + public SmartJobDao getJobDao() { + return jobDao; + } + + /** + * 保存执行记录 + * + * @param logEntity + * @param jobEntity + */ + @Transactional(rollbackFor = Throwable.class) + public void saveLog(SmartJobLogEntity logEntity, SmartJobEntity jobEntity) { + jobLogDao.insert(logEntity); + + jobEntity.setLastExecuteLogId(logEntity.getLogId()); + jobDao.updateById(jobEntity); + } + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/domain/SmartJobEntity.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/domain/SmartJobEntity.java new file mode 100644 index 00000000..7b470879 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/domain/SmartJobEntity.java @@ -0,0 +1,84 @@ +package net.lab1024.sa.base.module.support.job.repository.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import net.lab1024.sa.base.module.support.job.constant.SmartJobTriggerTypeEnum; + +import java.time.LocalDateTime; + +/** + * 定时任务 实体类 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Data +@TableName("t_smart_job") +public class SmartJobEntity { + + /** + * 任务id + */ + @TableId(type = IdType.AUTO) + private Integer jobId; + + /** + * 任务名称 + */ + private String jobName; + + /** + * 执行类 + */ + private String jobClass; + + /** + * 触发类型 + * + * @see SmartJobTriggerTypeEnum + */ + private String triggerType; + + /** + * 触发配置 + */ + private String triggerValue; + + /** + * 定时任务参数 可选 + */ + private String param; + + /** + * 是否启用 + */ + private Boolean enabledFlag; + + /** + * 最后一执行时间 + */ + private LocalDateTime lastExecuteTime; + + /** + * 最后一次执行记录id + */ + private Long lastExecuteLogId; + + /** + * 备注描述 可选 + */ + private String remark; + + /** + * 排序 + */ + private Integer sort; + + private String updateName; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/domain/SmartJobLogEntity.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/domain/SmartJobLogEntity.java new file mode 100644 index 00000000..95c1d495 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/repository/domain/SmartJobLogEntity.java @@ -0,0 +1,81 @@ +package net.lab1024.sa.base.module.support.job.repository.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 定时任务 执行记录 实体类 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Data +@TableName("t_smart_job_log") +public class SmartJobLogEntity { + + @TableId(type = IdType.AUTO) + private Long logId; + + /** + * 任务id + */ + private Integer jobId; + + /** + * 任务名称 + */ + private String jobName; + + /** + * 定时任务参数 可选 + */ + private String param; + + /** + * 执行结果 是否成功 + */ + private Boolean successFlag; + + /** + * 开始执行时间 + */ + private LocalDateTime executeStartTime; + + /** + * 执行时长-毫秒 + */ + private Long executeTimeMillis; + + /** + * 执行结束时间 + */ + private LocalDateTime executeEndTime; + + /** + * 执行结果 描述 可选 + */ + private String executeResult; + + /** + * ip + */ + private String ip; + + /** + * 进程id + */ + private String processId; + + /** + * 程序目录 + */ + private String programPath; + + private String createName; + + private LocalDateTime createTime; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/SmartJobSample1.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/SmartJobSample1.java new file mode 100644 index 00000000..70369151 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/SmartJobSample1.java @@ -0,0 +1,29 @@ +package net.lab1024.sa.base.module.support.job.sample; + +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.base.module.support.job.core.SmartJob; +import org.springframework.stereotype.Service; + +/** + * 定时任务 示例1 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Slf4j +@Service +public class SmartJobSample1 implements SmartJob { + + /** + * 定时任务示例 + * + * @param param 可选参数 任务不需要时不用管 + * @return + */ + @Override + public String run(String param) { + // 写点什么业务逻辑 + return "执行完毕,随便说点什么吧"; + } + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/SmartJobSample2.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/SmartJobSample2.java new file mode 100644 index 00000000..18d9a215 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/SmartJobSample2.java @@ -0,0 +1,48 @@ +package net.lab1024.sa.base.module.support.job.sample; + +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.base.module.support.config.ConfigDao; +import net.lab1024.sa.base.module.support.config.domain.ConfigEntity; +import net.lab1024.sa.base.module.support.job.core.SmartJob; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +/** + * 定时任务 示例2 + * + * @author huke + * @date 2024/6/17 21:30 + */ +@Slf4j +@Service +public class SmartJobSample2 implements SmartJob { + + @Autowired + private ConfigDao configDao; + + /** + * 定时任务示例 + * 需要事务时 添加 @Transactional 注解 + * + * @param param 可选参数 任务不需要时不用管 + * @return + */ + @Transactional(rollbackFor = Throwable.class) + @Override + public String run(String param) { + // 随便更新点什么东西 + ConfigEntity configEntity = new ConfigEntity(); + configEntity.setConfigId(1L); + configEntity.setRemark(param); + configDao.updateById(configEntity); + + configEntity = new ConfigEntity(); + configEntity.setConfigId(2L); + configEntity.setRemark("SmartJob Sample2 update"); + configDao.updateById(configEntity); + + return "执行成功,本次处理数据1条"; + } + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/package-info.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/package-info.java new file mode 100644 index 00000000..d72e5a7e --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/job/sample/package-info.java @@ -0,0 +1,5 @@ +/** + * 定时任务 示例包 + * 可以删除 + */ +package net.lab1024.sa.base.module.support.job.sample; \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/loginlog/domain/LoginLogQueryForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/loginlog/domain/LoginLogQueryForm.java index 2aa44194..7af0dbe6 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/loginlog/domain/LoginLogQueryForm.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/loginlog/domain/LoginLogQueryForm.java @@ -16,6 +16,12 @@ import net.lab1024.sa.base.common.domain.PageParam; @Data public class LoginLogQueryForm extends PageParam { + @Schema(description = "用户ID") + private Long userId; + + @Schema(description = "用户类型") + private Integer userType; + @Schema(description = "开始日期") private String startDate; diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/constant/MessageTemplateEnum.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/constant/MessageTemplateEnum.java new file mode 100644 index 00000000..d9c6785b --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/constant/MessageTemplateEnum.java @@ -0,0 +1,31 @@ +package net.lab1024.sa.base.module.support.message.constant; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.lab1024.sa.base.common.enumeration.BaseEnum; + +/** + * 消息模板类型 + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@Getter +@AllArgsConstructor +public enum MessageTemplateEnum implements BaseEnum { + + + + ORDER_AUDIT(1000, "订单审批", MessageTypeEnum.ORDER, "您有一个订单等待审批,订单号【${orderNumber}】"), + + ; + + private final Integer value; + + private final String desc; + + private final MessageTypeEnum messageTypeEnum; + + private final String content; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/constant/MessageTypeEnum.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/constant/MessageTypeEnum.java new file mode 100644 index 00000000..b94cb100 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/constant/MessageTypeEnum.java @@ -0,0 +1,27 @@ +package net.lab1024.sa.base.module.support.message.constant; + + +import lombok.AllArgsConstructor; +import lombok.Getter; +import net.lab1024.sa.base.common.enumeration.BaseEnum; + + +/** + * 消息类型 + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@Getter +@AllArgsConstructor +public enum MessageTypeEnum implements BaseEnum { + + MAIL(1, "站内信"), + + ORDER(2, "订单"), + ; + + private final Integer value; + + private final String desc; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/controller/MessageController.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/controller/MessageController.java new file mode 100644 index 00000000..3a1548fc --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/controller/MessageController.java @@ -0,0 +1,68 @@ +package net.lab1024.sa.base.module.support.message.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import net.lab1024.sa.base.common.controller.SupportBaseController; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.domain.RequestUser; +import net.lab1024.sa.base.common.domain.ResponseDTO; +import net.lab1024.sa.base.common.util.SmartRequestUtil; +import net.lab1024.sa.base.constant.SwaggerTagConst; +import net.lab1024.sa.base.module.support.message.domain.MessageQueryForm; +import net.lab1024.sa.base.module.support.message.domain.MessageVO; +import net.lab1024.sa.base.module.support.message.service.MessageService; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +/** + * 消息 + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@RestController +@Tag(name = SwaggerTagConst.Support.MESSAGE) +public class MessageController extends SupportBaseController { + + @Resource + private MessageService messageService; + + @Operation(summary = "分页查询我的消息 @luoyi") + @PostMapping("/message/queryMyMessage") + public ResponseDTO> query(@RequestBody @Valid MessageQueryForm queryForm) { + RequestUser user = SmartRequestUtil.getRequestUser(); + if(user == null){ + return ResponseDTO.userErrorParam("用户未登录"); + } + + queryForm.setSearchCount(false); + queryForm.setReceiverUserId(user.getUserId()); + queryForm.setReceiverUserType(user.getUserType().getValue()); + return ResponseDTO.ok(messageService.query(queryForm)); + } + + @Operation(summary = "查询未读消息数量 @luoyi") + @GetMapping("/message/getUnreadCount") + public ResponseDTO getUnreadCount() { + RequestUser user = SmartRequestUtil.getRequestUser(); + if(user == null){ + return ResponseDTO.userErrorParam("用户未登录"); + } + return ResponseDTO.ok(messageService.getUnreadCount(user.getUserType(), user.getUserId())); + } + + @Operation(summary = "更新已读 @luoyi") + @GetMapping("/message/read/{messageId}") + public ResponseDTO updateReadFlag(@PathVariable Long messageId) { + RequestUser user = SmartRequestUtil.getRequestUser(); + if(user == null){ + return ResponseDTO.userErrorParam("用户未登录"); + } + + messageService.updateReadFlag(messageId, user.getUserType(), user.getUserId()); + return ResponseDTO.ok(); + } + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/dao/MessageDao.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/dao/MessageDao.java new file mode 100644 index 00000000..80ec9e75 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/dao/MessageDao.java @@ -0,0 +1,46 @@ +package net.lab1024.sa.base.module.support.message.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import net.lab1024.sa.base.module.support.message.domain.MessageEntity; +import net.lab1024.sa.base.module.support.message.domain.MessageQueryForm; +import net.lab1024.sa.base.module.support.message.domain.MessageVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 消息 接受者类型枚举 + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@Component +@Mapper +public interface MessageDao extends BaseMapper { + + /** + * 分页查询消息 + * + */ + List query(Page page, @Param("query") MessageQueryForm queryForm); + + /** + * 更新已读状态 + */ + Integer updateReadFlag(@Param("messageId") Long messageId, + @Param("receiverUserType") Integer receiverUserType, + @Param("receiverUserId") Long receiverUserId, + @Param("readFlag") Boolean readFlag); + + /** + * 查询未读消息数 + */ + Long getUnreadCount( @Param("receiverUserType") Integer receiverUserType, + @Param("receiverUserId") Long receiverUserId); + + + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageEntity.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageEntity.java new file mode 100644 index 00000000..673ed691 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageEntity.java @@ -0,0 +1,70 @@ +package net.lab1024.sa.base.module.support.message.domain; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import net.lab1024.sa.base.module.support.message.constant.MessageTypeEnum; + +import java.time.LocalDateTime; + +/** + * 消息实体 + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@Data +@TableName("t_message") +public class MessageEntity { + + @TableId(type = IdType.AUTO) + private Long messageId; + + /** + * 消息类型 + * + * @see MessageTypeEnum + */ + private Integer messageType; + /** + * 接收者类型 + * + * @see net.lab1024.sa.base.common.enumeration.UserTypeEnum + */ + private Integer receiverUserType; + + /** + * 接收者id + */ + private Long receiverUserId; + + /** + * 相关业务id + */ + private String dataId; + + /** + * 消息标题 + */ + private String title; + + /** + * 消息内容 + */ + private String content; + + /** + * 是否已读 + */ + private Boolean readFlag; + + /** + * 已读时间 + */ + private LocalDateTime readTime; + + private LocalDateTime updateTime; + + private LocalDateTime createTime; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageQueryForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageQueryForm.java new file mode 100644 index 00000000..b8613a2a --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageQueryForm.java @@ -0,0 +1,44 @@ +package net.lab1024.sa.base.module.support.message.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.domain.PageParam; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.common.validator.enumeration.CheckEnum; +import net.lab1024.sa.base.module.support.message.constant.MessageTypeEnum; +import org.hibernate.validator.constraints.Length; + +import java.time.LocalDate; + +/** + * 消息查询form + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@Data +public class MessageQueryForm extends PageParam { + + @Schema(description = "搜索词") + @Length(max = 50, message = "搜索词最多50字符") + private String searchWord; + + @SchemaEnum(value = MessageTypeEnum.class) + @CheckEnum(value = MessageTypeEnum.class, message = "消息类型") + private Integer messageType; + + @Schema(description = "是否已读") + private Boolean readFlag; + + @Schema(description = "查询开始时间") + private LocalDate startDate; + + @Schema(description = "查询结束时间") + private LocalDate endDate; + + @Schema(hidden = true) + private Long receiverUserId; + + @Schema(hidden = true) + private Integer receiverUserType; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageSendForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageSendForm.java new file mode 100644 index 00000000..fa08df1c --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageSendForm.java @@ -0,0 +1,45 @@ +package net.lab1024.sa.base.module.support.message.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.enumeration.UserTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.module.support.message.constant.MessageTypeEnum; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +/** + * 消息发送form + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@Data +public class MessageSendForm { + + @SchemaEnum(value = MessageTypeEnum.class, desc = "消息类型") + @NotNull(message = "消息类型不能为空") + private Integer messageType; + + @SchemaEnum(value = UserTypeEnum.class, desc = "接收者类型") + @NotNull(message = "接收者类型不能为空") + private Integer receiverUserType; + + @Schema(description = "接收者id") + @NotNull(message = "接收者id不能为空") + private Long receiverUserId; + + @Schema(description = "标题") + @NotBlank(message = "标题") + private String title; + + @Schema(description = "内容") + @NotBlank(message = "内容") + private String content; + + /** + * 相关业务id | 可选 + */ + private Object dataId; + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageTemplateSendForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageTemplateSendForm.java new file mode 100644 index 00000000..f6eb622b --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageTemplateSendForm.java @@ -0,0 +1,41 @@ +package net.lab1024.sa.base.module.support.message.domain; + +import lombok.Data; +import net.lab1024.sa.base.common.enumeration.UserTypeEnum; +import net.lab1024.sa.base.module.support.message.constant.MessageTemplateEnum; + +import javax.validation.constraints.NotNull; +import java.util.Map; + +/** + * 消息发送form + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@Data +public class MessageTemplateSendForm { + + @NotNull(message = "消息子类型不能为空") + private MessageTemplateEnum messageTemplateEnum; + + @NotNull(message = "接收者类型不能为空") + private UserTypeEnum receiverUserType; + + @NotNull(message = "接收者id不能为空") + private Long receiverUserId; + + /** + * 相关业务id | 可选 + * 用于跳转具体业务 + */ + private Object dataId; + + /** + * 消息参数 | 可选 + * 例:订单号:【{orderId}】{time}所提交的对账单被作废,请核实信息重新提交~ + * {orderId} {time} 就是消息的参数变量 + * 发送消息时 需要在map中放入k->orderId k->time + */ + private Map contentParam; +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageVO.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageVO.java new file mode 100644 index 00000000..eb7366fe --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/domain/MessageVO.java @@ -0,0 +1,48 @@ +package net.lab1024.sa.base.module.support.message.domain; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import net.lab1024.sa.base.common.enumeration.UserTypeEnum; +import net.lab1024.sa.base.common.swagger.SchemaEnum; +import net.lab1024.sa.base.module.support.message.constant.MessageTypeEnum; + +import java.time.LocalDateTime; + +/** + * 消息 + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@Data +public class MessageVO { + + private Long messageId; + + @SchemaEnum(value = MessageTypeEnum.class) + private Integer messageType; + + @SchemaEnum(value = UserTypeEnum.class) + private Integer receiverUserType; + + @Schema(description = "接收者id") + private Long receiverUserId; + + @Schema(description = "相关业务id") + private String dataId; + + @Schema(description = "消息标题") + private String title; + + @Schema(description = "消息内容") + private String content; + + @Schema(description = "是否已读") + private Boolean readFlag; + + @Schema(description = "已读时间") + private LocalDateTime readTime; + + @Schema(description = "创建时间") + private LocalDateTime createTime; +} \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/service/MessageManager.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/service/MessageManager.java new file mode 100644 index 00000000..e1e24196 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/service/MessageManager.java @@ -0,0 +1,18 @@ +package net.lab1024.sa.base.module.support.message.service; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.lab1024.sa.base.module.support.message.dao.MessageDao; +import net.lab1024.sa.base.module.support.message.domain.MessageEntity; +import org.springframework.stereotype.Service; + +/** + * 消息manager + * + * @author luoyi + * @date 2024/06/22 20:20 + */ +@Service +public class MessageManager extends ServiceImpl { + + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/service/MessageService.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/service/MessageService.java new file mode 100644 index 00000000..0a9f5a84 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/message/service/MessageService.java @@ -0,0 +1,108 @@ +package net.lab1024.sa.base.module.support.message.service; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.google.common.collect.Lists; +import net.lab1024.sa.base.common.domain.PageResult; +import net.lab1024.sa.base.common.enumeration.UserTypeEnum; +import net.lab1024.sa.base.common.util.SmartBeanUtil; +import net.lab1024.sa.base.common.util.SmartPageUtil; +import net.lab1024.sa.base.module.support.message.constant.MessageTemplateEnum; +import net.lab1024.sa.base.module.support.message.dao.MessageDao; +import net.lab1024.sa.base.module.support.message.domain.*; +import org.apache.commons.text.StringSubstitutor; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author luoyi + * @date 2024/6/27 12:14 上午 + */ +@Service +public class MessageService { + + @Resource + private MessageDao messageDao; + + @Resource + private MessageManager messageManager; + + /** + * 分页查询 消息 + */ + public PageResult query(MessageQueryForm queryForm) { + Page page = SmartPageUtil.convert2PageQuery(queryForm); + List messageVOList = messageDao.query(page, queryForm); + return SmartPageUtil.convert2PageResult(page, messageVOList); + } + + /** + * 查询未读消息数量 + */ + public Long getUnreadCount(UserTypeEnum userType, Long userId) { + return messageDao.getUnreadCount(userType.getValue(), userId); + } + + /** + * 更新已读状态 + */ + public void updateReadFlag(Long messageId, UserTypeEnum userType, Long receiverUserId) { + messageDao.updateReadFlag(messageId, userType.getValue(), receiverUserId, true); + } + + + /** + * 发送【模板消息】 + */ + public void sendTemplateMessage(MessageTemplateSendForm... sendTemplateForms) { + List sendFormList = Lists.newArrayList(); + for (MessageTemplateSendForm sendTemplateForm : sendTemplateForms) { + MessageTemplateEnum msgTemplateTypeEnum = sendTemplateForm.getMessageTemplateEnum(); + StringSubstitutor stringSubstitutor = new StringSubstitutor(sendTemplateForm.getContentParam()); + String content = stringSubstitutor.replace(msgTemplateTypeEnum.getContent()); + + MessageSendForm messageSendForm = new MessageSendForm(); + messageSendForm.setMessageType(msgTemplateTypeEnum.getMessageTypeEnum().getValue()); + messageSendForm.setReceiverUserType(sendTemplateForm.getReceiverUserType().getValue()); + messageSendForm.setReceiverUserId(sendTemplateForm.getReceiverUserId()); + messageSendForm.setTitle(msgTemplateTypeEnum.getDesc()); + messageSendForm.setContent(content); + messageSendForm.setDataId(sendTemplateForm.getDataId()); + sendFormList.add(messageSendForm); + + } + this.sendMessage(sendFormList); + } + + /** + * 发送消息 + */ + public void sendMessage(MessageSendForm... sendForms) { + this.sendMessage(Lists.newArrayList(sendForms)); + } + + /** + * 批量发送通知消息 + */ + public void sendMessage(List sendList) { + for (MessageSendForm sendDTO : sendList) { + String verify = SmartBeanUtil.verify(sendDTO); + if (null != verify) { + throw new RuntimeException("send msg error: " + verify); + } + } + List messageEntityList = sendList.stream().map(e -> { + MessageEntity messageEntity = new MessageEntity(); + messageEntity.setMessageType(e.getMessageType()); + messageEntity.setReceiverUserType(e.getReceiverUserType()); + messageEntity.setReceiverUserId(e.getReceiverUserId()); + messageEntity.setDataId(String.valueOf(e.getDataId())); + messageEntity.setTitle(e.getTitle()); + messageEntity.setContent(e.getContent()); + return messageEntity; + }).collect(Collectors.toList()); + messageManager.saveBatch(messageEntityList); + } +} \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/operatelog/domain/OperateLogQueryForm.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/operatelog/domain/OperateLogQueryForm.java index ed3f49be..53bdbce7 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/operatelog/domain/OperateLogQueryForm.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/operatelog/domain/OperateLogQueryForm.java @@ -16,6 +16,11 @@ import lombok.Data; @Data public class OperateLogQueryForm extends PageParam { + @Schema(description = "用户ID") + private Long operateUserId; + + @Schema(description = "用户类型") + private Integer operateUserType; @Schema(description = "开始日期") private String startDate; diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/redis/RedissonService.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/redis/RedissonService.java new file mode 100644 index 00000000..aaab74a8 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/redis/RedissonService.java @@ -0,0 +1,139 @@ +package net.lab1024.sa.base.module.support.redis; + +import lombok.extern.slf4j.Slf4j; +import net.lab1024.sa.base.common.exception.BusinessException; +import org.redisson.api.RBucket; +import org.redisson.api.RIdGenerator; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.Duration; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; + +/** + * Redisson 业务 + * + * @author huke + * @date 2024/6/19 20:39 + */ +@Slf4j +@Service +public class RedissonService { + + @Autowired + private final RedissonClient redissonClient; + + public RedissonService(RedissonClient redissonClient) { + this.redissonClient = redissonClient; + } + + public RedissonClient getRedissonClient() { + return redissonClient; + } + + /** + * 获取锁 并 执行程序 + * + * @param lockKey + * @param waitTime 毫秒 + * @param lockTime 毫秒 + * @param supplier + */ + public T executeWithLock(String lockKey, long waitTime, long lockTime, Supplier supplier) { + // 获取锁 + RLock lock = this.tryLock(lockKey, waitTime, lockTime); + try { + return supplier.get(); + } finally { + // 释放锁 + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + } + + /** + * 获取锁 并 执行程序 + * + * @param lockKey + * @param waitTime 毫秒 + * @param lockTime 毫秒 + * @param runnable + */ + public void executeWithLock(String lockKey, long waitTime, long lockTime, Runnable runnable) { + // 获取锁 + RLock lock = this.tryLock(lockKey, waitTime, lockTime); + try { + runnable.run(); + } finally { + // 释放锁 + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + } + + /** + * 尝试获取锁 + * 最多等待 waitTime 毫秒 + * 获取锁成功后占用 lockTime 毫秒 + * ps:需要手动解锁 lock.unlock() + * + * @param lockKey + * @param waitTime 毫秒 + * @param lockTime 毫秒 + * @return + */ + public RLock tryLock(String lockKey, long waitTime, long lockTime) { + RLock lock = redissonClient.getLock(lockKey); + try { + boolean getLock = lock.tryLock(waitTime, lockTime, TimeUnit.MILLISECONDS); + if (getLock) { + return lock; + } + } catch (InterruptedException e) { + log.error("Redisson tryLock", e); + } + throw new BusinessException("业务繁忙,请稍后重试~"); + } + + /** + * 获取 id 生成器 + * nextId 可生成连续不重复的id + * + * @param key + * @return + */ + public RIdGenerator idGenerator(String key) { + return redissonClient.getIdGenerator(key); + } + + /** + * 存放任意数据类型 + * + * @param key + * @param v + * @param duration + * @param + */ + public void putObj(String key, T v, Duration duration) { + redissonClient.getBucket(key).set(v, duration); + } + + /** + * 获取任意数据类型 + * + * @param key + * @param clazz + * @param + * @return 如果没有找到则返回null + */ + public T getObj(String key, Class clazz) { + RBucket bucket = redissonClient.getBucket(key); + return bucket.get(); + } + +} diff --git a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/reload/core/SmartReloadManager.java b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/reload/core/SmartReloadManager.java index 18c8721d..966715d4 100644 --- a/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/reload/core/SmartReloadManager.java +++ b/smart-admin-api/sa-base/src/main/java/net/lab1024/sa/base/module/support/reload/core/SmartReloadManager.java @@ -6,9 +6,15 @@ import net.lab1024.sa.base.module.support.reload.core.annoation.SmartReload; import net.lab1024.sa.base.module.support.reload.core.domain.SmartReloadObject; import net.lab1024.sa.base.module.support.reload.core.thread.SmartReloadRunnable; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.config.BeanPostProcessor; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.annotation.Resource; import java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -24,19 +30,32 @@ import java.util.concurrent.TimeUnit; * @Date 2015-03-02 19:11:52 * @Wechat zhuoda1024 * @Email lab1024@163.com - * @Copyright 1024创新实验室 + * @Copyright 1024创新实验室 */ @Slf4j +@Service public class SmartReloadManager implements BeanPostProcessor { private static final String THREAD_NAME_PREFIX = "smart-reload"; private static final int THREAD_COUNT = 1; - private Map reloadObjectMap = new ConcurrentHashMap<>(); + @Value("${reload.interval-seconds}") + private Integer intervalSeconds; + + @Resource + private AbstractSmartReloadCommand reloadCommand; + + private final Map reloadObjectMap = new ConcurrentHashMap<>(); private ScheduledThreadPoolExecutor threadPoolExecutor; - public SmartReloadManager(AbstractSmartReloadCommand reloadCommand, int intervalSeconds) { + + @PostConstruct + public void init() { + if (threadPoolExecutor != null) { + return; + } + this.threadPoolExecutor = new ScheduledThreadPoolExecutor(THREAD_COUNT, r -> { Thread t = new Thread(r, THREAD_NAME_PREFIX); if (!t.isDaemon()) { @@ -44,17 +63,23 @@ public class SmartReloadManager implements BeanPostProcessor { } return t; }); - this.threadPoolExecutor.scheduleWithFixedDelay(new SmartReloadRunnable(reloadCommand), 10, intervalSeconds, TimeUnit.SECONDS); - reloadCommand.setReloadManager(this); + this.threadPoolExecutor.scheduleWithFixedDelay(new SmartReloadRunnable(this.reloadCommand), 10, this.intervalSeconds, TimeUnit.SECONDS); + this.reloadCommand.setReloadManager(this); + } + + + @PreDestroy + public void shutdown() { + if (this.threadPoolExecutor != null) { + this.threadPoolExecutor.shutdownNow(); + this.threadPoolExecutor = null; + } } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Method[] methods = ReflectionUtils.getAllDeclaredMethods(bean.getClass()); - if (methods == null) { - return bean; - } for (Method method : methods) { SmartReload smartReload = method.getAnnotation(SmartReload.class); if (smartReload == null) { diff --git a/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml index 62069872..ed7d3064 100644 --- a/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/dev/sa-base.yaml @@ -139,4 +139,17 @@ sa-token: # 启动时的字符画打印 is-print: false # 是否从cookie读取token - is-read-cookie: false \ No newline at end of file + is-read-cookie: false + +# SmartJob 定时任务配置(不需要可以直接删除以下配置,详细文档请看:https://www.xxxxxx.com) +smart: + job: + enabled: true + # 任务初始化延迟 默认30秒 可选 + init-delay: 10 + # 定时任务执行线程池数量 默认2 可选 + core-pool-size: 2 + # 数据库配置检测-开关 默认开启 可选(作用是固定间隔读取数据库配置更新任务,关闭后只能重启服务或通过接口修改定时任务,建议开启) + db-refresh-enabled: true + # 数据库配置检测-执行间隔 默认120秒 可选 + db-refresh-interval: 60 \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/resources/mapper/support/LoginLogMapper.xml b/smart-admin-api/sa-base/src/main/resources/mapper/support/LoginLogMapper.xml index 8e7f7c24..b2b88edc 100644 --- a/smart-admin-api/sa-base/src/main/resources/mapper/support/LoginLogMapper.xml +++ b/smart-admin-api/sa-base/src/main/resources/mapper/support/LoginLogMapper.xml @@ -7,6 +7,15 @@ * from t_login_log + + AND user_id = #{query.userId} + + + AND user_type = #{query.userType} + + + AND INSTR(login_ip,#{query.ip}) + AND DATE_FORMAT(create_time, '%Y-%m-%d') >= #{query.startDate} diff --git a/smart-admin-api/sa-base/src/main/resources/mapper/support/MessageMapper.xml b/smart-admin-api/sa-base/src/main/resources/mapper/support/MessageMapper.xml new file mode 100644 index 00000000..2a3764c7 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/resources/mapper/support/MessageMapper.xml @@ -0,0 +1,56 @@ + + + + + + + UPDATE t_message + SET read_flag = #{readFlag}, + read_time = now() + WHERE message_id = #{messageId} + AND receiver_user_type = #{receiverUserType} + AND receiver_user_id = #{receiverUserId} + AND read_flag != #{readFlag} + + + + + + + \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/resources/mapper/support/OperateLogMapper.xml b/smart-admin-api/sa-base/src/main/resources/mapper/support/OperateLogMapper.xml index 42a9c9c1..1d22bee1 100644 --- a/smart-admin-api/sa-base/src/main/resources/mapper/support/OperateLogMapper.xml +++ b/smart-admin-api/sa-base/src/main/resources/mapper/support/OperateLogMapper.xml @@ -7,6 +7,12 @@ * from t_operate_log + + AND operate_user_id = #{query.operateUserId} + + + AND operate_user_type = #{query.operateUserType} + AND DATE_FORMAT(create_time, '%Y-%m-%d') >= #{query.startDate} diff --git a/smart-admin-api/sa-base/src/main/resources/mapper/support/SmartJobLogMapper.xml b/smart-admin-api/sa-base/src/main/resources/mapper/support/SmartJobLogMapper.xml new file mode 100644 index 00000000..48727dd7 --- /dev/null +++ b/smart-admin-api/sa-base/src/main/resources/mapper/support/SmartJobLogMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/resources/mapper/support/SmartJobMapper.xml b/smart-admin-api/sa-base/src/main/resources/mapper/support/SmartJobMapper.xml new file mode 100644 index 00000000..41863b6d --- /dev/null +++ b/smart-admin-api/sa-base/src/main/resources/mapper/support/SmartJobMapper.xml @@ -0,0 +1,28 @@ + + + + + + + + \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml index b60bb994..e71d5ff6 100644 --- a/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/pre/sa-base.yaml @@ -141,4 +141,17 @@ sa-token: # 启动时的字符画打印 is-print: false # 是否从cookie读取token - is-read-cookie: false \ No newline at end of file + is-read-cookie: false + +# SmartJob 定时任务配置(不需要可以直接删除以下配置,详细文档请看:https://www.xxxxxx.com) +smart: + job: + enabled: true + # 任务初始化延迟 默认30秒 可选 + init-delay: 10 + # 定时任务执行线程池数量 默认2 可选 + core-pool-size: 2 + # 数据库配置检测-开关 默认开启 可选(作用是固定间隔读取数据库配置更新任务,关闭后只能重启服务或通过接口修改定时任务,建议开启) + db-refresh-enabled: true + # 数据库配置检测-执行间隔 默认120秒 可选 + db-refresh-interval: 60 \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml index 0122533b..4758a75d 100644 --- a/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/prod/sa-base.yaml @@ -1,9 +1,9 @@ spring: # 数据库连接信息 datasource: - url: jdbc:mysql://127.0.0.1:3306/smart_admin_v3?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai + url: jdbc:mysql://127.0.0.1:3306/smart_admin_v3_dev?autoReconnect=true&useServerPreparedStmts=false&rewriteBatchedStatements=true&characterEncoding=UTF-8&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai username: root - password: Zhuoda1024lab + password: Zhuoda#1024lab initial-size: 10 min-idle: 10 max-active: 100 @@ -108,7 +108,7 @@ http: keep-alive: 300000 # 跨域配置 -access-control-allow-origin: 'smartadmin.vip' +access-control-allow-origin: 'https://preview.smartadmin.vip' # 心跳配置 heart-beat: @@ -141,4 +141,17 @@ sa-token: # 启动时的字符画打印 is-print: false # 是否从cookie读取token - is-read-cookie: false \ No newline at end of file + is-read-cookie: false + +# SmartJob 定时任务配置(不需要可以直接删除以下配置,详细文档请看:https://www.xxxxxx.com) +smart: + job: + enabled: true + # 任务初始化延迟 默认30秒 可选 + init-delay: 10 + # 定时任务执行线程池数量 默认2 可选 + core-pool-size: 2 + # 数据库配置检测-开关 默认开启 可选(作用是固定间隔读取数据库配置更新任务,关闭后只能重启服务或通过接口修改定时任务,建议开启) + db-refresh-enabled: true + # 数据库配置检测-执行间隔 默认120秒 可选 + db-refresh-interval: 60 \ No newline at end of file diff --git a/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml b/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml index 27de1c00..e9fc251d 100644 --- a/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml +++ b/smart-admin-api/sa-base/src/main/resources/test/sa-base.yaml @@ -74,9 +74,9 @@ file: upload-path: /home/smart_admin_v3/upload/ #文件上传目录 url-prefix: cloud: - region: oss-cn-qingdao - endpoint: oss-cn-qingdao.aliyuncs.com - bucket-name: common + region: oss-cn-hangzhou + endpoint: oss-cn-hangzhou.aliyuncs.com + bucket-name: 1024lab-smart-admin access-key: secret-key: url-prefix: https://${file.storage.cloud.bucket-name}.${file.storage.cloud.endpoint}/ @@ -89,6 +89,7 @@ springdoc: enabled: true # 开关 doc-expansion: none #关闭展开 tags-sorter: alpha + server-base-url: http://smartadmin.dev.1024lab.net/api/ api-docs: enabled: true # 开关 knife4j: @@ -141,4 +142,17 @@ sa-token: # 启动时的字符画打印 is-print: false # 是否从cookie读取token - is-read-cookie: false \ No newline at end of file + is-read-cookie: false + +# SmartJob 定时任务配置(不需要可以直接删除以下配置,详细文档请看:https://www.xxxxxx.com) +smart: + job: + enabled: true + # 任务初始化延迟 默认30秒 可选 + init-delay: 10 + # 定时任务执行线程池数量 默认2 可选 + core-pool-size: 2 + # 数据库配置检测-开关 默认开启 可选(作用是固定间隔读取数据库配置更新任务,关闭后只能重启服务或通过接口修改定时任务,建议开启) + db-refresh-enabled: true + # 数据库配置检测-执行间隔 默认120秒 可选 + db-refresh-interval: 60 \ No newline at end of file diff --git a/smart-admin-web/javascript-ant-design-vue3/.env.development b/smart-admin-web/javascript-ant-design-vue3/.env.development index 7ae8066c..df615c53 100644 --- a/smart-admin-web/javascript-ant-design-vue3/.env.development +++ b/smart-admin-web/javascript-ant-design-vue3/.env.development @@ -1,3 +1,3 @@ NODE_ENV=development VITE_APP_TITLE='SmartAdmin 开发环境(Dev)' -VITE_APP_API_URL='http://127.0.0.1:1024' \ No newline at end of file +VITE_APP_API_URL='http://smartadmin.dev.1024lab.net/api/' diff --git a/smart-admin-web/javascript-ant-design-vue3/.env.test b/smart-admin-web/javascript-ant-design-vue3/.env.test index b56e45cb..d034749e 100644 --- a/smart-admin-web/javascript-ant-design-vue3/.env.test +++ b/smart-admin-web/javascript-ant-design-vue3/.env.test @@ -1,3 +1,3 @@ NODE_ENV=production VITE_APP_TITLE='SmartAdmin 测试环境(Test)' -VITE_APP_API_URL='http://127.0.0.1:1024' \ No newline at end of file +VITE_APP_API_URL='http://smartadmin.dev.1024lab.net/api/' diff --git a/smart-admin-web/javascript-ant-design-vue3/package.json b/smart-admin-web/javascript-ant-design-vue3/package.json index fcf1f31a..a1491dbc 100644 --- a/smart-admin-web/javascript-ant-design-vue3/package.json +++ b/smart-admin-web/javascript-ant-design-vue3/package.json @@ -11,15 +11,16 @@ "scripts": { "localhost": "vite --mode localhost", "dev": "vite", - "build:test": "vite build --mode test", + "build:test": "vite build --base=/admin/ --mode test", "build:pre": "vite build --mode pre", "build:prod": "vite build --mode production" }, "type": "module", "dependencies": { + "@ant-design/icons-vue": "^6.1.0", "@wangeditor/editor": "5.1.14", "@wangeditor/editor-for-vue": "5.1.12", - "ant-design-vue": "4.2.0", + "ant-design-vue": "4.2.1", "axios": "1.6.8", "clipboard": "2.0.11", "crypto-js": "4.1.1", @@ -37,14 +38,15 @@ "sortablejs": "1.15.0", "ua-parser-js": "1.0.35", "v-viewer": "~1.6.4", - "vue": "3.3.13", - "vue-i18n": "9.10.2", - "vue-router": "4.3.0", - "vue3-json-viewer": "2.2.2" + "vue": "3.4.27", + "vue-i18n": "9.13.1", + "vue-router": "4.3.2", + "vue3-json-viewer": "2.2.2", + "vue3-tabs-chrome": "^0.3.3" }, "devDependencies": { "@vitejs/plugin-vue": "5.0.4", - "@vue/compiler-sfc": "3.4.21", + "@vue/compiler-sfc": "3.4.27", "eslint": "^8.16.0", "eslint-config-prettier": "~9.0.0", "eslint-plugin-prettier": "~5.0.0", @@ -58,7 +60,7 @@ "stylelint-config-standard": "~25.0.0", "stylelint-order": "~5.0.0", "terser": "~5.29.2", - "vite": "5.2.6", + "vite": "5.2.12", "vue-eslint-parser": "~9.4.2" }, "engines": { diff --git a/smart-admin-web/javascript-ant-design-vue3/src/api/support/job-api.js b/smart-admin-web/javascript-ant-design-vue3/src/api/support/job-api.js new file mode 100644 index 00000000..aeea96ef --- /dev/null +++ b/smart-admin-web/javascript-ant-design-vue3/src/api/support/job-api.js @@ -0,0 +1,34 @@ +/* + * job api + * + * @Author: huke + * @Date: 2024/06/25 + */ +import { postRequest, getRequest } from '/src/lib/axios'; + +export const jobApi = { + // 分页查询 @huke + queryJob: (param) => { + return postRequest('/support/job/query', param); + }, + // 定时任务-查询详情 @huke + queryJobInfo: (param) => { + return getRequest(`/support/job/${param}`); + }, + // 执行任务 @huke + executeJob: (param) => { + return postRequest('/support/job/execute', param); + }, + // 定时任务-更新-任务信息 @huke + updateJob: (param) => { + return postRequest('/support/job/update', param); + }, + // 定时任务-更新-开启状态 @huke + updateJobEnabled: (param) => { + return postRequest('/support/job/update/enabled', param); + }, + // 定时任务-执行记录-分页查询 @huke + queryJobLog: (param) => { + return postRequest('/support/job/log/query', param); + }, +}; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/api/support/login-log-api.js b/smart-admin-web/javascript-ant-design-vue3/src/api/support/login-log-api.js index 271bf15e..1a631bd1 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/api/support/login-log-api.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/api/support/login-log-api.js @@ -14,4 +14,8 @@ export const loginLogApi = { queryList: (param) => { return postRequest('/support/loginLog/page/query', param); }, + // 分页查询当前登录人信息 @author 善逸 + queryListLogin: (param) => { + return postRequest('/support/loginLog/page/query/login', param); + }, }; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/api/support/message-api.js b/smart-admin-web/javascript-ant-design-vue3/src/api/support/message-api.js new file mode 100644 index 00000000..71b70ce8 --- /dev/null +++ b/smart-admin-web/javascript-ant-design-vue3/src/api/support/message-api.js @@ -0,0 +1,16 @@ +import { getRequest, postRequest } from '/src/lib/axios'; + +export const messageApi = { + // 通知消息-分页查询 + queryMessage: (param) => { + return postRequest('/support/message/queryMyMessage', param); + }, + // 通知消息-查询未读消息数 + queryUnreadCount: () => { + return getRequest('/support/message/getUnreadCount'); + }, + // 通知消息-标记已读 + updateReadFlag: (messageId) => { + return getRequest(`/support/message/read/${messageId}`); + }, +}; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/api/support/operate-log-api.js b/smart-admin-web/javascript-ant-design-vue3/src/api/support/operate-log-api.js index 82c84a9a..ff613ec2 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/api/support/operate-log-api.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/api/support/operate-log-api.js @@ -18,4 +18,8 @@ export const operateLogApi = { detail: (id) => { return getRequest(`/support/operateLog/detail/${id}`); }, + // 分页查询当前登录人信息 @author 善逸 + queryListLogin: (param) => { + return postRequest('/support/operateLog/page/query/login', param); + }, }; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/api/system/employee-api.js b/smart-admin-web/javascript-ant-design-vue3/src/api/system/employee-api.js index fbf50654..dd02ec6f 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/api/system/employee-api.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/api/system/employee-api.js @@ -35,6 +35,18 @@ export const employeeApi = { updateEmployee: (params) => { return postRequest('/employee/update', params); }, + /** + * 更新登录人信息 + */ + updateByLogin: (params) => { + return postRequest('/employee/update/login', params); + }, + /** + * 更新登录人头像 + */ + updateAvatar: (params) => { + return postRequest('/employee/update/avatar', params); + }, /** * 删除员工 */ diff --git a/smart-admin-web/javascript-ant-design-vue3/src/api/system/position-api.js b/smart-admin-web/javascript-ant-design-vue3/src/api/system/position-api.js new file mode 100644 index 00000000..e6d09907 --- /dev/null +++ b/smart-admin-web/javascript-ant-design-vue3/src/api/system/position-api.js @@ -0,0 +1,55 @@ +/** + * 职务表 api 封装 + * + * @Author: kaiyun + * @Date: 2024-06-23 23:31:38 + * @Copyright 1024创新实验室 + */ +import { postRequest, getRequest } from '/@/lib/axios'; + +export const positionApi = { + + /** + * 分页查询 @author kaiyun + */ + queryPage : (param) => { + return postRequest('/position/queryPage', param); + }, + + /** + * 增加 @author kaiyun + */ + add: (param) => { + return postRequest('/position/add', param); + }, + + /** + * 修改 @author kaiyun + */ + update: (param) => { + return postRequest('/position/update', param); + }, + + + /** + * 删除 @author kaiyun + */ + delete: (id) => { + return getRequest(`/position/delete/${id}`); + }, + + /** + * 批量删除 @author kaiyun + */ + batchDelete: (idList) => { + return postRequest('/position/batchDelete', idList); + }, + + /** + * 查询列表 @author kaiyun + */ + queryList: () => { + return getRequest('/position/queryList'); + }, + +}; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/components/system/position-select/index.vue b/smart-admin-web/javascript-ant-design-vue3/src/components/system/position-select/index.vue new file mode 100644 index 00000000..16be61b5 --- /dev/null +++ b/smart-admin-web/javascript-ant-design-vue3/src/components/system/position-select/index.vue @@ -0,0 +1,79 @@ + + + + diff --git a/smart-admin-web/javascript-ant-design-vue3/src/config/app-config.js b/smart-admin-web/javascript-ant-design-vue3/src/config/app-config.js index 8d967df4..183620f7 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/config/app-config.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/config/app-config.js @@ -24,12 +24,16 @@ export const appDefaultConfig = { borderRadius: 6, // 标签页 pageTagFlag: true, + // 标签页样式: default、 antd + pageTagStyle: 'default', // 面包屑 breadCrumbFlag: true, // 页脚 footerFlag: true, // 帮助文档 helpDocFlag: true, + // 帮助文档默认展开 + helpDocExpandFlag: true, // 水印 watermarkFlag: true, // 网站名称 diff --git a/smart-admin-web/javascript-ant-design-vue3/src/constants/business/message/message-const.js b/smart-admin-web/javascript-ant-design-vue3/src/constants/business/message/message-const.js new file mode 100644 index 00000000..b71d1305 --- /dev/null +++ b/smart-admin-web/javascript-ant-design-vue3/src/constants/business/message/message-const.js @@ -0,0 +1,30 @@ +/* + * @Description: file content + * @Author: yandy + * @Date: 2022-07-24 21:43:43 + * @LastEditors: + * @LastEditTime: 2022-07-24 21:43:43 + */ +export const MESSAGE_TYPE_ENUM = { + MAIL: { + value: 1, + desc: '站内信' + }, + ORDER: { + value: 2, + desc: '订单' + }, + }; + + +export const MESSAGE_RECEIVE_TYPE_ENUM = { + EMPLOYEE: { + value: 1, + desc: '员工' + }, + }; + +export default { + MESSAGE_TYPE_ENUM, + MESSAGE_RECEIVE_TYPE_ENUM +}; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/constants/index.js b/smart-admin-web/javascript-ant-design-vue3/src/constants/index.js index e242e488..ff49eb05 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/constants/index.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/constants/index.js @@ -17,8 +17,10 @@ import file from './support/file-const'; import notice from './business/oa/notice-const'; import loginLog from './support/login-log-const'; import enterprise from './business/oa/enterprise-const'; +import message from './business/message/message-const'; import codeGeneratorConst from './support/code-generator-const'; import changeLogConst from './support/change-log-const'; +import jobConst from './support/job-const.js'; export default { FLAG_NUMBER_ENUM, @@ -33,6 +35,8 @@ export default { ...file, ...notice, ...enterprise, + ...message, ...codeGeneratorConst, ...changeLogConst, + ...jobConst, }; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/constants/layout-const.js b/smart-admin-web/javascript-ant-design-vue3/src/constants/layout-const.js index 0c06a0dd..b5f124e0 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/constants/layout-const.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/constants/layout-const.js @@ -21,3 +21,14 @@ export const LAYOUT_ENUM = { desc: '顶部', }, }; + +export const PAGE_TAG_ENUM = { + DEFAULT: { + value: 'default', + desc: '默认', + }, + ANTD: { + value: 'antd', + desc: 'Ant Design', + }, +}; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/constants/support/job-const.js b/smart-admin-web/javascript-ant-design-vue3/src/constants/support/job-const.js new file mode 100644 index 00000000..6d89f8ec --- /dev/null +++ b/smart-admin-web/javascript-ant-design-vue3/src/constants/support/job-const.js @@ -0,0 +1,18 @@ +/** + * job 常量 + * @type {{CRON: {value: number, desc: string}, FIXED_DELAY: {value: number, desc: string}}} + */ +export const TRIGGER_TYPE_ENUM = { + CRON: { + value: 'cron', + desc: 'cron表达式', + }, + FIXED_DELAY: { + value: 'fixed_delay', + desc: '固定间隔', + }, +}; + +export default { + TRIGGER_TYPE_ENUM, +}; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/constants/support/table-id-const.js b/smart-admin-web/javascript-ant-design-vue3/src/constants/support/table-id-const.js index 00076b34..572a27d4 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/constants/support/table-id-const.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/constants/support/table-id-const.js @@ -40,6 +40,7 @@ export const TABLE_ID_CONST = { SYSTEM: { EMPLOYEE: systemInitTableId + 1, //员工 MENU: systemInitTableId + 2, //菜单 + POSITION:systemInitTableId + 3, //职位 }, /** * 支撑 @@ -53,5 +54,7 @@ export const TABLE_ID_CONST = { LOGIN_LOG: supportInitTableId + 6, //登录日志 RELOAD: supportInitTableId + 7, //reload HELP_DOC: supportInitTableId + 8, //帮助文档 + JOB: supportInitTableId + 9, //Job + JOB_LOG: supportInitTableId + 10, //JobLog }, }; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/i18n/lang/en-US/index.js b/smart-admin-web/javascript-ant-design-vue3/src/i18n/lang/en-US/index.js index 6d4a3eb7..e5301dff 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/i18n/lang/en-US/index.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/i18n/lang/en-US/index.js @@ -23,7 +23,9 @@ export default { 'setting.compact': 'Page Compact', 'setting.bread': 'Show Bread', 'setting.pagetag': 'Show PageTag', + 'setting.pagetag.style': 'PageTag Style', 'setting.footer': 'Show Footer', 'setting.helpdoc': 'Show Helpdoc', + 'setting.helpdoc.expand': 'Helpdoc Expand', 'setting.watermark': 'Show Watermark', }; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/i18n/lang/zh-CN/index.js b/smart-admin-web/javascript-ant-design-vue3/src/i18n/lang/zh-CN/index.js index 28b2e2a9..8561276c 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/i18n/lang/zh-CN/index.js +++ b/smart-admin-web/javascript-ant-design-vue3/src/i18n/lang/zh-CN/index.js @@ -23,7 +23,9 @@ export default { 'setting.page.width': '页面宽度', 'setting.bread': '面包屑', 'setting.pagetag': '标签页', + 'setting.pagetag.style': '标签页样式', 'setting.footer': '页脚', 'setting.helpdoc': '帮助文档', + 'setting.helpdoc.expand': '帮助文档展开', 'setting.watermark': '水印', }; diff --git a/smart-admin-web/javascript-ant-design-vue3/src/layout/components/header-user-space/header-avatar.vue b/smart-admin-web/javascript-ant-design-vue3/src/layout/components/header-user-space/header-avatar.vue index d67f2889..5af75daa 100644 --- a/smart-admin-web/javascript-ant-design-vue3/src/layout/components/header-user-space/header-avatar.vue +++ b/smart-admin-web/javascript-ant-design-vue3/src/layout/components/header-user-space/header-avatar.vue @@ -1,24 +1,28 @@